### Install CodableJSON Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/index.mdx Install CodableJSON using npm, yarn, or pnpm. ```bash npm install codablejson # or yarn add codablejson # or pnpm add codablejson ``` -------------------------------- ### Temporal API Support Example Source: https://github.com/pie6k/codablejson/blob/main/README.md Demonstrates how CodableJSON automatically supports modern Temporal API types like Instant and Duration when Temporal is available globally. Includes an example of importing a polyfill if needed. ```APIDOC ## Temporal API Support CodableJSON automatically supports all modern [Temporal API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal) types when `Temporal` is available globally: `Instant`, `Duration`, `PlainDate`, `PlainDateTime`, `PlainMonthDay`, `PlainTime`, `PlainYearMonth`, and `ZonedDateTime`. If your environment doesn't natively support Temporal, import a polyfill before using CodableJSON: ```typescript // import "temporal-polyfill/global"; // you need this if your environment doesn't natively support Temporal import { encode, decode } from "codablejson"; const instant = Temporal.Instant.from("1970-01-01T00:00:00Z"); const encoded = encode(instant); // { $$Instant: "1970-01-01T00:00:00Z" } const decoded = decode(encoded); // decoded instanceof Temporal.Instant === true // Calculate duration between dates const start = Temporal.PlainDate.from("2024-01-01"); const end = Temporal.PlainDate.from("2025-12-25"); const duration = start.until(end); const encodedDuration = encode(duration); // { $$Duration: "P1Y11M24D" } ``` ``` -------------------------------- ### Complete MobX Example with CodableJSON Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/recipes/mobx.mdx This example demonstrates serializing and deserializing a MobX-managed project structure. It verifies that reactivity is preserved, and changes to the decoded object trigger reactions as expected. ```typescript const project = new Project(); const scene = project.addScene(); scene.addZoom(new Zoom({ start: 0, end: 1, scale: 1 })); const zoom2 = new Zoom({ start: 2, end: 3, scale: 2 }); scene.addZoom(zoom2); scene.addZoom(zoom2); // Test reference preservation const encoded = coder.encode(project); const decoded = coder.decode(encoded); // Verify reactivity const runner = autorun(() => { const firstScene = decoded.scenes.values().next().value!; return [decoded.scenes.size, firstScene.zooms.length, decoded.settings.size]; }); // All changes trigger reactions decoded.addScene(); decoded.scenes.values().next().value!.addZoom(new Zoom({ start: 4, end: 5, scale: 3 })); decoded.setSetting("theme", "dark"); decoded.setSetting("language", "en"); ``` -------------------------------- ### Core Functions Source: https://github.com/pie6k/codablejson/blob/main/README.md Provides examples of the core functions in CodableJSON: `encode`, `decode`, `stringify`, `parse`, and `clone` for basic data manipulation and deep cloning. ```APIDOC ## Core Functions ```typescript import { encode, decode, stringify, parse, clone } from "codablejson"; // Basic encoding/decoding const encoded = encode(data); const decoded = decode(encoded); // With JSON stringification const jsonString = stringify(data); const restored = parse(jsonString); // Deep clone maintaining all types and references equality const foo = { foo: "foo" }; const original = [foo, foo]; const cloned = clone(original); // cloned === original; // false // cloned[0] === original[0]; // false -> nested clone // cloned[0] === cloned[1]; // true -> reference equality is preserved ``` ``` -------------------------------- ### Declarative Class Serialization Setup Source: https://github.com/pie6k/codablejson/blob/main/README.md Define serializable classes using `@codableClass` and `@codable` decorators. Ensure your classes have a memberwise constructor for automatic serialization. ```typescript import { codableClass, codable, Coder } from "codablejson"; @codableClass("Player") class Player { @codable() name: string; @codable() score: number; // Note: constructor is not needed for CodableJSON to work, it is here for convenience of creating instances. constructor(data: Pick) { this.name = data.name; this.score = data.score; } } @codableClass("GameState") class GameState { @codable() players: Set = new Set(); @codable() createdAt = new Date(); @codable() activePlayer: Player | null = null; addPlayer(player: Player) { this.players.add(player); this.activePlayer = player; } } // Use your classes naturally const gameState = new GameState(); gameState.addPlayer(new Player({ name: "Alice", score: 100 })); // Create a custom coder instance that is aware of your classes const coder = new Coder([GameState, Player]); const encoded = coder.encode(gameState); const decoded = coder.decode(encoded); ``` -------------------------------- ### Validate Data Before Encoding Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/security.mdx Provides an example function to validate data before encoding with CodableJSON. It checks for invalid data types and the presence of dangerous properties like 'constructor', '__proto__', and 'prototype'. ```typescript // Example: Validate before encoding function safeEncode(data: unknown) { // Validate data structure if (typeof data !== 'object' || data === null) { throw new Error('Invalid data type'); } // Check for dangerous properties const dangerousKeys = ['constructor', '__proto__', 'prototype']; for (const key of dangerousKeys) { if (key in data) { throw new Error(`Dangerous property detected: ${key}`); } } return encode(data); } ``` -------------------------------- ### Temporal API Support with Polyfill Source: https://github.com/pie6k/codablejson/blob/main/codablejson/README.md Demonstrates encoding and decoding Temporal API objects like Instant and Duration. Ensure 'temporal-polyfill/global' is imported if Temporal is not natively supported. ```typescript import "temporal-polyfill/global"; import { encode, decode } from "codablejson"; const instant = Temporal.Instant.from("1970-01-01T00:00:00Z"); const encoded = encode(instant); // { $$Instant: "1970-01-01T00:00:00Z" } const decoded = decode(encoded); // decoded instanceof Temporal.Instant === true // Calculate duration between dates const start = Temporal.PlainDate.from("2024-01-01"); const end = Temporal.PlainDate.from("2025-12-25"); const duration = start.until(end); const encodedDuration = encode(duration); // { $$Duration: "P1Y11M24D" } ``` -------------------------------- ### Adding a Custom Type Inline with Coder.addType Source: https://context7.com/pie6k/codablejson/llms.txt Coder.addType provides a concise way to register a custom type directly within the Coder instance. This example shows encoding a Color object to a hex string. ```typescript import { Coder } from "codablejson"; class Color { constructor(public r: number, public g: number, public b: number) {} toHex() { return `#${[this.r, this.g, this.b].map(n => n.toString(16).padStart(2, "0")).join("")}`; } } const coder = new Coder(); coder.addType( "Color", (v): v is Color => v instanceof Color, (c) => c.toHex(), // encode as hex string (hex) => { const n = parseInt(hex.slice(1), 16); return new Color((n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff); }, ); const encoded = coder.encode(new Color(255, 128, 0)); // { $$Color: "#ff8000" } const decoded = coder.decode(encoded); // decoded.r === 255, decoded.g === 128, decoded.b === 0 ``` -------------------------------- ### Benchmark Results: Plain JSON Encode/Decode Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/performance.mdx Compares CodableJSON and SuperJSON for encoding and decoding plain JSON data. Shows performance differences with and without reference preservation. ```bash ✓ tests/benchmark.bench.ts > benchmark > plain json > encode - 6mb 536ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 141.32 5.8634 8.0289 7.0763 7.7076 8.0289 8.0289 8.0289 ±5.96% 15 · superjson 38.4136 25.6165 26.3393 26.0325 26.0943 26.3393 26.3393 26.3393 ±1.84% 4 ✓ tests/benchmark.bench.ts > benchmark > plain json > decode - 6mb 442ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 241.27 3.8788 4.4581 4.1447 4.2970 4.4581 4.4581 4.4581 ±1.77% 25 · superjson 187.22 4.8906 5.5359 5.3414 5.4529 5.5359 5.5359 5.5359 ±1.50% 19 ✓ tests/benchmark.bench.ts > benchmark > plain json > encode - 6mb (no preserve refs) 558ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 187.33 4.5381 6.1755 5.3381 5.7754 6.1755 6.1755 6.1755 ±5.23% 19 · superjson 27.3290 25.9383 65.7288 36.5912 28.6778 65.7288 65.7288 65.7288 ±84.64% 4 ✓ tests/benchmark.bench.ts > benchmark > plain json > decode - 6mb (no preserve refs) 431ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 241.86 3.9113 4.3932 4.1346 4.2824 4.3932 4.3932 4.3932 ±1.68% 25 · superjson 189.36 4.8939 5.4525 5.2810 5.3857 5.4525 5.4525 5.4525 ±1.35% 19 ``` -------------------------------- ### Benchmark Results: Complex Data Encode/Decode (Small) Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/performance.mdx Compares CodableJSON and SuperJSON for encoding and decoding small complex data structures. Highlights performance with and without reference preservation. ```bash ✓ tests/benchmark.bench.ts > benchmark > complex data > encode - small 406ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 21,234.54 0.0377 1.3792 0.0471 0.0425 0.0540 0.8579 1.0047 ±5.99% 2124 · superjson 5,463.87 0.1525 1.0877 0.1830 0.1668 0.7494 0.8460 1.0877 ±4.88% 547 ✓ tests/benchmark.bench.ts > benchmark > complex data > decode - small 407ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 29,806.52 0.0304 0.2429 0.0335 0.0329 0.0361 0.0422 0.2369 ±1.30% 2981 · superjson 17,753.50 0.0500 0.3205 0.0563 0.0548 0.0672 0.2338 0.3092 ±1.52% 1776 ✓ tests/benchmark.bench.ts > benchmark > complex data > encode - small (no preserve refs) 406ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 25,394.95 0.0319 1.3072 0.0394 0.0352 0.0409 0.0458 1.2718 ±7.28% 2540 · superjson 3,638.95 0.1531 18.5522 0.2748 0.1754 1.0328 1.6148 18.5522 ±36.52% 364 ✓ tests/benchmark.bench.ts > benchmark > complex data > decode - small (no preserve refs) 406ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 29,951.03 0.0302 0.2175 0.0334 0.0329 0.0395 0.0415 0.1940 ±1.01% 2996 · superjson 18,056.05 0.0501 0.2413 0.0554 0.0542 0.0652 0.1729 0.1977 ±1.00% 1806 ``` -------------------------------- ### Import Temporal Polyfill and CodableJSON Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/json-serialization/temporal.mdx If your environment doesn't natively support the Temporal API, import a polyfill before importing CodableJSON. The polyfill must be imported before CodableJSON. ```typescript import "temporal-polyfill/global"; import { encode, decode } from "codablejson"; ``` -------------------------------- ### Benchmark Results: Complex Data Encode/Decode (Average) Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/performance.mdx Compares CodableJSON and SuperJSON for encoding and decoding average-sized complex data structures. Shows performance with and without reference preservation. ```bash ✓ tests/benchmark.bench.ts > benchmark > complex data > encode - avg 415ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 1,460.57 0.5659 1.7502 0.6847 0.6249 1.7420 1.7502 1.7502 ±5.83% 148 · superjson 348.01 2.4765 3.3156 2.8735 3.1347 3.3156 3.3156 3.3156 ±3.30% 35 ✓ tests/benchmark.bench.ts > benchmark > complex data > decode - avg 410ms name hz min max mean p75 p99 p995 p999 rme samples · codablejson 1,329.21 0.6902 0.9735 0.7523 0.7467 0.9650 0.9735 0.9735 ±1.03% 134 · superjson 1,144.66 0.7891 1.0923 0.8736 0.8608 1.0761 1.0923 1.0923 ±1.62% 115 ✓ tests/benchmark.bench.ts > benchmark > complex data > encode - avg (no preserve refs) 414ms ``` -------------------------------- ### Multi-level Class Inheritance with @codableClass Source: https://context7.com/pie6k/codablejson/llms.txt Demonstrates how to use @codableClass for multi-level inheritance. Parent classes must be declared in dependencies. ```typescript import { codableClass, codable, Coder } from "codablejson"; @codableClass("Vehicle") class Vehicle { @codable() make: string; @codable() year: number; constructor(data: Pick) { this.make = data.make; this.year = data.year; } } @codableClass("ElectricCar", { dependencies: [Vehicle] }) class ElectricCar extends Vehicle { @codable() batteryKwh: number; @codable() chargePorts: Set; constructor(data: Pick) { super({ make: data.make, year: data.year }); this.batteryKwh = data.batteryKwh; this.chargePorts = data.chargePorts; } } const coder = new Coder([ElectricCar]); const car = new ElectricCar({ make: "Tesla", year: 2024, batteryKwh: 75, chargePorts: new Set(["CCS", "Type 2"]) }); const encoded = coder.encode(car); // { $$ElectricCar: [{ make: "Tesla", year: 2024, batteryKwh: 75, chargePorts: { $$Set: ["CCS","Type 2"] } }] } const decoded = coder.decode(encoded); // decoded instanceof ElectricCar === true // decoded instanceof Vehicle === true // decoded.make === "Tesla" (from parent) // decoded.chargePorts instanceof Set === true ``` -------------------------------- ### Declarative Class Serialization Source: https://github.com/pie6k/codablejson/blob/main/README.md Illustrates how to use `codableClass` and `codable` decorators to enable declarative serialization for custom classes, along with using the `Coder` class. ```APIDOC ## Declarative Class Serialization ```typescript import { codableClass, codable, Coder } from "codablejson"; @codableClass("MyClass") class MyClass { @codable() property: string; } const coder = new Coder([MyClass]); const encoded = coder.encode(instance); const decoded = coder.decode(encoded); ``` ``` -------------------------------- ### Basic Class Inheritance with @codable() Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/declarative-serialization/inheritance.mdx Demonstrates basic inheritance where a `Dog` class extends an `Animal` class. Only properties marked with `@codable()` are encoded. Ensure the `Coder` is initialized with the base class for proper decoding. ```typescript import { Coder, Memberwise, codable, codableClass } from "codablejson"; @codableClass("Animal") class Animal { @codable() name: string; @codable() age: number; constructor(data: Memberwise) { this.name = data.name; this.age = data.age; } } @codableClass("Dog", { dependencies: [Animal] }) class Dog extends Animal { @codable() breed: string; @codable() tricks: Set; constructor(data: Memberwise) { super({ name: data.name, age: data.age }); this.breed = data.breed; this.tricks = data.tricks; } } const coder = new Coder([Dog]); const dog = new Dog({ name: "Buddy", age: 3, breed: "Golden Retriever", tricks: new Set(["sit", "stay", "roll over"]) }); const encoded = coder.encode(dog); /** * { * $$Dog: [ * { * name: "Buddy", * age: 3, * breed: "Golden Retriever", * tricks: { $$Set: ["sit", "stay", "roll over"] } * } * ] * } */ const decoded = coder.decode(encoded); // decoded instanceof Dog === true // decoded.name === "Buddy" (from parent class) // decoded.breed === "Golden Retriever" (from child class) ``` -------------------------------- ### Custom Types Source: https://github.com/pie6k/codablejson/blob/main/README.md Shows how to use the lower-level `codableType` API to create and register custom types for encoding and decoding with CodableJSON. ```APIDOC ## Custom Types You can also use lower-level API to create custom types and encode/decode them manually. ```typescript import { codableType, Coder } from "codablejson"; const $$custom = codableType( "CustomType", // name of the type (value) => value instanceof CustomType, // how to detect some value should be encoded using this type (instance) => instance.data, // how to encode the value (might return rich data like `Map` or `Set`, or even other custom types) (data) => new CustomType(data), // how to recreate the value from the encoded data ); const coder = new Coder([$$custom]); // or const coder = new Coder(); coder.register($$custom); ``` ``` -------------------------------- ### Automatic Dependency Discovery Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/declarative-serialization/dependencies.mdx When using the `dependencies` option, you only need to register the root class with the `Coder`. All other dependent classes will be discovered automatically. ```typescript // Without dependencies - you'd need to register both classes const coder = new Coder([Foo, Bar]); // Before // With dependencies - automatic discovery const coder = new Coder([Foo]); // Now ``` -------------------------------- ### Encode Options Source: https://context7.com/pie6k/codablejson/llms.txt Provides options for controlling the encoding process, including how to handle unknown input types, preserve object references, and include error stack traces. ```APIDOC ## Encode Options ```typescript import { encode } from "codablejson"; class Unparsed {} // unknownInputMode — controls behaviour for unregistered class instances encode(new Unparsed(), { unknownInputMode: "null" }); // → null (default) encode(new Unparsed(), { unknownInputMode: "unchanged" }); // → raw object passed through // encode(new Unparsed(), { unknownInputMode: "throw" }); // throws an error // preserveReferences — disable to skip reference tracking (faster for acyclic data) encode([1, 2, 3], { preserveReferences: false }); // includeErrorStack — include error.stack in serialized Error objects const err = new Error("oops"); const encoded = encode(err, { includeErrorStack: true }); // { $$Error: { message: "oops", stack: "Error: oops\n at …" } } ``` ``` -------------------------------- ### Codable vs. Observable Decorator Convention Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/recipes/mobx.mdx Illustrates the convention where decorators prefixed with `$` indicate MobX observability, distinguishing them from regular `codable` decorators. ```typescript // Regular codable (not observable) @codable() accessor regularProperty: string = "value"; // Observable codable (MobX + CodableJSON) @$codable() accessor reactiveProperty: string = "value"; ``` -------------------------------- ### Enable SuperJSON Compatibility Mode Source: https://context7.com/pie6k/codablejson/llms.txt Importing 'codablejson/superjson' enables automatic decoding of data previously encoded by SuperJSON, facilitating seamless migration. ```typescript // Import once early in your app entry point: import "codablejson/superjson"; import { decode } from "codablejson"; // Data encoded by the legacy SuperJSON library const superJsonOutput = { json: { date: "2025-01-01T00:00:00.000Z", count: 1 }, meta: { values: { date: ["Date"] } }, }; // CodableJSON automatically delegates to SuperJSON for decoding const decoded = decode(superJsonOutput); // decoded.date instanceof Date === true ``` -------------------------------- ### Compose MobX and CodableJSON Decorators Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/recipes/mobx.mdx Use the `combineDecorators` utility to create a single decorator that applies both MobX's `observable` and CodableJSON's `codable`. ```typescript import { combineDecorators } from "codablejson"; // Create a composed decorator const $codable = combineDecorators(codable(), observable); @codableClass("ReactiveModel") class ReactiveModel { @$codable() accessor data: string = "initial"; @$codable() accessor items: Set = new Set(); } ``` -------------------------------- ### Core Functions: encode, decode, stringify, parse, clone Source: https://context7.com/pie6k/codablejson/llms.txt Use these top-level convenience functions for encoding, decoding, stringifying, parsing, and cloning data with built-in type support. They are wrappers around the default Coder instance. ```typescript import { encode, decode, stringify, parse, clone } from "codablejson"; // encode: converts any JS value to a plain JSONValue const data = { date: new Date("2025-01-01"), map: new Map([["key", "value"]]), set: new Set([1, 2, 3]), big: 9007199254740993n, nan: NaN, undef: undefined, }; const encoded = encode(data); // { // date: { $$Date: "2025-01-01T00:00:00.000Z" }, // map: { $$Map: [["key", "value"]] }, // set: { $$Set: [1, 2, 3] }, // big: { $$BigInt: "9007199254740993" }, // nan: { $$number: "NaN" }, // undef: { $$undefined: null } // } const decoded = decode(encoded); // decoded.date instanceof Date === true // decoded.map instanceof Map === true // decoded.set instanceof Set === true // typeof decoded.big === "bigint" // isNaN(decoded.nan) === true // decoded.undef === undefined // stringify / parse: encode then JSON.stringify / JSON.parse then decode const jsonStr = stringify(data); // single JSON string const restored = parse(jsonStr); // restored.date instanceof Date === true // clone: deep clone preserving all types AND internal reference equality const shared = { id: 1 }; const original = [shared, shared]; const cloned = clone(original); // cloned[0] === cloned[1] → true (reference equality preserved inside copy) // cloned[0] !== original[0] → true (independent copy) ``` -------------------------------- ### SuperJSON Compatibility Mode Source: https://context7.com/pie6k/codablejson/llms.txt Importing `codablejson/superjson` enables automatic decoding of data previously encoded by SuperJSON, facilitating a seamless migration. ```APIDOC ## SuperJSON Compatibility Mode Importing `codablejson/superjson` enables automatic decoding of data that was previously encoded by SuperJSON, making migration seamless. ```typescript // Import once early in your app entry point: import "codablejson/superjson"; import { decode } from "codablejson"; // Data encoded by the legacy SuperJSON library const superJsonOutput = { json: { date: "2025-01-01T00:00:00.000Z", count: 1 }, meta: { values: { date: ["Date"] } }, }; // CodableJSON automatically delegates to SuperJSON for decoding const decoded = decode(superJsonOutput); // decoded.date instanceof Date === true ``` ``` -------------------------------- ### File Persistence with CodableJSON Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/json-serialization/integrations.mdx Utilize this class for saving and loading rich data formats to disk, ensuring that complex types like Dates and Maps are preserved. ```typescript import { writeFileSync, readFileSync } from "fs"; import { stringify, parse } from "codablejson"; class FileStorage { constructor(private filePath: string) {} save(data: T): void { writeFileSync(this.filePath, stringify(data), "utf8"); } load(): T | null { try { const content = readFileSync(this.filePath, "utf8"); return parse(content); } catch { return null; } } } // Usage const projectStorage = new FileStorage<{ name: string; createdAt: Date; files: Map; }>("./project.json"); const project = { name: "My Project", createdAt: new Date(), files: new Map([ ["index.ts", { content: "console.info('hello')", modified: new Date() }] ]) }; projectStorage.save(project); const loaded = projectStorage.load(); // All types preserved: Date, Map, etc. ``` -------------------------------- ### Type-Safe Local Storage Wrapper Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/json-serialization/integrations.mdx Use this wrapper to create type-safe access to localStorage for complex data structures, ensuring type preservation for Dates, Sets, and Maps. ```typescript import { stringify, parse } from "codablejson"; class LocalStorageValue { constructor(private key: string) {} get(): T | null { const stored = localStorage.getItem(this.key); if (!stored) return null; try { return parse(stored); } catch { return null; } } set(value: T): void { localStorage.setItem(this.key, stringify(value)); } remove(): void { localStorage.removeItem(this.key); } } // Usage const userPrefs = new LocalStorageValue<{ theme: string; lastLogin: Date; favorites: Set; }>("user-preferences"); userPrefs.set({ theme: "dark", lastLogin: new Date(), favorites: new Set(["react", "typescript"]) }); const prefs = userPrefs.get(); // prefs.lastLogin instanceof Date === true // prefs.favorites instanceof Set === true ``` -------------------------------- ### Temporal API Support Source: https://github.com/pie6k/codablejson/blob/main/codablejson/README.md CodableJSON automatically supports all Temporal API types when `Temporal` is available globally, providing seamless encoding and decoding of time-related objects like `Instant`, `Duration`, and `ZonedDateTime`. ```APIDOC ## Temporal API Support CodableJSON automatically supports all Temporal API types when `Temporal` is available globally: `Instant`, `Duration`, `PlainDate`, `PlainDateTime`, `PlainMonthDay`, `PlainTime`, `PlainYearMonth`, and `ZonedDateTime`. If your environment doesn't natively support Temporal, import a polyfill before using CodableJSON: ```typescript import "temporal-polyfill/global"; import { encode, decode } from "codablejson"; const instant = Temporal.Instant.from("1970-01-01T00:00:00Z"); const encoded = encode(instant); // { $$Instant: "1970-01-01T00:00:00Z" } const decoded = decode(encoded); // decoded instanceof Temporal.Instant === true // Calculate duration between dates const start = Temporal.PlainDate.from("2024-01-01"); const end = Temporal.PlainDate.from("2025-12-25"); const duration = start.until(end); const encodedDuration = encode(duration); // { $$Duration: "P1Y11M24D" } ``` ``` -------------------------------- ### Key Mapping with @codableClass keys option Source: https://context7.com/pie6k/codablejson/llms.txt Use the `keys` option in @codableClass to specify properties for encoding and to rename them in the wire format. Properties not listed are not encoded. ```typescript import { codableClass, Coder } from "codablejson"; @codableClass("User", { keys: { firstName: "first_name", // instance key → wire key lastName: "last_name", email: "email", }, }) class User { firstName: string; lastName: string; email: string; passwordHash: string; // not in keys → never encoded constructor(data: Pick) { this.firstName = data.firstName; this.lastName = data.lastName; this.email = data.email; } } const coder = new Coder([User]); const user = new User({ firstName: "Jane", lastName: "Doe", email: "jane@example.com" }); const encoded = coder.encode(user); // { $$User: [{ first_name: "Jane", last_name: "Doe", email: "jane@example.com" }] } const decoded = coder.decode(encoded); // decoded.firstName === "Jane" (mapped back) // decoded.lastName === "Doe" ``` -------------------------------- ### @codable(options?) decorator Source: https://context7.com/pie6k/codablejson/llms.txt A field decorator that marks an individual property for serialization. It can be used to specify an alias for the key in the wire format or provide an options object for more advanced configurations. ```APIDOC ## `@codable(options?)` decorator Field decorator that marks an individual property for serialization. Optionally accepts an `encodeAs` string alias or an options object to rename the key in the wire format. ```typescript import { codableClass, codable, Coder } from "codablejson"; @codableClass("Product") class Product { @codable("product_id") // encode property 'id' as 'product_id' in JSON id: string; @codable("product_name") name: string; @codable({ encodeAs: "price_usd" }) price: number; secret: string = "never encoded"; // no @codable → not included constructor(data: Pick) { this.id = data.id; this.name = data.name; this.price = data.price; } } const coder = new Coder([Product]); const p = new Product({ id: "sku-42", name: "Widget", price: 19.99 }); const encoded = coder.encode(p); // { $$Product: [{ product_id: "sku-42", product_name: "Widget", price_usd: 19.99 }] } const decoded = coder.decode(encoded); // decoded.id === "sku-42" // decoded.name === "Widget" // decoded.price === 19.99 ``` ``` -------------------------------- ### Custom Types with References Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/json-serialization/references.mdx Demonstrates seamless reference preservation with custom class types using `codableType`. ```typescript class Node { constructor(public value: string, public parent?: Node) {} } const $$node = codableType( "Node", (value) => value instanceof Node, (node) => ({ value: node.value, parent: node.parent }), (data) => new Node(data.value, data.parent) ); const coder = new Coder([$$node]); const parent = new Node("parent"); const child = new Node("child", parent); const encoded = coder.encode([parent, child]); // [ // { $$Node: { value: "parent", parent: undefined } }, // { $$Node: { value: "child", parent: { $$ref: "/0" } } } // ] ``` -------------------------------- ### Node.js File Persistence with CodableJSON Source: https://context7.com/pie6k/codablejson/llms.txt Saves and loads data to/from files in a Node.js environment, utilizing CodableJSON for serialization and deserialization. ```typescript import { writeFileSync, readFileSync } from "fs"; function saveFile(path: string, data: T) { writeFileSync(path, stringify(data, true), "utf8"); } function loadFile(path: string): T { return parse(readFileSync(path, "utf8")); } ``` -------------------------------- ### Decode Options Configuration Source: https://context7.com/pie6k/codablejson/llms.txt Configure decoding behavior using options like `externalReferences` to supply runtime objects needed by `@external` fields. ```typescript import { decode } from "codablejson"; // externalReferences — supply runtime objects needed by @external fields const encoded = /* previously encoded data containing $$external stubs */ {}; const decoded = decode(encoded, { externalReferences: { db: myDatabaseInstance, logger: console, }, }); ``` -------------------------------- ### Temporal API Support Source: https://context7.com/pie6k/codablejson/llms.txt Automatically handles all Temporal types when the Temporal API is available globally. This includes encoding and decoding of various Temporal objects. ```typescript import "temporal-polyfill/global"; // only needed if Temporal is not natively available import { encode, decode } from "codablejson"; const instant = Temporal.Instant.from("1970-01-01T00:00:00Z"); const duration = Temporal.Duration.from({ years: 1, months: 6 }); const plainDate = Temporal.PlainDate.from("2025-06-15"); const zonedDt = Temporal.ZonedDateTime.from("2025-06-15T12:00:00+01:00[Europe/Paris]"); const encoded = encode({ instant, duration, plainDate, zonedDt }); // { // instant: { $$Instant: "1970-01-01T00:00:00Z" }, // duration: { $$Duration: "P1Y6M" }, // plainDate: { $$PlainDate: "2025-06-15" }, // zonedDt: { $$ZonedDateTime: "2025-06-15T12:00:00+01:00[Europe/Paris]" } // } const decoded = decode(encoded); // decoded.instant instanceof Temporal.Instant === true // decoded.duration instanceof Temporal.Duration === true // decoded.plainDate instanceof Temporal.PlainDate === true ``` -------------------------------- ### Encode and Decode Temporal API Types with CodableJSON Source: https://github.com/pie6k/codablejson/blob/main/README.md Automatically supports Temporal API types like Instant and Duration when Temporal is globally available. Import a polyfill if your environment does not natively support Temporal. ```typescript import { encode, decode } from "codablejson"; const instant = Temporal.Instant.from("1970-01-01T00:00:00Z"); const encoded = encode(instant); // { $$Instant: "1970-01-01T00:00:00Z" } const decoded = decode(encoded); // decoded instanceof Temporal.Instant === true // Calculate duration between dates const start = Temporal.PlainDate.from("2024-01-01"); const end = Temporal.PlainDate.from("2025-12-25"); const duration = start.until(end); const encodedDuration = encode(duration); // { $$Duration: "P1Y11M24D" } ``` -------------------------------- ### Define Codable Classes Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/index.mdx Mark your classes and properties as codable using the `@codableClass` and `@codable` decorators to enable declarative serialization. ```typescript import { codableClass, codable, Coder } from "codablejson"; // Mark your classes as codable with `@codableClass("ClassName")` @codableClass("Player") class Player { // Mark properties as codable with `@codable()` @codable() name: string; @codable() score: number; // Constructor is optional and not needed for CodableJSON to work. constructor(data: Pick) { this.name = data.name; this.score = data.score; } } @codableClass("GameState") class GameState { @codable() players: Set = new Set(); @codable() createdAt = new Date(); @codable() activePlayer: Player | null = null; // Custom methods work like normal. addPlayer(player: Player) { this.players.add(player); this.activePlayer = player; } } const gameState = new GameState(); gameState.addPlayer(new Player({ name: "Alice", score: 100 })); ``` -------------------------------- ### Serialize and Deserialize GameState Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/declarative-serialization/index.mdx Create a `Coder` instance aware of your classes to serialize and deserialize complex objects directly. This handles nested structures and custom types like `Set` and `Date` automatically. ```typescript const coder = new Coder([GameState]); const gameState = new GameState(); gameState.addPlayer(new Player({ name: "Alice", score: 100 })); // Serialize directly const encoded = coder.encode(gameState); // Deserialize back to your classes const decoded = coder.decode(encoded); ``` -------------------------------- ### Encode and Decode Temporal Instant Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/json-serialization/temporal.mdx Encodes a Temporal Instant to its ISO 8601 string representation and decodes it back to a Temporal.Instant instance. ```typescript import { encode, decode } from "codablejson"; const instant = Temporal.Instant.from("1970-01-01T00:00:00.000000000Z"); const encoded = encode(instant); // { $$Instant: "1970-01-01T00:00:00Z" } const decoded = decode(encoded); // decoded instanceof Temporal.Instant === true // decoded.equals(instant) === true ``` -------------------------------- ### Managing Dependencies with the `dependencies` Option Source: https://context7.com/pie6k/codablejson/llms.txt Declare dependencies for codable classes and custom types using the `dependencies` option. This allows registering only the root type to automatically discover all transitive types. Supports plain arrays or function thunks for circular dependencies. ```typescript import { codableClass, codable, Coder } from "codablejson"; @codableClass("Comment", { dependencies: () => [User] }) class Comment { @codable() text: string; @codable() author: User; constructor(data: Pick) { this.text = data.text; this.author = data.author; } } @codableClass("User", { dependencies: () => [Comment] }) class User { @codable() name: string; @codable() comments: Comment[] = []; constructor(data: Pick) { this.name = data.name; } } // Register only the root type — Comment and User are both discovered automatically const coder = new Coder([User]); const alice = new User({ name: "Alice" }); alice.comments.push(new Comment({ text: "Hello!", author: alice })); const encoded = coder.encode(alice); const decoded = coder.decode(encoded); // decoded.comments[0].author === decoded (circular reference preserved) ``` -------------------------------- ### Encode and Decode with Custom Coder Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/index.mdx Create a `Coder` instance with your codable classes to encode and decode complex object graphs, preserving types and references. ```typescript const gameCoder = new Coder([GameState]); const encoded = gameCoder.encode(gameState); ``` ```json { "$$GameState": [ { "players": { "$$Set": [{ "$$Player": [{ "name": "Foo", "score": 100 }] }] }, "createdAt": { "$$Date": "2025-11-27T23:00:00.000Z" }, "activePlayer": { "$$ref": "/$$GameState/0/players/$$Set/0" } } ] } ``` ```typescript const decoded = gameCoder.decode(encoded); // decoded.players is Set // decoded.createdAt is Date // decoded.activePlayer is Player | null ``` -------------------------------- ### Combining Class-Level and Property-Level Key Mappings Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/declarative-serialization/customization.mdx Class-level `keys` options and property-level `@codable()` decorators can be used together. Mappings are merged, with property-level mappings taking precedence. ```typescript import { codableClass, codable, Coder } from "codablejson"; @codableClass("Order", { keys: { orderDate: "date", totalAmount: "total" } }) class Order { @codable("order_id") id: string; orderDate: Date; totalAmount: number; constructor(data: Pick) { this.id = data.id; this.orderDate = data.orderDate; this.totalAmount = data.totalAmount; } } const coder = new Coder([Order]); const order = new Order({ id: "order-456", orderDate: new Date(), totalAmount: 99.99 }); const encoded = coder.encode(order); // { $$Order: [{ order_id: "order-456", date: "2025-01-01T00:00:00.000Z", total: 99.99 }]} ``` -------------------------------- ### Migrate from SuperJSON to CodableJSON Source: https://github.com/pie6k/codablejson/blob/main/codablejson/README.md Replace SuperJSON imports and usage with CodableJSON for simple JSON serialization. For custom types, refer to the custom types documentation. ```typescript // Before import { stringify, parse } from "superjson"; const serialized = stringify(data); const deserialized = parse(serialized); // After import { stringify, parse } from "codablejson"; const serialized = stringify(data); const deserialized = parse(serialized); ``` -------------------------------- ### Memberwise Constructor with Specific Properties Source: https://github.com/pie6k/codablejson/blob/main/docs/src/content/declarative-serialization/memberwise-constructor.mdx Use `Memberwise` to create a constructor that only requires a specific property, like 'name', to be present. ```typescript @codableClass("User") class User { @codable() name!: string; nonCodable!: string; anotherNonCodable!: number; yetAnotherNonCodable!: boolean; someMethod() {} // Only 'name' property (other properties are not codable) constructor(data: Memberwise) { Object.assign(this, data); } } ```