# diff-error _(no submodules)_ ## 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.