Skip to content

chore: replace ESLint with oxlint (type-aware) and run lint in CI - #845

Open
jhuleatt wants to merge 1 commit into
mainfrom
chore/oxlint
Open

jhuleatt wants to merge 1 commit into
mainfrom
chore/oxlint

Conversation

@jhuleatt

Copy link
Copy Markdown
Collaborator

Summary

Replaces ESLint 8 and its plugins (@typescript-eslint v5, eslint-plugin-react, eslint-plugin-react-hooks v4, eslint-plugin-no-only-tests) with oxlint, including type-aware linting via oxlint-tsgolint. Also runs npm run lint in the test workflow before the tests.

On main, npm run lint currently fails (a require() in test/setupTests.ts), which is presumably why it wasn't in CI.

Rules

.oxlintrc.json lists rules explicitly. oxlint's categories are turned off, so upgrading oxlint doesn't change what's enforced. It's a rule-by-rule port of the latest recommended presets, keeping this repo's existing warn-level overrides:

  • ESLint recommended (minus the rules TypeScript already checks)
  • typescript-eslint recommended
  • eslint-plugin-react recommended (classic JSX runtime, matching "jsx": "react" in tsconfig)
  • eslint-plugin-react-hooks v7 recommended, including the React Compiler rules
  • vitest/no-focused-tests instead of eslint-plugin-no-only-tests

Type-aware rules from typescript-eslint's recommended-type-checked:

  • no-floating-promises, no-misused-promises, await-thenable, unbound-method, only-throw-error (promises allowed, for Suspense) and the rest of that preset are errors.
  • no-redundant-type-constituents, no-unnecessary-type-assertion and restrict-template-expressions have existing findings, so they're warnings for now. They can become errors once those are cleaned up.
  • no-deprecated (warning) replaces react/no-deprecated. It flags anything marked @deprecated in its types (e.g. RxJS's toPromise and empty, Vite 8's rollupOptions).
  • The no-unsafe-* rules are off. They flag every use of the any values that no-explicit-any already allows as a warning. require-await is off too (stylistic).

Not ported:

  • react/prop-types: TypeScript covers it.
  • react/jsx-uses-react and react/jsx-uses-vars: oxlint's no-unused-vars already handles JSX.
  • no-octal and no-dupe-args: strict mode covers them.
  • react/require-render-return and no-useless-assignment: still experimental in oxlint.

Code changes for new findings

  • test/setupTests.ts: require → import.
  • test/sdk.test.tsx, test/firebaseApp.test.tsx: await deleteApp in afterEach (no-misused-promises).
  • src/performance.tsx: suppressed react/static-components with a TODO. SuspenseWithPerf creates its fallback component during render, so React remounts it, and records an extra measure, whenever it re-renders while suspended. Fixing that changes runtime behavior, so it's left for a follow-up.
  • Disable comments for one intentional pattern in a test (react/globals) and one false positive (only-throw-error: error is always set when status === 'error').
  • test/tsconfig.json (extends tsconfig.test.json): type-aware rules use the nearest tsconfig.json, so without it, test files fell back to defaults (e.g. vi resolved to an error type). Editors pick it up too.
  • docs/reference: regenerated for a line number shift.
  • CONTRIBUTING.md: npm run lint --fix doesn't pass --fix through; changed it to npm run lint -- --fix.

Results

  • npm run lint: 0 errors, 89 warnings, ~0.3s (ESLint took ~2s).
  • Lockfile: 98 packages removed, oxlint and oxlint-tsgolint added (plus their platform binaries).
  • Locally: tsc (src and tests), the full emulator test suite, npm run docs, and npm ci + lint on Node 22 and 24 all pass.

Replace ESLint 8, @typescript-eslint v5, eslint-plugin-react,
eslint-plugin-react-hooks and eslint-plugin-no-only-tests with oxlint,
including type-aware rules via oxlint-tsgolint.

- .oxlintrc.json ports the current recommended presets (ESLint,
  typescript-eslint, eslint-plugin-react, eslint-plugin-react-hooks v7
  including the React Compiler rules) rule by rule, keeping the existing
  warn-level overrides. Categories are off so oxlint upgrades don't change
  what's enforced.
- Add typescript-eslint's recommended-type-checked rules. Rules with
  existing findings are warnings for now; the no-unsafe-* rules and
  require-await stay off. typescript/no-deprecated (warn) replaces
  react/no-deprecated.
- vitest/no-focused-tests replaces eslint-plugin-no-only-tests.
- Add test/tsconfig.json so type-aware rules (which use the nearest
  tsconfig.json) resolve test files with the test compiler settings.
- Fix findings: require -> import in test/setupTests.ts (already failing
  lint on main), and await deleteApp in two afterEach hooks.
- Suppress react/static-components in SuspenseWithPerf with a TODO
  (fixing it changes runtime behavior), plus one intentional pattern in a
  test and one only-throw-error false positive.
- Run `npm run lint` in the test workflow before the tests.
- Fix the `npm run lint -- --fix` instruction in CONTRIBUTING.md.
- Regenerate reference docs (line number shift).
@jhuleatt
jhuleatt requested a review from tyler-reitz October 28, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant