Files
gridpilot.gg/.eslintrc.json
2026-01-17 18:28:10 +01:00

543 lines
14 KiB
JSON

{
"env": {
"es2022": true,
"node": true
},
"ignorePatterns": [
"**/dist/**",
"**/*.d.ts"
],
"overrides": [
{
"files": [
"**/index.ts",
"**/index.tsx"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "index.ts files are forbidden. Use explicit file names instead (e.g., UserService.ts, not index.ts).",
"selector": "Program"
}
]
}
},
{
"files": [
"core/*/application/ports/*/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "Port interface names should not start with 'Get'. Use descriptive names without the 'Get' prefix.",
"selector": "TSInterfaceDeclaration[id.name=/^Get.*Port$/]"
}
]
}
},
{
"files": [
"core/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "Blocker classes/interfaces are not allowed in core. Use Guards in backend.",
"selector": "TSClassDeclaration[id.name=/Blocker$/], TSInterfaceDeclaration[id.name=/Blocker$/]"
},
{
"message": "Presenter classes/interfaces are not allowed in core. Presenters belong in API or frontend layers.",
"selector": "TSClassDeclaration[id.name=/Presenter$/], TSInterfaceDeclaration[id.name=/Presenter$/]"
},
{
"message": "DTO classes/interfaces are not allowed in core. DTOs belong in API or frontend layers.",
"selector": "TSClassDeclaration[id.name=/Dto$/], TSInterfaceDeclaration[id.name=/Dto$/]"
},
{
"message": "ViewModel classes/interfaces are not allowed in core. View Models belong in frontend.",
"selector": "TSClassDeclaration[id.name=/ViewModel$/], TSInterfaceDeclaration[id.name=/ViewModel$/]"
},
{
"message": "CommandModel classes/interfaces are not allowed in core. Command Models belong in frontend.",
"selector": "TSClassDeclaration[id.name=/CommandModel$/], TSInterfaceDeclaration[id.name=/CommandModel$/]"
}
]
}
},
{
"files": [
"core/**/application/dto/**/*.ts",
"core/**/application/dtos/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "core/*/application/dto is forbidden. Use application result models + output ports; DTOs belong in API/website layers.",
"selector": "Program"
}
]
}
},
{
"files": [
"core/**/infrastructure/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "core/*/infrastructure is forbidden. Implementations must live in adapters/ and be wired in apps/.",
"selector": "Program"
}
]
}
},
{
"files": [
"core/**/domain/ports/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "core/*/domain/ports is forbidden. Ports belong in application/ports (or shared application layer), not domain.",
"selector": "Program"
}
]
}
},
{
"files": [
"core/**/shared/presentation/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "core/shared/presentation is forbidden. Presentation belongs in API or website layers.",
"selector": "Program"
}
]
}
},
{
"files": [
"apps/website/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "Guard classes/interfaces are not allowed in frontend. Use Blockers in frontend.",
"selector": "TSClassDeclaration[id.name=/Guard$/], TSInterfaceDeclaration[id.name=/Guard$/]"
}
]
}
},
{
"files": [
"apps/api/**/*.ts",
"apps/website/lib/dtos/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "Transport enums must end with 'Enum'.",
"selector": "TSEnumDeclaration[id.name=/^(?!.*Enum$).+/]"
}
]
}
},
{
"files": [
"core/*/application/use-cases/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "Use Case classes must end with 'UseCase'.",
"selector": "TSClassDeclaration[id.name=/^(?!.*UseCase$).+/]"
}
]
}
},
{
"files": [
"core/*/application/services/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "Application Service classes must end with 'Service'.",
"selector": "TSClassDeclaration[id.name=/^(?!.*Service$).+/]"
}
]
}
},
{
"files": [
"apps/website/lib/view-models/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "View Model classes must end with 'ViewModel'.",
"selector": "TSClassDeclaration[id.name=/^(?!.*ViewModel$).+/]"
}
]
}
},
{
"files": [
"apps/website/lib/commands/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "Command Model classes must end with 'CommandModel'.",
"selector": "TSClassDeclaration[id.name=/^(?!.*CommandModel$).+/]"
}
]
}
},
{
"files": [
"apps/website/app/**/page.tsx",
"apps/website/app/**/page.ts",
"apps/website/app/**/layout.tsx",
"apps/website/app/**/layout.ts",
"playwright.*.config.ts",
"vitest.*.config.ts",
"vitest.config.ts"
],
"rules": {
"import/no-default-export": "off",
"no-restricted-syntax": [
"error",
{
"message": "Interface names should not start with 'I'. Use descriptive names without the 'I' prefix (e.g., 'LiverCompositor' instead of 'ILiveryCompositor').",
"selector": "TSInterfaceDeclaration[id.name=/^I[A-Z]/]"
}
],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off"
}
},
{
"extends": [
"plugin:import/recommended",
"plugin:import/typescript"
],
"files": [
"**/*.ts",
"**/*.tsx"
],
"excludedFiles": [
"playwright.*.config.ts",
"vitest.*.config.ts",
"vitest.config.ts"
],
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"boundaries",
"import"
],
"rules": {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": "error",
"boundaries/element-types": [
2,
{
"default": "disallow",
"rules": [
{
"allow": [
"website"
],
"from": [
"website"
]
},
{
"allow": [
"api",
"adapters",
"core"
],
"from": [
"api"
]
},
{
"allow": [
"adapters",
"core"
],
"from": [
"adapters"
]
},
{
"allow": [
"core"
],
"from": [
"core"
]
}
]
}
],
"import/no-default-export": "error",
"import/no-useless-path-segments": "error",
"no-restricted-syntax": [
"error",
{
"message": "Default exports are forbidden. Use named exports instead.",
"selector": "ExportDefaultDeclaration"
},
{
"message": "Interface names should not start with 'I'. Use descriptive names without the 'I' prefix (e.g., 'LiverCompositor' instead of 'ILiveryCompositor').",
"selector": "TSInterfaceDeclaration[id.name=/^I[A-Z]/]"
}
]
}
},
{
"files": [
"core/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"message": "Default exports are forbidden. Use named exports instead.",
"selector": "ExportDefaultDeclaration"
}
]
}
},
{
"files": [
"apps/website/**/*.tsx",
"apps/website/**/*.ts"
],
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"message": "Imports from @core are forbidden in website components",
"name": "@core/racing"
},
{
"message": "Imports from @core are forbidden in website components",
"name": "@core/analytics"
},
{
"message": "Imports from @core are forbidden in website components",
"name": "@core/identity"
},
{
"message": "Imports from @core are forbidden in website components",
"name": "@core/media"
},
{
"message": "Imports from @core are forbidden in website components",
"name": "@core/notifications"
},
{
"message": "Imports from @core are forbidden in website components",
"name": "@core/payments"
},
{
"message": "Imports from @core are forbidden in website components",
"name": "@core/shared"
},
{
"message": "Imports from @core are forbidden in website components",
"name": "@core/social"
},
{
"message": "Imports from @adapters are forbidden in website components",
"name": "@adapters"
},
{
"message": "Imports from @api are forbidden in website components",
"name": "@api"
}
],
"patterns": [
{
"group": [
"@core/*"
],
"message": "Imports from @core are forbidden in website components"
},
{
"group": [
"@adapters/*"
],
"message": "Imports from @adapters are forbidden in website components"
},
{
"group": [
"@api/*"
],
"message": "Imports from @api are forbidden in website components"
}
]
}
],
"no-restricted-syntax": [
"error",
{
"message": "ViewModel types must be defined in apps/website/lib/view-models, not in components.",
"selector": "TSInterfaceDeclaration[id.name=/ViewModel$/], TSTypeAliasDeclaration[id.name=/ViewModel$/], TSClassDeclaration[id.name=/ViewModel$/]"
},
{
"message": "DTO types are forbidden in website components. Use ViewModels instead.",
"selector": "TSInterfaceDeclaration[id.name=/DTO$/], TSTypeAliasDeclaration[id.name=/DTO$/], TSClassDeclaration[id.name=/DTO$/]"
}
]
}
},
{
"files": [
"apps/api/**/*.test.ts",
"apps/api/**/*.test.tsx"
],
"rules": {
"@typescript-eslint/no-explicit-any": "error",
"no-restricted-syntax": "error"
}
},
{
"files": [
"tests/**/*.ts"
],
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"message": "Integration tests must use in-memory adapters, not core directly",
"name": "@core/*"
},
{
"message": "Integration tests must use in-memory adapters only",
"name": "@adapters/*"
}
]
}
]
}
},
{
"files": [
"tests/e2e/**/*.ts"
],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": [
"**/inmemory/**"
],
"message": "E2E tests must use TypeORM/PostgreSQL, not in-memory adapters"
}
]
}
]
}
},
{
"files": [
"core/**/*.ts"
],
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"message": "Use @testing/* from adapters/testing",
"name": "testing"
},
{
"message": "Core layer should not depend on testing utilities",
"name": "@testing/*"
}
]
}
]
}
},
{
"files": [
"adapters/**/*.ts"
],
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"message": "Use @testing/* from adapters/testing",
"name": "testing"
}
]
}
]
}
}
],
"parserOptions": {
"ecmaVersion": 2022,
"sourceType": "module"
},
"settings": {
"boundaries/elements": [
{
"pattern": "apps/website/**/*",
"type": "website"
},
{
"pattern": "apps/api/**/*",
"type": "api"
},
{
"pattern": [
"adapters/**/*",
"@adapters/**/*"
],
"type": "adapters"
},
{
"pattern": [
"core/**/*",
"@core/**/*"
],
"type": "core"
}
],
"import/resolver": {
"typescript": {}
}
}
}