website refactor
This commit is contained in:
130
apps/website/eslint-rules/server-actions-must-use-mutations.js
Normal file
130
apps/website/eslint-rules/server-actions-must-use-mutations.js
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* ESLint Rule: Server Actions Must Use Mutations
|
||||
*
|
||||
* Ensures server actions use mutations instead of direct service calls
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Ensure server actions use mutations instead of direct service calls',
|
||||
category: 'Server Actions',
|
||||
recommended: true,
|
||||
},
|
||||
messages: {
|
||||
mustUseMutations: 'Server actions must use Mutations, not direct Service or API Client calls. See apps/website/docs/architecture/write/MUTATIONS.md',
|
||||
noDirectService: 'Direct service calls in server actions are not allowed',
|
||||
noMutationUsage: 'Server actions should instantiate and call mutations',
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const filename = context.getFilename();
|
||||
const isServerAction = filename.includes('/app/') &&
|
||||
(filename.endsWith('.ts') || filename.endsWith('.tsx')) &&
|
||||
!filename.endsWith('.test.ts') &&
|
||||
!filename.endsWith('.test.tsx');
|
||||
|
||||
if (!isServerAction) {
|
||||
return {};
|
||||
}
|
||||
|
||||
let hasUseServerDirective = false;
|
||||
let hasServiceImport = false;
|
||||
let hasApiClientImport = false;
|
||||
let hasMutationImport = false;
|
||||
const newExpressions = [];
|
||||
const callExpressions = [];
|
||||
|
||||
return {
|
||||
// Check for 'use server' directive
|
||||
ExpressionStatement(node) {
|
||||
if (node.expression.type === 'Literal' && node.expression.value === 'use server') {
|
||||
hasUseServerDirective = true;
|
||||
}
|
||||
},
|
||||
|
||||
// Check imports
|
||||
ImportDeclaration(node) {
|
||||
const importPath = node.source.value;
|
||||
|
||||
if (importPath.includes('/lib/services/')) {
|
||||
hasServiceImport = true;
|
||||
}
|
||||
if (importPath.includes('/lib/api/') || importPath.includes('/api/')) {
|
||||
hasApiClientImport = true;
|
||||
}
|
||||
if (importPath.includes('/lib/mutations/')) {
|
||||
hasMutationImport = true;
|
||||
}
|
||||
},
|
||||
|
||||
// Track all NewExpression (instantiations)
|
||||
NewExpression(node) {
|
||||
newExpressions.push(node);
|
||||
},
|
||||
|
||||
// Track all CallExpression (method calls)
|
||||
CallExpression(node) {
|
||||
callExpressions.push(node);
|
||||
},
|
||||
|
||||
'Program:exit'() {
|
||||
// Only check files with 'use server' directive
|
||||
if (!hasUseServerDirective) return;
|
||||
|
||||
// Check for direct service/API client instantiation
|
||||
const hasDirectServiceInstantiation = newExpressions.some(node => {
|
||||
if (node.callee.type === 'Identifier') {
|
||||
const calleeName = node.callee.name;
|
||||
return calleeName.endsWith('Service') || calleeName.endsWith('ApiClient') || calleeName.endsWith('Client');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Check for direct service method calls
|
||||
const hasDirectServiceCall = callExpressions.some(node => {
|
||||
if (node.callee.type === 'MemberExpression' &&
|
||||
node.callee.object.type === 'Identifier') {
|
||||
const objName = node.callee.object.name;
|
||||
return objName.endsWith('Service') || objName.endsWith('ApiClient');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Check if mutations are being used
|
||||
const hasMutationUsage = newExpressions.some(node => {
|
||||
if (node.callee.type === 'Identifier') {
|
||||
return node.callee.name.endsWith('Mutation');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Report violations
|
||||
if (hasDirectServiceInstantiation && !hasMutationUsage) {
|
||||
context.report({
|
||||
node: null,
|
||||
messageId: 'mustUseMutations',
|
||||
});
|
||||
}
|
||||
|
||||
if (hasDirectServiceCall) {
|
||||
context.report({
|
||||
node: null,
|
||||
messageId: 'noDirectService',
|
||||
});
|
||||
}
|
||||
|
||||
// If imports exist but no mutation usage
|
||||
if ((hasServiceImport || hasApiClientImport) && !hasMutationImport) {
|
||||
context.report({
|
||||
node: null,
|
||||
messageId: 'mustUseMutations',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user