@macroforge/mcp-server 0.1.42 → 0.1.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +22 -0
  2. package/docs/BOOK.md +165 -0
  3. package/docs/api/api-overview.md +67 -48
  4. package/docs/api/expand-sync.md +88 -53
  5. package/docs/api/native-plugin.md +121 -71
  6. package/docs/api/position-mapper.md +115 -55
  7. package/docs/api/transform-sync.md +86 -60
  8. package/docs/builtin-macros/clone.md +0 -20
  9. package/docs/builtin-macros/debug.md +0 -23
  10. package/docs/builtin-macros/default.md +1 -40
  11. package/docs/builtin-macros/deserialize/example.md +8 -1416
  12. package/docs/builtin-macros/deserialize.md +8 -1416
  13. package/docs/builtin-macros/hash.md +0 -42
  14. package/docs/builtin-macros/macros-overview/detailed-documentation.md +13 -0
  15. package/docs/builtin-macros/macros-overview/enum-support.md +30 -0
  16. package/docs/builtin-macros/macros-overview/interface-support.md +28 -0
  17. package/docs/builtin-macros/macros-overview/overview.md +36 -0
  18. package/docs/builtin-macros/macros-overview/type-alias-support.md +62 -0
  19. package/docs/builtin-macros/macros-overview.md +171 -130
  20. package/docs/builtin-macros/ord.md +0 -25
  21. package/docs/builtin-macros/partial-eq.md +0 -84
  22. package/docs/builtin-macros/partial-ord.md +2 -32
  23. package/docs/builtin-macros/serialize.md +2 -62
  24. package/docs/concepts/architecture.md +125 -48
  25. package/docs/concepts/derive-system/built-in-vs-custom-macros.md +13 -0
  26. package/docs/concepts/derive-system/overview.md +200 -0
  27. package/docs/concepts/derive-system.md +157 -104
  28. package/docs/concepts/how-macros-work.md +98 -47
  29. package/docs/custom-macros/custom-overview.md +79 -57
  30. package/docs/custom-macros/rust-setup.md +138 -99
  31. package/docs/custom-macros/ts-macro-derive/accessing-field-data.md +40 -31
  32. package/docs/custom-macros/ts-macro-derive/adding-imports.md +14 -11
  33. package/docs/custom-macros/ts-macro-derive/attribute-options.md +20 -25
  34. package/docs/custom-macros/ts-macro-derive/complete-example.md +40 -38
  35. package/docs/custom-macros/ts-macro-derive/deriveinput-structure.md +49 -47
  36. package/docs/custom-macros/ts-macro-derive/function-signature.md +12 -0
  37. package/docs/custom-macros/ts-macro-derive/overview.md +9 -7
  38. package/docs/custom-macros/ts-macro-derive/parsing-input.md +20 -18
  39. package/docs/custom-macros/ts-macro-derive/returning-errors.md +15 -13
  40. package/docs/custom-macros/ts-macro-derive.md +322 -228
  41. package/docs/custom-macros/ts-quote/backtick-template-literals.md +19 -7
  42. package/docs/custom-macros/ts-quote/comments-and.md +56 -22
  43. package/docs/custom-macros/ts-quote/complete-example-json-derive-macro.md +89 -98
  44. package/docs/custom-macros/ts-quote/conditionals-ifif.md +35 -29
  45. package/docs/custom-macros/ts-quote/identifier-concatenation-content.md +30 -22
  46. package/docs/custom-macros/ts-quote/iteration-for.md +48 -40
  47. package/docs/custom-macros/ts-quote/local-constants-let.md +23 -21
  48. package/docs/custom-macros/ts-quote/match-expressions-match.md +46 -38
  49. package/docs/custom-macros/ts-quote/overview.md +5 -10
  50. package/docs/custom-macros/ts-quote/pattern-matching-iflet.md +39 -0
  51. package/docs/custom-macros/ts-quote/quick-reference.md +50 -129
  52. package/docs/custom-macros/ts-quote/side-effects-do.md +13 -78
  53. package/docs/custom-macros/ts-quote/string-interpolation-textexpr.md +36 -0
  54. package/docs/custom-macros/ts-quote/tsstream-injection-typescript.md +43 -35
  55. package/docs/custom-macros/ts-quote/while-loops-while.md +31 -23
  56. package/docs/custom-macros/ts-quote.md +800 -520
  57. package/docs/getting-started/first-macro.md +98 -71
  58. package/docs/getting-started/installation.md +109 -65
  59. package/docs/integration/cli.md +214 -105
  60. package/docs/integration/configuration.md +115 -72
  61. package/docs/integration/integration-overview.md +55 -18
  62. package/docs/integration/mcp-server.md +84 -43
  63. package/docs/integration/svelte-preprocessor.md +183 -126
  64. package/docs/integration/typescript-plugin.md +101 -53
  65. package/docs/integration/vite-plugin.md +116 -76
  66. package/docs/language-servers/ls-overview.md +37 -21
  67. package/docs/language-servers/svelte.md +69 -38
  68. package/docs/language-servers/zed.md +81 -44
  69. package/docs/roadmap/roadmap.md +75 -53
  70. package/docs/sections.json +333 -44
  71. package/package.json +27 -28
@@ -1,112 +1,151 @@
1
1
  # Rust Setup
2
- *Create a new Rust crate that will contain your custom macros. This crate compiles to a native Node.js addon.*
3
- ## Prerequisites
4
- - Rust toolchain (1.88 or later)
5
- - Node.js 24 or later
6
- - NAPI-RS CLI: <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">cargo<span style="--shiki-dark:#9ECBFF;--shiki-light:#032F62"> install<span style="--shiki-dark:#9ECBFF;--shiki-light:#032F62"> macroforge_ts</code>
7
- ## Create the Project
8
- ```
9
- #&nbsp;Create&nbsp;a&nbsp;new&nbsp;directory
10
- mkdir&nbsp;my-macros
11
- cd&nbsp;my-macros
12
-
13
- #&nbsp;Initialize&nbsp;with&nbsp;NAPI-RS
14
- napi&nbsp;new&nbsp;--platform&nbsp;--name&nbsp;my-macros
15
- ``` ## Configure Cargo.toml
16
- Update your <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic;--shiki-light:#B31D28;--shiki-light-font-style:italic">Cargo.toml</code> with the required dependencies:
17
- ```
2
+
3
+ Create a new Rust crate that will contain your custom macros. This crate compiles to a native Node.js addon.
4
+
5
+ ## Prerequisites
6
+
7
+ * Rust toolchain (1.88 or later)
8
+ * Node.js 24 or later
9
+ * NAPI-RS CLI: `cargo install macroforge_ts`
10
+
11
+ ## Create the Project
12
+
13
+ Bash
14
+
15
+ ```
16
+ # Create a new directory
17
+ mkdir my-macros
18
+ cd my-macros
19
+
20
+ # Initialize with NAPI-RS
21
+ napi new --platform --name my-macros
22
+ ```
23
+
24
+ ## Configure Cargo.toml
25
+
26
+ Update your `Cargo.toml` with the required dependencies:
27
+
28
+ Cargo.toml
29
+
30
+ ```
18
31
  [package]
19
- name&nbsp;=&nbsp;"my-macros"
20
- version&nbsp;=&nbsp;"0.1.0"
21
- edition&nbsp;=&nbsp;"2024"
32
+ name = "my-macros"
33
+ version = "0.1.0"
34
+ edition = "2024"
22
35
 
23
36
  [lib]
24
- crate-type&nbsp;=&nbsp;["cdylib"]
37
+ crate-type = ["cdylib"]
25
38
 
26
39
  [dependencies]
27
- macroforge_ts&nbsp;=&nbsp;"0.1"
28
- napi&nbsp;=&nbsp;&#123;&nbsp;version&nbsp;=&nbsp;"3",&nbsp;features&nbsp;=&nbsp;["napi8",&nbsp;"compat-mode"]&nbsp;&#125;
29
- napi-derive&nbsp;=&nbsp;"3"
40
+ macroforge_ts = "0.1"
41
+ napi = { version = "3"features = ["napi8""compat-mode"] }
42
+ napi-derive = "3"
30
43
 
31
44
  [build-dependencies]
32
- napi-build&nbsp;=&nbsp;"2"
45
+ napi-build = "2"
33
46
 
34
47
  [profile.release]
35
- lto&nbsp;=&nbsp;true
36
- strip&nbsp;=&nbsp;true
37
- ``` ## Create build.rs
38
- ```
39
- fn&nbsp;main()&nbsp;&#123;
40
- &nbsp;&nbsp;&nbsp;&nbsp;napi_build::setup();
41
- &#125;
42
- ``` ## Create src/lib.rs
43
- ```
44
- use&nbsp;macroforge_ts::macros::&#123;ts_macro_derive,&nbsp;body&#125;;
45
- use&nbsp;macroforge_ts::ts_syn::&#123;
46
- &nbsp;&nbsp;&nbsp;&nbsp;Data,&nbsp;DeriveInput,&nbsp;MacroforgeError,&nbsp;TsStream,&nbsp;parse_ts_macro_input,
47
- &#125;;
48
+ lto = true
49
+ strip = true
50
+ ```
51
+
52
+ ## Create build.rs
53
+
54
+ build.rs
55
+
56
+ ```
57
+ fn main() {
58
+     napi_build::setup();
59
+ }
60
+ ```
61
+
62
+ ## Create src/lib.rs
63
+
64
+ src/lib.rs
65
+
66
+ ```
67
+ use macroforge_ts::macros::{ts_macro_derive, body};
68
+ use macroforge_ts::ts_syn::{
69
+     Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input,
70
+ };
48
71
 
49
72
  #[ts_macro_derive(
50
- &nbsp;&nbsp;&nbsp;&nbsp;JSON,
51
- &nbsp;&nbsp;&nbsp;&nbsp;description&nbsp;=&nbsp;"Generates&nbsp;toJSON()&nbsp;returning&nbsp;a&nbsp;plain&nbsp;object"
73
+     JSON,
74
+     description = "Generates toJSON() returning a plain object"
52
75
  )]
53
- pub&nbsp;fn&nbsp;derive_json(mut&nbsp;input:&nbsp;TsStream)&nbsp;->&nbsp;Result&#x3C;TsStream,&nbsp;MacroforgeError>&nbsp;&#123;
54
- &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;input&nbsp;=&nbsp;parse_ts_macro_input!(input&nbsp;as&nbsp;DeriveInput);
55
-
56
- &nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;&#x26;input.data&nbsp;&#123;
57
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data::Class(class)&nbsp;=>&nbsp;&#123;
58
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ok(body!&nbsp;&#123;
59
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;toJSON():&nbsp;Record&#x3C;string,&nbsp;unknown>&nbsp;&#123;
60
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&#123;
61
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;#for&nbsp;field&nbsp;in&nbsp;class.field_names()&#125;
62
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@&#123;field&#125;:&nbsp;this.@&#123;field&#125;,
63
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;/for&#125;
64
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;;
65
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
66
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;)
67
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
68
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_&nbsp;=>&nbsp;Err(MacroforgeError::new(
69
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;input.decorator_span(),
70
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"@derive(JSON)&nbsp;only&nbsp;works&nbsp;on&nbsp;classes",
71
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)),
72
- &nbsp;&nbsp;&nbsp;&nbsp;&#125;
73
- &#125;
74
- ``` ## Create package.json
75
- ```
76
- &#123;
77
- &nbsp;&nbsp;"name":&nbsp;"@my-org/macros",
78
- &nbsp;&nbsp;"version":&nbsp;"0.1.0",
79
- &nbsp;&nbsp;"main":&nbsp;"index.js",
80
- &nbsp;&nbsp;"types":&nbsp;"index.d.ts",
81
- &nbsp;&nbsp;"napi":&nbsp;&#123;
82
- &nbsp;&nbsp;&nbsp;&nbsp;"name":&nbsp;"my-macros",
83
- &nbsp;&nbsp;&nbsp;&nbsp;"triples":&nbsp;&#123;
84
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"defaults":&nbsp;true
85
- &nbsp;&nbsp;&nbsp;&nbsp;&#125;
86
- &nbsp;&nbsp;&#125;,
87
- &nbsp;&nbsp;"files":&nbsp;[
88
- &nbsp;&nbsp;&nbsp;&nbsp;"index.js",
89
- &nbsp;&nbsp;&nbsp;&nbsp;"index.d.ts",
90
- &nbsp;&nbsp;&nbsp;&nbsp;"*.node"
91
- &nbsp;&nbsp;],
92
- &nbsp;&nbsp;"scripts":&nbsp;&#123;
93
- &nbsp;&nbsp;&nbsp;&nbsp;"build":&nbsp;"napi&nbsp;build&nbsp;--release",
94
- &nbsp;&nbsp;&nbsp;&nbsp;"prepublishOnly":&nbsp;"napi&nbsp;build&nbsp;--release"
95
- &nbsp;&nbsp;&#125;,
96
- &nbsp;&nbsp;"devDependencies":&nbsp;&#123;
97
- &nbsp;&nbsp;&nbsp;&nbsp;"@napi-rs/cli":&nbsp;"^3.0.0-alpha.0"
98
- &nbsp;&nbsp;&#125;
99
- &#125;
100
- ``` ## Build the Package
101
- ```
102
- #&nbsp;Build&nbsp;the&nbsp;native&nbsp;addon
103
- npm&nbsp;run&nbsp;build
104
-
105
- #&nbsp;This&nbsp;creates:
106
- #&nbsp;-&nbsp;index.js&nbsp;(JavaScript&nbsp;bindings)
107
- #&nbsp;-&nbsp;index.d.ts&nbsp;(TypeScript&nbsp;types)
108
- #&nbsp;-&nbsp;*.node&nbsp;(native&nbsp;binary)
109
- ``` **Tip For cross-platform builds, use GitHub Actions with the NAPI-RS CI template. ## Next Steps
110
- - [Learn the #[ts_macro_derive] attribute](../../docs/custom-macros/ts-macro-derive)
111
- - [Master the template syntax](../../docs/custom-macros/ts-quote)
112
- **
76
+ pub fn derive_json(mut inputTsStream) -> Result<TsStreamMacroforgeError> {
77
+     let input = parse_ts_macro_input!(input as DeriveInput);
78
+
79
+     match &input.data {
80
+         Data::Class(class) => {
81
+             Ok(body! {
82
+                 toJSON()Record<stringunknown> {
83
+                     return {
84
+                         {#for field in class.field_names()}
85
+                             @{field}: this.@{field},
86
+                         {/for}
87
+                     };
88
+                 }
89
+             })
90
+         }
91
+         _ => Err(MacroforgeError::new(
92
+             input.decorator_span(),
93
+             "@derive(JSON) only works on classes",
94
+         )),
95
+     }
96
+ }
97
+ ```
98
+
99
+ ## Create package.json
100
+
101
+ package.json
102
+
103
+ ```
104
+ {
105
+   "name""@my-org/macros",
106
+   "version": "0.1.0",
107
+   "main": "index.js",
108
+   "types": "index.d.ts",
109
+   "napi": {
110
+     "name": "my-macros",
111
+     "triples": {
112
+       "defaults": true
113
+     }
114
+   },
115
+   "files": [
116
+     "index.js",
117
+     "index.d.ts",
118
+     "*.node"
119
+   ],
120
+   "scripts": {
121
+     "build": "napi build --release",
122
+     "prepublishOnly": "napi build --release"
123
+   },
124
+   "devDependencies": {
125
+     "@napi-rs/cli": "^3.0.0-alpha.0"
126
+   }
127
+ }
128
+ ```
129
+
130
+ ## Build the Package
131
+
132
+ Bash
133
+
134
+ ```
135
+ # Build the native addon
136
+ npm run build
137
+
138
+ # This creates:
139
+ # - index.js (JavaScript bindings)
140
+ # - index.d.ts (TypeScript types)
141
+ # - *.node (native binary)
142
+ ```
143
+
144
+ Tip
145
+
146
+ For cross-platform builds, use GitHub Actions with the NAPI-RS CI template.
147
+
148
+ ## Next Steps
149
+
150
+ * [Learn the #\[ts\_macro\_derive\] attribute](../../docs/custom-macros/ts-macro-derive)
151
+ * [Master the template syntax](../../docs/custom-macros/ts-quote)
@@ -2,52 +2,61 @@
2
2
 
3
3
  ### Class Fields (FieldIR)
4
4
 
5
- ```rust
6
- struct FieldIR {
7
- pub name: String, // Field name
8
- pub span: SpanIR, // Field span
9
- pub ts_type: String, // TypeScript type annotation
10
- pub optional: bool, // Whether field has ?
11
- pub readonly: bool, // Whether field is readonly
12
- pub visibility: Visibility, // Public, Protected, Private
13
- pub decorators: Vec<DecoratorIR>, // Field decorators
5
+ Rust
6
+
7
+ ```
8
+ struct FieldIR {
9
+     pub name: String,               // Field name
10
+     pub span: SpanIR,               // Field span
11
+     pub ts_type: String,            // TypeScript type annotation
12
+     pub optional: bool,             // Whether field has ?
13
+     pub readonly: bool,             // Whether field is readonly
14
+     pub visibility: Visibility,     // Public, Protected, Private
15
+     pub decorators: Vec<DecoratorIR>, // Field decorators
14
16
  }
15
17
  ```
16
18
 
17
19
  ### Interface Fields (InterfaceFieldIR)
18
20
 
19
- ```rust
20
- struct InterfaceFieldIR {
21
- pub name: String,
22
- pub span: SpanIR,
23
- pub ts_type: String,
24
- pub optional: bool,
25
- pub readonly: bool,
26
- pub decorators: Vec<DecoratorIR>,
27
- // Note: No visibility field (interfaces are always public)
21
+ Rust
22
+
23
+ ```
24
+ struct InterfaceFieldIR {
25
+     pub name: String,
26
+     pub span: SpanIR,
27
+     pub ts_type: String,
28
+     pub optional: bool,
29
+     pub readonly: bool,
30
+     pub decorators: Vec<DecoratorIR>,
31
+     // Note: No visibility field (interfaces are always public)
28
32
  }
29
33
  ```
30
34
 
31
35
  ### Enum Variants (EnumVariantIR)
32
36
 
33
- ```rust
34
- struct EnumVariantIR {
35
- pub name: String,
36
- pub span: SpanIR,
37
- pub value: EnumValue, // Auto, String(String), or Number(f64)
38
- pub decorators: Vec<DecoratorIR>,
37
+ Rust
38
+
39
+ ```
40
+ struct EnumVariantIR {
41
+     pub name: String,
42
+     pub span: SpanIR,
43
+     pub value: EnumValue,  // Auto, String(String), or Number(f64)
44
+     pub decorators: Vec<DecoratorIR>,
39
45
  }
40
46
  ```
41
47
 
42
48
  ### Decorator Structure
43
49
 
44
- ```rust
45
- struct DecoratorIR {
46
- pub name: String, // e.g., "serde"
47
- pub args_src: String, // Raw args text, e.g., "skip, rename: 'id'"
48
- pub span: SpanIR,
50
+ Rust
51
+
52
+ ```
53
+ struct DecoratorIR {
54
+     pub name: String,      // e.g., "serde"
55
+     pub args_src: String,  // Raw args text, e.g., "skip, rename: 'id'"
56
+     pub span: SpanIR,
49
57
  }
50
58
  ```
51
59
 
52
- >
53
- > To check for decorators, iterate through `field.decorators` and check `decorator.name`. For parsing options, you can write helper functions like the built-in macros do.
60
+ Note
61
+
62
+ To check for decorators, iterate through `field.decorators` and check `decorator.name`. For parsing options, you can write helper functions like the built-in macros do.
@@ -2,20 +2,23 @@
2
2
 
3
3
  If your macro generates code that requires imports, use the `add_import` method on `TsStream`:
4
4
 
5
- ```rust
6
- // Add an import to be inserted at the top of the file
7
- let mut output = body! {
8
- validate(): ValidationResult {
9
- return validateFields(this);
10
- }
5
+ Rust
6
+
7
+ ```
8
+ // Add an import to be inserted at the top of the file
9
+ let mut output = body! {
10
+     validate(): ValidationResult {
11
+         return validateFields(this);
12
+     }
11
13
  };
12
14
 
13
- // This will add: import { validateFields, ValidationResult } from "my-validation-lib";
14
- output.add_import("validateFields", "my-validation-lib");
15
- output.add_import("ValidationResult", "my-validation-lib");
15
+ // This will add: import { validateFields, ValidationResult } from "my-validation-lib";
16
+ output.add_import("validateFields", "my-validation-lib");
17
+ output.add_import("ValidationResult", "my-validation-lib");
16
18
 
17
19
  Ok(output)
18
20
  ```
19
21
 
20
- >
21
- > Imports are automatically deduplicated. If the same import already exists in the file, it won't be added again.
22
+ Note
23
+
24
+ Imports are automatically deduplicated. If the same import already exists in the file, it won't be added again.
@@ -4,47 +4,42 @@
4
4
 
5
5
  The first argument is the macro name that users will reference in `@derive()`:
6
6
 
7
- ```rust
8
- #[ts_macro_derive(JSON)] // Users write: @derive(JSON)
9
- pub fn derive_json(...)
7
+ Rust
8
+
9
+ ```
10
+ #[ts_macro_derive(JSON)]  // Users write: @derive(JSON)
11
+ pub fn derive_json(...)
10
12
  ```
11
13
 
12
14
  ### Description
13
15
 
14
16
  Provides documentation for the macro:
15
17
 
16
- ```rust
18
+ Rust
19
+
20
+ ```
17
21
  #[ts_macro_derive(
18
- JSON,
19
- description = "Generates toJSON() returning a plain object"
22
+     JSON,
23
+     description = "Generates toJSON() returning a plain object"
20
24
  )]
21
- pub fn derive_json(...)
25
+ pub fn derive_json(...)
22
26
  ```
23
27
 
24
28
  ### Attributes
25
29
 
26
30
  Declare which field-level decorators your macro accepts:
27
31
 
28
- ```rust
32
+ Rust
33
+
34
+ ```
29
35
  #[ts_macro_derive(
30
- Debug,
31
- description = "Generates toString()",
32
- attributes(debug) // Allows @debug({ ... }) on fields
36
+     Debug,
37
+     description = "Generates toString()",
38
+     attributes(debug)  // Allows @debug({ ... }) on fields
33
39
  )]
34
- pub fn derive_debug(...)
35
- ```
36
-
37
- >
38
- > Declared attributes become available as `@attributeName(&#123; options &#125;)` decorators in TypeScript.
39
-
40
- ## Function Signature
41
-
42
- ```rust
43
- pub fn my_macro(mut input: TsStream) -> Result<TsStream, MacroforgeError>
40
+ pub fn derive_debug(...)
44
41
  ```
45
42
 
46
- | `input: TsStream`
47
- | Token stream containing the class/interface AST
43
+ Note
48
44
 
49
- | `Result<TsStream, MacroforgeError>`
50
- | Returns generated code or an error with source location
45
+ Declared attributes become available as `@attributeName({ options })` decorators in TypeScript.
@@ -1,51 +1,53 @@
1
1
  ## Complete Example
2
2
 
3
- ```rust
4
- use macroforge_ts::macros::{ts_macro_derive, body};
5
- use macroforge_ts::ts_syn::{
6
- Data, DeriveInput, FieldIR, MacroforgeError, TsStream, parse_ts_macro_input,
3
+ Rust
4
+
5
+ ```
6
+ use macroforge_ts::macros::{ts_macro_derive, body};
7
+ use macroforge_ts::ts_syn::{
8
+     Data, DeriveInput, FieldIR, MacroforgeError, TsStream, parse_ts_macro_input,
7
9
  };
8
10
 
9
- // Helper function to check if a field has a decorator
10
- fn has_decorator(field: &FieldIR, name: &str) -> bool {
11
- field.decorators.iter().any(|d| d.name.eq_ignore_ascii_case(name))
11
+ // Helper function to check if a field has a decorator
12
+ fn has_decorator(field: &FieldIR, name: &str) -> bool {
13
+     field.decorators.iter().any(|d| d.name.eq_ignore_ascii_case(name))
12
14
  }
13
15
 
14
16
  #[ts_macro_derive(
15
- Validate,
16
- description = "Generates a validate() method",
17
- attributes(validate)
17
+     Validate,
18
+     description = "Generates a validate() method",
19
+     attributes(validate)
18
20
  )]
19
- pub fn derive_validate(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
20
- let input = parse_ts_macro_input!(input as DeriveInput);
21
-
22
- match &input.data {
23
- Data::Class(class) => {
24
- let validations: Vec<_> = class.fields()
25
- .iter()
26
- .filter(|f| has_decorator(f, "validate"))
27
- .collect();
28
-
29
- Ok(body! {
30
- validate(): string[] {
31
- const errors: string[] = [];
32
- {#for field in validations}
33
- if (!this.@{field.name}) {
34
- errors.push("@{field.name} is required");
35
- }
36
- {/for}
37
- return errors;
38
- }
39
- })
40
- }
41
- _ => Err(MacroforgeError::new(
42
- input.decorator_span(),
43
- "@derive(Validate) only works on classes",
44
- )),
45
- }
21
+ pub fn derive_validate(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
22
+     let input = parse_ts_macro_input!(input as DeriveInput);
23
+
24
+     match &input.data {
25
+         Data::Class(class) => {
26
+             let validations: Vec<_> = class.fields()
27
+                 .iter()
28
+                 .filter(|f| has_decorator(f, "validate"))
29
+                 .collect();
30
+
31
+             Ok(body! {
32
+                 validate(): string[] {
33
+                     const errors: string[] = [];
34
+                     {#for field in validations}
35
+                         if (!this.@{field.name}) {
36
+                             errors.push("@{field.name} is required");
37
+                         }
38
+                     {/for}
39
+                     return errors;
40
+                 }
41
+             })
42
+         }
43
+         _ => Err(MacroforgeError::new(
44
+             input.decorator_span(),
45
+             "@derive(Validate) only works on classes",
46
+         )),
47
+     }
46
48
  }
47
49
  ```
48
50
 
49
51
  ## Next Steps
50
52
 
51
- - [Learn the template syntax]({base}/docs/custom-macros/ts-quote)
53
+ * [Learn the template syntax](../../docs/custom-macros/ts-quote)