@macroforge/mcp-server 0.1.37 → 0.1.39

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 (43) hide show
  1. package/docs/api/api-overview.md +13 -13
  2. package/docs/api/expand-sync.md +8 -8
  3. package/docs/api/native-plugin.md +15 -15
  4. package/docs/api/position-mapper.md +6 -6
  5. package/docs/api/transform-sync.md +11 -11
  6. package/docs/builtin-macros/clone.md +43 -23
  7. package/docs/builtin-macros/debug.md +50 -18
  8. package/docs/builtin-macros/default.md +79 -28
  9. package/docs/builtin-macros/deserialize/cycleforward-reference-support.md +11 -0
  10. package/docs/builtin-macros/deserialize/example.md +1625 -0
  11. package/docs/builtin-macros/deserialize/overview.md +15 -10
  12. package/docs/builtin-macros/deserialize/union-type-deserialization.md +27 -0
  13. package/docs/builtin-macros/deserialize/validation.md +34 -0
  14. package/docs/builtin-macros/deserialize.md +1608 -23
  15. package/docs/builtin-macros/hash.md +87 -20
  16. package/docs/builtin-macros/macros-overview.md +40 -40
  17. package/docs/builtin-macros/ord.md +56 -31
  18. package/docs/builtin-macros/partial-eq/example.md +526 -0
  19. package/docs/builtin-macros/partial-eq/overview.md +39 -0
  20. package/docs/builtin-macros/partial-eq.md +184 -26
  21. package/docs/builtin-macros/partial-ord.md +68 -30
  22. package/docs/builtin-macros/serialize/example.md +139 -0
  23. package/docs/builtin-macros/serialize/overview.md +32 -0
  24. package/docs/builtin-macros/serialize/type-specific-serialization.md +22 -0
  25. package/docs/builtin-macros/serialize.md +130 -28
  26. package/docs/concepts/architecture.md +2 -2
  27. package/docs/concepts/derive-system.md +25 -39
  28. package/docs/concepts/how-macros-work.md +8 -4
  29. package/docs/custom-macros/custom-overview.md +23 -23
  30. package/docs/custom-macros/rust-setup.md +31 -31
  31. package/docs/custom-macros/ts-macro-derive.md +107 -107
  32. package/docs/custom-macros/ts-quote.md +226 -226
  33. package/docs/getting-started/first-macro.md +38 -28
  34. package/docs/getting-started/installation.md +15 -15
  35. package/docs/integration/cli.md +9 -9
  36. package/docs/integration/configuration.md +16 -16
  37. package/docs/integration/mcp-server.md +6 -6
  38. package/docs/integration/svelte-preprocessor.md +40 -41
  39. package/docs/integration/typescript-plugin.md +13 -12
  40. package/docs/integration/vite-plugin.md +12 -12
  41. package/docs/language-servers/zed.md +1 -1
  42. package/docs/sections.json +88 -2
  43. package/package.json +2 -2
@@ -8,18 +8,10 @@ including circular references.
8
8
 
9
9
  | Type | Generated Code | Description |
10
10
  |------|----------------|-------------|
11
- | Class | `toStringifiedJSON()`, `toObject()`, `__serialize(ctx)` | Instance methods |
12
- | Enum | `toStringifiedJSONEnumName(value)`, `__serializeEnumName` | Standalone functions |
13
- | Interface | `toStringifiedJSONInterfaceName(value)`, etc. | Standalone functions |
14
- | Type Alias | `toStringifiedJSONTypeName(value)`, etc. | Standalone functions |
15
-
16
- ## Configuration
17
-
18
- The `functionNamingStyle` option in `macroforge.json` controls naming:
19
- - `"prefix"` (default): Prefixes with type name (e.g., `myTypeToStringifiedJSON`)
20
- - `"suffix"`: Suffixes with type name (e.g., `toStringifiedJSONMyType`)
21
- - `"generic"`: Uses TypeScript generics (e.g., `toStringifiedJSON<T extends MyType>`)
22
- - `"namespace"`: Legacy namespace wrapping
11
+ | Class | `classNameSerialize(value)` + `static serialize(value)` | Standalone function + static wrapper method |
12
+ | Enum | `enumNameSerialize(value)`, `enumNameSerializeWithContext` | Standalone functions |
13
+ | Interface | `interfaceNameSerialize(value)`, etc. | Standalone functions |
14
+ | Type Alias | `typeNameSerialize(value)`, etc. | Standalone functions |
23
15
 
24
16
  ## Cycle Detection Protocol
25
17
 
@@ -45,11 +37,11 @@ When an object is serialized:
45
37
  |------|------------------------|
46
38
  | Primitives | Direct value |
47
39
  | `Date` | `toISOString()` |
48
- | Arrays | For primitive-like element types, pass through; for `Date`/`Date | null`, map to ISO strings; otherwise map and call `__serialize(ctx)` when available |
49
- | `Map<K,V>` | For primitive-like values, `Object.fromEntries(map.entries())`; for `Date`/`Date | null`, convert to ISO strings; otherwise call `__serialize(ctx)` per value when available |
40
+ | Arrays | For primitive-like element types, pass through; for `Date`/`Date | null`, map to ISO strings; otherwise map and call `SerializeWithContext(ctx)` when available |
41
+ | `Map<K,V>` | For primitive-like values, `Object.fromEntries(map.entries())`; for `Date`/`Date | null`, convert to ISO strings; otherwise call `SerializeWithContext(ctx)` per value when available |
50
42
  | `Set<T>` | Convert to array; element handling matches `Array<T>` |
51
- | Nullable | Include `null` explicitly; for primitive-like and `Date` unions the generator avoids runtime `__serialize` checks |
52
- | Objects | Call `__serialize(ctx)` if available (to support user-defined implementations) |
43
+ | Nullable | Include `null` explicitly; for primitive-like and `Date` unions the generator avoids runtime `SerializeWithContext` checks |
44
+ | Objects | Call `SerializeWithContext(ctx)` if available (to support user-defined implementations) |
53
45
 
54
46
  Note: the generator specializes some code paths based on the declared TypeScript type to
55
47
  avoid runtime feature detection on primitives and literal unions.
@@ -58,34 +50,144 @@ avoid runtime feature detection on primitives and literal unions.
58
50
 
59
51
  The `@serde` decorator supports:
60
52
 
61
- - `skip` / `skip_serializing` - Exclude field from serialization
53
+ - `skip` / `skipSerializing` - Exclude field from serialization
62
54
  - `rename = "jsonKey"` - Use different JSON property name
63
55
  - `flatten` - Merge nested object's fields into parent
64
56
 
65
57
  ## Example
66
58
 
67
- ```typescript
68
- @derive(Serialize)
59
+ ```typescript before
60
+ /** @derive(Serialize) */
69
61
  class User {
70
62
  id: number;
71
63
 
72
- @serde(rename = "userName")
64
+ /** @serde({ rename: "userName" }) */
73
65
  name: string;
74
66
 
75
- @serde(skip_serializing)
67
+ /** @serde({ skipSerializing: true }) */
76
68
  password: string;
77
69
 
78
- @serde(flatten)
70
+ /** @serde({ flatten: true }) */
79
71
  metadata: UserMetadata;
80
72
  }
73
+ ```
74
+
75
+ ```typescript after
76
+ import { SerializeContext } from 'macroforge/serde';
77
+
78
+ class User {
79
+ id: number;
81
80
 
82
- // Usage:
83
- const user = new User();
84
- const json = user.toStringifiedJSON();
85
- // => '{"__type":"User","__id":1,"id":1,"userName":"Alice",...}'
81
+ name: string;
82
+
83
+ password: string;
84
+
85
+ metadata: UserMetadata;
86
+ /** Serializes a value to a JSON string.
87
+ @param value - The value to serialize
88
+ @returns JSON string representation with cycle detection metadata */
89
+
90
+ static serialize(value: User): string {
91
+ return userSerialize(value);
92
+ }
93
+ /** @internal Serializes with an existing context for nested/cyclic object graphs.
94
+ @param value - The value to serialize
95
+ @param ctx - The serialization context */
96
+
97
+ static serializeWithContext(value: User, ctx: SerializeContext): Record<string, unknown> {
98
+ return userSerializeWithContext(value, ctx);
99
+ }
100
+ }
86
101
 
87
- const obj = user.toObject();
88
- // => { __type: "User", __id: 1, id: 1, userName: "Alice", ... }
102
+ /** Serializes a value to a JSON string.
103
+ @param value - The value to serialize
104
+ @returns JSON string representation with cycle detection metadata */ export function userSerialize(
105
+ value: User
106
+ ): string {
107
+ const ctx = SerializeContext.create();
108
+ return JSON.stringify(userSerializeWithContext(value, ctx));
109
+ } /** @internal Serializes with an existing context for nested/cyclic object graphs.
110
+ @param value - The value to serialize
111
+ @param ctx - The serialization context */
112
+ export function userSerializeWithContext(
113
+ value: User,
114
+ ctx: SerializeContext
115
+ ): Record<string, unknown> {
116
+ const existingId = ctx.getId(value);
117
+ if (existingId !== undefined) {
118
+ return { __ref: existingId };
119
+ }
120
+ const __id = ctx.register(value);
121
+ const result: Record<string, unknown> = { __type: 'User', __id };
122
+ result['id'] = value.id;
123
+ result['userName'] = value.name;
124
+ {
125
+ const __flattened = userMetadataSerializeWithContext(value.metadata, ctx);
126
+ const { __type: _, __id: __, ...rest } = __flattened as any;
127
+ Object.assign(result, rest);
128
+ }
129
+ return result;
130
+ }
131
+ ```
132
+
133
+ Generated output:
134
+
135
+ ```typescript
136
+ import { SerializeContext } from 'macroforge/serde';
137
+
138
+ class User {
139
+ id: number;
140
+
141
+ name: string;
142
+
143
+ password: string;
144
+
145
+ metadata: UserMetadata;
146
+ /** Serializes a value to a JSON string.
147
+ @param value - The value to serialize
148
+ @returns JSON string representation with cycle detection metadata */
149
+
150
+ static serialize(value: User): string {
151
+ return userSerialize(value);
152
+ }
153
+ /** @internal Serializes with an existing context for nested/cyclic object graphs.
154
+ @param value - The value to serialize
155
+ @param ctx - The serialization context */
156
+
157
+ static serializeWithContext(value: User, ctx: SerializeContext): Record<string, unknown> {
158
+ return userSerializeWithContext(value, ctx);
159
+ }
160
+ }
161
+
162
+ /** Serializes a value to a JSON string.
163
+ @param value - The value to serialize
164
+ @returns JSON string representation with cycle detection metadata */ export function userSerialize(
165
+ value: User
166
+ ): string {
167
+ const ctx = SerializeContext.create();
168
+ return JSON.stringify(userSerializeWithContext(value, ctx));
169
+ } /** @internal Serializes with an existing context for nested/cyclic object graphs.
170
+ @param value - The value to serialize
171
+ @param ctx - The serialization context */
172
+ export function userSerializeWithContext(
173
+ value: User,
174
+ ctx: SerializeContext
175
+ ): Record<string, unknown> {
176
+ const existingId = ctx.getId(value);
177
+ if (existingId !== undefined) {
178
+ return { __ref: existingId };
179
+ }
180
+ const __id = ctx.register(value);
181
+ const result: Record<string, unknown> = { __type: 'User', __id };
182
+ result['id'] = value.id;
183
+ result['userName'] = value.name;
184
+ {
185
+ const __flattened = userMetadataSerializeWithContext(value.metadata, ctx);
186
+ const { __type: _, __id: __, ...rest } = __flattened as any;
187
+ Object.assign(result, rest);
188
+ }
189
+ return result;
190
+ }
89
191
  ```
90
192
 
91
193
  ## Required Import
@@ -37,8 +37,8 @@
37
37
  For custom macro development, `macroforge_ts` re-exports everything you need:
38
38
  ```
39
39
  // Convenient re-exports for macro development
40
- use macroforge_ts::macros::{ts_macro_derive, body, ts_template, above, below, signature};
41
- use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
40
+ use macroforge_ts::macros::&#123;ts_macro_derive, body, ts_template, above, below, signature&#125;;
41
+ use macroforge_ts::ts_syn::&#123;Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input&#125;;
42
42
 
43
43
  // Also available: raw crate access and SWC modules
44
44
  use macroforge_ts::swc_core;
@@ -25,21 +25,21 @@ class User {
25
25
  ``` ### The import macro Statement
26
26
  To use macros from external packages, you must declare them with `import macro`:
27
27
  ```
28
- /** import macro { MacroName } from "package-name"; */
28
+ /** import macro &#123; MacroName &#125; from "package-name"; */
29
29
  ``` Syntax rules:
30
30
  - Must be inside a JSDoc comment (`/** */`)
31
31
  - Can appear anywhere in the file (typically at the top)
32
32
  - Multiple macros can be imported: `import macro { A, B } from "pkg";`
33
33
  - Multiple import statements can be used for different packages
34
34
  ```
35
- /** import macro { JSON, Validate } from "@my/macros"; */
36
- /** import macro { Builder } from "@other/macros"; */
35
+ /** import macro &#123; JSON, Validate &#125; from "@my/macros"; */
36
+ /** import macro &#123; Builder &#125; from "@other/macros"; */
37
37
 
38
38
  /** @derive(JSON, Validate, Builder) */
39
- class User {
39
+ class User &#123;
40
40
  name: string;
41
41
  email: string;
42
- }
42
+ &#125;
43
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
44
  Macros can define field-level attributes to customize behavior per field:
45
45
  ****Before:**
@@ -78,46 +78,32 @@ class User {
78
78
 
79
79
  metadata: Record<string, unknown>;
80
80
 
81
- toString(): string {
82
- const parts: string[] = [];
83
- parts.push("userId: " + this.id);
84
- parts.push("name: " + this.name);
85
- parts.push("metadata: " + this.metadata);
86
- return "User { " + parts.join(", ") + " }";
87
- }
88
-
89
- toStringifiedJSON(): string {
90
- const ctx = SerializeContext.create();
91
- return JSON.stringify(this.__serialize(ctx));
81
+ static toString(value: User): string {
82
+ return userToString(value);
92
83
  }
84
+ /** Serializes a value to a JSON string.
85
+ @param value - The value to serialize
86
+ @returns JSON string representation with cycle detection metadata */
93
87
 
94
- toObject(): Record<string, unknown> {
95
- const ctx = SerializeContext.create();
96
- return this.__serialize(ctx);
88
+ static serialize(value: User): string {
89
+ return userSerialize(value);
97
90
  }
91
+ /** @internal Serializes with an existing context for nested/cyclic object graphs.
92
+ @param value - The value to serialize
93
+ @param ctx - The serialization context */
98
94
 
99
- __serialize(ctx: SerializeContext): Record<string, unknown> {
100
- const existingId = ctx.getId(this);
101
- if (existingId !== undefined) {
102
- return {
103
- __ref: existingId
104
- };
105
- }
106
- const __id = ctx.register(this);
107
- const result: Record<string, unknown> = {
108
- __type: "User",
109
- __id
110
- };
111
- result["user_id"] = this.id;
112
- result["name"] = this.name;
113
- {
114
- const __flattened = record < string, unknown;
115
- const { __type: _, __id: __, ...rest } = __flattened as any;
116
- Object.assign(result, rest);
117
- }
118
- return result;
95
+ static serializeWithContext(value: User, ctx: SerializeContext): Record<string, unknown> {
96
+ return userSerializeWithContext(value, ctx);
119
97
  }
120
98
  }
99
+
100
+ export function userToString(value: User): string {const parts: string[]= []; parts.push("userId: " + value.id); parts.push("name: " + value.name); parts.push("metadata: " + value.metadata); return "User { " + parts.join(", " )+ " }" ; }
101
+
102
+ /** Serializes a value to a JSON string.
103
+ @param value - The value to serialize
104
+ @returns JSON string representation with cycle detection metadata */export function userSerialize(value: User): string {const ctx = SerializeContext.create(); return JSON.stringify(userSerializeWithContext(value, ctx));}/** @internal Serializes with an existing context for nested/cyclic object graphs.
105
+ @param value - The value to serialize
106
+ @param ctx - The serialization context */export function userSerializeWithContext(value: User, ctx: SerializeContext): Record<string, unknown>{const existingId = ctx.getId(value); if(existingId!== undefined){return {__ref: existingId};}const __id = ctx.register(value); const result: Record<string, unknown>= {__type: "User" , __id,}; result["user_id" ]= value.id; result["name" ]= value.name; {const __flattened = record<string, unknown>SerializeWithContext(value.metadata, ctx); const {__type: _, __id: __,...rest}= __flattened as any; Object.assign(result, rest);}return result;}
121
107
  ``` Syntax rules:
122
108
  - Must be inside a JSDoc comment immediately before the field
123
109
  - Options use object literal syntax: `@attr({ key: value })`
@@ -18,12 +18,16 @@ class User {
18
18
  class User {
19
19
  name: string;
20
20
 
21
- toString(): string {
22
- const parts: string[] = [];
23
- parts.push('name: ' + this.name);
24
- return 'User { ' + parts.join(', ') + ' }';
21
+ static toString(value: User): string {
22
+ return userToString(value);
25
23
  }
26
24
  }
25
+
26
+ export function userToString(value: User): string {
27
+ const parts: string[] = [];
28
+ parts.push('name: ' + value.name);
29
+ return 'User { ' + parts.join(', ') + ' }';
30
+ }
27
31
  ``` ## Zero Runtime Overhead
28
32
  Because code generation happens at compile time, there's no:
29
33
  - Runtime reflection or metadata
@@ -8,52 +8,52 @@
8
8
  4. Building and publishing as an npm package
9
9
  ## Quick Example
10
10
  ```
11
- use macroforge_ts::macros::{ts_macro_derive, body};
12
- use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
11
+ use macroforge_ts::macros::&#123;ts_macro_derive, body&#125;;
12
+ use macroforge_ts::ts_syn::&#123;Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input&#125;;
13
13
 
14
14
  #[ts_macro_derive(
15
15
  JSON,
16
16
  description = "Generates toJSON() returning a plain object"
17
17
  )]
18
- pub fn derive_json(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
18
+ pub fn derive_json(mut input: TsStream) -> Result&#x3C;TsStream, MacroforgeError> &#123;
19
19
  let input = parse_ts_macro_input!(input as DeriveInput);
20
20
 
21
- match &input.data {
22
- Data::Class(class) => {
23
- Ok(body! {
24
- toJSON(): Record<string, unknown> {
25
- return {
26
- {#for field in class.field_names()}
27
- @{field}: this.@{field},
28
- {/for}
29
- };
30
- }
31
- })
32
- }
21
+ match &#x26;input.data &#123;
22
+ Data::Class(class) => &#123;
23
+ Ok(body! &#123;
24
+ toJSON(): Record&#x3C;string, unknown> &#123;
25
+ return &#123;
26
+ &#123;#for field in class.field_names()&#125;
27
+ @&#123;field&#125;: this.@&#123;field&#125;,
28
+ &#123;/for&#125;
29
+ &#125;;
30
+ &#125;
31
+ &#125;)
32
+ &#125;
33
33
  _ => Err(MacroforgeError::new(
34
34
  input.decorator_span(),
35
35
  "@derive(JSON) only works on classes",
36
36
  )),
37
- }
38
- }
37
+ &#125;
38
+ &#125;
39
39
  ``` ## Using Custom Macros
40
40
  Once your macro package is published, users can import and use it:
41
41
  ```
42
- /** import macro { JSON } from "@my/macros"; */
42
+ /** import macro &#123; JSON &#125; from "@my/macros"; */
43
43
 
44
44
  /** @derive(JSON) */
45
- class User {
45
+ class User &#123;
46
46
  name: string;
47
47
  age: number;
48
48
 
49
- constructor(name: string, age: number) {
49
+ constructor(name: string, age: number) &#123;
50
50
  this.name = name;
51
51
  this.age = age;
52
- }
53
- }
52
+ &#125;
53
+ &#125;
54
54
 
55
55
  const user = new User("Alice", 30);
56
- console.log(user.toJSON()); // { name: "Alice", age: 30 }
56
+ console.log(user.toJSON()); // &#123; name: "Alice", age: 30 &#125;
57
57
  ``` > **Note:** The import macro comment tells Macroforge which package provides the macro. ## Getting Started
58
58
  Follow these guides to create your own macros:
59
59
  - [Set up a Rust macro crate](../docs/custom-macros/rust-setup)
@@ -25,7 +25,7 @@ crate-type = ["cdylib"]
25
25
 
26
26
  [dependencies]
27
27
  macroforge_ts = "0.1"
28
- napi = { version = "3", features = ["napi8", "compat-mode"] }
28
+ napi = &#123; version = "3", features = ["napi8", "compat-mode"] &#125;
29
29
  napi-derive = "3"
30
30
 
31
31
  [build-dependencies]
@@ -36,67 +36,67 @@ lto = true
36
36
  strip = true
37
37
  ``` ## Create build.rs
38
38
  ```
39
- fn main() {
39
+ fn main() &#123;
40
40
  napi_build::setup();
41
- }
41
+ &#125;
42
42
  ``` ## Create src/lib.rs
43
43
  ```
44
- use macroforge_ts::macros::{ts_macro_derive, body};
45
- use macroforge_ts::ts_syn::{
44
+ use macroforge_ts::macros::&#123;ts_macro_derive, body&#125;;
45
+ use macroforge_ts::ts_syn::&#123;
46
46
  Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input,
47
- };
47
+ &#125;;
48
48
 
49
49
  #[ts_macro_derive(
50
50
  JSON,
51
51
  description = "Generates toJSON() returning a plain object"
52
52
  )]
53
- pub fn derive_json(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
53
+ pub fn derive_json(mut input: TsStream) -> Result&#x3C;TsStream, MacroforgeError> &#123;
54
54
  let input = parse_ts_macro_input!(input as DeriveInput);
55
55
 
56
- match &input.data {
57
- Data::Class(class) => {
58
- Ok(body! {
59
- toJSON(): Record<string, unknown> {
60
- return {
61
- {#for field in class.field_names()}
62
- @{field}: this.@{field},
63
- {/for}
64
- };
65
- }
66
- })
67
- }
56
+ match &#x26;input.data &#123;
57
+ Data::Class(class) => &#123;
58
+ Ok(body! &#123;
59
+ toJSON(): Record&#x3C;string, unknown> &#123;
60
+ return &#123;
61
+ &#123;#for field in class.field_names()&#125;
62
+ @&#123;field&#125;: this.@&#123;field&#125;,
63
+ &#123;/for&#125;
64
+ &#125;;
65
+ &#125;
66
+ &#125;)
67
+ &#125;
68
68
  _ => Err(MacroforgeError::new(
69
69
  input.decorator_span(),
70
70
  "@derive(JSON) only works on classes",
71
71
  )),
72
- }
73
- }
72
+ &#125;
73
+ &#125;
74
74
  ``` ## Create package.json
75
75
  ```
76
- {
76
+ &#123;
77
77
  "name": "@my-org/macros",
78
78
  "version": "0.1.0",
79
79
  "main": "index.js",
80
80
  "types": "index.d.ts",
81
- "napi": {
81
+ "napi": &#123;
82
82
  "name": "my-macros",
83
- "triples": {
83
+ "triples": &#123;
84
84
  "defaults": true
85
- }
86
- },
85
+ &#125;
86
+ &#125;,
87
87
  "files": [
88
88
  "index.js",
89
89
  "index.d.ts",
90
90
  "*.node"
91
91
  ],
92
- "scripts": {
92
+ "scripts": &#123;
93
93
  "build": "napi build --release",
94
94
  "prepublishOnly": "napi build --release"
95
- },
96
- "devDependencies": {
95
+ &#125;,
96
+ "devDependencies": &#123;
97
97
  "@napi-rs/cli": "^3.0.0-alpha.0"
98
- }
99
- }
98
+ &#125;
99
+ &#125;
100
100
  ``` ## Build the Package
101
101
  ```
102
102
  # Build the native addon