import nextPlugin from '@next/eslint-plugin-next'; import tseslint from 'typescript-eslint'; import reactPlugin from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; import jsxA11y from 'eslint-plugin-jsx-a11y'; const nextCoreWebVitalsRules = nextPlugin.configs['core-web-vitals']?.rules ?? {}; export default [ // Ignores { ignores: [ 'node_modules/**', '.next/**', 'out/**', 'build/**', 'dist/**', 'coverage/**', 'src/lib/api/generated/**', 'src/mocks/**', // MSW mock data (demo mode only, not production code) 'public/mockServiceWorker.js', // Auto-generated by MSW '*.gen.ts', '*.gen.tsx', 'next-env.d.ts', // Auto-generated by Next.js 'eslint.config.mjs', // Do not lint the ESLint config itself ], }, // TypeScript recommended (non-type-checked) rules for broader compatibility ...tseslint.configs.recommended, // If you want type-aware linting, uncomment below and switch to `recommendedTypeChecked` // { // files: ['**/*.{ts,tsx}'], // languageOptions: { // parserOptions: { // project: ['./tsconfig.json'], // tsconfigRootDir: new URL('.', import.meta.url).pathname, // }, // }, // }, // Next.js + React rules (Core Web Vitals) { files: ['**/*.{js,jsx,ts,tsx}'], plugins: { '@next/next': nextPlugin, react: reactPlugin, 'react-hooks': reactHooks, 'jsx-a11y': jsxA11y, }, settings: { react: { version: 'detect', }, }, rules: { ...nextCoreWebVitalsRules, }, }, // Base rules for source code { files: ['src/**/*.{ts,tsx}'], rules: { // Enforce Dependency Injection pattern for auth store // Components/hooks must use useAuth() from AuthContext, not useAuthStore directly // This ensures testability via DI (E2E mocks, unit test props) // Exception: Non-React contexts (client.ts) use dynamic import + __TEST_AUTH_STORE__ check 'no-restricted-imports': [ 'error', { patterns: [ { group: ['**/stores/authStore'], importNames: ['useAuthStore'], message: "Import useAuth from '@/lib/auth/AuthContext' instead. Direct authStore imports bypass dependency injection and break test mocking.", }, ], }, ], }, }, // Relaxed rules for test files { files: ['tests/**/*.{ts,tsx}', '**/*.test.{ts,tsx}', '**/*.spec.{ts,tsx}'], rules: { '@typescript-eslint/no-explicit-any': 'off', // Test mocks often need any '@typescript-eslint/no-require-imports': 'off', // Jest sometimes needs require 'react/display-name': 'off', // Mock components don't need display names 'no-restricted-imports': 'off', // Tests can import store directly '@typescript-eslint/no-unused-vars': [ 'error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_', }, ], }, }, // Relaxed rules for E2E tests { files: ['e2e/**/*.{ts,tsx}'], rules: { '@typescript-eslint/no-explicit-any': 'off', // Playwright helpers need flexibility '@typescript-eslint/no-unused-vars': [ 'error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_', }, ], }, }, // Relaxed rules for scripts and config files { files: ['scripts/**/*.{ts,js}', '*.config.{ts,js,mjs}', 'jest.setup.js'], rules: { '@typescript-eslint/no-explicit-any': 'off', // Build scripts need flexibility '@typescript-eslint/no-require-imports': 'off', // CommonJS configs '@next/next/no-assign-module-variable': 'off', // Scripts may need module.exports '@typescript-eslint/no-unused-vars': [ 'error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_', }, ], }, }, ];