bunshin-clone 1.2.0 → 1.2.2
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 +23 -56
- package/dist/index.cjs +26 -29
- package/dist/index.d.cts +3 -5
- package/dist/index.d.ts +3 -5
- package/dist/index.js +26 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,14 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
High-performance deep clone utility with descriptor support. Handles circular ref and complex built-in types.
|
|
4
4
|
|
|
5
|
-
* Fast (no unnecessary overhead)
|
|
6
|
-
* Deep clone (no structural sharing)
|
|
7
|
-
* Supports circular ref
|
|
8
|
-
* Handles Map, Set, Array, TypedArray, Date, RegExp, etc.
|
|
9
|
-
* Optional descriptor preservation
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
5
|
## Install
|
|
14
6
|
|
|
15
7
|
```bash
|
|
@@ -28,7 +20,7 @@ import bunshinClone from 'https://cdn.jsdelivr.net/npm/bunshin-clone/+esm';
|
|
|
28
20
|
import bunshinClone from 'https://unpkg.com/bunshin-clone/dist/index.js';
|
|
29
21
|
```
|
|
30
22
|
|
|
31
|
-
##
|
|
23
|
+
## 📦 APIs
|
|
32
24
|
|
|
33
25
|
```ts
|
|
34
26
|
bunshinClone(source, options);
|
|
@@ -38,7 +30,7 @@ bunshinClone(source, options);
|
|
|
38
30
|
// options (optional): BunshinCloneOptions
|
|
39
31
|
```
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
## 🪄 Options
|
|
42
34
|
|
|
43
35
|
```ts
|
|
44
36
|
interface BunshinCloneOptions {
|
|
@@ -47,47 +39,20 @@ interface BunshinCloneOptions {
|
|
|
47
39
|
}
|
|
48
40
|
```
|
|
49
41
|
|
|
50
|
-
|
|
42
|
+
### `preserveDescriptors`
|
|
51
43
|
|
|
52
|
-
|
|
53
|
-
* `true`: preserve property descriptors (getters/setters, etc.)
|
|
44
|
+
If `true`, preserves property descriptors (getters/setters, etc.).
|
|
54
45
|
|
|
55
|
-
|
|
56
|
-
<summary>Example</summary>
|
|
46
|
+
### `strictDescriptors`
|
|
57
47
|
|
|
58
|
-
|
|
59
|
-
const source = {};
|
|
60
|
-
Object.defineProperty(source, 'x', {
|
|
61
|
-
get: () => 42,
|
|
62
|
-
enumerable: true,
|
|
63
|
-
});
|
|
48
|
+
If `true`, throws if descriptor cannot be merged (e.g. non-configurable or non-writable)
|
|
64
49
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Object.getOwnPropertyDescriptor(result, 'x')?.get;
|
|
68
|
-
// => function
|
|
69
|
-
```
|
|
70
|
-
</details>
|
|
71
|
-
|
|
72
|
-
**strictDescriptors**
|
|
73
|
-
|
|
74
|
-
* `false`: skip incompatible descriptors
|
|
75
|
-
* `true`: throw if descriptor cannot be merged (e.g. non-configurable or non-writable)
|
|
50
|
+
## 📖 Details
|
|
76
51
|
|
|
77
52
|
<details>
|
|
78
|
-
<summary>
|
|
53
|
+
<summary>Read more</summary>
|
|
79
54
|
|
|
80
|
-
|
|
81
|
-
Object.freeze(obj);
|
|
82
|
-
|
|
83
|
-
bunshinClone(obj, { strictDescriptors: true });
|
|
84
|
-
// => may throw TypeError
|
|
85
|
-
```
|
|
86
|
-
</details>
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## Example
|
|
55
|
+
### Example
|
|
91
56
|
|
|
92
57
|
```ts
|
|
93
58
|
const source = { foo: 1, nested: { x: 1 } };
|
|
@@ -101,7 +66,7 @@ console.log(result === source); // false
|
|
|
101
66
|
console.log(result.nested === source.nested); // false
|
|
102
67
|
```
|
|
103
68
|
|
|
104
|
-
|
|
69
|
+
### Supported Types
|
|
105
70
|
|
|
106
71
|
bunshin-clone correctly handles:
|
|
107
72
|
|
|
@@ -120,7 +85,7 @@ bunshin-clone correctly handles:
|
|
|
120
85
|
* URL
|
|
121
86
|
* URLSearchParams
|
|
122
87
|
|
|
123
|
-
|
|
88
|
+
### Circular ref
|
|
124
89
|
|
|
125
90
|
```ts
|
|
126
91
|
const a: any = { x: 1 };
|
|
@@ -131,9 +96,9 @@ const result = bunshinClone(a);
|
|
|
131
96
|
result.self === result; // true
|
|
132
97
|
```
|
|
133
98
|
|
|
134
|
-
|
|
99
|
+
### Descriptor Behavior
|
|
135
100
|
|
|
136
|
-
|
|
101
|
+
#### Default (fast path)
|
|
137
102
|
|
|
138
103
|
```ts
|
|
139
104
|
const source = {
|
|
@@ -148,7 +113,7 @@ result.x; // 42
|
|
|
148
113
|
// getter is NOT preserved
|
|
149
114
|
```
|
|
150
115
|
|
|
151
|
-
|
|
116
|
+
#### preserveDescriptors: true
|
|
152
117
|
|
|
153
118
|
```ts
|
|
154
119
|
const source = {};
|
|
@@ -165,7 +130,7 @@ Object.getOwnPropertyDescriptor(result, 'x')?.get;
|
|
|
165
130
|
// => preserved
|
|
166
131
|
```
|
|
167
132
|
|
|
168
|
-
|
|
133
|
+
#### Unsupported / Pass-through Types
|
|
169
134
|
|
|
170
135
|
Some values are returned as-is:
|
|
171
136
|
|
|
@@ -180,9 +145,9 @@ const fn = () => {};
|
|
|
180
145
|
bunshinClone(fn) === fn; // true
|
|
181
146
|
```
|
|
182
147
|
|
|
183
|
-
|
|
148
|
+
### Design Notes
|
|
184
149
|
|
|
185
|
-
|
|
150
|
+
#### Deep clone (no structural sharing)
|
|
186
151
|
|
|
187
152
|
Unlike merge utilities, bunshin-clone always produces a new structure:
|
|
188
153
|
|
|
@@ -195,12 +160,12 @@ result !== source; // true
|
|
|
195
160
|
result.a !== source.a; // true
|
|
196
161
|
```
|
|
197
162
|
|
|
198
|
-
|
|
163
|
+
#### Getter / Setter behavior
|
|
199
164
|
|
|
200
165
|
* Default: evaluated and converted to value
|
|
201
166
|
* preserveDescriptors: preserved as-is
|
|
202
167
|
|
|
203
|
-
|
|
168
|
+
#### Descriptor safety
|
|
204
169
|
|
|
205
170
|
When `preserveDescriptors` is enabled:
|
|
206
171
|
|
|
@@ -208,14 +173,14 @@ When `preserveDescriptors` is enabled:
|
|
|
208
173
|
* original object is never mutated
|
|
209
174
|
* errors are controlled via `strictDescriptors`
|
|
210
175
|
|
|
211
|
-
|
|
176
|
+
### Performance
|
|
212
177
|
|
|
213
178
|
* No proxy / no diffing
|
|
214
179
|
* Minimal branching
|
|
215
180
|
* Fast path for plain objects and arrays
|
|
216
181
|
* Competitive with structuredClone in many cases
|
|
217
182
|
|
|
218
|
-
|
|
183
|
+
### Comparison
|
|
219
184
|
|
|
220
185
|
| Feature | Bunshin Clone | structuredClone | lodash.clonedeep |
|
|
221
186
|
|---------------------|--------------|----------------|------------------|
|
|
@@ -227,3 +192,5 @@ When `preserveDescriptors` is enabled:
|
|
|
227
192
|
| Prototype preserved | ✅ | ❌ | ⚠️ |
|
|
228
193
|
| Custom control | ✅ | ❌ | ❌ |
|
|
229
194
|
| Performance | ⚡ fast | ⚡ fast | 🐢 slower |
|
|
195
|
+
|
|
196
|
+
</details>
|
package/dist/index.cjs
CHANGED
|
@@ -1,34 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
3
|
// src/index.ts
|
|
6
4
|
var EMPTY_OPTIONS = {};
|
|
7
5
|
var { hasOwnProperty: HAS_OWN } = Object.prototype;
|
|
8
|
-
function bunshinClone(source, options) {
|
|
9
|
-
return clone(source, options ?? EMPTY_OPTIONS, /* @__PURE__ */ new WeakMap());
|
|
10
|
-
}
|
|
11
|
-
function cloneWithDescriptors(node, options, refs) {
|
|
12
|
-
const result = Object.create(Object.getPrototypeOf(node));
|
|
13
|
-
refs.set(node, result);
|
|
14
|
-
const descs = Object.getOwnPropertyDescriptors(node);
|
|
15
|
-
forEachOwnKey(descs, (key) => {
|
|
16
|
-
if (isUnsafeKey(key)) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const desc = { ...descs[key] };
|
|
20
|
-
if ("value" in desc) {
|
|
21
|
-
desc.value = clone(desc.value, options, refs);
|
|
22
|
-
}
|
|
23
|
-
try {
|
|
24
|
-
Object.defineProperty(result, key, desc);
|
|
25
|
-
} catch (error) {
|
|
26
|
-
if (options.strictDescriptors) {
|
|
27
|
-
throw error;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
return result;
|
|
6
|
+
function bunshinClone(source, options, refs) {
|
|
7
|
+
return clone(source, options ?? EMPTY_OPTIONS, refs ?? /* @__PURE__ */ new WeakMap());
|
|
32
8
|
}
|
|
33
9
|
function clone(node, options, refs) {
|
|
34
10
|
if (!isObject(node)) {
|
|
@@ -184,6 +160,28 @@ function cloneError(value, options, refs) {
|
|
|
184
160
|
}
|
|
185
161
|
return result;
|
|
186
162
|
}
|
|
163
|
+
function cloneWithDescriptors(node, options, refs) {
|
|
164
|
+
const result = Object.create(Object.getPrototypeOf(node));
|
|
165
|
+
refs.set(node, result);
|
|
166
|
+
const descs = Object.getOwnPropertyDescriptors(node);
|
|
167
|
+
forEachOwnKey(descs, (key) => {
|
|
168
|
+
if (isUnsafeKey(key)) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const desc = { ...descs[key] };
|
|
172
|
+
if ("value" in desc) {
|
|
173
|
+
desc.value = clone(desc.value, options, refs);
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
Object.defineProperty(result, key, desc);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (options.strictDescriptors) {
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
187
185
|
function forEachOwnKey(object, fn) {
|
|
188
186
|
for (const key of Object.keys(object)) {
|
|
189
187
|
fn(key);
|
|
@@ -211,12 +209,11 @@ function isUnsafeKey(key) {
|
|
|
211
209
|
* High-performance deep clone utility with descriptor support.
|
|
212
210
|
* Handles circular ref and complex built-in types.
|
|
213
211
|
*
|
|
214
|
-
* @version 1.2.
|
|
212
|
+
* @version 1.2.2
|
|
215
213
|
* @author Yusuke Kamiyamane
|
|
216
214
|
* @license MIT
|
|
217
215
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
218
216
|
* @see {@link https://github.com/y14e/bunshin-clone}
|
|
219
217
|
*/
|
|
220
218
|
|
|
221
|
-
exports
|
|
222
|
-
exports.default = bunshinClone;
|
|
219
|
+
module.exports = bunshinClone;
|
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* High-performance deep clone utility with descriptor support.
|
|
4
4
|
* Handles circular ref and complex built-in types.
|
|
5
5
|
*
|
|
6
|
-
* @version 1.2.
|
|
6
|
+
* @version 1.2.2
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -13,9 +13,7 @@ interface BunshinCloneOptions {
|
|
|
13
13
|
readonly preserveDescriptors?: boolean;
|
|
14
14
|
readonly strictDescriptors?: boolean;
|
|
15
15
|
}
|
|
16
|
-
type Object$1 = Record<PropertyKey, unknown>;
|
|
17
16
|
type Refs = WeakMap<object, unknown>;
|
|
18
|
-
declare function bunshinClone<T>(source: T, options?: BunshinCloneOptions): T;
|
|
19
|
-
declare function cloneWithDescriptors<T extends Object$1>(node: T, options: BunshinCloneOptions, refs: Refs): T;
|
|
17
|
+
declare function bunshinClone<T>(source: T, options?: BunshinCloneOptions, refs?: Refs): T;
|
|
20
18
|
|
|
21
|
-
export { type BunshinCloneOptions,
|
|
19
|
+
export { type BunshinCloneOptions, bunshinClone as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* High-performance deep clone utility with descriptor support.
|
|
4
4
|
* Handles circular ref and complex built-in types.
|
|
5
5
|
*
|
|
6
|
-
* @version 1.2.
|
|
6
|
+
* @version 1.2.2
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -13,9 +13,7 @@ interface BunshinCloneOptions {
|
|
|
13
13
|
readonly preserveDescriptors?: boolean;
|
|
14
14
|
readonly strictDescriptors?: boolean;
|
|
15
15
|
}
|
|
16
|
-
type Object$1 = Record<PropertyKey, unknown>;
|
|
17
16
|
type Refs = WeakMap<object, unknown>;
|
|
18
|
-
declare function bunshinClone<T>(source: T, options?: BunshinCloneOptions): T;
|
|
19
|
-
declare function cloneWithDescriptors<T extends Object$1>(node: T, options: BunshinCloneOptions, refs: Refs): T;
|
|
17
|
+
declare function bunshinClone<T>(source: T, options?: BunshinCloneOptions, refs?: Refs): T;
|
|
20
18
|
|
|
21
|
-
export { type BunshinCloneOptions,
|
|
19
|
+
export { type BunshinCloneOptions, bunshinClone as default };
|
package/dist/index.js
CHANGED
|
@@ -1,30 +1,8 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
var EMPTY_OPTIONS = {};
|
|
3
3
|
var { hasOwnProperty: HAS_OWN } = Object.prototype;
|
|
4
|
-
function bunshinClone(source, options) {
|
|
5
|
-
return clone(source, options ?? EMPTY_OPTIONS, /* @__PURE__ */ new WeakMap());
|
|
6
|
-
}
|
|
7
|
-
function cloneWithDescriptors(node, options, refs) {
|
|
8
|
-
const result = Object.create(Object.getPrototypeOf(node));
|
|
9
|
-
refs.set(node, result);
|
|
10
|
-
const descs = Object.getOwnPropertyDescriptors(node);
|
|
11
|
-
forEachOwnKey(descs, (key) => {
|
|
12
|
-
if (isUnsafeKey(key)) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const desc = { ...descs[key] };
|
|
16
|
-
if ("value" in desc) {
|
|
17
|
-
desc.value = clone(desc.value, options, refs);
|
|
18
|
-
}
|
|
19
|
-
try {
|
|
20
|
-
Object.defineProperty(result, key, desc);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
if (options.strictDescriptors) {
|
|
23
|
-
throw error;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
return result;
|
|
4
|
+
function bunshinClone(source, options, refs) {
|
|
5
|
+
return clone(source, options ?? EMPTY_OPTIONS, refs ?? /* @__PURE__ */ new WeakMap());
|
|
28
6
|
}
|
|
29
7
|
function clone(node, options, refs) {
|
|
30
8
|
if (!isObject(node)) {
|
|
@@ -180,6 +158,28 @@ function cloneError(value, options, refs) {
|
|
|
180
158
|
}
|
|
181
159
|
return result;
|
|
182
160
|
}
|
|
161
|
+
function cloneWithDescriptors(node, options, refs) {
|
|
162
|
+
const result = Object.create(Object.getPrototypeOf(node));
|
|
163
|
+
refs.set(node, result);
|
|
164
|
+
const descs = Object.getOwnPropertyDescriptors(node);
|
|
165
|
+
forEachOwnKey(descs, (key) => {
|
|
166
|
+
if (isUnsafeKey(key)) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const desc = { ...descs[key] };
|
|
170
|
+
if ("value" in desc) {
|
|
171
|
+
desc.value = clone(desc.value, options, refs);
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
Object.defineProperty(result, key, desc);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (options.strictDescriptors) {
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
183
|
function forEachOwnKey(object, fn) {
|
|
184
184
|
for (const key of Object.keys(object)) {
|
|
185
185
|
fn(key);
|
|
@@ -207,11 +207,11 @@ function isUnsafeKey(key) {
|
|
|
207
207
|
* High-performance deep clone utility with descriptor support.
|
|
208
208
|
* Handles circular ref and complex built-in types.
|
|
209
209
|
*
|
|
210
|
-
* @version 1.2.
|
|
210
|
+
* @version 1.2.2
|
|
211
211
|
* @author Yusuke Kamiyamane
|
|
212
212
|
* @license MIT
|
|
213
213
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
214
214
|
* @see {@link https://github.com/y14e/bunshin-clone}
|
|
215
215
|
*/
|
|
216
216
|
|
|
217
|
-
export {
|
|
217
|
+
export { bunshinClone as default };
|