eslint.config.js 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. import js from '@eslint/js'
  2. import globals from 'globals'
  3. import tseslint from 'typescript-eslint'
  4. import reactHooks from 'eslint-plugin-react-hooks'
  5. import reactRefresh from 'eslint-plugin-react-refresh'
  6. export default tseslint.config(
  7. { ignores: ['dist', 'playwright-report', 'test-results'] },
  8. // App source + tests: TypeScript + React, browser globals.
  9. {
  10. files: ['**/*.{ts,tsx}'],
  11. extends: [js.configs.recommended, ...tseslint.configs.recommended],
  12. languageOptions: {
  13. ecmaVersion: 2022,
  14. globals: globals.browser,
  15. },
  16. plugins: {
  17. 'react-hooks': reactHooks,
  18. 'react-refresh': reactRefresh,
  19. },
  20. rules: {
  21. // Stable, battle-tested hooks rules (the newer plugin's `recommended`
  22. // also ships experimental rules that false-positive on legitimate
  23. // reset-state-on-open patterns, so enable the classic two explicitly).
  24. 'react-hooks/rules-of-hooks': 'error',
  25. 'react-hooks/exhaustive-deps': 'warn',
  26. 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
  27. // The codebase intentionally avoids `any` (see CLAUDE.md); keep that enforced.
  28. '@typescript-eslint/no-explicit-any': 'error',
  29. '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
  30. },
  31. },
  32. // Config / Node-side files: Node globals (e.g. __dirname in vite.config.ts).
  33. {
  34. files: ['*.config.{ts,js}', 'vite.config.ts', 'playwright.config.ts'],
  35. languageOptions: {
  36. globals: globals.node,
  37. },
  38. },
  39. )