eslint.config.js
Rama main · réplica de lectura del repositorio original.
import js from '@eslint/js'
import globals from 'globals'
import reactPlugin from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import tseslint from 'typescript-eslint'
// Vitest injects these into the global scope (`globals: true` in every SPA's
// vite.config test block). The `globals` package has no vitest set, so name them.
const TEST_GLOBALS = {
describe: 'readonly',
it: 'readonly',
test: 'readonly',
expect: 'readonly',
vi: 'readonly',
vitest: 'readonly',
beforeAll: 'readonly',
afterAll: 'readonly',
beforeEach: 'readonly',
afterEach: 'readonly',
}
export default [
{
// Build output, vendored code, and trees other seats own. `eslint .` from
// the repo root would otherwise reach into the Python package and the
// clients/ workspaces. The Desktop track lints `clients/desktop/**/*.ts`
// via the appended block near the end of this file; everything else under
// `clients/` stays out (the Rust/Tauri crate, the VR client).
ignores: [
'**/dist/**',
'**/build/**',
'**/coverage/**',
'**/node_modules/**',
// Workspace-local board/skill code and generated review/staging
// artifacts are private tooling, not repository lint targets. A local
// `eslint .` should match the clean-checkout CI surface.
'.agents/**',
'.artifacts/**',
'docs/_private/**',
// Local Python virtualenvs ship bundled JS (werkzeug debugger, urllib3
// emscripten worker) that `eslint .` would otherwise lint. CI has no venv;
// ignore it so `npm run lint` matches CI when run in a dev checkout.
'**/venv/**',
'**/.venv/**',
'**/*.min.js',
'oneirodex/**',
'scripts/**',
'clients/quest/**',
'clients/desktop/src-tauri/**',
// Standalone node harnesses for the classic (Jinja) theme JS. CI runs
// them with `node` directly; they are not part of any SPA and predate
// this seat's scope.
'tests/**',
// Generated — the source of truth is scripts/gen_loading_motifs.py.
'frontend/member-app/src/components/systemMotifCatalogue.ts',
],
},
js.configs.recommended,
// Member / admin / ops React SPAs, plus the shared frontend modules.
{
files: ['frontend/**/*.{js,jsx,mjs,cjs}'],
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',
parserOptions: { ecmaFeatures: { jsx: true } },
globals: { ...globals.browser },
},
plugins: { react: reactPlugin, 'react-hooks': reactHooks },
settings: { react: { version: 'detect' } },
rules: {
...reactPlugin.configs.flat.recommended.rules,
...reactPlugin.configs.flat['jsx-runtime'].rules,
// rules-of-hooks catches real bugs — keep it hard. exhaustive-deps is
// advisory (Phase 3 tightens it). The rest of react-hooks v7's compiler
// ruleset is deliberately not enabled here.
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
// The SPAs do not use PropTypes; TypeScript on-ramp (B0.3) is the type gate.
'react/prop-types': 'off',
// `_`-prefixed names are the codebase's "deliberately unused" marker
// (e.g. `{ shellConfig: _shellConfig }`, `catch (_err)`).
'no-unused-vars': [
'warn',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' },
],
'no-undef': 'error',
},
},
// Frontend test, setup, and Vite config files run under Node with Vitest
// globals in scope.
{
files: [
'frontend/**/*.{test,spec}.{js,jsx}',
'frontend/**/testSetup.{js,ts}',
'frontend/**/vite.config.js',
'frontend/**/*.config.{js,mjs}',
],
languageOptions: { globals: { ...globals.node, ...TEST_GLOBALS } },
},
// TypeScript surface owned by this seat: the shared API client. Uses
// typescript-eslint's non-type-checked recommended set (no project graph, so
// it stays fast). The Tauri companion (also TS) is linted from the Desktop
// track with this same block shape.
...tseslint.config({
files: ['frontend/api-client/**/*.{ts,tsx}'],
extends: [tseslint.configs.recommended],
languageOptions: {
globals: { ...globals.browser, ...globals.node },
},
rules: {
'@typescript-eslint/no-unused-vars': 'warn',
// Off on purpose: ~1,077 sites would drown the warnings that matter. The
// gate is scripts/any_lint.mjs (per-file baseline, CI-run, only moves
// down). Flip to 'error' when that baseline reaches 0.
'@typescript-eslint/no-explicit-any': 'off',
// tsc resolves identifiers and types; core no-undef only produces false
// positives on a TS surface.
'no-undef': 'off',
},
}),
{
files: ['frontend/api-client/**/*.{test,spec}.ts'],
languageOptions: { globals: { ...TEST_GLOBALS } },
},
// TypeScript surface owned by this seat: `@oneirodex/ui` (frontend/shared),
// ops-glance, and member-app (PR-5a). Same non-type-checked recommended set
// as the api-client block above, plus the React plugins because these files
// carry components/hooks.
...tseslint.config({
files: [
'frontend/shared/**/*.{ts,tsx}',
'frontend/ops-glance/**/*.{ts,tsx}',
'frontend/member-app/**/*.{ts,tsx}',
'frontend/admin-app/**/*.{ts,tsx}',
],
extends: [tseslint.configs.recommended],
plugins: { react: reactPlugin, 'react-hooks': reactHooks },
settings: { react: { version: 'detect' } },
languageOptions: {
globals: { ...globals.browser, ...globals.node },
},
rules: {
...reactPlugin.configs.flat.recommended.rules,
...reactPlugin.configs.flat['jsx-runtime'].rules,
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'react/prop-types': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' },
],
// Off on purpose: ~1,077 sites would drown the warnings that matter. The
// gate is scripts/any_lint.mjs (per-file baseline, CI-run, only moves
// down). Flip to 'error' when that baseline reaches 0.
'@typescript-eslint/no-explicit-any': 'off',
'no-undef': 'off',
},
}),
// --- Desktop track (clients/desktop) --------------------------------------
// Appended by the Desktop seat (wave C3.7-client / ci-wishlist [B0.2]).
// Mirrors the frontend/api-client block: typescript-eslint's non-type-checked
// recommended set over the Tauri companion's TS. Same rule tweaks so the two
// TS surfaces lint identically.
...tseslint.config({
files: ['clients/desktop/**/*.{ts,tsx}'],
extends: [tseslint.configs.recommended],
languageOptions: {
globals: { ...globals.browser, ...globals.node },
},
rules: {
'@typescript-eslint/no-unused-vars': 'warn',
// Off on purpose: ~1,077 sites would drown the warnings that matter. The
// gate is scripts/any_lint.mjs (per-file baseline, CI-run, only moves
// down). Flip to 'error' when that baseline reaches 0.
'@typescript-eslint/no-explicit-any': 'off',
'no-undef': 'off',
},
}),
{
files: ['clients/desktop/**/*.{test,spec}.ts'],
languageOptions: { globals: { ...TEST_GLOBALS } },
},
// Repo-root tooling files (this config included).
{
files: ['*.js', '*.mjs'],
languageOptions: { sourceType: 'module', globals: { ...globals.node } },
},
]