Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
# serialize-error
## Purpose
Defines the error hierarchy for `@suaveplan/serialize`. All errors thrown by this package extend `SerializationError`, which in turn extends `SuaveplanError` from `@suaveplan/error`. This design ensures every thrown error carries a stable, machine-readable code string (`SERIALIZE.*`) so callers can programmatically distinguish between circular references, depth overflows, size overflows, and unknown type tags without parsing human-readable messages.
The contextual payload (`SerializationErrorContext`) transports structural metadata — tag names, recursion depths, byte sizes, and dot-path strings — that would otherwise require expensive re-traversal to reconstruct after the fact.
## Features
- `SerializationError` — base class; extends `SuaveplanError<SerializationErrorCode>` with an optional `SerializationErrorContext`
- `CircularReferenceError` — emitted when a cycle is detected in the input object graph; includes the dot-path where the cycle was encountered
- `MaxDepthExceededError` — emitted when recursion depth exceeds the caller-configured `maxDepth`; includes the depth value
- `MaxSizeExceededError` — emitted when the serialized byte count exceeds `maxSize`; includes the approximate size in bytes
- `UnsupportedTypeError` — emitted during deserialization when a `__t` tag has no registered decoder; includes the unknown tag string
- Exported `SerializationErrorCode` union type for exhaustive `switch` narrowing
- Re-exported `SERIALIZE_CODES` constant map for use in tests and error construction
## Usage: Basic Example
```typescript
import {
CircularReferenceError,
MaxDepthExceededError,
SerializationError,
} from "@suaveplan/serialize";
try {
// serialization call here
} catch (err) {
if (err instanceof CircularReferenceError) {
console.error("Cycle at", err.context?.path);
} else if (err instanceof SerializationError) {
console.error("Serialization failed:", err.code);
}
}
```
## Usage: Advanced Example
```typescript
import {
SERIALIZE_CODES,
SerializationError,
UnsupportedTypeError,
type SerializationErrorCode,
} from "@suaveplan/serialize";
function handleSerializeError(err: unknown): never {
if (!(err instanceof SerializationError)) throw err;
const code: SerializationErrorCode = err.code;
switch (code) {
case SERIALIZE_CODES["CODEC.CIRCULAR_REFERENCE"]:
throw new Error(`Cycle at path: ${err.context?.path ?? "unknown"}`);
case SERIALIZE_CODES["CODEC.MAX_DEPTH"]:
throw new Error(`Too deep: ${err.context?.depth}`);
case SERIALIZE_CODES["CODEC.MAX_SIZE"]:
throw new Error(`Too large: ${err.context?.size} bytes`);
case SERIALIZE_CODES["CODEC.UNKNOWN_TAG"]:
throw new Error(`No decoder for tag: ${err.context?.tag}`);
default:
throw err;
}
}
// UnsupportedTypeError carries the unknown tag
const e = new UnsupportedTypeError("__MyCustomClass");
console.log(e.context?.tag); // "__MyCustomClass"
```
## API Reference
### `SerializationError`
```typescript
class SerializationError extends SuaveplanError<SerializationErrorCode> {
constructor(
code: SerializationErrorCode,
messageKey: string,
options?: SerializationErrorOptions,
): void
}
```
- `code` — one of the `SERIALIZE.*` codes
- `messageKey` — i18n key resolved via `@suaveplan/error` resolver
- `options.cause` — underlying error, chained via `Error.cause`
- `options.context` — `SerializationErrorContext` metadata
### `CircularReferenceError`
```typescript
new CircularReferenceError(path?: string, cause?: unknown)
```
Code: `SERIALIZE.CODEC.CIRCULAR_REFERENCE`. `context.path` is the dot-path string where the cycle was detected.
### `MaxDepthExceededError`
```typescript
new MaxDepthExceededError(depth: number, cause?: unknown)
```
Code: `SERIALIZE.CODEC.MAX_DEPTH`. `context.depth` is the depth value at which encoding was aborted.
### `MaxSizeExceededError`
```typescript
new MaxSizeExceededError(size: number, cause?: unknown)
```
Code: `SERIALIZE.CODEC.MAX_SIZE`. `context.size` is the approximate byte count.
### `UnsupportedTypeError`
```typescript
new UnsupportedTypeError(tag: string, cause?: unknown)
```
Code: `SERIALIZE.CODEC.UNKNOWN_TAG`. `context.tag` is the unrecognised tag string.
### `SerializationErrorContext`
```typescript
interface SerializationErrorContext {
tag?: string;
depth?: number;
size?: number;
path?: string;
}
```
### `SerializationErrorOptions`
```typescript
interface SerializationErrorOptions {
cause?: unknown;
context?: SerializationErrorContext;
}
```
### `SerializationErrorCode`
Union type of all `SERIALIZE.*` code strings; use with exhaustive `switch` statements.
## Implementation Notes
- `SerializationError` maps `SerializationErrorOptions.context` to the generic `Record<string, unknown>` shape expected by `SuaveplanErrorOptions` without widening the exported interface — callers always get the narrow `SerializationErrorContext` type.
- Each subclass uses a specific constructor signature (only the meaningful fields, not the full code/key/options triple) to make throw sites readable and to prevent code/message mismatches.
- The `SERIALIZE_CODES` constant is defined in a separate `codes.ts` module and re-exported from here so that the error file is self-contained for consumers who only import errors.