@macroforge/mcp-server 0.1.42 → 0.1.50

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 +1 -242
  71. package/package.json +27 -28
@@ -1,242 +1,336 @@
1
- # ts_macro_derive
2
- *The <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">#[ts_macro_derive]</code> attribute is a Rust procedural macro that registers your function as a Macroforge derive macro.*
3
- ## Basic Syntax
4
- ```
5
- use&nbsp;macroforge_ts::macros::ts_macro_derive;
6
- use&nbsp;macroforge_ts::ts_syn::&#123;TsStream,&nbsp;MacroforgeError&#125;;
1
+ # ts\_macro\_derive
2
+
3
+ The `#[ts_macro_derive]` attribute is a Rust procedural macro that registers your function as a Macroforge derive macro.
4
+
5
+ ## Basic Syntax
6
+
7
+ Rust
8
+
9
+ ```
10
+ use macroforge_ts::macros::ts_macro_derive;
11
+ use macroforge_ts::ts_syn::{TsStream, MacroforgeError};
7
12
 
8
13
  #[ts_macro_derive(MacroName)]
9
- pub&nbsp;fn&nbsp;my_macro(mut&nbsp;input:&nbsp;TsStream)&nbsp;->&nbsp;Result&#x3C;TsStream,&nbsp;MacroforgeError>&nbsp;&#123;
10
- &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Macro&nbsp;implementation
11
- &#125;
12
- ``` ## Attribute Options
13
- ### Name (Required)
14
- The first argument is the macro name that users will reference in <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">()</code>:
15
- ```
16
- #[ts_macro_derive(JSON)]&nbsp;&nbsp;//&nbsp;Users&nbsp;write:&nbsp;@derive(JSON)
17
- pub&nbsp;fn&nbsp;derive_json(...)
18
- ``` ### Description
19
- Provides documentation for the macro:
20
- ```
14
+ pub fn my_macro(mut inputTsStream) -> Result<TsStreamMacroforgeError> {
15
+     // Macro implementation
16
+ }
17
+ ```
18
+
19
+ ## Attribute Options
20
+
21
+ ### Name (Required)
22
+
23
+ The first argument is the macro name that users will reference in `@derive()`:
24
+
25
+ Rust
26
+
27
+ ```
28
+ #[ts_macro_derive(JSON)]  // Users write: @derive(JSON)
29
+ pub fn derive_json(...)
30
+ ```
31
+
32
+ ### Description
33
+
34
+ Provides documentation for the macro:
35
+
36
+ Rust
37
+
38
+ ```
21
39
  #[ts_macro_derive(
22
- &nbsp;&nbsp;&nbsp;&nbsp;JSON,
23
- &nbsp;&nbsp;&nbsp;&nbsp;description&nbsp;=&nbsp;"Generates&nbsp;toJSON()&nbsp;returning&nbsp;a&nbsp;plain&nbsp;object"
40
+     JSON,
41
+     description = "Generates toJSON() returning a plain object"
24
42
  )]
25
- pub&nbsp;fn&nbsp;derive_json(...)
26
- ``` ### Attributes
27
- Declare which field-level decorators your macro accepts:
28
- ```
43
+ pub fn derive_json(...)
44
+ ```
45
+
46
+ ### Attributes
47
+
48
+ Declare which field-level decorators your macro accepts:
49
+
50
+ Rust
51
+
52
+ ```
29
53
  #[ts_macro_derive(
30
- &nbsp;&nbsp;&nbsp;&nbsp;Debug,
31
- &nbsp;&nbsp;&nbsp;&nbsp;description&nbsp;=&nbsp;"Generates&nbsp;toString()",
32
- &nbsp;&nbsp;&nbsp;&nbsp;attributes(debug)&nbsp;&nbsp;//&nbsp;Allows&nbsp;@debug(&#123;&nbsp;...&nbsp;&#125;)&nbsp;on&nbsp;fields
54
+     Debug,
55
+     description = "Generates toString()",
56
+     attributes(debug)  // Allows @debug({ ... }) on fields
33
57
  )]
34
- pub&nbsp;fn&nbsp;derive_debug(...)
35
- ``` > **Note:** Declared attributes become available as @attributeName({ options }) decorators in TypeScript. ## Function Signature
36
- ```
37
- pub&nbsp;fn&nbsp;my_macro(mut&nbsp;input:&nbsp;TsStream)&nbsp;->&nbsp;Result&#x3C;TsStream,&nbsp;MacroforgeError>
38
- ``` | Parameter | Description |
39
- | --- | --- |
40
- | input: TsStream | Token stream containing the class/interface AST |
41
- | Result<TsStream, MacroforgeError> | Returns generated code or an error with source location |
42
- ## Parsing Input
43
- Use <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#B392F0;--shiki-light:#6F42C1">parse_ts_macro_input!</code> to convert the token stream:
44
- ```
45
- use&nbsp;macroforge_ts::ts_syn::&#123;Data,&nbsp;DeriveInput,&nbsp;parse_ts_macro_input&#125;;
58
+ pub fn derive_debug(...)
59
+ ```
60
+
61
+ Note
62
+
63
+ Declared attributes become available as `@attributeName({ options })` decorators in TypeScript.
64
+
65
+ ## Function Signature
66
+
67
+ Rust
68
+
69
+ ```
70
+ pub fn my_macro(mut input: TsStream) -> Result<TsStream, MacroforgeError>
71
+ ```
72
+
73
+ | Parameter | Description |
74
+ | ----------------------------------- | ------------------------------------------------------- |
75
+ | `input: TsStream` | Token stream containing the class/interface AST |
76
+ | `Result<TsStream, MacroforgeError>` | Returns generated code or an error with source location |
77
+
78
+ ## Parsing Input
79
+
80
+ Use `parse_ts_macro_input!` to convert the token stream:
81
+
82
+ Rust
83
+
84
+ ```
85
+ use macroforge_ts::ts_syn::{Data, DeriveInput, parse_ts_macro_input};
46
86
 
47
87
  #[ts_macro_derive(MyMacro)]
48
- pub&nbsp;fn&nbsp;my_macro(mut&nbsp;input:&nbsp;TsStream)&nbsp;->&nbsp;Result&#x3C;TsStream,&nbsp;MacroforgeError>&nbsp;&#123;
49
- &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;input&nbsp;=&nbsp;parse_ts_macro_input!(input&nbsp;as&nbsp;DeriveInput);
50
-
51
- &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Access&nbsp;class&nbsp;data
52
- &nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;&#x26;input.data&nbsp;&#123;
53
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data::Class(class)&nbsp;=>&nbsp;&#123;
54
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;class_name&nbsp;=&nbsp;input.name();
55
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;fields&nbsp;=&nbsp;class.fields();
56
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;...
57
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
58
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data::Interface(interface)&nbsp;=>&nbsp;&#123;
59
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Handle&nbsp;interfaces
60
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
61
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data::Enum(_)&nbsp;=>&nbsp;&#123;
62
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Handle&nbsp;enums&nbsp;(if&nbsp;supported)
63
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
64
- &nbsp;&nbsp;&nbsp;&nbsp;&#125;
65
- &#125;
66
- ``` ## DeriveInput Structure
67
- ```
68
- struct&nbsp;DeriveInput&nbsp;&#123;
69
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;ident:&nbsp;Ident,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;The&nbsp;type&nbsp;name
70
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;span:&nbsp;SpanIR,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Span&nbsp;of&nbsp;the&nbsp;type&nbsp;definition
71
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;attrs:&nbsp;Vec&#x3C;Attribute>,&nbsp;&nbsp;//&nbsp;Decorators&nbsp;(excluding&nbsp;@derive)
72
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;data:&nbsp;Data,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;The&nbsp;parsed&nbsp;type&nbsp;data
73
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;context:&nbsp;MacroContextIR,&nbsp;//&nbsp;Macro&nbsp;context&nbsp;with&nbsp;spans
74
-
75
- &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Helper&nbsp;methods
76
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;name(&#x26;self)&nbsp;->&nbsp;&#x26;str;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Get&nbsp;the&nbsp;type&nbsp;name
77
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;decorator_span(&#x26;self)&nbsp;->&nbsp;SpanIR;&nbsp;&nbsp;//&nbsp;Span&nbsp;of&nbsp;@derive&nbsp;decorator
78
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;as_class(&#x26;self)&nbsp;->&nbsp;Option&#x3C;&#x26;DataClass>;
79
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;as_interface(&#x26;self)&nbsp;->&nbsp;Option&#x3C;&#x26;DataInterface>;
80
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;as_enum(&#x26;self)&nbsp;->&nbsp;Option&#x3C;&#x26;DataEnum>;
81
- &#125;
82
-
83
- enum&nbsp;Data&nbsp;&#123;
84
- &nbsp;&nbsp;&nbsp;&nbsp;Class(DataClass),
85
- &nbsp;&nbsp;&nbsp;&nbsp;Interface(DataInterface),
86
- &nbsp;&nbsp;&nbsp;&nbsp;Enum(DataEnum),
87
- &nbsp;&nbsp;&nbsp;&nbsp;TypeAlias(DataTypeAlias),
88
- &#125;
89
-
90
- impl&nbsp;DataClass&nbsp;&#123;
91
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;fields(&#x26;self)&nbsp;->&nbsp;&#x26;[FieldIR];
92
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;methods(&#x26;self)&nbsp;->&nbsp;&#x26;[MethodSigIR];
93
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;field_names(&#x26;self)&nbsp;->&nbsp;impl&nbsp;Iterator&#x3C;Item&nbsp;=&nbsp;&#x26;str>;
94
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;field(&#x26;self,&nbsp;name:&nbsp;&#x26;str)&nbsp;->&nbsp;Option&#x3C;&#x26;FieldIR>;
95
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;body_span(&#x26;self)&nbsp;->&nbsp;SpanIR;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;For&nbsp;inserting&nbsp;code&nbsp;into&nbsp;class&nbsp;body
96
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;type_params(&#x26;self)&nbsp;->&nbsp;&#x26;[String];&nbsp;//&nbsp;Generic&nbsp;type&nbsp;parameters
97
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;heritage(&#x26;self)&nbsp;->&nbsp;&#x26;[String];&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;extends/implements&nbsp;clauses
98
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;is_abstract(&#x26;self)&nbsp;->&nbsp;bool;
99
- &#125;
100
-
101
- impl&nbsp;DataInterface&nbsp;&#123;
102
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;fields(&#x26;self)&nbsp;->&nbsp;&#x26;[InterfaceFieldIR];
103
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;methods(&#x26;self)&nbsp;->&nbsp;&#x26;[InterfaceMethodIR];
104
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;field_names(&#x26;self)&nbsp;->&nbsp;impl&nbsp;Iterator&#x3C;Item&nbsp;=&nbsp;&#x26;str>;
105
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;field(&#x26;self,&nbsp;name:&nbsp;&#x26;str)&nbsp;->&nbsp;Option&#x3C;&#x26;InterfaceFieldIR>;
106
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;body_span(&#x26;self)&nbsp;->&nbsp;SpanIR;
107
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;type_params(&#x26;self)&nbsp;->&nbsp;&#x26;[String];
108
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;heritage(&#x26;self)&nbsp;->&nbsp;&#x26;[String];&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;extends&nbsp;clauses
109
- &#125;
110
-
111
- impl&nbsp;DataEnum&nbsp;&#123;
112
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;variants(&#x26;self)&nbsp;->&nbsp;&#x26;[EnumVariantIR];
113
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;variant_names(&#x26;self)&nbsp;->&nbsp;impl&nbsp;Iterator&#x3C;Item&nbsp;=&nbsp;&#x26;str>;
114
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;variant(&#x26;self,&nbsp;name:&nbsp;&#x26;str)&nbsp;->&nbsp;Option&#x3C;&#x26;EnumVariantIR>;
115
- &#125;
116
-
117
- impl&nbsp;DataTypeAlias&nbsp;&#123;
118
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;body(&#x26;self)&nbsp;->&nbsp;&#x26;TypeBody;
119
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;type_params(&#x26;self)&nbsp;->&nbsp;&#x26;[String];
120
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;is_union(&#x26;self)&nbsp;->&nbsp;bool;
121
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;is_object(&#x26;self)&nbsp;->&nbsp;bool;
122
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;as_union(&#x26;self)&nbsp;->&nbsp;Option&#x3C;&#x26;[TypeMember]>;
123
- &nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;as_object(&#x26;self)&nbsp;->&nbsp;Option&#x3C;&#x26;[InterfaceFieldIR]>;
124
- &#125;
125
- ``` ## Accessing Field Data
126
- ### Class Fields (FieldIR)
127
- ```
128
- struct&nbsp;FieldIR&nbsp;&#123;
129
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;name:&nbsp;String,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Field&nbsp;name
130
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;span:&nbsp;SpanIR,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Field&nbsp;span
131
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;ts_type:&nbsp;String,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TypeScript&nbsp;type&nbsp;annotation
132
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;optional:&nbsp;bool,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Whether&nbsp;field&nbsp;has&nbsp;?
133
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;readonly:&nbsp;bool,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Whether&nbsp;field&nbsp;is&nbsp;readonly
134
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;visibility:&nbsp;Visibility,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Public,&nbsp;Protected,&nbsp;Private
135
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;decorators:&nbsp;Vec&#x3C;DecoratorIR>,&nbsp;//&nbsp;Field&nbsp;decorators
136
- &#125;
137
- ``` ### Interface Fields (InterfaceFieldIR)
138
- ```
139
- struct&nbsp;InterfaceFieldIR&nbsp;&#123;
140
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;name:&nbsp;String,
141
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;span:&nbsp;SpanIR,
142
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;ts_type:&nbsp;String,
143
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;optional:&nbsp;bool,
144
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;readonly:&nbsp;bool,
145
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;decorators:&nbsp;Vec&#x3C;DecoratorIR>,
146
- &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Note:&nbsp;No&nbsp;visibility&nbsp;field&nbsp;(interfaces&nbsp;are&nbsp;always&nbsp;public)
147
- &#125;
148
- ``` ### Enum Variants (EnumVariantIR)
149
- ```
150
- struct&nbsp;EnumVariantIR&nbsp;&#123;
151
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;name:&nbsp;String,
152
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;span:&nbsp;SpanIR,
153
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;value:&nbsp;EnumValue,&nbsp;&nbsp;//&nbsp;Auto,&nbsp;String(String),&nbsp;or&nbsp;Number(f64)
154
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;decorators:&nbsp;Vec&#x3C;DecoratorIR>,
155
- &#125;
156
- ``` ### Decorator Structure
157
- ```
158
- struct&nbsp;DecoratorIR&nbsp;&#123;
159
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;name:&nbsp;String,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;e.g.,&nbsp;"serde"
160
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;args_src:&nbsp;String,&nbsp;&nbsp;//&nbsp;Raw&nbsp;args&nbsp;text,&nbsp;e.g.,&nbsp;"skip,&nbsp;rename:&nbsp;'id'"
161
- &nbsp;&nbsp;&nbsp;&nbsp;pub&nbsp;span:&nbsp;SpanIR,
162
- &#125;
163
- ``` > **Note:** 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. ## Adding Imports
164
- If your macro generates code that requires imports, use the <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">add_import</code> method on <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">TsStream</code>:
165
- ```
166
- //&nbsp;Add&nbsp;an&nbsp;import&nbsp;to&nbsp;be&nbsp;inserted&nbsp;at&nbsp;the&nbsp;top&nbsp;of&nbsp;the&nbsp;file
167
- let&nbsp;mut&nbsp;output&nbsp;=&nbsp;body!&nbsp;&#123;
168
- &nbsp;&nbsp;&nbsp;&nbsp;validate():&nbsp;ValidationResult&nbsp;&#123;
169
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;validateFields(this);
170
- &nbsp;&nbsp;&nbsp;&nbsp;&#125;
171
- &#125;;
172
-
173
- //&nbsp;This&nbsp;will&nbsp;add:&nbsp;import&nbsp;&#123;&nbsp;validateFields,&nbsp;ValidationResult&nbsp;&#125;&nbsp;from&nbsp;"my-validation-lib";
174
- output.add_import("validateFields",&nbsp;"my-validation-lib");
175
- output.add_import("ValidationResult",&nbsp;"my-validation-lib");
88
+ pub fn my_macro(mut inputTsStream) -> Result<TsStreamMacroforgeError> {
89
+     let input = parse_ts_macro_input!(input as DeriveInput);
90
+
91
+     // Access class data
92
+     match &input.data {
93
+         Data::Class(class) => {
94
+             let class_name = input.name();
95
+             let fields = class.fields();
96
+             // ...
97
+         }
98
+         Data::Interface(interface) => {
99
+             // Handle interfaces
100
+         }
101
+         Data::Enum(_) => {
102
+             // Handle enums (if supported)
103
+         }
104
+     }
105
+ }
106
+ ```
107
+
108
+ ## DeriveInput Structure
109
+
110
+ Rust
111
+
112
+ ```
113
+ struct DeriveInput {
114
+     pub ident: Ident,           // The type name
115
+     pub span: SpanIR,           // Span of the type definition
116
+     pub attrs: Vec<Attribute>,  // Decorators (excluding @derive)
117
+     pub data: Data,             // The parsed type data
118
+     pub context: MacroContextIR, // Macro context with spans
119
+
120
+     // Helper methods
121
+     fn name(&self) -> &str;              // Get the type name
122
+     fn decorator_span(&self) -> SpanIR;  // Span of @derive decorator
123
+     fn as_class(&self) -> Option<&DataClass>;
124
+     fn as_interface(&self) -> Option<&DataInterface>;
125
+     fn as_enum(&self) -> Option<&DataEnum>;
126
+ }
127
+
128
+ enum Data {
129
+     Class(DataClass),
130
+     Interface(DataInterface),
131
+     Enum(DataEnum),
132
+     TypeAlias(DataTypeAlias),
133
+ }
134
+
135
+ impl DataClass {
136
+     fn fields(&self) -> &[FieldIR];
137
+     fn methods(&self) -> &[MethodSigIR];
138
+     fn field_names(&self) -> impl Iterator<Item = &str>;
139
+     fn field(&self, name: &str) -> Option<&FieldIR>;
140
+     fn body_span(&self) -> SpanIR;      // For inserting code into class body
141
+     fn type_params(&self) -> &[String]; // Generic type parameters
142
+     fn heritage(&self) -> &[String];    // extends/implements clauses
143
+     fn is_abstract(&self) -> bool;
144
+ }
145
+
146
+ impl DataInterface {
147
+     fn fields(&self) -> &[InterfaceFieldIR];
148
+     fn methods(&self) -> &[InterfaceMethodIR];
149
+     fn field_names(&self) -> impl Iterator<Item = &str>;
150
+     fn field(&self, name: &str) -> Option<&InterfaceFieldIR>;
151
+     fn body_span(&self) -> SpanIR;
152
+     fn type_params(&self) -> &[String];
153
+     fn heritage(&self) -> &[String];    // extends clauses
154
+ }
155
+
156
+ impl DataEnum {
157
+     fn variants(&self) -> &[EnumVariantIR];
158
+     fn variant_names(&self) -> impl Iterator<Item = &str>;
159
+     fn variant(&self, name: &str) -> Option<&EnumVariantIR>;
160
+ }
161
+
162
+ impl DataTypeAlias {
163
+     fn body(&self) -> &TypeBody;
164
+     fn type_params(&self) -> &[String];
165
+     fn is_union(&self) -> bool;
166
+     fn is_object(&self) -> bool;
167
+     fn as_union(&self) -> Option<&[TypeMember]>;
168
+     fn as_object(&self) -> Option<&[InterfaceFieldIR]>;
169
+ }
170
+ ```
171
+
172
+ ## Accessing Field Data
173
+
174
+ ### Class Fields (FieldIR)
175
+
176
+ Rust
177
+
178
+ ```
179
+ struct FieldIR {
180
+     pub nameString,               // Field name
181
+     pub spanSpanIR,               // Field span
182
+     pub ts_typeString,            // TypeScript type annotation
183
+     pub optionalbool,             // Whether field has ?
184
+     pub readonlybool,             // Whether field is readonly
185
+     pub visibility: Visibility,     // Public, Protected, Private
186
+     pub decorators: Vec<DecoratorIR>, // Field decorators
187
+ }
188
+ ```
189
+
190
+ ### Interface Fields (InterfaceFieldIR)
191
+
192
+ Rust
193
+
194
+ ```
195
+ struct InterfaceFieldIR {
196
+     pub name: String,
197
+     pub span: SpanIR,
198
+     pub ts_type: String,
199
+     pub optional: bool,
200
+     pub readonly: bool,
201
+     pub decorators: Vec<DecoratorIR>,
202
+     // Note: No visibility field (interfaces are always public)
203
+ }
204
+ ```
205
+
206
+ ### Enum Variants (EnumVariantIR)
207
+
208
+ Rust
209
+
210
+ ```
211
+ struct EnumVariantIR {
212
+     pub name: String,
213
+     pub span: SpanIR,
214
+     pub value: EnumValue,  // Auto, String(String), or Number(f64)
215
+     pub decorators: Vec<DecoratorIR>,
216
+ }
217
+ ```
218
+
219
+ ### Decorator Structure
220
+
221
+ Rust
222
+
223
+ ```
224
+ struct DecoratorIR {
225
+     pub name: String,      // e.g., "serde"
226
+     pub args_src: String,  // Raw args text, e.g., "skip, rename: 'id'"
227
+     pub span: SpanIR,
228
+ }
229
+ ```
230
+
231
+ Note
232
+
233
+ 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.
234
+
235
+ ## Adding Imports
236
+
237
+ If your macro generates code that requires imports, use the `add_import` method on `TsStream`:
238
+
239
+ Rust
240
+
241
+ ```
242
+ // Add an import to be inserted at the top of the file
243
+ let mut output = body! {
244
+     validate(): ValidationResult {
245
+         return validateFields(this);
246
+     }
247
+ };
248
+
249
+ // This will add: import { validateFields, ValidationResult } from "my-validation-lib";
250
+ output.add_import("validateFields", "my-validation-lib");
251
+ output.add_import("ValidationResult", "my-validation-lib");
176
252
 
177
253
  Ok(output)
178
- ``` > **Note:** Imports are automatically deduplicated. If the same import already exists in the file, it won't be added again. ## Returning Errors
179
- Use <code class="shiki-inline"><span class="line"><span style="--shiki-dark:#E1E4E8;--shiki-light:#24292E">MacroforgeError</code> to report errors with source locations:
180
- ```
254
+ ```
255
+
256
+ Note
257
+
258
+ Imports are automatically deduplicated. If the same import already exists in the file, it won't be added again.
259
+
260
+ ## Returning Errors
261
+
262
+ Use `MacroforgeError` to report errors with source locations:
263
+
264
+ Rust
265
+
266
+ ```
181
267
  #[ts_macro_derive(ClassOnly)]
182
- pub&nbsp;fn&nbsp;class_only(mut&nbsp;input:&nbsp;TsStream)&nbsp;->&nbsp;Result&#x3C;TsStream,&nbsp;MacroforgeError>&nbsp;&#123;
183
- &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;input&nbsp;=&nbsp;parse_ts_macro_input!(input&nbsp;as&nbsp;DeriveInput);
184
-
185
- &nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;&#x26;input.data&nbsp;&#123;
186
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data::Class(_)&nbsp;=>&nbsp;&#123;
187
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Generate&nbsp;code...
188
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ok(body!&nbsp;&#123;&nbsp;/*&nbsp;...&nbsp;*/&nbsp;&#125;)
189
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
190
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_&nbsp;=>&nbsp;Err(MacroforgeError::new(
191
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;input.decorator_span(),
192
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"@derive(ClassOnly)&nbsp;can&nbsp;only&nbsp;be&nbsp;used&nbsp;on&nbsp;classes",
193
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)),
194
- &nbsp;&nbsp;&nbsp;&nbsp;&#125;
195
- &#125;
196
- ``` ## Complete Example
197
- ```
198
- use&nbsp;macroforge_ts::macros::&#123;ts_macro_derive,&nbsp;body&#125;;
199
- use&nbsp;macroforge_ts::ts_syn::&#123;
200
- &nbsp;&nbsp;&nbsp;&nbsp;Data,&nbsp;DeriveInput,&nbsp;FieldIR,&nbsp;MacroforgeError,&nbsp;TsStream,&nbsp;parse_ts_macro_input,
201
- &#125;;
202
-
203
- //&nbsp;Helper&nbsp;function&nbsp;to&nbsp;check&nbsp;if&nbsp;a&nbsp;field&nbsp;has&nbsp;a&nbsp;decorator
204
- fn&nbsp;has_decorator(field:&nbsp;&#x26;FieldIR,&nbsp;name:&nbsp;&#x26;str)&nbsp;->&nbsp;bool&nbsp;&#123;
205
- &nbsp;&nbsp;&nbsp;&nbsp;field.decorators.iter().any(|d|&nbsp;d.name.eq_ignore_ascii_case(name))
206
- &#125;
268
+ pub fn class_only(mut inputTsStream) -> Result<TsStreamMacroforgeError> {
269
+     let input = parse_ts_macro_input!(input as DeriveInput);
270
+
271
+     match &input.data {
272
+         Data::Class(_) => {
273
+             // Generate code...
274
+             Ok(body! { /* ... */ })
275
+         }
276
+         _ => Err(MacroforgeError::new(
277
+             input.decorator_span(),
278
+             "@derive(ClassOnly) can only be used on classes",
279
+         )),
280
+     }
281
+ }
282
+ ```
283
+
284
+ ## Complete Example
285
+
286
+ Rust
287
+
288
+ ```
289
+ use macroforge_ts::macros::{ts_macro_derive, body};
290
+ use macroforge_ts::ts_syn::{
291
+     Data, DeriveInput, FieldIR, MacroforgeError, TsStream, parse_ts_macro_input,
292
+ };
293
+
294
+ // Helper function to check if a field has a decorator
295
+ fn has_decorator(field: &FieldIR, name: &str) -> bool {
296
+     field.decorators.iter().any(|d| d.name.eq_ignore_ascii_case(name))
297
+ }
207
298
 
208
299
  #[ts_macro_derive(
209
- &nbsp;&nbsp;&nbsp;&nbsp;Validate,
210
- &nbsp;&nbsp;&nbsp;&nbsp;description&nbsp;=&nbsp;"Generates&nbsp;a&nbsp;validate()&nbsp;method",
211
- &nbsp;&nbsp;&nbsp;&nbsp;attributes(validate)
300
+     Validate,
301
+     description = "Generates a validate() method",
302
+     attributes(validate)
212
303
  )]
213
- pub&nbsp;fn&nbsp;derive_validate(mut&nbsp;input:&nbsp;TsStream)&nbsp;->&nbsp;Result&#x3C;TsStream,&nbsp;MacroforgeError>&nbsp;&#123;
214
- &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;input&nbsp;=&nbsp;parse_ts_macro_input!(input&nbsp;as&nbsp;DeriveInput);
215
-
216
- &nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;&#x26;input.data&nbsp;&#123;
217
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data::Class(class)&nbsp;=>&nbsp;&#123;
218
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;validations:&nbsp;Vec&#x3C;_>&nbsp;=&nbsp;class.fields()
219
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.iter()
220
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.filter(|f|&nbsp;has_decorator(f,&nbsp;"validate"))
221
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.collect();
222
-
223
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ok(body!&nbsp;&#123;
224
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;validate():&nbsp;string[]&nbsp;&#123;
225
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;errors:&nbsp;string[]&nbsp;=&nbsp;[];
226
- &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;validations&#125;
227
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!this.@&#123;field.name&#125;)&nbsp;&#123;
228
- &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;errors.push("@&#123;field.name&#125;&nbsp;is&nbsp;required");
229
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
230
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;/for&#125;
231
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;errors;
232
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
233
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;)
234
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
235
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_&nbsp;=>&nbsp;Err(MacroforgeError::new(
236
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;input.decorator_span(),
237
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"@derive(Validate)&nbsp;only&nbsp;works&nbsp;on&nbsp;classes",
238
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)),
239
- &nbsp;&nbsp;&nbsp;&nbsp;&#125;
240
- &#125;
241
- ``` ## Next Steps
242
- - [Learn the template syntax](../../docs/custom-macros/ts-quote)
304
+ pub fn derive_validate(mut inputTsStream) -> Result<TsStreamMacroforgeError> {
305
+     let input = parse_ts_macro_input!(input as DeriveInput);
306
+
307
+     match &input.data {
308
+         Data::Class(class) => {
309
+             let validationsVec<_> = class.fields()
310
+                 .iter()
311
+                 .filter(|fhas_decorator(f"validate"))
312
+                 .collect();
313
+
314
+             Ok(body! {
315
+                 validate()string[] {
316
+                     const errorsstring[] = [];
317
+                     {#for field in validations}
318
+                         if (!this.@{field.name}) {
319
+                             errors.push("@{field.nameis required");
320
+                         }
321
+                     {/for}
322
+                     return errors;
323
+                 }
324
+             })
325
+         }
326
+         _ => Err(MacroforgeError::new(
327
+             input.decorator_span(),
328
+             "@derive(Validate) only works on classes",
329
+         )),
330
+     }
331
+ }
332
+ ```
333
+
334
+ ## Next Steps
335
+
336
+ * [Learn the template syntax](../../docs/custom-macros/ts-quote)
@@ -2,28 +2,40 @@
2
2
 
3
3
  For JavaScript template literals (backtick strings), use the `'^...^'` syntax. This outputs actual backticks and passes through `${"${}"}` for JS interpolation:
4
4
 
5
- ```rust
5
+ Rust
6
+
7
+ ```
6
8
  let tag_name = "div";
7
9
 
8
10
  let code = ts_template! {
9
- const html = "'^<@{tag_name}>\${content}</@{tag_name}>^'";
11
+ const html = "'^<@{tag_name}>${content}</@{tag_name}>^'";
10
12
  };
11
13
  ```
12
14
 
13
15
  **Generates:**
14
16
 
15
- <CodeBlock code={'const html = `${content}`;'} lang="typescript" />
17
+ TypeScript
18
+
19
+ ```
20
+ const html = `<div>${content}</div>`;
21
+ ```
16
22
 
17
- You can mix Rust `@&#123;&#125;` interpolation (evaluated at macro expansion time) with JS `${"${}"}` interpolation (evaluated at runtime):
23
+ You can mix Rust `@{}` interpolation (evaluated at macro expansion time) with JS `${"${}"}` interpolation (evaluated at runtime):
18
24
 
19
- ```rust
25
+ Rust
26
+
27
+ ```
20
28
  let class_name = "User";
21
29
 
22
30
  let code = ts_template! {
23
- "'^Hello \${this.name}, you are a @{class_name}^'"
31
+ "'^Hello ${this.name}, you are a @{class_name}^'"
24
32
  };
25
33
  ```
26
34
 
27
35
  **Generates:**
28
36
 
29
- <CodeBlock code={'`Hello ${this.name}, you are a User`'} lang="typescript" />
37
+ TypeScript
38
+
39
+ ```
40
+ `Hello ${this.name}, you are a User`
41
+ ```