@macroforge/mcp-server 0.1.37 → 0.1.39
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/api/api-overview.md +13 -13
- package/docs/api/expand-sync.md +8 -8
- package/docs/api/native-plugin.md +15 -15
- package/docs/api/position-mapper.md +6 -6
- package/docs/api/transform-sync.md +11 -11
- 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/macros-overview.md +40 -40
- 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/architecture.md +2 -2
- package/docs/concepts/derive-system.md +25 -39
- package/docs/concepts/how-macros-work.md +8 -4
- package/docs/custom-macros/custom-overview.md +23 -23
- package/docs/custom-macros/rust-setup.md +31 -31
- package/docs/custom-macros/ts-macro-derive.md +107 -107
- package/docs/custom-macros/ts-quote.md +226 -226
- package/docs/getting-started/first-macro.md +38 -28
- package/docs/getting-started/installation.md +15 -15
- package/docs/integration/cli.md +9 -9
- package/docs/integration/configuration.md +16 -16
- package/docs/integration/mcp-server.md +6 -6
- package/docs/integration/svelte-preprocessor.md +40 -41
- package/docs/integration/typescript-plugin.md +13 -12
- package/docs/integration/vite-plugin.md +12 -12
- package/docs/language-servers/zed.md +1 -1
- 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
|
-
- `"prefix"` (default): Prefixes with type name (e.g., `myTypeHashCode`)
|
|
20
|
-
- `"suffix"`: Suffixes with type name (e.g., `hashCodeMyType`)
|
|
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
|
|
@@ -16,57 +16,57 @@
|
|
|
16
16
|
Built-in macros don't require imports. Just use them with `@derive`:
|
|
17
17
|
```
|
|
18
18
|
/** @derive(Debug, Clone, PartialEq) */
|
|
19
|
-
class User
|
|
19
|
+
class User {
|
|
20
20
|
name: string;
|
|
21
21
|
age: number;
|
|
22
22
|
|
|
23
|
-
constructor(name: string, age: number)
|
|
23
|
+
constructor(name: string, age: number) {
|
|
24
24
|
this.name = name;
|
|
25
25
|
this.age = age;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
28
|
``` ## Interface Support
|
|
29
29
|
All built-in macros work with interfaces. For interfaces, methods are generated as functions in a namespace with the same name, using `self` as the first parameter:
|
|
30
30
|
```
|
|
31
31
|
/** @derive(Debug, Clone, PartialEq) */
|
|
32
|
-
interface Point
|
|
32
|
+
interface Point {
|
|
33
33
|
x: number;
|
|
34
34
|
y: number;
|
|
35
|
-
|
|
35
|
+
}
|
|
36
36
|
|
|
37
37
|
// Generated namespace:
|
|
38
|
-
// namespace Point
|
|
39
|
-
// export function toString(self: Point): string
|
|
40
|
-
// export function clone(self: Point): Point
|
|
41
|
-
// export function equals(self: Point, other: Point): boolean
|
|
42
|
-
// export function hashCode(self: Point): number
|
|
43
|
-
//
|
|
38
|
+
// namespace Point {
|
|
39
|
+
// export function toString(self: Point): string { ... }
|
|
40
|
+
// export function clone(self: Point): Point { ... }
|
|
41
|
+
// export function equals(self: Point, other: Point): boolean { ... }
|
|
42
|
+
// export function hashCode(self: Point): number { ... }
|
|
43
|
+
// }
|
|
44
44
|
|
|
45
|
-
const point: Point =
|
|
45
|
+
const point: Point = { x: 10, y: 20 };
|
|
46
46
|
|
|
47
47
|
// Use the namespace functions
|
|
48
|
-
console.log(Point.toString(point)); // "Point
|
|
49
|
-
const copy = Point.clone(point); //
|
|
48
|
+
console.log(Point.toString(point)); // "Point { x: 10, y: 20 }"
|
|
49
|
+
const copy = Point.clone(point); // { x: 10, y: 20 }
|
|
50
50
|
console.log(Point.equals(point, copy)); // true
|
|
51
51
|
``` ## Enum Support
|
|
52
52
|
All built-in macros work with enums. For enums, methods are generated as functions in a namespace with the same name:
|
|
53
53
|
```
|
|
54
54
|
/** @derive(Debug, Clone, PartialEq, Serialize, Deserialize) */
|
|
55
|
-
enum Status
|
|
55
|
+
enum Status {
|
|
56
56
|
Active = "active",
|
|
57
57
|
Inactive = "inactive",
|
|
58
58
|
Pending = "pending",
|
|
59
|
-
|
|
59
|
+
}
|
|
60
60
|
|
|
61
61
|
// Generated namespace:
|
|
62
|
-
// namespace Status
|
|
63
|
-
// export function toString(value: Status): string
|
|
64
|
-
// export function clone(value: Status): Status
|
|
65
|
-
// export function equals(a: Status, b: Status): boolean
|
|
66
|
-
// export function hashCode(value: Status): number
|
|
67
|
-
// export function toJSON(value: Status): string | number
|
|
68
|
-
// export function fromJSON(data: unknown): Status
|
|
69
|
-
//
|
|
62
|
+
// namespace Status {
|
|
63
|
+
// export function toString(value: Status): string { ... }
|
|
64
|
+
// export function clone(value: Status): Status { ... }
|
|
65
|
+
// export function equals(a: Status, b: Status): boolean { ... }
|
|
66
|
+
// export function hashCode(value: Status): number { ... }
|
|
67
|
+
// export function toJSON(value: Status): string | number { ... }
|
|
68
|
+
// export function fromJSON(data: unknown): Status { ... }
|
|
69
|
+
// }
|
|
70
70
|
|
|
71
71
|
// Use the namespace functions
|
|
72
72
|
console.log(Status.toString(Status.Active)); // "Status.Active"
|
|
@@ -77,24 +77,24 @@ const parsed = Status.fromJSON("active"); // Status.Active
|
|
|
77
77
|
All built-in macros work with type aliases. For object type aliases, field-aware methods are generated in a namespace:
|
|
78
78
|
```
|
|
79
79
|
/** @derive(Debug, Clone, PartialEq, Serialize, Deserialize) */
|
|
80
|
-
type Point =
|
|
80
|
+
type Point = {
|
|
81
81
|
x: number;
|
|
82
82
|
y: number;
|
|
83
|
-
|
|
83
|
+
};
|
|
84
84
|
|
|
85
85
|
// Generated namespace:
|
|
86
|
-
// namespace Point
|
|
87
|
-
// export function toString(value: Point): string
|
|
88
|
-
// export function clone(value: Point): Point
|
|
89
|
-
// export function equals(a: Point, b: Point): boolean
|
|
90
|
-
// export function hashCode(value: Point): number
|
|
91
|
-
// export function toJSON(value: Point): Record
|
|
92
|
-
// export function fromJSON(data: unknown): Point
|
|
93
|
-
//
|
|
86
|
+
// namespace Point {
|
|
87
|
+
// export function toString(value: Point): string { ... }
|
|
88
|
+
// export function clone(value: Point): Point { ... }
|
|
89
|
+
// export function equals(a: Point, b: Point): boolean { ... }
|
|
90
|
+
// export function hashCode(value: Point): number { ... }
|
|
91
|
+
// export function toJSON(value: Point): Record<string, unknown> { ... }
|
|
92
|
+
// export function fromJSON(data: unknown): Point { ... }
|
|
93
|
+
// }
|
|
94
94
|
|
|
95
|
-
const point: Point =
|
|
96
|
-
console.log(Point.toString(point)); // "Point
|
|
97
|
-
const copy = Point.clone(point); //
|
|
95
|
+
const point: Point = { x: 10, y: 20 };
|
|
96
|
+
console.log(Point.toString(point)); // "Point { x: 10, y: 20 }"
|
|
97
|
+
const copy = Point.clone(point); // { x: 10, y: 20 }
|
|
98
98
|
console.log(Point.equals(point, copy)); // true
|
|
99
99
|
``` Union type aliases also work, using JSON-based implementations:
|
|
100
100
|
```
|
|
@@ -102,7 +102,7 @@ console.log(Point.equals(point, copy)); // true
|
|
|
102
102
|
type ApiStatus = "loading" | "success" | "error";
|
|
103
103
|
|
|
104
104
|
const status: ApiStatus = "success";
|
|
105
|
-
console.log(ApiStatus.toString(status)); // "ApiStatus(
|
|
105
|
+
console.log(ApiStatus.toString(status)); // "ApiStatus(\\"success\\")"
|
|
106
106
|
console.log(ApiStatus.equals("success", "success")); // true
|
|
107
107
|
``` ## Combining Macros
|
|
108
108
|
All macros can be used together. They don't conflict and each generates independent methods:
|
|
@@ -111,7 +111,7 @@ const user = new User("Alice", 30);
|
|
|
111
111
|
|
|
112
112
|
// Debug
|
|
113
113
|
console.log(user.toString());
|
|
114
|
-
// "User
|
|
114
|
+
// "User { name: Alice, age: 30 }"
|
|
115
115
|
|
|
116
116
|
// Clone
|
|
117
117
|
const copy = user.clone();
|
|
@@ -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
|
-
- `"prefix"` (default): Prefixes with type name (e.g., `myTypeCompare`)
|
|
20
|
-
- `"suffix"`: Suffixes with type name (e.g., `compareMyType`)
|
|
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
|