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,116 @@
# diff-error
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`diff-error.ts` defines the error substrate for the `@suaveplan/diff` package. Every public API surface in the package throws a `DiffError` rather than a plain `Error`, giving callers a stable, machine-readable `code` property drawn from the `DIFF_CODES` registry. This makes error handling robust: you can match on `err.code` without parsing human-readable message text, and you can always narrow to a `DiffError` with `instanceof`.
The file intentionally avoids inheriting from `@suaveplan/error` so that `@suaveplan/diff` remains a true leaf package with no workspace runtime dependencies.
## Features
- `DIFF_CODES` constant object — five stable string codes covering all failure modes
- `DiffCode` union type — narrows `string` to only valid diff error codes
- `DiffErrorContext` interface — optional `path`, `operation`, and `reason` fields
- `DiffError` class — extends `Error`, sets `name = "DiffError"`, attaches context
- Fully typed: `readonly` fields prevent accidental mutation after construction
## Usage: Basic Example
```ts
import { DiffError, DIFF_CODES } from "@suaveplan/diff/errors";
try {
throw new DiffError("path not found", DIFF_CODES.PATH_INVALID, {
path: ["a", "b"],
operation: "remove",
});
} catch (err) {
if (err instanceof DiffError) {
console.error(err.code); // "DIFF.PATH_INVALID"
console.error(err.path); // ["a", "b"]
console.error(err.operation); // "remove"
}
}
```
## Usage: Advanced Example
```ts
import { DiffError, DIFF_CODES, type DiffCode } from "@suaveplan/diff/errors";
function assertNoDiffError(err: unknown): asserts err is never {
if (err instanceof DiffError) {
const ctx = [err.operation, err.path?.join("/"), err.reason]
.filter(Boolean)
.join(" | ");
throw new Error(`DiffError [${err.code}]: ${err.message} — ${ctx}`);
}
}
// Wrapping lower-level errors
function wrapApplyError(inner: unknown, path: string[]): DiffError {
const reason = inner instanceof Error ? inner.message : String(inner);
return new DiffError(`apply failed at /${path.join("/")}`, DIFF_CODES.APPLY_FAILED, {
path,
operation: "apply",
reason,
});
}
```
## API Reference
### `DIFF_CODES`
```ts
const DIFF_CODES: {
readonly INVALID_PATCH: "DIFF.INVALID_PATCH";
readonly TEST_FAILED: "DIFF.TEST_FAILED";
readonly PATH_INVALID: "DIFF.PATH_INVALID";
readonly APPLY_FAILED: "DIFF.APPLY_FAILED";
readonly INVERT_FAILED: "DIFF.INVERT_FAILED";
};
```
Stable string code registry. Always import codes from this object rather than inlining string literals.
### `DiffCode`
```ts
type DiffCode = (typeof DIFF_CODES)[keyof typeof DIFF_CODES];
```
Union of all valid diff error code strings.
### `DiffErrorContext`
```ts
interface DiffErrorContext {
path?: Path; // segment array of the JSON Pointer that failed
operation?: string; // RFC 6902 op name ("add", "remove", "replace", etc.)
reason?: string; // free-text explanation
}
```
### `DiffError`
```ts
class DiffError extends Error {
readonly code: DiffCode;
readonly path?: Path;
readonly operation?: string;
readonly reason?: string;
constructor(message: string, code: DiffCode, context?: DiffErrorContext): DiffError;
}
```
All context fields are `readonly` after construction. `name` is set to `"DiffError"` for reliable stack-trace display.
## Implementation Notes
- Inherits directly from `Error` (not `@suaveplan/error`) to keep this package dependency-free at runtime.
- Context fields are assigned only when defined to avoid sparse objects with explicit `undefined` values; this keeps `JSON.stringify` output clean.
- The `name = "DiffError"` assignment is in the constructor body (not a class field) to ensure the prototype chain is established first, which matters for `instanceof` checks across realm boundaries in bundled output.