@macroforge/mcp-server 0.1.17
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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/docs-loader.d.ts +30 -0
- package/dist/tools/docs-loader.d.ts.map +1 -0
- package/dist/tools/docs-loader.js +112 -0
- package/dist/tools/docs-loader.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +348 -0
- package/dist/tools/index.js.map +1 -0
- package/docs/api/api-overview.md +75 -0
- package/docs/api/expand-sync.md +121 -0
- package/docs/api/native-plugin.md +106 -0
- package/docs/api/position-mapper.md +127 -0
- package/docs/api/transform-sync.md +98 -0
- package/docs/builtin-macros/clone.md +180 -0
- package/docs/builtin-macros/debug.md +222 -0
- package/docs/builtin-macros/default.md +192 -0
- package/docs/builtin-macros/deserialize.md +662 -0
- package/docs/builtin-macros/hash.md +205 -0
- package/docs/builtin-macros/macros-overview.md +169 -0
- package/docs/builtin-macros/ord.md +258 -0
- package/docs/builtin-macros/partial-eq.md +306 -0
- package/docs/builtin-macros/partial-ord.md +268 -0
- package/docs/builtin-macros/serialize.md +321 -0
- package/docs/concepts/architecture.md +139 -0
- package/docs/concepts/derive-system.md +173 -0
- package/docs/concepts/how-macros-work.md +124 -0
- package/docs/custom-macros/custom-overview.md +84 -0
- package/docs/custom-macros/rust-setup.md +146 -0
- package/docs/custom-macros/ts-macro-derive.md +307 -0
- package/docs/custom-macros/ts-quote.md +696 -0
- package/docs/getting-started/first-macro.md +120 -0
- package/docs/getting-started/installation.md +110 -0
- package/docs/integration/cli.md +207 -0
- package/docs/integration/configuration.md +116 -0
- package/docs/integration/integration-overview.md +51 -0
- package/docs/integration/typescript-plugin.md +96 -0
- package/docs/integration/vite-plugin.md +126 -0
- package/docs/language-servers/ls-overview.md +47 -0
- package/docs/language-servers/svelte-ls.md +80 -0
- package/docs/language-servers/zed-extensions.md +84 -0
- package/docs/sections.json +258 -0
- package/package.json +48 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# PartialEq
|
|
2
|
+
|
|
3
|
+
*The `PartialEq` macro generates an `equals()` method for value-based equality comparison between objects.*
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
/** @derive(PartialEq) */
|
|
9
|
+
class Point {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
|
|
13
|
+
constructor(x: number, y: number) {
|
|
14
|
+
this.x = x;
|
|
15
|
+
this.y = y;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const p1 = new Point(10, 20);
|
|
20
|
+
const p2 = new Point(10, 20);
|
|
21
|
+
const p3 = new Point(5, 5);
|
|
22
|
+
|
|
23
|
+
console.log(p1.equals(p2)); // true (same values)
|
|
24
|
+
console.log(p1.equals(p3)); // false (different values)
|
|
25
|
+
console.log(p1 === p2); // false (different references)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Generated Code
|
|
29
|
+
|
|
30
|
+
The PartialEq macro generates an equals method that compares each field:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
equals(other: unknown): boolean {
|
|
34
|
+
if (this === other) return true;
|
|
35
|
+
if (!(other instanceof Point)) return false;
|
|
36
|
+
const typedOther = other as Point;
|
|
37
|
+
return this.x === typedOther.x && this.y === typedOther.y;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## How It Works
|
|
42
|
+
|
|
43
|
+
The PartialEq macro performs field-by-field comparison using these strategies:
|
|
44
|
+
|
|
45
|
+
- **Primitives** (string, number, boolean, null, undefined) → Strict equality (`===`)
|
|
46
|
+
|
|
47
|
+
- **Date** → Compares timestamps via `getTime()`
|
|
48
|
+
|
|
49
|
+
- **Array** → Length check + element-by-element comparison
|
|
50
|
+
|
|
51
|
+
- **Map** → Size check + entry comparison
|
|
52
|
+
|
|
53
|
+
- **Set** → Size check + membership verification
|
|
54
|
+
|
|
55
|
+
- **Objects** → Calls `equals()` if available, otherwise `===`
|
|
56
|
+
|
|
57
|
+
## Field Options
|
|
58
|
+
|
|
59
|
+
### @partialEq(skip)
|
|
60
|
+
|
|
61
|
+
Use `@partialEq(skip)` to exclude a field from equality comparison:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
/** @derive(PartialEq) */
|
|
65
|
+
class User {
|
|
66
|
+
id: number;
|
|
67
|
+
name: string;
|
|
68
|
+
|
|
69
|
+
/** @partialEq(skip) */
|
|
70
|
+
createdAt: Date; // Not compared
|
|
71
|
+
|
|
72
|
+
constructor(id: number, name: string, createdAt: Date) {
|
|
73
|
+
this.id = id;
|
|
74
|
+
this.name = name;
|
|
75
|
+
this.createdAt = createdAt;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const user1 = new User(1, "Alice", new Date("2024-01-01"));
|
|
80
|
+
const user2 = new User(1, "Alice", new Date("2024-12-01"));
|
|
81
|
+
|
|
82
|
+
console.log(user1.equals(user2)); // true (createdAt is skipped)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Type Safety
|
|
86
|
+
|
|
87
|
+
The generated `equals()` method accepts `unknown` and performs runtime type checking:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
/** @derive(PartialEq) */
|
|
91
|
+
class User {
|
|
92
|
+
name: string;
|
|
93
|
+
constructor(name: string) {
|
|
94
|
+
this.name = name;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** @derive(PartialEq) */
|
|
99
|
+
class Admin {
|
|
100
|
+
name: string;
|
|
101
|
+
constructor(name: string) {
|
|
102
|
+
this.name = name;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const user = new User("Alice");
|
|
107
|
+
const admin = new Admin("Alice");
|
|
108
|
+
|
|
109
|
+
console.log(user.equals(admin)); // false (different types)
|
|
110
|
+
console.log(user.equals("Alice")); // false (not a User instance)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## With Nested Objects
|
|
114
|
+
|
|
115
|
+
For objects with nested fields, PartialEq recursively calls `equals()` if available:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
/** @derive(PartialEq) */
|
|
119
|
+
class Address {
|
|
120
|
+
city: string;
|
|
121
|
+
zip: string;
|
|
122
|
+
|
|
123
|
+
constructor(city: string, zip: string) {
|
|
124
|
+
this.city = city;
|
|
125
|
+
this.zip = zip;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** @derive(PartialEq) */
|
|
130
|
+
class Person {
|
|
131
|
+
name: string;
|
|
132
|
+
address: Address;
|
|
133
|
+
|
|
134
|
+
constructor(name: string, address: Address) {
|
|
135
|
+
this.name = name;
|
|
136
|
+
this.address = address;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const addr1 = new Address("NYC", "10001");
|
|
141
|
+
const addr2 = new Address("NYC", "10001");
|
|
142
|
+
|
|
143
|
+
const p1 = new Person("Alice", addr1);
|
|
144
|
+
const p2 = new Person("Alice", addr2);
|
|
145
|
+
|
|
146
|
+
console.log(p1.equals(p2)); // true (deep equality via Address.equals)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## With Arrays
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
/** @derive(PartialEq) */
|
|
153
|
+
class Team {
|
|
154
|
+
name: string;
|
|
155
|
+
members: string[];
|
|
156
|
+
|
|
157
|
+
constructor(name: string, members: string[]) {
|
|
158
|
+
this.name = name;
|
|
159
|
+
this.members = members;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const t1 = new Team("Alpha", ["Alice", "Bob"]);
|
|
164
|
+
const t2 = new Team("Alpha", ["Alice", "Bob"]);
|
|
165
|
+
const t3 = new Team("Alpha", ["Alice", "Charlie"]);
|
|
166
|
+
|
|
167
|
+
console.log(t1.equals(t2)); // true
|
|
168
|
+
console.log(t1.equals(t3)); // false
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Interface Support
|
|
172
|
+
|
|
173
|
+
PartialEq works with interfaces. For interfaces, a namespace is generated with an `equals` function:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
/** @derive(PartialEq) */
|
|
177
|
+
interface Point {
|
|
178
|
+
x: number;
|
|
179
|
+
y: number;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Generated:
|
|
183
|
+
// export namespace Point {
|
|
184
|
+
// export function equals(self: Point, other: Point): boolean {
|
|
185
|
+
// if (self === other) return true;
|
|
186
|
+
// return self.x === other.x && self.y === other.y;
|
|
187
|
+
// }
|
|
188
|
+
// }
|
|
189
|
+
|
|
190
|
+
const p1: Point = { x: 10, y: 20 };
|
|
191
|
+
const p2: Point = { x: 10, y: 20 };
|
|
192
|
+
const p3: Point = { x: 5, y: 5 };
|
|
193
|
+
|
|
194
|
+
console.log(Point.equals(p1, p2)); // true
|
|
195
|
+
console.log(Point.equals(p1, p3)); // false
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Enum Support
|
|
199
|
+
|
|
200
|
+
PartialEq works with enums. For enums, strict equality comparison is used:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
/** @derive(PartialEq) */
|
|
204
|
+
enum Status {
|
|
205
|
+
Active = "active",
|
|
206
|
+
Inactive = "inactive",
|
|
207
|
+
Pending = "pending",
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Generated:
|
|
211
|
+
// export namespace Status {
|
|
212
|
+
// export function equals(a: Status, b: Status): boolean {
|
|
213
|
+
// return a === b;
|
|
214
|
+
// }
|
|
215
|
+
// }
|
|
216
|
+
|
|
217
|
+
console.log(Status.equals(Status.Active, Status.Active)); // true
|
|
218
|
+
console.log(Status.equals(Status.Active, Status.Inactive)); // false
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Type Alias Support
|
|
222
|
+
|
|
223
|
+
PartialEq works with type aliases. For object types, field-by-field comparison is used:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
/** @derive(PartialEq) */
|
|
227
|
+
type Point = {
|
|
228
|
+
x: number;
|
|
229
|
+
y: number;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Generated:
|
|
233
|
+
// export namespace Point {
|
|
234
|
+
// export function equals(a: Point, b: Point): boolean {
|
|
235
|
+
// if (a === b) return true;
|
|
236
|
+
// return a.x === b.x && a.y === b.y;
|
|
237
|
+
// }
|
|
238
|
+
// }
|
|
239
|
+
|
|
240
|
+
const p1: Point = { x: 10, y: 20 };
|
|
241
|
+
const p2: Point = { x: 10, y: 20 };
|
|
242
|
+
|
|
243
|
+
console.log(Point.equals(p1, p2)); // true
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
For union types, strict equality is used:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
/** @derive(PartialEq) */
|
|
250
|
+
type ApiStatus = "loading" | "success" | "error";
|
|
251
|
+
|
|
252
|
+
console.log(ApiStatus.equals("success", "success")); // true
|
|
253
|
+
console.log(ApiStatus.equals("success", "error")); // false
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Common Patterns
|
|
257
|
+
|
|
258
|
+
### Finding Items in Arrays
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
/** @derive(PartialEq) */
|
|
262
|
+
class Product {
|
|
263
|
+
sku: string;
|
|
264
|
+
name: string;
|
|
265
|
+
|
|
266
|
+
constructor(sku: string, name: string) {
|
|
267
|
+
this.sku = sku;
|
|
268
|
+
this.name = name;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const products = [
|
|
273
|
+
new Product("A1", "Widget"),
|
|
274
|
+
new Product("B2", "Gadget"),
|
|
275
|
+
new Product("C3", "Gizmo")
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
const target = new Product("B2", "Gadget");
|
|
279
|
+
const found = products.find(p => p.equals(target));
|
|
280
|
+
|
|
281
|
+
console.log(found); // Product { sku: "B2", name: "Gadget" }
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Use with Hash
|
|
285
|
+
|
|
286
|
+
When using objects as keys in Map-like structures, combine PartialEq with Hash:
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
/** @derive(PartialEq, Hash) */
|
|
290
|
+
class Key {
|
|
291
|
+
id: number;
|
|
292
|
+
type: string;
|
|
293
|
+
|
|
294
|
+
constructor(id: number, type: string) {
|
|
295
|
+
this.id = id;
|
|
296
|
+
this.type = type;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const k1 = new Key(1, "user");
|
|
301
|
+
const k2 = new Key(1, "user");
|
|
302
|
+
|
|
303
|
+
// Equal objects should have equal hash codes
|
|
304
|
+
console.log(k1.equals(k2)); // true
|
|
305
|
+
console.log(k1.hashCode() === k2.hashCode()); // true
|
|
306
|
+
```
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# PartialOrd
|
|
2
|
+
|
|
3
|
+
*The `PartialOrd` macro generates a `compareTo()` method that implements partial ordering, returning `-1`, `0`, `1`, or `null` for incomparable values.*
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
/** @derive(PartialOrd) */
|
|
9
|
+
class Temperature {
|
|
10
|
+
celsius: number;
|
|
11
|
+
|
|
12
|
+
constructor(celsius: number) {
|
|
13
|
+
this.celsius = celsius;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const t1 = new Temperature(20);
|
|
18
|
+
const t2 = new Temperature(30);
|
|
19
|
+
const t3 = new Temperature(20);
|
|
20
|
+
|
|
21
|
+
console.log(t1.compareTo(t2)); // -1 (t1 < t2)
|
|
22
|
+
console.log(t2.compareTo(t1)); // 1 (t2 > t1)
|
|
23
|
+
console.log(t1.compareTo(t3)); // 0 (t1 == t3)
|
|
24
|
+
|
|
25
|
+
// Returns null for incomparable types
|
|
26
|
+
console.log(t1.compareTo("not a Temperature")); // null
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Generated Code
|
|
30
|
+
|
|
31
|
+
The PartialOrd macro generates a compareTo method with runtime type checking:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
compareTo(other: unknown): number | null {
|
|
35
|
+
if (this === other) return 0;
|
|
36
|
+
if (!(other instanceof Temperature)) return null;
|
|
37
|
+
const typedOther = other as Temperature;
|
|
38
|
+
const cmp0 = (this.celsius < typedOther.celsius ? -1 : this.celsius > typedOther.celsius ? 1 : 0);
|
|
39
|
+
if (cmp0 === null) return null;
|
|
40
|
+
if (cmp0 !== 0) return cmp0;
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Return Values
|
|
46
|
+
|
|
47
|
+
The `compareTo()` method returns:
|
|
48
|
+
|
|
49
|
+
- `-1` → `this` is less than `other`
|
|
50
|
+
|
|
51
|
+
- `0` → `this` equals `other`
|
|
52
|
+
|
|
53
|
+
- `1` → `this` is greater than `other`
|
|
54
|
+
|
|
55
|
+
- `null` → Values are incomparable (e.g., different types)
|
|
56
|
+
|
|
57
|
+
## Comparison Logic
|
|
58
|
+
|
|
59
|
+
The PartialOrd macro compares fields in declaration order with type checking:
|
|
60
|
+
|
|
61
|
+
- `number` / `bigint` → Direct numeric comparison
|
|
62
|
+
|
|
63
|
+
- `string` → Uses `localeCompare()`
|
|
64
|
+
|
|
65
|
+
- `boolean` → `false < true`
|
|
66
|
+
|
|
67
|
+
- `Date` → Compares timestamps; returns `null` if not both Date instances
|
|
68
|
+
|
|
69
|
+
- `Array` → Lexicographic comparison; returns `null` if not both arrays
|
|
70
|
+
|
|
71
|
+
- `Object` → Calls `compareTo()` if available
|
|
72
|
+
|
|
73
|
+
- **Type mismatch** → Returns `null`
|
|
74
|
+
|
|
75
|
+
## Field Options
|
|
76
|
+
|
|
77
|
+
### @ord(skip)
|
|
78
|
+
|
|
79
|
+
Use `@ord(skip)` to exclude a field from ordering comparison:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
/** @derive(PartialOrd) */
|
|
83
|
+
class Item {
|
|
84
|
+
price: number;
|
|
85
|
+
name: string;
|
|
86
|
+
|
|
87
|
+
/** @ord(skip) */
|
|
88
|
+
description: string; // Not used for ordering
|
|
89
|
+
|
|
90
|
+
constructor(price: number, name: string, description: string) {
|
|
91
|
+
this.price = price;
|
|
92
|
+
this.name = name;
|
|
93
|
+
this.description = description;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const i1 = new Item(10, "Widget", "A useful widget");
|
|
98
|
+
const i2 = new Item(10, "Widget", "Different description");
|
|
99
|
+
|
|
100
|
+
console.log(i1.compareTo(i2)); // 0 (description is skipped)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Handling Null Results
|
|
104
|
+
|
|
105
|
+
When using PartialOrd, always handle the `null` case:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
/** @derive(PartialOrd) */
|
|
109
|
+
class Value {
|
|
110
|
+
amount: number;
|
|
111
|
+
|
|
112
|
+
constructor(amount: number) {
|
|
113
|
+
this.amount = amount;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function safeCompare(a: Value, b: unknown): string {
|
|
118
|
+
const result = a.compareTo(b);
|
|
119
|
+
if (result === null) {
|
|
120
|
+
return "incomparable";
|
|
121
|
+
} else if (result < 0) {
|
|
122
|
+
return "less than";
|
|
123
|
+
} else if (result > 0) {
|
|
124
|
+
return "greater than";
|
|
125
|
+
} else {
|
|
126
|
+
return "equal";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const v = new Value(100);
|
|
131
|
+
console.log(safeCompare(v, new Value(50))); // "greater than"
|
|
132
|
+
console.log(safeCompare(v, "string")); // "incomparable"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Sorting with PartialOrd
|
|
136
|
+
|
|
137
|
+
When sorting, handle `null` values appropriately:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
/** @derive(PartialOrd) */
|
|
141
|
+
class Score {
|
|
142
|
+
value: number;
|
|
143
|
+
|
|
144
|
+
constructor(value: number) {
|
|
145
|
+
this.value = value;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const scores = [
|
|
150
|
+
new Score(100),
|
|
151
|
+
new Score(50),
|
|
152
|
+
new Score(75)
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
// Safe sort that handles null (treats null as equal)
|
|
156
|
+
scores.sort((a, b) => a.compareTo(b) ?? 0);
|
|
157
|
+
// Result: [Score(50), Score(75), Score(100)]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Interface Support
|
|
161
|
+
|
|
162
|
+
PartialOrd works with interfaces. For interfaces, a namespace is generated with a `compareTo` function:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
/** @derive(PartialOrd) */
|
|
166
|
+
interface Measurement {
|
|
167
|
+
value: number;
|
|
168
|
+
unit: string;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Generated:
|
|
172
|
+
// export namespace Measurement {
|
|
173
|
+
// export function compareTo(self: Measurement, other: Measurement): number | null {
|
|
174
|
+
// if (self === other) return 0;
|
|
175
|
+
// const cmp0 = (self.value < other.value ? -1 : self.value > other.value ? 1 : 0);
|
|
176
|
+
// if (cmp0 !== 0) return cmp0;
|
|
177
|
+
// const cmp1 = self.unit.localeCompare(other.unit);
|
|
178
|
+
// if (cmp1 !== 0) return cmp1 < 0 ? -1 : 1;
|
|
179
|
+
// return 0;
|
|
180
|
+
// }
|
|
181
|
+
// }
|
|
182
|
+
|
|
183
|
+
const m1: Measurement = { value: 10, unit: "kg" };
|
|
184
|
+
const m2: Measurement = { value: 10, unit: "lb" };
|
|
185
|
+
|
|
186
|
+
console.log(Measurement.compareTo(m1, m2)); // 1 (kg > lb alphabetically)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Enum Support
|
|
190
|
+
|
|
191
|
+
PartialOrd works with enums:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
/** @derive(PartialOrd) */
|
|
195
|
+
enum Size {
|
|
196
|
+
Small = 1,
|
|
197
|
+
Medium = 2,
|
|
198
|
+
Large = 3
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Generated:
|
|
202
|
+
// export namespace Size {
|
|
203
|
+
// export function compareTo(a: Size, b: Size): number | null {
|
|
204
|
+
// return a < b ? -1 : a > b ? 1 : 0;
|
|
205
|
+
// }
|
|
206
|
+
// }
|
|
207
|
+
|
|
208
|
+
console.log(Size.compareTo(Size.Small, Size.Large)); // -1
|
|
209
|
+
console.log(Size.compareTo(Size.Large, Size.Small)); // 1
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Type Alias Support
|
|
213
|
+
|
|
214
|
+
PartialOrd works with type aliases:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
/** @derive(PartialOrd) */
|
|
218
|
+
type Interval = {
|
|
219
|
+
start: number;
|
|
220
|
+
end: number;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// Generated:
|
|
224
|
+
// export namespace Interval {
|
|
225
|
+
// export function compareTo(a: Interval, b: Interval): number | null {
|
|
226
|
+
// if (a === b) return 0;
|
|
227
|
+
// const cmp0 = (a.start < b.start ? -1 : a.start > b.start ? 1 : 0);
|
|
228
|
+
// if (cmp0 !== 0) return cmp0;
|
|
229
|
+
// const cmp1 = (a.end < b.end ? -1 : a.end > b.end ? 1 : 0);
|
|
230
|
+
// if (cmp1 !== 0) return cmp1;
|
|
231
|
+
// return 0;
|
|
232
|
+
// }
|
|
233
|
+
// }
|
|
234
|
+
|
|
235
|
+
const i1: Interval = { start: 0, end: 10 };
|
|
236
|
+
const i2: Interval = { start: 0, end: 20 };
|
|
237
|
+
|
|
238
|
+
console.log(Interval.compareTo(i1, i2)); // -1
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## PartialOrd vs Ord
|
|
242
|
+
|
|
243
|
+
Choose between `Ord` and `PartialOrd` based on your use case:
|
|
244
|
+
|
|
245
|
+
- **Ord** → Use when all values are always comparable (never returns null)
|
|
246
|
+
|
|
247
|
+
- **PartialOrd** → Use when comparing with `unknown` types or when some values might be incomparable
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// PartialOrd is safer for public APIs that accept unknown input
|
|
251
|
+
/** @derive(PartialOrd) */
|
|
252
|
+
class SafeValue {
|
|
253
|
+
data: number;
|
|
254
|
+
constructor(data: number) {
|
|
255
|
+
this.data = data;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Can safely compare with any value
|
|
259
|
+
isGreaterThan(other: unknown): boolean {
|
|
260
|
+
const result = this.compareTo(other);
|
|
261
|
+
return result !== null && result > 0;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const safe = new SafeValue(100);
|
|
266
|
+
console.log(safe.isGreaterThan(new SafeValue(50))); // true
|
|
267
|
+
console.log(safe.isGreaterThan("invalid")); // false
|
|
268
|
+
```
|