@macroforge/mcp-server 0.1.42 → 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.
Files changed (71) hide show
  1. package/LICENSE +22 -0
  2. package/docs/BOOK.md +165 -0
  3. package/docs/api/api-overview.md +67 -48
  4. package/docs/api/expand-sync.md +88 -53
  5. package/docs/api/native-plugin.md +121 -71
  6. package/docs/api/position-mapper.md +115 -55
  7. package/docs/api/transform-sync.md +86 -60
  8. package/docs/builtin-macros/clone.md +0 -20
  9. package/docs/builtin-macros/debug.md +0 -23
  10. package/docs/builtin-macros/default.md +1 -40
  11. package/docs/builtin-macros/deserialize/example.md +8 -1416
  12. package/docs/builtin-macros/deserialize.md +8 -1416
  13. package/docs/builtin-macros/hash.md +0 -42
  14. package/docs/builtin-macros/macros-overview/detailed-documentation.md +13 -0
  15. package/docs/builtin-macros/macros-overview/enum-support.md +30 -0
  16. package/docs/builtin-macros/macros-overview/interface-support.md +28 -0
  17. package/docs/builtin-macros/macros-overview/overview.md +36 -0
  18. package/docs/builtin-macros/macros-overview/type-alias-support.md +62 -0
  19. package/docs/builtin-macros/macros-overview.md +171 -130
  20. package/docs/builtin-macros/ord.md +0 -25
  21. package/docs/builtin-macros/partial-eq.md +0 -84
  22. package/docs/builtin-macros/partial-ord.md +2 -32
  23. package/docs/builtin-macros/serialize.md +2 -62
  24. package/docs/concepts/architecture.md +125 -48
  25. package/docs/concepts/derive-system/built-in-vs-custom-macros.md +13 -0
  26. package/docs/concepts/derive-system/overview.md +200 -0
  27. package/docs/concepts/derive-system.md +157 -104
  28. package/docs/concepts/how-macros-work.md +98 -47
  29. package/docs/custom-macros/custom-overview.md +79 -57
  30. package/docs/custom-macros/rust-setup.md +138 -99
  31. package/docs/custom-macros/ts-macro-derive/accessing-field-data.md +40 -31
  32. package/docs/custom-macros/ts-macro-derive/adding-imports.md +14 -11
  33. package/docs/custom-macros/ts-macro-derive/attribute-options.md +20 -25
  34. package/docs/custom-macros/ts-macro-derive/complete-example.md +40 -38
  35. package/docs/custom-macros/ts-macro-derive/deriveinput-structure.md +49 -47
  36. package/docs/custom-macros/ts-macro-derive/function-signature.md +12 -0
  37. package/docs/custom-macros/ts-macro-derive/overview.md +9 -7
  38. package/docs/custom-macros/ts-macro-derive/parsing-input.md +20 -18
  39. package/docs/custom-macros/ts-macro-derive/returning-errors.md +15 -13
  40. package/docs/custom-macros/ts-macro-derive.md +322 -228
  41. package/docs/custom-macros/ts-quote/backtick-template-literals.md +19 -7
  42. package/docs/custom-macros/ts-quote/comments-and.md +56 -22
  43. package/docs/custom-macros/ts-quote/complete-example-json-derive-macro.md +89 -98
  44. package/docs/custom-macros/ts-quote/conditionals-ifif.md +35 -29
  45. package/docs/custom-macros/ts-quote/identifier-concatenation-content.md +30 -22
  46. package/docs/custom-macros/ts-quote/iteration-for.md +48 -40
  47. package/docs/custom-macros/ts-quote/local-constants-let.md +23 -21
  48. package/docs/custom-macros/ts-quote/match-expressions-match.md +46 -38
  49. package/docs/custom-macros/ts-quote/overview.md +5 -10
  50. package/docs/custom-macros/ts-quote/pattern-matching-iflet.md +39 -0
  51. package/docs/custom-macros/ts-quote/quick-reference.md +50 -129
  52. package/docs/custom-macros/ts-quote/side-effects-do.md +13 -78
  53. package/docs/custom-macros/ts-quote/string-interpolation-textexpr.md +36 -0
  54. package/docs/custom-macros/ts-quote/tsstream-injection-typescript.md +43 -35
  55. package/docs/custom-macros/ts-quote/while-loops-while.md +31 -23
  56. package/docs/custom-macros/ts-quote.md +800 -520
  57. package/docs/getting-started/first-macro.md +98 -71
  58. package/docs/getting-started/installation.md +109 -65
  59. package/docs/integration/cli.md +214 -105
  60. package/docs/integration/configuration.md +115 -72
  61. package/docs/integration/integration-overview.md +55 -18
  62. package/docs/integration/mcp-server.md +84 -43
  63. package/docs/integration/svelte-preprocessor.md +183 -126
  64. package/docs/integration/typescript-plugin.md +101 -53
  65. package/docs/integration/vite-plugin.md +116 -76
  66. package/docs/language-servers/ls-overview.md +37 -21
  67. package/docs/language-servers/svelte.md +69 -38
  68. package/docs/language-servers/zed.md +81 -44
  69. package/docs/roadmap/roadmap.md +75 -53
  70. package/docs/sections.json +333 -44
  71. package/package.json +27 -28
@@ -1,161 +1,214 @@
1
1
  # The Derive System
2
- *The derive system is inspired by Rust's derive macros. It allows you to automatically implement common patterns by annotating your classes with <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@derive</code>.*
3
- ## Syntax Reference
4
- Macroforge uses JSDoc comments for all macro annotations. This ensures compatibility with standard TypeScript tooling.
5
- ### The @derive Statement
6
- The <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@derive</code> decorator triggers macro expansion on a class or interface:
7
- **Source:**
2
+
3
+ The derive system is inspired by Rust's derive macros. It allows you to automatically implement common patterns by annotating your classes with `@derive`.
4
+
5
+ ## Syntax Reference
6
+
7
+ Macroforge uses JSDoc comments for all macro annotations. This ensures compatibility with standard TypeScript tooling.
8
+
9
+ ### The @derive Statement
10
+
11
+ The `@derive` decorator triggers macro expansion on a class or interface:
12
+
13
+ Source
14
+
15
+ TypeScript
16
+
8
17
  ```
9
18
  /** @derive(Debug) */
10
- class MyClass &#123;
19
+ class MyClass {
11
20
  value: string;
12
- &#125;
13
- ``` Syntax rules:
14
- - Must be inside a JSDoc comment (<code class="shiki-inline"><span class="line"><span style="--shiki-dark:#6A737D;--shiki-light:#6A737D">/** */</code>)
15
- - Must appear immediately before the class/interface declaration
16
- - Multiple macros can be comma-separated: <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@<span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">derive<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">(<span style="--shiki-dark:#79B8FF;--shiki-light:#005CC5">A<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">, <span style="--shiki-dark:#79B8FF;--shiki-light:#005CC5">B<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">, <span style="--shiki-dark:#79B8FF;--shiki-light:#005CC5">C<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">)</code>
17
- - Multiple <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@derive</code> statements can be stacked
18
- **Source:**
21
+ }
22
+ ```
23
+
24
+ Syntax rules:
25
+
26
+ * Must be inside a JSDoc comment (`/** */`)
27
+ * Must appear immediately before the class/interface declaration
28
+ * Multiple macros can be comma-separated: `@derive(A, B, C)`
29
+ * Multiple `@derive` statements can be stacked
30
+
31
+ Source
32
+
33
+ TypeScript
34
+
19
35
  ```
20
36
  /** @derive(Debug, Clone) */
21
- class User &#123;
37
+ class User {
22
38
  name: string;
23
39
  email: string;
24
- &#125;
25
- ``` ### The import macro Statement
26
- To use macros from external packages, you must declare them with <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#F97583;--shiki-light:#D73A49">import<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E"> macro</code>:
27
- ```
28
- /**&nbsp;import&nbsp;macro&nbsp;&#123;&nbsp;MacroName&nbsp;&#125;&nbsp;from&nbsp;"package-name";&nbsp;*/
29
- ``` Syntax rules:
30
- - Must be inside a JSDoc comment (<code class="shiki-inline"><span class="line"><span style="--shiki-dark:#6A737D;--shiki-light:#6A737D">/** */</code>)
31
- - Can appear anywhere in the file (typically at the top)
32
- - Multiple macros can be imported: <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#F97583;--shiki-light:#D73A49">import<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E"> macro { A, B } <span style="--shiki-dark:#F97583;--shiki-light:#D73A49">from<span style="--shiki-dark:#9ECBFF;--shiki-light:#032F62"> "pkg"<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">;</code>
33
- - Multiple import statements can be used for different packages
34
- ```
35
- /**&nbsp;import&nbsp;macro&nbsp;&#123;&nbsp;JSON,&nbsp;Validate&nbsp;&#125;&nbsp;from&nbsp;"@my/macros";&nbsp;*/
36
- /**&nbsp;import&nbsp;macro&nbsp;&#123;&nbsp;Builder&nbsp;&#125;&nbsp;from&nbsp;"@other/macros";&nbsp;*/
37
-
38
- /**&nbsp;@derive(JSON,&nbsp;Validate,&nbsp;Builder)&nbsp;*/
39
- class&nbsp;User&nbsp;&#123;
40
- &nbsp;&nbsp;name:&nbsp;string;
41
- &nbsp;&nbsp;email:&nbsp;string;
42
- &#125;
43
- ``` **Built-in macros Built-in macros (Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize) do not require an import statement. ### Field Attributes
44
- Macros can define field-level attributes to customize behavior per field:
45
- **<div><div class="flex items-center justify-between gap-2 px-4 py-2 bg-muted rounded-t-lg border border-b-0 border-border">
46
- **Before:**
40
+ }
41
+ ```
42
+
43
+ ### The import macro Statement
44
+
45
+ To use macros from external packages, you must declare them with `import macro`:
46
+
47
+ TypeScript
48
+
49
+ ```
50
+ /** import macro { MacroName } from "package-name"; */
51
+ ```
52
+
53
+ Syntax rules:
54
+
55
+ * Must be inside a JSDoc comment (`/** */`)
56
+ * Can appear anywhere in the file (typically at the top)
57
+ * Multiple macros can be imported: `import macro { A, B } from "pkg";`
58
+ * Multiple import statements can be used for different packages
59
+
60
+ TypeScript
61
+
62
+ ```
63
+ /** import macro { JSON, Validate } from "@my/macros"; */
64
+ /** import macro { Builder } from "@other/macros"; */
65
+
66
+ /** @derive(JSON, Validate, Builder) */
67
+ class User {
68
+   name: string;
69
+   email: string;
70
+ }
71
+ ```
72
+
73
+ Built-in macros
74
+
75
+ Built-in macros (Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize) do not require an import statement.
76
+
77
+ ### Field Attributes
78
+
79
+ Macros can define field-level attributes to customize behavior per field:
80
+
81
+ Before (Your Code)
82
+
47
83
  ```
48
84
  /** @derive(Debug, Serialize) */
49
- class User &#123;
50
- /** @debug(&#123; rename: "userId" &#125;) */
51
- /** @serde(&#123; rename: "user_id" &#125;) */
85
+ class User {
86
+ /** @debug({ rename: "userId" }) */
87
+ /** @serde({ rename: "user_id" }) */
52
88
  id: number;
53
89
 
54
90
  name: string;
55
91
 
56
- /** @debug(&#123; skip: true &#125;) */
57
- /** @serde(&#123; skip: true &#125;) */
92
+ /** @debug({ skip: true }) */
93
+ /** @serde({ skip: true }) */
58
94
  password: string;
59
95
 
60
- metadata: Record&#x3C;string, unknown>;
61
- &#125;
62
- ``` <div class="flex items-center justify-between gap-2 px-4 py-2 bg-muted rounded-t-lg border border-b-0 border-border">
63
- **After:**
96
+ metadata: Record<string, unknown>;
97
+ }
98
+ ```
99
+
100
+ After (Generated)
101
+
64
102
  ```
65
- import &#123; SerializeContext &#125; from 'macroforge/serde';
103
+ import { SerializeContext as __mf_SerializeContext } from 'macroforge/serde';
66
104
 
67
- class User &#123;
105
+ class User {
68
106
  id: number;
69
107
 
70
108
  name: string;
71
109
 
72
110
  password: string;
73
111
 
74
- metadata: Record&#x3C;string, unknown>;
112
+ metadata: Record<string, unknown>;
75
113
 
76
- static toString(value: User): string &#123;
114
+ static toString(value: User): string {
77
115
  return userToString(value);
78
- &#125;
116
+ }
79
117
  /** Serializes a value to a JSON string.
80
118
  @param value - The value to serialize
81
119
  @returns JSON string representation with cycle detection metadata */
82
120
 
83
- static serialize(value: User): string &#123;
121
+ static serialize(value: User): string {
84
122
  return userSerialize(value);
85
- &#125;
123
+ }
86
124
  /** @internal Serializes with an existing context for nested/cyclic object graphs.
87
125
  @param value - The value to serialize
88
126
  @param ctx - The serialization context */
89
127
 
90
- static serializeWithContext(value: User, ctx: SerializeContext): Record&#x3C;string, unknown> &#123;
128
+ static serializeWithContext(value: User, ctx: __mf_SerializeContext): Record<string, unknown> {
91
129
  return userSerializeWithContext(value, ctx);
92
- &#125;
93
- &#125;
130
+ }
131
+ }
94
132
 
95
- export function userToString(value: User): string &#123;
133
+ export function userToString(value: User): string {
96
134
  const parts: string[] = [];
97
135
  parts.push('userId: ' + value.id);
98
136
  parts.push('name: ' + value.name);
99
137
  parts.push('metadata: ' + value.metadata);
100
- return 'User &#123; ' + parts.join(', ') + ' &#125;';
101
- &#125;
138
+ return 'User { ' + parts.join(', ') + ' }';
139
+ }
102
140
 
103
141
  /** Serializes a value to a JSON string.
104
142
  @param value - The value to serialize
105
143
  @returns JSON string representation with cycle detection metadata */ export function userSerialize(
106
144
  value: User
107
- ): string &#123;
108
- const ctx = SerializeContext.create();
145
+ ): string {
146
+ const ctx = __mf_SerializeContext.create();
109
147
  return JSON.stringify(userSerializeWithContext(value, ctx));
110
- &#125; /** @internal Serializes with an existing context for nested/cyclic object graphs.
148
+ } /** @internal Serializes with an existing context for nested/cyclic object graphs.
111
149
  @param value - The value to serialize
112
150
  @param ctx - The serialization context */
113
151
  export function userSerializeWithContext(
114
152
  value: User,
115
- ctx: SerializeContext
116
- ): Record&#x3C;string, unknown> &#123;
153
+ ctx: __mf_SerializeContext
154
+ ): Record<string, unknown> {
117
155
  const existingId = ctx.getId(value);
118
- if (existingId !== undefined) &#123;
119
- return &#123; __ref: existingId &#125;;
120
- &#125;
156
+ if (existingId !== undefined) {
157
+ return { __ref: existingId };
158
+ }
121
159
  const __id = ctx.register(value);
122
- const result: Record&#x3C;string, unknown> = &#123; __type: 'User', __id &#125;;
160
+ const result: Record<string, unknown> = { __type: 'User', __id };
123
161
  result['user_id'] = value.id;
124
162
  result['name'] = value.name;
125
163
  result['metadata'] = value.metadata;
126
164
  return result;
127
- &#125;
128
- ``` Syntax rules:
129
- - Must be inside a JSDoc comment immediately before the field
130
- - Options use object literal syntax: <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@<span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">attr<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">({ key: value })</code>
131
- - Boolean options: <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@<span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">attr<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">({ skip: <span style="--shiki-dark:#79B8FF;--shiki-light:#005CC5">true<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E"> })</code>
132
- - String options: <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@<span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">attr<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">({ rename: <span style="--shiki-dark:#9ECBFF;--shiki-light:#032F62">"newName"<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E"> })</code>
133
- - Multiple attributes can be on separate lines or combined
134
- Common field attributes by macro:
135
- | Macro | Attribute | Options |
136
- | --- | --- | --- |
137
- | Debug | @debug | skip, rename |
138
- | Clone | @clone | skip, clone_with |
139
- | Serialize/Deserialize | @serde | skip, rename, flatten, default |
140
- | Hash | @hash | skip |
141
- | PartialEq/Ord | @eq, @ord | skip |
142
- ## How It Works
143
- 1. **Declaration**: You write <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@<span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">derive<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">(MacroName)</code> before a class
144
- 2. **Discovery**: Macroforge finds all derive decorators in your code
145
- 3. **Expansion**: Each named macro receives the class AST and generates code
146
- 4. **Injection**: Generated methods/properties are added to the class
147
- ## What Can Be Derived
148
- The derive system works on:
149
- - **Classes**: The primary target for derive macros
150
- - **Interfaces**: Macros generate companion namespace functions
151
- - **Enums**: Macros generate namespace functions for enum values
152
- - **Type aliases**: Both object types and union types are supported
153
- ## Built-in vs Custom Macros
154
- Macroforge comes with built-in macros that work out of the box. You can also create custom macros in Rust and use them via the <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#F97583;--shiki-light:#D73A49">import<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E"> macro</code> statement.
155
- | Type | Import Required | Examples |
156
- | --- | --- | --- |
157
- | Built-in | No | Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize |
158
- | Custom | Yes | Any macro from an external package |
159
- ## Next Steps
160
- - [Explore built-in macros](../../docs/builtin-macros)
161
- - [Create custom macros](../../docs/custom-macros)
165
+ }
166
+ ```
167
+
168
+ Syntax rules:
169
+
170
+ * Must be inside a JSDoc comment immediately before the field
171
+ * Options use object literal syntax: `@attr({ key: value })`
172
+ * Boolean options: `@attr({ skip: true })`
173
+ * String options: `@attr({ rename: "newName" })`
174
+ * Multiple attributes can be on separate lines or combined
175
+
176
+ Common field attributes by macro:
177
+
178
+ | Macro | Attribute | Options |
179
+ | --------------------- | ------------- | -------------------------------------- |
180
+ | Debug | `@debug` | `skip`, `rename` |
181
+ | Clone | `@clone` | `skip`, `clone_with` |
182
+ | Serialize/Deserialize | `@serde` | `skip`, `rename`, `flatten`, `default` |
183
+ | Hash | `@hash` | `skip` |
184
+ | PartialEq/Ord | `@eq`, `@ord` | `skip` |
185
+
186
+ ## How It Works
187
+
188
+ 1. **Declaration**: You write `@derive(MacroName)` before a class
189
+ 2. **Discovery**: Macroforge finds all derive decorators in your code
190
+ 3. **Expansion**: Each named macro receives the class AST and generates code
191
+ 4. **Injection**: Generated methods/properties are added to the class
192
+
193
+ ## What Can Be Derived
194
+
195
+ The derive system works on:
196
+
197
+ * **Classes**: The primary target for derive macros
198
+ * **Interfaces**: Macros generate companion namespace functions
199
+ * **Enums**: Macros generate namespace functions for enum values
200
+ * **Type aliases**: Both object types and union types are supported
201
+
202
+ ## Built-in vs Custom Macros
203
+
204
+ Macroforge comes with built-in macros that work out of the box. You can also create custom macros in Rust and use them via the `import macro` statement.
205
+
206
+ | Type | Import Required | Examples |
207
+ | -------- | --------------- | ------------------------------------------------------------------------------- |
208
+ | Built-in | No | Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize |
209
+ | Custom | Yes | Any macro from an external package |
210
+
211
+ ## Next Steps
212
+
213
+ * [Explore built-in macros](../../docs/builtin-macros)
214
+ * [Create custom macros](../../docs/custom-macros)
@@ -1,58 +1,109 @@
1
1
  # How Macros Work
2
- *Macroforge performs compile-time code generation by parsing your TypeScript, expanding macros, and outputting transformed code. This happens before your code runs, resulting in zero runtime overhead.*
3
- ## Compile-Time Expansion
4
- Unlike runtime solutions that use reflection or proxies, Macroforge expands macros at compile time:
5
- 1. **Parse**: Your TypeScript code is parsed into an AST using SWC
6
- 2. **Find**: Macroforge finds <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@derive</code> decorators and their associated items
7
- 3. **Expand**: Each macro generates new code based on the class structure
8
- 4. **Output**: The transformed TypeScript is written out, ready for normal compilation
9
- <div><div class="flex items-center justify-between gap-2 px-4 py-2 bg-muted rounded-t-lg border border-b-0 border-border">
10
- **Before:**
2
+
3
+ Macroforge performs compile-time code generation by parsing your TypeScript, expanding macros, and outputting transformed code. This happens before your code runs, resulting in zero runtime overhead.
4
+
5
+ ## Compile-Time Expansion
6
+
7
+ Unlike runtime solutions that use reflection or proxies, Macroforge expands macros at compile time:
8
+
9
+ 1. **Parse**: Your TypeScript code is parsed into an AST using SWC
10
+ 2. **Find**: Macroforge finds `@derive` decorators and their associated items
11
+ 3. **Expand**: Each macro generates new code based on the class structure
12
+ 4. **Output**: The transformed TypeScript is written out, ready for normal compilation
13
+
14
+ Before (Your Code)
15
+
11
16
  ```
12
17
  /** @derive(Debug) */
13
- class User &#123;
18
+ class User {
14
19
  name: string;
15
- &#125;
16
- ``` <div class="flex items-center justify-between gap-2 px-4 py-2 bg-muted rounded-t-lg border border-b-0 border-border">
17
- **After:**
20
+ }
18
21
  ```
19
- class User &#123;
22
+
23
+ After (Generated)
24
+
25
+ ```
26
+ class User {
20
27
  name: string;
21
28
 
22
- static toString(value: User): string &#123;
29
+ static toString(value: User): string {
23
30
  return userToString(value);
24
- &#125;
25
- &#125;
31
+ }
32
+ }
26
33
 
27
- export function userToString(value: User): string &#123;
34
+ export function userToString(value: User): string {
28
35
  const parts: string[] = [];
29
36
  parts.push('name: ' + value.name);
30
- return 'User &#123; ' + parts.join(', ') + ' &#125;';
31
- &#125;
32
- ``` ## Zero Runtime Overhead
33
- Because code generation happens at compile time, there's no:
34
- - Runtime reflection or metadata
35
- - Proxy objects or wrappers
36
- - Additional dependencies in your bundle
37
- - Performance cost at runtime
38
- The generated code is plain TypeScript that compiles to efficient JavaScript.
39
- ## Source Mapping
40
- Macroforge tracks the relationship between your source code and the expanded output. This means:
41
- - Errors in generated code point back to your source
42
- - Debugging works correctly
43
- - IDE features like "go to definition" work as expected
44
- > with @derive decorators <div class="font-semibold text-foreground">SWC Parser TypeScript → AST <div class="font-semibold text-foreground">Macro Expansion Engine Finds @derive decorators, runs macros, generates new AST nodes <div class="font-semibold text-foreground">Code Generator AST → TypeScript <div class="font-semibold text-foreground">Expanded TypeScript ready for normal compilation ## Integration Points
45
- Macroforge integrates at two key points:
46
- ### IDE (TypeScript Plugin)
47
- The TypeScript plugin intercepts language server calls to provide:
48
- - Diagnostics that reference your source, not expanded code
49
- - Completions for generated methods
50
- - Hover information showing what macros generate
51
- ### Build (Vite Plugin)
52
- The Vite plugin runs macro expansion during the build process:
53
- - Transforms files before they reach the TypeScript compiler
54
- - Generates type declaration files (.d.ts)
55
- - Produces metadata for debugging
56
- ## Next Steps
57
- - [Learn about the derive system](../docs/concepts/derive-system)
58
- - [Explore the architecture](../docs/concepts/architecture)
37
+ return 'User { ' + parts.join(', ') + ' }';
38
+ }
39
+ ```
40
+
41
+ ## Zero Runtime Overhead
42
+
43
+ Because code generation happens at compile time, there's no:
44
+
45
+ * Runtime reflection or metadata
46
+ * Proxy objects or wrappers
47
+ * Additional dependencies in your bundle
48
+ * Performance cost at runtime
49
+
50
+ The generated code is plain TypeScript that compiles to efficient JavaScript.
51
+
52
+ ## Source Mapping
53
+
54
+ Macroforge tracks the relationship between your source code and the expanded output. This means:
55
+
56
+ * Errors in generated code point back to your source
57
+ * Debugging works correctly
58
+ * IDE features like "go to definition" work as expected
59
+
60
+ Error positioning
61
+
62
+ The TypeScript plugin uses source mapping to show errors at the `@derive` decorator position, not in the generated code.
63
+
64
+ ## Execution Flow
65
+
66
+ Your Source Code
67
+
68
+ with @derive decorators
69
+
70
+ SWC Parser
71
+
72
+ TypeScript → AST
73
+
74
+ Macro Expansion Engine
75
+
76
+ Finds @derive decorators, runs macros, generates new AST nodes
77
+
78
+ Code Generator
79
+
80
+ AST → TypeScript
81
+
82
+ Expanded TypeScript
83
+
84
+ ready for normal compilation
85
+
86
+ ## Integration Points
87
+
88
+ Macroforge integrates at two key points:
89
+
90
+ ### IDE (TypeScript Plugin)
91
+
92
+ The TypeScript plugin intercepts language server calls to provide:
93
+
94
+ * Diagnostics that reference your source, not expanded code
95
+ * Completions for generated methods
96
+ * Hover information showing what macros generate
97
+
98
+ ### Build (Vite Plugin)
99
+
100
+ The Vite plugin runs macro expansion during the build process:
101
+
102
+ * Transforms files before they reach the TypeScript compiler
103
+ * Generates type declaration files (.d.ts)
104
+ * Produces metadata for debugging
105
+
106
+ ## Next Steps
107
+
108
+ * [Learn about the derive system](../docs/concepts/derive-system)
109
+ * [Explore the architecture](../docs/concepts/architecture)
@@ -1,61 +1,83 @@
1
1
  # Custom Macros
2
- *Macroforge allows you to create custom derive macros in Rust. Your macros have full access to the class AST and can generate any TypeScript code.*
3
- ## Overview
4
- Custom macros are written in Rust and compiled to native Node.js addons. The process involves:
5
- 1. Creating a Rust crate with NAPI bindings
6
- 2. Defining macro functions with <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">#[ts_macro_derive]</code>
7
- 3. Using <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">macroforge_ts_quote</code> to generate TypeScript code
8
- 4. Building and publishing as an npm package
9
- ## Quick Example
10
- ```
11
- use&nbsp;macroforge_ts::macros::&#123;ts_macro_derive,&nbsp;body&#125;;
12
- use&nbsp;macroforge_ts::ts_syn::&#123;Data,&nbsp;DeriveInput,&nbsp;MacroforgeError,&nbsp;TsStream,&nbsp;parse_ts_macro_input&#125;;
2
+
3
+ Macroforge allows you to create custom derive macros in Rust. Your macros have full access to the class AST and can generate any TypeScript code.
4
+
5
+ ## Overview
6
+
7
+ Custom macros are written in Rust and compiled to native Node.js addons. The process involves:
8
+
9
+ 1. Creating a Rust crate with NAPI bindings
10
+ 2. Defining macro functions with `#[ts_macro_derive]`
11
+ 3. Using `macroforge_ts_quote` to generate TypeScript code
12
+ 4. Building and publishing as an npm package
13
+
14
+ ## Quick Example
15
+
16
+ Rust
17
+
18
+ ```
19
+ use macroforge_ts::macros::{ts_macro_derive, body};
20
+ use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
13
21
 
14
22
  #[ts_macro_derive(
15
- &nbsp;&nbsp;&nbsp;&nbsp;JSON,
16
- &nbsp;&nbsp;&nbsp;&nbsp;description&nbsp;=&nbsp;"Generates&nbsp;toJSON()&nbsp;returning&nbsp;a&nbsp;plain&nbsp;object"
23
+     JSON,
24
+     description = "Generates toJSON() returning a plain object"
17
25
  )]
18
- pub&nbsp;fn&nbsp;derive_json(mut&nbsp;input:&nbsp;TsStream)&nbsp;->&nbsp;Result&#x3C;TsStream,&nbsp;MacroforgeError>&nbsp;&#123;
19
- &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;input&nbsp;=&nbsp;parse_ts_macro_input!(input&nbsp;as&nbsp;DeriveInput);
20
-
21
- &nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;&#x26;input.data&nbsp;&#123;
22
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data::Class(class)&nbsp;=>&nbsp;&#123;
23
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ok(body!&nbsp;&#123;
24
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;toJSON():&nbsp;Record&#x3C;string,&nbsp;unknown>&nbsp;&#123;
25
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&#123;
26
- &nbsp;&nbsp;&nbsp;&nbsp;&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;class.field_names()&#125;
27
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;,
28
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;/for&#125;
29
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;;
30
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
31
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;)
32
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
33
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_&nbsp;=>&nbsp;Err(MacroforgeError::new(
34
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;input.decorator_span(),
35
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"@derive(JSON)&nbsp;only&nbsp;works&nbsp;on&nbsp;classes",
36
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)),
37
- &nbsp;&nbsp;&nbsp;&nbsp;&#125;
38
- &#125;
39
- ``` ## Using Custom Macros
40
- Once your macro package is published, users can import and use it:
41
- ```
42
- /**&nbsp;import&nbsp;macro&nbsp;&#123;&nbsp;JSON&nbsp;&#125;&nbsp;from&nbsp;"@my/macros";&nbsp;*/
43
-
44
- /**&nbsp;@derive(JSON)&nbsp;*/
45
- class&nbsp;User&nbsp;&#123;
46
- &nbsp;&nbsp;name:&nbsp;string;
47
- &nbsp;&nbsp;age:&nbsp;number;
48
-
49
- &nbsp;&nbsp;constructor(name:&nbsp;string,&nbsp;age:&nbsp;number)&nbsp;&#123;
50
- &nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;
51
- &nbsp;&nbsp;&nbsp;&nbsp;this.age&nbsp;=&nbsp;age;
52
- &nbsp;&nbsp;&#125;
53
- &#125;
54
-
55
- const&nbsp;user&nbsp;=&nbsp;new&nbsp;User("Alice",&nbsp;30);
56
- console.log(user.toJSON());&nbsp;//&nbsp;&#123;&nbsp;name:&nbsp;"Alice",&nbsp;age:&nbsp;30&nbsp;&#125;
57
- ``` > **Note:** The import macro comment tells Macroforge which package provides the macro. ## Getting Started
58
- Follow these guides to create your own macros:
59
- - [Set up a Rust macro crate](../docs/custom-macros/rust-setup)
60
- - [Learn the #[ts_macro_derive] attribute](../docs/custom-macros/ts-macro-derive)
61
- - [Learn the template syntax](../docs/custom-macros/ts-quote)
26
+ pub fn derive_json(mut inputTsStream) -> Result<TsStreamMacroforgeError> {
27
+     let input = parse_ts_macro_input!(input as DeriveInput);
28
+
29
+     match &input.data {
30
+         Data::Class(class) => {
31
+             Ok(body! {
32
+                 toJSON()Record<stringunknown> {
33
+                     return {
34
+                         {#for field in class.field_names()}
35
+                             @{field}: this.@{field},
36
+                         {/for}
37
+                     };
38
+                 }
39
+             })
40
+         }
41
+         _ => Err(MacroforgeError::new(
42
+             input.decorator_span(),
43
+             "@derive(JSON) only works on classes",
44
+         )),
45
+     }
46
+ }
47
+ ```
48
+
49
+ ## Using Custom Macros
50
+
51
+ Once your macro package is published, users can import and use it:
52
+
53
+ TypeScript
54
+
55
+ ```
56
+ /** import macro { JSON } from "@my/macros"; */
57
+
58
+ /** @derive(JSON) */
59
+ class User {
60
+   name: string;
61
+   age: number;
62
+
63
+   constructor(name: string, age: number) {
64
+     this.name = name;
65
+     this.age = age;
66
+   }
67
+ }
68
+
69
+ const user = new User("Alice", 30);
70
+ console.log(user.toJSON()); // { name: "Alice", age: 30 }
71
+ ```
72
+
73
+ Note
74
+
75
+ The `import macro` comment tells Macroforge which package provides the macro.
76
+
77
+ ## Getting Started
78
+
79
+ Follow these guides to create your own macros:
80
+
81
+ * [Set up a Rust macro crate](../docs/custom-macros/rust-setup)
82
+ * [Learn the #\[ts\_macro\_derive\] attribute](../docs/custom-macros/ts-macro-derive)
83
+ * [Learn the template syntax](../docs/custom-macros/ts-quote)