Skip to content

chore: replace Biome with oxlint, oxfmt and Knip - #7

Open
Thomasims wants to merge 4 commits into
mainfrom
chore/oxc-tooling
Open

chore: replace Biome with oxlint, oxfmt and Knip#7
Thomasims wants to merge 4 commits into
mainfrom
chore/oxc-tooling

Conversation

@Thomasims

@Thomasims Thomasims commented Sep 7, 2026

Copy link
Copy Markdown

Replaces @biomejs/biome with the shared @antelopejs/tooling-configs presets: oxlint (type-aware, via oxlint-tsgolint) for linting, oxfmt for formatting, and Knip for dead-code and dependency analysis.

Tooling swap

  • biome.json deleted, @biomejs/biome removed.
  • Added oxlint.config.ts, oxfmt.config.ts, knip.config.ts, each extending the shared preset.
  • oxlint is pinned to exactly 1.81.0 — the JS plugin API is alpha and has to match the version tooling-configs builds against.
  • Scripts: lintoxlint, lint:fixoxlint --fix, formatoxfmt ., format:checkoxfmt --check ., plus a new knip. .github/workflows/ci.yml gains pnpm format:check and pnpm knip steps next to the existing pnpm lint and pnpm test, in a separate ci: commit.
  • oxfmt.config.ts carries a temporary .github/ISSUE_TEMPLATE/** ignore — those are Markdown templates with a .yml extension that oxfmt cannot parse. It goes away with tooling-configs#5.

tsconfig

Type-aware linting runs tsgolint, which rejects options TypeScript 7 removed and auto-discovers each file's tsconfig.json (so pointing it at a separate config does not help). Two changes:

  • "moduleResolution": "node" deleted. tsgolint only rejects the explicit removed node10 value, so dropping the field satisfies it while the emit stays byte-compatible. "module": "commonjs" is deliberately left alone — raising it to node16 makes tsc emit native ESM dynamic imports that bypass the CommonJS resolver detour the ajs runtime installs.
  • "baseUrl": "." deleted and the self-referencing paths entry rewritten to the relative ./src/index.ts. That mapping is what lets the conformance suite import @antelopejs/interface-redis by its published name; nothing else relied on baseUrl.

pnpm build succeeds with no source changes.

What the linter forced

Only import order, autofixed by oxlint --fix: chai now sorts before @antelopejs/interface-redis in src/tests/index.test.ts. No cycles, nothing disabled anywhere in the repo.

Four typescript(unbound-method) warnings remain on the chai assertions in that suite (expect(client.set).to.be.a("function") and friends). Warnings across this migration are a deliberate backlog — only errors gate the build — so they are left untouched rather than silenced.

What Knip needed

Two declarations, both commented in knip.config.ts:

  • entry for src/tests/**/*.test.ts and src/antelope.test.ts. This is an interface package: ajs module test reads antelopeJs.test to build the test project and runs the compiled suites out of dist/tests, and that compiled tree ships in the package as the conformance suite the implementing modules run. The preset only knows the singular src/test/ spelling, so without this entry the whole suite — plus chai and @types/chai — reads as dead code.
  • ignoreBinaries: ["ajs"] — the CLI comes from @antelopejs/core, which CI installs globally rather than pulling into every package's dependency tree.

Nothing was deleted. pnpm knip exits 0 (the remaining "configuration hints" are preset globs that do not match this repo).

Verification

The public surface of a versioned interface must not move, so it was checked against a build from an untouched origin/main worktree:

  • package.json exports declares . and ./package.json. The runtime export keys of . are identical: GetClient, and internal with {client, SetClient, UnsetClient}.
  • dist/index.js and dist/index.d.ts are byte-identical to the origin/main build. The only differences anywhere in dist are the order of two require() calls in the compiled test file and the corresponding mappings shift in dist/tests/index.test.js.map, both from the import sort above.
  • Conformance suite: 14 passing, 0 failing on untouched origin/main, and 14 passing, 0 failing on this branch.
    What that suite actually exercises: ajs module test runs this branch's compiled dist/tests/**, but the interface implementation those tests call through resolves to the published @antelopejs/interface-redis@0.0.8 inside .antelope/cache/@antelopejs/redis/node_modules, not to this branch's dist/index.js. Verified by poisoning the local dist/index.js with a top-level throw: the suite still reports 14 passing. So the pass count proves the branch's compiled conformance suite still builds and runs; it does not independently validate the branch's dist/index.js. That rests on the byte-diff above.
  • pnpm lint, pnpm knip and pnpm format:check all exit 0.

The oxfmt pass is a separate commit recorded in .git-blame-ignore-revs to keep git blame readable. It normalizes package.json key order and reflows Markdown code blocks in AGENTS.md, CHANGELOG.md, docs/ and skills/; no source file changed.

Swaps @biomejs/biome for the shared @antelopejs/tooling-configs presets:
oxlint (type-aware, via oxlint-tsgolint) for linting, oxfmt for formatting
and Knip for dead-code and dependency analysis. The lint / format scripts
are repointed and a `knip` script is added; CI already runs `pnpm lint`.

tsconfig: tsgolint rejects the `moduleResolution: "node"` (node10) value
TypeScript 7 removed, and it discovers each file's tsconfig itself, so the
field is dropped rather than raised — `module: "commonjs"` is untouched so
the emit stays byte-compatible. `baseUrl` is dropped too and the
self-referencing `paths` entry the conformance suite uses to import
`@antelopejs/interface-redis` is rewritten as a relative path.

No source changes were required beyond the import order oxlint autofixed in
src/tests/index.test.ts. Four `typescript(unbound-method)` warnings on the
chai assertions in that suite are left as-is: warnings are a deliberate
backlog, only errors gate the build.

Knip needs two declarations, both commented in knip.config.ts: the
conformance suite lives in src/tests/ and src/antelope.test.ts rather than
the preset's src/test/ spelling (without the entry the whole shipped suite
plus chai and @types/chai read as dead code), and the `ajs` binary comes
from a globally installed @antelopejs/core rather than a dependency.

Verified: dist/index.js and dist/index.d.ts are byte-identical to those
built from origin/main, the runtime export keys of the `.` subpath match
(GetClient, internal{client,SetClient,UnsetClient}), and the conformance
suite is 14 passing on both origin/main and this branch.
@Thomasims
Thomasims marked this pull request as ready for review September 7, 2026 16:10
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