146 lines
3.6 KiB
TypeScript
146 lines
3.6 KiB
TypeScript
import eslint from '@eslint/js';
|
|
import tseslint from 'typescript-eslint';
|
|
import importPlugin from 'eslint-plugin-import-x';
|
|
|
|
export default [
|
|
{
|
|
ignores: [
|
|
'node_modules/**',
|
|
'dist/**',
|
|
'tmp/**',
|
|
'logs/**',
|
|
'scripts/**',
|
|
// Generated/seed data run via tsx, not part of the typechecked sources.
|
|
'src/db/migrations/**',
|
|
'src/db/seeders/**',
|
|
],
|
|
},
|
|
eslint.configs.recommended,
|
|
{
|
|
// CommonJS scripts/config (.cjs) kept outside the ESM TypeScript sources.
|
|
files: ['**/*.{js,cjs}'],
|
|
plugins: {
|
|
'import-x': importPlugin,
|
|
},
|
|
languageOptions: {
|
|
ecmaVersion: 'latest',
|
|
sourceType: 'commonjs',
|
|
globals: {
|
|
Buffer: 'readonly',
|
|
__dirname: 'readonly',
|
|
console: 'readonly',
|
|
module: 'readonly',
|
|
process: 'readonly',
|
|
require: 'readonly',
|
|
setInterval: 'readonly',
|
|
setTimeout: 'readonly',
|
|
URL: 'readonly',
|
|
},
|
|
},
|
|
settings: {
|
|
'import-x/resolver': {
|
|
node: { extensions: ['.js', '.ts', '.json'] },
|
|
},
|
|
},
|
|
rules: {
|
|
'import-x/no-unresolved': 'error',
|
|
},
|
|
},
|
|
// TypeScript: type-aware resolution is handled by tsc, not import-x.
|
|
...tseslint.configs.recommended.map((config) => ({
|
|
...config,
|
|
files: ['**/*.ts'],
|
|
})),
|
|
{
|
|
files: ['**/*.ts'],
|
|
rules: {
|
|
'@typescript-eslint/no-unused-vars': [
|
|
'error',
|
|
{
|
|
argsIgnorePattern: '^_',
|
|
varsIgnorePattern: '^_',
|
|
caughtErrorsIgnorePattern: '^_',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
// Layer import boundaries — hard invariants (see
|
|
// backend/docs/backend-architecture-refactor-plan.md). Debt that is still
|
|
// being paid down (API->DAL, BLL->HTTP) is ratcheted by the boundary test in
|
|
// src/shared/architecture/import-boundaries.test.ts, not here.
|
|
{
|
|
files: ['src/db/models/**/*.ts'],
|
|
rules: {
|
|
'no-restricted-imports': [
|
|
'error',
|
|
{
|
|
patterns: [
|
|
{
|
|
group: ['@/services/*', '@/api/*', '@/routes/*', '@/middlewares/*'],
|
|
message: 'DAL models must not import the BLL or API layers.',
|
|
},
|
|
{ group: ['express'], message: 'DAL models must not depend on Express.' },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: ['src/db/api/**/*.ts'],
|
|
rules: {
|
|
'no-restricted-imports': [
|
|
'error',
|
|
{
|
|
patterns: [
|
|
{
|
|
group: ['@/api/*', '@/routes/*', '@/middlewares/*'],
|
|
message: 'The DAL must not import the API layer.',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: ['src/shared/**/*.ts'],
|
|
rules: {
|
|
'no-restricted-imports': [
|
|
'error',
|
|
{
|
|
patterns: [
|
|
{
|
|
group: [
|
|
'@/api/*',
|
|
'@/routes/*',
|
|
'@/middlewares/*',
|
|
'@/services/*',
|
|
'@/db/*',
|
|
],
|
|
message:
|
|
'Cross-cutting code (shared/*) must not import any layer.',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
// Routes and controllers go through the BLL; they must not reach the DAL.
|
|
files: ['src/routes/**/*.ts', 'src/api/controllers/**/*.ts'],
|
|
rules: {
|
|
'no-restricted-imports': [
|
|
'error',
|
|
{
|
|
patterns: [
|
|
{
|
|
group: ['@/db/api/*', '@/db/models/*'],
|
|
message:
|
|
'The API layer must call a service (BLL), not the DAL directly.',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
];
|