UNPKG

@macroforge/mcp-server

Version:

MCP server for Macroforge documentation and code analysis

146 lines (115 loc) • 5.99 kB
# Serialize The `Serialize` macro generates JSON serialization methods with **cycle detection** and object identity tracking. This enables serialization of complex object graphs including circular references. ## Generated Methods | Type | Generated Code | Description | | ---------- | ------------------------------------------------------------------------------------- | ------------------------------------------- | | Class | `classNameSerialize(value, keepMetadata?)` + `static serialize(value, keepMetadata?)` | Standalone function + static wrapper method | | Enum | `enumNameSerialize(value)`, `enumNameSerializeWithContext` | Standalone functions | | Interface | `interfaceNameSerialize(value)`, etc. | Standalone functions | | Type Alias | `typeNameSerialize(value)`, etc. | Standalone functions | ## Cycle Detection Protocol The generated code handles circular references using `__id` and `__ref` markers: ```json { "__type": "User", "__id": 1, "name": "Alice", "friend": { "__ref": 2 } // Reference to object with __id: 2 } ``` When an object is serialized: 1. Check if it's already been serialized (has an `__id`) 2. If so, return `{ "__ref": existingId }` instead 3. Otherwise, register the object and serialize its fields ## Type-Specific Serialization | Type | Serialization Strategy | | ----------------------------------------- | -------------------------------------------------------------------------------- | | Primitives | Direct value | | `Date` | `toISOString()` | | Arrays | For primitive-like element types, pass through; for `Date`/`Date | | `Map<K,V>` | For primitive-like values, `Object.fromEntries(map.entries())`; for `Date`/`Date | | `Set<T>` | Convert to array; element handling matches `Array<T>` | | `Record<K,V>` | For primitive-like values, pass through; for `Date`/`Date | | Wrappers (`Partial<T>`, `Pick<T,K>`, ...) | Serialize based on the inner type `T` | | Nullable | Include `null` explicitly; non-null values follow the inner type's strategy | | Objects | Call the type's `nameSerializeWithContext` function | Note: which strategy applies is resolved **statically** from the field's declared TypeScript type at expansion time — there is no runtime feature detection. ## Field-Level Options The `@serde` decorator supports: - `skip` / `skipSerializing` - Exclude field from serialization - `rename = "jsonKey"` - Use different JSON property name - `flatten` - Merge nested object's fields into parent ## Example ```typescript before /** @derive(Serialize) */ class User { id: number; /** @serde({ rename: "userName" }) */ name: string; /** @serde({ skipSerializing: true }) */ password: string; /** @serde({ flatten: true }) */ metadata: UserMetadata; } ``` ```typescript after import { SerializeContext } from '@macroforge/core/serde'; class User { id: number; name: string; password: string; metadata: UserMetadata; /** Serializes a value to a JSON string. @param value - The value to serialize @returns JSON string representation with cycle detection metadata */ static serialize(value: User, keepMetadata?: boolean): string { return userSerialize(value, keepMetadata); } /** @internal Serializes with an existing context for nested/cyclic object graphs. @param value - The value to serialize @param ctx - The serialization context */ static serializeWithContext(value: User, ctx: __mf_SerializeContext): Record<string, unknown> { return userSerializeWithContext(value, ctx); } } /** Serializes a value to a JSON string. @param value - The value to serialize @returns JSON string representation with cycle detection metadata */ export function userSerialize( value: User, keepMetadata?: boolean ): string { const ctx = __mf_SerializeContext.create(); const __raw = userSerializeWithContext(value, ctx); if (keepMetadata) return JSON.stringify(__raw); return JSON.stringify( __raw, (key, val) => key === '__type' || key === '__id' ? undefined : val ); } /** @internal Serializes with an existing context for nested/cyclic object graphs. @param value - The value to serialize @param ctx - The serialization context */ export function userSerializeWithContext( value: User, ctx: SerializeContext ): Record<string, unknown> { const existingId = ctx.getId(value); if (existingId !== undefined) { return { __ref: existingId }; } const __id = ctx.register(value); const result: Record<string, unknown> = { __type: 'User', __id }; result['id'] = value.id; result['userName'] = value.name; { const __flattened = userMetadataSerializeWithContext(value.metadata, ctx); const { __type: _, __id: __, ...rest } = __flattened as any; // tag field name is configurable via `tag` option Object.assign(result, rest); } return result; } ``` ## Required Import The generated code automatically imports `SerializeContext` from `@macroforge/core/serde`.