@macroforge/mcp-server 0.1.17

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 (46) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +47 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/tools/docs-loader.d.ts +30 -0
  6. package/dist/tools/docs-loader.d.ts.map +1 -0
  7. package/dist/tools/docs-loader.js +112 -0
  8. package/dist/tools/docs-loader.js.map +1 -0
  9. package/dist/tools/index.d.ts +6 -0
  10. package/dist/tools/index.d.ts.map +1 -0
  11. package/dist/tools/index.js +348 -0
  12. package/dist/tools/index.js.map +1 -0
  13. package/docs/api/api-overview.md +75 -0
  14. package/docs/api/expand-sync.md +121 -0
  15. package/docs/api/native-plugin.md +106 -0
  16. package/docs/api/position-mapper.md +127 -0
  17. package/docs/api/transform-sync.md +98 -0
  18. package/docs/builtin-macros/clone.md +180 -0
  19. package/docs/builtin-macros/debug.md +222 -0
  20. package/docs/builtin-macros/default.md +192 -0
  21. package/docs/builtin-macros/deserialize.md +662 -0
  22. package/docs/builtin-macros/hash.md +205 -0
  23. package/docs/builtin-macros/macros-overview.md +169 -0
  24. package/docs/builtin-macros/ord.md +258 -0
  25. package/docs/builtin-macros/partial-eq.md +306 -0
  26. package/docs/builtin-macros/partial-ord.md +268 -0
  27. package/docs/builtin-macros/serialize.md +321 -0
  28. package/docs/concepts/architecture.md +139 -0
  29. package/docs/concepts/derive-system.md +173 -0
  30. package/docs/concepts/how-macros-work.md +124 -0
  31. package/docs/custom-macros/custom-overview.md +84 -0
  32. package/docs/custom-macros/rust-setup.md +146 -0
  33. package/docs/custom-macros/ts-macro-derive.md +307 -0
  34. package/docs/custom-macros/ts-quote.md +696 -0
  35. package/docs/getting-started/first-macro.md +120 -0
  36. package/docs/getting-started/installation.md +110 -0
  37. package/docs/integration/cli.md +207 -0
  38. package/docs/integration/configuration.md +116 -0
  39. package/docs/integration/integration-overview.md +51 -0
  40. package/docs/integration/typescript-plugin.md +96 -0
  41. package/docs/integration/vite-plugin.md +126 -0
  42. package/docs/language-servers/ls-overview.md +47 -0
  43. package/docs/language-servers/svelte-ls.md +80 -0
  44. package/docs/language-servers/zed-extensions.md +84 -0
  45. package/docs/sections.json +258 -0
  46. package/package.json +48 -0
@@ -0,0 +1,321 @@
1
+ # Serialize
2
+
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
+ ```typescript
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
+ }
20
+
21
+ const user = new User("Alice", 30);
22
+ console.log(JSON.stringify(user));
23
+ // {"name":"Alice","age":30,"createdAt":"2024-01-15T10:30:00.000Z"}
24
+ ```
25
+
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
+ ## Automatic Type Handling
39
+
40
+ Serialize automatically handles various TypeScript types:
41
+
42
+ | `string`, `number`, `boolean`
43
+ | Direct copy
44
+
45
+ | `Date`
46
+ | `.toISOString()`
47
+
48
+ | `T[]`
49
+ | Maps items, calling `toJSON()` if available
50
+
51
+ | `Map<K, V>`
52
+ | `Object.fromEntries()`
53
+
54
+ | `Set<T>`
55
+ | `Array.from()`
56
+
57
+ | Nested objects
58
+ | Calls `toJSON()` if available
59
+
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
+ ## Serde Options
71
+
72
+ Use the `@serde` decorator for fine-grained control over serialization:
73
+
74
+ ### Renaming Fields
75
+
76
+ ```typescript
77
+ /** @derive(Serialize) */
78
+ class User {
79
+ /** @serde({ rename: "user_id" }) */
80
+ id: string;
81
+
82
+ /** @serde({ rename: "full_name" }) */
83
+ name: string;
84
+ }
85
+
86
+ const user = new User();
87
+ user.id = "123";
88
+ user.name = "Alice";
89
+ console.log(JSON.stringify(user));
90
+ // {"user_id":"123","full_name":"Alice"}
91
+ ```
92
+
93
+ ### Skipping Fields
94
+
95
+ ```typescript
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
+ ```
108
+
109
+ <Alert type="tip" title="skip vs skip_serializing">
110
+ Use `skip: true` to exclude from both serialization and deserialization.
111
+ Use `skip_serializing: true` to only skip during serialization.
112
+ </Alert>
113
+
114
+ ### Rename All Fields
115
+
116
+ Apply a naming convention to all fields at the container level:
117
+
118
+ ```typescript
119
+ /** @derive(Serialize) */
120
+ /** @serde({ rename_all: "camelCase" }) */
121
+ class ApiResponse {
122
+ user_name: string; // becomes "userName"
123
+ created_at: Date; // becomes "createdAt"
124
+ is_active: boolean; // becomes "isActive"
125
+ }
126
+ ```
127
+
128
+ Supported conventions:
129
+
130
+ - `camelCase`
131
+
132
+ - `snake_case`
133
+
134
+ - `PascalCase`
135
+
136
+ - `SCREAMING_SNAKE_CASE`
137
+
138
+ - `kebab-case`
139
+
140
+ ### Flattening Nested Objects
141
+
142
+ ```typescript
143
+ /** @derive(Serialize) */
144
+ class Address {
145
+ city: string;
146
+ zip: string;
147
+ }
148
+
149
+ /** @derive(Serialize) */
150
+ class User {
151
+ name: string;
152
+
153
+ /** @serde({ flatten: true }) */
154
+ address: Address;
155
+ }
156
+
157
+ const user = new User();
158
+ user.name = "Alice";
159
+ user.address = { city: "NYC", zip: "10001" };
160
+ console.log(JSON.stringify(user));
161
+ // {"name":"Alice","city":"NYC","zip":"10001"}
162
+ ```
163
+
164
+ ## All Options
165
+
166
+ ### Container Options (on class/interface)
167
+
168
+ | `rename_all`
169
+ | `string`
170
+ | Apply naming convention to all fields
171
+
172
+ ### Field Options (on properties)
173
+
174
+ | `rename`
175
+ | `string`
176
+ | Use a different JSON key
177
+
178
+ | `skip`
179
+ | `boolean`
180
+ | Exclude from serialization and deserialization
181
+
182
+ | `skip_serializing`
183
+ | `boolean`
184
+ | Exclude from serialization only
185
+
186
+ | `flatten`
187
+ | `boolean`
188
+ | Merge nested object fields into parent
189
+
190
+ ## Interface Support
191
+
192
+ Serialize also works with interfaces. For interfaces, a namespace is generated with a `toJSON` function:
193
+
194
+ ```typescript
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
+ // }
212
+
213
+ const response: ApiResponse = {
214
+ status: 200,
215
+ message: "OK",
216
+ timestamp: new Date()
217
+ };
218
+
219
+ console.log(JSON.stringify(ApiResponse.toJSON(response)));
220
+ // {"status":200,"message":"OK","timestamp":"2024-01-15T10:30:00.000Z"}
221
+ ```
222
+
223
+ ## Enum Support
224
+
225
+ Serialize also works with enums. The `toJSON` function returns the underlying enum value (string or number):
226
+
227
+ ```typescript
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
+ // }
241
+
242
+ console.log(Status.toJSON(Status.Active)); // "active"
243
+ console.log(Status.toJSON(Status.Pending)); // "pending"
244
+ ```
245
+
246
+ Works with numeric enums too:
247
+
248
+ ```typescript
249
+ /** @derive(Serialize) */
250
+ enum Priority {
251
+ Low = 1,
252
+ Medium = 2,
253
+ High = 3,
254
+ }
255
+
256
+ console.log(Priority.toJSON(Priority.High)); // 3
257
+ ```
258
+
259
+ ## Type Alias Support
260
+
261
+ Serialize works with type aliases. For object types, fields are serialized with full type handling:
262
+
263
+ ```typescript
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
+ // }
281
+
282
+ const profile: UserProfile = {
283
+ id: "123",
284
+ name: "Alice",
285
+ createdAt: new Date("2024-01-15")
286
+ };
287
+
288
+ console.log(JSON.stringify(UserProfile.toJSON(profile)));
289
+ // {"id":"123","name":"Alice","createdAt":"2024-01-15T00:00:00.000Z"}
290
+ ```
291
+
292
+ For union types, the value is returned directly:
293
+
294
+ ```typescript
295
+ /** @derive(Serialize) */
296
+ type ApiStatus = "loading" | "success" | "error";
297
+
298
+ console.log(ApiStatus.toJSON("success")); // "success"
299
+ ```
300
+
301
+ ## Combining with Deserialize
302
+
303
+ Use both Serialize and Deserialize for complete JSON round-trip support:
304
+
305
+ ```typescript
306
+ /** @derive(Serialize, Deserialize) */
307
+ class User {
308
+ name: string;
309
+ createdAt: Date;
310
+ }
311
+
312
+ // Serialize
313
+ const user = new User();
314
+ user.name = "Alice";
315
+ user.createdAt = new Date();
316
+ const json = JSON.stringify(user);
317
+
318
+ // Deserialize
319
+ const parsed = User.fromJSON(JSON.parse(json));
320
+ console.log(parsed.createdAt instanceof Date); // true
321
+ ```
@@ -0,0 +1,139 @@
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
+ ```text
8
+ ┌─────────────────────────────────────────────────────────┐
9
+ │ Node.js / Vite │
10
+ ├─────────────────────────────────────────────────────────┤
11
+ │ NAPI-RS Bindings │
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
+ ```
22
+
23
+ ## Core Components
24
+
25
+ ### SWC Core
26
+
27
+ The foundation layer provides:
28
+
29
+ - Fast TypeScript/JavaScript parsing
30
+
31
+ - AST representation
32
+
33
+ - Code generation (AST → source code)
34
+
35
+ ### ts_syn
36
+
37
+ A Rust crate that provides:
38
+
39
+ - TypeScript-specific AST types
40
+
41
+ - Parsing utilities for macro input
42
+
43
+ - Derive input structures (class fields, decorators, etc.)
44
+
45
+ ### ts_quote
46
+
47
+ Template-based code generation similar to Rust's `quote!`:
48
+
49
+ - `ts_template!` - Generate TypeScript code from templates
50
+
51
+ - `body!` - Generate class body members
52
+
53
+ - Control flow: `{"{#for}"}`, `{"{#if}"}`, `{"{$let}"}`
54
+
55
+ ### ts_macro_derive
56
+
57
+ The procedural macro attribute for defining derive macros:
58
+
59
+ - `#[ts_macro_derive(Name)]` attribute
60
+
61
+ - Automatic registration with the macro system
62
+
63
+ - Error handling and span tracking
64
+
65
+ ### NAPI-RS Bindings
66
+
67
+ Bridges Rust and Node.js:
68
+
69
+ - Exposes `expandSync`, `transformSync`, etc.
70
+
71
+ - Provides the `NativePlugin` class for caching
72
+
73
+ - Handles data marshaling between Rust and JavaScript
74
+
75
+ ## Data Flow
76
+
77
+ ```text
78
+ 1. Source Code (TypeScript with @derive)
79
+
80
+
81
+ 2. NAPI-RS receives JavaScript string
82
+
83
+
84
+ 3. SWC parses to AST
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
+ ```
104
+
105
+ ## Performance Characteristics
106
+
107
+ - **Thread-safe**: Each expansion runs in an isolated thread with a 32MB stack
108
+
109
+ - **Caching**: `NativePlugin` caches results by file version
110
+
111
+ - **Binary search**: Position mapping uses O(log n) lookups
112
+
113
+ - **Zero-copy**: SWC's arena allocator minimizes allocations
114
+
115
+ ## Re-exported Crates
116
+
117
+ For custom macro development, `macroforge_ts` re-exports everything you need:
118
+
119
+ ```rust
120
+ // All available via macroforge_ts::*
121
+ pub extern crate ts_syn; // AST types, parsing
122
+ pub extern crate ts_quote; // Code generation templates
123
+ pub extern crate ts_macro_derive; // #[ts_macro_derive] attribute
124
+ pub extern crate inventory; // Macro registration
125
+ pub extern crate serde_json; // Serialization
126
+ pub extern crate napi; // Node.js bindings
127
+ pub extern crate napi_derive; // NAPI proc-macros
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;
133
+ ```
134
+
135
+ ## Next Steps
136
+
137
+ - [Write custom macros]({base}/docs/custom-macros)
138
+
139
+ - [Explore the API reference]({base}/docs/api)
@@ -0,0 +1,173 @@
1
+ # The Derive System
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
+ ```typescript
14
+ /** @derive(MacroName) */
15
+ class MyClass { }
16
+
17
+ /** @derive(Debug, Clone, PartialEq) */
18
+ class AnotherClass { }
19
+ ```
20
+
21
+ Syntax rules:
22
+
23
+ - Must be inside a JSDoc comment (`/** */`)
24
+
25
+ - Must appear immediately before the class/interface declaration
26
+
27
+ - Multiple macros can be comma-separated: `@derive(A, B, C)`
28
+
29
+ - Multiple `@derive` statements can be stacked
30
+
31
+ ```typescript
32
+ // Single derive with multiple macros
33
+ /** @derive(Debug, Clone) */
34
+ class User { }
35
+
36
+ // Multiple derive statements (equivalent)
37
+ /** @derive(Debug) */
38
+ /** @derive(Clone) */
39
+ class User { }
40
+ ```
41
+
42
+ ### The import macro Statement
43
+
44
+ To use macros from external packages, you must declare them with `import macro`:
45
+
46
+ ```typescript
47
+ /** import macro { MacroName } from "package-name"; */
48
+ ```
49
+
50
+ Syntax rules:
51
+
52
+ - Must be inside a JSDoc comment (`/** */`)
53
+
54
+ - Can appear anywhere in the file (typically at the top)
55
+
56
+ - Multiple macros can be imported: `import macro &#123; A, B &#125; from "pkg";`
57
+
58
+ - Multiple import statements can be used for different packages
59
+
60
+ ```typescript
61
+ /** import macro { JSON, Validate } from "@my/macros"; */
62
+ /** import macro { Builder } from "@other/macros"; */
63
+
64
+ /** @derive(JSON, Validate, Builder) */
65
+ class User {
66
+ name: string;
67
+ email: string;
68
+ }
69
+ ```
70
+
71
+ >
72
+ > Built-in macros (Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize) do not require an import statement.
73
+
74
+ ### Field Attributes
75
+
76
+ Macros can define field-level attributes to customize behavior per field:
77
+
78
+ ```typescript
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
+ ```
101
+
102
+ Syntax rules:
103
+
104
+ - Must be inside a JSDoc comment immediately before the field
105
+
106
+ - Options use object literal syntax: `@attr(&#123; key: value &#125;)`
107
+
108
+ - Boolean options: `@attr(&#123; skip: true &#125;)`
109
+
110
+ - String options: `@attr(&#123; rename: "newName" &#125;)`
111
+
112
+ - Multiple attributes can be on separate lines or combined
113
+
114
+ Common field attributes by macro:
115
+
116
+ | Debug
117
+ | `@debug`
118
+ | `skip`, `rename`
119
+
120
+ | Clone
121
+ | `@clone`
122
+ | `skip`, `clone_with`
123
+
124
+ | Serialize/Deserialize
125
+ | `@serde`
126
+ | `skip`, `rename`, `flatten`, `default`
127
+
128
+ | Hash
129
+ | `@hash`
130
+ | `skip`
131
+
132
+ | PartialEq/Ord
133
+ | `@eq`, `@ord`
134
+ | `skip`
135
+
136
+ ## How It Works
137
+
138
+ 1. **Declaration**: You write `@derive(MacroName)` before a class
139
+
140
+ 2. **Discovery**: Macroforge finds all derive decorators in your code
141
+
142
+ 3. **Expansion**: Each named macro receives the class AST and generates code
143
+
144
+ 4. **Injection**: Generated methods/properties are added to the class
145
+
146
+ ## What Can Be Derived
147
+
148
+ The derive system works on:
149
+
150
+ - **Classes**: The primary target for derive macros
151
+
152
+ - **Interfaces**: Some macros can generate companion functions
153
+
154
+ > **Warning:**
155
+ > Enums are not currently supported by the derive system.
156
+
157
+ ## Built-in vs Custom Macros
158
+
159
+ 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.
160
+
161
+ | Built-in
162
+ | No
163
+ | Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize
164
+
165
+ | Custom
166
+ | Yes
167
+ | Any macro from an external package
168
+
169
+ ## Next Steps
170
+
171
+ - [Explore built-in macros]({base}/docs/builtin-macros)
172
+
173
+ - [Create custom macros]({base}/docs/custom-macros)