@macroforge/mcp-server 0.1.17

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 (46) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +47 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/tools/docs-loader.d.ts +30 -0
  6. package/dist/tools/docs-loader.d.ts.map +1 -0
  7. package/dist/tools/docs-loader.js +112 -0
  8. package/dist/tools/docs-loader.js.map +1 -0
  9. package/dist/tools/index.d.ts +6 -0
  10. package/dist/tools/index.d.ts.map +1 -0
  11. package/dist/tools/index.js +348 -0
  12. package/dist/tools/index.js.map +1 -0
  13. package/docs/api/api-overview.md +75 -0
  14. package/docs/api/expand-sync.md +121 -0
  15. package/docs/api/native-plugin.md +106 -0
  16. package/docs/api/position-mapper.md +127 -0
  17. package/docs/api/transform-sync.md +98 -0
  18. package/docs/builtin-macros/clone.md +180 -0
  19. package/docs/builtin-macros/debug.md +222 -0
  20. package/docs/builtin-macros/default.md +192 -0
  21. package/docs/builtin-macros/deserialize.md +662 -0
  22. package/docs/builtin-macros/hash.md +205 -0
  23. package/docs/builtin-macros/macros-overview.md +169 -0
  24. package/docs/builtin-macros/ord.md +258 -0
  25. package/docs/builtin-macros/partial-eq.md +306 -0
  26. package/docs/builtin-macros/partial-ord.md +268 -0
  27. package/docs/builtin-macros/serialize.md +321 -0
  28. package/docs/concepts/architecture.md +139 -0
  29. package/docs/concepts/derive-system.md +173 -0
  30. package/docs/concepts/how-macros-work.md +124 -0
  31. package/docs/custom-macros/custom-overview.md +84 -0
  32. package/docs/custom-macros/rust-setup.md +146 -0
  33. package/docs/custom-macros/ts-macro-derive.md +307 -0
  34. package/docs/custom-macros/ts-quote.md +696 -0
  35. package/docs/getting-started/first-macro.md +120 -0
  36. package/docs/getting-started/installation.md +110 -0
  37. package/docs/integration/cli.md +207 -0
  38. package/docs/integration/configuration.md +116 -0
  39. package/docs/integration/integration-overview.md +51 -0
  40. package/docs/integration/typescript-plugin.md +96 -0
  41. package/docs/integration/vite-plugin.md +126 -0
  42. package/docs/language-servers/ls-overview.md +47 -0
  43. package/docs/language-servers/svelte-ls.md +80 -0
  44. package/docs/language-servers/zed-extensions.md +84 -0
  45. package/docs/sections.json +258 -0
  46. package/package.json +48 -0
@@ -0,0 +1,662 @@
1
+ # Deserialize
2
+
3
+ *The `Deserialize` macro generates a static `fromJSON()` method that parses JSON data into your class with runtime validation and automatic type conversion.*
4
+
5
+ ## Basic Usage
6
+
7
+ ```typescript
8
+ /** @derive(Deserialize) */
9
+ class User {
10
+ name: string;
11
+ age: number;
12
+ createdAt: Date;
13
+ }
14
+
15
+ const json = '{"name":"Alice","age":30,"createdAt":"2024-01-15T10:30:00.000Z"}';
16
+ const user = User.fromJSON(JSON.parse(json));
17
+
18
+ console.log(user.name); // "Alice"
19
+ console.log(user.age); // 30
20
+ console.log(user.createdAt instanceof Date); // true
21
+ ```
22
+
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
+ ## Runtime Validation
48
+
49
+ Deserialize validates the input data and throws descriptive errors:
50
+
51
+ ```typescript
52
+ /** @derive(Deserialize) */
53
+ class User {
54
+ name: string;
55
+ email: string;
56
+ }
57
+
58
+ // Missing required field
59
+ User.fromJSON({ name: "Alice" });
60
+ // Error: User.fromJSON: missing required field "email"
61
+
62
+ // Wrong type
63
+ User.fromJSON("not an object");
64
+ // Error: User.fromJSON: expected an object, got string
65
+
66
+ // Array instead of object
67
+ User.fromJSON([1, 2, 3]);
68
+ // Error: User.fromJSON: expected an object, got array
69
+ ```
70
+
71
+ ## Automatic Type Conversion
72
+
73
+ Deserialize automatically converts JSON types to their TypeScript equivalents:
74
+
75
+ | string/number/boolean
76
+ | `string`/`number`/`boolean`
77
+ | Direct assignment
78
+
79
+ | ISO string
80
+ | `Date`
81
+ | `new Date(string)`
82
+
83
+ | array
84
+ | `T[]`
85
+ | Maps items with auto-detection
86
+
87
+ | object
88
+ | `Map<K, V>`
89
+ | `new Map(Object.entries())`
90
+
91
+ | array
92
+ | `Set<T>`
93
+ | `new Set(array)`
94
+
95
+ | object
96
+ | Nested class
97
+ | Calls `fromJSON()` if available
98
+
99
+ ## Serde Options
100
+
101
+ Use the `@serde` decorator to customize deserialization:
102
+
103
+ ### Renaming Fields
104
+
105
+ ```typescript
106
+ /** @derive(Deserialize) */
107
+ class User {
108
+ /** @serde({ rename: "user_id" }) */
109
+ id: string;
110
+
111
+ /** @serde({ rename: "full_name" }) */
112
+ name: string;
113
+ }
114
+
115
+ const user = User.fromJSON({ user_id: "123", full_name: "Alice" });
116
+ console.log(user.id); // "123"
117
+ console.log(user.name); // "Alice"
118
+ ```
119
+
120
+ ### Default Values
121
+
122
+ ```typescript
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
+ }
133
+
134
+ const config = Config.fromJSON({ host: "localhost" });
135
+ console.log(config.port); // "3000"
136
+ console.log(config.debug); // false
137
+ ```
138
+
139
+ ### Skipping Fields
140
+
141
+ ```typescript
142
+ /** @derive(Deserialize) */
143
+ class User {
144
+ name: string;
145
+ email: string;
146
+
147
+ /** @serde({ skip: true }) */
148
+ cachedData: unknown;
149
+
150
+ /** @serde({ skip_deserializing: true }) */
151
+ computedField: string;
152
+ }
153
+ ```
154
+
155
+ <Alert type="tip" title="skip vs skip_deserializing">
156
+ Use `skip: true` to exclude from both serialization and deserialization.
157
+ Use `skip_deserializing: true` to only skip during deserialization.
158
+ </Alert>
159
+
160
+ ### Deny Unknown Fields
161
+
162
+ ```typescript
163
+ /** @derive(Deserialize) */
164
+ /** @serde({ deny_unknown_fields: true }) */
165
+ class StrictUser {
166
+ name: string;
167
+ email: string;
168
+ }
169
+
170
+ // This will throw an error
171
+ StrictUser.fromJSON({ name: "Alice", email: "a@b.com", extra: "field" });
172
+ // Error: StrictUser.fromJSON: unknown field "extra"
173
+ ```
174
+
175
+ ### Flatten Nested Objects
176
+
177
+ ```typescript
178
+ /** @derive(Deserialize) */
179
+ class Address {
180
+ city: string;
181
+ zip: string;
182
+ }
183
+
184
+ /** @derive(Deserialize) */
185
+ class User {
186
+ name: string;
187
+
188
+ /** @serde({ flatten: true }) */
189
+ address: Address;
190
+ }
191
+
192
+ // Flat JSON structure
193
+ const user = User.fromJSON({
194
+ name: "Alice",
195
+ city: "NYC",
196
+ zip: "10001"
197
+ });
198
+ console.log(user.address.city); // "NYC"
199
+ ```
200
+
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
+ ## All Options
428
+
429
+ ### Container Options (on class/interface)
430
+
431
+ | `rename_all`
432
+ | `string`
433
+ | Apply naming convention to all fields
434
+
435
+ | `deny_unknown_fields`
436
+ | `boolean`
437
+ | Throw error if JSON has unknown keys
438
+
439
+ ### Field Options (on properties)
440
+
441
+ | `rename`
442
+ | `string`
443
+ | Use a different JSON key
444
+
445
+ | `skip`
446
+ | `boolean`
447
+ | Exclude from serialization and deserialization
448
+
449
+ | `skip_deserializing`
450
+ | `boolean`
451
+ | Exclude from deserialization only
452
+
453
+ | `default`
454
+ | `boolean`
455
+ | Use TypeScript default if missing
456
+
457
+ | `default: "expr"`
458
+ | `string`
459
+ | Custom default expression
460
+
461
+ | `flatten`
462
+ | `boolean`
463
+ | Merge nested object fields from parent
464
+
465
+ | `validate`
466
+ | `string[] | object[]`
467
+ | Array of validators to run during deserialization
468
+
469
+ ## Interface Support
470
+
471
+ Deserialize also works with interfaces. For interfaces, a namespace is generated with `is` (type guard) and `fromJSON` functions:
472
+
473
+ ```typescript
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
+ // }
502
+
503
+ const json = { status: 200, message: "OK", timestamp: "2024-01-15T10:30:00.000Z" };
504
+
505
+ // Type guard
506
+ if (ApiResponse.is(json)) {
507
+ console.log(json.status); // TypeScript knows this is ApiResponse
508
+ }
509
+
510
+ // Deserialize with validation
511
+ const response = ApiResponse.fromJSON(json);
512
+ console.log(response.timestamp instanceof Date); // true
513
+ ```
514
+
515
+ ## Enum Support
516
+
517
+ Deserialize also works with enums. The `fromJSON` function validates that the input matches one of the enum values:
518
+
519
+ ```typescript
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
+ // }
538
+
539
+ const status = Status.fromJSON("active");
540
+ console.log(status); // Status.Active
541
+
542
+ // Invalid values throw an error
543
+ try {
544
+ Status.fromJSON("invalid");
545
+ } catch (e) {
546
+ console.log(e.message); // "Invalid Status value: invalid"
547
+ }
548
+ ```
549
+
550
+ Works with numeric enums too:
551
+
552
+ ```typescript
553
+ /** @derive(Deserialize) */
554
+ enum Priority {
555
+ Low = 1,
556
+ Medium = 2,
557
+ High = 3,
558
+ }
559
+
560
+ const priority = Priority.fromJSON(3);
561
+ console.log(priority); // Priority.High
562
+ ```
563
+
564
+ ## Type Alias Support
565
+
566
+ Deserialize works with type aliases. For object types, validation and type conversion is applied:
567
+
568
+ ```typescript
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
+ // }
590
+
591
+ const json = {
592
+ id: "123",
593
+ name: "Alice",
594
+ createdAt: "2024-01-15T00:00:00.000Z"
595
+ };
596
+
597
+ const profile = UserProfile.fromJSON(json);
598
+ console.log(profile.createdAt instanceof Date); // true
599
+ ```
600
+
601
+ For union types, basic validation is applied:
602
+
603
+ ```typescript
604
+ /** @derive(Deserialize) */
605
+ type ApiStatus = "loading" | "success" | "error";
606
+
607
+ const status = ApiStatus.fromJSON("success");
608
+ console.log(status); // "success"
609
+ ```
610
+
611
+ ## Combining with Serialize
612
+
613
+ Use both Serialize and Deserialize for complete JSON round-trip support:
614
+
615
+ ```typescript
616
+ /** @derive(Serialize, Deserialize) */
617
+ /** @serde({ rename_all: "camelCase" }) */
618
+ class UserProfile {
619
+ user_name: string;
620
+ created_at: Date;
621
+ is_active: boolean;
622
+ }
623
+
624
+ // Create and serialize
625
+ const profile = new UserProfile();
626
+ profile.user_name = "Alice";
627
+ profile.created_at = new Date();
628
+ profile.is_active = true;
629
+
630
+ const json = JSON.stringify(profile);
631
+ // {"userName":"Alice","createdAt":"2024-...","isActive":true}
632
+
633
+ // Deserialize back
634
+ const restored = UserProfile.fromJSON(JSON.parse(json));
635
+ console.log(restored.user_name); // "Alice"
636
+ console.log(restored.created_at instanceof Date); // true
637
+ ```
638
+
639
+ ## Error Handling
640
+
641
+ Handle deserialization errors gracefully:
642
+
643
+ ```typescript
644
+ /** @derive(Deserialize) */
645
+ class User {
646
+ name: string;
647
+ email: string;
648
+ }
649
+
650
+ function parseUser(json: unknown): User | null {
651
+ try {
652
+ return User.fromJSON(json);
653
+ } catch (error) {
654
+ console.error("Failed to parse user:", error.message);
655
+ return null;
656
+ }
657
+ }
658
+
659
+ const user = parseUser({ name: "Alice" });
660
+ // Logs: Failed to parse user: User.fromJSON: missing required field "email"
661
+ // Returns: null
662
+ ```