Skip to content

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

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

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

Conversation

@Thomasims

Copy link
Copy Markdown
Contributor

Replaces Biome with the shared @antelopejs/tooling-configs presets: oxlint
(type-aware, with the vendored anti-slop rules), oxfmt for formatting and Knip
for dead-code detection. oxlint is pinned to 1.81.0 because the JS plugin API
is still alpha and has to match the version tooling-configs builds against.

tsconfig

Type-aware linting runs through tsgolint, which rejects options TypeScript 7
removed, so moduleResolution: "node" and baseUrl are gone and the
self-referential @antelopejs/interface-data-api path mappings the test suites
use are now written relative, which is what the compiler wants once baseUrl
is absent.

module stays commonjs on purpose. Raising it to node16 would look like the
tidier fix and is a runtime break: tsc stops downlevelling dynamic imports and
emits native ESM ones, which bypass the CommonJS resolver detour the ajs
runtime installs.

The import cycles

import(no-cycle) found two, both through index.ts:

  • components.ts imported GetDataControllerMeta from index.ts, while
    index.ts imports Parameters, Query and Validation from
    components.ts.
  • metadata.ts imported the DataControllerCallbackWithOptions type from
    index.ts, while index.ts imports DataAPIMeta from metadata.ts.

Both are fixed by moving the shared declarations down into metadata.ts — the
endpoint callback types (DataControllerCallback,
DataControllerCallbackWithOptions, ExtractCallback, DataControllerDef,
ExtractDefCallbacks) and GetDataControllerMeta, all of which describe
metadata rather than controllers. metadata.ts imports neither of the other two
modules, so the graph is now acyclic.

The public surface is unchanged. index.ts re-exports every moved symbol,
and Object.keys(require("dist/index.js")) is identical before and after; the
metadata subpath gains those names, which is purely additive.

The first cycle was not theoretical. On main, requiring the components
subpath before the root throws:

TypeError: Cannot read properties of undefined (reading 'Get')
    at dist/index.js:203:72

because index.ts evaluates Parameters.Get() at module scope while
components is still half-initialized. Loading dist/components.js first works
on this branch.

Other code changes the linter forced

  • perfectionist(sort-imports): import ordering across the source and the
    suites, all applied by oxlint --fix.
  • unicorn(no-useless-fallback-in-spread): { ...(callback.options ?? {}), ...(options ?? {}) } becomes { ...callback.options, ...options }.
    Spreading undefined into an object literal is already a no-op, so this is
    behaviour-preserving.

Nothing was disabled. The remaining oxlint output is warnings only, which are a
deliberate backlog and are left as they are. pnpm lint exits 0.

Knip

Only ajs needed an ignore: CI installs @antelopejs/core globally instead of
adding the CLI to every package. Nothing was deleted — no unused files, exports
or dependencies are reported, and an interface package's exports are its
versioned contract, so they are kept whatever Knip could not see reaching them.

Verification

pnpm build, pnpm lint, pnpm knip, pnpm format:check all exit 0.
pnpm test: 89 passing, identical to the baseline measured on an untouched
main worktree.

The oxfmt pass is a separate commit and is recorded in .git-blame-ignore-revs
so git blame stays readable. It also normalizes Markdown, YAML and the
package.json key order, which accounts for most of the diff.

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 and baseUrl options go away and the self-referential
path mappings the tests use become relative. The module stays on commonjs so
the emit keeps using require, which is what the AntelopeJS resolver hooks.

import(no-cycle) found two real cycles through index.ts: components.ts needed
GetDataControllerMeta and metadata.ts needed the endpoint callback types, both
of which index.ts declared. Both now live in metadata.ts, which neither of the
other two entry points depends on in reverse, and index.ts re-exports them so
the @antelopejs/interface-data-api surface is byte-identical. The components
cycle was not theoretical: requiring dist/components.js first threw
"Cannot read properties of undefined (reading 'Get')" because index.ts
evaluated Parameters.Get() while components was still half-initialized.
@Thomasims
Thomasims marked this pull request as draft September 7, 2026 10:37
@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