@macroforge/mcp-server 0.1.39 → 0.1.42

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.
@@ -3,122 +3,122 @@
3
3
  ## Overview
4
4
  | Macro | Generates | Description |
5
5
  | --- | --- | --- |
6
- | [`Debug`](../docs/builtin-macros/debug) | `toString(): string` | Human-readable string representation |
7
- | [`Clone`](../docs/builtin-macros/clone) | `clone(): T` | Creates a deep copy of the object |
8
- | [`Default`](../docs/builtin-macros/default) | `static default(): T` | Creates an instance with default values |
9
- | [`Hash`](../docs/builtin-macros/hash) | `hashCode(): number` | Generates a hash code for the object |
10
- | [`PartialEq`](../docs/builtin-macros/partial-eq) | `equals(other: T): boolean` | Value equality comparison |
11
- | [`Ord`](../docs/builtin-macros/ord) | `compare(other: T): number` | Total ordering comparison (-1, 0, 1) |
12
- | [`PartialOrd`](../docs/builtin-macros/partial-ord) | `partialCompare(other: T): number | null` | Partial ordering comparison |
13
- | [`Serialize`](../docs/builtin-macros/serialize) | `toJSON(): Record<string, unknown>` | JSON serialization with type handling |
14
- | [`Deserialize`](../docs/builtin-macros/deserialize) | `static fromJSON(data: unknown): T` | JSON deserialization with validation |
6
+ | [Debug](../docs/builtin-macros/debug) | toString(): string | Human-readable string representation |
7
+ | [Clone](../docs/builtin-macros/clone) | clone(): T | Creates a deep copy of the object |
8
+ | [Default](../docs/builtin-macros/default) | static default(): T | Creates an instance with default values |
9
+ | [Hash](../docs/builtin-macros/hash) | hashCode(): number | Generates a hash code for the object |
10
+ | [PartialEq](../docs/builtin-macros/partial-eq) | equals(other: T): boolean | Value equality comparison |
11
+ | [Ord](../docs/builtin-macros/ord) | compare(other: T): number | Total ordering comparison (-1, 0, 1) |
12
+ | [PartialOrd](../docs/builtin-macros/partial-ord) | partialCompare(other: T): number | null | Partial ordering comparison |
13
+ | [Serialize](../docs/builtin-macros/serialize) | toJSON(): Record<string, unknown> | JSON serialization with type handling |
14
+ | [Deserialize](../docs/builtin-macros/deserialize) | static fromJSON(data: unknown): T | JSON deserialization with validation |
15
15
  ## Using Built-in Macros
16
- Built-in macros don't require imports. Just use them with `@derive`:
16
+ Built-in macros don't require imports. Just use them with <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">@derive</code>:
17
17
  ```
18
- /** @derive(Debug, Clone, PartialEq) */
19
- class User &#123;
20
- name: string;
21
- age: number;
18
+ /**&nbsp;@derive(Debug,&nbsp;Clone,&nbsp;PartialEq)&nbsp;*/
19
+ class&nbsp;User&nbsp;&#123;
20
+ &nbsp;&nbsp;name:&nbsp;string;
21
+ &nbsp;&nbsp;age:&nbsp;number;
22
22
 
23
- constructor(name: string, age: number) &#123;
24
- this.name = name;
25
- this.age = age;
26
- &#125;
23
+ &nbsp;&nbsp;constructor(name:&nbsp;string,&nbsp;age:&nbsp;number)&nbsp;&#123;
24
+ &nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;
25
+ &nbsp;&nbsp;&nbsp;&nbsp;this.age&nbsp;=&nbsp;age;
26
+ &nbsp;&nbsp;&#125;
27
27
  &#125;
28
28
  ``` ## Interface Support
29
- All built-in macros work with interfaces. For interfaces, methods are generated as functions in a namespace with the same name, using `self` as the first parameter:
29
+ All built-in macros work with interfaces. For interfaces, methods are generated as functions in a namespace with the same name, using <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">self</code> as the first parameter:
30
30
  ```
31
- /** @derive(Debug, Clone, PartialEq) */
32
- interface Point &#123;
33
- x: number;
34
- y: number;
31
+ /**&nbsp;@derive(Debug,&nbsp;Clone,&nbsp;PartialEq)&nbsp;*/
32
+ interface&nbsp;Point&nbsp;&#123;
33
+ &nbsp;&nbsp;x:&nbsp;number;
34
+ &nbsp;&nbsp;y:&nbsp;number;
35
35
  &#125;
36
36
 
37
- // Generated namespace:
38
- // namespace Point &#123;
39
- // export function toString(self: Point): string &#123; ... &#125;
40
- // export function clone(self: Point): Point &#123; ... &#125;
41
- // export function equals(self: Point, other: Point): boolean &#123; ... &#125;
42
- // export function hashCode(self: Point): number &#123; ... &#125;
43
- // &#125;
37
+ //&nbsp;Generated&nbsp;namespace:
38
+ //&nbsp;namespace&nbsp;Point&nbsp;&#123;
39
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;toString(self:&nbsp;Point):&nbsp;string&nbsp;&#123;&nbsp;...&nbsp;&#125;
40
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;clone(self:&nbsp;Point):&nbsp;Point&nbsp;&#123;&nbsp;...&nbsp;&#125;
41
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;equals(self:&nbsp;Point,&nbsp;other:&nbsp;Point):&nbsp;boolean&nbsp;&#123;&nbsp;...&nbsp;&#125;
42
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;hashCode(self:&nbsp;Point):&nbsp;number&nbsp;&#123;&nbsp;...&nbsp;&#125;
43
+ //&nbsp;&#125;
44
44
 
45
- const point: Point = &#123; x: 10, y: 20 &#125;;
45
+ const&nbsp;point:&nbsp;Point&nbsp;=&nbsp;&#123;&nbsp;x:&nbsp;10,&nbsp;y:&nbsp;20&nbsp;&#125;;
46
46
 
47
- // Use the namespace functions
48
- console.log(Point.toString(point)); // "Point &#123; x: 10, y: 20 &#125;"
49
- const copy = Point.clone(point); // &#123; x: 10, y: 20 &#125;
50
- console.log(Point.equals(point, copy)); // true
47
+ //&nbsp;Use&nbsp;the&nbsp;namespace&nbsp;functions
48
+ console.log(Point.toString(point));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;"Point&nbsp;&#123;&nbsp;x:&nbsp;10,&nbsp;y:&nbsp;20&nbsp;&#125;"
49
+ const&nbsp;copy&nbsp;=&nbsp;Point.clone(point);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&#123;&nbsp;x:&nbsp;10,&nbsp;y:&nbsp;20&nbsp;&#125;
50
+ console.log(Point.equals(point,&nbsp;copy));&nbsp;//&nbsp;true
51
51
  ``` ## Enum Support
52
52
  All built-in macros work with enums. For enums, methods are generated as functions in a namespace with the same name:
53
53
  ```
54
- /** @derive(Debug, Clone, PartialEq, Serialize, Deserialize) */
55
- enum Status &#123;
56
- Active = "active",
57
- Inactive = "inactive",
58
- Pending = "pending",
54
+ /**&nbsp;@derive(Debug,&nbsp;Clone,&nbsp;PartialEq,&nbsp;Serialize,&nbsp;Deserialize)&nbsp;*/
55
+ enum&nbsp;Status&nbsp;&#123;
56
+ &nbsp;&nbsp;Active&nbsp;=&nbsp;"active",
57
+ &nbsp;&nbsp;Inactive&nbsp;=&nbsp;"inactive",
58
+ &nbsp;&nbsp;Pending&nbsp;=&nbsp;"pending",
59
59
  &#125;
60
60
 
61
- // Generated namespace:
62
- // namespace Status &#123;
63
- // export function toString(value: Status): string &#123; ... &#125;
64
- // export function clone(value: Status): Status &#123; ... &#125;
65
- // export function equals(a: Status, b: Status): boolean &#123; ... &#125;
66
- // export function hashCode(value: Status): number &#123; ... &#125;
67
- // export function toJSON(value: Status): string | number &#123; ... &#125;
68
- // export function fromJSON(data: unknown): Status &#123; ... &#125;
69
- // &#125;
61
+ //&nbsp;Generated&nbsp;namespace:
62
+ //&nbsp;namespace&nbsp;Status&nbsp;&#123;
63
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;toString(value:&nbsp;Status):&nbsp;string&nbsp;&#123;&nbsp;...&nbsp;&#125;
64
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;clone(value:&nbsp;Status):&nbsp;Status&nbsp;&#123;&nbsp;...&nbsp;&#125;
65
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;equals(a:&nbsp;Status,&nbsp;b:&nbsp;Status):&nbsp;boolean&nbsp;&#123;&nbsp;...&nbsp;&#125;
66
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;hashCode(value:&nbsp;Status):&nbsp;number&nbsp;&#123;&nbsp;...&nbsp;&#125;
67
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;toJSON(value:&nbsp;Status):&nbsp;string&nbsp;|&nbsp;number&nbsp;&#123;&nbsp;...&nbsp;&#125;
68
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;fromJSON(data:&nbsp;unknown):&nbsp;Status&nbsp;&#123;&nbsp;...&nbsp;&#125;
69
+ //&nbsp;&#125;
70
70
 
71
- // Use the namespace functions
72
- console.log(Status.toString(Status.Active)); // "Status.Active"
73
- console.log(Status.equals(Status.Active, Status.Active)); // true
74
- const json = Status.toJSON(Status.Pending); // "pending"
75
- const parsed = Status.fromJSON("active"); // Status.Active
71
+ //&nbsp;Use&nbsp;the&nbsp;namespace&nbsp;functions
72
+ console.log(Status.toString(Status.Active));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;"Status.Active"
73
+ console.log(Status.equals(Status.Active,&nbsp;Status.Active));&nbsp;//&nbsp;true
74
+ const&nbsp;json&nbsp;=&nbsp;Status.toJSON(Status.Pending);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;"pending"
75
+ const&nbsp;parsed&nbsp;=&nbsp;Status.fromJSON("active");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Status.Active
76
76
  ``` ## Type Alias Support
77
77
  All built-in macros work with type aliases. For object type aliases, field-aware methods are generated in a namespace:
78
78
  ```
79
- /** @derive(Debug, Clone, PartialEq, Serialize, Deserialize) */
80
- type Point = &#123;
81
- x: number;
82
- y: number;
79
+ /**&nbsp;@derive(Debug,&nbsp;Clone,&nbsp;PartialEq,&nbsp;Serialize,&nbsp;Deserialize)&nbsp;*/
80
+ type&nbsp;Point&nbsp;=&nbsp;&#123;
81
+ &nbsp;&nbsp;x:&nbsp;number;
82
+ &nbsp;&nbsp;y:&nbsp;number;
83
83
  &#125;;
84
84
 
85
- // Generated namespace:
86
- // namespace Point &#123;
87
- // export function toString(value: Point): string &#123; ... &#125;
88
- // export function clone(value: Point): Point &#123; ... &#125;
89
- // export function equals(a: Point, b: Point): boolean &#123; ... &#125;
90
- // export function hashCode(value: Point): number &#123; ... &#125;
91
- // export function toJSON(value: Point): Record&#x3C;string, unknown> &#123; ... &#125;
92
- // export function fromJSON(data: unknown): Point &#123; ... &#125;
93
- // &#125;
85
+ //&nbsp;Generated&nbsp;namespace:
86
+ //&nbsp;namespace&nbsp;Point&nbsp;&#123;
87
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;toString(value:&nbsp;Point):&nbsp;string&nbsp;&#123;&nbsp;...&nbsp;&#125;
88
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;clone(value:&nbsp;Point):&nbsp;Point&nbsp;&#123;&nbsp;...&nbsp;&#125;
89
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;equals(a:&nbsp;Point,&nbsp;b:&nbsp;Point):&nbsp;boolean&nbsp;&#123;&nbsp;...&nbsp;&#125;
90
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;hashCode(value:&nbsp;Point):&nbsp;number&nbsp;&#123;&nbsp;...&nbsp;&#125;
91
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;toJSON(value:&nbsp;Point):&nbsp;Record&#x3C;string,&nbsp;unknown>&nbsp;&#123;&nbsp;...&nbsp;&#125;
92
+ //&nbsp;&nbsp;&nbsp;export&nbsp;function&nbsp;fromJSON(data:&nbsp;unknown):&nbsp;Point&nbsp;&#123;&nbsp;...&nbsp;&#125;
93
+ //&nbsp;&#125;
94
94
 
95
- const point: Point = &#123; x: 10, y: 20 &#125;;
96
- console.log(Point.toString(point)); // "Point &#123; x: 10, y: 20 &#125;"
97
- const copy = Point.clone(point); // &#123; x: 10, y: 20 &#125;
98
- console.log(Point.equals(point, copy)); // true
95
+ const&nbsp;point:&nbsp;Point&nbsp;=&nbsp;&#123;&nbsp;x:&nbsp;10,&nbsp;y:&nbsp;20&nbsp;&#125;;
96
+ console.log(Point.toString(point));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;"Point&nbsp;&#123;&nbsp;x:&nbsp;10,&nbsp;y:&nbsp;20&nbsp;&#125;"
97
+ const&nbsp;copy&nbsp;=&nbsp;Point.clone(point);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&#123;&nbsp;x:&nbsp;10,&nbsp;y:&nbsp;20&nbsp;&#125;
98
+ console.log(Point.equals(point,&nbsp;copy));&nbsp;//&nbsp;true
99
99
  ``` Union type aliases also work, using JSON-based implementations:
100
100
  ```
101
- /** @derive(Debug, PartialEq) */
102
- type ApiStatus = "loading" | "success" | "error";
101
+ /**&nbsp;@derive(Debug,&nbsp;PartialEq)&nbsp;*/
102
+ type&nbsp;ApiStatus&nbsp;=&nbsp;"loading"&nbsp;|&nbsp;"success"&nbsp;|&nbsp;"error";
103
103
 
104
- const status: ApiStatus = "success";
105
- console.log(ApiStatus.toString(status)); // "ApiStatus(\\"success\\")"
106
- console.log(ApiStatus.equals("success", "success")); // true
104
+ const&nbsp;status:&nbsp;ApiStatus&nbsp;=&nbsp;"success";
105
+ console.log(ApiStatus.toString(status));&nbsp;//&nbsp;"ApiStatus(\\"success\\")"
106
+ console.log(ApiStatus.equals("success",&nbsp;"success"));&nbsp;//&nbsp;true
107
107
  ``` ## Combining Macros
108
108
  All macros can be used together. They don't conflict and each generates independent methods:
109
109
  ```
110
- const user = new User("Alice", 30);
110
+ const&nbsp;user&nbsp;=&nbsp;new&nbsp;User("Alice",&nbsp;30);
111
111
 
112
- // Debug
112
+ //&nbsp;Debug
113
113
  console.log(user.toString());
114
- // "User &#123; name: Alice, age: 30 &#125;"
114
+ //&nbsp;"User&nbsp;&#123;&nbsp;name:&nbsp;Alice,&nbsp;age:&nbsp;30&nbsp;&#125;"
115
115
 
116
- // Clone
117
- const copy = user.clone();
118
- console.log(copy.name); // "Alice"
116
+ //&nbsp;Clone
117
+ const&nbsp;copy&nbsp;=&nbsp;user.clone();
118
+ console.log(copy.name);&nbsp;//&nbsp;"Alice"
119
119
 
120
- // Eq
121
- console.log(user.equals(copy)); // true
120
+ //&nbsp;Eq
121
+ console.log(user.equals(copy));&nbsp;//&nbsp;true
122
122
  ``` ## Detailed Documentation
123
123
  Each macro has its own options and behaviors:
124
124
  - [**Debug**](../docs/builtin-macros/debug) - Customizable field renaming and skipping
@@ -70,32 +70,30 @@ class Temperature {
70
70
  ```
71
71
 
72
72
  ```typescript after
73
- import { Option } from 'macroforge/utils';
74
-
75
73
  class Temperature {
76
74
  value: number | null;
77
75
  unit: string;
78
76
 
79
- static compareTo(a: Temperature, b: Temperature): Option<number> {
77
+ static compareTo(a: Temperature, b: Temperature): number | null {
80
78
  return temperaturePartialCompare(a, b);
81
79
  }
82
80
  }
83
81
 
84
- export function temperaturePartialCompare(a: Temperature, b: Temperature): Option<number> {
85
- if (a === b) return Option.some(0);
82
+ export function temperaturePartialCompare(a: Temperature, b: Temperature): number | null {
83
+ if (a === b) return 0;
86
84
  const cmp0 = (() => {
87
85
  if (typeof (a.value as any)?.compareTo === 'function') {
88
86
  const optResult = (a.value as any).compareTo(b.value);
89
- return Option.isNone(optResult) ? null : optResult.value;
87
+ return optResult === null ? null : optResult;
90
88
  }
91
89
  return a.value === b.value ? 0 : null;
92
90
  })();
93
- if (cmp0 === null) return Option.none();
94
- if (cmp0 !== 0) return Option.some(cmp0);
91
+ if (cmp0 === null) return null;
92
+ if (cmp0 !== 0) return cmp0;
95
93
  const cmp1 = a.unit.localeCompare(b.unit);
96
- if (cmp1 === null) return Option.none();
97
- if (cmp1 !== 0) return Option.some(cmp1);
98
- return Option.some(0);
94
+ if (cmp1 === null) return null;
95
+ if (cmp1 !== 0) return cmp1;
96
+ return 0;
99
97
  }
100
98
  ```
101
99
 
@@ -106,26 +104,26 @@ class Temperature {
106
104
  value: number | null;
107
105
  unit: string;
108
106
 
109
- static compareTo(a: Temperature, b: Temperature): Option<number> {
107
+ static compareTo(a: Temperature, b: Temperature): number | null {
110
108
  return temperaturePartialCompare(a, b);
111
109
  }
112
110
  }
113
111
 
114
- export function temperaturePartialCompare(a: Temperature, b: Temperature): Option<number> {
115
- if (a === b) return Option.some(0);
112
+ export function temperaturePartialCompare(a: Temperature, b: Temperature): number | null {
113
+ if (a === b) return 0;
116
114
  const cmp0 = (() => {
117
115
  if (typeof (a.value as any)?.compareTo === 'function') {
118
116
  const optResult = (a.value as any).compareTo(b.value);
119
- return Option.isNone(optResult) ? null : optResult.value;
117
+ return optResult === null ? null : optResult;
120
118
  }
121
119
  return a.value === b.value ? 0 : null;
122
120
  })();
123
- if (cmp0 === null) return Option.none();
124
- if (cmp0 !== 0) return Option.some(cmp0);
121
+ if (cmp0 === null) return null;
122
+ if (cmp0 !== 0) return cmp0;
125
123
  const cmp1 = a.unit.localeCompare(b.unit);
126
- if (cmp1 === null) return Option.none();
127
- if (cmp1 !== 0) return Option.some(cmp1);
128
- return Option.some(0);
124
+ if (cmp1 === null) return null;
125
+ if (cmp1 !== 0) return cmp1;
126
+ return 0;
129
127
  }
130
128
  ```
131
129
 
@@ -13,37 +13,37 @@
13
13
  - Parsing utilities for macro input
14
14
  - Derive input structures (class fields, decorators, etc.)
15
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}`
16
+ Template-based code generation similar to Rust's <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">quote!</code>:
17
+ - <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">ts_template!</code> - Generate TypeScript code from templates
18
+ - <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">body!</code> - Generate class body members
19
+ - Control flow: <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">{<span style="--shiki-dark:#9ECBFF;--shiki-light:#032F62">"{#for}"<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">}</code>, <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">{<span style="--shiki-dark:#9ECBFF;--shiki-light:#032F62">"{#if}"<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">}</code>, <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">{<span style="--shiki-dark:#9ECBFF;--shiki-light:#032F62">"{$let}"<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">}</code>
20
20
  ### macroforge_ts_macros
21
21
  The procedural macro attribute for defining derive macros:
22
- - `#[ts_macro_derive(Name)]` attribute
22
+ - <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">#[<span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">ts_macro_derive<span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">(Name)]</code> attribute
23
23
  - Automatic registration with the macro system
24
24
  - Error handling and span tracking
25
25
  ### NAPI-RS Bindings
26
26
  Bridges Rust and Node.js:
27
- - Exposes `expandSync`, `transformSync`, etc.
28
- - Provides the `NativePlugin` class for caching
27
+ - Exposes <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">expandSync</code>, <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">transformSync</code>, etc.
28
+ - Provides the <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">NativePlugin</code> class for caching
29
29
  - Handles data marshaling between Rust and JavaScript
30
30
  ## Data Flow
31
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
32
  - **Thread-safe**: Each expansion runs in an isolated thread with a 32MB stack
33
- - **Caching**: `NativePlugin` caches results by file version
33
+ - **Caching**: <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">NativePlugin</code> caches results by file version
34
34
  - **Binary search**: Position mapping uses O(log n) lookups
35
35
  - **Zero-copy**: SWC's arena allocator minimizes allocations
36
36
  ## Re-exported Crates
37
- For custom macro development, `macroforge_ts` re-exports everything you need:
37
+ For custom macro development, <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">macroforge_ts</code> re-exports everything you need:
38
38
  ```
39
- // Convenient re-exports for macro development
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;;
39
+ //&nbsp;Convenient&nbsp;re-exports&nbsp;for&nbsp;macro&nbsp;development
40
+ use&nbsp;macroforge_ts::macros::&#123;ts_macro_derive,&nbsp;body,&nbsp;ts_template,&nbsp;above,&nbsp;below,&nbsp;signature&#125;;
41
+ use&nbsp;macroforge_ts::ts_syn::&#123;Data,&nbsp;DeriveInput,&nbsp;MacroforgeError,&nbsp;TsStream,&nbsp;parse_ts_macro_input&#125;;
42
42
 
43
- // Also available: raw crate access and SWC modules
44
- use macroforge_ts::swc_core;
45
- use macroforge_ts::swc_common;
46
- use macroforge_ts::swc_ecma_ast;
43
+ //&nbsp;Also&nbsp;available:&nbsp;raw&nbsp;crate&nbsp;access&nbsp;and&nbsp;SWC&nbsp;modules
44
+ use&nbsp;macroforge_ts::swc_core;
45
+ use&nbsp;macroforge_ts::swc_common;
46
+ use&nbsp;macroforge_ts::swc_ecma_ast;
47
47
  ``` ## Next Steps
48
48
  - [Write custom macros](../../docs/custom-macros)
49
49
  - [Explore the API reference](../../docs/api)
@@ -1,125 +1,146 @@
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 `@derive`.*
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
3
  ## Syntax Reference
4
4
  Macroforge uses JSDoc comments for all macro annotations. This ensures compatibility with standard TypeScript tooling.
5
5
  ### The @derive Statement
6
- The `@derive` decorator triggers macro expansion on a class or interface:
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
7
  **Source:**
8
8
  ```
9
9
  /** @derive(Debug) */
10
- class MyClass {
11
- value: string;
12
- }
10
+ class MyClass &#123;
11
+ value: string;
12
+ &#125;
13
13
  ``` Syntax rules:
14
- - Must be inside a JSDoc comment (`/** */`)
14
+ - Must be inside a JSDoc comment (<code class="shiki-inline"><span class="line"><span style="--shiki-dark:#6A737D;--shiki-light:#6A737D">/** */</code>)
15
15
  - Must appear immediately before the class/interface declaration
16
- - Multiple macros can be comma-separated: `@derive(A, B, C)`
17
- - Multiple `@derive` statements can be stacked
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
18
  **Source:**
19
19
  ```
20
20
  /** @derive(Debug, Clone) */
21
- class User {
22
- name: string;
23
- email: string;
24
- }
21
+ class User &#123;
22
+ name: string;
23
+ email: string;
24
+ &#125;
25
25
  ``` ### The import macro Statement
26
- To use macros from external packages, you must declare them with `import macro`:
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
27
  ```
28
- /** import macro &#123; MacroName &#125; from "package-name"; */
28
+ /**&nbsp;import&nbsp;macro&nbsp;&#123;&nbsp;MacroName&nbsp;&#125;&nbsp;from&nbsp;"package-name";&nbsp;*/
29
29
  ``` Syntax rules:
30
- - Must be inside a JSDoc comment (`/** */`)
30
+ - Must be inside a JSDoc comment (<code class="shiki-inline"><span class="line"><span style="--shiki-dark:#6A737D;--shiki-light:#6A737D">/** */</code>)
31
31
  - Can appear anywhere in the file (typically at the top)
32
- - Multiple macros can be imported: `import macro { A, B } from "pkg";`
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
33
  - Multiple import statements can be used for different packages
34
34
  ```
35
- /** import macro &#123; JSON, Validate &#125; from "@my/macros"; */
36
- /** import macro &#123; Builder &#125; from "@other/macros"; */
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
37
 
38
- /** @derive(JSON, Validate, Builder) */
39
- class User &#123;
40
- name: string;
41
- email: string;
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
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
- ****Before:**
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:**
46
47
  ```
47
48
  /** @derive(Debug, Serialize) */
48
- class User {
49
- /** @debug({ rename: "userId" }) */
50
- /** @serde({ rename: "user_id" }) */
49
+ class User &#123;
50
+ /** @debug(&#123; rename: "userId" &#125;) */
51
+ /** @serde(&#123; rename: "user_id" &#125;) */
51
52
  id: number;
52
53
 
53
54
  name: string;
54
55
 
55
- /** @debug({ skip: true }) */
56
- /** @serde({ skip: true }) */
56
+ /** @debug(&#123; skip: true &#125;) */
57
+ /** @serde(&#123; skip: true &#125;) */
57
58
  password: string;
58
59
 
59
- /** @serde({ flatten: true }) */
60
- metadata: Record<string, unknown>;
61
- }
62
- ```
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
63
  **After:**
64
64
  ```
65
- import { SerializeContext } from "macroforge/serde";
65
+ import &#123; SerializeContext &#125; from 'macroforge/serde';
66
66
 
67
- class User {
68
-
69
-
70
- id: number;
67
+ class User &#123;
68
+ id: number;
71
69
 
72
- name: string;
70
+ name: string;
73
71
 
74
-
75
-
76
- password: string;
72
+ password: string;
77
73
 
78
-
79
- metadata: Record<string, unknown>;
74
+ metadata: Record&#x3C;string, unknown>;
80
75
 
81
- static toString(value: User): string {
82
- return userToString(value);
83
- }
84
- /** Serializes a value to a JSON string.
76
+ static toString(value: User): string &#123;
77
+ return userToString(value);
78
+ &#125;
79
+ /** Serializes a value to a JSON string.
85
80
  @param value - The value to serialize
86
81
  @returns JSON string representation with cycle detection metadata */
87
82
 
88
- static serialize(value: User): string {
89
- return userSerialize(value);
90
- }
91
- /** @internal Serializes with an existing context for nested/cyclic object graphs.
83
+ static serialize(value: User): string &#123;
84
+ return userSerialize(value);
85
+ &#125;
86
+ /** @internal Serializes with an existing context for nested/cyclic object graphs.
92
87
  @param value - The value to serialize
93
88
  @param ctx - The serialization context */
94
89
 
95
- static serializeWithContext(value: User, ctx: SerializeContext): Record<string, unknown> {
96
- return userSerializeWithContext(value, ctx);
97
- }
98
- }
90
+ static serializeWithContext(value: User, ctx: SerializeContext): Record&#x3C;string, unknown> &#123;
91
+ return userSerializeWithContext(value, ctx);
92
+ &#125;
93
+ &#125;
99
94
 
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(", " )+ " }" ; }
95
+ export function userToString(value: User): string &#123;
96
+ const parts: string[] = [];
97
+ parts.push('userId: ' + value.id);
98
+ parts.push('name: ' + value.name);
99
+ parts.push('metadata: ' + value.metadata);
100
+ return 'User &#123; ' + parts.join(', ') + ' &#125;';
101
+ &#125;
101
102
 
102
103
  /** Serializes a value to a JSON string.
103
104
  @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
+ @returns JSON string representation with cycle detection metadata */ export function userSerialize(
106
+ value: User
107
+ ): string &#123;
108
+ const ctx = SerializeContext.create();
109
+ return JSON.stringify(userSerializeWithContext(value, ctx));
110
+ &#125; /** @internal Serializes with an existing context for nested/cyclic object graphs.
105
111
  @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;}
112
+ @param ctx - The serialization context */
113
+ export function userSerializeWithContext(
114
+ value: User,
115
+ ctx: SerializeContext
116
+ ): Record&#x3C;string, unknown> &#123;
117
+ const existingId = ctx.getId(value);
118
+ if (existingId !== undefined) &#123;
119
+ return &#123; __ref: existingId &#125;;
120
+ &#125;
121
+ const __id = ctx.register(value);
122
+ const result: Record&#x3C;string, unknown> = &#123; __type: 'User', __id &#125;;
123
+ result['user_id'] = value.id;
124
+ result['name'] = value.name;
125
+ result['metadata'] = value.metadata;
126
+ return result;
127
+ &#125;
107
128
  ``` Syntax rules:
108
129
  - Must be inside a JSDoc comment immediately before the field
109
- - Options use object literal syntax: `@attr({ key: value })`
110
- - Boolean options: `@attr({ skip: true })`
111
- - String options: `@attr({ rename: "newName" })`
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>
112
133
  - Multiple attributes can be on separate lines or combined
113
134
  Common field attributes by macro:
114
135
  | Macro | Attribute | Options |
115
136
  | --- | --- | --- |
116
- | Debug | `@debug` | `skip`, `rename` |
117
- | Clone | `@clone` | `skip`, `clone_with` |
118
- | Serialize/Deserialize | `@serde` | `skip`, `rename`, `flatten`, `default` |
119
- | Hash | `@hash` | `skip` |
120
- | PartialEq/Ord | `@eq`, `@ord` | `skip` |
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 |
121
142
  ## How It Works
122
- 1. **Declaration**: You write `@derive(MacroName)` before a class
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
123
144
  2. **Discovery**: Macroforge finds all derive decorators in your code
124
145
  3. **Expansion**: Each named macro receives the class AST and generates code
125
146
  4. **Injection**: Generated methods/properties are added to the class
@@ -130,7 +151,7 @@ export function userToString(value: User): string {const parts: string[]= []; pa
130
151
  - **Enums**: Macros generate namespace functions for enum values
131
152
  - **Type aliases**: Both object types and union types are supported
132
153
  ## Built-in vs Custom Macros
133
- 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.
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.
134
155
  | Type | Import Required | Examples |
135
156
  | --- | --- | --- |
136
157
  | Built-in | No | Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize |