@macroforge/mcp-server 0.1.17
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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/docs-loader.d.ts +30 -0
- package/dist/tools/docs-loader.d.ts.map +1 -0
- package/dist/tools/docs-loader.js +112 -0
- package/dist/tools/docs-loader.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +348 -0
- package/dist/tools/index.js.map +1 -0
- package/docs/api/api-overview.md +75 -0
- package/docs/api/expand-sync.md +121 -0
- package/docs/api/native-plugin.md +106 -0
- package/docs/api/position-mapper.md +127 -0
- package/docs/api/transform-sync.md +98 -0
- package/docs/builtin-macros/clone.md +180 -0
- package/docs/builtin-macros/debug.md +222 -0
- package/docs/builtin-macros/default.md +192 -0
- package/docs/builtin-macros/deserialize.md +662 -0
- package/docs/builtin-macros/hash.md +205 -0
- package/docs/builtin-macros/macros-overview.md +169 -0
- package/docs/builtin-macros/ord.md +258 -0
- package/docs/builtin-macros/partial-eq.md +306 -0
- package/docs/builtin-macros/partial-ord.md +268 -0
- package/docs/builtin-macros/serialize.md +321 -0
- package/docs/concepts/architecture.md +139 -0
- package/docs/concepts/derive-system.md +173 -0
- package/docs/concepts/how-macros-work.md +124 -0
- package/docs/custom-macros/custom-overview.md +84 -0
- package/docs/custom-macros/rust-setup.md +146 -0
- package/docs/custom-macros/ts-macro-derive.md +307 -0
- package/docs/custom-macros/ts-quote.md +696 -0
- package/docs/getting-started/first-macro.md +120 -0
- package/docs/getting-started/installation.md +110 -0
- package/docs/integration/cli.md +207 -0
- package/docs/integration/configuration.md +116 -0
- package/docs/integration/integration-overview.md +51 -0
- package/docs/integration/typescript-plugin.md +96 -0
- package/docs/integration/vite-plugin.md +126 -0
- package/docs/language-servers/ls-overview.md +47 -0
- package/docs/language-servers/svelte-ls.md +80 -0
- package/docs/language-servers/zed-extensions.md +84 -0
- package/docs/sections.json +258 -0
- package/package.json +48 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# expandSync()
|
|
2
|
+
|
|
3
|
+
*Expands macros in TypeScript code synchronously and returns the transformed output.*
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
function expandSync(
|
|
9
|
+
code: string,
|
|
10
|
+
filepath: string,
|
|
11
|
+
options?: ExpandOptions
|
|
12
|
+
): ExpandResult
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Parameters
|
|
16
|
+
|
|
17
|
+
| `code`
|
|
18
|
+
| `string`
|
|
19
|
+
| TypeScript source code to transform
|
|
20
|
+
|
|
21
|
+
| `filepath`
|
|
22
|
+
| `string`
|
|
23
|
+
| File path (used for error reporting)
|
|
24
|
+
|
|
25
|
+
| `options`
|
|
26
|
+
| `ExpandOptions`
|
|
27
|
+
| Optional configuration
|
|
28
|
+
|
|
29
|
+
## ExpandOptions
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
interface ExpandOptions {
|
|
33
|
+
// Keep @derive decorators in output (default: false)
|
|
34
|
+
keepDecorators?: boolean;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## ExpandResult
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
interface ExpandResult {
|
|
42
|
+
// Transformed TypeScript code
|
|
43
|
+
code: string;
|
|
44
|
+
|
|
45
|
+
// Generated type declarations (.d.ts content)
|
|
46
|
+
types?: string;
|
|
47
|
+
|
|
48
|
+
// Macro expansion metadata (JSON string)
|
|
49
|
+
metadata?: string;
|
|
50
|
+
|
|
51
|
+
// Warnings and errors from macro expansion
|
|
52
|
+
diagnostics: MacroDiagnostic[];
|
|
53
|
+
|
|
54
|
+
// Position mapping data for source maps
|
|
55
|
+
sourceMapping?: SourceMappingResult;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## MacroDiagnostic
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
interface MacroDiagnostic {
|
|
63
|
+
message: string;
|
|
64
|
+
severity: "error" | "warning" | "info";
|
|
65
|
+
span: {
|
|
66
|
+
start: number;
|
|
67
|
+
end: number;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Example
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { expandSync } from "macroforge";
|
|
76
|
+
|
|
77
|
+
const sourceCode = \`
|
|
78
|
+
import { Debug } from "macroforge";
|
|
79
|
+
|
|
80
|
+
/** @derive(Debug) */
|
|
81
|
+
class User {
|
|
82
|
+
name: string;
|
|
83
|
+
age: number;
|
|
84
|
+
|
|
85
|
+
constructor(name: string, age: number) {
|
|
86
|
+
this.name = name;
|
|
87
|
+
this.age = age;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
\`;
|
|
91
|
+
|
|
92
|
+
const result = expandSync(sourceCode, "user.ts");
|
|
93
|
+
|
|
94
|
+
console.log("Transformed code:");
|
|
95
|
+
console.log(result.code);
|
|
96
|
+
|
|
97
|
+
if (result.types) {
|
|
98
|
+
console.log("Type declarations:");
|
|
99
|
+
console.log(result.types);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (result.diagnostics.length > 0) {
|
|
103
|
+
for (const diag of result.diagnostics) {
|
|
104
|
+
console.log(\`[\${diag.severity}] \${diag.message}\`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Error Handling
|
|
110
|
+
|
|
111
|
+
Syntax errors and macro errors are returned in the `diagnostics` array, not thrown as exceptions:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const result = expandSync(invalidCode, "file.ts");
|
|
115
|
+
|
|
116
|
+
for (const diag of result.diagnostics) {
|
|
117
|
+
if (diag.severity === "error") {
|
|
118
|
+
console.error(\`Error at \${diag.span.start}: \${diag.message}\`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# NativePlugin
|
|
2
|
+
|
|
3
|
+
*A stateful plugin class with version-based caching, designed for integration with language servers and IDEs.*
|
|
4
|
+
|
|
5
|
+
## Constructor
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const plugin = new NativePlugin();
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Methods
|
|
12
|
+
|
|
13
|
+
### processFile()
|
|
14
|
+
|
|
15
|
+
Process a file with version-based caching:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
processFile(
|
|
19
|
+
filepath: string,
|
|
20
|
+
code: string,
|
|
21
|
+
options?: ProcessFileOptions
|
|
22
|
+
): ExpandResult
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
interface ProcessFileOptions {
|
|
27
|
+
// Cache key - if unchanged, returns cached result
|
|
28
|
+
version?: string;
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### getMapper()
|
|
33
|
+
|
|
34
|
+
Get the position mapper for a previously processed file:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
getMapper(filepath: string): NativeMapper | null
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### mapDiagnostics()
|
|
41
|
+
|
|
42
|
+
Map diagnostics from expanded positions to original positions:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
mapDiagnostics(
|
|
46
|
+
filepath: string,
|
|
47
|
+
diagnostics: JsDiagnostic[]
|
|
48
|
+
): JsDiagnostic[]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### log() / setLogFile()
|
|
52
|
+
|
|
53
|
+
Logging utilities for debugging:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
log(message: string): void
|
|
57
|
+
setLogFile(path: string): void
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Caching Behavior
|
|
61
|
+
|
|
62
|
+
The plugin caches expansion results by file path and version:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
const plugin = new NativePlugin();
|
|
66
|
+
|
|
67
|
+
// First call - performs expansion
|
|
68
|
+
const result1 = plugin.processFile("user.ts", code, { version: "1" });
|
|
69
|
+
|
|
70
|
+
// Same version - returns cached result instantly
|
|
71
|
+
const result2 = plugin.processFile("user.ts", code, { version: "1" });
|
|
72
|
+
|
|
73
|
+
// Different version - re-expands
|
|
74
|
+
const result3 = plugin.processFile("user.ts", newCode, { version: "2" });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Example: Language Server Integration
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { NativePlugin } from "macroforge";
|
|
81
|
+
|
|
82
|
+
class MacroforgeLanguageService {
|
|
83
|
+
private plugin = new NativePlugin();
|
|
84
|
+
|
|
85
|
+
processDocument(uri: string, content: string, version: number) {
|
|
86
|
+
// Process with version-based caching
|
|
87
|
+
const result = this.plugin.processFile(uri, content, {
|
|
88
|
+
version: String(version)
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Get mapper for position translation
|
|
92
|
+
const mapper = this.plugin.getMapper(uri);
|
|
93
|
+
|
|
94
|
+
return { result, mapper };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
getSemanticDiagnostics(uri: string, diagnostics: Diagnostic[]) {
|
|
98
|
+
// Map positions from expanded to original
|
|
99
|
+
return this.plugin.mapDiagnostics(uri, diagnostics);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Thread Safety
|
|
105
|
+
|
|
106
|
+
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.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# PositionMapper
|
|
2
|
+
|
|
3
|
+
*Maps positions between original source code and macro-expanded code. Essential for accurate error reporting and debugging.*
|
|
4
|
+
|
|
5
|
+
## Getting a Mapper
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { NativePlugin, PositionMapper } from "macroforge";
|
|
9
|
+
|
|
10
|
+
const plugin = new NativePlugin();
|
|
11
|
+
const result = plugin.processFile("user.ts", code, { version: "1" });
|
|
12
|
+
|
|
13
|
+
// Get the mapper for this file
|
|
14
|
+
const mapper = plugin.getMapper("user.ts");
|
|
15
|
+
if (mapper) {
|
|
16
|
+
// Use the mapper...
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Methods
|
|
21
|
+
|
|
22
|
+
### isEmpty()
|
|
23
|
+
|
|
24
|
+
Check if the mapper has any mappings:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
isEmpty(): boolean
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### originalToExpanded()
|
|
31
|
+
|
|
32
|
+
Map a position from original to expanded code:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
originalToExpanded(pos: number): number
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### expandedToOriginal()
|
|
39
|
+
|
|
40
|
+
Map a position from expanded to original code:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
expandedToOriginal(pos: number): number | null
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Returns `null` if the position is in generated code.
|
|
47
|
+
|
|
48
|
+
### isInGenerated()
|
|
49
|
+
|
|
50
|
+
Check if a position is in macro-generated code:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
isInGenerated(pos: number): boolean
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### generatedBy()
|
|
57
|
+
|
|
58
|
+
Get the name of the macro that generated code at a position:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
generatedBy(pos: number): string | null
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### mapSpanToOriginal()
|
|
65
|
+
|
|
66
|
+
Map a span (range) from expanded to original code:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
mapSpanToOriginal(start: number, length: number): SpanResult | null
|
|
70
|
+
|
|
71
|
+
interface SpanResult {
|
|
72
|
+
start: number;
|
|
73
|
+
length: number;
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### mapSpanToExpanded()
|
|
78
|
+
|
|
79
|
+
Map a span from original to expanded code:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
mapSpanToExpanded(start: number, length: number): SpanResult
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Example: Error Position Mapping
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { NativePlugin } from "macroforge";
|
|
89
|
+
|
|
90
|
+
const plugin = new NativePlugin();
|
|
91
|
+
|
|
92
|
+
function mapError(filepath: string, expandedPos: number, message: string) {
|
|
93
|
+
const mapper = plugin.getMapper(filepath);
|
|
94
|
+
if (!mapper) return null;
|
|
95
|
+
|
|
96
|
+
// Check if the error is in generated code
|
|
97
|
+
if (mapper.isInGenerated(expandedPos)) {
|
|
98
|
+
const macroName = mapper.generatedBy(expandedPos);
|
|
99
|
+
return {
|
|
100
|
+
message: \`Error in code generated by @derive(\${macroName}): \${message}\`,
|
|
101
|
+
// Find the @derive decorator position
|
|
102
|
+
position: findDecoratorPosition(filepath)
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Map to original position
|
|
107
|
+
const originalPos = mapper.expandedToOriginal(expandedPos);
|
|
108
|
+
if (originalPos !== null) {
|
|
109
|
+
return {
|
|
110
|
+
message,
|
|
111
|
+
position: originalPos
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Performance
|
|
120
|
+
|
|
121
|
+
Position mapping uses binary search with O(log n) complexity:
|
|
122
|
+
|
|
123
|
+
- Fast lookups even for large files
|
|
124
|
+
|
|
125
|
+
- Minimal memory overhead
|
|
126
|
+
|
|
127
|
+
- Thread-safe access
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# transformSync()
|
|
2
|
+
|
|
3
|
+
*A lower-level transform function that returns additional metadata alongside the transformed code.*
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
function transformSync(
|
|
9
|
+
code: string,
|
|
10
|
+
filepath: string
|
|
11
|
+
): TransformResult
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Parameters
|
|
15
|
+
|
|
16
|
+
| `code`
|
|
17
|
+
| `string`
|
|
18
|
+
| TypeScript source code to transform
|
|
19
|
+
|
|
20
|
+
| `filepath`
|
|
21
|
+
| `string`
|
|
22
|
+
| File path (used for error reporting)
|
|
23
|
+
|
|
24
|
+
## TransformResult
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
interface TransformResult {
|
|
28
|
+
// Transformed TypeScript code
|
|
29
|
+
code: string;
|
|
30
|
+
|
|
31
|
+
// Source map (JSON string, not yet implemented)
|
|
32
|
+
map?: string;
|
|
33
|
+
|
|
34
|
+
// Generated type declarations
|
|
35
|
+
types?: string;
|
|
36
|
+
|
|
37
|
+
// Macro expansion metadata
|
|
38
|
+
metadata?: string;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Comparison with expandSync()
|
|
43
|
+
|
|
44
|
+
| Options
|
|
45
|
+
| Yes
|
|
46
|
+
| No
|
|
47
|
+
|
|
48
|
+
| Diagnostics
|
|
49
|
+
| Yes
|
|
50
|
+
| No
|
|
51
|
+
|
|
52
|
+
| Source Mapping
|
|
53
|
+
| Yes
|
|
54
|
+
| Limited
|
|
55
|
+
|
|
56
|
+
| Use Case
|
|
57
|
+
| General purpose
|
|
58
|
+
| Build tools
|
|
59
|
+
|
|
60
|
+
## Example
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { transformSync } from "macroforge";
|
|
64
|
+
|
|
65
|
+
const sourceCode = \`
|
|
66
|
+
/** @derive(Debug) */
|
|
67
|
+
class User {
|
|
68
|
+
name: string;
|
|
69
|
+
}
|
|
70
|
+
\`;
|
|
71
|
+
|
|
72
|
+
const result = transformSync(sourceCode, "user.ts");
|
|
73
|
+
|
|
74
|
+
console.log(result.code);
|
|
75
|
+
|
|
76
|
+
if (result.types) {
|
|
77
|
+
// Write to .d.ts file
|
|
78
|
+
fs.writeFileSync("user.d.ts", result.types);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (result.metadata) {
|
|
82
|
+
// Parse and use metadata
|
|
83
|
+
const meta = JSON.parse(result.metadata);
|
|
84
|
+
console.log("Macros expanded:", meta);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## When to Use
|
|
89
|
+
|
|
90
|
+
Use `transformSync` when:
|
|
91
|
+
|
|
92
|
+
- Building custom integrations
|
|
93
|
+
|
|
94
|
+
- You need raw output without diagnostics
|
|
95
|
+
|
|
96
|
+
- You're implementing a build tool plugin
|
|
97
|
+
|
|
98
|
+
Use `expandSync` for most other use cases, as it provides better error handling.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Clone
|
|
2
|
+
|
|
3
|
+
*The `Clone` macro generates a `clone()` method that creates a copy of the object.*
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
/** @derive(Clone) */
|
|
9
|
+
class Point {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
|
|
13
|
+
constructor(x: number, y: number) {
|
|
14
|
+
this.x = x;
|
|
15
|
+
this.y = y;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const original = new Point(10, 20);
|
|
20
|
+
const copy = original.clone();
|
|
21
|
+
|
|
22
|
+
console.log(copy.x, copy.y); // 10, 20
|
|
23
|
+
console.log(original === copy); // false (different instances)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Generated Code
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
clone(): Point {
|
|
30
|
+
return new Point(this.x, this.y);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## How It Works
|
|
35
|
+
|
|
36
|
+
The Clone macro:
|
|
37
|
+
|
|
38
|
+
1. Creates a new instance of the class
|
|
39
|
+
|
|
40
|
+
2. Passes all field values to the constructor
|
|
41
|
+
|
|
42
|
+
3. Returns the new instance
|
|
43
|
+
|
|
44
|
+
This creates a **shallow clone** - primitive values are copied, but object references remain the same.
|
|
45
|
+
|
|
46
|
+
## With Nested Objects
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
/** @derive(Clone) */
|
|
50
|
+
class User {
|
|
51
|
+
name: string;
|
|
52
|
+
address: { city: string; zip: string };
|
|
53
|
+
|
|
54
|
+
constructor(name: string, address: { city: string; zip: string }) {
|
|
55
|
+
this.name = name;
|
|
56
|
+
this.address = address;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const original = new User("Alice", { city: "NYC", zip: "10001" });
|
|
61
|
+
const copy = original.clone();
|
|
62
|
+
|
|
63
|
+
// The address object is the same reference
|
|
64
|
+
console.log(original.address === copy.address); // true
|
|
65
|
+
|
|
66
|
+
// Modifying the copy's address affects the original
|
|
67
|
+
copy.address.city = "LA";
|
|
68
|
+
console.log(original.address.city); // "LA"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For deep cloning of nested objects, you would need to implement custom clone methods or use a deep clone utility.
|
|
72
|
+
|
|
73
|
+
## Combining with Eq
|
|
74
|
+
|
|
75
|
+
Clone works well with Eq for creating independent copies that compare as equal:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
/** @derive(Clone, Eq) */
|
|
79
|
+
class Point {
|
|
80
|
+
x: number;
|
|
81
|
+
y: number;
|
|
82
|
+
|
|
83
|
+
constructor(x: number, y: number) {
|
|
84
|
+
this.x = x;
|
|
85
|
+
this.y = y;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const original = new Point(10, 20);
|
|
90
|
+
const copy = original.clone();
|
|
91
|
+
|
|
92
|
+
console.log(original === copy); // false (different instances)
|
|
93
|
+
console.log(original.equals(copy)); // true (same values)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Interface Support
|
|
97
|
+
|
|
98
|
+
Clone also works with interfaces. For interfaces, a namespace is generated with a `clone` function:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
/** @derive(Clone) */
|
|
102
|
+
interface Point {
|
|
103
|
+
x: number;
|
|
104
|
+
y: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Generated:
|
|
108
|
+
// export namespace Point {
|
|
109
|
+
// export function clone(self: Point): Point {
|
|
110
|
+
// return { x: self.x, y: self.y };
|
|
111
|
+
// }
|
|
112
|
+
// }
|
|
113
|
+
|
|
114
|
+
const original: Point = { x: 10, y: 20 };
|
|
115
|
+
const copy = Point.clone(original);
|
|
116
|
+
|
|
117
|
+
console.log(copy.x, copy.y); // 10, 20
|
|
118
|
+
console.log(original === copy); // false (different objects)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Enum Support
|
|
122
|
+
|
|
123
|
+
Clone also works with enums. For enums, the clone function simply returns the value as-is, since enum values are primitives and don't need cloning:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
/** @derive(Clone) */
|
|
127
|
+
enum Status {
|
|
128
|
+
Active = "active",
|
|
129
|
+
Inactive = "inactive",
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Generated:
|
|
133
|
+
// export namespace Status {
|
|
134
|
+
// export function clone(value: Status): Status {
|
|
135
|
+
// return value;
|
|
136
|
+
// }
|
|
137
|
+
// }
|
|
138
|
+
|
|
139
|
+
const original = Status.Active;
|
|
140
|
+
const copy = Status.clone(original);
|
|
141
|
+
|
|
142
|
+
console.log(copy); // "active"
|
|
143
|
+
console.log(original === copy); // true (same primitive value)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Type Alias Support
|
|
147
|
+
|
|
148
|
+
Clone works with type aliases. For object types, a shallow copy is created using spread:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
/** @derive(Clone) */
|
|
152
|
+
type Point = {
|
|
153
|
+
x: number;
|
|
154
|
+
y: number;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Generated:
|
|
158
|
+
// export namespace Point {
|
|
159
|
+
// export function clone(value: Point): Point {
|
|
160
|
+
// return { ...value };
|
|
161
|
+
// }
|
|
162
|
+
// }
|
|
163
|
+
|
|
164
|
+
const original: Point = { x: 10, y: 20 };
|
|
165
|
+
const copy = Point.clone(original);
|
|
166
|
+
|
|
167
|
+
console.log(copy.x, copy.y); // 10, 20
|
|
168
|
+
console.log(original === copy); // false (different objects)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
For union types, the value is returned as-is (unions of primitives don't need cloning):
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
/** @derive(Clone) */
|
|
175
|
+
type ApiStatus = "loading" | "success" | "error";
|
|
176
|
+
|
|
177
|
+
const status: ApiStatus = "success";
|
|
178
|
+
const copy = ApiStatus.clone(status);
|
|
179
|
+
console.log(copy); // "success"
|
|
180
|
+
```
|