@macroforge/mcp-server 0.1.32 → 0.1.34
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/README.md +68 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/docs-loader.d.ts +133 -5
- package/dist/tools/docs-loader.d.ts.map +1 -1
- package/dist/tools/docs-loader.js +131 -15
- package/dist/tools/docs-loader.js.map +1 -1
- package/dist/tools/index.d.ts +48 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +163 -14
- package/dist/tools/index.js.map +1 -1
- package/docs/api/api-overview.md +24 -46
- package/docs/api/expand-sync.md +24 -51
- package/docs/api/native-plugin.md +24 -56
- package/docs/api/position-mapper.md +34 -76
- package/docs/api/transform-sync.md +27 -59
- package/docs/builtin-macros/clone.md +150 -68
- package/docs/builtin-macros/debug.md +216 -81
- package/docs/builtin-macros/default.md +234 -91
- package/docs/builtin-macros/deserialize.md +891 -166
- package/docs/builtin-macros/hash.md +238 -82
- package/docs/builtin-macros/macros-overview.md +42 -103
- package/docs/builtin-macros/ord.md +205 -92
- package/docs/builtin-macros/partial-eq.md +178 -97
- package/docs/builtin-macros/partial-ord.md +209 -98
- package/docs/builtin-macros/serialize.md +326 -137
- package/docs/concepts/architecture.md +40 -99
- package/docs/concepts/derive-system.md +132 -125
- package/docs/concepts/how-macros-work.md +52 -84
- package/docs/custom-macros/custom-overview.md +17 -39
- package/docs/custom-macros/rust-setup.md +22 -55
- package/docs/custom-macros/ts-macro-derive.md +43 -107
- package/docs/custom-macros/ts-quote.md +177 -507
- package/docs/getting-started/first-macro.md +108 -33
- package/docs/getting-started/installation.md +32 -73
- package/docs/integration/cli.md +70 -156
- package/docs/integration/configuration.md +32 -75
- package/docs/integration/integration-overview.md +16 -55
- package/docs/integration/mcp-server.md +30 -69
- package/docs/integration/svelte-preprocessor.md +60 -83
- package/docs/integration/typescript-plugin.md +32 -74
- package/docs/integration/vite-plugin.md +30 -79
- package/docs/language-servers/ls-overview.md +22 -46
- package/docs/language-servers/svelte.md +30 -69
- package/docs/language-servers/zed.md +34 -72
- package/docs/roadmap/roadmap.md +54 -130
- package/docs/sections.json +3 -262
- package/package.json +2 -2
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
# PositionMapper
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Getting a Mapper
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
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
|
+
## Getting a Mapper
|
|
4
|
+
```
|
|
8
5
|
import { NativePlugin, PositionMapper } from "macroforge";
|
|
9
6
|
|
|
10
7
|
const plugin = new NativePlugin();
|
|
@@ -15,76 +12,43 @@ const mapper = plugin.getMapper("user.ts");
|
|
|
15
12
|
if (mapper) {
|
|
16
13
|
// Use the mapper...
|
|
17
14
|
}
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
### isEmpty()
|
|
23
|
-
|
|
24
|
-
Check if the mapper has any mappings:
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
15
|
+
``` ## Methods
|
|
16
|
+
### isEmpty()
|
|
17
|
+
Check if the mapper has any mappings:
|
|
18
|
+
```
|
|
27
19
|
isEmpty(): boolean
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Map a position from original to expanded code:
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
20
|
+
``` ### originalToExpanded()
|
|
21
|
+
Map a position from original to expanded code:
|
|
22
|
+
```
|
|
35
23
|
originalToExpanded(pos: number): number
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Map a position from expanded to original code:
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
24
|
+
``` ### expandedToOriginal()
|
|
25
|
+
Map a position from expanded to original code:
|
|
26
|
+
```
|
|
43
27
|
expandedToOriginal(pos: number): number | null
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### isInGenerated()
|
|
49
|
-
|
|
50
|
-
Check if a position is in macro-generated code:
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
28
|
+
``` Returns `null` if the position is in generated code.
|
|
29
|
+
### isInGenerated()
|
|
30
|
+
Check if a position is in macro-generated code:
|
|
31
|
+
```
|
|
53
32
|
isInGenerated(pos: number): boolean
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
Get the name of the macro that generated code at a position:
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
33
|
+
``` ### generatedBy()
|
|
34
|
+
Get the name of the macro that generated code at a position:
|
|
35
|
+
```
|
|
61
36
|
generatedBy(pos: number): string | null
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
Map a span (range) from expanded to original code:
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
37
|
+
``` ### mapSpanToOriginal()
|
|
38
|
+
Map a span (range) from expanded to original code:
|
|
39
|
+
```
|
|
69
40
|
mapSpanToOriginal(start: number, length: number): SpanResult | null
|
|
70
41
|
|
|
71
42
|
interface SpanResult {
|
|
72
43
|
start: number;
|
|
73
44
|
length: number;
|
|
74
45
|
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Map a span from original to expanded code:
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
46
|
+
``` ### mapSpanToExpanded()
|
|
47
|
+
Map a span from original to expanded code:
|
|
48
|
+
```
|
|
82
49
|
mapSpanToExpanded(start: number, length: number): SpanResult
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Example: Error Position Mapping
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
50
|
+
``` ## Example: Error Position Mapping
|
|
51
|
+
```
|
|
88
52
|
import { NativePlugin } from "macroforge";
|
|
89
53
|
|
|
90
54
|
const plugin = new NativePlugin();
|
|
@@ -97,7 +61,7 @@ function mapError(filepath: string, expandedPos: number, message: string) {
|
|
|
97
61
|
if (mapper.isInGenerated(expandedPos)) {
|
|
98
62
|
const macroName = mapper.generatedBy(expandedPos);
|
|
99
63
|
return {
|
|
100
|
-
message:
|
|
64
|
+
message: `Error in code generated by @derive(${macroName}): ${message}`,
|
|
101
65
|
// Find the @derive decorator position
|
|
102
66
|
position: findDecoratorPosition(filepath)
|
|
103
67
|
};
|
|
@@ -114,14 +78,8 @@ function mapError(filepath: string, expandedPos: number, message: string) {
|
|
|
114
78
|
|
|
115
79
|
return null;
|
|
116
80
|
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
- Fast lookups even for large files
|
|
124
|
-
|
|
125
|
-
- Minimal memory overhead
|
|
126
|
-
|
|
127
|
-
- Thread-safe access
|
|
81
|
+
``` ## Performance
|
|
82
|
+
Position mapping uses binary search with O(log n) complexity:
|
|
83
|
+
- Fast lookups even for large files
|
|
84
|
+
- Minimal memory overhead
|
|
85
|
+
- Thread-safe access
|
|
@@ -1,29 +1,18 @@
|
|
|
1
1
|
# transformSync()
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Signature
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
2
|
+
*Synchronously transforms TypeScript code through the macro expansion system. This is similar to [`expand_sync`] but returns a [`TransformResult`] which includes source map information (when available).*
|
|
3
|
+
## Signature
|
|
4
|
+
```
|
|
8
5
|
function transformSync(
|
|
9
6
|
code: string,
|
|
10
7
|
filepath: string
|
|
11
8
|
): TransformResult
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
| `
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
| `filepath`
|
|
21
|
-
| `string`
|
|
22
|
-
| File path (used for error reporting)
|
|
23
|
-
|
|
24
|
-
## TransformResult
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
9
|
+
``` ## Parameters
|
|
10
|
+
| Parameter | Type | Description |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| `code` | `string` | TypeScript source code to transform |
|
|
13
|
+
| `filepath` | `string` | File path (used for error reporting) |
|
|
14
|
+
## TransformResult
|
|
15
|
+
```
|
|
27
16
|
interface TransformResult {
|
|
28
17
|
// Transformed TypeScript code
|
|
29
18
|
code: string;
|
|
@@ -37,37 +26,23 @@ interface TransformResult {
|
|
|
37
26
|
// Macro expansion metadata
|
|
38
27
|
metadata?: string;
|
|
39
28
|
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
|
45
|
-
| Yes
|
|
46
|
-
|
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
29
|
+
``` ## Comparison with expandSync()
|
|
30
|
+
| Feature | `expandSync` | `transformSync` |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| Options | Yes | No |
|
|
33
|
+
| Diagnostics | Yes | No |
|
|
34
|
+
| Source Mapping | Yes | Limited |
|
|
35
|
+
| Use Case | General purpose | Build tools |
|
|
36
|
+
## Example
|
|
37
|
+
```
|
|
63
38
|
import { transformSync } from "macroforge";
|
|
64
39
|
|
|
65
|
-
const sourceCode =
|
|
40
|
+
const sourceCode = `
|
|
66
41
|
/** @derive(Debug) */
|
|
67
42
|
class User {
|
|
68
43
|
name: string;
|
|
69
44
|
}
|
|
70
|
-
|
|
45
|
+
`;
|
|
71
46
|
|
|
72
47
|
const result = transformSync(sourceCode, "user.ts");
|
|
73
48
|
|
|
@@ -83,16 +58,9 @@ if (result.metadata) {
|
|
|
83
58
|
const meta = JSON.parse(result.metadata);
|
|
84
59
|
console.log("Macros expanded:", meta);
|
|
85
60
|
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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.
|
|
61
|
+
``` ## When to Use
|
|
62
|
+
Use `transformSync` when:
|
|
63
|
+
- Building custom integrations
|
|
64
|
+
- You need raw output without diagnostics
|
|
65
|
+
- You're implementing a build tool plugin
|
|
66
|
+
Use `expandSync` for most other use cases, as it provides better error handling.
|
|
@@ -1,36 +1,82 @@
|
|
|
1
1
|
# Clone
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
*The `Clone` macro generates a `clone()` method for deep copying objects. This is analogous to Rust's `Clone` trait, providing a way to create independent copies of values.*
|
|
3
|
+
## Basic Usage
|
|
4
|
+
**Before:**
|
|
5
|
+
```
|
|
6
|
+
/** @derive(Clone) */
|
|
7
|
+
class Point {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
|
|
11
|
+
constructor(x: number, y: number) {
|
|
12
|
+
this.x = x;
|
|
13
|
+
this.y = y;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
**After:**
|
|
18
|
+
```
|
|
19
|
+
class Point {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
|
|
23
|
+
constructor(x: number, y: number) {
|
|
24
|
+
this.x = x;
|
|
25
|
+
this.y = y;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
clone(): Point {
|
|
29
|
+
const cloned = Object.create(Object.getPrototypeOf(this));
|
|
30
|
+
cloned.x = this.x;
|
|
31
|
+
cloned.y = this.y;
|
|
32
|
+
return cloned;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
``` ```
|
|
10
36
|
const original = new Point(10, 20);
|
|
11
37
|
const copy = original.clone();
|
|
12
38
|
|
|
13
39
|
console.log(copy.x, copy.y); // 10, 20
|
|
14
40
|
console.log(original === copy); // false (different instances)
|
|
41
|
+
``` ## How It Works
|
|
42
|
+
The Clone macro:
|
|
43
|
+
1. Creates a new instance of the class
|
|
44
|
+
2. Passes all field values to the constructor
|
|
45
|
+
3. Returns the new instance
|
|
46
|
+
This creates a **shallow clone** - primitive values are copied, but object references remain the same.
|
|
47
|
+
## With Nested Objects
|
|
48
|
+
**Before:**
|
|
15
49
|
```
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
50
|
+
/** @derive(Clone) */
|
|
51
|
+
class User {
|
|
52
|
+
name: string;
|
|
53
|
+
address: { city: string; zip: string };
|
|
54
|
+
|
|
55
|
+
constructor(name: string, address: { city: string; zip: string }) {
|
|
56
|
+
this.name = name;
|
|
57
|
+
this.address = address;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
**After:**
|
|
62
|
+
```
|
|
63
|
+
class User {
|
|
64
|
+
name: string;
|
|
65
|
+
address: { city: string; zip: string };
|
|
66
|
+
|
|
67
|
+
constructor(name: string, address: { city: string; zip: string }) {
|
|
68
|
+
this.name = name;
|
|
69
|
+
this.address = address;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
clone(): User {
|
|
73
|
+
const cloned = Object.create(Object.getPrototypeOf(this));
|
|
74
|
+
cloned.name = this.name;
|
|
75
|
+
cloned.address = this.address;
|
|
76
|
+
return cloned;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
``` ```
|
|
34
80
|
const original = new User("Alice", { city: "NYC", zip: "10001" });
|
|
35
81
|
const copy = original.clone();
|
|
36
82
|
|
|
@@ -40,15 +86,12 @@ console.log(original.address === copy.address); // true
|
|
|
40
86
|
// Modifying the copy's address affects the original
|
|
41
87
|
copy.address.city = "LA";
|
|
42
88
|
console.log(original.address.city); // "LA"
|
|
89
|
+
``` For deep cloning of nested objects, you would need to implement custom clone methods or use a deep clone utility.
|
|
90
|
+
## Combining with PartialEq
|
|
91
|
+
Clone works well with PartialEq for creating independent copies that compare as equal:
|
|
92
|
+
**Source:**
|
|
43
93
|
```
|
|
44
|
-
|
|
45
|
-
For deep cloning of nested objects, you would need to implement custom clone methods or use a deep clone utility.
|
|
46
|
-
|
|
47
|
-
## Combining with PartialEq
|
|
48
|
-
|
|
49
|
-
Clone works well with PartialEq for creating independent copies that compare as equal:
|
|
50
|
-
|
|
51
|
-
<InteractiveMacro code={`/** @derive(Clone, PartialEq) */
|
|
94
|
+
/** @derive(Clone, PartialEq) */
|
|
52
95
|
class Point {
|
|
53
96
|
x: number;
|
|
54
97
|
y: number;
|
|
@@ -57,64 +100,103 @@ class Point {
|
|
|
57
100
|
this.x = x;
|
|
58
101
|
this.y = y;
|
|
59
102
|
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
103
|
+
}
|
|
104
|
+
``` ```
|
|
63
105
|
const original = new Point(10, 20);
|
|
64
106
|
const copy = original.clone();
|
|
65
107
|
|
|
66
108
|
console.log(original === copy); // false (different instances)
|
|
67
109
|
console.log(original.equals(copy)); // true (same values)
|
|
110
|
+
``` ## Interface Support
|
|
111
|
+
Clone also works with interfaces. For interfaces, a namespace is generated with a `clone` function:
|
|
112
|
+
**Before:**
|
|
68
113
|
```
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
```
|
|
114
|
+
/** @derive(Clone) */
|
|
115
|
+
interface Point {
|
|
116
|
+
x: number;
|
|
117
|
+
y: number;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
**After:**
|
|
121
|
+
```
|
|
122
|
+
interface Point {
|
|
123
|
+
x: number;
|
|
124
|
+
y: number;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export namespace Point {
|
|
128
|
+
export function clone(self: Point): Point {
|
|
129
|
+
return { x: self.x, y: self.y };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
``` ```
|
|
77
133
|
const original: Point = { x: 10, y: 20 };
|
|
78
134
|
const copy = Point.clone(original);
|
|
79
135
|
|
|
80
136
|
console.log(copy.x, copy.y); // 10, 20
|
|
81
137
|
console.log(original === copy); // false (different objects)
|
|
138
|
+
``` ## Enum Support
|
|
139
|
+
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:
|
|
140
|
+
**Before:**
|
|
82
141
|
```
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
```
|
|
142
|
+
/** @derive(Clone) */
|
|
143
|
+
enum Status {
|
|
144
|
+
Active = 'active',
|
|
145
|
+
Inactive = 'inactive'
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
**After:**
|
|
149
|
+
```
|
|
150
|
+
enum Status {
|
|
151
|
+
Active = 'active',
|
|
152
|
+
Inactive = 'inactive'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export namespace Status {
|
|
156
|
+
export function clone(value: Status): Status {
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
``` ```
|
|
91
161
|
const original = Status.Active;
|
|
92
162
|
const copy = Status.clone(original);
|
|
93
163
|
|
|
94
164
|
console.log(copy); // "active"
|
|
95
165
|
console.log(original === copy); // true (same primitive value)
|
|
166
|
+
``` ## Type Alias Support
|
|
167
|
+
Clone works with type aliases. For object types, a shallow copy is created using spread:
|
|
168
|
+
**Before:**
|
|
96
169
|
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
```
|
|
170
|
+
/** @derive(Clone) */
|
|
171
|
+
type Point = {
|
|
172
|
+
x: number;
|
|
173
|
+
y: number;
|
|
174
|
+
};
|
|
175
|
+
```
|
|
176
|
+
**After:**
|
|
177
|
+
```
|
|
178
|
+
type Point = {
|
|
179
|
+
x: number;
|
|
180
|
+
y: number;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export namespace Point {
|
|
184
|
+
export function clone(value: Point): Point {
|
|
185
|
+
return { x: value.x, y: value.y };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
``` ```
|
|
105
189
|
const original: Point = { x: 10, y: 20 };
|
|
106
190
|
const copy = Point.clone(original);
|
|
107
191
|
|
|
108
192
|
console.log(copy.x, copy.y); // 10, 20
|
|
109
193
|
console.log(original === copy); // false (different objects)
|
|
194
|
+
``` For union types, the value is returned as-is (unions of primitives don't need cloning):
|
|
195
|
+
**Source:**
|
|
110
196
|
```
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
<InteractiveMacro code={`/** @derive(Clone) */
|
|
115
|
-
type ApiStatus = "loading" | "success" | "error";`} />
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
197
|
+
/** @derive(Clone) */
|
|
198
|
+
type ApiStatus = "loading" | "success" | "error";
|
|
199
|
+
``` ```
|
|
118
200
|
const status: ApiStatus = "success";
|
|
119
201
|
const copy = ApiStatus.clone(status);
|
|
120
202
|
console.log(copy); // "success"
|