From 1288a9dc307d9700d29dfd2d8ea41ab053eeb885 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Thu, 22 Jan 2026 18:57:48 +0100 Subject: [PATCH] eslint rules --- apps/website/.eslintrc.json | 3 +- apps/website/eslint-rules/index.js | 3 + .../eslint-rules/view-data-builder-imports.js | 80 +++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 apps/website/eslint-rules/view-data-builder-imports.js diff --git a/apps/website/.eslintrc.json b/apps/website/.eslintrc.json index 02e49b09b..c5e3abacd 100644 --- a/apps/website/.eslintrc.json +++ b/apps/website/.eslintrc.json @@ -57,7 +57,8 @@ "gridpilot-rules/filename-matches-export": "off", "gridpilot-rules/single-export-per-file": "off", "gridpilot-rules/view-data-builder-contract": "off", - "gridpilot-rules/view-data-builder-implements": "error" + "gridpilot-rules/view-data-builder-implements": "error", + "gridpilot-rules/view-data-builder-imports": "error" } }, { diff --git a/apps/website/eslint-rules/index.js b/apps/website/eslint-rules/index.js index 6948a6dec..c4e0aef13 100644 --- a/apps/website/eslint-rules/index.js +++ b/apps/website/eslint-rules/index.js @@ -47,6 +47,7 @@ const serverActionsReturnResult = require('./server-actions-return-result'); const serverActionsInterface = require('./server-actions-interface'); const noDisplayObjectsInUi = require('./no-display-objects-in-ui'); const viewDataBuilderImplements = require('./view-data-builder-implements'); +const viewDataBuilderImports = require('./view-data-builder-imports'); const viewModelBuilderImplements = require('./view-model-builder-implements'); const viewDataImplements = require('./view-data-implements'); const viewModelImplements = require('./view-model-implements'); @@ -133,6 +134,7 @@ module.exports = { 'view-data-location': viewDataLocation, 'view-data-builder-contract': viewDataBuilderContract, 'view-data-builder-implements': viewDataBuilderImplements, + 'view-data-builder-imports': viewDataBuilderImports, 'view-data-implements': viewDataImplements, // View Model Rules @@ -262,6 +264,7 @@ module.exports = { 'gridpilot-rules/view-data-location': 'error', 'gridpilot-rules/view-data-builder-contract': 'error', 'gridpilot-rules/view-data-builder-implements': 'error', + 'gridpilot-rules/view-data-builder-imports': 'error', 'gridpilot-rules/view-data-implements': 'error', // View Model diff --git a/apps/website/eslint-rules/view-data-builder-imports.js b/apps/website/eslint-rules/view-data-builder-imports.js new file mode 100644 index 000000000..80ae55503 --- /dev/null +++ b/apps/website/eslint-rules/view-data-builder-imports.js @@ -0,0 +1,80 @@ +/** + * ESLint rule to enforce ViewDataBuilder import paths + * + * ViewDataBuilders in lib/builders/view-data/ must: + * 1. Import DTO types from lib/types/generated/ + * 2. Import ViewData types from lib/view-data/ + */ + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Enforce ViewDataBuilder import paths', + category: 'Builders', + recommended: true, + }, + fixable: null, + schema: [], + messages: { + invalidDtoImport: 'ViewDataBuilders must import DTO types from lib/types/generated/, not from {{importPath}}', + invalidViewDataImport: 'ViewDataBuilders must import ViewData types from lib/view-data/, not from {{importPath}}', + missingDtoImport: 'ViewDataBuilders must import DTO types from lib/types/generated/', + missingViewDataImport: 'ViewDataBuilders must import ViewData types from lib/view-data/', + }, + }, + + create(context) { + const filename = context.getFilename(); + const isInViewDataBuilders = filename.includes('/lib/builders/view-data/'); + + if (!isInViewDataBuilders) return {}; + + let hasDtoImport = false; + let hasViewDataImport = false; + let dtoImportPath = null; + let viewDataImportPath = null; + + return { + ImportDeclaration(node) { + const importPath = node.source.value; + + // Check for DTO imports (should be from lib/types/generated/) + if (importPath.includes('/lib/types/')) { + if (!importPath.includes('/lib/types/generated/')) { + dtoImportPath = importPath; + context.report({ + node, + messageId: 'invalidDtoImport', + data: { importPath }, + }); + } else { + hasDtoImport = true; + } + } + + // Check for ViewData imports (should be from lib/view-data/) + if (importPath.includes('/lib/view-data/')) { + hasViewDataImport = true; + viewDataImportPath = importPath; + } + }, + + 'Program:exit'() { + if (!hasDtoImport) { + context.report({ + node: context.getSourceCode().ast, + messageId: 'missingDtoImport', + }); + } + + if (!hasViewDataImport) { + context.report({ + node: context.getSourceCode().ast, + messageId: 'missingViewDataImport', + }); + } + }, + }; + }, +};