@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,696 @@
1
+ # Template Syntax (ts_quote)
2
+
3
+ *The `ts_quote` crate provides template-based code generation for TypeScript. The `ts_template!` macro uses Rust-inspired syntax for control flow and interpolation, making it easy to generate complex TypeScript code.*
4
+
5
+ ## Available Macros
6
+
7
+ | `ts_template!`
8
+ | Any TypeScript code
9
+ | General code generation
10
+
11
+ | `body!`
12
+ | Class body members
13
+ | Methods and properties
14
+
15
+ ## Quick Reference
16
+
17
+ | `@{expr}`
18
+ | Interpolate a Rust expression (adds space after)
19
+
20
+ | `{| content |}`
21
+ | Ident block: concatenates without spaces (e.g., `{|get@{name}|}` → `getUser`)
22
+
23
+ | `@@{`
24
+ | Escape for literal `@{` (e.g., `"@@{foo}"` → `@{foo}`)
25
+
26
+ | `"text @{expr}"`
27
+ | String interpolation (auto-detected)
28
+
29
+ | `"'^template ${js}^'"`
30
+ | JS backtick template literal (outputs ``template ${js}``)
31
+
32
+ | `{#if cond}...{/if}`
33
+ | Conditional block
34
+
35
+ | `{#if cond}...{:else}...{/if}`
36
+ | Conditional with else
37
+
38
+ | `{#if a}...{:else if b}...{:else}...{/if}`
39
+ | Full if/else-if/else chain
40
+
41
+ | `{#if let pattern = expr}...{/if}`
42
+ | Pattern matching if-let
43
+
44
+ | `{#match expr}{:case pattern}...{/match}`
45
+ | Match expression with case arms
46
+
47
+ | `{#for item in list}...{/for}`
48
+ | Iterate over a collection
49
+
50
+ | `{#while cond}...{/while}`
51
+ | While loop
52
+
53
+ | `{#while let pattern = expr}...{/while}`
54
+ | While-let pattern matching loop
55
+
56
+ | `{$let name = expr}`
57
+ | Define a local constant
58
+
59
+ | `{$let mut name = expr}`
60
+ | Define a mutable local variable
61
+
62
+ | `{$do expr}`
63
+ | Execute a side-effectful expression
64
+
65
+ | `{$typescript stream}`
66
+ | Inject a TsStream, preserving its source and runtime_patches (imports)
67
+
68
+ **Note:** A single `@` not followed by `{` passes through unchanged (e.g., `email@domain.com` works as expected).
69
+
70
+ ## Interpolation: `@{expr}`
71
+
72
+ Insert Rust expressions into the generated TypeScript:
73
+
74
+ ```rust
75
+ let class_name = "User";
76
+ let method = "toString";
77
+
78
+ let code = ts_template! {
79
+ @{class_name}.prototype.@{method} = function() {
80
+ return "User instance";
81
+ };
82
+ };
83
+ ```
84
+
85
+ **Generates:**
86
+
87
+ ```typescript
88
+ User.prototype.toString = function () {
89
+ return "User instance";
90
+ };
91
+ ```
92
+
93
+ ## Identifier Concatenation: `{| content |}`
94
+
95
+ When you need to build identifiers dynamically (like `getUser`, `setName`), use the ident block syntax. Everything inside `{| |}` is concatenated without spaces:
96
+
97
+ ```rust
98
+ let field_name = "User";
99
+
100
+ let code = ts_template! {
101
+ function {|get@{field_name}|}() {
102
+ return this.@{field_name.to_lowercase()};
103
+ }
104
+ };
105
+ ```
106
+
107
+ **Generates:**
108
+
109
+ ```typescript
110
+ function getUser() {
111
+ return this.user;
112
+ }
113
+ ```
114
+
115
+ Without ident blocks, `@{}` always adds a space after for readability. Use `{| |}` when you explicitly want concatenation:
116
+
117
+ ```rust
118
+ let name = "Status";
119
+
120
+ // With space (default behavior)
121
+ ts_template! { namespace @{name} } // → "namespace Status"
122
+
123
+ // Without space (ident block)
124
+ ts_template! { {|namespace@{name}|} } // → "namespaceStatus"
125
+ ```
126
+
127
+ Multiple interpolations can be combined:
128
+
129
+ ```rust
130
+ let entity = "user";
131
+ let action = "create";
132
+
133
+ ts_template! { {|@{entity}_@{action}|} } // → "user_create"
134
+ ```
135
+
136
+ ## String Interpolation: `"text @{expr}"`
137
+
138
+ Interpolation works automatically inside string literals - no `format!()` needed:
139
+
140
+ ```rust
141
+ let name = "World";
142
+ let count = 42;
143
+
144
+ let code = ts_template! {
145
+ console.log("Hello @{name}!");
146
+ console.log("Count: @{count}, doubled: @{count * 2}");
147
+ };
148
+ ```
149
+
150
+ **Generates:**
151
+
152
+ ```typescript
153
+ console.log("Hello World!");
154
+ console.log("Count: 42, doubled: 84");
155
+ ```
156
+
157
+ This also works with method calls and complex expressions:
158
+
159
+ ```rust
160
+ let field = "username";
161
+
162
+ let code = ts_template! {
163
+ throw new Error("Invalid @{field.to_uppercase()}");
164
+ };
165
+ ```
166
+
167
+ ## Backtick Template Literals: `"'^...^'"`
168
+
169
+ For JavaScript template literals (backtick strings), use the `'^...^'` syntax. This outputs actual backticks and passes through `${"${}"}` for JS interpolation:
170
+
171
+ ```rust
172
+ let tag_name = "div";
173
+
174
+ let code = ts_template! {
175
+ const html = "'^<@{tag_name}>\${content}</@{tag_name}>^'";
176
+ };
177
+ ```
178
+
179
+ **Generates:**
180
+
181
+ <CodeBlock code={'const html = `${content}`;'} lang="typescript" />
182
+
183
+ You can mix Rust `@&#123;&#125;` interpolation (evaluated at macro expansion time) with JS `${"${}"}` interpolation (evaluated at runtime):
184
+
185
+ ```rust
186
+ let class_name = "User";
187
+
188
+ let code = ts_template! {
189
+ "'^Hello \${this.name}, you are a @{class_name}^'"
190
+ };
191
+ ```
192
+
193
+ **Generates:**
194
+
195
+ <CodeBlock code={'`Hello ${this.name}, you are a User`'} lang="typescript" />
196
+
197
+ ## Conditionals: `&#123;#if&#125;...&#123;/if&#125;`
198
+
199
+ Basic conditional:
200
+
201
+ ```rust
202
+ let needs_validation = true;
203
+
204
+ let code = ts_template! {
205
+ function save() {
206
+ {#if needs_validation}
207
+ if (!this.isValid()) return false;
208
+ {/if}
209
+ return this.doSave();
210
+ }
211
+ };
212
+ ```
213
+
214
+ ### If-Else
215
+
216
+ ```rust
217
+ let has_default = true;
218
+
219
+ let code = ts_template! {
220
+ {#if has_default}
221
+ return defaultValue;
222
+ {:else}
223
+ throw new Error("No default");
224
+ {/if}
225
+ };
226
+ ```
227
+
228
+ ### If-Else-If Chains
229
+
230
+ ```rust
231
+ let level = 2;
232
+
233
+ let code = ts_template! {
234
+ {#if level == 1}
235
+ console.log("Level 1");
236
+ {:else if level == 2}
237
+ console.log("Level 2");
238
+ {:else}
239
+ console.log("Other level");
240
+ {/if}
241
+ };
242
+ ```
243
+
244
+ ## Pattern Matching: `&#123;#if let&#125;`
245
+
246
+ Use `if let` for pattern matching on `Option`, `Result`, or other Rust enums:
247
+
248
+ ```rust
249
+ let maybe_name: Option<&str> = Some("Alice");
250
+
251
+ let code = ts_template! {
252
+ {#if let Some(name) = maybe_name}
253
+ console.log("Hello, @{name}!");
254
+ {:else}
255
+ console.log("Hello, anonymous!");
256
+ {/if}
257
+ };
258
+ ```
259
+
260
+ **Generates:**
261
+
262
+ ```typescript
263
+ console.log("Hello, Alice!");
264
+ ```
265
+
266
+ This is useful when working with optional values from your IR:
267
+
268
+ ```rust
269
+ let code = ts_template! {
270
+ {#if let Some(default_val) = field.default_value}
271
+ this.@{field.name} = @{default_val};
272
+ {:else}
273
+ this.@{field.name} = undefined;
274
+ {/if}
275
+ };
276
+ ```
277
+
278
+ ## Match Expressions: `&#123;#match&#125;`
279
+
280
+ Use `match` for exhaustive pattern matching:
281
+
282
+ ```rust
283
+ enum Visibility { Public, Private, Protected }
284
+ let visibility = Visibility::Public;
285
+
286
+ let code = ts_template! {
287
+ {#match visibility}
288
+ {:case Visibility::Public}
289
+ public
290
+ {:case Visibility::Private}
291
+ private
292
+ {:case Visibility::Protected}
293
+ protected
294
+ {/match}
295
+ field: string;
296
+ };
297
+ ```
298
+
299
+ **Generates:**
300
+
301
+ ```typescript
302
+ public field: string;
303
+ ```
304
+
305
+ ### Match with Value Extraction
306
+
307
+ ```rust
308
+ let result: Result<i32, &str> = Ok(42);
309
+
310
+ let code = ts_template! {
311
+ const value = {#match result}
312
+ {:case Ok(val)}
313
+ @{val}
314
+ {:case Err(msg)}
315
+ throw new Error("@{msg}")
316
+ {/match};
317
+ };
318
+ ```
319
+
320
+ ### Match with Wildcard
321
+
322
+ ```rust
323
+ let count = 5;
324
+
325
+ let code = ts_template! {
326
+ {#match count}
327
+ {:case 0}
328
+ console.log("none");
329
+ {:case 1}
330
+ console.log("one");
331
+ {:case _}
332
+ console.log("many");
333
+ {/match}
334
+ };
335
+ ```
336
+
337
+ ## Iteration: `&#123;#for&#125;`
338
+
339
+ ```rust
340
+ let fields = vec!["name", "email", "age"];
341
+
342
+ let code = ts_template! {
343
+ function toJSON() {
344
+ const result = {};
345
+ {#for field in fields}
346
+ result.@{field} = this.@{field};
347
+ {/for}
348
+ return result;
349
+ }
350
+ };
351
+ ```
352
+
353
+ **Generates:**
354
+
355
+ ```typescript
356
+ function toJSON() {
357
+ const result = {};
358
+ result.name = this.name;
359
+ result.email = this.email;
360
+ result.age = this.age;
361
+ return result;
362
+ }
363
+ ```
364
+
365
+ ### Tuple Destructuring in Loops
366
+
367
+ ```rust
368
+ let items = vec![("user", "User"), ("post", "Post")];
369
+
370
+ let code = ts_template! {
371
+ {#for (key, class_name) in items}
372
+ const @{key} = new @{class_name}();
373
+ {/for}
374
+ };
375
+ ```
376
+
377
+ ### Nested Iterations
378
+
379
+ ```rust
380
+ let classes = vec![
381
+ ("User", vec!["name", "email"]),
382
+ ("Post", vec!["title", "content"]),
383
+ ];
384
+
385
+ ts_template! {
386
+ {#for (class_name, fields) in classes}
387
+ @{class_name}.prototype.toJSON = function() {
388
+ return {
389
+ {#for field in fields}
390
+ @{field}: this.@{field},
391
+ {/for}
392
+ };
393
+ };
394
+ {/for}
395
+ }
396
+ ```
397
+
398
+ ## While Loops: `&#123;#while&#125;`
399
+
400
+ Use `while` for loops that need to continue until a condition is false:
401
+
402
+ ```rust
403
+ let items = get_items();
404
+ let mut idx = 0;
405
+
406
+ let code = ts_template! {
407
+ {$let mut i = 0}
408
+ {#while i < items.len()}
409
+ console.log("Item @{i}");
410
+ {$do i += 1}
411
+ {/while}
412
+ };
413
+ ```
414
+
415
+ ### While-Let Pattern Matching
416
+
417
+ Use `while let` for iterating with pattern matching, similar to `if let`:
418
+
419
+ ```rust
420
+ let mut items = vec!["a", "b", "c"].into_iter();
421
+
422
+ let code = ts_template! {
423
+ {#while let Some(item) = items.next()}
424
+ console.log("@{item}");
425
+ {/while}
426
+ };
427
+ ```
428
+
429
+ **Generates:**
430
+
431
+ ```typescript
432
+ console.log("a");
433
+ console.log("b");
434
+ console.log("c");
435
+ ```
436
+
437
+ This is especially useful when working with iterators or consuming optional values:
438
+
439
+ ```rust
440
+ let code = ts_template! {
441
+ {#while let Some(next_field) = remaining_fields.pop()}
442
+ result.@{next_field.name} = this.@{next_field.name};
443
+ {/while}
444
+ };
445
+ ```
446
+
447
+ ## Local Constants: `&#123;$let&#125;`
448
+
449
+ Define local variables within the template scope:
450
+
451
+ ```rust
452
+ let items = vec![("user", "User"), ("post", "Post")];
453
+
454
+ let code = ts_template! {
455
+ {#for (key, class_name) in items}
456
+ {$let upper = class_name.to_uppercase()}
457
+ console.log("Processing @{upper}");
458
+ const @{key} = new @{class_name}();
459
+ {/for}
460
+ };
461
+ ```
462
+
463
+ This is useful for computing derived values inside loops without cluttering the Rust code.
464
+
465
+ ## Mutable Variables: `&#123;$let mut&#125;`
466
+
467
+ When you need to modify a variable within the template (e.g., in a `while` loop), use `&#123;$let mut&#125;`:
468
+
469
+ ```rust
470
+ let code = ts_template! {
471
+ {$let mut count = 0}
472
+ {#for item in items}
473
+ console.log("Item @{count}: @{item}");
474
+ {$do count += 1}
475
+ {/for}
476
+ console.log("Total: @{count}");
477
+ };
478
+ ```
479
+
480
+ ## Side Effects: `&#123;$do&#125;`
481
+
482
+ Execute an expression for its side effects without producing output. This is commonly used with mutable variables:
483
+
484
+ ```rust
485
+ let code = ts_template! {
486
+ {$let mut results: Vec<String> = Vec::new()}
487
+ {#for field in fields}
488
+ {$do results.push(format!("this.{}", field))}
489
+ {/for}
490
+ return [@{results.join(", ")}];
491
+ };
492
+ ```
493
+
494
+ Common uses for `&#123;$do&#125;`:
495
+
496
+ - Incrementing counters: `&#123;$do i += 1&#125;`
497
+
498
+ - Building collections: `&#123;$do vec.push(item)&#125;`
499
+
500
+ - Setting flags: `&#123;$do found = true&#125;`
501
+
502
+ - Any mutating operation
503
+
504
+ ## TsStream Injection: `&#123;$typescript&#125;`
505
+
506
+ Inject another TsStream into your template, preserving both its source code and runtime patches (like imports added via `add_import()`):
507
+
508
+ ```rust
509
+ // Create a helper method with its own import
510
+ let mut helper = body! {
511
+ validateEmail(email: string): boolean {
512
+ return Result.ok(true);
513
+ }
514
+ };
515
+ helper.add_import("Result", "macroforge/result");
516
+
517
+ // Inject the helper into the main template
518
+ let result = body! {
519
+ {$typescript helper}
520
+
521
+ process(data: Record<string, unknown>): void {
522
+ // ...
523
+ }
524
+ };
525
+ // result now includes helper's source AND its Result import
526
+ ```
527
+
528
+ This is essential for composing multiple macro outputs while preserving imports and patches:
529
+
530
+ ```rust
531
+ let extra_methods = if include_validation {
532
+ Some(body! {
533
+ validate(): boolean { return true; }
534
+ })
535
+ } else {
536
+ None
537
+ };
538
+
539
+ body! {
540
+ mainMethod(): void {}
541
+
542
+ {#if let Some(methods) = extra_methods}
543
+ {$typescript methods}
544
+ {/if}
545
+ }
546
+ ```
547
+
548
+ ## Escape Syntax
549
+
550
+ If you need a literal `@&#123;` in your output (not interpolation), use `@@&#123;`:
551
+
552
+ ```rust
553
+ ts_template! {
554
+ // This outputs a literal @{foo}
555
+ const example = "Use @@{foo} for templates";
556
+ }
557
+ ```
558
+
559
+ **Generates:**
560
+
561
+ ```typescript
562
+ // This outputs a literal @{foo}
563
+ const example = "Use @{foo} for templates";
564
+ ```
565
+
566
+ ## Complete Example: JSON Derive Macro
567
+
568
+ Here's a comparison showing how `ts_template!` simplifies code generation:
569
+
570
+ ### Before (Manual AST Building)
571
+
572
+ ```rust
573
+ pub fn derive_json_macro(input: TsStream) -> MacroResult {
574
+ let input = parse_ts_macro_input!(input as DeriveInput);
575
+
576
+ match &input.data {
577
+ Data::Class(class) => {
578
+ let class_name = input.name();
579
+
580
+ let mut body_stmts = vec![ts_quote!( const result = {}; as Stmt )];
581
+
582
+ for field_name in class.field_names() {
583
+ body_stmts.push(ts_quote!(
584
+ result.$(ident!("{}", field_name)) = this.$(ident!("{}", field_name));
585
+ as Stmt
586
+ ));
587
+ }
588
+
589
+ body_stmts.push(ts_quote!( return result; as Stmt ));
590
+
591
+ let runtime_code = fn_assign!(
592
+ member_expr!(Expr::Ident(ident!(class_name)), "prototype"),
593
+ "toJSON",
594
+ body_stmts
595
+ );
596
+
597
+ // ...
598
+ }
599
+ }
600
+ }
601
+ ```
602
+
603
+ ### After (With ts_template!)
604
+
605
+ ```rust
606
+ pub fn derive_json_macro(input: TsStream) -> MacroResult {
607
+ let input = parse_ts_macro_input!(input as DeriveInput);
608
+
609
+ match &input.data {
610
+ Data::Class(class) => {
611
+ let class_name = input.name();
612
+ let fields = class.field_names();
613
+
614
+ let runtime_code = ts_template! {
615
+ @{class_name}.prototype.toJSON = function() {
616
+ const result = {};
617
+ {#for field in fields}
618
+ result.@{field} = this.@{field};
619
+ {/for}
620
+ return result;
621
+ };
622
+ };
623
+
624
+ // ...
625
+ }
626
+ }
627
+ }
628
+ ```
629
+
630
+ ## How It Works
631
+
632
+ 1. **Compile-Time:** The template is parsed during macro expansion
633
+
634
+ 2. **String Building:** Generates Rust code that builds a TypeScript string at runtime
635
+
636
+ 3. **SWC Parsing:** The generated string is parsed with SWC to produce a typed AST
637
+
638
+ 4. **Result:** Returns `Stmt` that can be used in `MacroResult` patches
639
+
640
+ ## Return Type
641
+
642
+ `ts_template!` returns a `Result<Stmt, TsSynError>` by default. The macro automatically unwraps and provides helpful error messages showing the generated TypeScript code if parsing fails:
643
+
644
+ ```text
645
+ Failed to parse generated TypeScript:
646
+ User.prototype.toJSON = function( {
647
+ return {};
648
+ }
649
+ ```
650
+
651
+ This shows you exactly what was generated, making debugging easy!
652
+
653
+ ## Nesting and Regular TypeScript
654
+
655
+ You can mix template syntax with regular TypeScript. Braces `&#123;&#125;` are recognized as either:
656
+
657
+ - **Template tags** if they start with `#`, `$`, `:`, or `/`
658
+
659
+ - **Regular TypeScript blocks** otherwise
660
+
661
+ ```rust
662
+ ts_template! {
663
+ const config = {
664
+ {#if use_strict}
665
+ strict: true,
666
+ {:else}
667
+ strict: false,
668
+ {/if}
669
+ timeout: 5000
670
+ };
671
+ }
672
+ ```
673
+
674
+ ## Comparison with Alternatives
675
+
676
+ | `ts_quote!`
677
+ | Compile-time validation, type-safe
678
+ | Can't handle Vec<Stmt>, verbose
679
+
680
+ | `parse_ts_str()`
681
+ | Maximum flexibility
682
+ | Runtime parsing, less readable
683
+
684
+ | `ts_template!`
685
+ | Readable, handles loops/conditions
686
+ | Small runtime parsing overhead
687
+
688
+ ## Best Practices
689
+
690
+ 1. Use `ts_template!` for complex code generation with loops/conditions
691
+
692
+ 2. Use `ts_quote!` for simple, static statements
693
+
694
+ 3. Keep templates readable - extract complex logic into variables
695
+
696
+ 4. Don't nest templates too deeply - split into helper functions