@macroforge/mcp-server 0.1.40 → 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 +65 -46
  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 +114 -54
  7. package/docs/api/transform-sync.md +85 -59
  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 +11 -43
  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 +171 -97
  28. package/docs/concepts/how-macros-work.md +89 -37
  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 +799 -519
  57. package/docs/getting-started/first-macro.md +61 -32
  58. package/docs/getting-started/installation.md +109 -66
  59. package/docs/integration/cli.md +212 -103
  60. package/docs/integration/configuration.md +114 -71
  61. package/docs/integration/integration-overview.md +54 -17
  62. package/docs/integration/mcp-server.md +83 -42
  63. package/docs/integration/svelte-preprocessor.md +183 -126
  64. package/docs/integration/typescript-plugin.md +101 -54
  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 -39
  68. package/docs/language-servers/zed.md +81 -45
  69. package/docs/roadmap/roadmap.md +75 -53
  70. package/docs/sections.json +333 -44
  71. package/package.json +27 -28
@@ -70,65 +70,33 @@ class Temperature {
70
70
  ```
71
71
 
72
72
  ```typescript after
73
- import { Option } from 'macroforge/utils';
74
-
75
- class Temperature {
76
- value: number | null;
77
- unit: string;
78
-
79
- static compareTo(a: Temperature, b: Temperature): Option<number> {
80
- return temperaturePartialCompare(a, b);
81
- }
82
- }
83
-
84
- export function temperaturePartialCompare(a: Temperature, b: Temperature): Option<number> {
85
- if (a === b) return Option.some(0);
86
- const cmp0 = (() => {
87
- if (typeof (a.value as any)?.compareTo === 'function') {
88
- const optResult = (a.value as any).compareTo(b.value);
89
- return Option.isNone(optResult) ? null : optResult.value;
90
- }
91
- return a.value === b.value ? 0 : null;
92
- })();
93
- if (cmp0 === null) return Option.none();
94
- if (cmp0 !== 0) return Option.some(cmp0);
95
- 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);
99
- }
100
- ```
101
-
102
- Generated output:
103
-
104
- ```typescript
105
73
  class Temperature {
106
74
  value: number | null;
107
75
  unit: string;
108
76
 
109
- static compareTo(a: Temperature, b: Temperature): Option<number> {
77
+ static compareTo(a: Temperature, b: Temperature): number | null {
110
78
  return temperaturePartialCompare(a, b);
111
79
  }
112
80
  }
113
81
 
114
- export function temperaturePartialCompare(a: Temperature, b: Temperature): Option<number> {
115
- if (a === b) return Option.some(0);
82
+ export function temperaturePartialCompare(a: Temperature, b: Temperature): number | null {
83
+ if (a === b) return 0;
116
84
  const cmp0 = (() => {
117
85
  if (typeof (a.value as any)?.compareTo === 'function') {
118
86
  const optResult = (a.value as any).compareTo(b.value);
119
- return Option.isNone(optResult) ? null : optResult.value;
87
+ return optResult === null ? null : optResult;
120
88
  }
121
89
  return a.value === b.value ? 0 : null;
122
90
  })();
123
- if (cmp0 === null) return Option.none();
124
- if (cmp0 !== 0) return Option.some(cmp0);
91
+ if (cmp0 === null) return null;
92
+ if (cmp0 !== 0) return cmp0;
125
93
  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);
94
+ if (cmp1 === null) return null;
95
+ if (cmp1 !== 0) return cmp1;
96
+ return 0;
129
97
  }
130
98
  ```
131
99
 
132
- ## Required Import
100
+ ## Return Type
133
101
 
134
- The generated code automatically adds an import for `Option` from `macroforge/utils`.
102
+ The generated functions return `number | null` where `null` indicates incomparable values.
@@ -94,7 +94,7 @@ class User {
94
94
  @param value - The value to serialize
95
95
  @param ctx - The serialization context */
96
96
 
97
- static serializeWithContext(value: User, ctx: SerializeContext): Record<string, unknown> {
97
+ static serializeWithContext(value: User, ctx: @{SERIALIZE_CONTEXT}): Record<string, unknown> {
98
98
  return userSerializeWithContext(value, ctx);
99
99
  }
100
100
  }
@@ -104,67 +104,7 @@ class User {
104
104
  @returns JSON string representation with cycle detection metadata */ export function userSerialize(
105
105
  value: User
106
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();
107
+ const ctx = @{SERIALIZE_CONTEXT}.create();
168
108
  return JSON.stringify(userSerializeWithContext(value, ctx));
169
109
  } /** @internal Serializes with an existing context for nested/cyclic object graphs.
170
110
  @param value - The value to serialize
@@ -1,49 +1,126 @@
1
1
  # Architecture
2
- *Macroforge is built as a native Node.js module using Rust and NAPI-RS. It leverages SWC for fast TypeScript parsing and code generation.*
3
- ## Overview
4
- <div class="border border-border bg-card p-4 text-center rounded-t-lg "><div class="font-semibold text-foreground">Node.js / Vite <div class="font-semibold text-foreground">NAPI-RS Bindings <div class="font-semibold text-foreground">Macro Crates <div class="px-3 py-1.5 bg-muted rounded text-sm text-muted-foreground font-mono">macroforge_ts_synmacroforge_ts_quotemacroforge_ts_macros<div class="font-semibold text-foreground">SWC Core <div class="px-3 py-1.5 bg-muted rounded text-sm text-muted-foreground font-mono">TypeScript parsing & codegen ## Core Components
5
- ### SWC Core
6
- The foundation layer provides:
7
- - Fast TypeScript/JavaScript parsing
8
- - AST representation
9
- - Code generation (AST → source code)
10
- ### macroforge_ts_syn
11
- A Rust crate that provides:
12
- - TypeScript-specific AST types
13
- - Parsing utilities for macro input
14
- - Derive input structures (class fields, decorators, etc.)
15
- ### macroforge_ts_quote
16
- Template-based code generation similar to Rust's `quote!`:
17
- - `ts_template!` - Generate TypeScript code from templates
18
- - `body!` - Generate class body members
19
- - Control flow: `{#for}`, `{#if}`, `{$let}`
20
- ### macroforge_ts_macros
21
- The procedural macro attribute for defining derive macros:
22
- - `#[ts_macro_derive(Name)]` attribute
23
- - Automatic registration with the macro system
24
- - Error handling and span tracking
25
- ### NAPI-RS Bindings
26
- Bridges Rust and Node.js:
27
- - Exposes `expandSync`, `transformSync`, etc.
28
- - Provides the `NativePlugin` class for caching
29
- - Handles data marshaling between Rust and JavaScript
30
- ## Data Flow
31
- <div class="w-full max-w-md border border-border rounded-lg bg-card p-4 text-center shadow-sm"><div class="font-semibold text-foreground">1. Source Code TypeScript with @derive <div class="font-semibold text-foreground">2. NAPI-RS receives JavaScript string <div class="font-semibold text-foreground">3. SWC Parser parses to AST <div class="font-semibold text-foreground">4. Macro Expander finds @derive decorators <div class="font-semibold text-foreground">5. For Each Macro extract data, run macro, generate AST nodes <div class="font-semibold text-foreground">6. Merge generated nodes into AST <div class="font-semibold text-foreground">7. SWC Codegen generates source code <div class="font-semibold text-foreground">8. Return to JavaScript with source mapping ## Performance Characteristics
32
- - **Thread-safe**: Each expansion runs in an isolated thread with a 32MB stack
33
- - **Caching**: `NativePlugin` caches results by file version
34
- - **Binary search**: Position mapping uses O(log n) lookups
35
- - **Zero-copy**: SWC's arena allocator minimizes allocations
36
- ## Re-exported Crates
37
- For custom macro development, `macroforge_ts` re-exports everything you need:
38
- ```
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;;
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;
47
- ``` ## Next Steps
48
- - [Write custom macros](../../docs/custom-macros)
49
- - [Explore the API reference](../../docs/api)
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
+ Node.js / Vite
8
+
9
+ NAPI-RS Bindings
10
+
11
+ Macro Crates
12
+
13
+ macroforge\_ts\_syn
14
+
15
+ macroforge\_ts\_quote
16
+
17
+ macroforge\_ts\_macros
18
+
19
+ SWC Core
20
+
21
+ TypeScript parsing & codegen
22
+
23
+ ## Core Components
24
+
25
+ ### SWC Core
26
+
27
+ The foundation layer provides:
28
+
29
+ * Fast TypeScript/JavaScript parsing
30
+ * AST representation
31
+ * Code generation (AST source code)
32
+
33
+ ### macroforge\_ts\_syn
34
+
35
+ A Rust crate that provides:
36
+
37
+ * TypeScript-specific AST types
38
+ * Parsing utilities for macro input
39
+ * Derive input structures (class fields, decorators, etc.)
40
+
41
+ ### macroforge\_ts\_quote
42
+
43
+ Template-based code generation similar to Rust's `quote!`:
44
+
45
+ * `ts_template!` - Generate TypeScript code from templates
46
+ * `body!` - Generate class body members
47
+ * Control flow: `{"{#for}"}`, `{"{#if}"}`, `{"{$let}"}`
48
+
49
+ ### macroforge\_ts\_macros
50
+
51
+ The procedural macro attribute for defining derive macros:
52
+
53
+ * `#[ts_macro_derive(Name)]` attribute
54
+ * Automatic registration with the macro system
55
+ * Error handling and span tracking
56
+
57
+ ### NAPI-RS Bindings
58
+
59
+ Bridges Rust and Node.js:
60
+
61
+ * Exposes `expandSync`, `transformSync`, etc.
62
+ * Provides the `NativePlugin` class for caching
63
+ * Handles data marshaling between Rust and JavaScript
64
+
65
+ ## Data Flow
66
+
67
+ 1\. Source Code
68
+
69
+ TypeScript with @derive
70
+
71
+ 2\. NAPI-RS
72
+
73
+ receives JavaScript string
74
+
75
+ 3\. SWC Parser
76
+
77
+ parses to AST
78
+
79
+ 4\. Macro Expander
80
+
81
+ finds @derive decorators
82
+
83
+ 5\. For Each Macro
84
+
85
+ extract data, run macro, generate AST nodes
86
+
87
+ 6\. Merge
88
+
89
+ generated nodes into AST
90
+
91
+ 7\. SWC Codegen
92
+
93
+ generates source code
94
+
95
+ 8\. Return
96
+
97
+ to JavaScript with source mapping
98
+
99
+ ## Performance Characteristics
100
+
101
+ * **Thread-safe**: Each expansion runs in an isolated thread with a 32MB stack
102
+ * **Caching**: `NativePlugin` caches results by file version
103
+ * **Binary search**: Position mapping uses O(log n) lookups
104
+ * **Zero-copy**: SWC's arena allocator minimizes allocations
105
+
106
+ ## Re-exported Crates
107
+
108
+ For custom macro development, `macroforge_ts` re-exports everything you need:
109
+
110
+ Rust
111
+
112
+ ```
113
+ // Convenient re-exports for macro development
114
+ use macroforge_ts::macros::{ts_macro_derive, body, ts_template, above, below, signature};
115
+ use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
116
+
117
+ // Also available: raw crate access and SWC modules
118
+ use macroforge_ts::swc_core;
119
+ use macroforge_ts::swc_common;
120
+ use macroforge_ts::swc_ecma_ast;
121
+ ```
122
+
123
+ ## Next Steps
124
+
125
+ * [Write custom macros](../../docs/custom-macros)
126
+ * [Explore the API reference](../../docs/api)
@@ -0,0 +1,13 @@
1
+ ## Built-in vs Custom Macros
2
+
3
+ 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.
4
+
5
+ | Type | Import Required | Examples |
6
+ | -------- | --------------- | ------------------------------------------------------------------------------- |
7
+ | Built-in | No | Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize |
8
+ | Custom | Yes | Any macro from an external package |
9
+
10
+ ## Next Steps
11
+
12
+ * [Explore built-in macros](../../docs/builtin-macros)
13
+ * [Create custom macros](../../docs/custom-macros)
@@ -0,0 +1,200 @@
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
+ Source
14
+
15
+ TypeScript
16
+
17
+ ```
18
+ /** @derive(Debug) */
19
+ class MyClass {
20
+ value: string;
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
+
35
+ ```
36
+ /** @derive(Debug, Clone) */
37
+ class User {
38
+ name: string;
39
+ email: string;
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
+
83
+ ```
84
+ /** @derive(Debug, Serialize) */
85
+ class User {
86
+ /** @debug({ rename: "userId" }) */
87
+ /** @serde({ rename: "user_id" }) */
88
+ id: number;
89
+
90
+ name: string;
91
+
92
+ /** @debug({ skip: true }) */
93
+ /** @serde({ skip: true }) */
94
+ password: string;
95
+
96
+ metadata: Record<string, unknown>;
97
+ }
98
+ ```
99
+
100
+ After (Generated)
101
+
102
+ ```
103
+ import { SerializeContext as __mf_SerializeContext } from 'macroforge/serde';
104
+
105
+ class User {
106
+ id: number;
107
+
108
+ name: string;
109
+
110
+ password: string;
111
+
112
+ metadata: Record<string, unknown>;
113
+
114
+ static toString(value: User): string {
115
+ return userToString(value);
116
+ }
117
+ /** Serializes a value to a JSON string.
118
+ @param value - The value to serialize
119
+ @returns JSON string representation with cycle detection metadata */
120
+
121
+ static serialize(value: User): string {
122
+ return userSerialize(value);
123
+ }
124
+ /** @internal Serializes with an existing context for nested/cyclic object graphs.
125
+ @param value - The value to serialize
126
+ @param ctx - The serialization context */
127
+
128
+ static serializeWithContext(value: User, ctx: __mf_SerializeContext): Record<string, unknown> {
129
+ return userSerializeWithContext(value, ctx);
130
+ }
131
+ }
132
+
133
+ export function userToString(value: User): string {
134
+ const parts: string[] = [];
135
+ parts.push('userId: ' + value.id);
136
+ parts.push('name: ' + value.name);
137
+ parts.push('metadata: ' + value.metadata);
138
+ return 'User { ' + parts.join(', ') + ' }';
139
+ }
140
+
141
+ /** Serializes a value to a JSON string.
142
+ @param value - The value to serialize
143
+ @returns JSON string representation with cycle detection metadata */ export function userSerialize(
144
+ value: User
145
+ ): string {
146
+ const ctx = __mf_SerializeContext.create();
147
+ return JSON.stringify(userSerializeWithContext(value, ctx));
148
+ } /** @internal Serializes with an existing context for nested/cyclic object graphs.
149
+ @param value - The value to serialize
150
+ @param ctx - The serialization context */
151
+ export function userSerializeWithContext(
152
+ value: User,
153
+ ctx: __mf_SerializeContext
154
+ ): Record<string, unknown> {
155
+ const existingId = ctx.getId(value);
156
+ if (existingId !== undefined) {
157
+ return { __ref: existingId };
158
+ }
159
+ const __id = ctx.register(value);
160
+ const result: Record<string, unknown> = { __type: 'User', __id };
161
+ result['user_id'] = value.id;
162
+ result['name'] = value.name;
163
+ result['metadata'] = value.metadata;
164
+ return result;
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