Skip to content

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

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

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

Conversation

@Thomasims

@Thomasims Thomasims commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Moves this repository off Biome and onto the shared
@antelopejs/tooling-configs
presets, in step with the rest of the ecosystem.

Tooling swap

  • @biomejs/biome and biome.json are gone.
  • oxlint (pinned to 1.81.0, the version the presets' JS plugin API matches),
    oxfmt, knip, oxlint-tsgolint and eslint-plugin-perfectionist come in as
    dev dependencies.
  • New oxlint.config.ts, oxfmt.config.ts and knip.config.ts, each extending
    the shared preset.
  • Scripts: lintoxlint, lint:fixoxlint --fix, formatoxfmt .,
    plus new format:check and knip. Every other script is untouched. CI gains
    pnpm format:check and pnpm knip next to the existing pnpm lint, in its
    own ci: commit.

The .github/ISSUE_TEMPLATE/** ignore in oxfmt.config.ts is temporary: those
files are Markdown templates with a .yml extension, which oxfmt cannot parse.
It goes away once
tooling-configs#5 ships
the shared ignore.

tsconfig

Type-aware linting runs through tsgolint, which rejects compiler options
TypeScript 7 removed and auto-discovers each file's tsconfig.json. The only
offender here was "moduleResolution": "node" (the removed node10), so the
field is dropped; tsgolint only objects to the explicit value, and the default
for module: "commonjs" is the same resolver, so the emit is unaffected.

"module": "commonjs" deliberately stays. Raising it to node16 looks like the
obvious fix and is a runtime break: tsc would stop downlevelling dynamic imports
and emit native ESM ones, bypassing the CommonJS resolver detour the ajs
runtime installs.

What the linter forced

Import order, and nothing else. perfectionist(sort-imports) autofixed every
error; import(no-cycle) found no cycles in this tree. Nothing was disabled and
no rule was silenced. The remaining oxlint output is warnings only
(no-redundant-type-constituents on the decorator overload unions,
unbound-method, no-base-to-string) — the deliberate backlog the presets ship
with, left alone here.

Knip

One real finding: src/logging/index.ts exports the Logging namespace both
named and as the default, which Knip reports as a duplicate export. Both
spellings are used by consumers across the ecosystem (import { Logging } from "@antelopejs/interface-core/logging" and import Logging from … both appear in
shipped modules), so this is published contract, not an oversight. Knip's tags
filter does not reach the duplicate-export check, so the issue is silenced by
path in knip.config.ts with
ignoreIssues: { "src/logging/index.ts": ["duplicates"] }; the duplicate-export
check stays on for the rest of the repository, and the reason is recorded
inline.

No exports were removed. This package is a versioned contract: its surface is
reachable only from consumers Knip cannot see, so an "unused export" here would
never be evidence of dead code.

Verification

  • Public surface unchanged. dist was built from untouched origin/main
    and from this branch, and the runtime export keys of every module reachable
    through the exports map (., ./config, ./logging, ./logging/* and the
    ./* wildcard — 11 modules in all) were diffed: identical. The .d.ts file
    set is identical too, and the only .d.ts byte difference is a reordered
    import line in modules.d.ts. The compiled .js differences are likewise
    reordered require calls and nothing else.
  • Build succeeds with no source changes beyond the import sort.
  • Tests. pnpm test on untouched origin/main: 75 passing, 0 failing. On
    this branch: 75 passing, 0 failing. pnpm test:package fails identically on
    both — it shells out to corepack, which is not on this machine — so it is
    environmental and pre-existing, not a regression from this change.
  • pnpm lint, pnpm knip and pnpm build all exit 0.

Commits

The oxfmt pass is its own commit and is recorded in .git-blame-ignore-revs, so
git blame stays readable. oxfmt also normalizes package.json key order and
sorts keywords; that is expected.

Adopts the shared @antelopejs/tooling-configs presets: oxlint with the
vendored anti-slop rules, oxfmt for formatting and Knip for dead code.

Type-aware linting needs a tsconfig tsgolint accepts, so the removed
moduleResolution node10 option goes away. The module stays on commonjs so the
emit keeps using require, which is what the AntelopeJS resolver hooks; the
compiled output is byte-identical apart from the reordered requires the import
sorter produced.

The only fixes the linter forced were import order. Knip's one finding is the
Logging namespace, exported from src/logging/index.ts both named and as the
default: consumers across the ecosystem use both spellings, so the duplicate is
published contract. Knip's tag filter does not reach the duplicate-export
check, so that issue type is switched off in knip.config.ts with the reason
recorded there. No export changes: this package is a contract, so its surface
is reachable only from consumers Knip cannot see.
Biome is gone, so the directives suppress nothing. The explanations they
carried are kept as plain comments.
Switching the `duplicates` issue type off for the whole repository hid the
check everywhere, not just on the one export that needs it. Knip's
`ignoreIssues` silences an issue type per path, so the Logging named/default
pair is ignored where it lives and any future accidental duplicate export is
still reported.
Biome is gone, so they suppressed nothing. AGENTS.md mandates self-documenting
code without non-TSDoc comments, so the directives are dropped rather than
demoted to plain comments.
@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