@macroforge/mcp-server 0.1.77 → 0.1.79
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 +13 -10
- package/docs/builtin-macros/debug.md +3 -1
- package/docs/builtin-macros/default.md +10 -8
- package/docs/builtin-macros/deserialize/cycleforward-reference-support.md +3 -2
- package/docs/builtin-macros/deserialize/example.md +10 -9
- package/docs/builtin-macros/deserialize/overview.md +10 -10
- package/docs/builtin-macros/deserialize/union-type-deserialization.md +15 -9
- package/docs/builtin-macros/deserialize/validation.md +5 -1
- package/docs/builtin-macros/deserialize.md +3 -308
- package/docs/builtin-macros/hash.md +6 -12
- package/docs/builtin-macros/partial-eq.md +4 -76
- package/docs/builtin-macros/partial-ord.md +19 -17
- package/docs/builtin-macros/serialize.md +3 -3
- package/docs/integration/cli.md +1 -1
- package/docs/language-servers/ls-overview.md +1 -1
- package/docs/language-servers/svelte-ls.md +1 -1
- package/docs/language-servers/svelte.md +1 -1
- package/docs/language-servers/zed-extensions.md +1 -1
- package/docs/language-servers/zed.md +1 -1
- package/docs/roadmap/roadmap.md +1 -1
- package/docs/sections.json +1 -54
- package/package.json +3 -3
|
@@ -9,21 +9,24 @@ independent copies of values.
|
|
|
9
9
|
| Type | Generated Code | Description |
|
|
10
10
|
|------|----------------|-------------|
|
|
11
11
|
| Class | `classNameClone(value)` + `static clone(value)` | Standalone function + static wrapper method |
|
|
12
|
-
| Enum | `enumNameClone(value
|
|
13
|
-
| Interface | `
|
|
14
|
-
| Type Alias | `typeNameClone(value
|
|
12
|
+
| Enum | `enumNameClone(value): EnumName` | Standalone function (enums are primitives, returns value as-is) |
|
|
13
|
+
| Interface | `ifaceNameClone(value): InterfaceName` | Standalone function creating a new object literal |
|
|
14
|
+
| Type Alias | `typeNameClone(value): TypeName` | Standalone function with spread copy for objects |
|
|
15
15
|
|
|
16
|
+
Names use **camelCase** conversion (e.g., `Point` -> `pointClone`).
|
|
16
17
|
|
|
17
|
-
## Cloning Strategy
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
## Cloning Strategy
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
- **Objects**: Reference is copied (not deep cloned)
|
|
23
|
-
- **Arrays**: Reference is copied (not deep cloned)
|
|
21
|
+
The generated clone is **type-aware** when a type registry is available:
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
- **Primitives** (`string`, `number`, `boolean`, `bigint`): Copied by value
|
|
24
|
+
- **`Date`**: Deep cloned via `new Date(x.getTime())`
|
|
25
|
+
- **Arrays**: Spread copy `[...arr]`, or deep map if element type has `Clone`
|
|
26
|
+
- **`Map`/`Set`**: New collection, deep copy if value type has `Clone`
|
|
27
|
+
- **Objects with `@derive(Clone)`**: Deep cloned via their standalone clone function
|
|
28
|
+
- **Optional fields**: Null-checked -- `null`/`undefined` pass through unchanged
|
|
29
|
+
- **Other objects**: Shallow copy (reference)
|
|
27
30
|
|
|
28
31
|
## Example
|
|
29
32
|
|
|
@@ -11,11 +11,13 @@ method `static toString(value)` returning a string like `"ClassName { field1: va
|
|
|
11
11
|
**Enums**: Generates a standalone function `enumNameToString(value)` that performs
|
|
12
12
|
reverse lookup on numeric enums.
|
|
13
13
|
|
|
14
|
-
**Interfaces**: Generates a standalone function `
|
|
14
|
+
**Interfaces**: Generates a standalone function `ifaceNameToString(value)`.
|
|
15
15
|
|
|
16
16
|
**Type Aliases**: Generates a standalone function using JSON.stringify for
|
|
17
17
|
complex types, or field enumeration for object types.
|
|
18
18
|
|
|
19
|
+
Names use **camelCase** conversion (e.g., `User` -> `userToString`).
|
|
20
|
+
|
|
19
21
|
|
|
20
22
|
## Field-Level Options
|
|
21
23
|
|
|
@@ -8,10 +8,12 @@ a standard way to create "zero" or "empty" instances of types.
|
|
|
8
8
|
|
|
9
9
|
| Type | Generated Code | Description |
|
|
10
10
|
|------|----------------|-------------|
|
|
11
|
-
| Class | `static defaultValue()
|
|
12
|
-
| Enum | `
|
|
13
|
-
| Interface | `
|
|
14
|
-
| Type Alias | `
|
|
11
|
+
| Class | `static defaultValue()` + `classNameDefaultValue()` | Static factory method + standalone function |
|
|
12
|
+
| Enum | `enumNameDefaultValue(): EnumName` | Standalone function returning `@default` variant |
|
|
13
|
+
| Interface | `ifaceNameDefaultValue(): InterfaceName` | Standalone function returning object literal |
|
|
14
|
+
| Type Alias | `typeNameDefaultValue(): TypeName` | Standalone function with type-appropriate default |
|
|
15
|
+
|
|
16
|
+
Names use **camelCase** conversion (e.g., `UserSettings` -> `userSettingsDefaultValue`).
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
## Default Values by Type
|
|
@@ -72,6 +74,10 @@ class UserSettings {
|
|
|
72
74
|
return instance;
|
|
73
75
|
}
|
|
74
76
|
}
|
|
77
|
+
|
|
78
|
+
export function userSettingsDefaultValue(): UserSettings {
|
|
79
|
+
return UserSettings.defaultValue();
|
|
80
|
+
}
|
|
75
81
|
```
|
|
76
82
|
|
|
77
83
|
## Enum Defaults
|
|
@@ -99,10 +105,6 @@ enum Status {
|
|
|
99
105
|
export function statusDefaultValue(): Status {
|
|
100
106
|
return Status.Pending;
|
|
101
107
|
}
|
|
102
|
-
|
|
103
|
-
namespace Status {
|
|
104
|
-
export const defaultValue = statusDefaultValue;
|
|
105
|
-
}
|
|
106
108
|
```
|
|
107
109
|
|
|
108
110
|
## Error Handling
|
|
@@ -7,5 +7,6 @@ Uses deferred patching to handle references:
|
|
|
7
7
|
3. After all objects are created, `ctx.applyPatches()` resolves all pending references
|
|
8
8
|
|
|
9
9
|
References only apply to object-shaped, serializable values. The generator avoids probing for
|
|
10
|
-
`__ref` on primitive-like fields (including literal unions and `T | null` where `T` is
|
|
11
|
-
and it parses `Date` / `Date | null` from ISO strings without treating them as
|
|
10
|
+
`__ref` on primitive-like fields (including literal unions and `T | null` where `T` is
|
|
11
|
+
primitive-like), and it parses `Date` / `Date | null` from ISO strings without treating them as
|
|
12
|
+
references.
|
|
@@ -53,7 +53,7 @@ class User {
|
|
|
53
53
|
*/
|
|
54
54
|
static deserialize(
|
|
55
55
|
input: unknown,
|
|
56
|
-
opts?: @
|
|
56
|
+
opts?: @DESERIALIZE_OPTIONS
|
|
57
57
|
): Result<
|
|
58
58
|
User,
|
|
59
59
|
Array<{
|
|
@@ -65,9 +65,9 @@ class User {
|
|
|
65
65
|
// Auto-detect: if string, parse as JSON first
|
|
66
66
|
const data = typeof input === 'string' ? JSON.parse(input) : input;
|
|
67
67
|
|
|
68
|
-
const ctx = @
|
|
68
|
+
const ctx = @DESERIALIZE_CONTEXT.create();
|
|
69
69
|
const resultOrRef = User.deserializeWithContext(data, ctx);
|
|
70
|
-
if (@
|
|
70
|
+
if (@PENDING_REF.is(resultOrRef)) {
|
|
71
71
|
return Result.err([
|
|
72
72
|
{
|
|
73
73
|
field: '_root',
|
|
@@ -81,7 +81,7 @@ class User {
|
|
|
81
81
|
}
|
|
82
82
|
return Result.ok(resultOrRef);
|
|
83
83
|
} catch (e) {
|
|
84
|
-
if (e instanceof @
|
|
84
|
+
if (e instanceof @DESERIALIZE_ERROR) {
|
|
85
85
|
return Result.err(e.errors);
|
|
86
86
|
}
|
|
87
87
|
const message = e instanceof Error ? e.message : String(e);
|
|
@@ -95,12 +95,12 @@ class User {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/** @internal */
|
|
98
|
-
static deserializeWithContext(value: any, ctx: @
|
|
98
|
+
static deserializeWithContext(value: any, ctx: @DESERIALIZE_CONTEXT): User | @PENDING_REF {
|
|
99
99
|
if (value?.__ref !== undefined) {
|
|
100
100
|
return ctx.getOrDefer(value.__ref);
|
|
101
101
|
}
|
|
102
102
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
103
|
-
throw new @
|
|
103
|
+
throw new @DESERIALIZE_ERROR([
|
|
104
104
|
{
|
|
105
105
|
field: '_root',
|
|
106
106
|
message: 'User.deserializeWithContext: expected an object'
|
|
@@ -134,7 +134,7 @@ class User {
|
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
136
|
if (errors.length > 0) {
|
|
137
|
-
throw new @
|
|
137
|
+
throw new @deserialize_error_expr(errors);
|
|
138
138
|
}
|
|
139
139
|
const instance = Object.create(User.prototype) as User;
|
|
140
140
|
if (obj.__id !== undefined) {
|
|
@@ -160,7 +160,7 @@ class User {
|
|
|
160
160
|
instance.age = __raw_age;
|
|
161
161
|
}
|
|
162
162
|
if (errors.length > 0) {
|
|
163
|
-
throw new @
|
|
163
|
+
throw new @deserialize_error_expr(errors);
|
|
164
164
|
}
|
|
165
165
|
return instance;
|
|
166
166
|
}
|
|
@@ -214,4 +214,5 @@ if (Result.isOk(result)) {
|
|
|
214
214
|
## Required Imports
|
|
215
215
|
|
|
216
216
|
The generated code automatically imports:
|
|
217
|
-
|
|
217
|
+
|
|
218
|
+
- `DeserializeContext`, `DeserializeError`, `PendingRef` from `macroforge/serde`
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
# Deserialize
|
|
2
2
|
|
|
3
|
-
The `Deserialize` macro generates JSON deserialization methods with **cycle and
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
The `Deserialize` macro generates JSON deserialization methods with **cycle and forward-reference
|
|
4
|
+
support**, plus comprehensive runtime validation. This enables safe parsing of complex JSON
|
|
5
|
+
structures including circular references.
|
|
6
6
|
|
|
7
7
|
## Generated Output
|
|
8
8
|
|
|
9
|
-
| Type
|
|
10
|
-
|
|
11
|
-
| Class
|
|
12
|
-
| Enum
|
|
13
|
-
| Interface
|
|
14
|
-
| Type Alias | `typeNameDeserialize(input)`, etc.
|
|
9
|
+
| Type | Generated Code | Description |
|
|
10
|
+
| ---------- | ----------------------------------------------------------------------------------------- | ------------------------------------------- |
|
|
11
|
+
| Class | `classNameDeserialize(input)` + `static deserialize(input)` | Standalone function + static factory method |
|
|
12
|
+
| Enum | `enumNameDeserialize(input)`, `enumNameDeserializeWithContext(data)`, `enumNameIs(value)` | Standalone functions |
|
|
13
|
+
| Interface | `interfaceNameDeserialize(input)`, etc. | Standalone functions |
|
|
14
|
+
| Type Alias | `typeNameDeserialize(input)`, etc. | Standalone functions |
|
|
15
15
|
|
|
16
16
|
## Return Type
|
|
17
17
|
|
|
18
18
|
All public deserialization methods return `Result<T, Array<{ field: string; message: string }>>`:
|
|
19
19
|
|
|
20
20
|
- `Result.ok(value)` - Successfully deserialized value
|
|
21
|
-
- `Result.err(errors)` - Array of validation errors with field names and messages
|
|
21
|
+
- `Result.err(errors)` - Array of validation errors with field names and messages
|
|
@@ -3,25 +3,31 @@
|
|
|
3
3
|
Union types are deserialized based on their member types:
|
|
4
4
|
|
|
5
5
|
### Literal Unions
|
|
6
|
-
|
|
7
|
-
the
|
|
6
|
+
|
|
7
|
+
For unions of literal values (`"A" | "B" | 123`), the value is validated against the allowed
|
|
8
|
+
literals directly.
|
|
8
9
|
|
|
9
10
|
### Primitive Unions
|
|
10
|
-
|
|
11
|
-
`
|
|
11
|
+
|
|
12
|
+
For unions containing primitive types (`string | number`), the deserializer uses `typeof` checks to
|
|
13
|
+
validate the value type. No `__type` discriminator is needed.
|
|
12
14
|
|
|
13
15
|
### Class/Interface Unions
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
For unions of serializable types (`User | Admin`), the deserializer requires a `__type` field in the
|
|
18
|
+
JSON to dispatch to the correct type's `deserializeWithContext` method.
|
|
16
19
|
|
|
17
20
|
### Generic Type Parameters
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
|
|
22
|
+
For generic unions like `type Result<T> = T | Error`, the generic type parameter `T` is passed
|
|
23
|
+
through as-is since its concrete type is only known at the call site.
|
|
20
24
|
|
|
21
25
|
### Mixed Unions
|
|
26
|
+
|
|
22
27
|
Mixed unions (e.g., `string | Date | User`) check in order:
|
|
28
|
+
|
|
23
29
|
1. Literal values
|
|
24
30
|
2. Primitives (via `typeof`)
|
|
25
31
|
3. Date (via `instanceof` or ISO string parsing)
|
|
26
32
|
4. Serializable types (via `__type` dispatch)
|
|
27
|
-
5. Generic type parameters (pass-through)
|
|
33
|
+
5. Generic type parameters (pass-through)
|
|
@@ -3,19 +3,23 @@
|
|
|
3
3
|
The macro supports 30+ validators via `@serde(validate(...))`:
|
|
4
4
|
|
|
5
5
|
### String Validators
|
|
6
|
+
|
|
6
7
|
- `email`, `url`, `uuid` - Format validation
|
|
7
8
|
- `minLength(n)`, `maxLength(n)`, `length(n)` - Length constraints
|
|
8
9
|
- `pattern("regex")` - Regular expression matching
|
|
9
10
|
- `nonEmpty`, `trimmed`, `lowercase`, `uppercase` - String properties
|
|
10
11
|
|
|
11
12
|
### Number Validators
|
|
13
|
+
|
|
12
14
|
- `gt(n)`, `gte(n)`, `lt(n)`, `lte(n)`, `between(min, max)` - Range checks
|
|
13
15
|
- `int`, `positive`, `nonNegative`, `finite` - Number properties
|
|
14
16
|
|
|
15
17
|
### Array Validators
|
|
18
|
+
|
|
16
19
|
- `minItems(n)`, `maxItems(n)`, `itemsCount(n)` - Collection size
|
|
17
20
|
|
|
18
21
|
### Date Validators
|
|
22
|
+
|
|
19
23
|
- `validDate`, `afterDate("ISO")`, `beforeDate("ISO")` - Date validation
|
|
20
24
|
|
|
21
25
|
## Field-Level Options
|
|
@@ -31,4 +35,4 @@ The `@serde` decorator supports:
|
|
|
31
35
|
## Container-Level Options
|
|
32
36
|
|
|
33
37
|
- `denyUnknownFields` - Error on unrecognized JSON properties
|
|
34
|
-
- `renameAll = "camelCase"` - Apply naming convention to all fields
|
|
38
|
+
- `renameAll = "camelCase"` - Apply naming convention to all fields
|
|
@@ -4,311 +4,6 @@ The `Deserialize` macro generates JSON deserialization methods with **cycle and
|
|
|
4
4
|
forward-reference support**, plus comprehensive runtime validation. This enables
|
|
5
5
|
safe parsing of complex JSON structures including circular references.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|------|----------------|-------------|
|
|
11
|
-
| Class | `classNameDeserialize(input)` + `static deserialize(input)` | Standalone function + static factory method |
|
|
12
|
-
| Enum | `enumNameDeserialize(input)`, `enumNameDeserializeWithContext(data)`, `enumNameIs(value)` | Standalone functions |
|
|
13
|
-
| Interface | `interfaceNameDeserialize(input)`, etc. | Standalone functions |
|
|
14
|
-
| Type Alias | `typeNameDeserialize(input)`, etc. | Standalone functions |
|
|
15
|
-
|
|
16
|
-
## Return Type
|
|
17
|
-
|
|
18
|
-
All public deserialization methods return `Result<T, Array<{ field: string; message: string }>>`:
|
|
19
|
-
|
|
20
|
-
- `Result.ok(value)` - Successfully deserialized value
|
|
21
|
-
- `Result.err(errors)` - Array of validation errors with field names and messages
|
|
22
|
-
|
|
23
|
-
## Cycle/Forward-Reference Support
|
|
24
|
-
|
|
25
|
-
Uses deferred patching to handle references:
|
|
26
|
-
|
|
27
|
-
1. When encountering `{ "__ref": id }`, returns a `PendingRef` marker
|
|
28
|
-
2. Continues deserializing other fields
|
|
29
|
-
3. After all objects are created, `ctx.applyPatches()` resolves all pending references
|
|
30
|
-
|
|
31
|
-
References only apply to object-shaped, serializable values. The generator avoids probing for
|
|
32
|
-
`__ref` on primitive-like fields (including literal unions and `T | null` where `T` is primitive-like),
|
|
33
|
-
and it parses `Date` / `Date | null` from ISO strings without treating them as references.
|
|
34
|
-
|
|
35
|
-
## Validation
|
|
36
|
-
|
|
37
|
-
The macro supports 30+ validators via `@serde(validate(...))`:
|
|
38
|
-
|
|
39
|
-
### String Validators
|
|
40
|
-
- `email`, `url`, `uuid` - Format validation
|
|
41
|
-
- `minLength(n)`, `maxLength(n)`, `length(n)` - Length constraints
|
|
42
|
-
- `pattern("regex")` - Regular expression matching
|
|
43
|
-
- `nonEmpty`, `trimmed`, `lowercase`, `uppercase` - String properties
|
|
44
|
-
|
|
45
|
-
### Number Validators
|
|
46
|
-
- `gt(n)`, `gte(n)`, `lt(n)`, `lte(n)`, `between(min, max)` - Range checks
|
|
47
|
-
- `int`, `positive`, `nonNegative`, `finite` - Number properties
|
|
48
|
-
|
|
49
|
-
### Array Validators
|
|
50
|
-
- `minItems(n)`, `maxItems(n)`, `itemsCount(n)` - Collection size
|
|
51
|
-
|
|
52
|
-
### Date Validators
|
|
53
|
-
- `validDate`, `afterDate("ISO")`, `beforeDate("ISO")` - Date validation
|
|
54
|
-
|
|
55
|
-
## Field-Level Options
|
|
56
|
-
|
|
57
|
-
The `@serde` decorator supports:
|
|
58
|
-
|
|
59
|
-
- `skip` / `skipDeserializing` - Exclude field from deserialization
|
|
60
|
-
- `rename = "jsonKey"` - Read from different JSON property
|
|
61
|
-
- `default` / `default = expr` - Use default value if missing
|
|
62
|
-
- `flatten` - Read fields from parent object level
|
|
63
|
-
- `validate(...)` - Apply validators
|
|
64
|
-
|
|
65
|
-
## Container-Level Options
|
|
66
|
-
|
|
67
|
-
- `denyUnknownFields` - Error on unrecognized JSON properties
|
|
68
|
-
- `renameAll = "camelCase"` - Apply naming convention to all fields
|
|
69
|
-
|
|
70
|
-
## Union Type Deserialization
|
|
71
|
-
|
|
72
|
-
Union types are deserialized based on their member types:
|
|
73
|
-
|
|
74
|
-
### Literal Unions
|
|
75
|
-
For unions of literal values (`"A" | "B" | 123`), the value is validated against
|
|
76
|
-
the allowed literals directly.
|
|
77
|
-
|
|
78
|
-
### Primitive Unions
|
|
79
|
-
For unions containing primitive types (`string | number`), the deserializer uses
|
|
80
|
-
`typeof` checks to validate the value type. No `__type` discriminator is needed.
|
|
81
|
-
|
|
82
|
-
### Class/Interface Unions
|
|
83
|
-
For unions of serializable types (`User | Admin`), the deserializer requires a
|
|
84
|
-
`__type` field in the JSON to dispatch to the correct type's `deserializeWithContext` method.
|
|
85
|
-
|
|
86
|
-
### Generic Type Parameters
|
|
87
|
-
For generic unions like `type Result<T> = T | Error`, the generic type parameter `T`
|
|
88
|
-
is passed through as-is since its concrete type is only known at the call site.
|
|
89
|
-
|
|
90
|
-
### Mixed Unions
|
|
91
|
-
Mixed unions (e.g., `string | Date | User`) check in order:
|
|
92
|
-
1. Literal values
|
|
93
|
-
2. Primitives (via `typeof`)
|
|
94
|
-
3. Date (via `instanceof` or ISO string parsing)
|
|
95
|
-
4. Serializable types (via `__type` dispatch)
|
|
96
|
-
5. Generic type parameters (pass-through)
|
|
97
|
-
|
|
98
|
-
## Example
|
|
99
|
-
|
|
100
|
-
```typescript before
|
|
101
|
-
/** @derive(Deserialize) @serde({ denyUnknownFields: true }) */
|
|
102
|
-
class User {
|
|
103
|
-
id: number;
|
|
104
|
-
|
|
105
|
-
/** @serde({ validate: { email: true, maxLength: 255 } }) */
|
|
106
|
-
email: string;
|
|
107
|
-
|
|
108
|
-
/** @serde({ default: "guest" }) */
|
|
109
|
-
name: string;
|
|
110
|
-
|
|
111
|
-
/** @serde({ validate: { positive: true } }) */
|
|
112
|
-
age?: number;
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
```typescript after
|
|
117
|
-
import { DeserializeContext } from 'macroforge/serde';
|
|
118
|
-
import { DeserializeError } from 'macroforge/serde';
|
|
119
|
-
import type { DeserializeOptions } from 'macroforge/serde';
|
|
120
|
-
import { PendingRef } from 'macroforge/serde';
|
|
121
|
-
|
|
122
|
-
/** @serde({ denyUnknownFields: true }) */
|
|
123
|
-
class User {
|
|
124
|
-
id: number;
|
|
125
|
-
|
|
126
|
-
email: string;
|
|
127
|
-
|
|
128
|
-
name: string;
|
|
129
|
-
|
|
130
|
-
age?: number;
|
|
131
|
-
|
|
132
|
-
constructor(props: {
|
|
133
|
-
id: number;
|
|
134
|
-
email: string;
|
|
135
|
-
name?: string;
|
|
136
|
-
age?: number;
|
|
137
|
-
}) {
|
|
138
|
-
this.id = props.id;
|
|
139
|
-
this.email = props.email;
|
|
140
|
-
this.name = props.name as string;
|
|
141
|
-
this.age = props.age as number;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Deserializes input to an instance of this class.
|
|
146
|
-
* Automatically detects whether input is a JSON string or object.
|
|
147
|
-
* @param input - JSON string or object to deserialize
|
|
148
|
-
* @param opts - Optional deserialization options
|
|
149
|
-
* @returns Result containing the deserialized instance or validation errors
|
|
150
|
-
*/
|
|
151
|
-
static deserialize(
|
|
152
|
-
input: unknown,
|
|
153
|
-
opts?: @{DESERIALIZE_OPTIONS}
|
|
154
|
-
): Result<
|
|
155
|
-
User,
|
|
156
|
-
Array<{
|
|
157
|
-
field: string;
|
|
158
|
-
message: string;
|
|
159
|
-
}>
|
|
160
|
-
> {
|
|
161
|
-
try {
|
|
162
|
-
// Auto-detect: if string, parse as JSON first
|
|
163
|
-
const data = typeof input === 'string' ? JSON.parse(input) : input;
|
|
164
|
-
|
|
165
|
-
const ctx = @{DESERIALIZE_CONTEXT}.create();
|
|
166
|
-
const resultOrRef = User.deserializeWithContext(data, ctx);
|
|
167
|
-
if (@{PENDING_REF}.is(resultOrRef)) {
|
|
168
|
-
return Result.err([
|
|
169
|
-
{
|
|
170
|
-
field: '_root',
|
|
171
|
-
message: 'User.deserialize: root cannot be a forward reference'
|
|
172
|
-
}
|
|
173
|
-
]);
|
|
174
|
-
}
|
|
175
|
-
ctx.applyPatches();
|
|
176
|
-
if (opts?.freeze) {
|
|
177
|
-
ctx.freezeAll();
|
|
178
|
-
}
|
|
179
|
-
return Result.ok(resultOrRef);
|
|
180
|
-
} catch (e) {
|
|
181
|
-
if (e instanceof @{DESERIALIZE_ERROR}) {
|
|
182
|
-
return Result.err(e.errors);
|
|
183
|
-
}
|
|
184
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
185
|
-
return Result.err([
|
|
186
|
-
{
|
|
187
|
-
field: '_root',
|
|
188
|
-
message
|
|
189
|
-
}
|
|
190
|
-
]);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/** @internal */
|
|
195
|
-
static deserializeWithContext(value: any, ctx: @{DESERIALIZE_CONTEXT}): User | @{PENDING_REF} {
|
|
196
|
-
if (value?.__ref !== undefined) {
|
|
197
|
-
return ctx.getOrDefer(value.__ref);
|
|
198
|
-
}
|
|
199
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
200
|
-
throw new @{DESERIALIZE_ERROR}([
|
|
201
|
-
{
|
|
202
|
-
field: '_root',
|
|
203
|
-
message: 'User.deserializeWithContext: expected an object'
|
|
204
|
-
}
|
|
205
|
-
]);
|
|
206
|
-
}
|
|
207
|
-
const obj = value as Record<string, unknown>;
|
|
208
|
-
const errors: Array<{
|
|
209
|
-
field: string;
|
|
210
|
-
message: string;
|
|
211
|
-
}> = [];
|
|
212
|
-
const knownKeys = new Set(['__type', '__id', '__ref', 'id', 'email', 'name', 'age']);
|
|
213
|
-
for (const key of Object.keys(obj)) {
|
|
214
|
-
if (!knownKeys.has(key)) {
|
|
215
|
-
errors.push({
|
|
216
|
-
field: key,
|
|
217
|
-
message: 'unknown field'
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (!('id' in obj)) {
|
|
222
|
-
errors.push({
|
|
223
|
-
field: 'id',
|
|
224
|
-
message: 'missing required field'
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
if (!('email' in obj)) {
|
|
228
|
-
errors.push({
|
|
229
|
-
field: 'email',
|
|
230
|
-
message: 'missing required field'
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
if (errors.length > 0) {
|
|
234
|
-
throw new @{DESERIALIZE_ERROR}(errors);
|
|
235
|
-
}
|
|
236
|
-
const instance = Object.create(User.prototype) as User;
|
|
237
|
-
if (obj.__id !== undefined) {
|
|
238
|
-
ctx.register(obj.__id as number, instance);
|
|
239
|
-
}
|
|
240
|
-
ctx.trackForFreeze(instance);
|
|
241
|
-
{
|
|
242
|
-
const __raw_id = obj['id'] as number;
|
|
243
|
-
instance.id = __raw_id;
|
|
244
|
-
}
|
|
245
|
-
{
|
|
246
|
-
const __raw_email = obj['email'] as string;
|
|
247
|
-
instance.email = __raw_email;
|
|
248
|
-
}
|
|
249
|
-
if ('name' in obj && obj['name'] !== undefined) {
|
|
250
|
-
const __raw_name = obj['name'] as string;
|
|
251
|
-
instance.name = __raw_name;
|
|
252
|
-
} else {
|
|
253
|
-
instance.name = "guest";
|
|
254
|
-
}
|
|
255
|
-
if ('age' in obj && obj['age'] !== undefined) {
|
|
256
|
-
const __raw_age = obj['age'] as number;
|
|
257
|
-
instance.age = __raw_age;
|
|
258
|
-
}
|
|
259
|
-
if (errors.length > 0) {
|
|
260
|
-
throw new @{DESERIALIZE_ERROR}(errors);
|
|
261
|
-
}
|
|
262
|
-
return instance;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
static validateField<K extends keyof User>(
|
|
266
|
-
field: K,
|
|
267
|
-
value: User[K]
|
|
268
|
-
): Array<{
|
|
269
|
-
field: string;
|
|
270
|
-
message: string;
|
|
271
|
-
}> {
|
|
272
|
-
return [];
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
static validateFields(partial: Partial<User>): Array<{
|
|
276
|
-
field: string;
|
|
277
|
-
message: string;
|
|
278
|
-
}> {
|
|
279
|
-
return [];
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
static hasShape(obj: unknown): boolean {
|
|
283
|
-
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
const o = obj as Record<string, unknown>;
|
|
287
|
-
return 'id' in o && 'email' in o;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
static is(obj: unknown): obj is User {
|
|
291
|
-
if (obj instanceof User) {
|
|
292
|
-
return true;
|
|
293
|
-
}
|
|
294
|
-
if (!User.hasShape(obj)) {
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
297
|
-
const result = User.deserialize(obj);
|
|
298
|
-
return Result.isOk(result);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Usage:
|
|
303
|
-
const result = User.deserialize('{"id":1,"email":"test@example.com"}');
|
|
304
|
-
if (Result.isOk(result)) {
|
|
305
|
-
const user = result.value;
|
|
306
|
-
} else {
|
|
307
|
-
console.error(result.error); // [{ field: "email", message: "must be a valid email" }]
|
|
308
|
-
}
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
## Required Imports
|
|
312
|
-
|
|
313
|
-
The generated code automatically imports:
|
|
314
|
-
- `DeserializeContext`, `DeserializeError`, `PendingRef` from `macroforge/serde`
|
|
7
|
+
See the original module documentation for full details on generated output,
|
|
8
|
+
return types, cycle/forward-reference support, validation, field-level options,
|
|
9
|
+
container-level options, and union type deserialization.
|
|
@@ -21,10 +21,13 @@ Uses the standard polynomial rolling hash algorithm:
|
|
|
21
21
|
```text
|
|
22
22
|
hash = 17 // Initial seed
|
|
23
23
|
for each field:
|
|
24
|
-
hash = (hash * 31 + fieldHash) | 0
|
|
24
|
+
hash = (hash * 31 + fieldHash) | 0
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
The `| 0` (bitwise OR with zero) at the end of each step coerces the result
|
|
28
|
+
to a 32-bit signed integer, preventing floating-point drift from repeated
|
|
29
|
+
multiplication. This is equivalent to casting to `i32` in Rust and consistent
|
|
30
|
+
with Java's `Objects.hash()` implementation.
|
|
28
31
|
|
|
29
32
|
## Type-Specific Hashing
|
|
30
33
|
|
|
@@ -49,7 +52,7 @@ The `@hash` decorator supports:
|
|
|
49
52
|
## Example
|
|
50
53
|
|
|
51
54
|
```typescript before
|
|
52
|
-
/** @derive(Hash
|
|
55
|
+
/** @derive(Hash) */
|
|
53
56
|
class User {
|
|
54
57
|
id: number;
|
|
55
58
|
name: string;
|
|
@@ -69,10 +72,6 @@ class User {
|
|
|
69
72
|
static hashCode(value: User): number {
|
|
70
73
|
return userHashCode(value);
|
|
71
74
|
}
|
|
72
|
-
|
|
73
|
-
static equals(a: User, b: User): boolean {
|
|
74
|
-
return userEquals(a, b);
|
|
75
|
-
}
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
export function userHashCode(value: User): number {
|
|
@@ -92,11 +91,6 @@ export function userHashCode(value: User): number {
|
|
|
92
91
|
0;
|
|
93
92
|
return hash;
|
|
94
93
|
}
|
|
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
94
|
```
|
|
101
95
|
|
|
102
96
|
## Hash Contract
|
|
@@ -40,12 +40,12 @@ The `@partialEq` decorator supports:
|
|
|
40
40
|
## Example
|
|
41
41
|
|
|
42
42
|
```typescript before
|
|
43
|
-
/** @derive(PartialEq
|
|
43
|
+
/** @derive(PartialEq) */
|
|
44
44
|
class User {
|
|
45
45
|
id: number;
|
|
46
46
|
name: string;
|
|
47
47
|
|
|
48
|
-
/** @partialEq({ skip: true })
|
|
48
|
+
/** @partialEq({ skip: true }) */
|
|
49
49
|
cachedScore: number;
|
|
50
50
|
}
|
|
51
51
|
```
|
|
@@ -60,34 +60,12 @@ class User {
|
|
|
60
60
|
static equals(a: User, b: User): boolean {
|
|
61
61
|
return userEquals(a, b);
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
static hashCode(value: User): number {
|
|
65
|
-
return userHashCode(value);
|
|
66
|
-
}
|
|
67
63
|
}
|
|
68
64
|
|
|
69
65
|
export function userEquals(a: User, b: User): boolean {
|
|
70
66
|
if (a === b) return true;
|
|
71
67
|
return a.id === b.id && a.name === b.name;
|
|
72
68
|
}
|
|
73
|
-
|
|
74
|
-
export function userHashCode(value: User): number {
|
|
75
|
-
let hash = 17;
|
|
76
|
-
hash =
|
|
77
|
-
(hash * 31 +
|
|
78
|
-
(Number.isInteger(value.id)
|
|
79
|
-
? value.id | 0
|
|
80
|
-
: value.id
|
|
81
|
-
.toString()
|
|
82
|
-
.split('')
|
|
83
|
-
.reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
|
|
84
|
-
0;
|
|
85
|
-
hash =
|
|
86
|
-
(hash * 31 +
|
|
87
|
-
(value.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
|
|
88
|
-
0;
|
|
89
|
-
return hash;
|
|
90
|
-
}
|
|
91
69
|
```
|
|
92
70
|
|
|
93
71
|
## Equality Contract
|
|
@@ -98,55 +76,5 @@ When implementing `PartialEq`, consider also implementing `Hash`:
|
|
|
98
76
|
- **Symmetry**: `a.equals(b)` implies `b.equals(a)`
|
|
99
77
|
- **Hash consistency**: Equal objects must have equal hash codes
|
|
100
78
|
|
|
101
|
-
To maintain the hash contract, skip the same fields in both `PartialEq` and `Hash
|
|
102
|
-
|
|
103
|
-
```typescript before
|
|
104
|
-
/** @derive(PartialEq, Hash) */
|
|
105
|
-
class User {
|
|
106
|
-
id: number;
|
|
107
|
-
name: string;
|
|
108
|
-
|
|
109
|
-
/** @partialEq({ skip: true }) @hash({ skip: true }) */
|
|
110
|
-
cachedScore: number;
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
```typescript after
|
|
115
|
-
class User {
|
|
116
|
-
id: number;
|
|
117
|
-
name: string;
|
|
118
|
-
|
|
119
|
-
cachedScore: number;
|
|
120
|
-
|
|
121
|
-
static equals(a: User, b: User): boolean {
|
|
122
|
-
return userEquals(a, b);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
static hashCode(value: User): number {
|
|
126
|
-
return userHashCode(value);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function userEquals(a: User, b: User): boolean {
|
|
131
|
-
if (a === b) return true;
|
|
132
|
-
return a.id === b.id && a.name === b.name;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export function userHashCode(value: User): number {
|
|
136
|
-
let hash = 17;
|
|
137
|
-
hash =
|
|
138
|
-
(hash * 31 +
|
|
139
|
-
(Number.isInteger(value.id)
|
|
140
|
-
? value.id | 0
|
|
141
|
-
: value.id
|
|
142
|
-
.toString()
|
|
143
|
-
.split('')
|
|
144
|
-
.reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) |
|
|
145
|
-
0;
|
|
146
|
-
hash =
|
|
147
|
-
(hash * 31 +
|
|
148
|
-
(value.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) |
|
|
149
|
-
0;
|
|
150
|
-
return hash;
|
|
151
|
-
}
|
|
152
|
-
```
|
|
79
|
+
To maintain the hash contract, skip the same fields in both `PartialEq` and `Hash`,
|
|
80
|
+
as shown in the example above using `@partialEq({ skip: true }) @hash({ skip: true })`.
|
|
@@ -9,18 +9,20 @@ between values where some pairs may be incomparable.
|
|
|
9
9
|
| Type | Generated Code | Description |
|
|
10
10
|
|------|----------------|-------------|
|
|
11
11
|
| Class | `classNamePartialCompare(a, b)` + `static compareTo(a, b)` | Standalone function + static wrapper method |
|
|
12
|
-
| Enum | `enumNamePartialCompare(a
|
|
13
|
-
| Interface | `
|
|
14
|
-
| Type Alias | `typeNamePartialCompare(a
|
|
12
|
+
| Enum | `enumNamePartialCompare(a, b): number \| null` | Standalone function returning `number \| null` |
|
|
13
|
+
| Interface | `ifaceNamePartialCompare(a, b): number \| null` | Standalone function returning `number \| null` |
|
|
14
|
+
| Type Alias | `typeNamePartialCompare(a, b): number \| null` | Standalone function returning `number \| null` |
|
|
15
|
+
|
|
16
|
+
Names use **camelCase** conversion (e.g., `Temperature` → `temperaturePartialCompare`).
|
|
15
17
|
|
|
16
18
|
## Return Values
|
|
17
19
|
|
|
18
|
-
Unlike `Ord`, `PartialOrd` returns
|
|
20
|
+
Unlike `Ord`, `PartialOrd` returns `number | null` to handle incomparable values:
|
|
19
21
|
|
|
20
|
-
-
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
22
|
+
- **-1**: `a` is less than `b`
|
|
23
|
+
- **0**: `a` is equal to `b`
|
|
24
|
+
- **1**: `a` is greater than `b`
|
|
25
|
+
- **null**: Values are incomparable
|
|
24
26
|
|
|
25
27
|
## When to Use PartialOrd vs Ord
|
|
26
28
|
|
|
@@ -36,8 +38,8 @@ Unlike `Ord`, `PartialOrd` returns an `Option<number>` to handle incomparable va
|
|
|
36
38
|
Fields are compared **lexicographically** in declaration order:
|
|
37
39
|
|
|
38
40
|
1. Compare first field
|
|
39
|
-
2. If incomparable, return `
|
|
40
|
-
3. If not equal, return that result
|
|
41
|
+
2. If incomparable, return `null`
|
|
42
|
+
3. If not equal, return that result
|
|
41
43
|
4. Otherwise, compare next field
|
|
42
44
|
5. Continue until a difference is found or all fields are equal
|
|
43
45
|
|
|
@@ -45,13 +47,13 @@ Fields are compared **lexicographically** in declaration order:
|
|
|
45
47
|
|
|
46
48
|
| Type | Comparison Method |
|
|
47
49
|
|------|-------------------|
|
|
48
|
-
| `number`/`bigint` | Direct
|
|
49
|
-
| `string` | `localeCompare()`
|
|
50
|
-
| `boolean` | false
|
|
51
|
-
| null/undefined | Returns
|
|
52
|
-
| Arrays | Lexicographic, propagates
|
|
53
|
-
| `Date` | Timestamp comparison,
|
|
54
|
-
| Objects |
|
|
50
|
+
| `number`/`bigint` | Direct subtraction (`a - b`) |
|
|
51
|
+
| `string` | `localeCompare()` |
|
|
52
|
+
| `boolean` | `false < true` (cast to number) |
|
|
53
|
+
| null/undefined | Returns `null` for mismatched nullability |
|
|
54
|
+
| Arrays | Lexicographic, propagates `null` on incomparable elements |
|
|
55
|
+
| `Date` | Timestamp comparison, `null` if invalid |
|
|
56
|
+
| Objects | Delegates to `compareTo()` if available |
|
|
55
57
|
|
|
56
58
|
## Field-Level Options
|
|
57
59
|
|
|
@@ -94,7 +94,7 @@ class User {
|
|
|
94
94
|
@param value - The value to serialize
|
|
95
95
|
@param ctx - The serialization context */
|
|
96
96
|
|
|
97
|
-
static serializeWithContext(value: User, ctx: @
|
|
97
|
+
static serializeWithContext(value: User, ctx: @SERIALIZE_CONTEXT): Record<string, unknown> {
|
|
98
98
|
return userSerializeWithContext(value, ctx);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -104,7 +104,7 @@ class User {
|
|
|
104
104
|
@returns JSON string representation with cycle detection metadata */ export function userSerialize(
|
|
105
105
|
value: User
|
|
106
106
|
): string {
|
|
107
|
-
const ctx = @
|
|
107
|
+
const ctx = @SERIALIZE_CONTEXT.create();
|
|
108
108
|
return JSON.stringify(userSerializeWithContext(value, ctx));
|
|
109
109
|
} /** @internal Serializes with an existing context for nested/cyclic object graphs.
|
|
110
110
|
@param value - The value to serialize
|
|
@@ -123,7 +123,7 @@ export function userSerializeWithContext(
|
|
|
123
123
|
result['userName'] = value.name;
|
|
124
124
|
{
|
|
125
125
|
const __flattened = userMetadataSerializeWithContext(value.metadata, ctx);
|
|
126
|
-
const { __type: _, __id: __, ...rest } = __flattened as any;
|
|
126
|
+
const { __type: _, __id: __, ...rest } = __flattened as any; // tag field name is configurable via `tag` option
|
|
127
127
|
Object.assign(result, rest);
|
|
128
128
|
}
|
|
129
129
|
return result;
|
package/docs/integration/cli.md
CHANGED
|
@@ -25,7 +25,7 @@ and editors.
|
|
|
25
25
|
The language servers are functional and used during development of macroforge itself. However, they
|
|
26
26
|
require manual installation:
|
|
27
27
|
|
|
28
|
-
1. Fork or clone the [macroforge-ts repository](https://github.com/
|
|
28
|
+
1. Fork or clone the [macroforge-ts repository](https://github.com/macroforge-ts/macroforge-ts)
|
|
29
29
|
2. Build the extension you need
|
|
30
30
|
3. Install it as a developer extension in your editor
|
|
31
31
|
|
|
@@ -25,7 +25,7 @@ This package is not yet published as an official extension. You'll need to build
|
|
|
25
25
|
### 1. Clone the Repository
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
git clone https://github.com/
|
|
28
|
+
git clone https://github.com/macroforge-ts/macroforge-ts.git
|
|
29
29
|
cd macroforge-ts
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -20,7 +20,7 @@ These extensions are not yet in the Zed extension registry. You'll need to insta
|
|
|
20
20
|
### 1. Clone the Repository
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
git clone https://github.com/
|
|
23
|
+
git clone https://github.com/macroforge-ts/macroforge-ts.git
|
|
24
24
|
cd macroforge-ts
|
|
25
25
|
```
|
|
26
26
|
|
package/docs/roadmap/roadmap.md
CHANGED
|
@@ -73,7 +73,7 @@ Improvements to the developer experience.
|
|
|
73
73
|
|
|
74
74
|
Interested in helping? We welcome contributions of all kinds:
|
|
75
75
|
|
|
76
|
-
- Feature requests and feedback on [GitHub Issues](https://github.com/
|
|
76
|
+
- Feature requests and feedback on [GitHub Issues](https://github.com/macroforge-ts/macroforge-ts/issues)
|
|
77
77
|
- Pull requests for new macros or improvements
|
|
78
78
|
- Documentation improvements
|
|
79
79
|
- Framework integrations
|
package/docs/sections.json
CHANGED
|
@@ -63,65 +63,12 @@
|
|
|
63
63
|
"path": "builtin-macros/serialize.md",
|
|
64
64
|
"use_cases": "toJSON, serialization, json, api, data transfer"
|
|
65
65
|
},
|
|
66
|
-
{
|
|
67
|
-
"id": "deserialize/overview",
|
|
68
|
-
"title": "Deserialize: Overview",
|
|
69
|
-
"category": "builtin-macros",
|
|
70
|
-
"category_title": "Built-in Macros",
|
|
71
|
-
"path": "builtin-macros/deserialize/overview.md",
|
|
72
|
-
"use_cases": "fromJSON, deserialization, deserialize, classnamedeserialize(input), enumnamedeserialize(input)",
|
|
73
|
-
"parent_id": "deserialize"
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"id": "deserialize/cycleforward-reference-support",
|
|
77
|
-
"title": "Deserialize: Cycle/Forward-Reference Support",
|
|
78
|
-
"category": "builtin-macros",
|
|
79
|
-
"category_title": "Built-in Macros",
|
|
80
|
-
"path": "builtin-macros/deserialize/cycleforward-reference-support.md",
|
|
81
|
-
"use_cases": "fromJSON, deserialization, pendingref, ctx.applypatches(), __ref",
|
|
82
|
-
"parent_id": "deserialize"
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"id": "deserialize/validation",
|
|
86
|
-
"title": "Deserialize: Validation",
|
|
87
|
-
"category": "builtin-macros",
|
|
88
|
-
"category_title": "Built-in Macros",
|
|
89
|
-
"path": "builtin-macros/deserialize/validation.md",
|
|
90
|
-
"use_cases": "fromJSON, deserialization, @serde(validate(...)), email, url, uuid",
|
|
91
|
-
"parent_id": "deserialize"
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"id": "deserialize/union-type-deserialization",
|
|
95
|
-
"title": "Deserialize: Union Type Deserialization",
|
|
96
|
-
"category": "builtin-macros",
|
|
97
|
-
"category_title": "Built-in Macros",
|
|
98
|
-
"path": "builtin-macros/deserialize/union-type-deserialization.md",
|
|
99
|
-
"use_cases": "fromJSON, deserialization, typeof, __type",
|
|
100
|
-
"parent_id": "deserialize"
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
"id": "deserialize/example",
|
|
104
|
-
"title": "Deserialize: Example",
|
|
105
|
-
"category": "builtin-macros",
|
|
106
|
-
"category_title": "Built-in Macros",
|
|
107
|
-
"path": "builtin-macros/deserialize/example.md",
|
|
108
|
-
"use_cases": "fromJSON, deserialization",
|
|
109
|
-
"parent_id": "deserialize"
|
|
110
|
-
},
|
|
111
66
|
{
|
|
112
67
|
"id": "deserialize",
|
|
113
68
|
"title": "Deserialize",
|
|
114
69
|
"category": "builtin-macros",
|
|
115
70
|
"category_title": "Built-in Macros",
|
|
116
71
|
"path": "builtin-macros/deserialize.md",
|
|
117
|
-
"use_cases": "fromJSON, deserialization, parsing, validation, json"
|
|
118
|
-
"is_chunked": true,
|
|
119
|
-
"chunk_ids": [
|
|
120
|
-
"deserialize/overview",
|
|
121
|
-
"deserialize/cycleforward-reference-support",
|
|
122
|
-
"deserialize/validation",
|
|
123
|
-
"deserialize/union-type-deserialization",
|
|
124
|
-
"deserialize/example"
|
|
125
|
-
]
|
|
72
|
+
"use_cases": "fromJSON, deserialization, parsing, validation, json"
|
|
126
73
|
}
|
|
127
74
|
]
|
package/package.json
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"main": "dist/index.js",
|
|
26
26
|
"name": "@macroforge/mcp-server",
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"macroforge": "
|
|
28
|
+
"macroforge": "file:../../crates/macroforge_ts"
|
|
29
29
|
},
|
|
30
30
|
"peerDependenciesMeta": {
|
|
31
31
|
"macroforge": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|
|
37
|
-
"url": "git+https://github.com/macroforge-ts/
|
|
37
|
+
"url": "git+https://github.com/macroforge-ts/macroforge-ts.git"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "deno install --node-modules-dir --quiet && deno run -A npm:typescript@5/tsc && chmod +x dist/index.js",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"test": "node --test tests/**/*.test.js"
|
|
47
47
|
},
|
|
48
48
|
"type": "module",
|
|
49
|
-
"version": "0.1.
|
|
49
|
+
"version": "0.1.79"
|
|
50
50
|
}
|