website refactor

This commit is contained in:
2026-01-18 16:18:18 +01:00
parent 0b301feb61
commit 13567d51af
329 changed files with 4701 additions and 4750 deletions

View File

@@ -45,6 +45,7 @@ const cleanErrorHandling = require('./clean-error-handling');
const servicesImplementContract = require('./services-implement-contract');
const serverActionsReturnResult = require('./server-actions-return-result');
const serverActionsInterface = require('./server-actions-interface');
const noGenericUiPrimitivesInComponents = require('./no-generic-ui-primitives-in-components');
module.exports = {
rules: {
@@ -153,6 +154,7 @@ module.exports = {
'ui-element-purity': require('./ui-element-purity'),
'no-nextjs-imports-in-ui': require('./no-nextjs-imports-in-ui'),
'component-classification': require('./component-classification'),
'no-generic-ui-primitives-in-components': noGenericUiPrimitivesInComponents,
// Route Configuration Rules
'no-hardcoded-routes': require('./no-hardcoded-routes'),

View File

@@ -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',
});
}
}
};
},
};