@macroforge/mcp-server 0.1.40 → 0.1.49
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.
- package/LICENSE +22 -0
- package/docs/BOOK.md +165 -0
- package/docs/api/api-overview.md +65 -46
- package/docs/api/expand-sync.md +88 -53
- package/docs/api/native-plugin.md +121 -71
- package/docs/api/position-mapper.md +114 -54
- package/docs/api/transform-sync.md +85 -59
- package/docs/builtin-macros/clone.md +0 -20
- package/docs/builtin-macros/debug.md +0 -23
- package/docs/builtin-macros/default.md +1 -40
- package/docs/builtin-macros/deserialize/example.md +8 -1416
- package/docs/builtin-macros/deserialize.md +8 -1416
- package/docs/builtin-macros/hash.md +0 -42
- package/docs/builtin-macros/macros-overview/detailed-documentation.md +13 -0
- package/docs/builtin-macros/macros-overview/enum-support.md +30 -0
- package/docs/builtin-macros/macros-overview/interface-support.md +28 -0
- package/docs/builtin-macros/macros-overview/overview.md +36 -0
- package/docs/builtin-macros/macros-overview/type-alias-support.md +62 -0
- package/docs/builtin-macros/macros-overview.md +171 -130
- package/docs/builtin-macros/ord.md +0 -25
- package/docs/builtin-macros/partial-eq.md +0 -84
- package/docs/builtin-macros/partial-ord.md +11 -43
- package/docs/builtin-macros/serialize.md +2 -62
- package/docs/concepts/architecture.md +125 -48
- package/docs/concepts/derive-system/built-in-vs-custom-macros.md +13 -0
- package/docs/concepts/derive-system/overview.md +200 -0
- package/docs/concepts/derive-system.md +171 -97
- package/docs/concepts/how-macros-work.md +89 -37
- package/docs/custom-macros/custom-overview.md +79 -57
- package/docs/custom-macros/rust-setup.md +138 -99
- package/docs/custom-macros/ts-macro-derive/accessing-field-data.md +40 -31
- package/docs/custom-macros/ts-macro-derive/adding-imports.md +14 -11
- package/docs/custom-macros/ts-macro-derive/attribute-options.md +20 -25
- package/docs/custom-macros/ts-macro-derive/complete-example.md +40 -38
- package/docs/custom-macros/ts-macro-derive/deriveinput-structure.md +49 -47
- package/docs/custom-macros/ts-macro-derive/function-signature.md +12 -0
- package/docs/custom-macros/ts-macro-derive/overview.md +9 -7
- package/docs/custom-macros/ts-macro-derive/parsing-input.md +20 -18
- package/docs/custom-macros/ts-macro-derive/returning-errors.md +15 -13
- package/docs/custom-macros/ts-macro-derive.md +322 -228
- package/docs/custom-macros/ts-quote/backtick-template-literals.md +19 -7
- package/docs/custom-macros/ts-quote/comments-and.md +56 -22
- package/docs/custom-macros/ts-quote/complete-example-json-derive-macro.md +89 -98
- package/docs/custom-macros/ts-quote/conditionals-ifif.md +35 -29
- package/docs/custom-macros/ts-quote/identifier-concatenation-content.md +30 -22
- package/docs/custom-macros/ts-quote/iteration-for.md +48 -40
- package/docs/custom-macros/ts-quote/local-constants-let.md +23 -21
- package/docs/custom-macros/ts-quote/match-expressions-match.md +46 -38
- package/docs/custom-macros/ts-quote/overview.md +5 -10
- package/docs/custom-macros/ts-quote/pattern-matching-iflet.md +39 -0
- package/docs/custom-macros/ts-quote/quick-reference.md +50 -129
- package/docs/custom-macros/ts-quote/side-effects-do.md +13 -78
- package/docs/custom-macros/ts-quote/string-interpolation-textexpr.md +36 -0
- package/docs/custom-macros/ts-quote/tsstream-injection-typescript.md +43 -35
- package/docs/custom-macros/ts-quote/while-loops-while.md +31 -23
- package/docs/custom-macros/ts-quote.md +799 -519
- package/docs/getting-started/first-macro.md +61 -32
- package/docs/getting-started/installation.md +109 -66
- package/docs/integration/cli.md +212 -103
- package/docs/integration/configuration.md +114 -71
- package/docs/integration/integration-overview.md +54 -17
- package/docs/integration/mcp-server.md +83 -42
- package/docs/integration/svelte-preprocessor.md +183 -126
- package/docs/integration/typescript-plugin.md +101 -54
- package/docs/integration/vite-plugin.md +116 -76
- package/docs/language-servers/ls-overview.md +37 -21
- package/docs/language-servers/svelte.md +69 -39
- package/docs/language-servers/zed.md +81 -45
- package/docs/roadmap/roadmap.md +75 -53
- package/docs/sections.json +333 -44
- package/package.json +27 -28
|
@@ -1,45 +1,79 @@
|
|
|
1
|
-
## Comments:
|
|
1
|
+
## Comments: `{> "..." <}` and `{>> "..." <<}`
|
|
2
2
|
|
|
3
3
|
Since Rust's tokenizer strips whitespace before macros see them, use string literals to preserve exact spacing in comments:
|
|
4
4
|
|
|
5
5
|
### Block Comments
|
|
6
6
|
|
|
7
|
-
Use
|
|
7
|
+
Use `{> "comment" <}` for block comments:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
Rust
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
let code = ts_template! {
|
|
13
|
+
{> "This is a block comment" <}
|
|
14
|
+
const x = 42;
|
|
13
15
|
};
|
|
14
16
|
```
|
|
15
17
|
|
|
16
18
|
**Generates:**
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
TypeScript
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
/* This is a block comment */
|
|
24
|
+
const x = 42;
|
|
21
25
|
```
|
|
22
26
|
|
|
23
27
|
### Doc Comments (JSDoc)
|
|
24
28
|
|
|
25
|
-
Use
|
|
29
|
+
Use `{>> "doc" <<}` for JSDoc comments:
|
|
30
|
+
|
|
31
|
+
Rust
|
|
26
32
|
|
|
27
|
-
```
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
```
|
|
34
|
+
let code = ts_template! {
|
|
35
|
+
{>> "@param {string} name - The user's name" <<}
|
|
36
|
+
{>> "@returns {string} A greeting message" <<}
|
|
37
|
+
function greet(name: string): string {
|
|
38
|
+
return "Hello, " + name;
|
|
39
|
+
}
|
|
34
40
|
};
|
|
35
41
|
```
|
|
36
42
|
|
|
37
43
|
**Generates:**
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
TypeScript
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
/** @param {string} name - The user's name */
|
|
49
|
+
/** @returns {string} A greeting message */
|
|
50
|
+
function greet(name: string): string {
|
|
51
|
+
return "Hello, " + name;
|
|
44
52
|
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Comments with Interpolation
|
|
56
|
+
|
|
57
|
+
Use `format!()` or similar to build dynamic comment strings:
|
|
58
|
+
|
|
59
|
+
Rust
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
let param_name = "userId";
|
|
63
|
+
let param_type = "number";
|
|
64
|
+
let comment = format!("@param {{{}}} {} - The user ID", param_type, param_name);
|
|
65
|
+
|
|
66
|
+
let code = ts_template! {
|
|
67
|
+
{>> @{comment} <<}
|
|
68
|
+
function getUser(userId: number) {}
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Generates:**
|
|
73
|
+
|
|
74
|
+
TypeScript
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
/** @param {number} userId - The user ID */
|
|
78
|
+
function getUser(userId: number) {}
|
|
45
79
|
```
|
|
@@ -4,82 +4,85 @@ Here's a comparison showing how `ts_template!` simplifies code generation:
|
|
|
4
4
|
|
|
5
5
|
### Before (Manual AST Building)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let input = parse_ts_macro_input!(input as DeriveInput);
|
|
10
|
-
|
|
11
|
-
match &input.data {
|
|
12
|
-
Data::Class(class) => {
|
|
13
|
-
let class_name = input.name();
|
|
14
|
-
|
|
15
|
-
let mut body_stmts = vec![ts_quote!( const result = {}; as Stmt )];
|
|
16
|
-
|
|
17
|
-
for field_name in class.field_names() {
|
|
18
|
-
body_stmts.push(ts_quote!(
|
|
19
|
-
result.$(ident!("{}", field_name)) = this.$(ident!("{}", field_name));
|
|
20
|
-
as Stmt
|
|
21
|
-
));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
body_stmts.push(ts_quote!( return result; as Stmt ));
|
|
25
|
-
|
|
26
|
-
let runtime_code = fn_assign!(
|
|
27
|
-
member_expr!(Expr::Ident(ident!(class_name)), "prototype"),
|
|
28
|
-
"toJSON",
|
|
29
|
-
body_stmts
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
// ...
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
7
|
+
Rust
|
|
8
|
+
|
|
36
9
|
```
|
|
10
|
+
pub fn derive_json_macro(input: TsStream) -> MacroResult {
|
|
11
|
+
let input = parse_ts_macro_input!(input as DeriveInput);
|
|
12
|
+
|
|
13
|
+
match &input.data {
|
|
14
|
+
Data::Class(class) => {
|
|
15
|
+
let class_name = input.name();
|
|
16
|
+
|
|
17
|
+
let mut body_stmts = vec![ts_quote!( const result = {}; as Stmt )];
|
|
18
|
+
|
|
19
|
+
for field_name in class.field_names() {
|
|
20
|
+
body_stmts.push(ts_quote!(
|
|
21
|
+
result.$(ident!("{}", field_name)) = this.$(ident!("{}", field_name));
|
|
22
|
+
as Stmt
|
|
23
|
+
));
|
|
24
|
+
}
|
|
37
25
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
let runtime_code = ts_template! {
|
|
50
|
-
@{class_name}.prototype.toJSON = function() {
|
|
51
|
-
const result = {};
|
|
52
|
-
{#for field in fields}
|
|
53
|
-
result.@{field} = this.@{field};
|
|
54
|
-
{/for}
|
|
55
|
-
return result;
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// ...
|
|
60
|
-
}
|
|
61
|
-
}
|
|
26
|
+
body_stmts.push(ts_quote!( return result; as Stmt ));
|
|
27
|
+
|
|
28
|
+
let runtime_code = fn_assign!(
|
|
29
|
+
member_expr!(Expr::Ident(ident!(class_name)), "prototype"),
|
|
30
|
+
"toJSON",
|
|
31
|
+
body_stmts
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// ...
|
|
35
|
+
}
|
|
36
|
+
}
|
|
62
37
|
}
|
|
63
38
|
```
|
|
64
39
|
|
|
65
|
-
|
|
40
|
+
### After (With ts\_template!)
|
|
66
41
|
|
|
67
|
-
|
|
42
|
+
Rust
|
|
68
43
|
|
|
69
|
-
|
|
44
|
+
```
|
|
45
|
+
pub fn derive_json_macro(input: TsStream) -> MacroResult {
|
|
46
|
+
let input = parse_ts_macro_input!(input as DeriveInput);
|
|
47
|
+
|
|
48
|
+
match &input.data {
|
|
49
|
+
Data::Class(class) => {
|
|
50
|
+
let class_name = input.name();
|
|
51
|
+
let fields = class.field_names();
|
|
52
|
+
|
|
53
|
+
let runtime_code = ts_template! {
|
|
54
|
+
@{class_name}.prototype.toJSON = function() {
|
|
55
|
+
const result = {};
|
|
56
|
+
{#for field in fields}
|
|
57
|
+
result.@{field} = this.@{field};
|
|
58
|
+
{/for}
|
|
59
|
+
return result;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// ...
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
70
68
|
|
|
71
|
-
|
|
69
|
+
## How It Works
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
1. **Compile-Time:** The template is parsed during macro expansion
|
|
72
|
+
2. **String Building:** Generates Rust code that builds a TypeScript string at runtime
|
|
73
|
+
3. **SWC Parsing:** The generated string is parsed with SWC to produce a typed AST
|
|
74
|
+
4. **Result:** Returns `Stmt` that can be used in `MacroResult` patches
|
|
74
75
|
|
|
75
76
|
## Return Type
|
|
76
77
|
|
|
77
|
-
`ts_template!` returns a `Result<Stmt,
|
|
78
|
+
`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:
|
|
79
|
+
|
|
80
|
+
Text
|
|
78
81
|
|
|
79
|
-
```
|
|
80
|
-
Failed
|
|
81
|
-
User.prototype.toJSON
|
|
82
|
-
|
|
82
|
+
```
|
|
83
|
+
Failed to parse generated TypeScript:
|
|
84
|
+
User.prototype.toJSON = function( {
|
|
85
|
+
return {};
|
|
83
86
|
}
|
|
84
87
|
```
|
|
85
88
|
|
|
@@ -87,49 +90,37 @@ This shows you exactly what was generated, making debugging easy!
|
|
|
87
90
|
|
|
88
91
|
## Nesting and Regular TypeScript
|
|
89
92
|
|
|
90
|
-
You can mix template syntax with regular TypeScript. Braces
|
|
93
|
+
You can mix template syntax with regular TypeScript. Braces `{}` are recognized as either:
|
|
91
94
|
|
|
92
|
-
|
|
95
|
+
* **Template tags** if they start with `#`, `$`, `:`, or `/`
|
|
96
|
+
* **Regular TypeScript blocks** otherwise
|
|
93
97
|
|
|
94
|
-
|
|
98
|
+
Rust
|
|
95
99
|
|
|
96
|
-
```
|
|
97
|
-
ts_template!
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
```
|
|
101
|
+
ts_template! {
|
|
102
|
+
const config = {
|
|
103
|
+
{#if use_strict}
|
|
104
|
+
strict: true,
|
|
105
|
+
{:else}
|
|
106
|
+
strict: false,
|
|
107
|
+
{/if}
|
|
108
|
+
timeout: 5000
|
|
109
|
+
};
|
|
106
110
|
}
|
|
107
111
|
```
|
|
108
112
|
|
|
109
113
|
## Comparison with Alternatives
|
|
110
114
|
|
|
111
|
-
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
| `parse_ts_str()`
|
|
118
|
-
| Maximum flexibility
|
|
119
|
-
| Runtime parsing, less readable
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
| `ts_template!`
|
|
124
|
-
| Readable, handles loops/conditions
|
|
125
|
-
| Small runtime parsing overhead
|
|
115
|
+
| Approach | Pros | Cons |
|
|
116
|
+
| ---------------- | ---------------------------------- | -------------------------------- |
|
|
117
|
+
| `ts_quote!` | Compile-time validation, type-safe | Can't handle Vec\<Stmt>, verbose |
|
|
118
|
+
| `parse_ts_str()` | Maximum flexibility | Runtime parsing, less readable |
|
|
119
|
+
| `ts_template!` | Readable, handles loops/conditions | Small runtime parsing overhead |
|
|
126
120
|
|
|
127
121
|
## Best Practices
|
|
128
122
|
|
|
129
|
-
1.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
3. Keep templates readable - extract complex logic into variables
|
|
134
|
-
|
|
135
|
-
4. Don't nest templates too deeply - split into helper functions
|
|
123
|
+
1. Use `ts_template!` for complex code generation with loops/conditions
|
|
124
|
+
2. Use `ts_quote!` for simple, static statements
|
|
125
|
+
3. Keep templates readable - extract complex logic into variables
|
|
126
|
+
4. Don't nest templates too deeply - split into helper functions
|
|
@@ -1,46 +1,52 @@
|
|
|
1
|
-
## Conditionals:
|
|
1
|
+
## Conditionals: `{#if}...{/if}`
|
|
2
2
|
|
|
3
3
|
Basic conditional:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
let needs_validation = true;
|
|
5
|
+
Rust
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
```
|
|
8
|
+
let needs_validation = true;
|
|
9
|
+
|
|
10
|
+
let code = ts_template! {
|
|
11
|
+
function save() {
|
|
12
|
+
{#if needs_validation}
|
|
13
|
+
if (!this.isValid()) return false;
|
|
14
|
+
{/if}
|
|
15
|
+
return this.doSave();
|
|
16
|
+
}
|
|
15
17
|
};
|
|
16
18
|
```
|
|
17
19
|
|
|
18
20
|
### If-Else
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
let has_default = true;
|
|
22
|
+
Rust
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
```
|
|
25
|
+
let has_default = true;
|
|
26
|
+
|
|
27
|
+
let code = ts_template! {
|
|
28
|
+
{#if has_default}
|
|
29
|
+
return defaultValue;
|
|
30
|
+
{:else}
|
|
31
|
+
throw new Error("No default");
|
|
32
|
+
{/if}
|
|
29
33
|
};
|
|
30
34
|
```
|
|
31
35
|
|
|
32
36
|
### If-Else-If Chains
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
let
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
Rust
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
let level = 2;
|
|
42
|
+
|
|
43
|
+
let code = ts_template! {
|
|
44
|
+
{#if level == 1}
|
|
45
|
+
console.log("Level 1");
|
|
46
|
+
{:else if level == 2}
|
|
47
|
+
console.log("Level 2");
|
|
48
|
+
{:else}
|
|
49
|
+
console.log("Other level");
|
|
50
|
+
{/if}
|
|
45
51
|
};
|
|
46
52
|
```
|
|
@@ -1,42 +1,50 @@
|
|
|
1
|
-
## Identifier Concatenation:
|
|
1
|
+
## Identifier Concatenation: `{| content |}`
|
|
2
2
|
|
|
3
|
-
When you need to build identifiers dynamically (like `getUser`, `setName`), use the ident block syntax. Everything inside
|
|
3
|
+
When you need to build identifiers dynamically (like `getUser`, `setName`), use the ident block syntax. Everything inside `{| |}` is concatenated without spaces:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
let field_name = "User";
|
|
5
|
+
Rust
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
```
|
|
8
|
+
let field_name = "User";
|
|
9
|
+
|
|
10
|
+
let code = ts_template! {
|
|
11
|
+
function {|get@{field_name}|}() {
|
|
12
|
+
return this.@{field_name.to_lowercase()};
|
|
13
|
+
}
|
|
12
14
|
};
|
|
13
15
|
```
|
|
14
16
|
|
|
15
17
|
**Generates:**
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
TypeScript
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
function getUser() {
|
|
23
|
+
return this.user;
|
|
20
24
|
}
|
|
21
25
|
```
|
|
22
26
|
|
|
23
|
-
Without ident blocks,
|
|
27
|
+
Without ident blocks, `@{}` always adds a space after for readability. Use `{| |}` when you explicitly want concatenation:
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
let name = "Status";
|
|
29
|
+
Rust
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
```
|
|
32
|
+
let name = "Status";
|
|
33
|
+
|
|
34
|
+
// With space (default behavior)
|
|
35
|
+
ts_template! { namespace @{name} } // → "namespace Status"
|
|
30
36
|
|
|
31
|
-
//
|
|
32
|
-
ts_template!
|
|
37
|
+
// Without space (ident block)
|
|
38
|
+
ts_template! { {|namespace@{name}|} } // → "namespaceStatus"
|
|
33
39
|
```
|
|
34
40
|
|
|
35
41
|
Multiple interpolations can be combined:
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
Rust
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
let entity = "user";
|
|
47
|
+
let action = "create";
|
|
40
48
|
|
|
41
|
-
ts_template!
|
|
49
|
+
ts_template! { {|@{entity}_@{action}|} } // → "user_create"
|
|
42
50
|
```
|
|
@@ -1,60 +1,68 @@
|
|
|
1
|
-
## Iteration:
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
## Iteration: `{#for}`
|
|
2
|
+
|
|
3
|
+
Rust
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
let fields = vec!["name", "email", "age"];
|
|
7
|
+
|
|
8
|
+
let code = ts_template! {
|
|
9
|
+
function toJSON() {
|
|
10
|
+
const result = {};
|
|
11
|
+
{#for field in fields}
|
|
12
|
+
result.@{field} = this.@{field};
|
|
13
|
+
{/for}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
14
16
|
};
|
|
15
17
|
```
|
|
16
18
|
|
|
17
19
|
**Generates:**
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
TypeScript
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
function toJSON() {
|
|
25
|
+
const result = {};
|
|
26
|
+
result.name = this.name;
|
|
27
|
+
result.email = this.email;
|
|
28
|
+
result.age = this.age;
|
|
29
|
+
return result;
|
|
26
30
|
}
|
|
27
31
|
```
|
|
28
32
|
|
|
29
33
|
### Tuple Destructuring in Loops
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
Rust
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
let items = vec![("user", "User"), ("post", "Post")];
|
|
33
39
|
|
|
34
|
-
let
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
let code = ts_template! {
|
|
41
|
+
{#for (key, class_name) in items}
|
|
42
|
+
const @{key} = new @{class_name}();
|
|
43
|
+
{/for}
|
|
38
44
|
};
|
|
39
45
|
```
|
|
40
46
|
|
|
41
47
|
### Nested Iterations
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
Rust
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
let classes = vec![
|
|
53
|
+
("User", vec!["name", "email"]),
|
|
54
|
+
("Post", vec!["title", "content"]),
|
|
47
55
|
];
|
|
48
56
|
|
|
49
|
-
ts_template!
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
ts_template! {
|
|
58
|
+
{#for (class_name, fields) in classes}
|
|
59
|
+
@{class_name}.prototype.toJSON = function() {
|
|
60
|
+
return {
|
|
61
|
+
{#for field in fields}
|
|
62
|
+
@{field}: this.@{field},
|
|
63
|
+
{/for}
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
{/for}
|
|
59
67
|
}
|
|
60
68
|
```
|
|
@@ -1,34 +1,36 @@
|
|
|
1
|
-
## Local Constants:
|
|
1
|
+
## Local Constants: `{$let}`
|
|
2
2
|
|
|
3
3
|
Define local variables within the template scope:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
let items = vec![("user", "User"), ("post", "Post")];
|
|
5
|
+
Rust
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
```
|
|
8
|
+
let items = vec![("user", "User"), ("post", "Post")];
|
|
9
|
+
|
|
10
|
+
let code = ts_template! {
|
|
11
|
+
{#for (key, class_name) in items}
|
|
12
|
+
{$let upper = class_name.to_uppercase()}
|
|
13
|
+
console.log("Processing @{upper}");
|
|
14
|
+
const @{key} = new @{class_name}();
|
|
15
|
+
{/for}
|
|
14
16
|
};
|
|
15
17
|
```
|
|
16
18
|
|
|
17
19
|
This is useful for computing derived values inside loops without cluttering the Rust code.
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
Mutable Variables: `{$let mut}`
|
|
21
|
-
</h2>
|
|
21
|
+
## Mutable Variables: `{$let mut}`
|
|
22
22
|
|
|
23
|
-
When you need to modify a variable within the template (e.g., in a
|
|
23
|
+
When you need to modify a variable within the template (e.g., in a `while` loop), use `{$let mut}`:
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
Rust
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
let code = ts_template! {
|
|
29
|
+
{$let mut count = 0}
|
|
30
|
+
{#for item in items}
|
|
31
|
+
console.log("Item @{count}: @{item}");
|
|
32
|
+
{$do count += 1}
|
|
33
|
+
{/for}
|
|
34
|
+
console.log("Total: @{count}");
|
|
33
35
|
};
|
|
34
36
|
```
|