@macroforge/mcp-server 0.1.38 → 0.1.40
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.
- package/docs/api/api-overview.md +13 -13
- package/docs/api/expand-sync.md +8 -8
- package/docs/api/native-plugin.md +15 -15
- package/docs/api/position-mapper.md +6 -6
- package/docs/api/transform-sync.md +11 -11
- package/docs/builtin-macros/default.md +6 -6
- package/docs/builtin-macros/macros-overview.md +40 -40
- package/docs/concepts/architecture.md +2 -2
- package/docs/concepts/derive-system.md +5 -5
- package/docs/custom-macros/custom-overview.md +23 -23
- package/docs/custom-macros/rust-setup.md +31 -31
- package/docs/custom-macros/ts-macro-derive.md +107 -107
- package/docs/custom-macros/ts-quote.md +226 -226
- package/docs/getting-started/first-macro.md +2 -2
- package/docs/getting-started/installation.md +15 -15
- package/docs/integration/cli.md +9 -9
- package/docs/integration/configuration.md +16 -16
- package/docs/integration/mcp-server.md +6 -6
- package/docs/integration/svelte-preprocessor.md +40 -41
- package/docs/integration/typescript-plugin.md +13 -12
- package/docs/integration/vite-plugin.md +12 -12
- package/docs/language-servers/zed.md +1 -1
- package/package.json +2 -2
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
## Basic Syntax
|
|
4
4
|
```
|
|
5
5
|
use macroforge_ts::macros::ts_macro_derive;
|
|
6
|
-
use macroforge_ts::ts_syn
|
|
6
|
+
use macroforge_ts::ts_syn::{TsStream, MacroforgeError};
|
|
7
7
|
|
|
8
8
|
#[ts_macro_derive(MacroName)]
|
|
9
|
-
pub fn my_macro(mut input: TsStream) -> Result
|
|
9
|
+
pub fn my_macro(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
|
|
10
10
|
// Macro implementation
|
|
11
|
-
|
|
11
|
+
}
|
|
12
12
|
``` ## Attribute Options
|
|
13
13
|
### Name (Required)
|
|
14
14
|
The first argument is the macro name that users will reference in `@derive()`:
|
|
@@ -29,12 +29,12 @@ pub fn derive_json(...)
|
|
|
29
29
|
#[ts_macro_derive(
|
|
30
30
|
Debug,
|
|
31
31
|
description = "Generates toString()",
|
|
32
|
-
attributes(debug) // Allows @debug(
|
|
32
|
+
attributes(debug) // Allows @debug({ ... }) on fields
|
|
33
33
|
)]
|
|
34
34
|
pub fn derive_debug(...)
|
|
35
35
|
``` > **Note:** Declared attributes become available as @attributeName({ options }) decorators in TypeScript. ## Function Signature
|
|
36
36
|
```
|
|
37
|
-
pub fn my_macro(mut input: TsStream) -> Result
|
|
37
|
+
pub fn my_macro(mut input: TsStream) -> Result<TsStream, MacroforgeError>
|
|
38
38
|
``` | Parameter | Description |
|
|
39
39
|
| --- | --- |
|
|
40
40
|
| `input: TsStream` | Token stream containing the class/interface AST |
|
|
@@ -42,135 +42,135 @@ pub fn my_macro(mut input: TsStream) -> Result<TsStream, MacroforgeError>
|
|
|
42
42
|
## Parsing Input
|
|
43
43
|
Use `parse_ts_macro_input!` to convert the token stream:
|
|
44
44
|
```
|
|
45
|
-
use macroforge_ts::ts_syn
|
|
45
|
+
use macroforge_ts::ts_syn::{Data, DeriveInput, parse_ts_macro_input};
|
|
46
46
|
|
|
47
47
|
#[ts_macro_derive(MyMacro)]
|
|
48
|
-
pub fn my_macro(mut input: TsStream) -> Result
|
|
48
|
+
pub fn my_macro(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
|
|
49
49
|
let input = parse_ts_macro_input!(input as DeriveInput);
|
|
50
50
|
|
|
51
51
|
// Access class data
|
|
52
|
-
match
|
|
53
|
-
Data::Class(class) =>
|
|
52
|
+
match &input.data {
|
|
53
|
+
Data::Class(class) => {
|
|
54
54
|
let class_name = input.name();
|
|
55
55
|
let fields = class.fields();
|
|
56
56
|
// ...
|
|
57
|
-
|
|
58
|
-
Data::Interface(interface) =>
|
|
57
|
+
}
|
|
58
|
+
Data::Interface(interface) => {
|
|
59
59
|
// Handle interfaces
|
|
60
|
-
|
|
61
|
-
Data::Enum(_) =>
|
|
60
|
+
}
|
|
61
|
+
Data::Enum(_) => {
|
|
62
62
|
// Handle enums (if supported)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
66
|
``` ## DeriveInput Structure
|
|
67
67
|
```
|
|
68
|
-
struct DeriveInput
|
|
68
|
+
struct DeriveInput {
|
|
69
69
|
pub ident: Ident, // The type name
|
|
70
70
|
pub span: SpanIR, // Span of the type definition
|
|
71
|
-
pub attrs: Vec
|
|
71
|
+
pub attrs: Vec<Attribute>, // Decorators (excluding @derive)
|
|
72
72
|
pub data: Data, // The parsed type data
|
|
73
73
|
pub context: MacroContextIR, // Macro context with spans
|
|
74
74
|
|
|
75
75
|
// Helper methods
|
|
76
|
-
fn name(
|
|
77
|
-
fn decorator_span(
|
|
78
|
-
fn as_class(
|
|
79
|
-
fn as_interface(
|
|
80
|
-
fn as_enum(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
enum Data
|
|
76
|
+
fn name(&self) -> &str; // Get the type name
|
|
77
|
+
fn decorator_span(&self) -> SpanIR; // Span of @derive decorator
|
|
78
|
+
fn as_class(&self) -> Option<&DataClass>;
|
|
79
|
+
fn as_interface(&self) -> Option<&DataInterface>;
|
|
80
|
+
fn as_enum(&self) -> Option<&DataEnum>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
enum Data {
|
|
84
84
|
Class(DataClass),
|
|
85
85
|
Interface(DataInterface),
|
|
86
86
|
Enum(DataEnum),
|
|
87
87
|
TypeAlias(DataTypeAlias),
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
impl DataClass
|
|
91
|
-
fn fields(
|
|
92
|
-
fn methods(
|
|
93
|
-
fn field_names(
|
|
94
|
-
fn field(
|
|
95
|
-
fn body_span(
|
|
96
|
-
fn type_params(
|
|
97
|
-
fn heritage(
|
|
98
|
-
fn is_abstract(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
impl DataInterface
|
|
102
|
-
fn fields(
|
|
103
|
-
fn methods(
|
|
104
|
-
fn field_names(
|
|
105
|
-
fn field(
|
|
106
|
-
fn body_span(
|
|
107
|
-
fn type_params(
|
|
108
|
-
fn heritage(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
impl DataEnum
|
|
112
|
-
fn variants(
|
|
113
|
-
fn variant_names(
|
|
114
|
-
fn variant(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
impl DataTypeAlias
|
|
118
|
-
fn body(
|
|
119
|
-
fn type_params(
|
|
120
|
-
fn is_union(
|
|
121
|
-
fn is_object(
|
|
122
|
-
fn as_union(
|
|
123
|
-
fn as_object(
|
|
124
|
-
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
impl DataClass {
|
|
91
|
+
fn fields(&self) -> &[FieldIR];
|
|
92
|
+
fn methods(&self) -> &[MethodSigIR];
|
|
93
|
+
fn field_names(&self) -> impl Iterator<Item = &str>;
|
|
94
|
+
fn field(&self, name: &str) -> Option<&FieldIR>;
|
|
95
|
+
fn body_span(&self) -> SpanIR; // For inserting code into class body
|
|
96
|
+
fn type_params(&self) -> &[String]; // Generic type parameters
|
|
97
|
+
fn heritage(&self) -> &[String]; // extends/implements clauses
|
|
98
|
+
fn is_abstract(&self) -> bool;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
impl DataInterface {
|
|
102
|
+
fn fields(&self) -> &[InterfaceFieldIR];
|
|
103
|
+
fn methods(&self) -> &[InterfaceMethodIR];
|
|
104
|
+
fn field_names(&self) -> impl Iterator<Item = &str>;
|
|
105
|
+
fn field(&self, name: &str) -> Option<&InterfaceFieldIR>;
|
|
106
|
+
fn body_span(&self) -> SpanIR;
|
|
107
|
+
fn type_params(&self) -> &[String];
|
|
108
|
+
fn heritage(&self) -> &[String]; // extends clauses
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
impl DataEnum {
|
|
112
|
+
fn variants(&self) -> &[EnumVariantIR];
|
|
113
|
+
fn variant_names(&self) -> impl Iterator<Item = &str>;
|
|
114
|
+
fn variant(&self, name: &str) -> Option<&EnumVariantIR>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
impl DataTypeAlias {
|
|
118
|
+
fn body(&self) -> &TypeBody;
|
|
119
|
+
fn type_params(&self) -> &[String];
|
|
120
|
+
fn is_union(&self) -> bool;
|
|
121
|
+
fn is_object(&self) -> bool;
|
|
122
|
+
fn as_union(&self) -> Option<&[TypeMember]>;
|
|
123
|
+
fn as_object(&self) -> Option<&[InterfaceFieldIR]>;
|
|
124
|
+
}
|
|
125
125
|
``` ## Accessing Field Data
|
|
126
126
|
### Class Fields (FieldIR)
|
|
127
127
|
```
|
|
128
|
-
struct FieldIR
|
|
128
|
+
struct FieldIR {
|
|
129
129
|
pub name: String, // Field name
|
|
130
130
|
pub span: SpanIR, // Field span
|
|
131
131
|
pub ts_type: String, // TypeScript type annotation
|
|
132
132
|
pub optional: bool, // Whether field has ?
|
|
133
133
|
pub readonly: bool, // Whether field is readonly
|
|
134
134
|
pub visibility: Visibility, // Public, Protected, Private
|
|
135
|
-
pub decorators: Vec
|
|
136
|
-
|
|
135
|
+
pub decorators: Vec<DecoratorIR>, // Field decorators
|
|
136
|
+
}
|
|
137
137
|
``` ### Interface Fields (InterfaceFieldIR)
|
|
138
138
|
```
|
|
139
|
-
struct InterfaceFieldIR
|
|
139
|
+
struct InterfaceFieldIR {
|
|
140
140
|
pub name: String,
|
|
141
141
|
pub span: SpanIR,
|
|
142
142
|
pub ts_type: String,
|
|
143
143
|
pub optional: bool,
|
|
144
144
|
pub readonly: bool,
|
|
145
|
-
pub decorators: Vec
|
|
145
|
+
pub decorators: Vec<DecoratorIR>,
|
|
146
146
|
// Note: No visibility field (interfaces are always public)
|
|
147
|
-
|
|
147
|
+
}
|
|
148
148
|
``` ### Enum Variants (EnumVariantIR)
|
|
149
149
|
```
|
|
150
|
-
struct EnumVariantIR
|
|
150
|
+
struct EnumVariantIR {
|
|
151
151
|
pub name: String,
|
|
152
152
|
pub span: SpanIR,
|
|
153
153
|
pub value: EnumValue, // Auto, String(String), or Number(f64)
|
|
154
|
-
pub decorators: Vec
|
|
155
|
-
|
|
154
|
+
pub decorators: Vec<DecoratorIR>,
|
|
155
|
+
}
|
|
156
156
|
``` ### Decorator Structure
|
|
157
157
|
```
|
|
158
|
-
struct DecoratorIR
|
|
158
|
+
struct DecoratorIR {
|
|
159
159
|
pub name: String, // e.g., "serde"
|
|
160
160
|
pub args_src: String, // Raw args text, e.g., "skip, rename: 'id'"
|
|
161
161
|
pub span: SpanIR,
|
|
162
|
-
|
|
162
|
+
}
|
|
163
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
164
|
If your macro generates code that requires imports, use the `add_import` method on `TsStream`:
|
|
165
165
|
```
|
|
166
166
|
// Add an import to be inserted at the top of the file
|
|
167
|
-
let mut output = body!
|
|
168
|
-
validate(): ValidationResult
|
|
167
|
+
let mut output = body! {
|
|
168
|
+
validate(): ValidationResult {
|
|
169
169
|
return validateFields(this);
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
172
|
|
|
173
|
-
// This will add: import
|
|
173
|
+
// This will add: import { validateFields, ValidationResult } from "my-validation-lib";
|
|
174
174
|
output.add_import("validateFields", "my-validation-lib");
|
|
175
175
|
output.add_import("ValidationResult", "my-validation-lib");
|
|
176
176
|
|
|
@@ -179,64 +179,64 @@ Ok(output)
|
|
|
179
179
|
Use `MacroforgeError` to report errors with source locations:
|
|
180
180
|
```
|
|
181
181
|
#[ts_macro_derive(ClassOnly)]
|
|
182
|
-
pub fn class_only(mut input: TsStream) -> Result
|
|
182
|
+
pub fn class_only(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
|
|
183
183
|
let input = parse_ts_macro_input!(input as DeriveInput);
|
|
184
184
|
|
|
185
|
-
match
|
|
186
|
-
Data::Class(_) =>
|
|
185
|
+
match &input.data {
|
|
186
|
+
Data::Class(_) => {
|
|
187
187
|
// Generate code...
|
|
188
|
-
Ok(body!
|
|
189
|
-
|
|
188
|
+
Ok(body! { /* ... */ })
|
|
189
|
+
}
|
|
190
190
|
_ => Err(MacroforgeError::new(
|
|
191
191
|
input.decorator_span(),
|
|
192
192
|
"@derive(ClassOnly) can only be used on classes",
|
|
193
193
|
)),
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
196
|
``` ## Complete Example
|
|
197
197
|
```
|
|
198
|
-
use macroforge_ts::macros
|
|
199
|
-
use macroforge_ts::ts_syn
|
|
198
|
+
use macroforge_ts::macros::{ts_macro_derive, body};
|
|
199
|
+
use macroforge_ts::ts_syn::{
|
|
200
200
|
Data, DeriveInput, FieldIR, MacroforgeError, TsStream, parse_ts_macro_input,
|
|
201
|
-
|
|
201
|
+
};
|
|
202
202
|
|
|
203
203
|
// Helper function to check if a field has a decorator
|
|
204
|
-
fn has_decorator(field:
|
|
204
|
+
fn has_decorator(field: &FieldIR, name: &str) -> bool {
|
|
205
205
|
field.decorators.iter().any(|d| d.name.eq_ignore_ascii_case(name))
|
|
206
|
-
|
|
206
|
+
}
|
|
207
207
|
|
|
208
208
|
#[ts_macro_derive(
|
|
209
209
|
Validate,
|
|
210
210
|
description = "Generates a validate() method",
|
|
211
211
|
attributes(validate)
|
|
212
212
|
)]
|
|
213
|
-
pub fn derive_validate(mut input: TsStream) -> Result
|
|
213
|
+
pub fn derive_validate(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
|
|
214
214
|
let input = parse_ts_macro_input!(input as DeriveInput);
|
|
215
215
|
|
|
216
|
-
match
|
|
217
|
-
Data::Class(class) =>
|
|
218
|
-
let validations: Vec
|
|
216
|
+
match &input.data {
|
|
217
|
+
Data::Class(class) => {
|
|
218
|
+
let validations: Vec<_> = class.fields()
|
|
219
219
|
.iter()
|
|
220
220
|
.filter(|f| has_decorator(f, "validate"))
|
|
221
221
|
.collect();
|
|
222
222
|
|
|
223
|
-
Ok(body!
|
|
224
|
-
validate(): string[]
|
|
223
|
+
Ok(body! {
|
|
224
|
+
validate(): string[] {
|
|
225
225
|
const errors: string[] = [];
|
|
226
|
-
|
|
227
|
-
if (!this
|
|
228
|
-
errors.push("
|
|
229
|
-
|
|
230
|
-
|
|
226
|
+
{#for field in validations}
|
|
227
|
+
if (!this.@{field.name}) {
|
|
228
|
+
errors.push("@{field.name} is required");
|
|
229
|
+
}
|
|
230
|
+
{/for}
|
|
231
231
|
return errors;
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
}
|
|
235
235
|
_ => Err(MacroforgeError::new(
|
|
236
236
|
input.decorator_span(),
|
|
237
237
|
"@derive(Validate) only works on classes",
|
|
238
238
|
)),
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
241
|
``` ## Next Steps
|
|
242
242
|
- [Learn the template syntax](../../docs/custom-macros/ts-quote)
|