eslint.config.mjs
Rama main · réplica de lectura del repositorio original.
import { createRequire } from "node:module";
import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
import tsParser from "@typescript-eslint/parser";
const require = createRequire(import.meta.url);
/** @type {import('eslint').Linter.Config[]} */
const config = [
...nextCoreWebVitals,
{
// `.claude/**` is git-ignored for the same reason it belongs here: it holds
// agent worktrees, each a full checkout with its own `.next` and
// `node_modules`. Those nested build outputs don't match the bare `.next/**`
// pattern above, so linting the repo meant linting minified bundles - a few
// hundred errors about someone else's generated code, in a script that is
// supposed to fail only for ours.
ignores: [
".next/**",
"out/**",
"node_modules/**",
"coverage/**",
".claude/**",
"public/maplibre/**",
"test-results/**",
"playwright-report/**",
".vitest/**",
],
},
{
// First half of what `eslint-config-next` needs to run under ESLint 10.
// The preset sets `settings.react.version = "detect"`, and that string is
// the only thing that sends `eslint-plugin-react` down `detectReactVersion()`,
// which reads `context.getFilename()` - removed in v10. Naming a version
// skips the branch outright, so the plugin's rules keep working; nothing
// here disables them. Read from React's own manifest rather than typed as a
// literal, because a hardcoded "19" is a figure that goes stale silently the
// next time React majors and nothing would fail to tell us.
settings: { react: { version: require("react/package.json").version } },
},
{
// Second half. Everything the preset does not hand to `@typescript-eslint`
// it parses with `eslint-config-next/parser`, a re-export of Next's compiled
// `@babel/eslint-parser`, whose `ScopeManager` predates v10's `addGlobals` -
// and the preset declares over a thousand globals, so v10 calls it on every
// such file and throws. Routing them through the TypeScript parser avoids it.
// `.mts` and `.cts` are in this list because they are not: they are
// TypeScript, but the preset's TS block does not claim them, so they reached
// the Babel parser and were the last two files still failing.
// The cost is that `next/babel`-specific syntax would no longer parse in a
// plain `.js` file. Nothing here is such a file - these are config and
// `scripts/*.mjs` - so it costs nothing today, and would announce itself
// loudly rather than silently if that changed.
files: ["**/*.{js,mjs,cjs,jsx,mts,cts}"],
languageOptions: {
parser: tsParser,
parserOptions: { ecmaFeatures: { jsx: true } },
},
},
{
rules: {
"react/no-unescaped-entities": "off",
// Guardrail against XSS: `dangerouslySetInnerHTML` bypasses React's
// default output escaping, so introducing it (e.g. to render
// markdown/rich text) needs a deliberate `eslint-disable` plus a
// sanitizer (e.g. DOMPurify/rehype-sanitize), not an unreviewed add.
"react/no-danger": "error",
},
},
];
export default config;