@macroforge/mcp-server 0.1.17 → 0.1.20
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.
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +108 -0
- package/dist/tools/index.js.map +1 -1
- package/docs/builtin-macros/clone.md +18 -77
- package/docs/builtin-macros/debug.md +19 -118
- package/docs/builtin-macros/default.md +13 -98
- package/docs/builtin-macros/deserialize.md +38 -383
- package/docs/builtin-macros/hash.md +16 -98
- package/docs/builtin-macros/macros-overview.md +33 -9
- package/docs/builtin-macros/ord.md +16 -115
- package/docs/builtin-macros/partial-eq.md +26 -128
- package/docs/builtin-macros/partial-ord.md +19 -99
- package/docs/builtin-macros/serialize.md +28 -126
- package/docs/concepts/architecture.md +27 -58
- package/docs/concepts/derive-system.md +17 -45
- package/docs/concepts/how-macros-work.md +11 -50
- package/docs/custom-macros/custom-overview.md +4 -5
- package/docs/custom-macros/rust-setup.md +3 -4
- package/docs/custom-macros/ts-macro-derive.md +4 -5
- package/docs/custom-macros/ts-quote.md +2 -2
- package/docs/getting-started/first-macro.md +6 -72
- package/docs/getting-started/installation.md +2 -2
- package/docs/integration/integration-overview.md +21 -14
- package/docs/integration/mcp-server.md +84 -0
- package/docs/integration/svelte-preprocessor.md +152 -0
- package/docs/language-servers/svelte.md +80 -0
- package/docs/language-servers/zed.md +84 -0
- package/docs/roadmap/roadmap.md +131 -0
- package/docs/sections.json +29 -5
- package/package.json +4 -3
|
@@ -4,14 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
## Basic Usage
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
/** @derive(Deserialize) */
|
|
9
|
-
class User {
|
|
10
|
-
name: string;
|
|
11
|
-
age: number;
|
|
12
|
-
createdAt: Date;
|
|
13
|
-
}
|
|
7
|
+
<MacroExample before={data.examples.basic.before} after={data.examples.basic.after} />
|
|
14
8
|
|
|
9
|
+
```typescript
|
|
15
10
|
const json = '{"name":"Alice","age":30,"createdAt":"2024-01-15T10:30:00.000Z"}';
|
|
16
11
|
const user = User.fromJSON(JSON.parse(json));
|
|
17
12
|
|
|
@@ -20,41 +15,17 @@ console.log(user.age); // 30
|
|
|
20
15
|
console.log(user.createdAt instanceof Date); // true
|
|
21
16
|
```
|
|
22
17
|
|
|
23
|
-
## Generated Code
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
static fromJSON(data: unknown): User {
|
|
27
|
-
if (typeof data !== "object" || data === null || Array.isArray(data)) {
|
|
28
|
-
throw new Error("User.fromJSON: expected an object, got " + typeof data);
|
|
29
|
-
}
|
|
30
|
-
const obj = data as Record<string, unknown>;
|
|
31
|
-
|
|
32
|
-
if (!("name" in obj)) {
|
|
33
|
-
throw new Error("User.fromJSON: missing required field \\"name\\"");
|
|
34
|
-
}
|
|
35
|
-
if (!("age" in obj)) {
|
|
36
|
-
throw new Error("User.fromJSON: missing required field \\"age\\"");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const instance = new User();
|
|
40
|
-
instance.name = obj["name"] as string;
|
|
41
|
-
instance.age = obj["age"] as number;
|
|
42
|
-
instance.createdAt = new Date(obj["createdAt"] as string);
|
|
43
|
-
return instance;
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
18
|
## Runtime Validation
|
|
48
19
|
|
|
49
20
|
Deserialize validates the input data and throws descriptive errors:
|
|
50
21
|
|
|
51
|
-
|
|
52
|
-
/** @derive(Deserialize) */
|
|
22
|
+
<InteractiveMacro code={`/** @derive(Deserialize) */
|
|
53
23
|
class User {
|
|
54
24
|
name: string;
|
|
55
25
|
email: string;
|
|
56
|
-
}
|
|
26
|
+
}`} />
|
|
57
27
|
|
|
28
|
+
```typescript
|
|
58
29
|
// Missing required field
|
|
59
30
|
User.fromJSON({ name: "Alice" });
|
|
60
31
|
// Error: User.fromJSON: missing required field "email"
|
|
@@ -102,16 +73,9 @@ Use the `@serde` decorator to customize deserialization:
|
|
|
102
73
|
|
|
103
74
|
### Renaming Fields
|
|
104
75
|
|
|
105
|
-
|
|
106
|
-
/** @derive(Deserialize) */
|
|
107
|
-
class User {
|
|
108
|
-
/** @serde({ rename: "user_id" }) */
|
|
109
|
-
id: string;
|
|
110
|
-
|
|
111
|
-
/** @serde({ rename: "full_name" }) */
|
|
112
|
-
name: string;
|
|
113
|
-
}
|
|
76
|
+
<MacroExample before={data.examples.rename.before} after={data.examples.rename.after} />
|
|
114
77
|
|
|
78
|
+
```typescript
|
|
115
79
|
const user = User.fromJSON({ user_id: "123", full_name: "Alice" });
|
|
116
80
|
console.log(user.id); // "123"
|
|
117
81
|
console.log(user.name); // "Alice"
|
|
@@ -119,18 +83,9 @@ console.log(user.name); // "Alice"
|
|
|
119
83
|
|
|
120
84
|
### Default Values
|
|
121
85
|
|
|
122
|
-
|
|
123
|
-
/** @derive(Deserialize) */
|
|
124
|
-
class Config {
|
|
125
|
-
host: string;
|
|
126
|
-
|
|
127
|
-
/** @serde({ default: "3000" }) */
|
|
128
|
-
port: string;
|
|
129
|
-
|
|
130
|
-
/** @serde({ default: "false" }) */
|
|
131
|
-
debug: boolean;
|
|
132
|
-
}
|
|
86
|
+
<MacroExample before={data.examples.default.before} after={data.examples.default.after} />
|
|
133
87
|
|
|
88
|
+
```typescript
|
|
134
89
|
const config = Config.fromJSON({ host: "localhost" });
|
|
135
90
|
console.log(config.port); // "3000"
|
|
136
91
|
console.log(config.debug); // false
|
|
@@ -138,8 +93,7 @@ console.log(config.debug); // false
|
|
|
138
93
|
|
|
139
94
|
### Skipping Fields
|
|
140
95
|
|
|
141
|
-
|
|
142
|
-
/** @derive(Deserialize) */
|
|
96
|
+
<InteractiveMacro code={`/** @derive(Deserialize) */
|
|
143
97
|
class User {
|
|
144
98
|
name: string;
|
|
145
99
|
email: string;
|
|
@@ -149,8 +103,7 @@ class User {
|
|
|
149
103
|
|
|
150
104
|
/** @serde({ skip_deserializing: true }) */
|
|
151
105
|
computedField: string;
|
|
152
|
-
}
|
|
153
|
-
```
|
|
106
|
+
}`} />
|
|
154
107
|
|
|
155
108
|
<Alert type="tip" title="skip vs skip_deserializing">
|
|
156
109
|
Use `skip: true` to exclude from both serialization and deserialization.
|
|
@@ -159,14 +112,14 @@ Use `skip_deserializing: true` to only skip during deserialization.
|
|
|
159
112
|
|
|
160
113
|
### Deny Unknown Fields
|
|
161
114
|
|
|
162
|
-
|
|
163
|
-
/** @derive(Deserialize) */
|
|
115
|
+
<InteractiveMacro code={`/** @derive(Deserialize) */
|
|
164
116
|
/** @serde({ deny_unknown_fields: true }) */
|
|
165
117
|
class StrictUser {
|
|
166
118
|
name: string;
|
|
167
119
|
email: string;
|
|
168
|
-
}
|
|
120
|
+
}`} />
|
|
169
121
|
|
|
122
|
+
```typescript
|
|
170
123
|
// This will throw an error
|
|
171
124
|
StrictUser.fromJSON({ name: "Alice", email: "a@b.com", extra: "field" });
|
|
172
125
|
// Error: StrictUser.fromJSON: unknown field "extra"
|
|
@@ -174,8 +127,7 @@ StrictUser.fromJSON({ name: "Alice", email: "a@b.com", extra: "field" });
|
|
|
174
127
|
|
|
175
128
|
### Flatten Nested Objects
|
|
176
129
|
|
|
177
|
-
|
|
178
|
-
/** @derive(Deserialize) */
|
|
130
|
+
<InteractiveMacro code={`/** @derive(Deserialize) */
|
|
179
131
|
class Address {
|
|
180
132
|
city: string;
|
|
181
133
|
zip: string;
|
|
@@ -187,8 +139,9 @@ class User {
|
|
|
187
139
|
|
|
188
140
|
/** @serde({ flatten: true }) */
|
|
189
141
|
address: Address;
|
|
190
|
-
}
|
|
142
|
+
}`} />
|
|
191
143
|
|
|
144
|
+
```typescript
|
|
192
145
|
// Flat JSON structure
|
|
193
146
|
const user = User.fromJSON({
|
|
194
147
|
name: "Alice",
|
|
@@ -198,232 +151,6 @@ const user = User.fromJSON({
|
|
|
198
151
|
console.log(user.address.city); // "NYC"
|
|
199
152
|
```
|
|
200
153
|
|
|
201
|
-
## Field Validation
|
|
202
|
-
|
|
203
|
-
Use the `validate` option to add runtime validation to fields. Validation errors are collected and returned as `Result.err(string[])`.
|
|
204
|
-
|
|
205
|
-
### Basic Validation
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
/** @derive(Deserialize) */
|
|
209
|
-
class User {
|
|
210
|
-
/** @serde({ validate: ["email"] }) */
|
|
211
|
-
email: string;
|
|
212
|
-
|
|
213
|
-
/** @serde({ validate: ["minLength(2)", "maxLength(50)"] }) */
|
|
214
|
-
name: string;
|
|
215
|
-
|
|
216
|
-
/** @serde({ validate: ["positive", "int"] }) */
|
|
217
|
-
age: number;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const result = User.fromJSON({ email: "invalid", name: "A", age: -5 });
|
|
221
|
-
if (result.isErr()) {
|
|
222
|
-
console.log(result.unwrapErr());
|
|
223
|
-
// [
|
|
224
|
-
// 'User.fromJSON: field "email" must be a valid email',
|
|
225
|
-
// 'User.fromJSON: field "name" must have at least 2 characters',
|
|
226
|
-
// 'User.fromJSON: field "age" must be positive',
|
|
227
|
-
// ]
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Custom Error Messages
|
|
232
|
-
|
|
233
|
-
Use the object form to provide custom error messages:
|
|
234
|
-
|
|
235
|
-
```typescript
|
|
236
|
-
/** @derive(Deserialize) */
|
|
237
|
-
class Product {
|
|
238
|
-
/** @serde({ validate: [
|
|
239
|
-
{ validate: "nonEmpty", message: "Product name is required" },
|
|
240
|
-
{ validate: "maxLength(100)", message: "Name too long (max 100 chars)" }
|
|
241
|
-
] }) */
|
|
242
|
-
name: string;
|
|
243
|
-
|
|
244
|
-
/** @serde({ validate: [
|
|
245
|
-
{ validate: "positive", message: "Price must be greater than zero" }
|
|
246
|
-
] }) */
|
|
247
|
-
price: number;
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### Custom Validator Functions
|
|
252
|
-
|
|
253
|
-
Use `custom(functionName)` to call your own validation function:
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
function isValidSKU(value: string): boolean {
|
|
257
|
-
return /^[A-Z]{3}-\\d{4}$/.test(value);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/** @derive(Deserialize) */
|
|
261
|
-
class Product {
|
|
262
|
-
/** @serde({ validate: [
|
|
263
|
-
{ validate: "custom(isValidSKU)", message: "Invalid SKU format (expected XXX-0000)" }
|
|
264
|
-
] }) */
|
|
265
|
-
sku: string;
|
|
266
|
-
}
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Available Validators
|
|
270
|
-
|
|
271
|
-
#### String Validators
|
|
272
|
-
|
|
273
|
-
| `email`
|
|
274
|
-
| Must be a valid email address
|
|
275
|
-
|
|
276
|
-
| `url`
|
|
277
|
-
| Must be a valid URL
|
|
278
|
-
|
|
279
|
-
| `uuid`
|
|
280
|
-
| Must be a valid UUID
|
|
281
|
-
|
|
282
|
-
| `nonEmpty`
|
|
283
|
-
| Must not be empty string
|
|
284
|
-
|
|
285
|
-
| `trimmed`
|
|
286
|
-
| Must have no leading/trailing whitespace
|
|
287
|
-
|
|
288
|
-
| `lowercase`
|
|
289
|
-
| Must be all lowercase
|
|
290
|
-
|
|
291
|
-
| `uppercase`
|
|
292
|
-
| Must be all uppercase
|
|
293
|
-
|
|
294
|
-
| `capitalized`
|
|
295
|
-
| First character must be uppercase
|
|
296
|
-
|
|
297
|
-
| `uncapitalized`
|
|
298
|
-
| First character must be lowercase
|
|
299
|
-
|
|
300
|
-
| `minLength(n)`
|
|
301
|
-
| Must have at least n characters
|
|
302
|
-
|
|
303
|
-
| `maxLength(n)`
|
|
304
|
-
| Must have at most n characters
|
|
305
|
-
|
|
306
|
-
| `length(n)`
|
|
307
|
-
| Must have exactly n characters
|
|
308
|
-
|
|
309
|
-
| `length(min, max)`
|
|
310
|
-
| Must have between min and max characters
|
|
311
|
-
|
|
312
|
-
| `pattern("regex")`
|
|
313
|
-
| Must match the regular expression
|
|
314
|
-
|
|
315
|
-
| `startsWith("prefix")`
|
|
316
|
-
| Must start with the given prefix
|
|
317
|
-
|
|
318
|
-
| `endsWith("suffix")`
|
|
319
|
-
| Must end with the given suffix
|
|
320
|
-
|
|
321
|
-
| `includes("substring")`
|
|
322
|
-
| Must contain the substring
|
|
323
|
-
|
|
324
|
-
#### Number Validators
|
|
325
|
-
|
|
326
|
-
| `positive`
|
|
327
|
-
| Must be greater than 0
|
|
328
|
-
|
|
329
|
-
| `negative`
|
|
330
|
-
| Must be less than 0
|
|
331
|
-
|
|
332
|
-
| `nonNegative`
|
|
333
|
-
| Must be 0 or greater
|
|
334
|
-
|
|
335
|
-
| `nonPositive`
|
|
336
|
-
| Must be 0 or less
|
|
337
|
-
|
|
338
|
-
| `int`
|
|
339
|
-
| Must be an integer
|
|
340
|
-
|
|
341
|
-
| `finite`
|
|
342
|
-
| Must be finite (not Infinity)
|
|
343
|
-
|
|
344
|
-
| `nonNaN`
|
|
345
|
-
| Must not be NaN
|
|
346
|
-
|
|
347
|
-
| `uint8`
|
|
348
|
-
| Must be integer 0-255
|
|
349
|
-
|
|
350
|
-
| `greaterThan(n)`
|
|
351
|
-
| Must be greater than n
|
|
352
|
-
|
|
353
|
-
| `greaterThanOrEqualTo(n)`
|
|
354
|
-
| Must be greater than or equal to n
|
|
355
|
-
|
|
356
|
-
| `lessThan(n)`
|
|
357
|
-
| Must be less than n
|
|
358
|
-
|
|
359
|
-
| `lessThanOrEqualTo(n)`
|
|
360
|
-
| Must be less than or equal to n
|
|
361
|
-
|
|
362
|
-
| `between(min, max)`
|
|
363
|
-
| Must be between min and max (inclusive)
|
|
364
|
-
|
|
365
|
-
| `multipleOf(n)`
|
|
366
|
-
| Must be a multiple of n
|
|
367
|
-
|
|
368
|
-
#### Array Validators
|
|
369
|
-
|
|
370
|
-
| `minItems(n)`
|
|
371
|
-
| Must have at least n items
|
|
372
|
-
|
|
373
|
-
| `maxItems(n)`
|
|
374
|
-
| Must have at most n items
|
|
375
|
-
|
|
376
|
-
| `itemsCount(n)`
|
|
377
|
-
| Must have exactly n items
|
|
378
|
-
|
|
379
|
-
#### Date Validators
|
|
380
|
-
|
|
381
|
-
| `validDate`
|
|
382
|
-
| Must be a valid date (not Invalid Date)
|
|
383
|
-
|
|
384
|
-
| `greaterThanDate("ISO")`
|
|
385
|
-
| Must be after the given date
|
|
386
|
-
|
|
387
|
-
| `greaterThanOrEqualToDate("ISO")`
|
|
388
|
-
| Must be on or after the given date
|
|
389
|
-
|
|
390
|
-
| `lessThanDate("ISO")`
|
|
391
|
-
| Must be before the given date
|
|
392
|
-
|
|
393
|
-
| `lessThanOrEqualToDate("ISO")`
|
|
394
|
-
| Must be on or before the given date
|
|
395
|
-
|
|
396
|
-
| `betweenDate("ISO1", "ISO2")`
|
|
397
|
-
| Must be between the two dates
|
|
398
|
-
|
|
399
|
-
#### BigInt Validators
|
|
400
|
-
|
|
401
|
-
| `positiveBigInt`
|
|
402
|
-
| Must be greater than 0n
|
|
403
|
-
|
|
404
|
-
| `negativeBigInt`
|
|
405
|
-
| Must be less than 0n
|
|
406
|
-
|
|
407
|
-
| `nonNegativeBigInt`
|
|
408
|
-
| Must be 0n or greater
|
|
409
|
-
|
|
410
|
-
| `nonPositiveBigInt`
|
|
411
|
-
| Must be 0n or less
|
|
412
|
-
|
|
413
|
-
| `greaterThanBigInt(n)`
|
|
414
|
-
| Must be greater than BigInt(n)
|
|
415
|
-
|
|
416
|
-
| `lessThanBigInt(n)`
|
|
417
|
-
| Must be less than BigInt(n)
|
|
418
|
-
|
|
419
|
-
| `betweenBigInt(min, max)`
|
|
420
|
-
| Must be between BigInt(min) and BigInt(max)
|
|
421
|
-
|
|
422
|
-
#### Custom Validators
|
|
423
|
-
|
|
424
|
-
| `custom(fnName)`
|
|
425
|
-
| Calls fnName(value), fails if it returns false
|
|
426
|
-
|
|
427
154
|
## All Options
|
|
428
155
|
|
|
429
156
|
### Container Options (on class/interface)
|
|
@@ -451,55 +178,20 @@ class Product {
|
|
|
451
178
|
| Exclude from deserialization only
|
|
452
179
|
|
|
453
180
|
| `default`
|
|
454
|
-
| `boolean`
|
|
455
|
-
| Use TypeScript default if missing
|
|
456
|
-
|
|
457
|
-
| `default: "expr"`
|
|
458
|
-
| `string`
|
|
459
|
-
| Custom default expression
|
|
181
|
+
| `boolean | string`
|
|
182
|
+
| Use TypeScript default or custom expression if missing
|
|
460
183
|
|
|
461
184
|
| `flatten`
|
|
462
185
|
| `boolean`
|
|
463
|
-
| Merge nested object fields from parent
|
|
464
|
-
|
|
465
|
-
| `validate`
|
|
466
|
-
| `string[] | object[]`
|
|
467
|
-
| Array of validators to run during deserialization
|
|
186
|
+
| Merge nested object fields from parent
|
|
468
187
|
|
|
469
188
|
## Interface Support
|
|
470
189
|
|
|
471
190
|
Deserialize also works with interfaces. For interfaces, a namespace is generated with `is` (type guard) and `fromJSON` functions:
|
|
472
191
|
|
|
473
|
-
|
|
474
|
-
/** @derive(Deserialize) */
|
|
475
|
-
interface ApiResponse {
|
|
476
|
-
status: number;
|
|
477
|
-
message: string;
|
|
478
|
-
timestamp: Date;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Generated:
|
|
482
|
-
// export namespace ApiResponse {
|
|
483
|
-
// export function is(data: unknown): data is ApiResponse {
|
|
484
|
-
// if (typeof data !== "object" || data === null) return false;
|
|
485
|
-
// const obj = data as Record<string, unknown>;
|
|
486
|
-
// if (typeof obj["status"] !== "number") return false;
|
|
487
|
-
// if (typeof obj["message"] !== "string") return false;
|
|
488
|
-
// // ... additional checks
|
|
489
|
-
// return true;
|
|
490
|
-
// }
|
|
491
|
-
//
|
|
492
|
-
// export function fromJSON(data: unknown): ApiResponse {
|
|
493
|
-
// if (!is(data)) {
|
|
494
|
-
// throw new Error("ApiResponse.fromJSON: validation failed");
|
|
495
|
-
// }
|
|
496
|
-
// return {
|
|
497
|
-
// ...data,
|
|
498
|
-
// timestamp: new Date(data.timestamp)
|
|
499
|
-
// };
|
|
500
|
-
// }
|
|
501
|
-
// }
|
|
192
|
+
<MacroExample before={data.examples.interface.before} after={data.examples.interface.after} />
|
|
502
193
|
|
|
194
|
+
```typescript
|
|
503
195
|
const json = { status: 200, message: "OK", timestamp: "2024-01-15T10:30:00.000Z" };
|
|
504
196
|
|
|
505
197
|
// Type guard
|
|
@@ -516,26 +208,9 @@ console.log(response.timestamp instanceof Date); // true
|
|
|
516
208
|
|
|
517
209
|
Deserialize also works with enums. The `fromJSON` function validates that the input matches one of the enum values:
|
|
518
210
|
|
|
519
|
-
|
|
520
|
-
/** @derive(Deserialize) */
|
|
521
|
-
enum Status {
|
|
522
|
-
Active = "active",
|
|
523
|
-
Inactive = "inactive",
|
|
524
|
-
Pending = "pending",
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
// Generated:
|
|
528
|
-
// export namespace Status {
|
|
529
|
-
// export function fromJSON(data: unknown): Status {
|
|
530
|
-
// for (const key of Object.keys(Status)) {
|
|
531
|
-
// if (Status[key as keyof typeof Status] === data) {
|
|
532
|
-
// return data as Status;
|
|
533
|
-
// }
|
|
534
|
-
// }
|
|
535
|
-
// throw new Error(\`Invalid Status value: \${data}\`);
|
|
536
|
-
// }
|
|
537
|
-
// }
|
|
211
|
+
<MacroExample before={data.examples.enum.before} after={data.examples.enum.after} />
|
|
538
212
|
|
|
213
|
+
```typescript
|
|
539
214
|
const status = Status.fromJSON("active");
|
|
540
215
|
console.log(status); // Status.Active
|
|
541
216
|
|
|
@@ -549,14 +224,14 @@ try {
|
|
|
549
224
|
|
|
550
225
|
Works with numeric enums too:
|
|
551
226
|
|
|
552
|
-
|
|
553
|
-
/** @derive(Deserialize) */
|
|
227
|
+
<InteractiveMacro code={`/** @derive(Deserialize) */
|
|
554
228
|
enum Priority {
|
|
555
229
|
Low = 1,
|
|
556
230
|
Medium = 2,
|
|
557
231
|
High = 3,
|
|
558
|
-
}
|
|
232
|
+
}`} />
|
|
559
233
|
|
|
234
|
+
```typescript
|
|
560
235
|
const priority = Priority.fromJSON(3);
|
|
561
236
|
console.log(priority); // Priority.High
|
|
562
237
|
```
|
|
@@ -565,29 +240,9 @@ console.log(priority); // Priority.High
|
|
|
565
240
|
|
|
566
241
|
Deserialize works with type aliases. For object types, validation and type conversion is applied:
|
|
567
242
|
|
|
568
|
-
|
|
569
|
-
/** @derive(Deserialize) */
|
|
570
|
-
type UserProfile = {
|
|
571
|
-
id: string;
|
|
572
|
-
name: string;
|
|
573
|
-
createdAt: Date;
|
|
574
|
-
};
|
|
575
|
-
|
|
576
|
-
// Generated:
|
|
577
|
-
// export namespace UserProfile {
|
|
578
|
-
// export function fromJSON(data: unknown): UserProfile {
|
|
579
|
-
// if (typeof data !== "object" || data === null) {
|
|
580
|
-
// throw new Error("UserProfile.fromJSON: expected object");
|
|
581
|
-
// }
|
|
582
|
-
// const obj = data as Record<string, unknown>;
|
|
583
|
-
// return {
|
|
584
|
-
// id: obj["id"] as string,
|
|
585
|
-
// name: obj["name"] as string,
|
|
586
|
-
// createdAt: new Date(obj["createdAt"] as string),
|
|
587
|
-
// };
|
|
588
|
-
// }
|
|
589
|
-
// }
|
|
243
|
+
<MacroExample before={data.examples.typeAlias.before} after={data.examples.typeAlias.after} />
|
|
590
244
|
|
|
245
|
+
```typescript
|
|
591
246
|
const json = {
|
|
592
247
|
id: "123",
|
|
593
248
|
name: "Alice",
|
|
@@ -600,10 +255,10 @@ console.log(profile.createdAt instanceof Date); // true
|
|
|
600
255
|
|
|
601
256
|
For union types, basic validation is applied:
|
|
602
257
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
type ApiStatus = "loading" | "success" | "error";
|
|
258
|
+
<InteractiveMacro code={`/** @derive(Deserialize) */
|
|
259
|
+
type ApiStatus = "loading" | "success" | "error";`} />
|
|
606
260
|
|
|
261
|
+
```typescript
|
|
607
262
|
const status = ApiStatus.fromJSON("success");
|
|
608
263
|
console.log(status); // "success"
|
|
609
264
|
```
|
|
@@ -612,15 +267,15 @@ console.log(status); // "success"
|
|
|
612
267
|
|
|
613
268
|
Use both Serialize and Deserialize for complete JSON round-trip support:
|
|
614
269
|
|
|
615
|
-
|
|
616
|
-
/** @derive(Serialize, Deserialize) */
|
|
270
|
+
<InteractiveMacro code={`/** @derive(Serialize, Deserialize) */
|
|
617
271
|
/** @serde({ rename_all: "camelCase" }) */
|
|
618
272
|
class UserProfile {
|
|
619
273
|
user_name: string;
|
|
620
274
|
created_at: Date;
|
|
621
275
|
is_active: boolean;
|
|
622
|
-
}
|
|
276
|
+
}`} />
|
|
623
277
|
|
|
278
|
+
```typescript
|
|
624
279
|
// Create and serialize
|
|
625
280
|
const profile = new UserProfile();
|
|
626
281
|
profile.user_name = "Alice";
|
|
@@ -640,13 +295,13 @@ console.log(restored.created_at instanceof Date); // true
|
|
|
640
295
|
|
|
641
296
|
Handle deserialization errors gracefully:
|
|
642
297
|
|
|
643
|
-
|
|
644
|
-
/** @derive(Deserialize) */
|
|
298
|
+
<InteractiveMacro code={`/** @derive(Deserialize) */
|
|
645
299
|
class User {
|
|
646
300
|
name: string;
|
|
647
301
|
email: string;
|
|
648
|
-
}
|
|
302
|
+
}`} />
|
|
649
303
|
|
|
304
|
+
```typescript
|
|
650
305
|
function parseUser(json: unknown): User | null {
|
|
651
306
|
try {
|
|
652
307
|
return User.fromJSON(json);
|