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,85 @@
# json-decode
## Purpose
Implements `deserialize`, the inverse of `serialize`. Given a tagged JSON string produced by the encoder, it reconstructs the original JavaScript value graph including all registered types (built-ins and custom), `undefined`, `NaN`, and `±Infinity`. Any `__t` tag that has no registered handler causes an `UnsupportedTypeError` to be thrown immediately rather than silently discarding data.
The decoder is intentionally strict: it is safer to fail loudly on an unrecognised tag than to silently drop values, which could cause subtle data corruption downstream.
## Features
- Full inverse of `serialize`: all built-in type tags are decoded back to their original JavaScript types
- `AbortSignal` support for cancelling mid-traversal on large payloads, checked every 256 nodes
- `UnsupportedTypeError` thrown (with the tag name in `context.tag`) for unrecognised `__t` values
- Recursive array and plain-object decoding
- Zero allocations for pass-through primitives (string, number, boolean, null)
## Usage: Basic Example
```typescript
import { deserialize, serialize } from "@suaveplan/serialize";
const original = { created: new Date(), tags: new Set(["x", "y"]) };
const json = serialize(original);
const restored = deserialize(json) as typeof original;
restored.created instanceof Date; // true
restored.tags instanceof Set; // true
```
## Usage: Advanced Example
```typescript
import { deserialize, UnsupportedTypeError } from "@suaveplan/serialize";
const controller = new AbortController();
// Cancel deserialization partway through:
setTimeout(() => controller.abort(new Error("timeout")), 10);
try {
const value = deserialize(largeJson, { signal: controller.signal });
processValue(value);
} catch (err) {
if (err instanceof UnsupportedTypeError) {
console.error("Unknown type tag:", err.context?.tag);
} else {
// likely the abort reason
throw err;
}
}
```
## API Reference
### `deserialize(json: string, opts?: DeserializeOptions): unknown`
Parse `json` and recursively reconstruct the JavaScript value it encodes.
**Parameters:**
- `json` — a tagged JSON string produced by `serialize`
- `opts.signal` — an `AbortSignal`; checked every 256 nodes
**Returns:** the reconstructed value.
**Throws:**
- `UnsupportedTypeError` when a `__t` tag has no registered decoder
- `SyntaxError` from `JSON.parse` if the input is not valid JSON
- The `AbortSignal`'s reason when `signal` is aborted
### `DeserializeOptions`
```typescript
interface DeserializeOptions {
signal?: AbortSignal;
}
```
## Implementation Notes
- The decoder calls `JSON.parse` once at the top level and then recursively traverses the parsed intermediate tree. This avoids parsing partial JSON strings and keeps the implementation simple.
- For tagged objects, the inner `v` payload is decoded recursively *before* being handed to `def.decode`. This means registered type decoders always receive already-decoded JavaScript values, not raw JSON intermediates.
- Signal checking is shared with a module-level counter that resets per `deserialize` call; it fires every 256 traversed nodes.
- The decoder does not validate the structure of `v` beyond calling `def.decode`; responsibility for validating the payload shape belongs to each registered type definition.