import js from "@eslint/js"; import tseslint from "typescript-eslint"; import reactHooks from "eslint-plugin-react-hooks"; import reactRefresh from "eslint-plugin-react-refresh"; import globals from "globals"; import prettier from "eslint-config-prettier"; export default tseslint.config( { ignores: [ "dist/**", "dist-client/**", "node_modules/**", "prisma/migrations/**", "src/admin/bones/**", "*.config.js", "*.config.mjs", "*.config.ts", ".claude/**", ], }, js.configs.recommended, ...tseslint.configs.recommended, { // Server + shared code files: ["src/**/*.{ts,tsx}", "scripts/**/*.ts", "prisma/seed.ts"], languageOptions: { globals: { ...globals.node, ...globals.browser }, }, rules: { // TS already resolves identifiers — `no-undef` only false-positives on // global types/ambient names in .ts files. "no-undef": "off", "@typescript-eslint/no-explicit-any": "warn", "@typescript-eslint/no-unused-vars": [ "warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }, ], "@typescript-eslint/no-require-imports": "warn", "no-empty": ["warn", { allowEmptyCatch: false }], // Intentional control-character regexes (NUL/path-traversal guards, // combining-marks stripping) — not a defect here. "no-control-regex": "off", // Stylistic / advisory — surface as warnings, don't fail the lint gate. "no-useless-escape": "warn", "no-useless-assignment": "warn", "preserve-caught-error": "warn", "prefer-const": "warn", }, }, { // Frontend React code files: ["src/admin/**/*.{ts,tsx}", "src/**/*.tsx"], plugins: { "react-hooks": reactHooks, "react-refresh": reactRefresh, }, rules: { "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn", }, }, { // Plain Node helper scripts (.js/.mjs/.cjs in scripts/) files: ["scripts/**/*.{js,mjs,cjs}"], languageOptions: { globals: { ...globals.node } }, rules: { "no-undef": "off" }, }, { // Tests files: ["src/__tests__/**/*.ts"], languageOptions: { globals: { ...globals.node } }, rules: { "@typescript-eslint/no-explicit-any": "off", }, }, prettier, );