@macroforge/mcp-server 0.1.17 → 0.1.21

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.
@@ -4,14 +4,9 @@
4
4
 
5
5
  ## Basic Usage
6
6
 
7
- ```typescript
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
- ```typescript
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
- ```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
- }
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
- ```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
- }
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
- ```typescript
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
- ```typescript
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
- ```typescript
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
- ```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
- // }
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
- ```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
- // }
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
- ```typescript
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
- ```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
- // }
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
- ```typescript
604
- /** @derive(Deserialize) */
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
- ```typescript
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
- ```typescript
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);