90 lines
2.5 KiB
JavaScript
90 lines
2.5 KiB
JavaScript
/**
|
|
* ESLint Rule: Page Query Must Use Builder
|
|
*
|
|
* Ensures page queries use builders to map their results
|
|
*/
|
|
|
|
module.exports = {
|
|
meta: {
|
|
type: 'problem',
|
|
docs: {
|
|
description: 'Ensure page queries use builders to map their results',
|
|
category: 'Page Query',
|
|
recommended: true,
|
|
},
|
|
messages: {
|
|
mustUseBuilder: 'Page queries must use Builders to map Page DTO to View Data/View Model. See apps/website/docs/architecture/write/BUILDERS.md',
|
|
},
|
|
schema: [],
|
|
},
|
|
|
|
create(context) {
|
|
const filename = context.getFilename();
|
|
|
|
// Only apply to page query files
|
|
if (!filename.includes('/lib/page-queries/') || !filename.endsWith('.ts')) {
|
|
return {};
|
|
}
|
|
|
|
let hasBuilderImport = false;
|
|
let hasReturnStatement = false;
|
|
|
|
return {
|
|
// Check imports for builder
|
|
ImportDeclaration(node) {
|
|
const importPath = node.source.value;
|
|
if (importPath.includes('/lib/builders/')) {
|
|
hasBuilderImport = true;
|
|
}
|
|
},
|
|
|
|
// Check for return statements
|
|
ReturnStatement(node) {
|
|
hasReturnStatement = true;
|
|
},
|
|
|
|
'Program:exit'() {
|
|
// Skip if file doesn't look like a page query
|
|
const isPageQueryFile = filename.includes('/lib/page-queries/') &&
|
|
filename.endsWith('.ts') &&
|
|
!filename.endsWith('.test.ts') &&
|
|
!filename.includes('/result/');
|
|
|
|
if (!isPageQueryFile) return;
|
|
|
|
// Check if it's a class-based page query
|
|
const sourceCode = context.getSourceCode();
|
|
const classNode = sourceCode.ast.body.find(node =>
|
|
node.type === 'ClassDeclaration' &&
|
|
node.id &&
|
|
node.id.name.endsWith('PageQuery')
|
|
);
|
|
|
|
if (!classNode) return;
|
|
|
|
// Check if the class has an execute method
|
|
const executeMethod = classNode.body.body.find(member =>
|
|
member.type === 'MethodDefinition' &&
|
|
member.key.type === 'Identifier' &&
|
|
member.key.name === 'execute'
|
|
);
|
|
|
|
if (!executeMethod) return;
|
|
|
|
// Check if the execute method uses a builder
|
|
// Look for builder usage in the method body
|
|
const methodBody = executeMethod.value.body;
|
|
if (!methodBody) return;
|
|
|
|
// Check if there's a builder import
|
|
if (!hasBuilderImport) {
|
|
context.report({
|
|
node: classNode,
|
|
messageId: 'mustUseBuilder',
|
|
});
|
|
}
|
|
},
|
|
};
|
|
},
|
|
};
|