const path = require('path'); const src = path.resolve(__dirname, 'src'); module.exports = { parser: '@typescript-eslint/parser', parserOptions: { sourceType: 'module', ecmaFeatures: { jsx: true }, }, plugins: ['@typescript-eslint/eslint-plugin', 'react', 'react-hooks', 'import', '@conarti/feature-sliced'], extends: [ 'plugin:@typescript-eslint/recommended', 'plugin:react/recommended', 'plugin:react-hooks/recommended', ], root: true, env: { browser: true, es2020: true, }, settings: { react: { version: 'detect' }, 'import/resolver': { typescript: { alwaysTryTypes: true, project: './tsconfig.json', }, }, }, ignorePatterns: ['.eslintrc.cjs', 'vite.config.ts', 'vitest.config.ts', 'dist/'], rules: { 'no-restricted-imports': ['warn', { paths: [{ name: '@mui/material', importNames: [ // DS-covered: import from @moex-vibe/design-system 'Typography', 'Button', 'TextField', 'Select', 'Checkbox', 'Paper', 'Chip', 'Badge', 'Alert', 'Dialog', 'Skeleton', 'CircularProgress', 'Link', 'IconButton', 'Table', 'TableBody', 'TableCell', 'TableContainer', 'TableHead', 'TableRow', 'TableSortLabel', 'TablePagination', 'Pagination', ], message: 'Import from @moex-vibe/design-system instead, or use Box/Stack/Grid for layout.', }], }], '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], '@typescript-eslint/no-explicit-any': 'off', 'react/react-in-jsx-scope': 'off', // FSD layer boundaries (from @conarti/eslint-plugin-feature-sliced) // layers-slices: catches cross-layer violations (e.g., shared→entities) '@conarti/feature-sliced/layers-slices': ['error', { // allow test files and test utilities to import from any layer for mocking ignoreInFilesPatterns: ['**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx', '**/test/**'], }], // absolute-relative: false positives with @/ alias convention — disabled '@conarti/feature-sliced/absolute-relative': 'off', // public-api: too strict for app/ and test internals — disabled '@conarti/feature-sliced/public-api': 'off', // FSD layer boundaries (from import/no-restricted-paths) // NOTE: `from` = what's being imported, `target` = the file doing the import 'import/no-restricted-paths': [ 'error', { zones: [ // shared/ cannot import from entities/, features/, widgets/, pages/, app/ { from: `${src}/entities`, target: `${src}/shared` }, { from: `${src}/features`, target: `${src}/shared` }, { from: `${src}/widgets`, target: `${src}/shared` }, { from: `${src}/pages`, target: `${src}/shared` }, { from: `${src}/app`, target: `${src}/shared` }, // entities/ cannot import from features/, widgets/, pages/, app/ { from: `${src}/features`, target: `${src}/entities` }, { from: `${src}/widgets`, target: `${src}/entities` }, { from: `${src}/pages`, target: `${src}/entities` }, { from: `${src}/app`, target: `${src}/entities` }, // features/ cannot import from widgets/, pages/, app/ { from: `${src}/widgets`, target: `${src}/features` }, { from: `${src}/pages`, target: `${src}/features` }, { from: `${src}/app`, target: `${src}/features` }, // widgets/ cannot import from pages/, app/ { from: `${src}/pages`, target: `${src}/widgets` }, { from: `${src}/app`, target: `${src}/widgets` }, // pages/ cannot import from app/ { from: `${src}/app`, target: `${src}/pages` }, ], }, ], }, };