// ESLint flat config for Next.js 16 // Note: Using a workaround for FlatCompat circular reference issue // For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format import storybook from "eslint-plugin-storybook"; import js from "@eslint/js"; import tseslint from "@typescript-eslint/eslint-plugin"; import tsparser from "@typescript-eslint/parser"; import nextPlugin from "@next/eslint-plugin-next"; import globals from "globals"; import react from "eslint-plugin-react"; import reactHooks from "eslint-plugin-react-hooks"; const eslintConfig = [ // Base JavaScript recommended rules js.configs.recommended, // Storybook config ...storybook.configs["flat/recommended"], // Global ignores { ignores: [ ".next/**", "node_modules/**", "dist/**", "build/**", "coverage/**", "storybook-static/**", "playwright-report/**", "test-results/**", "lhci-results/**", "docs/**", ], }, // JavaScript files configuration { files: ["**/*.{js,jsx}"], languageOptions: { ecmaVersion: "latest", sourceType: "module", globals: { ...globals.node, ...globals.browser, ...globals.es2021, React: "readonly", }, parserOptions: { ecmaFeatures: { jsx: true, }, }, }, plugins: { react, "react-hooks": reactHooks, }, settings: { react: { version: "detect", }, }, rules: { ...react.configs.recommended.rules, ...reactHooks.configs.recommended.rules, "react/react-in-jsx-scope": "off", // React 19 doesn't require React import "react/prop-types": "off", // Using TypeScript for prop validation }, }, // TypeScript files configuration { files: ["**/*.{ts,tsx}"], languageOptions: { parser: tsparser, globals: { ...globals.node, ...globals.browser, ...globals.es2021, React: "readonly", process: "readonly", }, parserOptions: { ecmaVersion: "latest", sourceType: "module", ecmaFeatures: { jsx: true, }, project: "./tsconfig.json", }, }, plugins: { "@typescript-eslint": tseslint, "@next/next": nextPlugin, react, "react-hooks": reactHooks, }, settings: { react: { version: "detect", }, }, rules: { ...react.configs.recommended.rules, ...reactHooks.configs.recommended.rules, "react/react-in-jsx-scope": "off", // React 19 doesn't require React import "react/prop-types": "off", // Using TypeScript for prop validation "@typescript-eslint/no-unused-vars": [ "error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_", caughtErrorsIgnorePattern: "^_", }, ], "no-unused-vars": [ "error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_", caughtErrorsIgnorePattern: "^_", }, ], "@typescript-eslint/no-explicit-any": "warn", // Next.js rules "@next/next/no-html-link-for-pages": "off", "@next/next/no-img-element": "warn", }, }, // All files - basic rules { files: ["**/*.{ts,tsx,js,jsx}"], rules: { // Basic rules "react/no-unescaped-entities": "off", // Default: discourage console usage, but allow warn/error as "standard practice" "no-console": ["warn", { allow: ["warn", "error"] }], }, }, // App/lib code: no console.* (enforced) { files: ["app/**/*.{ts,tsx,js,jsx}", "lib/**/*.{ts,tsx,js,jsx}"], rules: { "no-console": "error", }, }, // Tests/Storybook/scripts: console is acceptable { files: [ "tests/**/*.{ts,tsx,js,jsx}", "stories/**/*.{ts,tsx,js,jsx}", "scripts/**/*.{ts,js}", ], rules: { "no-console": "off", }, }, // Config files - allow Node.js globals { files: ["*.config.{js,mjs,ts}", "scripts/**/*.{js,ts}"], languageOptions: { globals: { ...globals.node, process: "readonly", require: "readonly", console: "readonly", __dirname: "readonly", __filename: "readonly", module: "readonly", exports: "readonly", }, }, }, // Storybook files - disable React hooks rules (render functions are called by Storybook) // This must come AFTER the general rules to override them { files: ["**/*.stories.{js,jsx,ts,tsx}"], rules: { "react-hooks/rules-of-hooks": "off", "react-hooks/exhaustive-deps": "off", }, }, // Type definition files - interface properties are used in implementation files { files: ["**/*.types.ts"], rules: { "no-unused-vars": "off", "@typescript-eslint/no-unused-vars": "off", }, }, ]; export default eslintConfig;