import js from "@eslint/js"; import eslintConfigPrettier from "eslint-config-prettier"; import pluginReactHooks from "eslint-plugin-react-hooks"; import pluginReactRefresh from "eslint-plugin-react-refresh"; import globals from "globals"; import tseslint from "typescript-eslint"; import noNonBooleanJsxAnd from "./eslint-rules/no-non-boolean-jsx-and.js"; import noVpErrorOutsideText from "./eslint-rules/no-vp-error-outside-text.js"; const localRules = { rules: { "no-non-boolean-jsx-and": noNonBooleanJsxAnd, "no-vp-error-outside-text": noVpErrorOutsideText, }, }; const legacyIgnores = [ "src/pages/**", "src/app/store.js", "src/app/slices/**", "src/lib/queryClient.js", "src/hooks/**/*.js", "src/components/*.{js,css}", "src/constants/**", "src/layouts/**", "src/**/*.js", "src/**/*.jsx", ]; export default tseslint.config( { ignores: [ "dist/**", "build/**", "node_modules/**", "coverage/**", "infra/cdk/cdk.out/**", "infra/cdk/bin/**/*.d.ts", "infra/cdk/bin/**/*.js", "infra/cdk/lib/**/*.d.ts", "infra/cdk/lib/**/*.js", ...legacyIgnores, ], }, js.configs.recommended, ...tseslint.configs.recommended, eslintConfigPrettier, { files: [ "src/{api,domain,app,lib,providers,infra,config,hooks,components/auth}/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "vite.config.ts", ], languageOptions: { ecmaVersion: "latest", sourceType: "module", globals: globals.browser, parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname, }, }, plugins: { "react-hooks": pluginReactHooks, "react-refresh": pluginReactRefresh, seahaven: localRules, }, rules: { ...pluginReactHooks.configs.recommended.rules, "react-hooks/set-state-in-effect": "off", "react-hooks/exhaustive-deps": "warn", "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], "@typescript-eslint/no-explicit-any": "warn", "seahaven/no-non-boolean-jsx-and": "error", "seahaven/no-vp-error-outside-text": "error", "no-restricted-syntax": [ "error", { selector: "JSXExpressionContainer > ConditionalExpression[alternate.type='Literal'][alternate.value=null]", message: "Use logical AND for one-sided JSX rendering instead of `condition ? element : null`.", }, { selector: ":matches(JSXOpeningElement[name.name='p'], JSXOpeningElement[name.name='h1'], JSXOpeningElement[name.name='h2'], JSXOpeningElement[name.name='h3'], JSXOpeningElement[name.name='h4'], JSXOpeningElement[name.name='h5'], JSXOpeningElement[name.name='h6'])", message: "Use the shared Text component so typography semantics, family, tone, and feedback behavior stay consistent.", }, ], }, }, { files: ["vite.config.ts", "scripts/**/*.{js,mjs}"], languageOptions: { globals: globals.node, }, }, );