3.9 KiB
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_CODESconstant object — five stable string codes covering all failure modesDiffCodeunion type — narrowsstringto only valid diff error codesDiffErrorContextinterface — optionalpath,operation, andreasonfieldsDiffErrorclass — extendsError, setsname = "DiffError", attaches context- Fully typed:
readonlyfields prevent accidental mutation after construction
Usage: Basic Example
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
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
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
type DiffCode = (typeof DIFF_CODES)[keyof typeof DIFF_CODES];
Union of all valid diff error code strings.
DiffErrorContext
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
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
undefinedvalues; this keepsJSON.stringifyoutput clean. - The
name = "DiffError"assignment is in the constructor body (not a class field) to ensure the prototype chain is established first, which matters forinstanceofchecks across realm boundaries in bundled output.