@macroforge/mcp-server 0.1.33 → 0.1.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +68 -0
  2. package/dist/index.d.ts +32 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +46 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/tools/docs-loader.d.ts +133 -5
  7. package/dist/tools/docs-loader.d.ts.map +1 -1
  8. package/dist/tools/docs-loader.js +131 -15
  9. package/dist/tools/docs-loader.js.map +1 -1
  10. package/dist/tools/index.d.ts +48 -1
  11. package/dist/tools/index.d.ts.map +1 -1
  12. package/dist/tools/index.js +163 -14
  13. package/dist/tools/index.js.map +1 -1
  14. package/docs/api/api-overview.md +24 -46
  15. package/docs/api/expand-sync.md +24 -51
  16. package/docs/api/native-plugin.md +24 -56
  17. package/docs/api/position-mapper.md +34 -76
  18. package/docs/api/transform-sync.md +27 -59
  19. package/docs/builtin-macros/clone.md +45 -104
  20. package/docs/builtin-macros/debug.md +33 -104
  21. package/docs/builtin-macros/default.md +78 -114
  22. package/docs/builtin-macros/deserialize.md +93 -273
  23. package/docs/builtin-macros/hash.md +58 -100
  24. package/docs/builtin-macros/macros-overview.md +42 -103
  25. package/docs/builtin-macros/ord.md +65 -133
  26. package/docs/builtin-macros/partial-eq.md +53 -179
  27. package/docs/builtin-macros/partial-ord.md +67 -159
  28. package/docs/builtin-macros/serialize.md +64 -194
  29. package/docs/concepts/architecture.md +40 -99
  30. package/docs/concepts/derive-system.md +129 -125
  31. package/docs/concepts/how-macros-work.md +52 -84
  32. package/docs/custom-macros/custom-overview.md +17 -39
  33. package/docs/custom-macros/rust-setup.md +22 -55
  34. package/docs/custom-macros/ts-macro-derive.md +43 -107
  35. package/docs/custom-macros/ts-quote.md +177 -507
  36. package/docs/getting-started/first-macro.md +108 -33
  37. package/docs/getting-started/installation.md +32 -73
  38. package/docs/integration/cli.md +70 -156
  39. package/docs/integration/configuration.md +32 -75
  40. package/docs/integration/integration-overview.md +16 -55
  41. package/docs/integration/mcp-server.md +30 -69
  42. package/docs/integration/svelte-preprocessor.md +60 -83
  43. package/docs/integration/typescript-plugin.md +32 -74
  44. package/docs/integration/vite-plugin.md +30 -79
  45. package/docs/language-servers/ls-overview.md +22 -46
  46. package/docs/language-servers/svelte.md +30 -69
  47. package/docs/language-servers/zed.md +34 -72
  48. package/docs/roadmap/roadmap.md +54 -130
  49. package/docs/sections.json +3 -262
  50. package/package.json +2 -2
@@ -1,138 +1,102 @@
1
1
  # Default
2
2
 
3
- *The `Default` macro generates a static `defaultValue()` factory method that creates instances with default field values. It works like Rust's `#[derive(Default)]` trait.*
3
+ The `Default` macro generates a static `defaultValue()` factory method that creates
4
+ instances with default values. This is analogous to Rust's `Default` trait, providing
5
+ a standard way to create "zero" or "empty" instances of types.
4
6
 
5
- ## Basic Usage
7
+ ## Generated Output
6
8
 
7
- <MacroExample before={data.examples.basic.before} after={data.examples.basic.after} />
9
+ | Type | Generated Code | Description |
10
+ |------|----------------|-------------|
11
+ | Class | `static defaultValue(): ClassName` | Static factory method |
12
+ | Enum | `defaultValueEnumName(): EnumName` | Standalone function returning marked variant |
13
+ | Interface | `defaultValueInterfaceName(): InterfaceName` | Standalone function returning object literal |
14
+ | Type Alias | `defaultValueTypeName(): TypeName` | Standalone function with type-appropriate default |
8
15
 
9
- ```typescript
10
- const config = Config.defaultValue();
11
- console.log(config.host); // ""
12
- console.log(config.port); // 0
13
- console.log(config.enabled); // false
14
- ```
15
-
16
- ## Automatic Default Values
17
-
18
- Like Rust's `Default` trait, the macro automatically determines default values for primitive types and common collections:
19
-
20
- | `string` | `""` | `String::default()`
21
-
22
- | `number` | `0` | `i32::default()`
23
-
24
- | `boolean` | `false` | `bool::default()`
25
-
26
- | `bigint` | `0n` | `i64::default()`
27
-
28
- | `T[]` / `Array<T>` | `[]` | `Vec::default()`
29
-
30
- | `Map<K, V>` | `new Map()` | `HashMap::default()`
31
-
32
- | `Set<T>` | `new Set()` | `HashSet::default()`
33
-
34
- | `Date` | `new Date()` | —
35
-
36
- | `T | null` / `T | undefined` | `null` | `Option::default()`
37
-
38
- | Custom types | **Error** | **Error** (needs `impl Default`)
39
-
40
- ## Nullable Types (like Rust's Option)
41
-
42
- Just like Rust's `Option<T>` defaults to `None`, nullable TypeScript types automatically default to `null`:
43
-
44
- <MacroExample before={data.examples.nullable.before} after={data.examples.nullable.after} />
45
-
46
- ```typescript
47
- const user = User.defaultValue();
48
- console.log(user.name); // ""
49
- console.log(user.email); // null (nullable type)
50
- console.log(user.age); // 0
51
- console.log(user.metadata); // null (nullable type)
52
- ```
53
-
54
- ## Custom Types Require @default
55
-
56
- Just like Rust requires `impl Default` for custom types, Macroforge requires the `@default()` decorator on fields with non-primitive types:
57
-
58
- <MacroExample before={data.examples.customType.before} after={data.examples.customType.after} />
59
-
60
- <p class="text-red-500 text-sm mt-2">
61
- Without `@default` on custom type fields, the macro will emit an error:
62
- </p>
16
+ ## Configuration
63
17
 
64
- ```text
65
- // Error: @derive(Default) cannot determine default for non-primitive fields.
66
- // Add @default(value) to: settings, permissions
67
- ```
18
+ The `functionNamingStyle` option in `macroforge.json` controls naming:
19
+ - `"suffix"` (default): Suffixes with type name (e.g., `defaultValueMyType`)
20
+ - `"prefix"`: Prefixes with type name (e.g., `myTypeDefaultValue`)
21
+ - `"generic"`: Uses TypeScript generics (e.g., `defaultValue<T extends MyType>`)
22
+ - `"namespace"`: Legacy namespace wrapping
68
23
 
69
- ## Custom Default Values
24
+ ## Default Values by Type
70
25
 
71
- Use the `@default()` decorator to specify custom default values for any field:
26
+ The macro uses Rust-like default semantics:
72
27
 
73
- <MacroExample before={data.examples.custom.before} after={data.examples.custom.after} />
28
+ | Type | Default Value |
29
+ |------|---------------|
30
+ | `string` | `""` (empty string) |
31
+ | `number` | `0` |
32
+ | `boolean` | `false` |
33
+ | `bigint` | `0n` |
34
+ | `T[]` | `[]` (empty array) |
35
+ | `Array<T>` | `[]` (empty array) |
36
+ | `Map<K,V>` | `new Map()` |
37
+ | `Set<T>` | `new Set()` |
38
+ | `Date` | `new Date()` (current time) |
39
+ | `T \| null` | `null` |
40
+ | `CustomType` | `CustomType.defaultValue()` (recursive) |
74
41
 
75
- ```typescript
76
- const config = ServerConfig.defaultValue();
77
- console.log(config.host); // "localhost"
78
- console.log(config.port); // 8080
79
- console.log(config.enabled); // true
80
- console.log(config.logLevels); // ["info", "error"]
81
- ```
42
+ ## Field-Level Options
82
43
 
83
- ## Interface Support
44
+ The `@default` decorator allows specifying explicit default values:
84
45
 
85
- Default also works with interfaces. For interfaces, a namespace is generated with a `defaultValue()` function:
46
+ - `@default(42)` - Use 42 as the default
47
+ - `@default("hello")` - Use "hello" as the default
48
+ - `@default([])` - Use empty array as the default
49
+ - `@default({ value: "test" })` - Named form for complex values
86
50
 
87
- <MacroExample before={data.examples.interface.before} after={data.examples.interface.after} />
51
+ ## Example
88
52
 
89
53
  ```typescript
90
- const origin = Point.defaultValue();
91
- console.log(origin); // { x: 0, y: 0 }
54
+ @derive(Default)
55
+ class UserSettings {
56
+ @default("light")
57
+ theme: string;
58
+
59
+ @default(10)
60
+ pageSize: number;
61
+
62
+ notifications: boolean; // Uses type default: false
63
+ }
64
+
65
+ // Generated:
66
+ // static defaultValue(): UserSettings {
67
+ // const instance = new UserSettings();
68
+ // instance.theme = "light";
69
+ // instance.pageSize = 10;
70
+ // instance.notifications = false;
71
+ // return instance;
72
+ // }
92
73
  ```
93
74
 
94
- ## Enum Support
75
+ ## Enum Defaults
95
76
 
96
- Default works with enums. For enums, it returns the first variant as the default value:
97
-
98
- <MacroExample before={data.examples.enum.before} after={data.examples.enum.after} />
77
+ For enums, mark one variant with `@default`:
99
78
 
100
79
  ```typescript
101
- const defaultStatus = Status.defaultValue();
102
- console.log(defaultStatus); // "pending"
80
+ @derive(Default)
81
+ enum Status {
82
+ @default
83
+ Pending,
84
+ Active,
85
+ Completed
86
+ }
87
+
88
+ // Generated:
89
+ // export namespace Status {
90
+ // export function defaultValue(): Status {
91
+ // return Status.Pending;
92
+ // }
93
+ // }
103
94
  ```
104
95
 
105
- ## Type Alias Support
106
-
107
- Default works with type aliases. For object types, it creates an object with default field values:
96
+ ## Error Handling
108
97
 
109
- <MacroExample before={data.examples.typeAlias.before} after={data.examples.typeAlias.after} />
110
-
111
- ```typescript
112
- const dims = Dimensions.defaultValue();
113
- console.log(dims); // { width: 0, height: 0 }
114
- ```
115
-
116
- ## Combining with Other Macros
117
-
118
- <InteractiveMacro code={`/** @derive(Default, Debug, Clone, PartialEq) */
119
- class User {
120
- /** @default("Anonymous") */
121
- name: string;
122
-
123
- /** @default(0) */
124
- age: number;
125
-
126
- constructor(name: string, age: number) {
127
- this.name = name;
128
- this.age = age;
129
- }
130
- }`} />
131
-
132
- ```typescript
133
- const user1 = User.defaultValue();
134
- const user2 = user1.clone();
98
+ The macro will return an error if:
135
99
 
136
- console.log(user1.toString()); // User { name: "Anonymous", age: 0 }
137
- console.log(user1.equals(user2)); // true
138
- ```
100
+ - A non-primitive field lacks `@default` and has no known default
101
+ - An enum has no variant marked with `@default`
102
+ - A union type has no `@default` on a variant
@@ -1,317 +1,137 @@
1
1
  # Deserialize
2
2
 
3
- *The `Deserialize` macro generates a static `fromJSON()` method that parses JSON data into your class with runtime validation and automatic type conversion.*
3
+ The `Deserialize` macro generates JSON deserialization methods with **cycle and
4
+ forward-reference support**, plus comprehensive runtime validation. This enables
5
+ safe parsing of complex JSON structures including circular references.
4
6
 
5
- ## Basic Usage
7
+ ## Generated Output
6
8
 
7
- <MacroExample before={data.examples.basic.before} after={data.examples.basic.after} />
9
+ | Type | Generated Code | Description |
10
+ |------|----------------|-------------|
11
+ | Class | `static fromStringifiedJSON()`, `static fromObject()`, `static __deserialize()` | Static factory methods |
12
+ | Enum | `fromStringifiedJSONEnumName(json)`, `__deserializeEnumName(data)`, `isEnumName(value)` | Standalone functions |
13
+ | Interface | `fromStringifiedJSONInterfaceName(json)`, `fromObjectInterfaceName(obj)`, etc. | Standalone functions |
14
+ | Type Alias | `fromStringifiedJSONTypeName(json)`, `fromObjectTypeName(obj)`, etc. | Standalone functions |
8
15
 
9
- ```typescript
10
- const json = '{"name":"Alice","age":30,"createdAt":"2024-01-15T10:30:00.000Z"}';
11
- const user = User.fromJSON(JSON.parse(json));
16
+ ## Configuration
12
17
 
13
- console.log(user.name); // "Alice"
14
- console.log(user.age); // 30
15
- console.log(user.createdAt instanceof Date); // true
16
- ```
18
+ The `functionNamingStyle` option in `macroforge.json` controls naming:
19
+ - `"suffix"` (default): Suffixes with type name (e.g., `fromStringifiedJSONMyType`)
20
+ - `"prefix"`: Prefixes with type name (e.g., `myTypeFromStringifiedJSON`)
21
+ - `"generic"`: Uses TypeScript generics (e.g., `fromStringifiedJSON<T extends MyType>`)
22
+ - `"namespace"`: Legacy namespace wrapping
17
23
 
18
- ## Runtime Validation
24
+ ## Return Type
19
25
 
20
- Deserialize validates the input data and throws descriptive errors:
26
+ All public deserialization methods return `Result<T, Array<{ field: string; message: string }>>`:
21
27
 
22
- <InteractiveMacro code={`/** @derive(Deserialize) */
23
- class User {
24
- name: string;
25
- email: string;
26
- }`} />
28
+ - `Result.ok(value)` - Successfully deserialized value
29
+ - `Result.err(errors)` - Array of validation errors with field names and messages
27
30
 
28
- ```typescript
29
- // Missing required field
30
- User.fromJSON({ name: "Alice" });
31
- // Error: User.fromJSON: missing required field "email"
31
+ ## Cycle/Forward-Reference Support
32
32
 
33
- // Wrong type
34
- User.fromJSON("not an object");
35
- // Error: User.fromJSON: expected an object, got string
33
+ Uses deferred patching to handle references:
36
34
 
37
- // Array instead of object
38
- User.fromJSON([1, 2, 3]);
39
- // Error: User.fromJSON: expected an object, got array
40
- ```
35
+ 1. When encountering `{ "__ref": id }`, returns a `PendingRef` marker
36
+ 2. Continues deserializing other fields
37
+ 3. After all objects are created, `ctx.applyPatches()` resolves all pending references
41
38
 
42
- ## Automatic Type Conversion
39
+ References only apply to object-shaped, serializable values. The generator avoids probing for
40
+ `__ref` on primitive-like fields (including literal unions and `T | null` where `T` is primitive-like),
41
+ and it parses `Date` / `Date | null` from ISO strings without treating them as references.
43
42
 
44
- Deserialize automatically converts JSON types to their TypeScript equivalents:
43
+ ## Validation
45
44
 
46
- | string/number/boolean
47
- | `string`/`number`/`boolean`
48
- | Direct assignment
45
+ The macro supports 30+ validators via `@serde(validate(...))`:
49
46
 
50
- | ISO string
51
- | `Date`
52
- | `new Date(string)`
47
+ ### String Validators
48
+ - `email`, `url`, `uuid` - Format validation
49
+ - `minLength(n)`, `maxLength(n)`, `length(n)` - Length constraints
50
+ - `pattern("regex")` - Regular expression matching
51
+ - `nonEmpty`, `trimmed`, `lowercase`, `uppercase` - String properties
53
52
 
54
- | array
55
- | `T[]`
56
- | Maps items with auto-detection
53
+ ### Number Validators
54
+ - `gt(n)`, `gte(n)`, `lt(n)`, `lte(n)`, `between(min, max)` - Range checks
55
+ - `int`, `positive`, `nonNegative`, `finite` - Number properties
57
56
 
58
- | object
59
- | `Map<K, V>`
60
- | `new Map(Object.entries())`
57
+ ### Array Validators
58
+ - `minItems(n)`, `maxItems(n)`, `itemsCount(n)` - Collection size
61
59
 
62
- | array
63
- | `Set<T>`
64
- | `new Set(array)`
60
+ ### Date Validators
61
+ - `validDate`, `afterDate("ISO")`, `beforeDate("ISO")` - Date validation
65
62
 
66
- | object
67
- | Nested class
68
- | Calls `fromJSON()` if available
63
+ ## Field-Level Options
69
64
 
70
- ## Serde Options
65
+ The `@serde` decorator supports:
71
66
 
72
- Use the `@serde` decorator to customize deserialization:
73
-
74
- ### Renaming Fields
75
-
76
- <MacroExample before={data.examples.rename.before} after={data.examples.rename.after} />
77
-
78
- ```typescript
79
- const user = User.fromJSON({ user_id: "123", full_name: "Alice" });
80
- console.log(user.id); // "123"
81
- console.log(user.name); // "Alice"
82
- ```
67
+ - `skip` / `skip_deserializing` - Exclude field from deserialization
68
+ - `rename = "jsonKey"` - Read from different JSON property
69
+ - `default` / `default = expr` - Use default value if missing
70
+ - `flatten` - Read fields from parent object level
71
+ - `validate(...)` - Apply validators
83
72
 
84
- ### Default Values
73
+ ## Container-Level Options
85
74
 
86
- <MacroExample before={data.examples.default.before} after={data.examples.default.after} />
75
+ - `deny_unknown_fields` - Error on unrecognized JSON properties
76
+ - `rename_all = "camelCase"` - Apply naming convention to all fields
87
77
 
88
- ```typescript
89
- const config = Config.fromJSON({ host: "localhost" });
90
- console.log(config.port); // "3000"
91
- console.log(config.debug); // false
92
- ```
78
+ ## Union Type Deserialization
93
79
 
94
- ### Skipping Fields
80
+ Union types are deserialized based on their member types:
95
81
 
96
- <InteractiveMacro code={`/** @derive(Deserialize) */
97
- class User {
98
- name: string;
99
- email: string;
82
+ ### Literal Unions
83
+ For unions of literal values (`"A" | "B" | 123`), the value is validated against
84
+ the allowed literals directly.
100
85
 
101
- /** @serde({ skip: true }) */
102
- cachedData: unknown;
86
+ ### Primitive Unions
87
+ For unions containing primitive types (`string | number`), the deserializer uses
88
+ `typeof` checks to validate the value type. No `__type` discriminator is needed.
103
89
 
104
- /** @serde({ skip_deserializing: true }) */
105
- computedField: string;
106
- }`} />
90
+ ### Class/Interface Unions
91
+ For unions of serializable types (`User | Admin`), the deserializer requires a
92
+ `__type` field in the JSON to dispatch to the correct type's `__deserialize` method.
107
93
 
108
- <Alert type="tip" title="skip vs skip_deserializing">
109
- Use `skip: true` to exclude from both serialization and deserialization.
110
- Use `skip_deserializing: true` to only skip during deserialization.
111
- </Alert>
94
+ ### Generic Type Parameters
95
+ For generic unions like `type Result<T> = T | Error`, the generic type parameter `T`
96
+ is passed through as-is since its concrete type is only known at the call site.
112
97
 
113
- ### Deny Unknown Fields
98
+ ### Mixed Unions
99
+ Mixed unions (e.g., `string | Date | User`) check in order:
100
+ 1. Literal values
101
+ 2. Primitives (via `typeof`)
102
+ 3. Date (via `instanceof` or ISO string parsing)
103
+ 4. Serializable types (via `__type` dispatch)
104
+ 5. Generic type parameters (pass-through)
114
105
 
115
- <InteractiveMacro code={`/** @derive(Deserialize) */
116
- /** @serde({ deny_unknown_fields: true }) */
117
- class StrictUser {
118
- name: string;
119
- email: string;
120
- }`} />
106
+ ## Example
121
107
 
122
108
  ```typescript
123
- // This will throw an error
124
- StrictUser.fromJSON({ name: "Alice", email: "a@b.com", extra: "field" });
125
- // Error: StrictUser.fromJSON: unknown field "extra"
126
- ```
127
-
128
- ### Flatten Nested Objects
129
-
130
- <InteractiveMacro code={`/** @derive(Deserialize) */
131
- class Address {
132
- city: string;
133
- zip: string;
134
- }
135
-
136
- /** @derive(Deserialize) */
109
+ @derive(Deserialize)
110
+ @serde(deny_unknown_fields)
137
111
  class User {
138
- name: string;
112
+ id: number;
139
113
 
140
- /** @serde({ flatten: true }) */
141
- address: Address;
142
- }`} />
114
+ @serde(validate(email, maxLength(255)))
115
+ email: string;
143
116
 
144
- ```typescript
145
- // Flat JSON structure
146
- const user = User.fromJSON({
147
- name: "Alice",
148
- city: "NYC",
149
- zip: "10001"
150
- });
151
- console.log(user.address.city); // "NYC"
152
- ```
153
-
154
- ## All Options
155
-
156
- ### Container Options (on class/interface)
157
-
158
- | `rename_all`
159
- | `string`
160
- | Apply naming convention to all fields
161
-
162
- | `deny_unknown_fields`
163
- | `boolean`
164
- | Throw error if JSON has unknown keys
165
-
166
- ### Field Options (on properties)
167
-
168
- | `rename`
169
- | `string`
170
- | Use a different JSON key
171
-
172
- | `skip`
173
- | `boolean`
174
- | Exclude from serialization and deserialization
175
-
176
- | `skip_deserializing`
177
- | `boolean`
178
- | Exclude from deserialization only
179
-
180
- | `default`
181
- | `boolean | string`
182
- | Use TypeScript default or custom expression if missing
183
-
184
- | `flatten`
185
- | `boolean`
186
- | Merge nested object fields from parent
187
-
188
- ## Interface Support
189
-
190
- Deserialize also works with interfaces. For interfaces, a namespace is generated with `is` (type guard) and `fromJSON` functions:
191
-
192
- <MacroExample before={data.examples.interface.before} after={data.examples.interface.after} />
193
-
194
- ```typescript
195
- const json = { status: 200, message: "OK", timestamp: "2024-01-15T10:30:00.000Z" };
117
+ @serde(default = "guest")
118
+ name: string;
196
119
 
197
- // Type guard
198
- if (ApiResponse.is(json)) {
199
- console.log(json.status); // TypeScript knows this is ApiResponse
120
+ @serde(validate(positive))
121
+ age?: number;
200
122
  }
201
123
 
202
- // Deserialize with validation
203
- const response = ApiResponse.fromJSON(json);
204
- console.log(response.timestamp instanceof Date); // true
205
- ```
206
-
207
- ## Enum Support
208
-
209
- Deserialize also works with enums. The `fromJSON` function validates that the input matches one of the enum values:
210
-
211
- <MacroExample before={data.examples.enum.before} after={data.examples.enum.after} />
212
-
213
- ```typescript
214
- const status = Status.fromJSON("active");
215
- console.log(status); // Status.Active
216
-
217
- // Invalid values throw an error
218
- try {
219
- Status.fromJSON("invalid");
220
- } catch (e) {
221
- console.log(e.message); // "Invalid Status value: invalid"
124
+ // Usage:
125
+ const result = User.fromStringifiedJSON('{"id":1,"email":"test@example.com"}');
126
+ if (Result.isOk(result)) {
127
+ const user = result.value;
128
+ } else {
129
+ console.error(result.error); // [{ field: "email", message: "must be a valid email" }]
222
130
  }
223
131
  ```
224
132
 
225
- Works with numeric enums too:
226
-
227
- <InteractiveMacro code={`/** @derive(Deserialize) */
228
- enum Priority {
229
- Low = 1,
230
- Medium = 2,
231
- High = 3,
232
- }`} />
233
-
234
- ```typescript
235
- const priority = Priority.fromJSON(3);
236
- console.log(priority); // Priority.High
237
- ```
238
-
239
- ## Type Alias Support
240
-
241
- Deserialize works with type aliases. For object types, validation and type conversion is applied:
242
-
243
- <MacroExample before={data.examples.typeAlias.before} after={data.examples.typeAlias.after} />
244
-
245
- ```typescript
246
- const json = {
247
- id: "123",
248
- name: "Alice",
249
- createdAt: "2024-01-15T00:00:00.000Z"
250
- };
251
-
252
- const profile = UserProfile.fromJSON(json);
253
- console.log(profile.createdAt instanceof Date); // true
254
- ```
255
-
256
- For union types, basic validation is applied:
257
-
258
- <InteractiveMacro code={`/** @derive(Deserialize) */
259
- type ApiStatus = "loading" | "success" | "error";`} />
260
-
261
- ```typescript
262
- const status = ApiStatus.fromJSON("success");
263
- console.log(status); // "success"
264
- ```
265
-
266
- ## Combining with Serialize
267
-
268
- Use both Serialize and Deserialize for complete JSON round-trip support:
269
-
270
- <InteractiveMacro code={`/** @derive(Serialize, Deserialize) */
271
- /** @serde({ rename_all: "camelCase" }) */
272
- class UserProfile {
273
- user_name: string;
274
- created_at: Date;
275
- is_active: boolean;
276
- }`} />
277
-
278
- ```typescript
279
- // Create and serialize
280
- const profile = new UserProfile();
281
- profile.user_name = "Alice";
282
- profile.created_at = new Date();
283
- profile.is_active = true;
284
-
285
- const json = JSON.stringify(profile);
286
- // {"userName":"Alice","createdAt":"2024-...","isActive":true}
287
-
288
- // Deserialize back
289
- const restored = UserProfile.fromJSON(JSON.parse(json));
290
- console.log(restored.user_name); // "Alice"
291
- console.log(restored.created_at instanceof Date); // true
292
- ```
293
-
294
- ## Error Handling
295
-
296
- Handle deserialization errors gracefully:
297
-
298
- <InteractiveMacro code={`/** @derive(Deserialize) */
299
- class User {
300
- name: string;
301
- email: string;
302
- }`} />
303
-
304
- ```typescript
305
- function parseUser(json: unknown): User | null {
306
- try {
307
- return User.fromJSON(json);
308
- } catch (error) {
309
- console.error("Failed to parse user:", error.message);
310
- return null;
311
- }
312
- }
133
+ ## Required Imports
313
134
 
314
- const user = parseUser({ name: "Alice" });
315
- // Logs: Failed to parse user: User.fromJSON: missing required field "email"
316
- // Returns: null
317
- ```
135
+ The generated code automatically imports:
136
+ - `Result` from `macroforge/utils`
137
+ - `DeserializeContext`, `DeserializeError`, `PendingRef` from `macroforge/serde`