website refactor
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* ESLint rule to ban usage of generic UI primitives in components
|
||||
*
|
||||
* Generic primitives like Box and Surface should only be used in the ui/ layer
|
||||
* to build semantic UI elements. Components should use those semantic elements.
|
||||
*
|
||||
* Rationale:
|
||||
* - Encourages use of semantic UI components
|
||||
* - Maintains architectural boundaries
|
||||
* - Improves consistency across the application
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Ban usage of generic UI primitives in components',
|
||||
category: 'Architecture',
|
||||
recommended: true,
|
||||
},
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
noGenericPrimitive: 'Generic UI primitive "{{name}}" is not allowed in components. Primitives are internal to the UI layer. Use semantic UI elements from @/ui instead (e.g., Card, Section, Table, Stack, Grid). If a semantic element is missing, create one in apps/website/ui/ using primitives.',
|
||||
noPrimitiveExport: 'Do not re-export primitives from the UI layer. Primitives should remain internal to apps/website/ui/primitives/.',
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const filename = context.getFilename();
|
||||
|
||||
// Only run for files under /components/ (and *.ts/*.tsx)
|
||||
const isComponent = filename.includes('/components/') && (filename.endsWith('.ts') || filename.endsWith('.tsx'));
|
||||
|
||||
// Check for re-exports in the UI layer (excluding primitives themselves)
|
||||
const isUiLayer = filename.includes('/ui/') && !filename.includes('/ui/primitives/');
|
||||
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (!isComponent) return;
|
||||
|
||||
const importPath = node.source.value;
|
||||
|
||||
// Check if it's an import from the UI primitives layer
|
||||
const isPrimitiveImport =
|
||||
importPath.includes('/ui/primitives') ||
|
||||
importPath.startsWith('@/ui/primitives') ||
|
||||
// Legacy direct paths
|
||||
importPath.endsWith('/ui/Box') ||
|
||||
importPath.endsWith('/ui/Surface') ||
|
||||
importPath === '@/ui/Box' ||
|
||||
importPath === '@/ui/Surface';
|
||||
|
||||
if (isPrimitiveImport) {
|
||||
node.specifiers.forEach(specifier => {
|
||||
let importedName = '';
|
||||
|
||||
if (specifier.type === 'ImportSpecifier') {
|
||||
importedName = specifier.imported.name;
|
||||
} else if (specifier.type === 'ImportDefaultSpecifier') {
|
||||
importedName = specifier.local.name;
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: specifier,
|
||||
messageId: 'noGenericPrimitive',
|
||||
data: { name: importedName },
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
ExportNamedDeclaration(node) {
|
||||
if (!isUiLayer) return;
|
||||
if (!node.source) return;
|
||||
|
||||
const exportPath = node.source.value;
|
||||
if (exportPath.includes('/primitives/') || exportPath.startsWith('./primitives/')) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'noPrimitiveExport',
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
ExportAllDeclaration(node) {
|
||||
if (!isUiLayer) return;
|
||||
|
||||
const exportPath = node.source.value;
|
||||
if (exportPath.includes('/primitives/') || exportPath.startsWith('./primitives/')) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'noPrimitiveExport',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user