@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
package/docs/api/api-overview.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
<span class="stats svelte-1c8t0id">52 exported items *Macroforge provides a programmatic API for expanding macros in TypeScript code.*
|
|
3
3
|
## Overview
|
|
4
4
|
```
|
|
5
|
-
import
|
|
5
|
+
import {
|
|
6
6
|
expandSync,
|
|
7
7
|
transformSync,
|
|
8
8
|
checkSyntax,
|
|
9
9
|
parseImportSources,
|
|
10
10
|
NativePlugin,
|
|
11
11
|
PositionMapper
|
|
12
|
-
|
|
12
|
+
} from "macroforge";
|
|
13
13
|
``` ## Core Functions
|
|
14
14
|
| Function | Description |
|
|
15
15
|
| --- | --- |
|
|
@@ -24,28 +24,28 @@ import {
|
|
|
24
24
|
| [`PositionMapper`](../docs/api/position-mapper) | Maps positions between original and expanded code |
|
|
25
25
|
## Quick Example
|
|
26
26
|
```
|
|
27
|
-
import
|
|
27
|
+
import { expandSync } from "macroforge";
|
|
28
28
|
|
|
29
|
-
const sourceCode =
|
|
29
|
+
const sourceCode = \`
|
|
30
30
|
/** @derive(Debug) */
|
|
31
|
-
class User
|
|
31
|
+
class User {
|
|
32
32
|
name: string;
|
|
33
|
-
constructor(name: string)
|
|
33
|
+
constructor(name: string) {
|
|
34
34
|
this.name = name;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
\`;
|
|
38
38
|
|
|
39
|
-
const result = expandSync(sourceCode, "user.ts",
|
|
39
|
+
const result = expandSync(sourceCode, "user.ts", {
|
|
40
40
|
keepDecorators: false
|
|
41
|
-
|
|
41
|
+
});
|
|
42
42
|
|
|
43
43
|
console.log(result.code);
|
|
44
44
|
// Output: class with toString() method generated
|
|
45
45
|
|
|
46
|
-
if (result.diagnostics.length > 0)
|
|
46
|
+
if (result.diagnostics.length > 0) {
|
|
47
47
|
console.error("Errors:", result.diagnostics);
|
|
48
|
-
|
|
48
|
+
}
|
|
49
49
|
``` ## Detailed Reference
|
|
50
50
|
- [`expandSync()`](../docs/api/expand-sync) - Full options and return types
|
|
51
51
|
- [`transformSync()`](../docs/api/transform-sync) - Transform with source maps
|
package/docs/api/expand-sync.md
CHANGED
|
@@ -15,13 +15,13 @@ function expandSync(
|
|
|
15
15
|
| `options` | `ExpandOptions` | Optional configuration |
|
|
16
16
|
## ExpandOptions
|
|
17
17
|
```
|
|
18
|
-
interface ExpandOptions
|
|
18
|
+
interface ExpandOptions {
|
|
19
19
|
// Keep @derive decorators in output (default: false)
|
|
20
20
|
keepDecorators?: boolean;
|
|
21
|
-
|
|
21
|
+
}
|
|
22
22
|
``` ## ExpandResult
|
|
23
23
|
```
|
|
24
|
-
interface ExpandResult
|
|
24
|
+
interface ExpandResult {
|
|
25
25
|
// Transformed TypeScript code
|
|
26
26
|
code: string;
|
|
27
27
|
|
|
@@ -36,17 +36,17 @@ interface ExpandResult {
|
|
|
36
36
|
|
|
37
37
|
// Position mapping data for source maps
|
|
38
38
|
sourceMapping?: SourceMappingResult;
|
|
39
|
-
|
|
39
|
+
}
|
|
40
40
|
``` ## MacroDiagnostic
|
|
41
41
|
```
|
|
42
|
-
interface MacroDiagnostic
|
|
42
|
+
interface MacroDiagnostic {
|
|
43
43
|
message: string;
|
|
44
44
|
severity: "error" | "warning" | "info";
|
|
45
|
-
span:
|
|
45
|
+
span: {
|
|
46
46
|
start: number;
|
|
47
47
|
end: number;
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
50
|
``` ## Example
|
|
51
51
|
```
|
|
52
52
|
import { expandSync } from "macroforge";
|
|
@@ -13,10 +13,10 @@ processFile(
|
|
|
13
13
|
options?: ProcessFileOptions
|
|
14
14
|
): ExpandResult
|
|
15
15
|
``` ```
|
|
16
|
-
interface ProcessFileOptions
|
|
16
|
+
interface ProcessFileOptions {
|
|
17
17
|
// Cache key - if unchanged, returns cached result
|
|
18
18
|
version?: string;
|
|
19
|
-
|
|
19
|
+
}
|
|
20
20
|
``` ### getMapper()
|
|
21
21
|
Get the position mapper for a previously processed file:
|
|
22
22
|
```
|
|
@@ -39,36 +39,36 @@ setLogFile(path: string): void
|
|
|
39
39
|
const plugin = new NativePlugin();
|
|
40
40
|
|
|
41
41
|
// First call - performs expansion
|
|
42
|
-
const result1 = plugin.processFile("user.ts", code,
|
|
42
|
+
const result1 = plugin.processFile("user.ts", code, { version: "1" });
|
|
43
43
|
|
|
44
44
|
// Same version - returns cached result instantly
|
|
45
|
-
const result2 = plugin.processFile("user.ts", code,
|
|
45
|
+
const result2 = plugin.processFile("user.ts", code, { version: "1" });
|
|
46
46
|
|
|
47
47
|
// Different version - re-expands
|
|
48
|
-
const result3 = plugin.processFile("user.ts", newCode,
|
|
48
|
+
const result3 = plugin.processFile("user.ts", newCode, { version: "2" });
|
|
49
49
|
``` ## Example: Language Server Integration
|
|
50
50
|
```
|
|
51
|
-
import
|
|
51
|
+
import { NativePlugin } from "macroforge";
|
|
52
52
|
|
|
53
|
-
class MacroforgeLanguageService
|
|
53
|
+
class MacroforgeLanguageService {
|
|
54
54
|
private plugin = new NativePlugin();
|
|
55
55
|
|
|
56
|
-
processDocument(uri: string, content: string, version: number)
|
|
56
|
+
processDocument(uri: string, content: string, version: number) {
|
|
57
57
|
// Process with version-based caching
|
|
58
|
-
const result = this.plugin.processFile(uri, content,
|
|
58
|
+
const result = this.plugin.processFile(uri, content, {
|
|
59
59
|
version: String(version)
|
|
60
|
-
|
|
60
|
+
});
|
|
61
61
|
|
|
62
62
|
// Get mapper for position translation
|
|
63
63
|
const mapper = this.plugin.getMapper(uri);
|
|
64
64
|
|
|
65
|
-
return
|
|
66
|
-
|
|
65
|
+
return { result, mapper };
|
|
66
|
+
}
|
|
67
67
|
|
|
68
|
-
getSemanticDiagnostics(uri: string, diagnostics: Diagnostic[])
|
|
68
|
+
getSemanticDiagnostics(uri: string, diagnostics: Diagnostic[]) {
|
|
69
69
|
// Map positions from expanded to original
|
|
70
70
|
return this.plugin.mapDiagnostics(uri, diagnostics);
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
73
|
``` ## Thread Safety
|
|
74
74
|
The `NativePlugin` class is thread-safe and can be used from multiple async contexts. Each file is processed in an isolated thread with its own stack space.
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
*Bidirectional position mapper for translating between original and expanded source positions. This mapper enables IDE features like error reporting, go-to-definition, and hover to work correctly with macro-expanded code by translating positions between the original source (what the user wrote) and the expanded source (what the compiler sees).*
|
|
3
3
|
## Getting a Mapper
|
|
4
4
|
```
|
|
5
|
-
import
|
|
5
|
+
import { NativePlugin, PositionMapper } from "macroforge";
|
|
6
6
|
|
|
7
7
|
const plugin = new NativePlugin();
|
|
8
|
-
const result = plugin.processFile("user.ts", code,
|
|
8
|
+
const result = plugin.processFile("user.ts", code, { version: "1" });
|
|
9
9
|
|
|
10
10
|
// Get the mapper for this file
|
|
11
11
|
const mapper = plugin.getMapper("user.ts");
|
|
12
|
-
if (mapper)
|
|
12
|
+
if (mapper) {
|
|
13
13
|
// Use the mapper...
|
|
14
|
-
|
|
14
|
+
}
|
|
15
15
|
``` ## Methods
|
|
16
16
|
### isEmpty()
|
|
17
17
|
Check if the mapper has any mappings:
|
|
@@ -39,10 +39,10 @@ generatedBy(pos: number): string | null
|
|
|
39
39
|
```
|
|
40
40
|
mapSpanToOriginal(start: number, length: number): SpanResult | null
|
|
41
41
|
|
|
42
|
-
interface SpanResult
|
|
42
|
+
interface SpanResult {
|
|
43
43
|
start: number;
|
|
44
44
|
length: number;
|
|
45
|
-
|
|
45
|
+
}
|
|
46
46
|
``` ### mapSpanToExpanded()
|
|
47
47
|
Map a span from original to expanded code:
|
|
48
48
|
```
|
|
@@ -13,7 +13,7 @@ function transformSync(
|
|
|
13
13
|
| `filepath` | `string` | File path (used for error reporting) |
|
|
14
14
|
## TransformResult
|
|
15
15
|
```
|
|
16
|
-
interface TransformResult
|
|
16
|
+
interface TransformResult {
|
|
17
17
|
// Transformed TypeScript code
|
|
18
18
|
code: string;
|
|
19
19
|
|
|
@@ -25,7 +25,7 @@ interface TransformResult {
|
|
|
25
25
|
|
|
26
26
|
// Macro expansion metadata
|
|
27
27
|
metadata?: string;
|
|
28
|
-
|
|
28
|
+
}
|
|
29
29
|
``` ## Comparison with expandSync()
|
|
30
30
|
| Feature | `expandSync` | `transformSync` |
|
|
31
31
|
| --- | --- | --- |
|
|
@@ -35,29 +35,29 @@ interface TransformResult {
|
|
|
35
35
|
| Use Case | General purpose | Build tools |
|
|
36
36
|
## Example
|
|
37
37
|
```
|
|
38
|
-
import
|
|
38
|
+
import { transformSync } from "macroforge";
|
|
39
39
|
|
|
40
|
-
const sourceCode =
|
|
40
|
+
const sourceCode = \`
|
|
41
41
|
/** @derive(Debug) */
|
|
42
|
-
class User
|
|
42
|
+
class User {
|
|
43
43
|
name: string;
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
}
|
|
45
|
+
\`;
|
|
46
46
|
|
|
47
47
|
const result = transformSync(sourceCode, "user.ts");
|
|
48
48
|
|
|
49
49
|
console.log(result.code);
|
|
50
50
|
|
|
51
|
-
if (result.types)
|
|
51
|
+
if (result.types) {
|
|
52
52
|
// Write to .d.ts file
|
|
53
53
|
fs.writeFileSync("user.d.ts", result.types);
|
|
54
|
-
|
|
54
|
+
}
|
|
55
55
|
|
|
56
|
-
if (result.metadata)
|
|
56
|
+
if (result.metadata) {
|
|
57
57
|
// Parse and use metadata
|
|
58
58
|
const meta = JSON.parse(result.metadata);
|
|
59
59
|
console.log("Macros expanded:", meta);
|
|
60
|
-
|
|
60
|
+
}
|
|
61
61
|
``` ## When to Use
|
|
62
62
|
Use `transformSync` when:
|
|
63
63
|
- Building custom integrations
|
|
@@ -8,18 +8,11 @@ independent copies of values.
|
|
|
8
8
|
|
|
9
9
|
| Type | Generated Code | Description |
|
|
10
10
|
|------|----------------|-------------|
|
|
11
|
-
| Class | `
|
|
12
|
-
| Enum | `
|
|
13
|
-
| Interface | `
|
|
14
|
-
| Type Alias | `
|
|
11
|
+
| Class | `classNameClone(value)` + `static clone(value)` | Standalone function + static wrapper method |
|
|
12
|
+
| Enum | `enumNameClone(value: EnumName): EnumName` | Standalone function (enums are primitives, returns value as-is) |
|
|
13
|
+
| Interface | `interfaceNameClone(value: InterfaceName): InterfaceName` | Standalone function creating a new object literal |
|
|
14
|
+
| Type Alias | `typeNameClone(value: TypeName): TypeName` | Standalone function with spread copy for objects |
|
|
15
15
|
|
|
16
|
-
## Configuration
|
|
17
|
-
|
|
18
|
-
The `functionNamingStyle` option in `macroforge.json` controls naming:
|
|
19
|
-
- `"prefix"` (default): Prefixes with type name (e.g., `myTypeClone`)
|
|
20
|
-
- `"suffix"`: Suffixes with type name (e.g., `cloneMyType`)
|
|
21
|
-
- `"generic"`: Uses TypeScript generics (e.g., `clone<T extends MyType>`)
|
|
22
|
-
- `"namespace"`: Legacy namespace wrapping
|
|
23
16
|
|
|
24
17
|
## Cloning Strategy
|
|
25
18
|
|
|
@@ -34,28 +27,55 @@ and the caller should clone them explicitly.
|
|
|
34
27
|
|
|
35
28
|
## Example
|
|
36
29
|
|
|
37
|
-
```typescript
|
|
38
|
-
@derive(Clone)
|
|
30
|
+
```typescript before
|
|
31
|
+
/** @derive(Clone) */
|
|
32
|
+
class Point {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```typescript after
|
|
39
39
|
class Point {
|
|
40
40
|
x: number;
|
|
41
41
|
y: number;
|
|
42
|
+
|
|
43
|
+
static clone(value: Point): Point {
|
|
44
|
+
return pointClone(value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function pointClone(value: Point): Point {
|
|
49
|
+
const cloned = Object.create(Object.getPrototypeOf(value));
|
|
50
|
+
cloned.x = value.x;
|
|
51
|
+
cloned.y = value.y;
|
|
52
|
+
return cloned;
|
|
42
53
|
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Generated output:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
class Point {
|
|
60
|
+
x: number;
|
|
61
|
+
y: number;
|
|
43
62
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// cloned.y = this.y;
|
|
49
|
-
// return cloned;
|
|
50
|
-
// }
|
|
63
|
+
static clone(value: Point): Point {
|
|
64
|
+
return pointClone(value);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
51
67
|
|
|
52
|
-
|
|
53
|
-
const
|
|
68
|
+
export function pointClone(value: Point): Point {
|
|
69
|
+
const cloned = Object.create(Object.getPrototypeOf(value));
|
|
70
|
+
cloned.x = value.x;
|
|
71
|
+
cloned.y = value.y;
|
|
72
|
+
return cloned;
|
|
73
|
+
}
|
|
54
74
|
```
|
|
55
75
|
|
|
56
76
|
## Implementation Notes
|
|
57
77
|
|
|
58
|
-
- **Classes**: Uses `Object.create(Object.getPrototypeOf(
|
|
78
|
+
- **Classes**: Uses `Object.create(Object.getPrototypeOf(value))` to preserve
|
|
59
79
|
the prototype chain, ensuring `instanceof` checks work correctly
|
|
60
80
|
- **Enums**: Simply returns the value (enums are primitives in TypeScript)
|
|
61
81
|
- **Interfaces/Type Aliases**: Creates new object literals with spread operator
|
|
@@ -5,24 +5,17 @@ TypeScript classes, interfaces, enums, and type aliases.
|
|
|
5
5
|
|
|
6
6
|
## Generated Output
|
|
7
7
|
|
|
8
|
-
**Classes**: Generates
|
|
9
|
-
like `"ClassName { field1: value1, field2: value2 }"`.
|
|
8
|
+
**Classes**: Generates a standalone function `classNameToString(value)` and a static wrapper
|
|
9
|
+
method `static toString(value)` returning a string like `"ClassName { field1: value1, field2: value2 }"`.
|
|
10
10
|
|
|
11
|
-
**Enums**: Generates a standalone function `
|
|
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 `interfaceNameToString(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
|
-
## Configuration
|
|
20
|
-
|
|
21
|
-
The `functionNamingStyle` option in `macroforge.json` controls naming:
|
|
22
|
-
- `"prefix"` (default): Prefixes with type name (e.g., `myTypeToString`)
|
|
23
|
-
- `"suffix"`: Suffixes with type name (e.g., `toStringMyType`)
|
|
24
|
-
- `"generic"`: Uses TypeScript generics (e.g., `toString<T extends MyType>`)
|
|
25
|
-
- `"namespace"`: Legacy namespace wrapping
|
|
26
19
|
|
|
27
20
|
## Field-Level Options
|
|
28
21
|
|
|
@@ -33,20 +26,59 @@ The `@debug` decorator supports:
|
|
|
33
26
|
|
|
34
27
|
## Example
|
|
35
28
|
|
|
29
|
+
```typescript before
|
|
30
|
+
/** @derive(Debug) */
|
|
31
|
+
class User {
|
|
32
|
+
/** @debug({ rename: "id" }) */
|
|
33
|
+
userId: number;
|
|
34
|
+
|
|
35
|
+
/** @debug({ skip: true }) */
|
|
36
|
+
password: string;
|
|
37
|
+
|
|
38
|
+
email: string;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```typescript after
|
|
43
|
+
class User {
|
|
44
|
+
userId: number;
|
|
45
|
+
|
|
46
|
+
password: string;
|
|
47
|
+
|
|
48
|
+
email: string;
|
|
49
|
+
|
|
50
|
+
static toString(value: User): string {
|
|
51
|
+
return userToString(value);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function userToString(value: User): string {
|
|
56
|
+
const parts: string[] = [];
|
|
57
|
+
parts.push('id: ' + value.userId);
|
|
58
|
+
parts.push('email: ' + value.email);
|
|
59
|
+
return 'User { ' + parts.join(', ') + ' }';
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Generated output:
|
|
64
|
+
|
|
36
65
|
```typescript
|
|
37
|
-
@derive(Debug)
|
|
38
66
|
class User {
|
|
39
|
-
@debug(rename = "id")
|
|
40
67
|
userId: number;
|
|
41
68
|
|
|
42
|
-
@debug(skip)
|
|
43
69
|
password: string;
|
|
44
70
|
|
|
45
71
|
email: string;
|
|
72
|
+
|
|
73
|
+
static toString(value: User): string {
|
|
74
|
+
return userToString(value);
|
|
75
|
+
}
|
|
46
76
|
}
|
|
47
77
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
78
|
+
export function userToString(value: User): string {
|
|
79
|
+
const parts: string[] = [];
|
|
80
|
+
parts.push('id: ' + value.userId);
|
|
81
|
+
parts.push('email: ' + value.email);
|
|
82
|
+
return 'User { ' + parts.join(', ') + ' }';
|
|
83
|
+
}
|
|
52
84
|
```
|
|
@@ -13,13 +13,6 @@ a standard way to create "zero" or "empty" instances of types.
|
|
|
13
13
|
| Interface | `defaultValueInterfaceName(): InterfaceName` | Standalone function returning object literal |
|
|
14
14
|
| Type Alias | `defaultValueTypeName(): TypeName` | Standalone function with type-appropriate default |
|
|
15
15
|
|
|
16
|
-
## Configuration
|
|
17
|
-
|
|
18
|
-
The `functionNamingStyle` option in `macroforge.json` controls naming:
|
|
19
|
-
- `"prefix"` (default): Prefixes with type name (e.g., `myTypeDefaultValue`)
|
|
20
|
-
- `"suffix"`: Suffixes with type name (e.g., `defaultValueMyType`)
|
|
21
|
-
- `"generic"`: Uses TypeScript generics (e.g., `defaultValue<T extends MyType>`)
|
|
22
|
-
- `"namespace"`: Legacy namespace wrapping
|
|
23
16
|
|
|
24
17
|
## Default Values by Type
|
|
25
18
|
|
|
@@ -50,47 +43,105 @@ The `@default` decorator allows specifying explicit default values:
|
|
|
50
43
|
|
|
51
44
|
## Example
|
|
52
45
|
|
|
53
|
-
```typescript
|
|
54
|
-
@derive(Default)
|
|
46
|
+
```typescript before
|
|
47
|
+
/** @derive(Default) */
|
|
55
48
|
class UserSettings {
|
|
56
|
-
@default("light")
|
|
49
|
+
/** @default("light") */
|
|
57
50
|
theme: string;
|
|
58
51
|
|
|
59
|
-
@default(10)
|
|
52
|
+
/** @default(10) */
|
|
60
53
|
pageSize: number;
|
|
61
54
|
|
|
62
|
-
notifications: boolean;
|
|
55
|
+
notifications: boolean; // Uses type default: false
|
|
63
56
|
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```typescript after
|
|
60
|
+
class UserSettings {
|
|
61
|
+
theme: string;
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
pageSize: number;
|
|
64
|
+
|
|
65
|
+
notifications: boolean; // Uses type default: false
|
|
66
|
+
|
|
67
|
+
static defaultValue(): UserSettings {
|
|
68
|
+
const instance = new UserSettings();
|
|
69
|
+
instance.theme = 'light';
|
|
70
|
+
instance.pageSize = 10;
|
|
71
|
+
instance.notifications = false;
|
|
72
|
+
return instance;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Generated output:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
class UserSettings {
|
|
81
|
+
theme: string;
|
|
82
|
+
|
|
83
|
+
pageSize: number;
|
|
84
|
+
|
|
85
|
+
notifications: boolean; // Uses type default: false
|
|
86
|
+
|
|
87
|
+
static defaultValue(): UserSettings {
|
|
88
|
+
const instance = new UserSettings();
|
|
89
|
+
instance.theme = 'light';
|
|
90
|
+
instance.pageSize = 10;
|
|
91
|
+
instance.notifications = false;
|
|
92
|
+
return instance;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
73
95
|
```
|
|
74
96
|
|
|
75
97
|
## Enum Defaults
|
|
76
98
|
|
|
77
99
|
For enums, mark one variant with `@default`:
|
|
78
100
|
|
|
101
|
+
```typescript before
|
|
102
|
+
/** @derive(Default) */
|
|
103
|
+
enum Status {
|
|
104
|
+
/** @default */
|
|
105
|
+
Pending,
|
|
106
|
+
Active,
|
|
107
|
+
Completed
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```typescript after
|
|
112
|
+
enum Status {
|
|
113
|
+
/** @default */
|
|
114
|
+
Pending,
|
|
115
|
+
Active,
|
|
116
|
+
Completed
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function statusDefaultValue(): Status {
|
|
120
|
+
return Status.Pending;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export const Status = {
|
|
124
|
+
defaultValue: statusDefaultValue
|
|
125
|
+
} as const;
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Generated output:
|
|
129
|
+
|
|
79
130
|
```typescript
|
|
80
|
-
@derive(Default)
|
|
81
131
|
enum Status {
|
|
82
|
-
@default
|
|
132
|
+
/** @default */
|
|
83
133
|
Pending,
|
|
84
134
|
Active,
|
|
85
135
|
Completed
|
|
86
136
|
}
|
|
87
137
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
138
|
+
export function statusDefaultValue(): Status {
|
|
139
|
+
return Status.Pending;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const Status = {
|
|
143
|
+
defaultValue: statusDefaultValue
|
|
144
|
+
} as const;
|
|
94
145
|
```
|
|
95
146
|
|
|
96
147
|
## Error Handling
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Cycle/Forward-Reference Support
|
|
2
|
+
|
|
3
|
+
Uses deferred patching to handle references:
|
|
4
|
+
|
|
5
|
+
1. When encountering `{ "__ref": id }`, returns a `PendingRef` marker
|
|
6
|
+
2. Continues deserializing other fields
|
|
7
|
+
3. After all objects are created, `ctx.applyPatches()` resolves all pending references
|
|
8
|
+
|
|
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 primitive-like),
|
|
11
|
+
and it parses `Date` / `Date | null` from ISO strings without treating them as references.
|