first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
# `biome-runner`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`@suaveplan/linter/biome-runner` is the seam between the linter and the Biome CLI. Rather
than calling `execSync` from library code (which makes tests impossible and blocks the
event loop), the runner shells out through an injectable `CommandRunner` whose default
implementation wraps `node:child_process.spawn`. Tests pass real fake runners that
return canned `CommandResult` objects; production callers get the real subprocess. Every
run is wrapped in duration measurement so the OTel histogram captures the cost of every
biome invocation across the project.
## Features
- Three modes — `"check"` (read-only), `"check-write"` (lint+fix, `--write --unsafe`),
`"format-write"` (formatter only with `--write`).
- Returns a `BiomeReport` with `mode`, `exitCode`, `stdout`, `stderr`, `success`, and
`durationMs` so downstream callers can render summaries without re-parsing.
- `"check"` mode throws `LinterError(LINTER.BIOME_FAILED)` on a non-zero exit (the
expected contract for CI gates); `"check-write"` and `"format-write"` return the
report unconditionally so write-mode runs can report success even when biome surfaced
diagnostics that it auto-fixed.
- `probeBiomeAvailable({ runner })` — non-fatal `bunx biome --version` ping returning
`boolean`. Used by the orchestrator to gate the biome lane.
- Zod-validated options — invalid `mode` values raise
`LinterError(LINTER.INVALID_OPTIONS)`.
- Injectable `ClockLike` for deterministic duration measurement in tests.
## Usage: Basic
```ts
import {
nodeCommandRunner,
runBiome,
} from "@suaveplan/linter/biome-runner";
const report = await runBiome({
cwd: ".",
mode: "check",
runner: nodeCommandRunner,
});
console.log(report.success, report.durationMs);
```
## Usage: Advanced
Drive the runner from a test with a recording fake runner:
```ts
import { runBiome } from "@suaveplan/linter/biome-runner";
import type { CommandInput, CommandRunner } from "@suaveplan/linter";
const calls: CommandInput[] = [];
const runner: CommandRunner = {
async run(input) {
calls.push(input);
return { exitCode: 0, stdout: "ok", stderr: "" };
},
};
const clock = { now: () => 1000 };
const report = await runBiome({
cwd: ".",
mode: "check-write",
runner,
clock,
});
// calls[0].args === ['biome', 'check', '--write', '--unsafe', '--max-diagnostics', '500', '.']
// report.success === true
// report.durationMs === 0
```
## API Reference
### `runBiome(options): Promise<BiomeReport>`
- `options.cwd: string` — required, forwarded to the runner.
- `options.mode: "check" | "check-write" | "format-write"` — required.
- `options.runner: CommandRunner` — required.
- `options.clock?: ClockLike` — defaults to `Date.now`.
Throws `LinterError` with code `INVALID_OPTIONS`, `RUNNER_FAILED`, or `BIOME_FAILED`.
### `probeBiomeAvailable(options): Promise<boolean>`
- `options.runner: CommandRunner` — required.
- `options.cwd?: string` — defaults to `"."`.
Resolves to `true` only on `exitCode === 0`; runner rejections resolve to `false`.
### `nodeCommandRunner: CommandRunner`
Default runner wrapping `child_process.spawn`. Inherits the current `process.env` and
overlays any `env` field provided in the `CommandInput`.
## Implementation Notes
- The runner shells through `bunx biome` (not `npx`) so the catalogued
`@biomejs/biome` version is the one that runs. Bunx resolves the binary from the
current workspace install, matching what `bun run lint` would invoke in every other
package.
- The default runner buffers stdout / stderr in memory and resolves on `close`, NOT
`exit` — `close` fires after both streams are drained, so the report includes
trailing output that `exit` would miss.
- `RunBiomeOptions` is validated via Zod at the boundary so consumers passing
hand-typed strings get an `INVALID_OPTIONS` error rather than a runtime crash deep
inside the runner.
- `recordBiomeRun(mode, outcome)` and `recordRunDuration("biome", ms)` fire on every
successful runner completion (success or failure); the only path that skips them is
a runner rejection, which is the `RUNNER_FAILED` branch.
- `probeBiomeAvailable` deliberately swallows rejections — a missing binary should not
bubble an unhandled rejection through the orchestrator. Callers who want strict
behaviour can raise `BIOME_UNAVAILABLE` themselves after a `false` probe.