Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
# `error-codes`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`@suaveplan/linter/error-codes` owns the stable error-code registry and the typed
`LinterError` class that every other module in the package throws. The registry is
expressed through `defineCodes("LINTER", [...])` from `@suaveplan/error` so each code
carries the `LINTER.` namespace prefix and survives across module boundaries, worker
threads, RPC envelopes, and serialised error transports without losing its identity.
Consumers of the linter — pre-commit hooks, CI gates, IDE integrations — discriminate
on `error.code` to make routing decisions (retry, suppress, surface to the user) without
parsing free-form messages, so the registry is a public contract, not an implementation
detail.
## Features
- Closed code set declared once via `defineCodes` — typo-safe, no string literals at
call sites.
- `LinterError extends SuaveplanError<LinterCode>` — interoperable with every
observability adapter shipped in `@suaveplan/error` (OTel span events, redaction,
i18n hooks).
- Optional `details` payload preserved on the instance and on the underlying
`SuaveplanError.context` field so structured diagnostics travel with the error.
- Optional `cause` forwarded to the native `Error.cause` chain — preserves the
underlying failure (e.g. an `EACCES` from `fs.writeFile`) for debugging.
## Usage: Basic
```ts
import { LINTER_CODES, LinterError } from "@suaveplan/linter/error-codes";
throw new LinterError(LINTER_CODES.NO_TARGETS_FOUND, "no .md files matched", {
details: { pattern: "docs/**/*.md" },
});
```
## Usage: Advanced
Route errors by code in a CI gate:
```ts
import { LinterError } from "@suaveplan/linter/error-codes";
import { runUnifiedLint } from "@suaveplan/linter/unified-lint";
try {
const report = await runUnifiedLint({ fix: false });
if (!report.success) {
process.exitCode = 1;
}
} catch (err) {
if (err instanceof LinterError) {
switch (err.code) {
case "LINTER.BIOME_UNAVAILABLE":
console.warn("biome not installed — skipping JS/TS lane");
break;
case "LINTER.NO_TARGETS_FOUND":
process.exitCode = 0; // empty repo, not a failure
break;
default:
console.error(err.code, err.message, err.details);
process.exitCode = 2;
}
} else {
throw err;
}
}
```
## API Reference
### `LINTER_CODES`
A frozen object whose values are the registered `LINTER.<REASON>` strings. Members:
`INVALID_OPTIONS`, `FILE_NOT_FOUND`, `NO_TARGETS_FOUND`, `READ_FAILED`,
`WRITE_FAILED`, `MARKDOWN_PARSE_FAILED`, `BIOME_UNAVAILABLE`, `BIOME_FAILED`,
`RUNNER_FAILED`, `UNKNOWN_FLAG`.
### `type LinterCode`
Union of every value in `LINTER_CODES`.
### `class LinterError extends SuaveplanError<LinterCode>`
Constructor: `new LinterError(code, message, options?)`.
- `code: LinterCode` — one of the registered codes.
- `message: string` — human-readable summary.
- `options.cause?: unknown` — forwarded to `Error.cause`.
- `options.details?: Record<string, unknown>` — stored as both
`instance.details` AND `instance.context` (via `SuaveplanError`).
`instance.name` is set to `"LinterError"`.
## Implementation Notes
- The registry is enumerated by tests (`Object.values(LINTER_CODES).sort()`) to
guarantee the public set matches the spec delta exactly. Adding a code without
updating the test fails the gate.
- `details` defaults to `{}` rather than `undefined` so consumers can safely spread or
read fields without a null-check; the spec scenario "defaults details to empty record
when omitted" pins this contract.
- `SuaveplanError` accepts `cause` only when defined — passing `undefined` would set
`cause: undefined` on the chain, which differs from "no cause." The constructor
guards this with the `options?.cause === undefined ? {} : { cause: options.cause }`
ternary.
- The class extends `SuaveplanError<LinterCode>` rather than `SuaveplanError` so the
`code` getter is narrowed to the linter's registered union at the type level — IDE
autocompletion lists exactly the ten codes.