@macroforge/mcp-server 0.1.34 → 0.1.36

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,279 +1,81 @@
1
1
  # Hash
2
- *The `Hash` macro generates a `hashCode()` method for computing numeric hash codes. This is analogous to Rust's `Hash` trait and Java's `hashCode()` method, enabling objects to be used as keys in hash-based collections.*
3
- ## Basic Usage
4
- **Before:**
5
- ```
6
- /** @derive(Hash) */
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 `Hash` macro generates a `hashCode()` method for computing numeric hash codes.
4
+ This is analogous to Rust's `Hash` trait and Java's `hashCode()` method, enabling
5
+ objects to be used as keys in hash-based collections.
22
6
 
23
- constructor(x: number, y: number) {
24
- this.x = x;
25
- this.y = y;
26
- }
7
+ ## Generated Output
27
8
 
28
- hashCode(): number {
29
- let hash = 17;
30
- hash =
31
- (hash * 31 +
32
- (Number.isInteger(this.x)
33
- ? this.x | 0
34
- : this.x
35
- .toString()
36
- .split('')
37
- .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
38
- 0;
39
- hash =
40
- (hash * 31 +
41
- (Number.isInteger(this.y)
42
- ? this.y | 0
43
- : this.y
44
- .toString()
45
- .split('')
46
- .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
47
- 0;
48
- return hash;
49
- }
50
- }
51
- ``` ```
52
- const p1 = new Point(10, 20);
53
- const p2 = new Point(10, 20);
54
- const p3 = new Point(5, 5);
9
+ | Type | Generated Code | Description |
10
+ |------|----------------|-------------|
11
+ | Class | `hashCode(): number` | Instance method computing hash from all fields |
12
+ | Enum | `hashCodeEnumName(value: EnumName): number` | Standalone function hashing by enum value |
13
+ | Interface | `hashCodeInterfaceName(value: InterfaceName): number` | Standalone function computing hash |
14
+ | Type Alias | `hashCodeTypeName(value: TypeName): number` | Standalone function computing hash |
55
15
 
56
- console.log(p1.hashCode()); // Same hash
57
- console.log(p2.hashCode()); // Same hash (equal values = equal hash)
58
- console.log(p3.hashCode()); // Different hash
59
- ``` ## Hash Algorithm
60
- The generated hash function uses the following algorithm for different types:
61
- - `number` → Integers use bitwise OR (`| 0`), floats are stringified and hashed
62
- - `string` → Character-by-character hash: `(h * 31 + charCode) | 0`
63
- - `boolean` → `1231` for true, `1237` for false (Java convention)
64
- - `bigint` → Converted to string and hashed character-by-character
65
- - `Date` → Uses `getTime() | 0` for timestamp hash
66
- - `Array` → Combines element hashes with `h * 31 + elementHash`
67
- - `Map/Set` → Combines all entry hashes
68
- - `Object` → Calls `hashCode()` if available, otherwise JSON stringifies and hashes
69
- - `null` → Returns 0
70
- - `undefined` → Returns 1
71
- ## Field Options
72
- ### @hash(skip)
73
- Use `@hash(skip)` to exclude a field from hash computation:
74
- **Before:**
75
- ```
76
- /** @derive(Hash) */
77
- class User {
78
- id: number;
79
- name: string;
16
+ ## Configuration
80
17
 
81
- /** @hash(skip) */
82
- lastLogin: Date;
18
+ The `functionNamingStyle` option in `macroforge.json` controls naming:
19
+ - `"suffix"` (default): Suffixes with type name (e.g., `hashCodeMyType`)
20
+ - `"prefix"`: Prefixes with type name (e.g., `myTypeHashCode`)
21
+ - `"generic"`: Uses TypeScript generics (e.g., `hashCode<T extends MyType>`)
22
+ - `"namespace"`: Legacy namespace wrapping
83
23
 
84
- constructor(id: number, name: string, lastLogin: Date) {
85
- this.id = id;
86
- this.name = name;
87
- this.lastLogin = lastLogin;
88
- }
89
- }
90
- ```
91
- **After:**
24
+ ## Hash Algorithm
25
+
26
+ Uses the standard polynomial rolling hash algorithm:
27
+
28
+ ```text
29
+ hash = 17 // Initial seed
30
+ for each field:
31
+ hash = (hash * 31 + fieldHash) | 0 // Bitwise OR keeps it 32-bit integer
92
32
  ```
93
- class User {
94
- id: number;
95
- name: string;
96
33
 
97
- lastLogin: Date;
34
+ This algorithm is consistent with Java's `Objects.hash()` implementation.
98
35
 
99
- constructor(id: number, name: string, lastLogin: Date) {
100
- this.id = id;
101
- this.name = name;
102
- this.lastLogin = lastLogin;
103
- }
36
+ ## Type-Specific Hashing
104
37
 
105
- hashCode(): number {
106
- let hash = 17;
107
- hash =
108
- (hash * 31 +
109
- (Number.isInteger(this.id)
110
- ? this.id | 0
111
- : this.id
112
- .toString()
113
- .split('')
114
- .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
115
- 0;
116
- hash =
117
- (hash * 31 +
118
- (this.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
119
- 0;
120
- return hash;
121
- }
122
- }
123
- ``` ```
124
- const user1 = new User(1, "Alice", new Date("2024-01-01"));
125
- const user2 = new User(1, "Alice", new Date("2024-12-01"));
38
+ | Type | Hash Strategy |
39
+ |------|---------------|
40
+ | `number` | Integer: direct value; Float: string hash of decimal |
41
+ | `bigint` | String hash of decimal representation |
42
+ | `string` | Character-by-character polynomial hash |
43
+ | `boolean` | 1231 for true, 1237 for false (Java convention) |
44
+ | `Date` | `getTime()` timestamp |
45
+ | Arrays | Element-by-element hash combination |
46
+ | `Map` | Entry-by-entry key+value hash |
47
+ | `Set` | Element-by-element hash |
48
+ | Objects | Calls `hashCode()` if available, else JSON string hash |
126
49
 
127
- console.log(user1.hashCode() === user2.hashCode()); // true (lastLogin is skipped)
128
- ``` ## Use with PartialEq
129
- Hash is often used together with PartialEq. Objects that are equal should have the same hash code:
130
- **Source:**
131
- ```
132
- /** @derive(Hash, PartialEq) */
133
- class Product {
134
- sku: string;
135
- name: string;
50
+ ## Field-Level Options
136
51
 
137
- constructor(sku: string, name: string) {
138
- this.sku = sku;
139
- this.name = name;
140
- }
141
- }
142
- ``` ```
143
- const p1 = new Product("ABC123", "Widget");
144
- const p2 = new Product("ABC123", "Widget");
52
+ The `@hash` decorator supports:
145
53
 
146
- // Equal objects have equal hash codes
147
- console.log(p1.equals(p2)); // true
148
- console.log(p1.hashCode() === p2.hashCode()); // true
149
- ``` ## Interface Support
150
- Hash also works with interfaces. For interfaces, a namespace is generated with a `hashCode` function:
151
- **Before:**
152
- ```
153
- /** @derive(Hash) */
154
- interface Point {
155
- x: number;
156
- y: number;
157
- }
158
- ```
159
- **After:**
160
- ```
161
- interface Point {
162
- x: number;
163
- y: number;
164
- }
54
+ - `skip` - Exclude the field from hash calculation
165
55
 
166
- export namespace Point {
167
- export function hashCode(self: Point): number {
168
- let hash = 17;
169
- hash =
170
- (hash * 31 +
171
- (Number.isInteger(self.x)
172
- ? self.x | 0
173
- : self.x
174
- .toString()
175
- .split('')
176
- .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
177
- 0;
178
- hash =
179
- (hash * 31 +
180
- (Number.isInteger(self.y)
181
- ? self.y | 0
182
- : self.y
183
- .toString()
184
- .split('')
185
- .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
186
- 0;
187
- return hash;
188
- }
189
- }
190
- ``` ```
191
- const p: Point = { x: 10, y: 20 };
192
- console.log(Point.hashCode(p)); // numeric hash value
193
- ``` ## Enum Support
194
- Hash works with enums. For string enums, it hashes the string value; for numeric enums, it uses the numeric value directly:
195
- **Before:**
196
- ```
197
- /** @derive(Hash) */
198
- enum Status {
199
- Active = 'active',
200
- Inactive = 'inactive',
201
- Pending = 'pending'
202
- }
203
- ```
204
- **After:**
205
- ```
206
- enum Status {
207
- Active = 'active',
208
- Inactive = 'inactive',
209
- Pending = 'pending'
210
- }
56
+ ## Example
211
57
 
212
- export namespace Status {
213
- export function hashCode(value: Status): number {
214
- if (typeof value === 'string') {
215
- let hash = 0;
216
- for (let i = 0; i < value.length; i++) {
217
- hash = (hash * 31 + value.charCodeAt(i)) | 0;
218
- }
219
- return hash;
220
- }
221
- return value as number;
222
- }
223
- }
224
- ``` ```
225
- console.log(Status.hashCode(Status.Active)); // consistent hash
226
- console.log(Status.hashCode(Status.Inactive)); // different hash
227
- ``` ## Type Alias Support
228
- Hash works with type aliases. For object types, it hashes each field:
229
- **Before:**
230
- ```
231
- /** @derive(Hash) */
232
- type Coordinates = {
233
- lat: number;
234
- lng: number;
235
- };
236
- ```
237
- **After:**
238
- ```
239
- type Coordinates = {
240
- lat: number;
241
- lng: number;
242
- };
58
+ ```typescript
59
+ @derive(Hash, PartialEq)
60
+ class User {
61
+ id: number;
62
+ name: string;
243
63
 
244
- export namespace Coordinates {
245
- export function hashCode(value: Coordinates): number {
246
- let hash = 17;
247
- hash =
248
- (hash * 31 +
249
- (Number.isInteger(value.lat)
250
- ? value.lat | 0
251
- : value.lat
252
- .toString()
253
- .split('')
254
- .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
255
- 0;
256
- hash =
257
- (hash * 31 +
258
- (Number.isInteger(value.lng)
259
- ? value.lng | 0
260
- : value.lng
261
- .toString()
262
- .split('')
263
- .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
264
- 0;
265
- return hash;
266
- }
64
+ @hash(skip) // Cached value shouldn't affect hash
65
+ cachedScore: number;
267
66
  }
268
- ``` ```
269
- const loc: Coordinates = { lat: 40.7128, lng: -74.0060 };
270
- console.log(Coordinates.hashCode(loc));
271
- ``` For union types, it uses JSON stringification as a fallback:
272
- **Source:**
67
+
68
+ // Generated:
69
+ // hashCode(): number {
70
+ // let hash = 17;
71
+ // hash = (hash * 31 + (Number.isInteger(this.id) ? this.id | 0 : ...)) | 0;
72
+ // hash = (hash * 31 + (this.name ?? '').split('').reduce(...)) | 0;
73
+ // return hash;
74
+ // }
273
75
  ```
274
- /** @derive(Hash) */
275
- type Result = "success" | "error" | "pending";
276
- ``` ```
277
- console.log(Result.hashCode("success")); // hash of "success" string
278
- console.log(Result.hashCode("error")); // hash of "error" string
279
- ```
76
+
77
+ ## Hash Contract
78
+
79
+ Objects that are equal (`PartialEq`) should produce the same hash code.
80
+ When using `@hash(skip)`, ensure the same fields are skipped in both
81
+ `Hash` and `PartialEq` to maintain this contract.
@@ -1,272 +1,91 @@
1
1
  # Ord
2
- *The `Ord` macro generates a `compareTo()` method for **total ordering** comparison. This is analogous to Rust's `Ord` trait, enabling objects to be sorted and compared with a guaranteed ordering relationship.*
3
- ## Basic Usage
4
- **Before:**
5
- ```
6
- /** @derive(Ord) */
7
- class Version {
8
- major: number;
9
- minor: number;
10
- patch: number;
11
2
 
12
- constructor(major: number, minor: number, patch: number) {
13
- this.major = major;
14
- this.minor = minor;
15
- this.patch = patch;
16
- }
17
- }
18
- ```
19
- **After:**
20
- ```
21
- class Version {
22
- major: number;
23
- minor: number;
24
- patch: number;
3
+ The `Ord` macro generates a `compareTo()` method for **total ordering** comparison.
4
+ This is analogous to Rust's `Ord` trait, enabling objects to be sorted and
5
+ compared with a guaranteed ordering relationship.
25
6
 
26
- constructor(major: number, minor: number, patch: number) {
27
- this.major = major;
28
- this.minor = minor;
29
- this.patch = patch;
30
- }
7
+ ## Generated Output
31
8
 
32
- compareTo(other: Version): number {
33
- if (this === other) return 0;
34
- const typedOther = other;
35
- const cmp0 = this.major < typedOther.major ? -1 : this.major > typedOther.major ? 1 : 0;
36
- if (cmp0 !== 0) return cmp0;
37
- const cmp1 = this.minor < typedOther.minor ? -1 : this.minor > typedOther.minor ? 1 : 0;
38
- if (cmp1 !== 0) return cmp1;
39
- const cmp2 = this.patch < typedOther.patch ? -1 : this.patch > typedOther.patch ? 1 : 0;
40
- if (cmp2 !== 0) return cmp2;
41
- return 0;
42
- }
43
- }
44
- ``` ```
45
- const v1 = new Version(1, 0, 0);
46
- const v2 = new Version(1, 2, 0);
47
- const v3 = new Version(1, 2, 0);
9
+ | Type | Generated Code | Description |
10
+ |------|----------------|-------------|
11
+ | Class | `compareTo(other): number` | Instance method returning -1, 0, or 1 |
12
+ | Enum | `compareEnumName(a: EnumName, b: EnumName): number` | Standalone function comparing enum values |
13
+ | Interface | `compareInterfaceName(a: InterfaceName, b: InterfaceName): number` | Standalone function comparing fields |
14
+ | Type Alias | `compareTypeName(a: TypeName, b: TypeName): number` | Standalone function with type-appropriate comparison |
48
15
 
49
- console.log(v1.compareTo(v2)); // -1 (v1 < v2)
50
- console.log(v2.compareTo(v1)); // 1 (v2 > v1)
51
- console.log(v2.compareTo(v3)); // 0 (v2 == v3)
52
- ``` ## Comparison Logic
53
- The Ord macro compares fields in declaration order (lexicographic ordering). For each type:
54
- - `number` / `bigint` → Direct numeric comparison
55
- - `string` → Uses `localeCompare()` clamped to -1/0/1
56
- - `boolean` → `false < true`
57
- - `Date` → Compares timestamps via `getTime()`
58
- - `Array` → Lexicographic: compares element-by-element, then length
59
- - `Map/Set` → Size and content comparison
60
- - `Object` → Calls `compareTo()` if available, otherwise 0
61
- - `null/undefined` → Treated as equal (returns 0)
62
- ## Return Values
63
- The `compareTo()` method always returns:
64
- - `-1` → `this` is less than `other`
65
- - `0` → `this` equals `other`
66
- - `1` → `this` is greater than `other`
67
- Unlike `PartialOrd`, the `Ord` macro never returns `null` - it provides total ordering.
68
- ## Field Options
69
- ### @ord(skip)
70
- Use `@ord(skip)` to exclude a field from ordering comparison:
71
- **Before:**
72
- ```
73
- /** @derive(Ord) */
74
- class Task {
75
- priority: number;
76
- name: string;
16
+ ## Configuration
77
17
 
78
- /** @ord(skip) */
79
- createdAt: Date;
18
+ The `functionNamingStyle` option in `macroforge.json` controls naming:
19
+ - `"suffix"` (default): Suffixes with type name (e.g., `compareMyType`)
20
+ - `"prefix"`: Prefixes with type name (e.g., `myTypeCompare`)
21
+ - `"generic"`: Uses TypeScript generics (e.g., `compare<T extends MyType>`)
22
+ - `"namespace"`: Legacy namespace wrapping
80
23
 
81
- constructor(priority: number, name: string, createdAt: Date) {
82
- this.priority = priority;
83
- this.name = name;
84
- this.createdAt = createdAt;
85
- }
86
- }
87
- ```
88
- **After:**
89
- ```
90
- class Task {
91
- priority: number;
92
- name: string;
24
+ ## Return Values
93
25
 
94
- createdAt: Date;
26
+ Unlike `PartialOrd`, `Ord` provides **total ordering** - every pair of values
27
+ can be compared:
95
28
 
96
- constructor(priority: number, name: string, createdAt: Date) {
97
- this.priority = priority;
98
- this.name = name;
99
- this.createdAt = createdAt;
100
- }
29
+ - **-1**: `this` is less than `other`
30
+ - **0**: `this` is equal to `other`
31
+ - **1**: `this` is greater than `other`
101
32
 
102
- compareTo(other: Task): number {
103
- if (this === other) return 0;
104
- const typedOther = other;
105
- const cmp0 =
106
- this.priority < typedOther.priority ? -1 : this.priority > typedOther.priority ? 1 : 0;
107
- if (cmp0 !== 0) return cmp0;
108
- const cmp1 = ((cmp) => (cmp < 0 ? -1 : cmp > 0 ? 1 : 0))(
109
- this.name.localeCompare(typedOther.name)
110
- );
111
- if (cmp1 !== 0) return cmp1;
112
- return 0;
113
- }
114
- }
115
- ``` ```
116
- const t1 = new Task(1, "Bug fix", new Date("2024-01-01"));
117
- const t2 = new Task(1, "Bug fix", new Date("2024-12-01"));
33
+ The method **never returns null** - all values must be comparable.
118
34
 
119
- console.log(t1.compareTo(t2)); // 0 (createdAt is skipped)
120
- ``` ## Sorting Arrays
121
- The generated `compareTo()` method works directly with `Array.sort()`:
122
- **Source:**
123
- ```
124
- /** @derive(Ord) */
125
- class Score {
126
- points: number;
127
- name: string;
35
+ ## Comparison Strategy
128
36
 
129
- constructor(points: number, name: string) {
130
- this.points = points;
131
- this.name = name;
132
- }
133
- }
134
- ``` ```
135
- const scores = [
136
- new Score(100, "Alice"),
137
- new Score(50, "Bob"),
138
- new Score(150, "Charlie"),
139
- new Score(50, "Alice") // Same points, different name
140
- ];
37
+ Fields are compared **lexicographically** in declaration order:
141
38
 
142
- // Sort ascending
143
- scores.sort((a, b) => a.compareTo(b));
144
- // Result: [Bob(50), Alice(50), Alice(100), Charlie(150)]
39
+ 1. Compare first field
40
+ 2. If not equal, return that result
41
+ 3. Otherwise, compare next field
42
+ 4. Continue until a difference is found or all fields are equal
145
43
 
146
- // Sort descending
147
- scores.sort((a, b) => b.compareTo(a));
148
- // Result: [Charlie(150), Alice(100), Alice(50), Bob(50)]
149
- ``` ## Interface Support
150
- Ord works with interfaces. For interfaces, a namespace is generated with a `compareTo` function:
151
- **Before:**
152
- ```
153
- /** @derive(Ord) */
154
- interface Point {
155
- x: number;
156
- y: number;
157
- }
158
- ```
159
- **After:**
160
- ```
161
- interface Point {
162
- x: number;
163
- y: number;
164
- }
44
+ ## Type-Specific Comparisons
165
45
 
166
- export namespace Point {
167
- export function compareTo(self: Point, other: Point): number {
168
- if (self === other) return 0;
169
- const cmp0 = self.x < other.x ? -1 : self.x > other.x ? 1 : 0;
170
- if (cmp0 !== 0) return cmp0;
171
- const cmp1 = self.y < other.y ? -1 : self.y > other.y ? 1 : 0;
172
- if (cmp1 !== 0) return cmp1;
173
- return 0;
174
- }
175
- }
176
- ``` ```
177
- const points: Point[] = [
178
- { x: 5, y: 10 },
179
- { x: 1, y: 20 },
180
- { x: 5, y: 5 }
181
- ];
46
+ | Type | Comparison Method |
47
+ |------|-------------------|
48
+ | `number`/`bigint` | Direct `<` and `>` comparison |
49
+ | `string` | `localeCompare()` (clamped to -1, 0, 1) |
50
+ | `boolean` | false &lt; true |
51
+ | Arrays | Lexicographic element-by-element |
52
+ | `Date` | `getTime()` timestamp comparison |
53
+ | Objects | Calls `compareTo()` if available, else 0 |
182
54
 
183
- points.sort((a, b) => Point.compareTo(a, b));
184
- // Result: [{ x: 1, y: 20 }, { x: 5, y: 5 }, { x: 5, y: 10 }]
185
- ``` ## Enum Support
186
- Ord works with enums. For numeric enums, it compares the numeric values; for string enums, it uses string comparison:
187
- **Before:**
188
- ```
189
- /** @derive(Ord) */
190
- enum Priority {
191
- Low = 0,
192
- Medium = 1,
193
- High = 2,
194
- Critical = 3
195
- }
196
- ```
197
- **After:**
198
- ```
199
- enum Priority {
200
- Low = 0,
201
- Medium = 1,
202
- High = 2,
203
- Critical = 3
204
- }
55
+ ## Field-Level Options
205
56
 
206
- export namespace Priority {
207
- export function compareTo(a: Priority, b: Priority): number {
208
- if (typeof a === 'number' && typeof b === 'number') {
209
- return a < b ? -1 : a > b ? 1 : 0;
210
- }
211
- if (typeof a === 'string' && typeof b === 'string') {
212
- const cmp = a.localeCompare(b);
213
- return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
214
- }
215
- return 0;
216
- }
217
- }
218
- ``` ```
219
- console.log(Priority.compareTo(Priority.Low, Priority.High)); // -1
220
- console.log(Priority.compareTo(Priority.Critical, Priority.Low)); // 1
221
- console.log(Priority.compareTo(Priority.Medium, Priority.Medium)); // 0
222
- ``` ## Type Alias Support
223
- Ord works with type aliases. For object types, it uses lexicographic field comparison:
224
- **Before:**
225
- ```
226
- /** @derive(Ord) */
227
- type Coordinate = {
228
- x: number;
229
- y: number;
230
- };
231
- ```
232
- **After:**
233
- ```
234
- type Coordinate = {
235
- x: number;
236
- y: number;
237
- };
57
+ The `@ord` decorator supports:
238
58
 
239
- export namespace Coordinate {
240
- export function compareTo(a: Coordinate, b: Coordinate): number {
241
- if (a === b) return 0;
242
- const cmp0 = a.x < b.x ? -1 : a.x > b.x ? 1 : 0;
243
- if (cmp0 !== 0) return cmp0;
244
- const cmp1 = a.y < b.y ? -1 : a.y > b.y ? 1 : 0;
245
- if (cmp1 !== 0) return cmp1;
246
- return 0;
247
- }
248
- }
249
- ``` ```
250
- const c1: Coordinate = { x: 10, y: 20 };
251
- const c2: Coordinate = { x: 10, y: 30 };
59
+ - `skip` - Exclude the field from ordering comparison
252
60
 
253
- console.log(Coordinate.compareTo(c1, c2)); // -1 (c1 < c2)
254
- ``` ## Ord vs PartialOrd
255
- Use `Ord` when all values of a type are comparable. Use `PartialOrd` when some values might be incomparable (e.g., different types at runtime).
256
- **Source:**
257
- ```
258
- // Ord: Total ordering - never returns null
259
- /** @derive(Ord) */
61
+ ## Example
62
+
63
+ ```typescript
64
+ @derive(Ord)
260
65
  class Version {
261
- major: number;
262
- minor: number;
263
- constructor(major: number, minor: number) {
264
- this.major = major;
265
- this.minor = minor;
266
- }
66
+ major: number;
67
+ minor: number;
68
+ patch: number;
267
69
  }
268
- ``` ```
269
- const v1 = new Version(1, 0);
270
- const v2 = new Version(2, 0);
271
- console.log(v1.compareTo(v2)); // Always -1, 0, or 1
272
- ```
70
+
71
+ // Generated:
72
+ // compareTo(other: Version): number {
73
+ // if (this === other) return 0;
74
+ // const typedOther = other;
75
+ // const cmp0 = this.major < typedOther.major ? -1 : this.major > typedOther.major ? 1 : 0;
76
+ // if (cmp0 !== 0) return cmp0;
77
+ // const cmp1 = this.minor < typedOther.minor ? -1 : ...;
78
+ // if (cmp1 !== 0) return cmp1;
79
+ // const cmp2 = this.patch < typedOther.patch ? -1 : ...;
80
+ // if (cmp2 !== 0) return cmp2;
81
+ // return 0;
82
+ // }
83
+
84
+ // Usage:
85
+ versions.sort((a, b) => a.compareTo(b));
86
+ ```
87
+
88
+ ## Ord vs PartialOrd
89
+
90
+ - Use **Ord** when all values are comparable (total ordering)
91
+ - Use **PartialOrd** when some values may be incomparable (returns `Option<number>`)