import eslint from '@eslint/js'; import nextPlugin from '@next/eslint-plugin-next'; import pluginQuery from '@tanstack/eslint-plugin-query'; import parser from '@typescript-eslint/parser'; import importPlugin from 'eslint-plugin-import'; import prettierPlugin from 'eslint-plugin-prettier/recommended'; import pluginReact from 'eslint-plugin-react'; import reactCompiler from 'eslint-plugin-react-compiler'; import pluginReactHooks from 'eslint-plugin-react-hooks'; import globals from 'globals'; import tseslint from 'typescript-eslint'; /** @type {import("eslint").Linter.Config} */ export default [ eslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, prettierPlugin, { plugins: { import: importPlugin, }, rules: { 'import/no-default-export': 'warn', }, }, { languageOptions: { parserOptions: { projectService: true, // EXPERIMENTAL_useProjectService: true, // project: ['./tsconfig.json', './apps/*/tsconfig.json', './packages/*/tsconfig.json'], }, }, rules: { // custom rules 'arrow-body-style': 'off', 'prefer-arrow-callback': 'off', 'no-debugger': 'warn', 'prefer-const': 'warn', 'prettier/prettier': ['warn', {}, { usePrettierrc: true }], // typescript-eslint rules '@typescript-eslint/interface-name-prefix': 'off', '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-explicit-any': 'warn', '@typescript-eslint/no-unnecessary-type-assertion': 'error', '@typescript-eslint/consistent-type-assertions': ['warn', { assertionStyle: 'as' }], '@typescript-eslint/no-unsafe-type-assertion': 'error', '@typescript-eslint/no-unused-vars': [ 'warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', }, ], '@typescript-eslint/no-misused-promises': 'error', '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/require-await': 'warn', // it's dying in CI, so warn for now // '@typescript-eslint/no-redundant-type-constituents': 'warn', // reenable later - start with warn // '@typescript-eslint/no-unsafe-return': 'off', // '@typescript-eslint/no-unsafe-assignment': 'off', // '@typescript-eslint/no-unsafe-member-access': 'off', // '@typescript-eslint/no-unsafe-call': 'off', // '@typescript-eslint/no-unsafe-argument': 'off', // '@typescript-eslint/restrict-template-expressions': 'off', }, }, { files: ['**/*.spec.ts', '**/*.test.ts', '**/*.spec.tsx', '**/*.test.tsx'], rules: { '@typescript-eslint/no-unsafe-return': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-argument': 'off', '@typescript-eslint/restrict-template-expressions': 'off', '@typescript-eslint/no-unnecessary-type-assertion': 'off', '@typescript-eslint/consistent-type-assertions': 'off', '@typescript-eslint/no-unsafe-type-assertion': 'off', '@typescript-eslint/require-await': 'off', }, }, { files: ['**/*.js', '**/*.cjs', '**/*.mjs'], rules: { ...tseslint.configs.disableTypeChecked, }, }, { ignores: [ 'dist/**', 'node_modules', '.next', '.prettierrc.*js', 'postcss.config.*js', 'tailwind.config.*js', 'eslint.config.*js', 'next-sitemap.config.*js', 'next.config.*js', 'packages/config/eslint/**.js', ], }, ...pluginQuery.configs['flat/recommended'], { files: ['**/*.{js,jsx,ts,tsx}'], plugins: { '@next/next': nextPlugin }, rules: { ...nextPlugin.configs['core-web-vitals'].rules }, }, { ...pluginReact.configs.flat.recommended, languageOptions: { ...pluginReact.configs.flat.recommended.languageOptions, globals: { ...globals.serviceworker, ...globals.browser, ...globals.node, }, }, }, { plugins: { 'react-hooks': pluginReactHooks }, settings: { react: { version: 'detect' } }, rules: { ...pluginReactHooks.configs.recommended.rules, // React scope no longer necessary with new JSX transform. 'react/react-in-jsx-scope': 'off', }, }, reactCompiler.configs.recommended, { rules: { 'react-compiler/react-compiler': 'error' }, }, { languageOptions: { parser, parserOptions: { ecmaVersion: 'latest', sourceType: 'module', ecmaFeatures: { jsx: true } }, }, }, // overrides { files: ['**/*.{js,jsx,ts,tsx}'], rules: { 'no-restricted-syntax': [ 'warn', { selector: "CallExpression[callee.name='unwrap']", message: 'Handle errors instead of unwrapping!' }, ], '@typescript-eslint/no-misused-promises': [ 'error', { checksVoidReturn: { arguments: false, attributes: false } }, ], '@typescript-eslint/no-floating-promises': ['error', { ignoreIIFE: true, ignoreVoid: true }], 'react/no-unescaped-entities': 'off', }, }, { files: ['src/app/**/{page,layout,not-found,default,loading,global-error,error}.tsx'], rules: { 'import/no-default-export': 'off', '@typescript-eslint/require-await': 'off', }, }, { files: ['src/app/**/routeType.ts'], rules: { '@typescript-eslint/no-unused-vars': [ 'warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_|^Route', destructuredArrayIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', }, ], }, }, { files: ['next.config.ts'], rules: { '@typescript-eslint/no-unsafe-type-assertion': 'off', 'import/no-default-export': 'off' }, }, { files: ['prisma.config.ts'], rules: { 'import/no-default-export': 'off' }, }, { ignores: ['next-env.d.ts', 'gen/**/*', 'src/generated/**'] }, ];