@macroforge/mcp-server 0.1.17 → 0.1.20
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/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +108 -0
- package/dist/tools/index.js.map +1 -1
- package/docs/builtin-macros/clone.md +18 -77
- package/docs/builtin-macros/debug.md +19 -118
- package/docs/builtin-macros/default.md +13 -98
- package/docs/builtin-macros/deserialize.md +38 -383
- package/docs/builtin-macros/hash.md +16 -98
- package/docs/builtin-macros/macros-overview.md +33 -9
- package/docs/builtin-macros/ord.md +16 -115
- package/docs/builtin-macros/partial-eq.md +26 -128
- package/docs/builtin-macros/partial-ord.md +19 -99
- package/docs/builtin-macros/serialize.md +28 -126
- package/docs/concepts/architecture.md +27 -58
- package/docs/concepts/derive-system.md +17 -45
- package/docs/concepts/how-macros-work.md +11 -50
- package/docs/custom-macros/custom-overview.md +4 -5
- package/docs/custom-macros/rust-setup.md +3 -4
- package/docs/custom-macros/ts-macro-derive.md +4 -5
- package/docs/custom-macros/ts-quote.md +2 -2
- package/docs/getting-started/first-macro.md +6 -72
- package/docs/getting-started/installation.md +2 -2
- package/docs/integration/integration-overview.md +21 -14
- package/docs/integration/mcp-server.md +84 -0
- package/docs/integration/svelte-preprocessor.md +152 -0
- package/docs/language-servers/svelte.md +80 -0
- package/docs/language-servers/zed.md +84 -0
- package/docs/roadmap/roadmap.md +131 -0
- package/docs/sections.json +29 -5
- package/package.json +4 -3
|
@@ -4,37 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## Basic Usage
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
/** @derive(Serialize) */
|
|
9
|
-
class User {
|
|
10
|
-
name: string;
|
|
11
|
-
age: number;
|
|
12
|
-
createdAt: Date;
|
|
13
|
-
|
|
14
|
-
constructor(name: string, age: number) {
|
|
15
|
-
this.name = name;
|
|
16
|
-
this.age = age;
|
|
17
|
-
this.createdAt = new Date();
|
|
18
|
-
}
|
|
19
|
-
}
|
|
7
|
+
<MacroExample before={data.examples.basic.before} after={data.examples.basic.after} />
|
|
20
8
|
|
|
9
|
+
```typescript
|
|
21
10
|
const user = new User("Alice", 30);
|
|
22
11
|
console.log(JSON.stringify(user));
|
|
23
12
|
// {"name":"Alice","age":30,"createdAt":"2024-01-15T10:30:00.000Z"}
|
|
24
13
|
```
|
|
25
14
|
|
|
26
|
-
## Generated Code
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
toJSON(): Record<string, unknown> {
|
|
30
|
-
const result: Record<string, unknown> = {};
|
|
31
|
-
result["name"] = this.name;
|
|
32
|
-
result["age"] = this.age;
|
|
33
|
-
result["createdAt"] = this.createdAt.toISOString();
|
|
34
|
-
return result;
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
15
|
## Automatic Type Handling
|
|
39
16
|
|
|
40
17
|
Serialize automatically handles various TypeScript types:
|
|
@@ -57,32 +34,15 @@ Serialize automatically handles various TypeScript types:
|
|
|
57
34
|
| Nested objects
|
|
58
35
|
| Calls `toJSON()` if available
|
|
59
36
|
|
|
60
|
-
```typescript
|
|
61
|
-
/** @derive(Serialize) */
|
|
62
|
-
class DataContainer {
|
|
63
|
-
items: string[];
|
|
64
|
-
metadata: Map<string, number>;
|
|
65
|
-
tags: Set<string>;
|
|
66
|
-
nested: User;
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
37
|
## Serde Options
|
|
71
38
|
|
|
72
39
|
Use the `@serde` decorator for fine-grained control over serialization:
|
|
73
40
|
|
|
74
41
|
### Renaming Fields
|
|
75
42
|
|
|
76
|
-
|
|
77
|
-
/** @derive(Serialize) */
|
|
78
|
-
class User {
|
|
79
|
-
/** @serde({ rename: "user_id" }) */
|
|
80
|
-
id: string;
|
|
81
|
-
|
|
82
|
-
/** @serde({ rename: "full_name" }) */
|
|
83
|
-
name: string;
|
|
84
|
-
}
|
|
43
|
+
<MacroExample before={data.examples.rename.before} after={data.examples.rename.after} />
|
|
85
44
|
|
|
45
|
+
```typescript
|
|
86
46
|
const user = new User();
|
|
87
47
|
user.id = "123";
|
|
88
48
|
user.name = "Alice";
|
|
@@ -92,19 +52,7 @@ console.log(JSON.stringify(user));
|
|
|
92
52
|
|
|
93
53
|
### Skipping Fields
|
|
94
54
|
|
|
95
|
-
|
|
96
|
-
/** @derive(Serialize) */
|
|
97
|
-
class User {
|
|
98
|
-
name: string;
|
|
99
|
-
email: string;
|
|
100
|
-
|
|
101
|
-
/** @serde({ skip: true }) */
|
|
102
|
-
password: string;
|
|
103
|
-
|
|
104
|
-
/** @serde({ skip_serializing: true }) */
|
|
105
|
-
internalId: string;
|
|
106
|
-
}
|
|
107
|
-
```
|
|
55
|
+
<MacroExample before={data.examples.skip.before} after={data.examples.skip.after} />
|
|
108
56
|
|
|
109
57
|
<Alert type="tip" title="skip vs skip_serializing">
|
|
110
58
|
Use `skip: true` to exclude from both serialization and deserialization.
|
|
@@ -115,15 +63,13 @@ Use `skip_serializing: true` to only skip during serialization.
|
|
|
115
63
|
|
|
116
64
|
Apply a naming convention to all fields at the container level:
|
|
117
65
|
|
|
118
|
-
|
|
119
|
-
/** @derive(Serialize) */
|
|
66
|
+
<InteractiveMacro code={`/** @derive(Serialize) */
|
|
120
67
|
/** @serde({ rename_all: "camelCase" }) */
|
|
121
68
|
class ApiResponse {
|
|
122
|
-
user_name: string;
|
|
123
|
-
created_at: Date;
|
|
124
|
-
is_active: boolean;
|
|
125
|
-
}
|
|
126
|
-
```
|
|
69
|
+
user_name: string;
|
|
70
|
+
created_at: Date;
|
|
71
|
+
is_active: boolean;
|
|
72
|
+
}`} />
|
|
127
73
|
|
|
128
74
|
Supported conventions:
|
|
129
75
|
|
|
@@ -139,8 +85,7 @@ Supported conventions:
|
|
|
139
85
|
|
|
140
86
|
### Flattening Nested Objects
|
|
141
87
|
|
|
142
|
-
|
|
143
|
-
/** @derive(Serialize) */
|
|
88
|
+
<InteractiveMacro code={`/** @derive(Serialize) */
|
|
144
89
|
class Address {
|
|
145
90
|
city: string;
|
|
146
91
|
zip: string;
|
|
@@ -152,8 +97,9 @@ class User {
|
|
|
152
97
|
|
|
153
98
|
/** @serde({ flatten: true }) */
|
|
154
99
|
address: Address;
|
|
155
|
-
}
|
|
100
|
+
}`} />
|
|
156
101
|
|
|
102
|
+
```typescript
|
|
157
103
|
const user = new User();
|
|
158
104
|
user.name = "Alice";
|
|
159
105
|
user.address = { city: "NYC", zip: "10001" };
|
|
@@ -191,25 +137,9 @@ console.log(JSON.stringify(user));
|
|
|
191
137
|
|
|
192
138
|
Serialize also works with interfaces. For interfaces, a namespace is generated with a `toJSON` function:
|
|
193
139
|
|
|
194
|
-
|
|
195
|
-
/** @derive(Serialize) */
|
|
196
|
-
interface ApiResponse {
|
|
197
|
-
status: number;
|
|
198
|
-
message: string;
|
|
199
|
-
timestamp: Date;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Generated:
|
|
203
|
-
// export namespace ApiResponse {
|
|
204
|
-
// export function toJSON(self: ApiResponse): Record<string, unknown> {
|
|
205
|
-
// const result: Record<string, unknown> = {};
|
|
206
|
-
// result["status"] = self.status;
|
|
207
|
-
// result["message"] = self.message;
|
|
208
|
-
// result["timestamp"] = self.timestamp.toISOString();
|
|
209
|
-
// return result;
|
|
210
|
-
// }
|
|
211
|
-
// }
|
|
140
|
+
<MacroExample before={data.examples.interface.before} after={data.examples.interface.after} />
|
|
212
141
|
|
|
142
|
+
```typescript
|
|
213
143
|
const response: ApiResponse = {
|
|
214
144
|
status: 200,
|
|
215
145
|
message: "OK",
|
|
@@ -224,35 +154,23 @@ console.log(JSON.stringify(ApiResponse.toJSON(response)));
|
|
|
224
154
|
|
|
225
155
|
Serialize also works with enums. The `toJSON` function returns the underlying enum value (string or number):
|
|
226
156
|
|
|
227
|
-
|
|
228
|
-
/** @derive(Serialize) */
|
|
229
|
-
enum Status {
|
|
230
|
-
Active = "active",
|
|
231
|
-
Inactive = "inactive",
|
|
232
|
-
Pending = "pending",
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Generated:
|
|
236
|
-
// export namespace Status {
|
|
237
|
-
// export function toJSON(value: Status): string | number {
|
|
238
|
-
// return value;
|
|
239
|
-
// }
|
|
240
|
-
// }
|
|
157
|
+
<MacroExample before={data.examples.enum.before} after={data.examples.enum.after} />
|
|
241
158
|
|
|
159
|
+
```typescript
|
|
242
160
|
console.log(Status.toJSON(Status.Active)); // "active"
|
|
243
161
|
console.log(Status.toJSON(Status.Pending)); // "pending"
|
|
244
162
|
```
|
|
245
163
|
|
|
246
164
|
Works with numeric enums too:
|
|
247
165
|
|
|
248
|
-
|
|
249
|
-
/** @derive(Serialize) */
|
|
166
|
+
<InteractiveMacro code={`/** @derive(Serialize) */
|
|
250
167
|
enum Priority {
|
|
251
168
|
Low = 1,
|
|
252
169
|
Medium = 2,
|
|
253
170
|
High = 3,
|
|
254
|
-
}
|
|
171
|
+
}`} />
|
|
255
172
|
|
|
173
|
+
```typescript
|
|
256
174
|
console.log(Priority.toJSON(Priority.High)); // 3
|
|
257
175
|
```
|
|
258
176
|
|
|
@@ -260,25 +178,9 @@ console.log(Priority.toJSON(Priority.High)); // 3
|
|
|
260
178
|
|
|
261
179
|
Serialize works with type aliases. For object types, fields are serialized with full type handling:
|
|
262
180
|
|
|
263
|
-
|
|
264
|
-
/** @derive(Serialize) */
|
|
265
|
-
type UserProfile = {
|
|
266
|
-
id: string;
|
|
267
|
-
name: string;
|
|
268
|
-
createdAt: Date;
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
// Generated:
|
|
272
|
-
// export namespace UserProfile {
|
|
273
|
-
// export function toJSON(value: UserProfile): Record<string, unknown> {
|
|
274
|
-
// const result: Record<string, unknown> = {};
|
|
275
|
-
// result["id"] = value.id;
|
|
276
|
-
// result["name"] = value.name;
|
|
277
|
-
// result["createdAt"] = value.createdAt.toISOString();
|
|
278
|
-
// return result;
|
|
279
|
-
// }
|
|
280
|
-
// }
|
|
181
|
+
<MacroExample before={data.examples.typeAlias.before} after={data.examples.typeAlias.after} />
|
|
281
182
|
|
|
183
|
+
```typescript
|
|
282
184
|
const profile: UserProfile = {
|
|
283
185
|
id: "123",
|
|
284
186
|
name: "Alice",
|
|
@@ -291,10 +193,10 @@ console.log(JSON.stringify(UserProfile.toJSON(profile)));
|
|
|
291
193
|
|
|
292
194
|
For union types, the value is returned directly:
|
|
293
195
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
type ApiStatus = "loading" | "success" | "error";
|
|
196
|
+
<InteractiveMacro code={`/** @derive(Serialize) */
|
|
197
|
+
type ApiStatus = "loading" | "success" | "error";`} />
|
|
297
198
|
|
|
199
|
+
```typescript
|
|
298
200
|
console.log(ApiStatus.toJSON("success")); // "success"
|
|
299
201
|
```
|
|
300
202
|
|
|
@@ -302,13 +204,13 @@ console.log(ApiStatus.toJSON("success")); // "success"
|
|
|
302
204
|
|
|
303
205
|
Use both Serialize and Deserialize for complete JSON round-trip support:
|
|
304
206
|
|
|
305
|
-
|
|
306
|
-
/** @derive(Serialize, Deserialize) */
|
|
207
|
+
<InteractiveMacro code={`/** @derive(Serialize, Deserialize) */
|
|
307
208
|
class User {
|
|
308
209
|
name: string;
|
|
309
210
|
createdAt: Date;
|
|
310
|
-
}
|
|
211
|
+
}`} />
|
|
311
212
|
|
|
213
|
+
```typescript
|
|
312
214
|
// Serialize
|
|
313
215
|
const user = new User();
|
|
314
216
|
user.name = "Alice";
|
|
@@ -4,21 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
|
|
14
|
-
│ │ ts_syn │ │ ts_quote │ │ts_macro_derive│ │
|
|
15
|
-
│ │ (parsing) │ │ (templating) │ │ (proc-macro) │ │
|
|
16
|
-
│ └─────────────┘ └──────────────┘ └───────────────┘ │
|
|
17
|
-
├─────────────────────────────────────────────────────────┤
|
|
18
|
-
│ SWC Core │
|
|
19
|
-
│ (TypeScript parsing & codegen) │
|
|
20
|
-
└─────────────────────────────────────────────────────────┘
|
|
21
|
-
```
|
|
7
|
+
<ArchitectureDiagram layers={[
|
|
8
|
+
{ title: "Node.js / Vite" },
|
|
9
|
+
{ title: "NAPI-RS Bindings" },
|
|
10
|
+
{ title: "Macro Crates", items: ["macroforge_ts_syn", "macroforge_ts_quote", "macroforge_ts_macros"] },
|
|
11
|
+
{ title: "SWC Core", items: ["TypeScript parsing & codegen"] }
|
|
12
|
+
]} />
|
|
22
13
|
|
|
23
14
|
## Core Components
|
|
24
15
|
|
|
@@ -32,7 +23,7 @@ The foundation layer provides:
|
|
|
32
23
|
|
|
33
24
|
- Code generation (AST → source code)
|
|
34
25
|
|
|
35
|
-
###
|
|
26
|
+
### macroforge_ts_syn
|
|
36
27
|
|
|
37
28
|
A Rust crate that provides:
|
|
38
29
|
|
|
@@ -42,7 +33,7 @@ A Rust crate that provides:
|
|
|
42
33
|
|
|
43
34
|
- Derive input structures (class fields, decorators, etc.)
|
|
44
35
|
|
|
45
|
-
###
|
|
36
|
+
### macroforge_ts_quote
|
|
46
37
|
|
|
47
38
|
Template-based code generation similar to Rust's `quote!`:
|
|
48
39
|
|
|
@@ -52,7 +43,7 @@ Template-based code generation similar to Rust's `quote!`:
|
|
|
52
43
|
|
|
53
44
|
- Control flow: `{"{#for}"}`, `{"{#if}"}`, `{"{$let}"}`
|
|
54
45
|
|
|
55
|
-
###
|
|
46
|
+
### macroforge_ts_macros
|
|
56
47
|
|
|
57
48
|
The procedural macro attribute for defining derive macros:
|
|
58
49
|
|
|
@@ -74,33 +65,16 @@ Bridges Rust and Node.js:
|
|
|
74
65
|
|
|
75
66
|
## Data Flow
|
|
76
67
|
|
|
77
|
-
|
|
78
|
-
1. Source Code
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
4. Macro expander finds @derive decorators
|
|
88
|
-
│
|
|
89
|
-
▼
|
|
90
|
-
5. For each macro:
|
|
91
|
-
│ a. Extract class/interface data
|
|
92
|
-
│ b. Run macro function
|
|
93
|
-
│ c. Generate new AST nodes
|
|
94
|
-
│
|
|
95
|
-
▼
|
|
96
|
-
6. Merge generated nodes into AST
|
|
97
|
-
│
|
|
98
|
-
▼
|
|
99
|
-
7. SWC generates source code
|
|
100
|
-
│
|
|
101
|
-
▼
|
|
102
|
-
8. Return to JavaScript with source mapping
|
|
103
|
-
```
|
|
68
|
+
<Flowchart steps={[
|
|
69
|
+
{ title: "1. Source Code", description: "TypeScript with @derive" },
|
|
70
|
+
{ title: "2. NAPI-RS", description: "receives JavaScript string" },
|
|
71
|
+
{ title: "3. SWC Parser", description: "parses to AST" },
|
|
72
|
+
{ title: "4. Macro Expander", description: "finds @derive decorators" },
|
|
73
|
+
{ title: "5. For Each Macro", description: "extract data, run macro, generate AST nodes" },
|
|
74
|
+
{ title: "6. Merge", description: "generated nodes into AST" },
|
|
75
|
+
{ title: "7. SWC Codegen", description: "generates source code" },
|
|
76
|
+
{ title: "8. Return", description: "to JavaScript with source mapping" }
|
|
77
|
+
]} />
|
|
104
78
|
|
|
105
79
|
## Performance Characteristics
|
|
106
80
|
|
|
@@ -117,19 +91,14 @@ Bridges Rust and Node.js:
|
|
|
117
91
|
For custom macro development, `macroforge_ts` re-exports everything you need:
|
|
118
92
|
|
|
119
93
|
```rust
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// SWC modules
|
|
130
|
-
pub use ts_syn::swc_core;
|
|
131
|
-
pub use ts_syn::swc_common;
|
|
132
|
-
pub use ts_syn::swc_ecma_ast;
|
|
94
|
+
// Convenient re-exports for macro development
|
|
95
|
+
use macroforge_ts::macros::{ts_macro_derive, body, ts_template, above, below, signature};
|
|
96
|
+
use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
|
|
97
|
+
|
|
98
|
+
// Also available: raw crate access and SWC modules
|
|
99
|
+
use macroforge_ts::swc_core;
|
|
100
|
+
use macroforge_ts::swc_common;
|
|
101
|
+
use macroforge_ts::swc_ecma_ast;
|
|
133
102
|
```
|
|
134
103
|
|
|
135
104
|
## Next Steps
|
|
@@ -10,13 +10,10 @@ Macroforge uses JSDoc comments for all macro annotations. This ensures compatibi
|
|
|
10
10
|
|
|
11
11
|
The `@derive` decorator triggers macro expansion on a class or interface:
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/** @derive(Debug, Clone, PartialEq) */
|
|
18
|
-
class AnotherClass { }
|
|
19
|
-
```
|
|
13
|
+
<InteractiveMacro code={`/** @derive(Debug) */
|
|
14
|
+
class MyClass {
|
|
15
|
+
value: string;
|
|
16
|
+
}`} />
|
|
20
17
|
|
|
21
18
|
Syntax rules:
|
|
22
19
|
|
|
@@ -28,16 +25,11 @@ Syntax rules:
|
|
|
28
25
|
|
|
29
26
|
- Multiple `@derive` statements can be stacked
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// Multiple derive statements (equivalent)
|
|
37
|
-
/** @derive(Debug) */
|
|
38
|
-
/** @derive(Clone) */
|
|
39
|
-
class User { }
|
|
40
|
-
```
|
|
28
|
+
<InteractiveMacro code={`/** @derive(Debug, Clone) */
|
|
29
|
+
class User {
|
|
30
|
+
name: string;
|
|
31
|
+
email: string;
|
|
32
|
+
}`} />
|
|
41
33
|
|
|
42
34
|
### The import macro Statement
|
|
43
35
|
|
|
@@ -68,36 +60,15 @@ class User {
|
|
|
68
60
|
}
|
|
69
61
|
```
|
|
70
62
|
|
|
71
|
-
>
|
|
72
|
-
|
|
63
|
+
<Alert type="note" title="Built-in macros">
|
|
64
|
+
Built-in macros (Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize) do not require an import statement.
|
|
65
|
+
</Alert>
|
|
73
66
|
|
|
74
67
|
### Field Attributes
|
|
75
68
|
|
|
76
69
|
Macros can define field-level attributes to customize behavior per field:
|
|
77
70
|
|
|
78
|
-
|
|
79
|
-
/** @attributeName(options) */
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
The attribute name and available options depend on the macro. Common patterns:
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
/** @derive(Debug, Serialize) */
|
|
86
|
-
class User {
|
|
87
|
-
/** @debug({ rename: "userId" }) */
|
|
88
|
-
/** @serde({ rename: "user_id" }) */
|
|
89
|
-
id: number;
|
|
90
|
-
|
|
91
|
-
name: string;
|
|
92
|
-
|
|
93
|
-
/** @debug({ skip: true }) */
|
|
94
|
-
/** @serde({ skip: true }) */
|
|
95
|
-
password: string;
|
|
96
|
-
|
|
97
|
-
/** @serde({ flatten: true }) */
|
|
98
|
-
metadata: Record<string, unknown>;
|
|
99
|
-
}
|
|
100
|
-
```
|
|
71
|
+
<MacroExample before={data.examples.fieldAttributes.before} after={data.examples.fieldAttributes.after} />
|
|
101
72
|
|
|
102
73
|
Syntax rules:
|
|
103
74
|
|
|
@@ -149,10 +120,11 @@ The derive system works on:
|
|
|
149
120
|
|
|
150
121
|
- **Classes**: The primary target for derive macros
|
|
151
122
|
|
|
152
|
-
- **Interfaces**:
|
|
123
|
+
- **Interfaces**: Macros generate companion namespace functions
|
|
124
|
+
|
|
125
|
+
- **Enums**: Macros generate namespace functions for enum values
|
|
153
126
|
|
|
154
|
-
|
|
155
|
-
> Enums are not currently supported by the derive system.
|
|
127
|
+
- **Type aliases**: Both object types and union types are supported
|
|
156
128
|
|
|
157
129
|
## Built-in vs Custom Macros
|
|
158
130
|
|
|
@@ -14,22 +14,7 @@ Unlike runtime solutions that use reflection or proxies, Macroforge expands macr
|
|
|
14
14
|
|
|
15
15
|
4. **Output**: The transformed TypeScript is written out, ready for normal compilation
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
// Your source code
|
|
19
|
-
/** @derive(Debug) */
|
|
20
|
-
class User {
|
|
21
|
-
name: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// After macro expansion
|
|
25
|
-
class User {
|
|
26
|
-
name: string;
|
|
27
|
-
|
|
28
|
-
toString(): string {
|
|
29
|
-
return \`User { name: \${this.name} }\`;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
```
|
|
17
|
+
<MacroExample before={data.examples.basic.before} after={data.examples.basic.after} />
|
|
33
18
|
|
|
34
19
|
## Zero Runtime Overhead
|
|
35
20
|
|
|
@@ -55,43 +40,19 @@ Macroforge tracks the relationship between your source code and the expanded out
|
|
|
55
40
|
|
|
56
41
|
- IDE features like "go to definition" work as expected
|
|
57
42
|
|
|
58
|
-
>
|
|
59
|
-
|
|
43
|
+
<Alert type="info" title="Error positioning">
|
|
44
|
+
The TypeScript plugin uses source mapping to show errors at the `@derive` decorator position, not in the generated code.
|
|
45
|
+
</Alert>
|
|
60
46
|
|
|
61
47
|
## Execution Flow
|
|
62
48
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
┌─────────────────────────────────────────────────────────┐
|
|
71
|
-
│ SWC Parser │
|
|
72
|
-
│ (TypeScript → AST) │
|
|
73
|
-
└───────────────────────┬─────────────────────────────────┘
|
|
74
|
-
│
|
|
75
|
-
▼
|
|
76
|
-
┌─────────────────────────────────────────────────────────┐
|
|
77
|
-
│ Macro Expansion Engine │
|
|
78
|
-
│ - Finds @derive decorators │
|
|
79
|
-
│ - Runs registered macros │
|
|
80
|
-
│ - Generates new AST nodes │
|
|
81
|
-
└───────────────────────┬─────────────────────────────────┘
|
|
82
|
-
│
|
|
83
|
-
▼
|
|
84
|
-
┌─────────────────────────────────────────────────────────┐
|
|
85
|
-
│ Code Generator │
|
|
86
|
-
│ (AST → TypeScript) │
|
|
87
|
-
└───────────────────────┬─────────────────────────────────┘
|
|
88
|
-
│
|
|
89
|
-
▼
|
|
90
|
-
┌─────────────────────────────────────────────────────────┐
|
|
91
|
-
│ Expanded TypeScript │
|
|
92
|
-
│ (ready for normal compilation) │
|
|
93
|
-
└─────────────────────────────────────────────────────────┘
|
|
94
|
-
```
|
|
49
|
+
<Flowchart steps={[
|
|
50
|
+
{ title: "Your Source Code", description: "with @derive decorators" },
|
|
51
|
+
{ title: "SWC Parser", description: "TypeScript → AST" },
|
|
52
|
+
{ title: "Macro Expansion Engine", description: "Finds @derive decorators, runs macros, generates new AST nodes" },
|
|
53
|
+
{ title: "Code Generator", description: "AST → TypeScript" },
|
|
54
|
+
{ title: "Expanded TypeScript", description: "ready for normal compilation" }
|
|
55
|
+
]} />
|
|
95
56
|
|
|
96
57
|
## Integration Points
|
|
97
58
|
|
|
@@ -10,15 +10,14 @@ Custom macros are written in Rust and compiled to native Node.js addons. The pro
|
|
|
10
10
|
|
|
11
11
|
2. Defining macro functions with `#[ts_macro_derive]`
|
|
12
12
|
|
|
13
|
-
3. Using `
|
|
13
|
+
3. Using `macroforge_ts_quote` to generate TypeScript code
|
|
14
14
|
|
|
15
15
|
4. Building and publishing as an npm package
|
|
16
16
|
|
|
17
17
|
## Quick Example
|
|
18
18
|
|
|
19
19
|
```rust
|
|
20
|
-
use macroforge_ts::
|
|
21
|
-
use macroforge_ts::ts_quote::body;
|
|
20
|
+
use macroforge_ts::macros::{ts_macro_derive, body};
|
|
22
21
|
use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
|
|
23
22
|
|
|
24
23
|
#[ts_macro_derive(
|
|
@@ -79,6 +78,6 @@ Follow these guides to create your own macros:
|
|
|
79
78
|
|
|
80
79
|
- [Set up a Rust macro crate]({base}/docs/custom-macros/rust-setup)
|
|
81
80
|
|
|
82
|
-
- [
|
|
81
|
+
- [Learn the #[ts_macro_derive] attribute]({base}/docs/custom-macros/ts-macro-derive)
|
|
83
82
|
|
|
84
|
-
- [Learn the
|
|
83
|
+
- [Learn the template syntax]({base}/docs/custom-macros/ts-quote)
|
|
@@ -61,8 +61,7 @@ fn main() {
|
|
|
61
61
|
|
|
62
62
|
`src/lib.rs`
|
|
63
63
|
```rust
|
|
64
|
-
use macroforge_ts::
|
|
65
|
-
use macroforge_ts::ts_quote::body;
|
|
64
|
+
use macroforge_ts::macros::{ts_macro_derive, body};
|
|
66
65
|
use macroforge_ts::ts_syn::{
|
|
67
66
|
Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input,
|
|
68
67
|
};
|
|
@@ -141,6 +140,6 @@ npm run build
|
|
|
141
140
|
|
|
142
141
|
## Next Steps
|
|
143
142
|
|
|
144
|
-
- [Learn the ts_macro_derive attribute]({base}/docs/custom-macros/ts-macro-derive)
|
|
143
|
+
- [Learn the #[ts_macro_derive] attribute]({base}/docs/custom-macros/ts-macro-derive)
|
|
145
144
|
|
|
146
|
-
- [Master the
|
|
145
|
+
- [Master the template syntax]({base}/docs/custom-macros/ts-quote)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
## Basic Syntax
|
|
6
6
|
|
|
7
7
|
```rust
|
|
8
|
-
use macroforge_ts::
|
|
8
|
+
use macroforge_ts::macros::ts_macro_derive;
|
|
9
9
|
use macroforge_ts::ts_syn::{TsStream, MacroforgeError};
|
|
10
10
|
|
|
11
11
|
#[ts_macro_derive(MacroName)]
|
|
@@ -70,7 +70,7 @@ pub fn my_macro(mut input: TsStream) -> Result<TsStream, MacroforgeError>
|
|
|
70
70
|
Use `parse_ts_macro_input!` to convert the token stream:
|
|
71
71
|
|
|
72
72
|
```rust
|
|
73
|
-
use macroforge_ts::ts_syn::{
|
|
73
|
+
use macroforge_ts::ts_syn::{Data, DeriveInput, parse_ts_macro_input};
|
|
74
74
|
|
|
75
75
|
#[ts_macro_derive(MyMacro)]
|
|
76
76
|
pub fn my_macro(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
|
|
@@ -256,8 +256,7 @@ pub fn class_only(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
|
|
|
256
256
|
## Complete Example
|
|
257
257
|
|
|
258
258
|
```rust
|
|
259
|
-
use macroforge_ts::
|
|
260
|
-
use macroforge_ts::ts_quote::body;
|
|
259
|
+
use macroforge_ts::macros::{ts_macro_derive, body};
|
|
261
260
|
use macroforge_ts::ts_syn::{
|
|
262
261
|
Data, DeriveInput, FieldIR, MacroforgeError, TsStream, parse_ts_macro_input,
|
|
263
262
|
};
|
|
@@ -304,4 +303,4 @@ pub fn derive_validate(mut input: TsStream) -> Result<TsStream, MacroforgeError>
|
|
|
304
303
|
|
|
305
304
|
## Next Steps
|
|
306
305
|
|
|
307
|
-
- [Learn the
|
|
306
|
+
- [Learn the template syntax]({base}/docs/custom-macros/ts-quote)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Template Syntax
|
|
1
|
+
# Template Syntax
|
|
2
2
|
|
|
3
|
-
*The `
|
|
3
|
+
*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.*
|
|
4
4
|
|
|
5
5
|
## Available Macros
|
|
6
6
|
|