import { dirname } from 'path'; import { fileURLToPath } from 'url'; import { FlatCompat } from '@eslint/eslintrc'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const compat = new FlatCompat({ baseDirectory: __dirname }); // ── Clean Architecture layer boundary rules ────────────────── // Domain → nothing from this project // Infrastructure → domain only // Application → domain + infrastructure // Store → domain only // Views/Components → application + store + domain (NOT infrastructure) const LAYERS = { domain: ['@/domain/*', '*/domain/*'], infrastructure: ['@/infrastructure/*', '*/infrastructure/*'], application: ['@/application/*', '*/application/*'], store: ['@/store/*', '*/store/*'], views: ['@/views/*', '*/views/*'], }; function noImport(patterns, message) { return patterns.map((group) => ({ group: [group], message })); } const config = [ ...compat.extends('next/core-web-vitals', 'next/typescript'), // ── Domain: pure entities + interfaces, zero outward deps ── { files: ['src/domain/**/*.ts', 'src/domain/**/*.tsx'], rules: { 'no-restricted-imports': ['error', { patterns: [ ...noImport(LAYERS.infrastructure, 'Domain must not import Infrastructure'), ...noImport(LAYERS.application, 'Domain must not import Application'), ...noImport(LAYERS.store, 'Domain must not import Store'), ...noImport(LAYERS.views, 'Domain must not import Views'), ], }], }, }, // ── Infrastructure: repos + HTTP client, depends on domain only ── { files: ['src/infrastructure/**/*.ts', 'src/infrastructure/**/*.tsx'], rules: { 'no-restricted-imports': ['error', { patterns: [ ...noImport(LAYERS.application, 'Infrastructure must not import Application'), ...noImport(LAYERS.store, 'Infrastructure must not import Store'), ...noImport(LAYERS.views, 'Infrastructure must not import Views'), ], }], }, }, // ── Application (use cases): depends on domain + infrastructure ── { files: ['src/application/**/*.ts', 'src/application/**/*.tsx'], rules: { 'no-restricted-imports': ['error', { patterns: [ ...noImport(LAYERS.store, 'Application must not import Store'), ...noImport(LAYERS.views, 'Application must not import Views'), ], }], }, }, // ── Store (Redux + Zustand): UI state only, depends on domain ── { files: ['src/store/**/*.ts', 'src/store/**/*.tsx'], rules: { 'no-restricted-imports': ['error', { patterns: [ ...noImport(LAYERS.infrastructure, 'Store must not import Infrastructure'), ...noImport(LAYERS.application, 'Store must not import Application'), ...noImport(LAYERS.views, 'Store must not import Views'), ], }], }, }, // ── Presentation (views + components + layouts): no direct infra access ── { files: [ 'src/views/**/*.ts', 'src/views/**/*.tsx', 'src/components/**/*.ts', 'src/components/**/*.tsx', 'src/layouts/**/*.ts', 'src/layouts/**/*.tsx', ], rules: { 'no-restricted-imports': ['error', { patterns: [ ...noImport( LAYERS.infrastructure, 'Presentation must not import Infrastructure directly — use Application use-cases', ), ], }], }, }, ]; export default config;