@macroforge/mcp-server 0.1.39 → 0.1.42

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