@macroforge/mcp-server 0.1.37 → 0.1.39

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 (43) hide show
  1. package/docs/api/api-overview.md +13 -13
  2. package/docs/api/expand-sync.md +8 -8
  3. package/docs/api/native-plugin.md +15 -15
  4. package/docs/api/position-mapper.md +6 -6
  5. package/docs/api/transform-sync.md +11 -11
  6. package/docs/builtin-macros/clone.md +43 -23
  7. package/docs/builtin-macros/debug.md +50 -18
  8. package/docs/builtin-macros/default.md +79 -28
  9. package/docs/builtin-macros/deserialize/cycleforward-reference-support.md +11 -0
  10. package/docs/builtin-macros/deserialize/example.md +1625 -0
  11. package/docs/builtin-macros/deserialize/overview.md +15 -10
  12. package/docs/builtin-macros/deserialize/union-type-deserialization.md +27 -0
  13. package/docs/builtin-macros/deserialize/validation.md +34 -0
  14. package/docs/builtin-macros/deserialize.md +1608 -23
  15. package/docs/builtin-macros/hash.md +87 -20
  16. package/docs/builtin-macros/macros-overview.md +40 -40
  17. package/docs/builtin-macros/ord.md +56 -31
  18. package/docs/builtin-macros/partial-eq/example.md +526 -0
  19. package/docs/builtin-macros/partial-eq/overview.md +39 -0
  20. package/docs/builtin-macros/partial-eq.md +184 -26
  21. package/docs/builtin-macros/partial-ord.md +68 -30
  22. package/docs/builtin-macros/serialize/example.md +139 -0
  23. package/docs/builtin-macros/serialize/overview.md +32 -0
  24. package/docs/builtin-macros/serialize/type-specific-serialization.md +22 -0
  25. package/docs/builtin-macros/serialize.md +130 -28
  26. package/docs/concepts/architecture.md +2 -2
  27. package/docs/concepts/derive-system.md +25 -39
  28. package/docs/concepts/how-macros-work.md +8 -4
  29. package/docs/custom-macros/custom-overview.md +23 -23
  30. package/docs/custom-macros/rust-setup.md +31 -31
  31. package/docs/custom-macros/ts-macro-derive.md +107 -107
  32. package/docs/custom-macros/ts-quote.md +226 -226
  33. package/docs/getting-started/first-macro.md +38 -28
  34. package/docs/getting-started/installation.md +15 -15
  35. package/docs/integration/cli.md +9 -9
  36. package/docs/integration/configuration.md +16 -16
  37. package/docs/integration/mcp-server.md +6 -6
  38. package/docs/integration/svelte-preprocessor.md +40 -41
  39. package/docs/integration/typescript-plugin.md +13 -12
  40. package/docs/integration/vite-plugin.md +12 -12
  41. package/docs/language-servers/zed.md +1 -1
  42. package/docs/sections.json +88 -2
  43. package/package.json +2 -2
@@ -0,0 +1,526 @@
1
+ ## Example
2
+
3
+ ```typescript before
4
+ /** @derive(PartialEq, Hash) */
5
+ class User {
6
+ id: number;
7
+ name: string;
8
+
9
+ @partialEq(skip) // Don't compare cached values
10
+ /** @hash({ skip: true }) */
11
+ cachedScore: number;
12
+ }
13
+ ```
14
+
15
+ ```typescript after
16
+ class User {
17
+ id: number;
18
+ name: string;
19
+
20
+ // Don't compare cached values
21
+ /** @hash({ skip: true }) */
22
+ cachedScore: number;
23
+
24
+ equals(other: unknown): boolean {
25
+ if (this === other) return true;
26
+ if (!(other instanceof User)) return false;
27
+ const typedOther = other as User;
28
+ return this.id === typedOther.id && this.name === typedOther.name;
29
+ }
30
+
31
+ hashCode(): number {
32
+ let hash = 17;
33
+ hash =
34
+ (hash * 31 +
35
+ (Number.isInteger(this.id)
36
+ ? this.id | 0
37
+ : this.id
38
+ .toString()
39
+ .split('')
40
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
41
+ 0;
42
+ hash =
43
+ (hash * 31 +
44
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
45
+ 0;
46
+ hash =
47
+ (hash * 31 +
48
+ (Number.isInteger(this.cachedScore)
49
+ ? this.cachedScore | 0
50
+ : this.cachedScore
51
+ .toString()
52
+ .split('')
53
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
54
+ 0;
55
+ return hash;
56
+ }
57
+ }
58
+ ```
59
+
60
+ Generated output:
61
+
62
+ ```typescript before
63
+ class User {
64
+ id: number;
65
+ name: string;
66
+
67
+ // Don't compare cached values
68
+ /** @hash({ skip: true }) */
69
+ cachedScore: number;
70
+
71
+ equals(other: unknown): boolean {
72
+ if (this === other) return true;
73
+ if (!(other instanceof User)) return false;
74
+ const typedOther = other as User;
75
+ return this.id === typedOther.id && this.name === typedOther.name;
76
+ }
77
+
78
+ hashCode(): number {
79
+ let hash = 17;
80
+ hash =
81
+ (hash * 31 +
82
+ (Number.isInteger(this.id)
83
+ ? this.id | 0
84
+ : this.id
85
+ .toString()
86
+ .split('')
87
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
88
+ 0;
89
+ hash =
90
+ (hash * 31 +
91
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
92
+ 0;
93
+ hash =
94
+ (hash * 31 +
95
+ (Number.isInteger(this.cachedScore)
96
+ ? this.cachedScore | 0
97
+ : this.cachedScore
98
+ .toString()
99
+ .split('')
100
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
101
+ 0;
102
+ return hash;
103
+ }
104
+ }
105
+ ```
106
+
107
+ ```typescript after
108
+ class User {
109
+ id: number;
110
+ name: string;
111
+
112
+ // Don't compare cached values
113
+ /** @hash({ skip: true }) */
114
+ cachedScore: number;
115
+
116
+ equals(other: unknown): boolean {
117
+ if (this === other) return true;
118
+ if (!(other instanceof User)) return false;
119
+ const typedOther = other as User;
120
+ return this.id === typedOther.id && this.name === typedOther.name;
121
+ }
122
+
123
+ hashCode(): number {
124
+ let hash = 17;
125
+ hash =
126
+ (hash * 31 +
127
+ (Number.isInteger(this.id)
128
+ ? this.id | 0
129
+ : this.id
130
+ .toString()
131
+ .split('')
132
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
133
+ 0;
134
+ hash =
135
+ (hash * 31 +
136
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
137
+ 0;
138
+ hash =
139
+ (hash * 31 +
140
+ (Number.isInteger(this.cachedScore)
141
+ ? this.cachedScore | 0
142
+ : this.cachedScore
143
+ .toString()
144
+ .split('')
145
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
146
+ 0;
147
+ return hash;
148
+ }
149
+ }
150
+ ```
151
+
152
+ Generated output:
153
+
154
+ ```typescript before
155
+ class User {
156
+ id: number;
157
+ name: string;
158
+
159
+ // Don't compare cached values
160
+ /** @hash({ skip: true }) */
161
+ cachedScore: number;
162
+
163
+ equals(other: unknown): boolean {
164
+ if (this === other) return true;
165
+ if (!(other instanceof User)) return false;
166
+ const typedOther = other as User;
167
+ return this.id === typedOther.id && this.name === typedOther.name;
168
+ }
169
+
170
+ hashCode(): number {
171
+ let hash = 17;
172
+ hash =
173
+ (hash * 31 +
174
+ (Number.isInteger(this.id)
175
+ ? this.id | 0
176
+ : this.id
177
+ .toString()
178
+ .split('')
179
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
180
+ 0;
181
+ hash =
182
+ (hash * 31 +
183
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
184
+ 0;
185
+ hash =
186
+ (hash * 31 +
187
+ (Number.isInteger(this.cachedScore)
188
+ ? this.cachedScore | 0
189
+ : this.cachedScore
190
+ .toString()
191
+ .split('')
192
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
193
+ 0;
194
+ return hash;
195
+ }
196
+ }
197
+ ```
198
+
199
+ ```typescript after
200
+ class User {
201
+ id: number;
202
+ name: string;
203
+
204
+ // Don't compare cached values
205
+ /** @hash({ skip: true }) */
206
+ cachedScore: number;
207
+
208
+ equals(other: unknown): boolean {
209
+ if (this === other) return true;
210
+ if (!(other instanceof User)) return false;
211
+ const typedOther = other as User;
212
+ return this.id === typedOther.id && this.name === typedOther.name;
213
+ }
214
+
215
+ hashCode(): number {
216
+ let hash = 17;
217
+ hash =
218
+ (hash * 31 +
219
+ (Number.isInteger(this.id)
220
+ ? this.id | 0
221
+ : this.id
222
+ .toString()
223
+ .split('')
224
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
225
+ 0;
226
+ hash =
227
+ (hash * 31 +
228
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
229
+ 0;
230
+ hash =
231
+ (hash * 31 +
232
+ (Number.isInteger(this.cachedScore)
233
+ ? this.cachedScore | 0
234
+ : this.cachedScore
235
+ .toString()
236
+ .split('')
237
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
238
+ 0;
239
+ return hash;
240
+ }
241
+ }
242
+ ```
243
+
244
+ Generated output:
245
+
246
+ ```typescript before
247
+ class User {
248
+ id: number;
249
+ name: string;
250
+
251
+ // Don't compare cached values
252
+ /** @hash({ skip: true }) */
253
+ cachedScore: number;
254
+
255
+ equals(other: unknown): boolean {
256
+ if (this === other) return true;
257
+ if (!(other instanceof User)) return false;
258
+ const typedOther = other as User;
259
+ return this.id === typedOther.id && this.name === typedOther.name;
260
+ }
261
+
262
+ hashCode(): number {
263
+ let hash = 17;
264
+ hash =
265
+ (hash * 31 +
266
+ (Number.isInteger(this.id)
267
+ ? this.id | 0
268
+ : this.id
269
+ .toString()
270
+ .split('')
271
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
272
+ 0;
273
+ hash =
274
+ (hash * 31 +
275
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
276
+ 0;
277
+ hash =
278
+ (hash * 31 +
279
+ (Number.isInteger(this.cachedScore)
280
+ ? this.cachedScore | 0
281
+ : this.cachedScore
282
+ .toString()
283
+ .split('')
284
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
285
+ 0;
286
+ return hash;
287
+ }
288
+ }
289
+ ```
290
+
291
+ ```typescript after
292
+ class User {
293
+ id: number;
294
+ name: string;
295
+
296
+ // Don't compare cached values
297
+ /** @hash({ skip: true }) */
298
+ cachedScore: number;
299
+
300
+ equals(other: unknown): boolean {
301
+ if (this === other) return true;
302
+ if (!(other instanceof User)) return false;
303
+ const typedOther = other as User;
304
+ return this.id === typedOther.id && this.name === typedOther.name;
305
+ }
306
+
307
+ hashCode(): number {
308
+ let hash = 17;
309
+ hash =
310
+ (hash * 31 +
311
+ (Number.isInteger(this.id)
312
+ ? this.id | 0
313
+ : this.id
314
+ .toString()
315
+ .split('')
316
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
317
+ 0;
318
+ hash =
319
+ (hash * 31 +
320
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
321
+ 0;
322
+ hash =
323
+ (hash * 31 +
324
+ (Number.isInteger(this.cachedScore)
325
+ ? this.cachedScore | 0
326
+ : this.cachedScore
327
+ .toString()
328
+ .split('')
329
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
330
+ 0;
331
+ return hash;
332
+ }
333
+ }
334
+ ```
335
+
336
+ Generated output:
337
+
338
+ ```typescript before
339
+ class User {
340
+ id: number;
341
+ name: string;
342
+
343
+ // Don't compare cached values
344
+ /** @hash({ skip: true }) */
345
+ cachedScore: number;
346
+
347
+ equals(other: unknown): boolean {
348
+ if (this === other) return true;
349
+ if (!(other instanceof User)) return false;
350
+ const typedOther = other as User;
351
+ return this.id === typedOther.id && this.name === typedOther.name;
352
+ }
353
+
354
+ hashCode(): number {
355
+ let hash = 17;
356
+ hash =
357
+ (hash * 31 +
358
+ (Number.isInteger(this.id)
359
+ ? this.id | 0
360
+ : this.id
361
+ .toString()
362
+ .split('')
363
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
364
+ 0;
365
+ hash =
366
+ (hash * 31 +
367
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
368
+ 0;
369
+ hash =
370
+ (hash * 31 +
371
+ (Number.isInteger(this.cachedScore)
372
+ ? this.cachedScore | 0
373
+ : this.cachedScore
374
+ .toString()
375
+ .split('')
376
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
377
+ 0;
378
+ return hash;
379
+ }
380
+ }
381
+ ```
382
+
383
+ ```typescript after
384
+ class User {
385
+ id: number;
386
+ name: string;
387
+
388
+ // Don't compare cached values
389
+ /** @hash({ skip: true }) */
390
+ cachedScore: number;
391
+
392
+ equals(other: unknown): boolean {
393
+ if (this === other) return true;
394
+ if (!(other instanceof User)) return false;
395
+ const typedOther = other as User;
396
+ return this.id === typedOther.id && this.name === typedOther.name;
397
+ }
398
+
399
+ hashCode(): number {
400
+ let hash = 17;
401
+ hash =
402
+ (hash * 31 +
403
+ (Number.isInteger(this.id)
404
+ ? this.id | 0
405
+ : this.id
406
+ .toString()
407
+ .split('')
408
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
409
+ 0;
410
+ hash =
411
+ (hash * 31 +
412
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
413
+ 0;
414
+ hash =
415
+ (hash * 31 +
416
+ (Number.isInteger(this.cachedScore)
417
+ ? this.cachedScore | 0
418
+ : this.cachedScore
419
+ .toString()
420
+ .split('')
421
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
422
+ 0;
423
+ return hash;
424
+ }
425
+ }
426
+ ```
427
+
428
+ Generated output:
429
+
430
+ ```typescript before
431
+ class User {
432
+ id: number;
433
+ name: string;
434
+
435
+ // Don't compare cached values
436
+ /** @hash({ skip: true }) */
437
+ cachedScore: number;
438
+
439
+ equals(other: unknown): boolean {
440
+ if (this === other) return true;
441
+ if (!(other instanceof User)) return false;
442
+ const typedOther = other as User;
443
+ return this.id === typedOther.id && this.name === typedOther.name;
444
+ }
445
+
446
+ hashCode(): number {
447
+ let hash = 17;
448
+ hash =
449
+ (hash * 31 +
450
+ (Number.isInteger(this.id)
451
+ ? this.id | 0
452
+ : this.id
453
+ .toString()
454
+ .split('')
455
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
456
+ 0;
457
+ hash =
458
+ (hash * 31 +
459
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
460
+ 0;
461
+ hash =
462
+ (hash * 31 +
463
+ (Number.isInteger(this.cachedScore)
464
+ ? this.cachedScore | 0
465
+ : this.cachedScore
466
+ .toString()
467
+ .split('')
468
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
469
+ 0;
470
+ return hash;
471
+ }
472
+ }
473
+ ```
474
+
475
+ ```typescript after
476
+ class User {
477
+ id: number;
478
+ name: string;
479
+
480
+ // Don't compare cached values
481
+ /** @hash({ skip: true }) */
482
+ cachedScore: number;
483
+
484
+ equals(other: unknown): boolean {
485
+ if (this === other) return true;
486
+ if (!(other instanceof User)) return false;
487
+ const typedOther = other as User;
488
+ return this.id === typedOther.id && this.name === typedOther.name;
489
+ }
490
+
491
+ hashCode(): number {
492
+ let hash = 17;
493
+ hash =
494
+ (hash * 31 +
495
+ (Number.isInteger(this.id)
496
+ ? this.id | 0
497
+ : this.id
498
+ .toString()
499
+ .split('')
500
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
501
+ 0;
502
+ hash =
503
+ (hash * 31 +
504
+ (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
505
+ 0;
506
+ hash =
507
+ (hash * 31 +
508
+ (Number.isInteger(this.cachedScore)
509
+ ? this.cachedScore | 0
510
+ : this.cachedScore
511
+ .toString()
512
+ .split('')
513
+ .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
514
+ 0;
515
+ return hash;
516
+ }
517
+ }
518
+ ```
519
+
520
+ ## Equality Contract
521
+
522
+ When implementing `PartialEq`, consider also implementing `Hash`:
523
+
524
+ - **Reflexivity**: `a.equals(a)` is always true
525
+ - **Symmetry**: `a.equals(b)` implies `b.equals(a)`
526
+ - **Hash consistency**: Equal objects must have equal hash codes
@@ -0,0 +1,39 @@
1
+ # PartialEq
2
+
3
+ The `PartialEq` macro generates an `equals()` method for field-by-field
4
+ structural equality comparison. This is analogous to Rust's `PartialEq` trait,
5
+ enabling value-based equality semantics instead of reference equality.
6
+
7
+ ## Generated Output
8
+
9
+ | Type | Generated Code | Description |
10
+ |------|----------------|-------------|
11
+ | Class | `equals(other: unknown): boolean` | Instance method with instanceof check |
12
+ | Enum | `equalsEnumName(a: EnumName, b: EnumName): boolean` | Standalone function using strict equality |
13
+ | Interface | `equalsInterfaceName(a: InterfaceName, b: InterfaceName): boolean` | Standalone function comparing fields |
14
+ | Type Alias | `equalsTypeName(a: TypeName, b: TypeName): boolean` | Standalone function with type-appropriate comparison |
15
+
16
+ ## Comparison Strategy
17
+
18
+ The generated equality check:
19
+
20
+ 1. **Identity check**: `this === other` returns true immediately
21
+ 2. **Type check**: For classes, uses `instanceof`; returns false if wrong type
22
+ 3. **Field comparison**: Compares each non-skipped field
23
+
24
+ ## Type-Specific Comparisons
25
+
26
+ | Type | Comparison Method |
27
+ |------|-------------------|
28
+ | Primitives | Strict equality (`===`) |
29
+ | Arrays | Length + element-by-element (recursive) |
30
+ | `Date` | `getTime()` comparison |
31
+ | `Map` | Size + entry-by-entry comparison |
32
+ | `Set` | Size + membership check |
33
+ | Objects | Calls `equals()` if available, else `===` |
34
+
35
+ ## Field-Level Options
36
+
37
+ The `@partialEq` decorator supports:
38
+
39
+ - `skip` - Exclude the field from equality comparison