@macroforge/mcp-server 0.1.36 → 0.1.38
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/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/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/derive-system.md +33 -42
- package/docs/concepts/how-macros-work.md +8 -4
- package/docs/getting-started/first-macro.md +36 -26
- package/docs/sections.json +88 -2
- package/package.json +2 -2
|
@@ -8,18 +8,11 @@ objects to be used as keys in hash-based collections.
|
|
|
8
8
|
|
|
9
9
|
| Type | Generated Code | Description |
|
|
10
10
|
|------|----------------|-------------|
|
|
11
|
-
| Class | `
|
|
12
|
-
| Enum | `
|
|
13
|
-
| Interface | `
|
|
14
|
-
| Type Alias | `
|
|
11
|
+
| Class | `classNameHashCode(value)` + `static hashCode(value)` | Standalone function + static wrapper method |
|
|
12
|
+
| Enum | `enumNameHashCode(value: EnumName): number` | Standalone function hashing by enum value |
|
|
13
|
+
| Interface | `interfaceNameHashCode(value: InterfaceName): number` | Standalone function computing hash |
|
|
14
|
+
| Type Alias | `typeNameHashCode(value: TypeName): number` | Standalone function computing hash |
|
|
15
15
|
|
|
16
|
-
## Configuration
|
|
17
|
-
|
|
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
|
|
23
16
|
|
|
24
17
|
## Hash Algorithm
|
|
25
18
|
|
|
@@ -55,23 +48,97 @@ The `@hash` decorator supports:
|
|
|
55
48
|
|
|
56
49
|
## Example
|
|
57
50
|
|
|
51
|
+
```typescript before
|
|
52
|
+
/** @derive(Hash, PartialEq) */
|
|
53
|
+
class User {
|
|
54
|
+
id: number;
|
|
55
|
+
name: string;
|
|
56
|
+
|
|
57
|
+
/** @hash({ skip: true }) */
|
|
58
|
+
cachedScore: number;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```typescript after
|
|
63
|
+
class User {
|
|
64
|
+
id: number;
|
|
65
|
+
name: string;
|
|
66
|
+
|
|
67
|
+
cachedScore: number;
|
|
68
|
+
|
|
69
|
+
static hashCode(value: User): number {
|
|
70
|
+
return userHashCode(value);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static equals(a: User, b: User): boolean {
|
|
74
|
+
return userEquals(a, b);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function userHashCode(value: User): number {
|
|
79
|
+
let hash = 17;
|
|
80
|
+
hash =
|
|
81
|
+
(hash * 31 +
|
|
82
|
+
(Number.isInteger(value.id)
|
|
83
|
+
? value.id | 0
|
|
84
|
+
: value.id
|
|
85
|
+
.toString()
|
|
86
|
+
.split('')
|
|
87
|
+
.reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
|
|
88
|
+
0;
|
|
89
|
+
hash =
|
|
90
|
+
(hash * 31 +
|
|
91
|
+
(value.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
|
|
92
|
+
0;
|
|
93
|
+
return hash;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function userEquals(a: User, b: User): boolean {
|
|
97
|
+
if (a === b) return true;
|
|
98
|
+
return a.id === b.id && a.name === b.name && a.cachedScore === b.cachedScore;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Generated output:
|
|
103
|
+
|
|
58
104
|
```typescript
|
|
59
|
-
@derive(Hash, PartialEq)
|
|
60
105
|
class User {
|
|
61
106
|
id: number;
|
|
62
107
|
name: string;
|
|
63
108
|
|
|
64
|
-
@hash(skip) // Cached value shouldn't affect hash
|
|
65
109
|
cachedScore: number;
|
|
110
|
+
|
|
111
|
+
static hashCode(value: User): number {
|
|
112
|
+
return userHashCode(value);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static equals(a: User, b: User): boolean {
|
|
116
|
+
return userEquals(a, b);
|
|
117
|
+
}
|
|
66
118
|
}
|
|
67
119
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
120
|
+
export function userHashCode(value: User): number {
|
|
121
|
+
let hash = 17;
|
|
122
|
+
hash =
|
|
123
|
+
(hash * 31 +
|
|
124
|
+
(Number.isInteger(value.id)
|
|
125
|
+
? value.id | 0
|
|
126
|
+
: value.id
|
|
127
|
+
.toString()
|
|
128
|
+
.split('')
|
|
129
|
+
.reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
|
|
130
|
+
0;
|
|
131
|
+
hash =
|
|
132
|
+
(hash * 31 +
|
|
133
|
+
(value.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
|
|
134
|
+
0;
|
|
135
|
+
return hash;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function userEquals(a: User, b: User): boolean {
|
|
139
|
+
if (a === b) return true;
|
|
140
|
+
return a.id === b.id && a.name === b.name && a.cachedScore === b.cachedScore;
|
|
141
|
+
}
|
|
75
142
|
```
|
|
76
143
|
|
|
77
144
|
## Hash Contract
|
|
@@ -8,29 +8,22 @@ compared with a guaranteed ordering relationship.
|
|
|
8
8
|
|
|
9
9
|
| Type | Generated Code | Description |
|
|
10
10
|
|------|----------------|-------------|
|
|
11
|
-
| Class | `
|
|
12
|
-
| Enum | `
|
|
13
|
-
| Interface | `
|
|
14
|
-
| Type Alias | `
|
|
11
|
+
| Class | `classNameCompare(a, b)` + `static compareTo(a, b)` | Standalone function + static wrapper method |
|
|
12
|
+
| Enum | `enumNameCompare(a: EnumName, b: EnumName): number` | Standalone function comparing enum values |
|
|
13
|
+
| Interface | `interfaceNameCompare(a: InterfaceName, b: InterfaceName): number` | Standalone function comparing fields |
|
|
14
|
+
| Type Alias | `typeNameCompare(a: TypeName, b: TypeName): number` | Standalone function with type-appropriate comparison |
|
|
15
15
|
|
|
16
|
-
## Configuration
|
|
17
|
-
|
|
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
|
|
23
16
|
|
|
24
17
|
## Return Values
|
|
25
18
|
|
|
26
19
|
Unlike `PartialOrd`, `Ord` provides **total ordering** - every pair of values
|
|
27
20
|
can be compared:
|
|
28
21
|
|
|
29
|
-
- **-1**: `
|
|
30
|
-
- **0**: `
|
|
31
|
-
- **1**: `
|
|
22
|
+
- **-1**: `a` is less than `b`
|
|
23
|
+
- **0**: `a` is equal to `b`
|
|
24
|
+
- **1**: `a` is greater than `b`
|
|
32
25
|
|
|
33
|
-
The
|
|
26
|
+
The function **never returns null** - all values must be comparable.
|
|
34
27
|
|
|
35
28
|
## Comparison Strategy
|
|
36
29
|
|
|
@@ -60,29 +53,61 @@ The `@ord` decorator supports:
|
|
|
60
53
|
|
|
61
54
|
## Example
|
|
62
55
|
|
|
56
|
+
```typescript before
|
|
57
|
+
/** @derive(Ord) */
|
|
58
|
+
class Version {
|
|
59
|
+
major: number;
|
|
60
|
+
minor: number;
|
|
61
|
+
patch: number;
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```typescript after
|
|
66
|
+
class Version {
|
|
67
|
+
major: number;
|
|
68
|
+
minor: number;
|
|
69
|
+
patch: number;
|
|
70
|
+
|
|
71
|
+
static compareTo(a: Version, b: Version): number {
|
|
72
|
+
return versionCompare(a, b);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function versionCompare(a: Version, b: Version): number {
|
|
77
|
+
if (a === b) return 0;
|
|
78
|
+
const cmp0 = a.major < b.major ? -1 : a.major > b.major ? 1 : 0;
|
|
79
|
+
if (cmp0 !== 0) return cmp0;
|
|
80
|
+
const cmp1 = a.minor < b.minor ? -1 : a.minor > b.minor ? 1 : 0;
|
|
81
|
+
if (cmp1 !== 0) return cmp1;
|
|
82
|
+
const cmp2 = a.patch < b.patch ? -1 : a.patch > b.patch ? 1 : 0;
|
|
83
|
+
if (cmp2 !== 0) return cmp2;
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Generated output:
|
|
89
|
+
|
|
63
90
|
```typescript
|
|
64
|
-
@derive(Ord)
|
|
65
91
|
class Version {
|
|
66
92
|
major: number;
|
|
67
93
|
minor: number;
|
|
68
94
|
patch: number;
|
|
95
|
+
|
|
96
|
+
static compareTo(a: Version, b: Version): number {
|
|
97
|
+
return versionCompare(a, b);
|
|
98
|
+
}
|
|
69
99
|
}
|
|
70
100
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// return 0;
|
|
82
|
-
// }
|
|
83
|
-
|
|
84
|
-
// Usage:
|
|
85
|
-
versions.sort((a, b) => a.compareTo(b));
|
|
101
|
+
export function versionCompare(a: Version, b: Version): number {
|
|
102
|
+
if (a === b) return 0;
|
|
103
|
+
const cmp0 = a.major < b.major ? -1 : a.major > b.major ? 1 : 0;
|
|
104
|
+
if (cmp0 !== 0) return cmp0;
|
|
105
|
+
const cmp1 = a.minor < b.minor ? -1 : a.minor > b.minor ? 1 : 0;
|
|
106
|
+
if (cmp1 !== 0) return cmp1;
|
|
107
|
+
const cmp2 = a.patch < b.patch ? -1 : a.patch > b.patch ? 1 : 0;
|
|
108
|
+
if (cmp2 !== 0) return cmp2;
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
86
111
|
```
|
|
87
112
|
|
|
88
113
|
## Ord vs PartialOrd
|