@macroforge/mcp-server 0.1.37 → 0.1.39
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/clone.md +43 -23
- package/docs/builtin-macros/debug.md +50 -18
- package/docs/builtin-macros/default.md +79 -28
- package/docs/builtin-macros/deserialize/cycleforward-reference-support.md +11 -0
- package/docs/builtin-macros/deserialize/example.md +1625 -0
- package/docs/builtin-macros/deserialize/overview.md +15 -10
- package/docs/builtin-macros/deserialize/union-type-deserialization.md +27 -0
- package/docs/builtin-macros/deserialize/validation.md +34 -0
- package/docs/builtin-macros/deserialize.md +1608 -23
- package/docs/builtin-macros/hash.md +87 -20
- package/docs/builtin-macros/macros-overview.md +40 -40
- package/docs/builtin-macros/ord.md +56 -31
- package/docs/builtin-macros/partial-eq/example.md +526 -0
- package/docs/builtin-macros/partial-eq/overview.md +39 -0
- package/docs/builtin-macros/partial-eq.md +184 -26
- package/docs/builtin-macros/partial-ord.md +68 -30
- package/docs/builtin-macros/serialize/example.md +139 -0
- package/docs/builtin-macros/serialize/overview.md +32 -0
- package/docs/builtin-macros/serialize/type-specific-serialization.md +22 -0
- package/docs/builtin-macros/serialize.md +130 -28
- package/docs/concepts/architecture.md +2 -2
- package/docs/concepts/derive-system.md +25 -39
- package/docs/concepts/how-macros-work.md +8 -4
- 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 +38 -28
- 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/docs/sections.json +88 -2
- package/package.json +2 -2
|
@@ -8,18 +8,10 @@ including circular references.
|
|
|
8
8
|
|
|
9
9
|
| Type | Generated Code | Description |
|
|
10
10
|
|------|----------------|-------------|
|
|
11
|
-
| Class | `
|
|
12
|
-
| Enum | `
|
|
13
|
-
| Interface | `
|
|
14
|
-
| Type Alias | `
|
|
15
|
-
|
|
16
|
-
## Configuration
|
|
17
|
-
|
|
18
|
-
The `functionNamingStyle` option in `macroforge.json` controls naming:
|
|
19
|
-
- `"prefix"` (default): Prefixes with type name (e.g., `myTypeToStringifiedJSON`)
|
|
20
|
-
- `"suffix"`: Suffixes with type name (e.g., `toStringifiedJSONMyType`)
|
|
21
|
-
- `"generic"`: Uses TypeScript generics (e.g., `toStringifiedJSON<T extends MyType>`)
|
|
22
|
-
- `"namespace"`: Legacy namespace wrapping
|
|
11
|
+
| Class | `classNameSerialize(value)` + `static serialize(value)` | Standalone function + static wrapper method |
|
|
12
|
+
| Enum | `enumNameSerialize(value)`, `enumNameSerializeWithContext` | Standalone functions |
|
|
13
|
+
| Interface | `interfaceNameSerialize(value)`, etc. | Standalone functions |
|
|
14
|
+
| Type Alias | `typeNameSerialize(value)`, etc. | Standalone functions |
|
|
23
15
|
|
|
24
16
|
## Cycle Detection Protocol
|
|
25
17
|
|
|
@@ -45,11 +37,11 @@ When an object is serialized:
|
|
|
45
37
|
|------|------------------------|
|
|
46
38
|
| Primitives | Direct value |
|
|
47
39
|
| `Date` | `toISOString()` |
|
|
48
|
-
| Arrays | For primitive-like element types, pass through; for `Date`/`Date | null`, map to ISO strings; otherwise map and call `
|
|
49
|
-
| `Map<K,V>` | For primitive-like values, `Object.fromEntries(map.entries())`; for `Date`/`Date | null`, convert to ISO strings; otherwise call `
|
|
40
|
+
| Arrays | For primitive-like element types, pass through; for `Date`/`Date | null`, map to ISO strings; otherwise map and call `SerializeWithContext(ctx)` when available |
|
|
41
|
+
| `Map<K,V>` | For primitive-like values, `Object.fromEntries(map.entries())`; for `Date`/`Date | null`, convert to ISO strings; otherwise call `SerializeWithContext(ctx)` per value when available |
|
|
50
42
|
| `Set<T>` | Convert to array; element handling matches `Array<T>` |
|
|
51
|
-
| Nullable | Include `null` explicitly; for primitive-like and `Date` unions the generator avoids runtime `
|
|
52
|
-
| Objects | Call `
|
|
43
|
+
| Nullable | Include `null` explicitly; for primitive-like and `Date` unions the generator avoids runtime `SerializeWithContext` checks |
|
|
44
|
+
| Objects | Call `SerializeWithContext(ctx)` if available (to support user-defined implementations) |
|
|
53
45
|
|
|
54
46
|
Note: the generator specializes some code paths based on the declared TypeScript type to
|
|
55
47
|
avoid runtime feature detection on primitives and literal unions.
|
|
@@ -58,34 +50,144 @@ avoid runtime feature detection on primitives and literal unions.
|
|
|
58
50
|
|
|
59
51
|
The `@serde` decorator supports:
|
|
60
52
|
|
|
61
|
-
- `skip` / `
|
|
53
|
+
- `skip` / `skipSerializing` - Exclude field from serialization
|
|
62
54
|
- `rename = "jsonKey"` - Use different JSON property name
|
|
63
55
|
- `flatten` - Merge nested object's fields into parent
|
|
64
56
|
|
|
65
57
|
## Example
|
|
66
58
|
|
|
67
|
-
```typescript
|
|
68
|
-
@derive(Serialize)
|
|
59
|
+
```typescript before
|
|
60
|
+
/** @derive(Serialize) */
|
|
69
61
|
class User {
|
|
70
62
|
id: number;
|
|
71
63
|
|
|
72
|
-
@serde(rename
|
|
64
|
+
/** @serde({ rename: "userName" }) */
|
|
73
65
|
name: string;
|
|
74
66
|
|
|
75
|
-
@serde(
|
|
67
|
+
/** @serde({ skipSerializing: true }) */
|
|
76
68
|
password: string;
|
|
77
69
|
|
|
78
|
-
@serde(flatten)
|
|
70
|
+
/** @serde({ flatten: true }) */
|
|
79
71
|
metadata: UserMetadata;
|
|
80
72
|
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```typescript after
|
|
76
|
+
import { SerializeContext } from 'macroforge/serde';
|
|
77
|
+
|
|
78
|
+
class User {
|
|
79
|
+
id: number;
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
name: string;
|
|
82
|
+
|
|
83
|
+
password: string;
|
|
84
|
+
|
|
85
|
+
metadata: UserMetadata;
|
|
86
|
+
/** Serializes a value to a JSON string.
|
|
87
|
+
@param value - The value to serialize
|
|
88
|
+
@returns JSON string representation with cycle detection metadata */
|
|
89
|
+
|
|
90
|
+
static serialize(value: User): string {
|
|
91
|
+
return userSerialize(value);
|
|
92
|
+
}
|
|
93
|
+
/** @internal Serializes with an existing context for nested/cyclic object graphs.
|
|
94
|
+
@param value - The value to serialize
|
|
95
|
+
@param ctx - The serialization context */
|
|
96
|
+
|
|
97
|
+
static serializeWithContext(value: User, ctx: SerializeContext): Record<string, unknown> {
|
|
98
|
+
return userSerializeWithContext(value, ctx);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
86
101
|
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
/** Serializes a value to a JSON string.
|
|
103
|
+
@param value - The value to serialize
|
|
104
|
+
@returns JSON string representation with cycle detection metadata */ export function userSerialize(
|
|
105
|
+
value: User
|
|
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();
|
|
168
|
+
return JSON.stringify(userSerializeWithContext(value, ctx));
|
|
169
|
+
} /** @internal Serializes with an existing context for nested/cyclic object graphs.
|
|
170
|
+
@param value - The value to serialize
|
|
171
|
+
@param ctx - The serialization context */
|
|
172
|
+
export function userSerializeWithContext(
|
|
173
|
+
value: User,
|
|
174
|
+
ctx: SerializeContext
|
|
175
|
+
): Record<string, unknown> {
|
|
176
|
+
const existingId = ctx.getId(value);
|
|
177
|
+
if (existingId !== undefined) {
|
|
178
|
+
return { __ref: existingId };
|
|
179
|
+
}
|
|
180
|
+
const __id = ctx.register(value);
|
|
181
|
+
const result: Record<string, unknown> = { __type: 'User', __id };
|
|
182
|
+
result['id'] = value.id;
|
|
183
|
+
result['userName'] = value.name;
|
|
184
|
+
{
|
|
185
|
+
const __flattened = userMetadataSerializeWithContext(value.metadata, ctx);
|
|
186
|
+
const { __type: _, __id: __, ...rest } = __flattened as any;
|
|
187
|
+
Object.assign(result, rest);
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
89
191
|
```
|
|
90
192
|
|
|
91
193
|
## Required Import
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
For custom macro development, `macroforge_ts` re-exports everything you need:
|
|
38
38
|
```
|
|
39
39
|
// Convenient re-exports for macro development
|
|
40
|
-
use macroforge_ts::macros
|
|
41
|
-
use macroforge_ts::ts_syn
|
|
40
|
+
use macroforge_ts::macros::{ts_macro_derive, body, ts_template, above, below, signature};
|
|
41
|
+
use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
|
|
42
42
|
|
|
43
43
|
// Also available: raw crate access and SWC modules
|
|
44
44
|
use macroforge_ts::swc_core;
|
|
@@ -25,21 +25,21 @@ class User {
|
|
|
25
25
|
``` ### The import macro Statement
|
|
26
26
|
To use macros from external packages, you must declare them with `import macro`:
|
|
27
27
|
```
|
|
28
|
-
/** import macro
|
|
28
|
+
/** import macro { MacroName } from "package-name"; */
|
|
29
29
|
``` Syntax rules:
|
|
30
30
|
- Must be inside a JSDoc comment (`/** */`)
|
|
31
31
|
- Can appear anywhere in the file (typically at the top)
|
|
32
32
|
- Multiple macros can be imported: `import macro { A, B } from "pkg";`
|
|
33
33
|
- Multiple import statements can be used for different packages
|
|
34
34
|
```
|
|
35
|
-
/** import macro
|
|
36
|
-
/** import macro
|
|
35
|
+
/** import macro { JSON, Validate } from "@my/macros"; */
|
|
36
|
+
/** import macro { Builder } from "@other/macros"; */
|
|
37
37
|
|
|
38
38
|
/** @derive(JSON, Validate, Builder) */
|
|
39
|
-
class User
|
|
39
|
+
class User {
|
|
40
40
|
name: string;
|
|
41
41
|
email: string;
|
|
42
|
-
|
|
42
|
+
}
|
|
43
43
|
``` **Built-in macros Built-in macros (Debug, Clone, Default, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize) do not require an import statement. ### Field Attributes
|
|
44
44
|
Macros can define field-level attributes to customize behavior per field:
|
|
45
45
|
****Before:**
|
|
@@ -78,46 +78,32 @@ class User {
|
|
|
78
78
|
|
|
79
79
|
metadata: Record<string, unknown>;
|
|
80
80
|
|
|
81
|
-
toString(): string {
|
|
82
|
-
|
|
83
|
-
parts.push("userId: " + this.id);
|
|
84
|
-
parts.push("name: " + this.name);
|
|
85
|
-
parts.push("metadata: " + this.metadata);
|
|
86
|
-
return "User { " + parts.join(", ") + " }";
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
toStringifiedJSON(): string {
|
|
90
|
-
const ctx = SerializeContext.create();
|
|
91
|
-
return JSON.stringify(this.__serialize(ctx));
|
|
81
|
+
static toString(value: User): string {
|
|
82
|
+
return userToString(value);
|
|
92
83
|
}
|
|
84
|
+
/** Serializes a value to a JSON string.
|
|
85
|
+
@param value - The value to serialize
|
|
86
|
+
@returns JSON string representation with cycle detection metadata */
|
|
93
87
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return this.__serialize(ctx);
|
|
88
|
+
static serialize(value: User): string {
|
|
89
|
+
return userSerialize(value);
|
|
97
90
|
}
|
|
91
|
+
/** @internal Serializes with an existing context for nested/cyclic object graphs.
|
|
92
|
+
@param value - The value to serialize
|
|
93
|
+
@param ctx - The serialization context */
|
|
98
94
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (existingId !== undefined) {
|
|
102
|
-
return {
|
|
103
|
-
__ref: existingId
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
const __id = ctx.register(this);
|
|
107
|
-
const result: Record<string, unknown> = {
|
|
108
|
-
__type: "User",
|
|
109
|
-
__id
|
|
110
|
-
};
|
|
111
|
-
result["user_id"] = this.id;
|
|
112
|
-
result["name"] = this.name;
|
|
113
|
-
{
|
|
114
|
-
const __flattened = record < string, unknown;
|
|
115
|
-
const { __type: _, __id: __, ...rest } = __flattened as any;
|
|
116
|
-
Object.assign(result, rest);
|
|
117
|
-
}
|
|
118
|
-
return result;
|
|
95
|
+
static serializeWithContext(value: User, ctx: SerializeContext): Record<string, unknown> {
|
|
96
|
+
return userSerializeWithContext(value, ctx);
|
|
119
97
|
}
|
|
120
98
|
}
|
|
99
|
+
|
|
100
|
+
export function userToString(value: User): string {const parts: string[]= []; parts.push("userId: " + value.id); parts.push("name: " + value.name); parts.push("metadata: " + value.metadata); return "User { " + parts.join(", " )+ " }" ; }
|
|
101
|
+
|
|
102
|
+
/** Serializes a value to a JSON string.
|
|
103
|
+
@param value - The value to serialize
|
|
104
|
+
@returns JSON string representation with cycle detection metadata */export function userSerialize(value: User): string {const ctx = SerializeContext.create(); return JSON.stringify(userSerializeWithContext(value, ctx));}/** @internal Serializes with an existing context for nested/cyclic object graphs.
|
|
105
|
+
@param value - The value to serialize
|
|
106
|
+
@param ctx - The serialization context */export function userSerializeWithContext(value: User, ctx: SerializeContext): Record<string, unknown>{const existingId = ctx.getId(value); if(existingId!== undefined){return {__ref: existingId};}const __id = ctx.register(value); const result: Record<string, unknown>= {__type: "User" , __id,}; result["user_id" ]= value.id; result["name" ]= value.name; {const __flattened = record<string, unknown>SerializeWithContext(value.metadata, ctx); const {__type: _, __id: __,...rest}= __flattened as any; Object.assign(result, rest);}return result;}
|
|
121
107
|
``` Syntax rules:
|
|
122
108
|
- Must be inside a JSDoc comment immediately before the field
|
|
123
109
|
- Options use object literal syntax: `@attr({ key: value })`
|
|
@@ -18,12 +18,16 @@ class User {
|
|
|
18
18
|
class User {
|
|
19
19
|
name: string;
|
|
20
20
|
|
|
21
|
-
toString(): string {
|
|
22
|
-
|
|
23
|
-
parts.push('name: ' + this.name);
|
|
24
|
-
return 'User { ' + parts.join(', ') + ' }';
|
|
21
|
+
static toString(value: User): string {
|
|
22
|
+
return userToString(value);
|
|
25
23
|
}
|
|
26
24
|
}
|
|
25
|
+
|
|
26
|
+
export function userToString(value: User): string {
|
|
27
|
+
const parts: string[] = [];
|
|
28
|
+
parts.push('name: ' + value.name);
|
|
29
|
+
return 'User { ' + parts.join(', ') + ' }';
|
|
30
|
+
}
|
|
27
31
|
``` ## Zero Runtime Overhead
|
|
28
32
|
Because code generation happens at compile time, there's no:
|
|
29
33
|
- Runtime reflection or metadata
|
|
@@ -8,52 +8,52 @@
|
|
|
8
8
|
4. Building and publishing as an npm package
|
|
9
9
|
## Quick Example
|
|
10
10
|
```
|
|
11
|
-
use macroforge_ts::macros
|
|
12
|
-
use macroforge_ts::ts_syn
|
|
11
|
+
use macroforge_ts::macros::{ts_macro_derive, body};
|
|
12
|
+
use macroforge_ts::ts_syn::{Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input};
|
|
13
13
|
|
|
14
14
|
#[ts_macro_derive(
|
|
15
15
|
JSON,
|
|
16
16
|
description = "Generates toJSON() returning a plain object"
|
|
17
17
|
)]
|
|
18
|
-
pub fn derive_json(mut input: TsStream) -> Result
|
|
18
|
+
pub fn derive_json(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
|
|
19
19
|
let input = parse_ts_macro_input!(input as DeriveInput);
|
|
20
20
|
|
|
21
|
-
match
|
|
22
|
-
Data::Class(class) =>
|
|
23
|
-
Ok(body!
|
|
24
|
-
toJSON(): Record
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
match &input.data {
|
|
22
|
+
Data::Class(class) => {
|
|
23
|
+
Ok(body! {
|
|
24
|
+
toJSON(): Record<string, unknown> {
|
|
25
|
+
return {
|
|
26
|
+
{#for field in class.field_names()}
|
|
27
|
+
@{field}: this.@{field},
|
|
28
|
+
{/for}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
33
|
_ => Err(MacroforgeError::new(
|
|
34
34
|
input.decorator_span(),
|
|
35
35
|
"@derive(JSON) only works on classes",
|
|
36
36
|
)),
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
39
|
``` ## Using Custom Macros
|
|
40
40
|
Once your macro package is published, users can import and use it:
|
|
41
41
|
```
|
|
42
|
-
/** import macro
|
|
42
|
+
/** import macro { JSON } from "@my/macros"; */
|
|
43
43
|
|
|
44
44
|
/** @derive(JSON) */
|
|
45
|
-
class User
|
|
45
|
+
class User {
|
|
46
46
|
name: string;
|
|
47
47
|
age: number;
|
|
48
48
|
|
|
49
|
-
constructor(name: string, age: number)
|
|
49
|
+
constructor(name: string, age: number) {
|
|
50
50
|
this.name = name;
|
|
51
51
|
this.age = age;
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
54
|
|
|
55
55
|
const user = new User("Alice", 30);
|
|
56
|
-
console.log(user.toJSON()); //
|
|
56
|
+
console.log(user.toJSON()); // { name: "Alice", age: 30 }
|
|
57
57
|
``` > **Note:** The import macro comment tells Macroforge which package provides the macro. ## Getting Started
|
|
58
58
|
Follow these guides to create your own macros:
|
|
59
59
|
- [Set up a Rust macro crate](../docs/custom-macros/rust-setup)
|
|
@@ -25,7 +25,7 @@ crate-type = ["cdylib"]
|
|
|
25
25
|
|
|
26
26
|
[dependencies]
|
|
27
27
|
macroforge_ts = "0.1"
|
|
28
|
-
napi =
|
|
28
|
+
napi = { version = "3", features = ["napi8", "compat-mode"] }
|
|
29
29
|
napi-derive = "3"
|
|
30
30
|
|
|
31
31
|
[build-dependencies]
|
|
@@ -36,67 +36,67 @@ lto = true
|
|
|
36
36
|
strip = true
|
|
37
37
|
``` ## Create build.rs
|
|
38
38
|
```
|
|
39
|
-
fn main()
|
|
39
|
+
fn main() {
|
|
40
40
|
napi_build::setup();
|
|
41
|
-
|
|
41
|
+
}
|
|
42
42
|
``` ## Create src/lib.rs
|
|
43
43
|
```
|
|
44
|
-
use macroforge_ts::macros
|
|
45
|
-
use macroforge_ts::ts_syn
|
|
44
|
+
use macroforge_ts::macros::{ts_macro_derive, body};
|
|
45
|
+
use macroforge_ts::ts_syn::{
|
|
46
46
|
Data, DeriveInput, MacroforgeError, TsStream, parse_ts_macro_input,
|
|
47
|
-
|
|
47
|
+
};
|
|
48
48
|
|
|
49
49
|
#[ts_macro_derive(
|
|
50
50
|
JSON,
|
|
51
51
|
description = "Generates toJSON() returning a plain object"
|
|
52
52
|
)]
|
|
53
|
-
pub fn derive_json(mut input: TsStream) -> Result
|
|
53
|
+
pub fn derive_json(mut input: TsStream) -> Result<TsStream, MacroforgeError> {
|
|
54
54
|
let input = parse_ts_macro_input!(input as DeriveInput);
|
|
55
55
|
|
|
56
|
-
match
|
|
57
|
-
Data::Class(class) =>
|
|
58
|
-
Ok(body!
|
|
59
|
-
toJSON(): Record
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
match &input.data {
|
|
57
|
+
Data::Class(class) => {
|
|
58
|
+
Ok(body! {
|
|
59
|
+
toJSON(): Record<string, unknown> {
|
|
60
|
+
return {
|
|
61
|
+
{#for field in class.field_names()}
|
|
62
|
+
@{field}: this.@{field},
|
|
63
|
+
{/for}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
68
|
_ => Err(MacroforgeError::new(
|
|
69
69
|
input.decorator_span(),
|
|
70
70
|
"@derive(JSON) only works on classes",
|
|
71
71
|
)),
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
74
|
``` ## Create package.json
|
|
75
75
|
```
|
|
76
|
-
|
|
76
|
+
{
|
|
77
77
|
"name": "@my-org/macros",
|
|
78
78
|
"version": "0.1.0",
|
|
79
79
|
"main": "index.js",
|
|
80
80
|
"types": "index.d.ts",
|
|
81
|
-
"napi":
|
|
81
|
+
"napi": {
|
|
82
82
|
"name": "my-macros",
|
|
83
|
-
"triples":
|
|
83
|
+
"triples": {
|
|
84
84
|
"defaults": true
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
87
|
"files": [
|
|
88
88
|
"index.js",
|
|
89
89
|
"index.d.ts",
|
|
90
90
|
"*.node"
|
|
91
91
|
],
|
|
92
|
-
"scripts":
|
|
92
|
+
"scripts": {
|
|
93
93
|
"build": "napi build --release",
|
|
94
94
|
"prepublishOnly": "napi build --release"
|
|
95
|
-
|
|
96
|
-
"devDependencies":
|
|
95
|
+
},
|
|
96
|
+
"devDependencies": {
|
|
97
97
|
"@napi-rs/cli": "^3.0.0-alpha.0"
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
100
|
``` ## Build the Package
|
|
101
101
|
```
|
|
102
102
|
# Build the native addon
|