import { FlatCompat } from '@eslint/eslintrc'; import js from '@eslint/js'; import typescriptEslint from '@typescript-eslint/eslint-plugin'; import typescriptParser from '@typescript-eslint/parser'; import prettier from 'eslint-config-prettier'; import importPlugin from 'eslint-plugin-import'; import jestDom from 'eslint-plugin-jest-dom'; import jsxA11y from 'eslint-plugin-jsx-a11y'; import react from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; import testingLibrary from 'eslint-plugin-testing-library'; import { dirname } from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const compat = new FlatCompat({ baseDirectory: __dirname, }); const eslintConfig = [ js.configs.recommended, ...compat.extends('next/core-web-vitals', 'next/typescript'), { files: ['**/*.{js,jsx,ts,tsx}'], plugins: { '@typescript-eslint': typescriptEslint, react, 'react-hooks': reactHooks, 'jsx-a11y': jsxA11y, import: importPlugin, }, languageOptions: { parser: typescriptParser, parserOptions: { ecmaVersion: 'latest', sourceType: 'module', ecmaFeatures: { jsx: true, }, }, }, settings: { react: { version: 'detect', }, 'import/resolver': { typescript: { alwaysTryTypes: true, }, node: { extensions: ['.js', '.jsx', '.ts', '.tsx'], }, }, }, rules: { // TypeScript specific rules '@typescript-eslint/no-unused-vars': [ 'error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }, ], '@typescript-eslint/no-explicit-any': 'warn', '@typescript-eslint/prefer-as-const': 'error', '@typescript-eslint/no-non-null-assertion': 'warn', // React specific rules 'react/react-in-jsx-scope': 'off', // Not needed in Next.js 'react/prop-types': 'off', // Using TypeScript 'react/jsx-uses-react': 'off', // Not needed in Next.js 'react/jsx-uses-vars': 'error', 'react/jsx-key': 'error', 'react/jsx-no-duplicate-props': 'error', 'react/jsx-no-undef': 'error', 'react/no-children-prop': 'error', 'react/no-danger-with-children': 'error', 'react/no-deprecated': 'error', 'react/no-direct-mutation-state': 'error', 'react/no-find-dom-node': 'error', 'react/no-is-mounted': 'error', 'react/no-render-return-value': 'error', 'react/no-string-refs': 'error', 'react/no-unescaped-entities': 'error', 'react/no-unknown-property': 'error', 'react/require-render-return': 'error', 'react/self-closing-comp': 'error', // React Hooks rules 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn', // Import rules 'import/order': [ 'error', { groups: ['builtin', 'external', 'internal', ['parent', 'sibling'], 'index'], 'newlines-between': 'always', alphabetize: { order: 'asc', caseInsensitive: true, }, }, ], 'import/no-duplicates': 'error', 'import/no-unresolved': 'error', 'import/no-cycle': 'error', // General rules 'no-console': 'warn', 'no-debugger': 'error', 'no-alert': 'error', 'no-var': 'error', 'prefer-const': 'error', 'no-unused-expressions': 'error', 'no-duplicate-imports': 'error', }, }, { files: ['**/__tests__/**/*', '**/*.{test,spec}.{js,jsx,ts,tsx}'], plugins: { 'testing-library': testingLibrary, 'jest-dom': jestDom, }, rules: { ...testingLibrary.configs.react.rules, ...jestDom.configs.recommended.rules, }, }, prettier, // Must be last to override other configs ]; export default eslintConfig;