@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,285 +1,78 @@
1
1
  # PartialEq
2
- *The `PartialEq` macro generates an `equals()` method for field-by-field structural equality comparison. This is analogous to Rust's `PartialEq` trait, enabling value-based equality semantics instead of reference equality.*
3
- ## Basic Usage
4
- **Before:**
5
- ```
6
- /** @derive(PartialEq) */
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 `PartialEq` macro generates an `equals()` method for field-by-field
4
+ structural equality comparison. This is analogous to Rust's `PartialEq` trait,
5
+ enabling value-based equality semantics instead of reference equality.
22
6
 
23
- constructor(x: number, y: number) {
24
- this.x = x;
25
- this.y = y;
26
- }
7
+ ## Generated Output
27
8
 
28
- equals(other: unknown): boolean {
29
- if (this === other) return true;
30
- if (!(other instanceof Point)) return false;
31
- const typedOther = other as Point;
32
- return this.x === typedOther.x && this.y === typedOther.y;
33
- }
34
- }
35
- ``` ```
36
- const p1 = new Point(10, 20);
37
- const p2 = new Point(10, 20);
38
- const p3 = new Point(5, 5);
9
+ | Type | Generated Code | Description |
10
+ |------|----------------|-------------|
11
+ | Class | `equals(other: unknown): boolean` | Instance method with instanceof check |
12
+ | Enum | `equalsEnumName(a: EnumName, b: EnumName): boolean` | Standalone function using strict equality |
13
+ | Interface | `equalsInterfaceName(a: InterfaceName, b: InterfaceName): boolean` | Standalone function comparing fields |
14
+ | Type Alias | `equalsTypeName(a: TypeName, b: TypeName): boolean` | Standalone function with type-appropriate comparison |
39
15
 
40
- console.log(p1.equals(p2)); // true (same values)
41
- console.log(p1.equals(p3)); // false (different values)
42
- console.log(p1 === p2); // false (different references)
43
- ``` ## How It Works
44
- The PartialEq macro performs field-by-field comparison using these strategies:
45
- - **Primitives** (string, number, boolean, null, undefined) → Strict equality (`===`)
46
- - **Date** → Compares timestamps via `getTime()`
47
- - **Array** → Length check + element-by-element comparison
48
- - **Map** → Size check + entry comparison
49
- - **Set** → Size check + membership verification
50
- - **Objects** → Calls `equals()` if available, otherwise `===`
51
- ## Field Options
52
- ### @partialEq(skip)
53
- Use `@partialEq(skip)` to exclude a field from equality comparison:
54
- **Before:**
55
- ```
56
- /** @derive(PartialEq) */
57
- class User {
58
- id: number;
59
- name: string;
16
+ ## Configuration
60
17
 
61
- /** @partialEq(skip) */
62
- createdAt: Date;
18
+ The `functionNamingStyle` option in `macroforge.json` controls naming:
19
+ - `"suffix"` (default): Suffixes with type name (e.g., `equalsMyType`)
20
+ - `"prefix"`: Prefixes with type name (e.g., `myTypeEquals`)
21
+ - `"generic"`: Uses TypeScript generics (e.g., `equals<T extends MyType>`)
22
+ - `"namespace"`: Legacy namespace wrapping
63
23
 
64
- constructor(id: number, name: string, createdAt: Date) {
65
- this.id = id;
66
- this.name = name;
67
- this.createdAt = createdAt;
68
- }
69
- }
70
- ```
71
- **After:**
72
- ```
73
- class User {
74
- id: number;
75
- name: string;
24
+ ## Comparison Strategy
76
25
 
77
- createdAt: Date;
26
+ The generated equality check:
78
27
 
79
- constructor(id: number, name: string, createdAt: Date) {
80
- this.id = id;
81
- this.name = name;
82
- this.createdAt = createdAt;
83
- }
28
+ 1. **Identity check**: `this === other` returns true immediately
29
+ 2. **Type check**: For classes, uses `instanceof`; returns false if wrong type
30
+ 3. **Field comparison**: Compares each non-skipped field
84
31
 
85
- equals(other: unknown): boolean {
86
- if (this === other) return true;
87
- if (!(other instanceof User)) return false;
88
- const typedOther = other as User;
89
- return this.id === typedOther.id && this.name === typedOther.name;
90
- }
91
- }
92
- ``` ```
93
- const user1 = new User(1, "Alice", new Date("2024-01-01"));
94
- const user2 = new User(1, "Alice", new Date("2024-12-01"));
32
+ ## Type-Specific Comparisons
95
33
 
96
- console.log(user1.equals(user2)); // true (createdAt is skipped)
97
- ``` ## Type Safety
98
- The generated `equals()` method accepts `unknown` and performs runtime type checking:
99
- **Source:**
100
- ```
101
- /** @derive(PartialEq) */
102
- class User {
103
- name: string;
104
- constructor(name: string) {
105
- this.name = name;
106
- }
107
- }
108
- ``` ```
109
- const user = new User("Alice");
34
+ | Type | Comparison Method |
35
+ |------|-------------------|
36
+ | Primitives | Strict equality (`===`) |
37
+ | Arrays | Length + element-by-element (recursive) |
38
+ | `Date` | `getTime()` comparison |
39
+ | `Map` | Size + entry-by-entry comparison |
40
+ | `Set` | Size + membership check |
41
+ | Objects | Calls `equals()` if available, else `===` |
110
42
 
111
- console.log(user.equals(new User("Alice"))); // true
112
- console.log(user.equals("Alice")); // false (not a User instance)
113
- ``` ## With Nested Objects
114
- For objects with nested fields, PartialEq recursively calls `equals()` if available:
115
- **Source:**
116
- ```
117
- /** @derive(PartialEq) */
118
- class Address {
119
- city: string;
120
- zip: string;
43
+ ## Field-Level Options
121
44
 
122
- constructor(city: string, zip: string) {
123
- this.city = city;
124
- this.zip = zip;
125
- }
126
- }
127
-
128
- /** @derive(PartialEq) */
129
- class Person {
130
- name: string;
131
- address: Address;
45
+ The `@partialEq` decorator supports:
132
46
 
133
- constructor(name: string, address: Address) {
134
- this.name = name;
135
- this.address = address;
136
- }
137
- }
138
- ``` ```
139
- const addr1 = new Address("NYC", "10001");
140
- const addr2 = new Address("NYC", "10001");
47
+ - `skip` - Exclude the field from equality comparison
141
48
 
142
- const p1 = new Person("Alice", addr1);
143
- const p2 = new Person("Alice", addr2);
49
+ ## Example
144
50
 
145
- console.log(p1.equals(p2)); // true (deep equality via Address.equals)
146
- ``` ## Interface Support
147
- PartialEq works with interfaces. For interfaces, a namespace is generated with an `equals` function:
148
- **Before:**
149
- ```
150
- /** @derive(PartialEq) */
151
- interface Point {
152
- x: number;
153
- y: number;
154
- }
155
- ```
156
- **After:**
157
- ```
158
- interface Point {
159
- x: number;
160
- y: number;
161
- }
162
-
163
- export namespace Point {
164
- export function equals(self: Point, other: Point): boolean {
165
- if (self === other) return true;
166
- return self.x === other.x && self.y === other.y;
167
- }
168
- }
169
- ``` ```
170
- const p1: Point = { x: 10, y: 20 };
171
- const p2: Point = { x: 10, y: 20 };
172
- const p3: Point = { x: 5, y: 5 };
173
-
174
- console.log(Point.equals(p1, p2)); // true
175
- console.log(Point.equals(p1, p3)); // false
176
- ``` ## Enum Support
177
- PartialEq works with enums. For enums, strict equality comparison is used:
178
- **Before:**
179
- ```
180
- /** @derive(PartialEq) */
181
- enum Status {
182
- Active = 'active',
183
- Inactive = 'inactive',
184
- Pending = 'pending'
185
- }
186
- ```
187
- **After:**
188
- ```
189
- enum Status {
190
- Active = 'active',
191
- Inactive = 'inactive',
192
- Pending = 'pending'
193
- }
194
-
195
- export namespace Status {
196
- export function equals(a: Status, b: Status): boolean {
197
- return a === b;
198
- }
199
- }
200
- ``` ```
201
- console.log(Status.equals(Status.Active, Status.Active)); // true
202
- console.log(Status.equals(Status.Active, Status.Inactive)); // false
203
- ``` ## Type Alias Support
204
- PartialEq works with type aliases. For object types, field-by-field comparison is used:
205
- **Before:**
206
- ```
207
- /** @derive(PartialEq) */
208
- type Point = {
209
- x: number;
210
- y: number;
211
- };
212
- ```
213
- **After:**
214
- ```
215
- type Point = {
216
- x: number;
217
- y: number;
218
- };
51
+ ```typescript
52
+ @derive(PartialEq, Hash)
53
+ class User {
54
+ id: number;
55
+ name: string;
219
56
 
220
- export namespace Point {
221
- export function equals(a: Point, b: Point): boolean {
222
- if (a === b) return true;
223
- return a.x === b.x && a.y === b.y;
224
- }
57
+ @partialEq(skip) // Don't compare cached values
58
+ @hash(skip)
59
+ cachedScore: number;
225
60
  }
226
- ``` ```
227
- const p1: Point = { x: 10, y: 20 };
228
- const p2: Point = { x: 10, y: 20 };
229
61
 
230
- console.log(Point.equals(p1, p2)); // true
231
- ``` For union types, strict equality is used:
232
- **Source:**
233
- ```
234
- /** @derive(PartialEq) */
235
- type ApiStatus = "loading" | "success" | "error";
236
- ``` ```
237
- console.log(ApiStatus.equals("success", "success")); // true
238
- console.log(ApiStatus.equals("success", "error")); // false
239
- ``` ## Common Patterns
240
- ### Finding Items in Arrays
241
- **Source:**
62
+ // Generated:
63
+ // equals(other: unknown): boolean {
64
+ // if (this === other) return true;
65
+ // if (!(other instanceof User)) return false;
66
+ // const typedOther = other as User;
67
+ // return this.id === typedOther.id &&
68
+ // this.name === typedOther.name;
69
+ // }
242
70
  ```
243
- /** @derive(PartialEq) */
244
- class Product {
245
- sku: string;
246
- name: string;
247
71
 
248
- constructor(sku: string, name: string) {
249
- this.sku = sku;
250
- this.name = name;
251
- }
252
- }
253
- ``` ```
254
- const products = [
255
- new Product("A1", "Widget"),
256
- new Product("B2", "Gadget"),
257
- new Product("C3", "Gizmo")
258
- ];
259
-
260
- const target = new Product("B2", "Gadget");
261
- const found = products.find(p => p.equals(target));
72
+ ## Equality Contract
262
73
 
263
- console.log(found); // Product { sku: "B2", name: "Gadget" }
264
- ``` ### Use with Hash
265
- When using objects as keys in Map-like structures, combine PartialEq with Hash:
266
- **Source:**
267
- ```
268
- /** @derive(PartialEq, Hash) */
269
- class Key {
270
- id: number;
271
- type: string;
272
-
273
- constructor(id: number, type: string) {
274
- this.id = id;
275
- this.type = type;
276
- }
277
- }
278
- ``` ```
279
- const k1 = new Key(1, "user");
280
- const k2 = new Key(1, "user");
74
+ When implementing `PartialEq`, consider also implementing `Hash`:
281
75
 
282
- // Equal objects should have equal hash codes
283
- console.log(k1.equals(k2)); // true
284
- console.log(k1.hashCode() === k2.hashCode()); // true
285
- ```
76
+ - **Reflexivity**: `a.equals(a)` is always true
77
+ - **Symmetry**: `a.equals(b)` implies `b.equals(a)`
78
+ - **Hash consistency**: Equal objects must have equal hash codes