import js from '@eslint/js'; import prettier from 'eslint-config-prettier'; import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript'; import importX from 'eslint-plugin-import-x'; import turbo from 'eslint-plugin-turbo'; import globals from 'globals'; import tseslint from 'typescript-eslint'; /** * Base flat config: TypeScript rules + import hygiene + the architectural * boundary rules that every package in the workspace must obey. * * @type {import("eslint").Linter.Config[]} */ export const baseConfig = [ { ignores: [ '**/dist/**', '**/build/**', '**/.next/**', '**/.turbo/**', '**/coverage/**', '**/node_modules/**', '**/generated/**', ], }, js.configs.recommended, ...tseslint.configs.recommended, importX.flatConfigs.recommended, importX.flatConfigs.typescript, turbo.configs['flat/recommended'], { languageOptions: { ecmaVersion: 2023, globals: { ...globals.node, ...globals.es2021 }, }, settings: { // TypeScript resolver first: it understands `.ts` extensionless imports, // path aliases and workspace `exports` maps. The node resolver is the // fallback for plain JS config files. 'import-x/resolver-next': [ createTypeScriptImportResolver({ alwaysTryTypes: true, project: ['*/tsconfig.json'] }), importX.createNodeResolver(), ], }, rules: { // --- Type safety ------------------------------------------------- '@typescript-eslint/no-unused-vars': [ 'error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' }, ], '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/consistent-type-imports': [ 'error', { prefer: 'type-imports', fixStyle: 'inline-type-imports' }, ], // `import type` statements stay with their source group rather than being // herded to the bottom of the file, where they lose the context of what // they belong to. '@typescript-eslint/no-import-type-side-effects': 'error', '@typescript-eslint/no-non-null-assertion': 'warn', // --- Import hygiene ---------------------------------------------- 'import-x/no-default-export': 'error', 'import-x/order': [ 'error', { groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'], pathGroups: [{ pattern: '@sport/**', group: 'internal', position: 'before' }], pathGroupsExcludedImportTypes: ['type'], 'newlines-between': 'always', alphabetize: { order: 'asc', caseInsensitive: true }, }, ], 'import-x/no-cycle': ['error', { maxDepth: 4 }], // --- General ------------------------------------------------------ eqeqeq: ['error', 'smart'], 'no-console': ['error', { allow: ['warn', 'error'] }], 'prefer-const': 'error', 'object-shorthand': 'error', }, }, { // Config files and scripts are allowed default exports and console output. files: ['**/*.config.{js,mjs,ts}', '**/scripts/**', '**/*.cjs'], rules: { 'import-x/no-default-export': 'off', 'no-console': 'off', }, }, { files: ['**/*.{test,spec}.{ts,tsx}', '**/test/**'], rules: { '@typescript-eslint/no-explicit-any': 'off', 'no-console': 'off', }, }, prettier, ]; export default baseConfig;