website refactor
This commit is contained in:
94
apps/website/eslint-rules/filename-matches-export.js
Normal file
94
apps/website/eslint-rules/filename-matches-export.js
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* ESLint rule to enforce filename matches exported name
|
||||
*
|
||||
* The filename (without extension) should match the exported name exactly.
|
||||
* For example: AdminDashboardPageQuery.ts should export AdminDashboardPageQuery
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Enforce filename matches exported name',
|
||||
category: 'Best Practices',
|
||||
recommended: true,
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
filenameMismatch: 'Filename "{{filename}}" should match exported name "{{exportName}}"',
|
||||
noMatchFound: 'No export found that matches filename "{{filename}}"',
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const filename = context.getFilename();
|
||||
|
||||
// Extract base filename without extension
|
||||
const baseName = filename.split('/').pop(); // Get last part of path
|
||||
const nameWithoutExt = baseName?.replace(/\.(ts|tsx|js|jsx)$/, '');
|
||||
|
||||
// Skip test files, index files, and type definition files
|
||||
if (!nameWithoutExt ||
|
||||
nameWithoutExt.endsWith('.test') ||
|
||||
nameWithoutExt.endsWith('.spec') ||
|
||||
nameWithoutExt === 'index' ||
|
||||
nameWithoutExt.endsWith('.d')) {
|
||||
return {};
|
||||
}
|
||||
|
||||
let exportedName = null;
|
||||
|
||||
return {
|
||||
// Track named exports
|
||||
ExportNamedDeclaration(node) {
|
||||
if (node.declaration) {
|
||||
if (node.declaration.id) {
|
||||
exportedName = node.declaration.id.name;
|
||||
} else if (node.declaration.declarations) {
|
||||
// Multiple const exports - use the first one
|
||||
const first = node.declaration.declarations[0];
|
||||
if (first.id && first.id.name) {
|
||||
exportedName = first.id.name;
|
||||
}
|
||||
}
|
||||
} else if (node.specifiers && node.specifiers.length > 0) {
|
||||
// Re-exports - use the first one
|
||||
exportedName = node.specifiers[0].exported.name;
|
||||
}
|
||||
},
|
||||
|
||||
// Track default exports
|
||||
ExportDefaultDeclaration(node) {
|
||||
if (node.declaration && node.declaration.id) {
|
||||
exportedName = node.declaration.id.name;
|
||||
} else {
|
||||
exportedName = 'default';
|
||||
}
|
||||
},
|
||||
|
||||
'Program:exit'() {
|
||||
if (!exportedName) {
|
||||
// No export found - this might be okay for some files
|
||||
return;
|
||||
}
|
||||
|
||||
if (exportedName === 'default') {
|
||||
// Default exports don't need to match filename
|
||||
return;
|
||||
}
|
||||
|
||||
if (exportedName !== nameWithoutExt) {
|
||||
context.report({
|
||||
node: context.getSourceCode().ast,
|
||||
messageId: 'filenameMismatch',
|
||||
data: {
|
||||
filename: nameWithoutExt,
|
||||
exportName: exportedName,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user