Skip to content

Migrate from ESLint to oxlint and reorganize imports - #339

Merged
sroussey merged 6 commits into
mainfrom
claude/oxlint-tsgolint-migration-x9goh5
Sep 1, 2026
Merged

Migrate from ESLint to oxlint and reorganize imports#339
sroussey merged 6 commits into
mainfrom
claude/oxlint-tsgolint-migration-x9goh5

Conversation

@sroussey

@sroussey sroussey commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR replaces the ESLint configuration with oxlint, a faster Rust-based linter, and applies comprehensive import sorting across the codebase to align with the new linting standards.

Key Changes

  • Linting infrastructure: Replaced eslint.config.js with .oxlintrc.json configuration, removing ESLint dependencies in favor of oxlint's faster analysis
  • Import organization: Sorted imports alphabetically across ~200+ files to match oxlint's import ordering rules:
    • Type imports grouped separately
    • Standard library imports before third-party before local imports
    • Consistent alphabetical ordering within groups
  • Build tooling: Updated .prettierrc to set arrowParens: "always" and added bun run lint command to .claude/CLAUDE.md
  • CI/CD: Added oxlint check to GitHub Actions test workflow
  • Storage registry: Reorganized imports in src/config/storageRegistry.ts to reflect new alphabetical ordering across multiple storage schema imports
  • Export organization: Sorted exports in src/index.ts for consistency with new import standards

Implementation Details

The oxlint configuration preserves the rule families from the previous ESLint setup (@typescript-eslint, jsx-a11y, react, react-hooks) while removing rules without oxlint equivalents (eslint-plugin-regexp). The migration maintains the same linting strictness while improving performance through Rust-based analysis.

All import changes are mechanical reorganization with no functional code modifications—the behavior of the application remains identical.

https://claude.ai/code/session_01915bWFf9P9RkSzpYztkFEH

`eslint.config.js` named typescript-eslint, react, jsx-a11y and regexp, but no
`eslint` dependency was installed, no script invoked it and CI never ran it — so
none of those rules had ever fired. It is replaced by `.oxlintrc.json`, an
`oxlint` + `oxlint-tsgolint` pair in devDependencies, a `lint` script and a CI
step, so the rules now actually run.

The rule set is the old config's, expressed in oxlint: `correctness` (a superset
of `typescript-eslint/recommended` here, since that config never pulled in
`js.configs.recommended`) plus the seven `typescript/*` rules outside it, with
`no-unused-vars` and `no-explicit-any` off as before. `unicorn` and `oxc` stay
off — new rule families are worth adopting on their own. `eslint-plugin-regexp`
has no oxlint equivalent and is gone; `no-super-linear-backtracking`, the ReDoS
guard, is the loss with no substitute.

Findings that had accumulated behind the config never running:

- 12 useless regex escapes (autofixed)
- `for…in` over an array in StoreSubmissionTickersTask, now `.entries()`
- `WeakMap<Function, …>` in Form.ts, now `WeakMap<object, …>`
- a stale `@ts-ignore` in EntitySubmission.test.ts that suppressed nothing, and
  a second one promoted to a described `@ts-expect-error`
- eight `@typescript-eslint/no-explicit-any` directives for a rule this config
  leaves off; the two carrying a reason keep it as a plain comment

Type-aware rules run through tsgolint and need no build — `@workglow/*` resolve
through the published `dist/*.d.ts`. The ones the tree does not pass yet are
staged off with the count they report today beside them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01915bWFf9P9RkSzpYztkFEH
`typescript` goes from `^6.0.3` to `^7.0.2`, matching what `oxlint-tsgolint`
targets. It is now an explicit devDependency as well as a peer range: `bunset`
declares a `typescript: ^6.0.3` peer, and without a direct dependency bun
resolves in its favour and quietly keeps 6.0.3 installed.

TypeScript 7 is the native (Go) compiler, so `tsc` here is a different binary
than it was, not just a newer one. `build`, `typecheck-tests`, `format-check`
and `lint` all pass on it, and the 2746-test suite is green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01915bWFf9P9RkSzpYztkFEH
`~7.0.2` rather than `^7.0.2` for the dev dependency: a caret floats onto 7.1
the day it ships, and 7.x is a brand-new compiler, so that is a red CI on a day
nobody touched the code. The peer range stays `^7.0.2` where there is one —
that one describes what consumers may use, not what this repo builds with.

Same resolved version either way (7.0.2); only the declared range changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01915bWFf9P9RkSzpYztkFEH
`prettier-plugin-organize-imports` was never installed here, but it is what libs
used and it cannot survive TypeScript 7 — it drives the TS language service,
which 7 no longer exposes from the `typescript` package, and it responds by
silently formatting nothing. This plugin is Babel-based with no `typescript`
dependency at all, so it is unaffected either way.

It replaces the sorting half only. The pruning half is already covered:
`noUnusedLocals` errors on an unused import at build time.

Checked before adopting, because this plugin hoists imports to the top of the
module and that can move more than whitespace:

- side-effect imports (`import "workglow"`) act as sort barriers — none moved,
  so module evaluation order is unchanged
- no file carries an `organize-imports-ignore` marker here
- no `@license` header and no `@vitest-environment` docblock ended up below an
  import
- `import type` is preserved rather than folded into inline specifiers, which
  the code style requires

291 files re-sorted. build, typecheck-tests, format-check and lint pass, and the
suite is 2746 tests green — the same count as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01915bWFf9P9RkSzpYztkFEH
Replaces `@ianvs/prettier-plugin-sort-imports`, which was picked only because
the upstream organizer cannot run on TypeScript 7 — it drives the TS language
service that 7 no longer exposes from the `typescript` package. This fork
carries its own `@typescript/typescript6` and drives that, so it is the real
organizer rather than a sorter that approximates it.

Two things the sorter could not do:

- It prunes unused imports. This package sets no `noUnusedLocals`, so nothing
  was catching them — `globalServiceRegistry` alone was imported and unused in
  eight modules.
- It merges duplicate imports from one module, which is most of the net -22
  lines here.

63 files rather than the sorter's 291: the orderings differ, and this one is
closer to what the tree already had.

The one behavioural difference to know about is that this plugin sorts
side-effect imports along with everything else rather than treating them as
barriers. The only one here is `import "workglow"` in five test files, and it
sits among value imports of the same module, so its position cannot matter.

format-check, build, typecheck-tests and lint pass; 2746 tests green, unchanged
from before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01915bWFf9P9RkSzpYztkFEH
1.0.14 drops the `typescript: ^6.0.3` peer dependency. That peer is why this
branch had to add typescript as an explicit devDependency: with only the peer
range and this package's own peer range in play, bun resolved typescript to
6.0.3 and `bun update typescript` rewrote the range back to match.

The devDependency stays — this package invokes `tsc` in `build-types`,
`dev-types` and `typecheck-tests`, so declaring it directly is right regardless
of what bunset asks for. Resolution is unchanged at 7.0.2; lint, format-check
and build all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01915bWFf9P9RkSzpYztkFEH
@sroussey
sroussey merged commit fc299d6 into main Sep 1, 2026
1 check passed
@sroussey
sroussey deleted the claude/oxlint-tsgolint-migration-x9goh5 branch September 1, 2026 23:29
sroussey added a commit that referenced this pull request Sep 1, 2026
### Features

- migrate from ESLint to oxlint and reorganize imports (#339)
- add backfill script for XBRL flags repair
- add CLAUDE.md documentation for project guidance
- enhance person name handling and resolution logic
- integrate phone number handling across multiple forms
- add international phone normalization and enhance phone detection logic

### Bug Fixes

- add index for filing date order in storage registry
- four defects found reviewing the filing-document work
- ensure `--force` flag works correctly in `bootstrap ingest` command

### Refactors

- migrate phone number handling to @sroussey/parse-phonenumber

### Chores

- update deps
- update dependencies
- update deps to get new person naming normalizer
- update deps

### Updated Dependencies

- `@sroussey/parse-full-name`: ^3.0.2
- `@workglow/cli`: 0.4.6
- `fast-xml-parser`: ^5.11.1
- `typebox`: 1.3.25
- `workglow`: 0.4.6
- `bunset`: 1.0.15
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.

2 participants