@macroforge/mcp-server 0.1.34 → 0.1.35

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.
@@ -1,203 +1,62 @@
1
1
  # Clone
2
- *The `Clone` macro generates a `clone()` method for deep copying objects. This is analogous to Rust's `Clone` trait, providing a way to create independent copies of values.*
3
- ## Basic Usage
4
- **Before:**
5
- ```
6
- /** @derive(Clone) */
7
- class Point {
8
- x: number;
9
- y: number;
10
2
 
11
- constructor(x: number, y: number) {
12
- this.x = x;
13
- this.y = y;
14
- }
15
- }
16
- ```
17
- **After:**
18
- ```
19
- class Point {
20
- x: number;
21
- y: number;
3
+ The `Clone` macro generates a `clone()` method for deep copying objects.
4
+ This is analogous to Rust's `Clone` trait, providing a way to create
5
+ independent copies of values.
22
6
 
23
- constructor(x: number, y: number) {
24
- this.x = x;
25
- this.y = y;
26
- }
7
+ ## Generated Output
27
8
 
28
- clone(): Point {
29
- const cloned = Object.create(Object.getPrototypeOf(this));
30
- cloned.x = this.x;
31
- cloned.y = this.y;
32
- return cloned;
33
- }
34
- }
35
- ``` ```
36
- const original = new Point(10, 20);
37
- const copy = original.clone();
9
+ | Type | Generated Code | Description |
10
+ |------|----------------|-------------|
11
+ | Class | `clone(): ClassName` | Instance method creating a new instance with copied fields |
12
+ | Enum | `cloneEnumName(value: EnumName): EnumName` | Standalone function (enums are primitives, returns value as-is) |
13
+ | Interface | `cloneInterfaceName(value: InterfaceName): InterfaceName` | Standalone function creating a new object literal |
14
+ | Type Alias | `cloneTypeName(value: TypeName): TypeName` | Standalone function with spread copy for objects |
38
15
 
39
- console.log(copy.x, copy.y); // 10, 20
40
- console.log(original === copy); // false (different instances)
41
- ``` ## How It Works
42
- The Clone macro:
43
- 1. Creates a new instance of the class
44
- 2. Passes all field values to the constructor
45
- 3. Returns the new instance
46
- This creates a **shallow clone** - primitive values are copied, but object references remain the same.
47
- ## With Nested Objects
48
- **Before:**
49
- ```
50
- /** @derive(Clone) */
51
- class User {
52
- name: string;
53
- address: { city: string; zip: string };
16
+ ## Configuration
54
17
 
55
- constructor(name: string, address: { city: string; zip: string }) {
56
- this.name = name;
57
- this.address = address;
58
- }
59
- }
60
- ```
61
- **After:**
62
- ```
63
- class User {
64
- name: string;
65
- address: { city: string; zip: string };
18
+ The `functionNamingStyle` option in `macroforge.json` controls naming:
19
+ - `"suffix"` (default): Suffixes with type name (e.g., `cloneMyType`)
20
+ - `"prefix"`: Prefixes with type name (e.g., `myTypeClone`)
21
+ - `"generic"`: Uses TypeScript generics (e.g., `clone<T extends MyType>`)
22
+ - `"namespace"`: Legacy namespace wrapping
66
23
 
67
- constructor(name: string, address: { city: string; zip: string }) {
68
- this.name = name;
69
- this.address = address;
70
- }
24
+ ## Cloning Strategy
71
25
 
72
- clone(): User {
73
- const cloned = Object.create(Object.getPrototypeOf(this));
74
- cloned.name = this.name;
75
- cloned.address = this.address;
76
- return cloned;
77
- }
78
- }
79
- ``` ```
80
- const original = new User("Alice", { city: "NYC", zip: "10001" });
81
- const copy = original.clone();
26
+ The generated clone performs a **shallow copy** of all fields:
82
27
 
83
- // The address object is the same reference
84
- console.log(original.address === copy.address); // true
28
+ - **Primitives** (`string`, `number`, `boolean`): Copied by value
29
+ - **Objects**: Reference is copied (not deep cloned)
30
+ - **Arrays**: Reference is copied (not deep cloned)
85
31
 
86
- // Modifying the copy's address affects the original
87
- copy.address.city = "LA";
88
- console.log(original.address.city); // "LA"
89
- ``` For deep cloning of nested objects, you would need to implement custom clone methods or use a deep clone utility.
90
- ## Combining with PartialEq
91
- Clone works well with PartialEq for creating independent copies that compare as equal:
92
- **Source:**
93
- ```
94
- /** @derive(Clone, PartialEq) */
95
- class Point {
96
- x: number;
97
- y: number;
32
+ For deep cloning of nested objects, those objects should also derive `Clone`
33
+ and the caller should clone them explicitly.
98
34
 
99
- constructor(x: number, y: number) {
100
- this.x = x;
101
- this.y = y;
102
- }
103
- }
104
- ``` ```
105
- const original = new Point(10, 20);
106
- const copy = original.clone();
35
+ ## Example
107
36
 
108
- console.log(original === copy); // false (different instances)
109
- console.log(original.equals(copy)); // true (same values)
110
- ``` ## Interface Support
111
- Clone also works with interfaces. For interfaces, a namespace is generated with a `clone` function:
112
- **Before:**
113
- ```
114
- /** @derive(Clone) */
115
- interface Point {
116
- x: number;
117
- y: number;
118
- }
119
- ```
120
- **After:**
121
- ```
122
- interface Point {
37
+ ```typescript
38
+ @derive(Clone)
39
+ class Point {
123
40
  x: number;
124
41
  y: number;
125
42
  }
126
43
 
127
- export namespace Point {
128
- export function clone(self: Point): Point {
129
- return { x: self.x, y: self.y };
130
- }
131
- }
132
- ``` ```
133
- const original: Point = { x: 10, y: 20 };
134
- const copy = Point.clone(original);
44
+ // Generated:
45
+ // clone(): Point {
46
+ // const cloned = Object.create(Object.getPrototypeOf(this));
47
+ // cloned.x = this.x;
48
+ // cloned.y = this.y;
49
+ // return cloned;
50
+ // }
135
51
 
136
- console.log(copy.x, copy.y); // 10, 20
137
- console.log(original === copy); // false (different objects)
138
- ``` ## Enum Support
139
- Clone also works with enums. For enums, the clone function simply returns the value as-is, since enum values are primitives and don't need cloning:
140
- **Before:**
52
+ const p1 = new Point();
53
+ const p2 = p1.clone(); // Creates a new Point with same values
141
54
  ```
142
- /** @derive(Clone) */
143
- enum Status {
144
- Active = 'active',
145
- Inactive = 'inactive'
146
- }
147
- ```
148
- **After:**
149
- ```
150
- enum Status {
151
- Active = 'active',
152
- Inactive = 'inactive'
153
- }
154
55
 
155
- export namespace Status {
156
- export function clone(value: Status): Status {
157
- return value;
158
- }
159
- }
160
- ``` ```
161
- const original = Status.Active;
162
- const copy = Status.clone(original);
56
+ ## Implementation Notes
163
57
 
164
- console.log(copy); // "active"
165
- console.log(original === copy); // true (same primitive value)
166
- ``` ## Type Alias Support
167
- Clone works with type aliases. For object types, a shallow copy is created using spread:
168
- **Before:**
169
- ```
170
- /** @derive(Clone) */
171
- type Point = {
172
- x: number;
173
- y: number;
174
- };
175
- ```
176
- **After:**
177
- ```
178
- type Point = {
179
- x: number;
180
- y: number;
181
- };
182
-
183
- export namespace Point {
184
- export function clone(value: Point): Point {
185
- return { x: value.x, y: value.y };
186
- }
187
- }
188
- ``` ```
189
- const original: Point = { x: 10, y: 20 };
190
- const copy = Point.clone(original);
191
-
192
- console.log(copy.x, copy.y); // 10, 20
193
- console.log(original === copy); // false (different objects)
194
- ``` For union types, the value is returned as-is (unions of primitives don't need cloning):
195
- **Source:**
196
- ```
197
- /** @derive(Clone) */
198
- type ApiStatus = "loading" | "success" | "error";
199
- ``` ```
200
- const status: ApiStatus = "success";
201
- const copy = ApiStatus.clone(status);
202
- console.log(copy); // "success"
203
- ```
58
+ - **Classes**: Uses `Object.create(Object.getPrototypeOf(this))` to preserve
59
+ the prototype chain, ensuring `instanceof` checks work correctly
60
+ - **Enums**: Simply returns the value (enums are primitives in TypeScript)
61
+ - **Interfaces/Type Aliases**: Creates new object literals with spread operator
62
+ for union/tuple types, or field-by-field copy for object types
@@ -1,258 +1,52 @@
1
1
  # Debug
2
- *The `Debug` macro generates a human-readable `toString()` method for TypeScript classes, interfaces, enums, and type aliases.*
3
- ## Basic Usage
4
- **Before:**
5
- ```
6
- /** @derive(Debug) */
7
- class User {
8
- name: string;
9
- age: number;
10
-
11
- constructor(name: string, age: number) {
12
- this.name = name;
13
- this.age = age;
14
- }
15
- }
16
- ```
17
- **After:**
18
- ```
19
- class User {
20
- name: string;
21
- age: number;
22
2
 
23
- constructor(name: string, age: number) {
24
- this.name = name;
25
- this.age = age;
26
- }
3
+ The `Debug` macro generates a human-readable `toString()` method for
4
+ TypeScript classes, interfaces, enums, and type aliases.
27
5
 
28
- toString(): string {
29
- const parts: string[] = [];
30
- parts.push('name: ' + this.name);
31
- parts.push('age: ' + this.age);
32
- return 'User { ' + parts.join(', ') + ' }';
33
- }
34
- }
35
- ``` ```
36
- const user = new User("Alice", 30);
37
- console.log(user.toString());
38
- // Output: User { name: Alice, age: 30 }
39
- ``` ## Field Options
40
- Use the `@debug` field decorator to customize behavior:
41
- ### Renaming Fields
42
- **Before:**
43
- ```
44
- /** @derive(Debug) */
45
- class User {
46
- /** @debug({ rename: "userId" }) */
47
- id: number;
6
+ ## Generated Output
48
7
 
49
- name: string;
8
+ **Classes**: Generates an instance method returning a string
9
+ like `"ClassName { field1: value1, field2: value2 }"`.
50
10
 
51
- constructor(id: number, name: string) {
52
- this.id = id;
53
- this.name = name;
54
- }
55
- }
56
- ```
57
- **After:**
58
- ```
59
- class User {
60
- id: number;
11
+ **Enums**: Generates a standalone function `toStringEnumName(value)` that performs
12
+ reverse lookup on numeric enums.
61
13
 
62
- name: string;
14
+ **Interfaces**: Generates a standalone function `toStringInterfaceName(value)`.
63
15
 
64
- constructor(id: number, name: string) {
65
- this.id = id;
66
- this.name = name;
67
- }
68
-
69
- toString(): string {
70
- const parts: string[] = [];
71
- parts.push('userId: ' + this.id);
72
- parts.push('name: ' + this.name);
73
- return 'User { ' + parts.join(', ') + ' }';
74
- }
75
- }
76
- ``` ```
77
- const user = new User(42, "Alice");
78
- console.log(user.toString());
79
- // Output: User { userId: 42, name: Alice }
80
- ``` ### Skipping Fields
81
- Use `skip: true` to exclude sensitive fields from the output:
82
- **Before:**
83
- ```
84
- /** @derive(Debug) */
85
- class User {
86
- name: string;
87
- email: string;
88
-
89
- /** @debug({ skip: true }) */
90
- password: string;
91
-
92
- /** @debug({ skip: true }) */
93
- authToken: string;
94
-
95
- constructor(name: string, email: string, password: string, authToken: string) {
96
- this.name = name;
97
- this.email = email;
98
- this.password = password;
99
- this.authToken = authToken;
100
- }
101
- }
102
- ```
103
- **After:**
104
- ```
105
- class User {
106
- name: string;
107
- email: string;
16
+ **Type Aliases**: Generates a standalone function using JSON.stringify for
17
+ complex types, or field enumeration for object types.
108
18
 
109
- password: string;
19
+ ## Configuration
110
20
 
111
- authToken: string;
21
+ The `functionNamingStyle` option in `macroforge.json` controls naming:
22
+ - `"suffix"` (default): Suffixes with type name (e.g., `toStringMyType`)
23
+ - `"prefix"`: Prefixes with type name (e.g., `myTypeToString`)
24
+ - `"generic"`: Uses TypeScript generics (e.g., `toString<T extends MyType>`)
25
+ - `"namespace"`: Legacy namespace wrapping
112
26
 
113
- constructor(name: string, email: string, password: string, authToken: string) {
114
- this.name = name;
115
- this.email = email;
116
- this.password = password;
117
- this.authToken = authToken;
118
- }
27
+ ## Field-Level Options
119
28
 
120
- toString(): string {
121
- const parts: string[] = [];
122
- parts.push('name: ' + this.name);
123
- parts.push('email: ' + this.email);
124
- return 'User { ' + parts.join(', ') + ' }';
125
- }
126
- }
127
- ``` ```
128
- const user = new User("Alice", "alice@example.com", "secret", "tok_xxx");
129
- console.log(user.toString());
130
- // Output: User { name: Alice, email: alice@example.com }
131
- // Note: password and authToken are not included
132
- ``` **Security Always skip sensitive fields like passwords, tokens, and API keys to prevent accidental logging. ## Combining Options
133
- ****Source:**
134
- ```
135
- /** @derive(Debug) */
136
- class ApiResponse {
137
- /** @debug({ rename: "statusCode" }) */
138
- status: number;
29
+ The `@debug` decorator supports:
139
30
 
140
- data: unknown;
31
+ - `skip` - Exclude the field from debug output
32
+ - `rename = "label"` - Use a custom label instead of the field name
141
33
 
142
- /** @debug({ skip: true }) */
143
- internalMetadata: Record<string, unknown>;
144
- }
145
- ``` ## All Options
146
- | Option | Type | Description |
147
- | --- | --- | --- |
148
- | `rename` | `string` | Display a different name in the output |
149
- | `skip` | `boolean` | Exclude this field from the output |
150
- ## Interface Support
151
- Debug also works with interfaces. For interfaces, a namespace is generated with a `toString` function:
152
- **Before:**
153
- ```
154
- /** @derive(Debug) */
155
- interface Status {
156
- active: boolean;
157
- message: string;
158
- }
159
- ```
160
- **After:**
161
- ```
162
- interface Status {
163
- active: boolean;
164
- message: string;
165
- }
34
+ ## Example
166
35
 
167
- export namespace Status {
168
- export function toString(self: Status): string {
169
- const parts: string[] = [];
170
- parts.push('active: ' + self.active);
171
- parts.push('message: ' + self.message);
172
- return 'Status { ' + parts.join(', ') + ' }';
173
- }
174
- }
175
- ``` ```
176
- const status: Status = { active: true, message: "OK" };
177
- console.log(Status.toString(status));
178
- // Output: Status { active: true, message: OK }
179
- ``` ## Enum Support
180
- Debug also works with enums. For enums, a namespace is generated with a `toString` function that displays the enum name and variant:
181
- **Before:**
182
- ```
183
- /** @derive(Debug) */
184
- enum Priority {
185
- Low = 1,
186
- Medium = 2,
187
- High = 3
188
- }
189
- ```
190
- **After:**
191
- ```
192
- enum Priority {
193
- Low = 1,
194
- Medium = 2,
195
- High = 3
196
- }
36
+ ```typescript
37
+ @derive(Debug)
38
+ class User {
39
+ @debug(rename = "id")
40
+ userId: number;
197
41
 
198
- export namespace Priority {
199
- export function toString(value: Priority): string {
200
- const key = Priority[value as unknown as keyof typeof Priority];
201
- if (key !== undefined) {
202
- return 'Priority.' + key;
203
- }
204
- return 'Priority(' + String(value) + ')';
205
- }
206
- }
207
- ``` ```
208
- console.log(Priority.toString(Priority.High));
209
- // Output: Priority.High
42
+ @debug(skip)
43
+ password: string;
210
44
 
211
- console.log(Priority.toString(Priority.Low));
212
- // Output: Priority.Low
213
- ``` Works with both numeric and string enums:
214
- **Source:**
215
- ```
216
- /** @derive(Debug) */
217
- enum Status {
218
- Active = "active",
219
- Inactive = "inactive",
45
+ email: string;
220
46
  }
221
- ``` ## Type Alias Support
222
- Debug works with type aliases. For object types, fields are displayed similar to interfaces:
223
- **Before:**
224
- ```
225
- /** @derive(Debug) */
226
- type Point = {
227
- x: number;
228
- y: number;
229
- };
230
- ```
231
- **After:**
232
- ```
233
- type Point = {
234
- x: number;
235
- y: number;
236
- };
237
47
 
238
- export namespace Point {
239
- export function toString(value: Point): string {
240
- const parts: string[] = [];
241
- parts.push('x: ' + value.x);
242
- parts.push('y: ' + value.y);
243
- return 'Point { ' + parts.join(', ') + ' }';
244
- }
245
- }
246
- ``` ```
247
- const point: Point = { x: 10, y: 20 };
248
- console.log(Point.toString(point));
249
- // Output: Point { x: 10, y: 20 }
250
- ``` For union types, the value is displayed using JSON.stringify:
251
- **Source:**
48
+ // Generated:
49
+ // toString(): string {
50
+ // return "User { id: " + this.userId + ", email: " + this.email + " }";
51
+ // }
252
52
  ```
253
- /** @derive(Debug) */
254
- type ApiStatus = "loading" | "success" | "error";
255
- ``` ```
256
- console.log(ApiStatus.toString("success"));
257
- // Output: ApiStatus("success")
258
- ```