@macroforge/mcp-server 0.1.32 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +68 -0
  2. package/dist/index.d.ts +32 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +46 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/tools/docs-loader.d.ts +133 -5
  7. package/dist/tools/docs-loader.d.ts.map +1 -1
  8. package/dist/tools/docs-loader.js +131 -15
  9. package/dist/tools/docs-loader.js.map +1 -1
  10. package/dist/tools/index.d.ts +48 -1
  11. package/dist/tools/index.d.ts.map +1 -1
  12. package/dist/tools/index.js +163 -14
  13. package/dist/tools/index.js.map +1 -1
  14. package/docs/api/api-overview.md +24 -46
  15. package/docs/api/expand-sync.md +24 -51
  16. package/docs/api/native-plugin.md +24 -56
  17. package/docs/api/position-mapper.md +34 -76
  18. package/docs/api/transform-sync.md +27 -59
  19. package/docs/builtin-macros/clone.md +150 -68
  20. package/docs/builtin-macros/debug.md +216 -81
  21. package/docs/builtin-macros/default.md +234 -91
  22. package/docs/builtin-macros/deserialize.md +891 -166
  23. package/docs/builtin-macros/hash.md +238 -82
  24. package/docs/builtin-macros/macros-overview.md +42 -103
  25. package/docs/builtin-macros/ord.md +205 -92
  26. package/docs/builtin-macros/partial-eq.md +178 -97
  27. package/docs/builtin-macros/partial-ord.md +209 -98
  28. package/docs/builtin-macros/serialize.md +326 -137
  29. package/docs/concepts/architecture.md +40 -99
  30. package/docs/concepts/derive-system.md +132 -125
  31. package/docs/concepts/how-macros-work.md +52 -84
  32. package/docs/custom-macros/custom-overview.md +17 -39
  33. package/docs/custom-macros/rust-setup.md +22 -55
  34. package/docs/custom-macros/ts-macro-derive.md +43 -107
  35. package/docs/custom-macros/ts-quote.md +177 -507
  36. package/docs/getting-started/first-macro.md +108 -33
  37. package/docs/getting-started/installation.md +32 -73
  38. package/docs/integration/cli.md +70 -156
  39. package/docs/integration/configuration.md +32 -75
  40. package/docs/integration/integration-overview.md +16 -55
  41. package/docs/integration/mcp-server.md +30 -69
  42. package/docs/integration/svelte-preprocessor.md +60 -83
  43. package/docs/integration/typescript-plugin.md +32 -74
  44. package/docs/integration/vite-plugin.md +30 -79
  45. package/docs/language-servers/ls-overview.md +22 -46
  46. package/docs/language-servers/svelte.md +30 -69
  47. package/docs/language-servers/zed.md +34 -72
  48. package/docs/roadmap/roadmap.md +54 -130
  49. package/docs/sections.json +3 -262
  50. package/package.json +2 -2
@@ -1,91 +1,210 @@
1
1
  # Serialize
2
+ *The `Serialize` macro generates JSON serialization methods with **cycle detection** and object identity tracking. This enables serialization of complex object graphs including circular references.*
3
+ ## Basic Usage
4
+ **Before:**
5
+ ```
6
+ /** @derive(Serialize) */
7
+ class User {
8
+ name: string;
9
+ age: number;
10
+ createdAt: Date;
11
+
12
+ constructor(name: string, age: number) {
13
+ this.name = name;
14
+ this.age = age;
15
+ this.createdAt = new Date();
16
+ }
17
+ }
18
+ ```
19
+ **After:**
20
+ ```
21
+ import { SerializeContext } from 'macroforge/serde';
2
22
 
3
- *The `Serialize` macro generates a `toJSON()` method that converts your object to a JSON-compatible format with automatic handling of complex types like Date, Map, Set, and nested objects.*
4
-
5
- ## Basic Usage
6
-
7
- <MacroExample before={data.examples.basic.before} after={data.examples.basic.after} />
8
-
9
- ```typescript
23
+ class User {
24
+ name: string;
25
+ age: number;
26
+ createdAt: Date;
27
+
28
+ constructor(name: string, age: number) {
29
+ this.name = name;
30
+ this.age = age;
31
+ this.createdAt = new Date();
32
+ }
33
+
34
+ toStringifiedJSON(): string {
35
+ const ctx = SerializeContext.create();
36
+ return JSON.stringify(this.__serialize(ctx));
37
+ }
38
+
39
+ toObject(): Record<string, unknown> {
40
+ const ctx = SerializeContext.create();
41
+ return this.__serialize(ctx);
42
+ }
43
+
44
+ __serialize(ctx: SerializeContext): Record<string, unknown> {
45
+ const existingId = ctx.getId(this);
46
+ if (existingId !== undefined) {
47
+ return {
48
+ __ref: existingId
49
+ };
50
+ }
51
+ const __id = ctx.register(this);
52
+ const result: Record<string, unknown> = {
53
+ __type: 'User',
54
+ __id
55
+ };
56
+ result['name'] = this.name;
57
+ result['age'] = this.age;
58
+ result['createdAt'] = this.createdAt.toISOString();
59
+ return result;
60
+ }
61
+ }
62
+ ``` ```
10
63
  const user = new User("Alice", 30);
11
64
  console.log(JSON.stringify(user));
12
65
  // {"name":"Alice","age":30,"createdAt":"2024-01-15T10:30:00.000Z"}
66
+ ``` ## Automatic Type Handling
67
+ Serialize automatically handles various TypeScript types:
68
+ | Type | Serialization |
69
+ | --- | --- |
70
+ | `string`, `number`, `boolean` | Direct copy |
71
+ | `Date` | `.toISOString()` |
72
+ | `T[]` | Maps items, calling `toJSON()` if available |
73
+ | `Map<K, V>` | `Object.fromEntries()` |
74
+ | `Set<T>` | `Array.from()` |
75
+ | Nested objects | Calls `toJSON()` if available |
76
+ ## Serde Options
77
+ Use the `@serde` decorator for fine-grained control over serialization:
78
+ ### Renaming Fields
79
+ **Before:**
13
80
  ```
81
+ /** @derive(Serialize) */
82
+ class User {
83
+ /** @serde({ rename: "user_id" }) */
84
+ id: string;
14
85
 
15
- ## Automatic Type Handling
16
-
17
- Serialize automatically handles various TypeScript types:
18
-
19
- | `string`, `number`, `boolean`
20
- | Direct copy
21
-
22
- | `Date`
23
- | `.toISOString()`
24
-
25
- | `T[]`
26
- | Maps items, calling `toJSON()` if available
27
-
28
- | `Map<K, V>`
29
- | `Object.fromEntries()`
30
-
31
- | `Set<T>`
32
- | `Array.from()`
33
-
34
- | Nested objects
35
- | Calls `toJSON()` if available
36
-
37
- ## Serde Options
38
-
39
- Use the `@serde` decorator for fine-grained control over serialization:
40
-
41
- ### Renaming Fields
42
-
43
- <MacroExample before={data.examples.rename.before} after={data.examples.rename.after} />
86
+ /** @serde({ rename: "full_name" }) */
87
+ name: string;
88
+ }
89
+ ```
90
+ **After:**
91
+ ```
92
+ import { SerializeContext } from 'macroforge/serde';
44
93
 
45
- ```typescript
94
+ class User {
95
+ id: string;
96
+
97
+ name: string;
98
+
99
+ toStringifiedJSON(): string {
100
+ const ctx = SerializeContext.create();
101
+ return JSON.stringify(this.__serialize(ctx));
102
+ }
103
+
104
+ toObject(): Record<string, unknown> {
105
+ const ctx = SerializeContext.create();
106
+ return this.__serialize(ctx);
107
+ }
108
+
109
+ __serialize(ctx: SerializeContext): Record<string, unknown> {
110
+ const existingId = ctx.getId(this);
111
+ if (existingId !== undefined) {
112
+ return {
113
+ __ref: existingId
114
+ };
115
+ }
116
+ const __id = ctx.register(this);
117
+ const result: Record<string, unknown> = {
118
+ __type: 'User',
119
+ __id
120
+ };
121
+ result['user_id'] = this.id;
122
+ result['full_name'] = this.name;
123
+ return result;
124
+ }
125
+ }
126
+ ``` ```
46
127
  const user = new User();
47
128
  user.id = "123";
48
129
  user.name = "Alice";
49
130
  console.log(JSON.stringify(user));
50
131
  // {"user_id":"123","full_name":"Alice"}
132
+ ``` ### Skipping Fields
133
+ **Before:**
51
134
  ```
135
+ /** @derive(Serialize) */
136
+ class User {
137
+ name: string;
138
+ email: string;
52
139
 
53
- ### Skipping Fields
54
-
55
- <MacroExample before={data.examples.skip.before} after={data.examples.skip.after} />
56
-
57
- <Alert type="tip" title="skip vs skip_serializing">
58
- Use `skip: true` to exclude from both serialization and deserialization.
59
- Use `skip_serializing: true` to only skip during serialization.
60
- </Alert>
61
-
62
- ### Rename All Fields
140
+ /** @serde({ skip: true }) */
141
+ password: string;
63
142
 
64
- Apply a naming convention to all fields at the container level:
143
+ /** @serde({ skip_serializing: true }) */
144
+ internalId: string;
145
+ }
146
+ ```
147
+ **After:**
148
+ ```
149
+ import { SerializeContext } from 'macroforge/serde';
65
150
 
66
- <InteractiveMacro code={`/** @derive(Serialize) */
151
+ class User {
152
+ name: string;
153
+ email: string;
154
+
155
+ password: string;
156
+
157
+ internalId: string;
158
+
159
+ toStringifiedJSON(): string {
160
+ const ctx = SerializeContext.create();
161
+ return JSON.stringify(this.__serialize(ctx));
162
+ }
163
+
164
+ toObject(): Record<string, unknown> {
165
+ const ctx = SerializeContext.create();
166
+ return this.__serialize(ctx);
167
+ }
168
+
169
+ __serialize(ctx: SerializeContext): Record<string, unknown> {
170
+ const existingId = ctx.getId(this);
171
+ if (existingId !== undefined) {
172
+ return {
173
+ __ref: existingId
174
+ };
175
+ }
176
+ const __id = ctx.register(this);
177
+ const result: Record<string, unknown> = {
178
+ __type: 'User',
179
+ __id
180
+ };
181
+ result['name'] = this.name;
182
+ result['email'] = this.email;
183
+ return result;
184
+ }
185
+ }
186
+ ``` **skip vs skip_serializing Use `skip: true` to exclude from both serialization and deserialization.
187
+ Use `skip_serializing: true` to only skip during serialization. ### Rename All Fields
188
+ Apply a naming convention to all fields at the container level:
189
+ ****Source:**
190
+ ```
191
+ /** @derive(Serialize) */
67
192
  /** @serde({ rename_all: "camelCase" }) */
68
193
  class ApiResponse {
69
194
  user_name: string;
70
195
  created_at: Date;
71
196
  is_active: boolean;
72
- }`} />
73
-
74
- Supported conventions:
75
-
76
- - `camelCase`
77
-
78
- - `snake_case`
79
-
80
- - `PascalCase`
81
-
82
- - `SCREAMING_SNAKE_CASE`
83
-
84
- - `kebab-case`
85
-
86
- ### Flattening Nested Objects
87
-
88
- <InteractiveMacro code={`/** @derive(Serialize) */
197
+ }
198
+ ``` Supported conventions:
199
+ - `camelCase`
200
+ - `snake_case`
201
+ - `PascalCase`
202
+ - `SCREAMING_SNAKE_CASE`
203
+ - `kebab-case`
204
+ ### Flattening Nested Objects
205
+ **Source:**
206
+ ```
207
+ /** @derive(Serialize) */
89
208
  class Address {
90
209
  city: string;
91
210
  zip: string;
@@ -97,49 +216,69 @@ class User {
97
216
 
98
217
  /** @serde({ flatten: true }) */
99
218
  address: Address;
100
- }`} />
101
-
102
- ```typescript
219
+ }
220
+ ``` ```
103
221
  const user = new User();
104
222
  user.name = "Alice";
105
223
  user.address = { city: "NYC", zip: "10001" };
106
224
  console.log(JSON.stringify(user));
107
225
  // {"name":"Alice","city":"NYC","zip":"10001"}
226
+ ``` ## All Options
227
+ ### Container Options (on class/interface)
228
+ | Option | Type | Description |
229
+ | --- | --- | --- |
230
+ | `rename_all` | `string` | Apply naming convention to all fields |
231
+ ### Field Options (on properties)
232
+ | Option | Type | Description |
233
+ | --- | --- | --- |
234
+ | `rename` | `string` | Use a different JSON key |
235
+ | `skip` | `boolean` | Exclude from serialization and deserialization |
236
+ | `skip_serializing` | `boolean` | Exclude from serialization only |
237
+ | `flatten` | `boolean` | Merge nested object fields into parent |
238
+ ## Interface Support
239
+ Serialize also works with interfaces. For interfaces, a namespace is generated with a `toJSON` function:
240
+ **Before:**
108
241
  ```
242
+ /** @derive(Serialize) */
243
+ interface ApiResponse {
244
+ status: number;
245
+ message: string;
246
+ timestamp: Date;
247
+ }
248
+ ```
249
+ **After:**
250
+ ```
251
+ import { SerializeContext } from 'macroforge/serde';
109
252
 
110
- ## All Options
111
-
112
- ### Container Options (on class/interface)
113
-
114
- | `rename_all`
115
- | `string`
116
- | Apply naming convention to all fields
117
-
118
- ### Field Options (on properties)
119
-
120
- | `rename`
121
- | `string`
122
- | Use a different JSON key
123
-
124
- | `skip`
125
- | `boolean`
126
- | Exclude from serialization and deserialization
127
-
128
- | `skip_serializing`
129
- | `boolean`
130
- | Exclude from serialization only
131
-
132
- | `flatten`
133
- | `boolean`
134
- | Merge nested object fields into parent
135
-
136
- ## Interface Support
137
-
138
- Serialize also works with interfaces. For interfaces, a namespace is generated with a `toJSON` function:
139
-
140
- <MacroExample before={data.examples.interface.before} after={data.examples.interface.after} />
253
+ interface ApiResponse {
254
+ status: number;
255
+ message: string;
256
+ timestamp: Date;
257
+ }
141
258
 
142
- ```typescript
259
+ export namespace ApiResponse {
260
+ export function toStringifiedJSON(self: ApiResponse): string {
261
+ const ctx = SerializeContext.create();
262
+ return JSON.stringify(__serialize(self, ctx));
263
+ }
264
+ export function toObject(self: ApiResponse): Record<string, unknown> {
265
+ const ctx = SerializeContext.create();
266
+ return __serialize(self, ctx);
267
+ }
268
+ export function __serialize(self: ApiResponse, ctx: SerializeContext): Record<string, unknown> {
269
+ const existingId = ctx.getId(self);
270
+ if (existingId !== undefined) {
271
+ return { __ref: existingId };
272
+ }
273
+ const __id = ctx.register(self);
274
+ const result: Record<string, unknown> = { __type: 'ApiResponse', __id };
275
+ result['status'] = self.status;
276
+ result['message'] = self.message;
277
+ result['timestamp'] = self.timestamp.toISOString();
278
+ return result;
279
+ }
280
+ }
281
+ ``` ```
143
282
  const response: ApiResponse = {
144
283
  status: 200,
145
284
  message: "OK",
@@ -148,39 +287,94 @@ const response: ApiResponse = {
148
287
 
149
288
  console.log(JSON.stringify(ApiResponse.toJSON(response)));
150
289
  // {"status":200,"message":"OK","timestamp":"2024-01-15T10:30:00.000Z"}
290
+ ``` ## Enum Support
291
+ Serialize also works with enums. The `toJSON` function returns the underlying enum value (string or number):
292
+ **Before:**
151
293
  ```
294
+ /** @derive(Serialize) */
295
+ enum Status {
296
+ Active = 'active',
297
+ Inactive = 'inactive',
298
+ Pending = 'pending'
299
+ }
300
+ ```
301
+ **After:**
302
+ ```
303
+ enum Status {
304
+ Active = 'active',
305
+ Inactive = 'inactive',
306
+ Pending = 'pending'
307
+ }
152
308
 
153
- ## Enum Support
154
-
155
- Serialize also works with enums. The `toJSON` function returns the underlying enum value (string or number):
156
-
157
- <MacroExample before={data.examples.enum.before} after={data.examples.enum.after} />
158
-
159
- ```typescript
309
+ export namespace Status {
310
+ export function toStringifiedJSON(value: Status): string {
311
+ return JSON.stringify(value);
312
+ }
313
+ export function __serialize(_ctx: SerializeContext): string | number {
314
+ return value;
315
+ }
316
+ }
317
+ ``` ```
160
318
  console.log(Status.toJSON(Status.Active)); // "active"
161
319
  console.log(Status.toJSON(Status.Pending)); // "pending"
320
+ ``` Works with numeric enums too:
321
+ **Source:**
162
322
  ```
163
-
164
- Works with numeric enums too:
165
-
166
- <InteractiveMacro code={`/** @derive(Serialize) */
323
+ /** @derive(Serialize) */
167
324
  enum Priority {
168
325
  Low = 1,
169
326
  Medium = 2,
170
327
  High = 3,
171
- }`} />
172
-
173
- ```typescript
328
+ }
329
+ ``` ```
174
330
  console.log(Priority.toJSON(Priority.High)); // 3
331
+ ``` ## Type Alias Support
332
+ Serialize works with type aliases. For object types, fields are serialized with full type handling:
333
+ **Before:**
175
334
  ```
335
+ /** @derive(Serialize) */
336
+ type UserProfile = {
337
+ id: string;
338
+ name: string;
339
+ createdAt: Date;
340
+ };
341
+ ```
342
+ **After:**
343
+ ```
344
+ import { SerializeContext } from 'macroforge/serde';
176
345
 
177
- ## Type Alias Support
178
-
179
- Serialize works with type aliases. For object types, fields are serialized with full type handling:
180
-
181
- <MacroExample before={data.examples.typeAlias.before} after={data.examples.typeAlias.after} />
346
+ type UserProfile = {
347
+ id: string;
348
+ name: string;
349
+ createdAt: Date;
350
+ };
182
351
 
183
- ```typescript
352
+ export namespace UserProfile {
353
+ export function toStringifiedJSON(value: UserProfile): string {
354
+ const ctx = SerializeContext.create();
355
+ return JSON.stringify(__serialize(value, ctx));
356
+ }
357
+ export function toObject(value: UserProfile): Record<string, unknown> {
358
+ const ctx = SerializeContext.create();
359
+ return __serialize(value, ctx);
360
+ }
361
+ export function __serialize(
362
+ value: UserProfile,
363
+ ctx: SerializeContext
364
+ ): Record<string, unknown> {
365
+ const existingId = ctx.getId(value);
366
+ if (existingId !== undefined) {
367
+ return { __ref: existingId };
368
+ }
369
+ const __id = ctx.register(value);
370
+ const result: Record<string, unknown> = { __type: 'UserProfile', __id };
371
+ result['id'] = value.id;
372
+ result['name'] = value.name;
373
+ result['createdAt'] = value.createdAt;
374
+ return result;
375
+ }
376
+ }
377
+ ``` ```
184
378
  const profile: UserProfile = {
185
379
  id: "123",
186
380
  name: "Alice",
@@ -189,28 +383,23 @@ const profile: UserProfile = {
189
383
 
190
384
  console.log(JSON.stringify(UserProfile.toJSON(profile)));
191
385
  // {"id":"123","name":"Alice","createdAt":"2024-01-15T00:00:00.000Z"}
386
+ ``` For union types, the value is returned directly:
387
+ **Source:**
192
388
  ```
193
-
194
- For union types, the value is returned directly:
195
-
196
- <InteractiveMacro code={`/** @derive(Serialize) */
197
- type ApiStatus = "loading" | "success" | "error";`} />
198
-
199
- ```typescript
389
+ /** @derive(Serialize) */
390
+ type ApiStatus = "loading" | "success" | "error";
391
+ ``` ```
200
392
  console.log(ApiStatus.toJSON("success")); // "success"
393
+ ``` ## Combining with Deserialize
394
+ Use both Serialize and Deserialize for complete JSON round-trip support:
395
+ **Source:**
201
396
  ```
202
-
203
- ## Combining with Deserialize
204
-
205
- Use both Serialize and Deserialize for complete JSON round-trip support:
206
-
207
- <InteractiveMacro code={`/** @derive(Serialize, Deserialize) */
397
+ /** @derive(Serialize, Deserialize) */
208
398
  class User {
209
399
  name: string;
210
400
  createdAt: Date;
211
- }`} />
212
-
213
- ```typescript
401
+ }
402
+ ``` ```
214
403
  // Serialize
215
404
  const user = new User();
216
405
  user.name = "Alice";
@@ -1,96 +1,41 @@
1
1
  # Architecture
2
-
3
- *Macroforge is built as a native Node.js module using Rust and NAPI-RS. It leverages SWC for fast TypeScript parsing and code generation.*
4
-
5
- ## Overview
6
-
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
- ]} />
13
-
14
- ## Core Components
15
-
16
- ### SWC Core
17
-
18
- The foundation layer provides:
19
-
20
- - Fast TypeScript/JavaScript parsing
21
-
22
- - AST representation
23
-
24
- - Code generation (AST source code)
25
-
26
- ### macroforge_ts_syn
27
-
28
- A Rust crate that provides:
29
-
30
- - TypeScript-specific AST types
31
-
32
- - Parsing utilities for macro input
33
-
34
- - Derive input structures (class fields, decorators, etc.)
35
-
36
- ### macroforge_ts_quote
37
-
38
- Template-based code generation similar to Rust's `quote!`:
39
-
40
- - `ts_template!` - Generate TypeScript code from templates
41
-
42
- - `body!` - Generate class body members
43
-
44
- - Control flow: `{"{#for}"}`, `{"{#if}"}`, `{"{$let}"}`
45
-
46
- ### macroforge_ts_macros
47
-
48
- The procedural macro attribute for defining derive macros:
49
-
50
- - `#[ts_macro_derive(Name)]` attribute
51
-
52
- - Automatic registration with the macro system
53
-
54
- - Error handling and span tracking
55
-
56
- ### NAPI-RS Bindings
57
-
58
- Bridges Rust and Node.js:
59
-
60
- - Exposes `expandSync`, `transformSync`, etc.
61
-
62
- - Provides the `NativePlugin` class for caching
63
-
64
- - Handles data marshaling between Rust and JavaScript
65
-
66
- ## Data Flow
67
-
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
- ]} />
78
-
79
- ## Performance Characteristics
80
-
81
- - **Thread-safe**: Each expansion runs in an isolated thread with a 32MB stack
82
-
83
- - **Caching**: `NativePlugin` caches results by file version
84
-
85
- - **Binary search**: Position mapping uses O(log n) lookups
86
-
87
- - **Zero-copy**: SWC's arena allocator minimizes allocations
88
-
89
- ## Re-exported Crates
90
-
91
- For custom macro development, `macroforge_ts` re-exports everything you need:
92
-
93
- ```rust
2
+ *Macroforge is built as a native Node.js module using Rust and NAPI-RS. It leverages SWC for fast TypeScript parsing and code generation.*
3
+ ## Overview
4
+ <div class="border border-border bg-card p-4 text-center rounded-t-lg "><div class="font-semibold text-foreground">Node.js / Vite <div class="font-semibold text-foreground">NAPI-RS Bindings <div class="font-semibold text-foreground">Macro Crates <div class="px-3 py-1.5 bg-muted rounded text-sm text-muted-foreground font-mono">macroforge_ts_synmacroforge_ts_quotemacroforge_ts_macros<div class="font-semibold text-foreground">SWC Core <div class="px-3 py-1.5 bg-muted rounded text-sm text-muted-foreground font-mono">TypeScript parsing & codegen ## Core Components
5
+ ### SWC Core
6
+ The foundation layer provides:
7
+ - Fast TypeScript/JavaScript parsing
8
+ - AST representation
9
+ - Code generation (AST → source code)
10
+ ### macroforge_ts_syn
11
+ A Rust crate that provides:
12
+ - TypeScript-specific AST types
13
+ - Parsing utilities for macro input
14
+ - Derive input structures (class fields, decorators, etc.)
15
+ ### macroforge_ts_quote
16
+ Template-based code generation similar to Rust's `quote!`:
17
+ - `ts_template!` - Generate TypeScript code from templates
18
+ - `body!` - Generate class body members
19
+ - Control flow: `{#for}`, `{#if}`, `{$let}`
20
+ ### macroforge_ts_macros
21
+ The procedural macro attribute for defining derive macros:
22
+ - `#[ts_macro_derive(Name)]` attribute
23
+ - Automatic registration with the macro system
24
+ - Error handling and span tracking
25
+ ### NAPI-RS Bindings
26
+ Bridges Rust and Node.js:
27
+ - Exposes `expandSync`, `transformSync`, etc.
28
+ - Provides the `NativePlugin` class for caching
29
+ - Handles data marshaling between Rust and JavaScript
30
+ ## Data Flow
31
+ <div class="w-full max-w-md border border-border rounded-lg bg-card p-4 text-center shadow-sm"><div class="font-semibold text-foreground">1. Source Code TypeScript with @derive <div class="font-semibold text-foreground">2. NAPI-RS receives JavaScript string <div class="font-semibold text-foreground">3. SWC Parser parses to AST <div class="font-semibold text-foreground">4. Macro Expander finds @derive decorators <div class="font-semibold text-foreground">5. For Each Macro extract data, run macro, generate AST nodes <div class="font-semibold text-foreground">6. Merge generated nodes into AST <div class="font-semibold text-foreground">7. SWC Codegen generates source code <div class="font-semibold text-foreground">8. Return to JavaScript with source mapping ## Performance Characteristics
32
+ - **Thread-safe**: Each expansion runs in an isolated thread with a 32MB stack
33
+ - **Caching**: `NativePlugin` caches results by file version
34
+ - **Binary search**: Position mapping uses O(log n) lookups
35
+ - **Zero-copy**: SWC's arena allocator minimizes allocations
36
+ ## Re-exported Crates
37
+ For custom macro development, `macroforge_ts` re-exports everything you need:
38
+ ```
94
39
  // Convenient re-exports for macro development
95
40
  use macroforge_ts::macros::{ts_macro_derive, body, ts_template, above, below, signature};
96
41
  use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
@@ -99,10 +44,6 @@ use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_
99
44
  use macroforge_ts::swc_core;
100
45
  use macroforge_ts::swc_common;
101
46
  use macroforge_ts::swc_ecma_ast;
102
- ```
103
-
104
- ## Next Steps
105
-
106
- - [Write custom macros]({base}/docs/custom-macros)
107
-
108
- - [Explore the API reference]({base}/docs/api)
47
+ ``` ## Next Steps
48
+ - [Write custom macros](../../docs/custom-macros)
49
+ - [Explore the API reference](../../docs/api)