bunshin-clone 1.0.7 → 1.0.9

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 CHANGED
@@ -2,14 +2,28 @@
2
2
 
3
3
  High-performance deep clone utility with descriptor support. Supports circular references 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
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
10
 
11
11
  ---
12
12
 
13
+ ## Install
14
+
15
+ ```bash
16
+ npm i bunshin-clone
17
+ ```
18
+
19
+ ```ts
20
+ // npm
21
+ import bunshinClone from 'bunshin-clone';
22
+
23
+ // CDN
24
+ import bunshinClone from 'https://cdn.jsdelivr.net/npm/bunshin-clone/+esm';
25
+ ```
26
+
13
27
  ## Usage
14
28
 
15
29
  ```ts
@@ -36,15 +50,15 @@ bunshinClone(target, options)
36
50
  ## Options
37
51
 
38
52
  ```ts
39
- interface BunshinCloneOptions {
40
- preserveDescriptors?: boolean;
41
- strictDescriptors?: boolean;
53
+ BunshinCloneOptions {
54
+ preserveDescriptors: false;
55
+ strictDescriptors: false;
42
56
  }
43
57
  ```
44
58
 
45
- ### preserveDescriptors
59
+ **preserveDescriptors**
46
60
 
47
- * `false` (default): use standard merge (faster, ignores property descriptors)
61
+ * `false`: use standard merge (faster, ignores property descriptors)
48
62
  * `true`: preserve property descriptors (getters/setters, etc.)
49
63
 
50
64
  <details>
@@ -64,9 +78,9 @@ Object.getOwnPropertyDescriptor(result, 'x')?.get;
64
78
  ```
65
79
  </details>
66
80
 
67
- ### strictDescriptors
81
+ **strictDescriptors**
68
82
 
69
- * `false` (default): skip incompatible descriptors
83
+ * `false`: skip incompatible descriptors
70
84
  * `true`: throw if descriptor cannot be merged (e.g. non-configurable or non-writable)
71
85
 
72
86
  <details>
@@ -80,6 +94,8 @@ bunshinClone(obj, { strictDescriptors: true });
80
94
  ```
81
95
  </details>
82
96
 
97
+ ---
98
+
83
99
  ## Supported Types
84
100
 
85
101
  bunshin-clone correctly handles:
package/dist/index.cjs CHANGED
@@ -3,7 +3,6 @@
3
3
  // src/index.ts
4
4
  var EMPTY_OPTIONS = {};
5
5
  var { hasOwnProperty: HAS_OWN } = Object.prototype;
6
- var { toString: OBJECT_TO_STRING } = Object.prototype;
7
6
  function bunshinClone(source, options) {
8
7
  return clone(source, options ?? EMPTY_OPTIONS, /* @__PURE__ */ new WeakMap());
9
8
  }
@@ -85,9 +84,7 @@ function clone(node, options, ref) {
85
84
  }
86
85
  }
87
86
  if (node instanceof Error || typeof DOMException !== "undefined" && node instanceof DOMException) {
88
- const result = cloneError(node, options, ref);
89
- ref.set(node, result);
90
- return result;
87
+ return cloneError(node, options, ref);
91
88
  }
92
89
  if (typeof Blob !== "undefined" && node instanceof Blob) {
93
90
  const result = node.slice(0, node.size, node.type);
@@ -120,10 +117,18 @@ function clone(node, options, ref) {
120
117
  return node;
121
118
  }
122
119
  function cloneError(value, options, ref) {
120
+ if (value instanceof DOMException) {
121
+ const result2 = new DOMException(value.message, value.name);
122
+ ref.set(value, result2);
123
+ return result2;
124
+ }
123
125
  const name = value.name || "Error";
124
126
  const message = value.message || "";
125
127
  let result;
126
128
  switch (name) {
129
+ case "EvalError":
130
+ result = new EvalError(message);
131
+ break;
127
132
  case "RangeError":
128
133
  result = new RangeError(message);
129
134
  break;
@@ -136,36 +141,32 @@ function cloneError(value, options, ref) {
136
141
  case "TypeError":
137
142
  result = new TypeError(message);
138
143
  break;
144
+ case "URIError":
145
+ result = new URIError(message);
146
+ break;
139
147
  default:
140
148
  result = new Error(message);
141
149
  result.name = name;
142
150
  }
143
- if (!options.preserveDescriptors && "cause" in value) {
144
- const cause = value.cause;
145
- if (cause !== void 0) {
146
- result.cause = clone(cause, options, ref);
147
- }
151
+ ref.set(value, result);
152
+ if ("cause" in value && value.cause !== void 0) {
153
+ result.cause = clone(value.cause, options, ref);
148
154
  }
149
155
  if (value.stack) {
150
156
  result.stack = value.stack;
151
157
  }
152
- for (const key of Object.keys(value)) {
153
- if (key === "name" || key === "message" || key === "stack") {
154
- continue;
155
- }
156
- result[key] = value[key];
157
- }
158
158
  return result;
159
159
  }
160
160
  function cloneWithDescriptors(node, options, ref) {
161
161
  const result = Object.create(Object.getPrototypeOf(node));
162
162
  ref.set(node, result);
163
163
  const descs = Object.getOwnPropertyDescriptors(node);
164
- const keys = Reflect.ownKeys(descs);
165
- for (let i = 0, l = keys.length; i < l; i++) {
166
- const key = keys[i];
164
+ forEachOwnKey(descs, (key) => {
165
+ if (!key) {
166
+ return;
167
+ }
167
168
  if (isUnsafeKey(key)) {
168
- continue;
169
+ return;
169
170
  }
170
171
  const desc = { ...descs[key] };
171
172
  if ("value" in desc) {
@@ -178,14 +179,31 @@ function cloneWithDescriptors(node, options, ref) {
178
179
  throw error;
179
180
  }
180
181
  }
181
- }
182
+ });
182
183
  return result;
183
184
  }
185
+ function forEachOwnKey(object, callback) {
186
+ for (const key of Object.keys(object)) {
187
+ callback(key);
188
+ }
189
+ const symbols = Object.getOwnPropertySymbols(object);
190
+ for (let i = 0, l = symbols.length; i < l; i++) {
191
+ const symbol = symbols[i];
192
+ if (!symbol) {
193
+ continue;
194
+ }
195
+ callback(symbol);
196
+ }
197
+ }
184
198
  function isObject(value) {
185
199
  return typeof value === "object" && value !== null;
186
200
  }
187
201
  function isPlainObject(value) {
188
- return OBJECT_TO_STRING.call(value) === "[object Object]";
202
+ if (value === null || typeof value !== "object") {
203
+ return false;
204
+ }
205
+ const proto = Object.getPrototypeOf(value);
206
+ return proto === Object.prototype || proto === null;
189
207
  }
190
208
  function isUnsafeKey(key) {
191
209
  return typeof key === "string" && (key === "__proto__" || key === "prototype" || key === "constructor");
@@ -195,7 +213,7 @@ function isUnsafeKey(key) {
195
213
  * High-performance deep clone utility with descriptor support.
196
214
  * Supports circular ref and complex built-in types.
197
215
  *
198
- * @version 1.0.7
216
+ * @version 1.0.9
199
217
  * @author Yusuke Kamiyamane
200
218
  * @license MIT
201
219
  * @copyright Copyright (c) 2026 Yusuke Kamiyamane
package/dist/index.d.cts CHANGED
@@ -3,7 +3,7 @@
3
3
  * High-performance deep clone utility with descriptor support.
4
4
  * Supports circular ref and complex built-in types.
5
5
  *
6
- * @version 1.0.7
6
+ * @version 1.0.9
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) 2026 Yusuke Kamiyamane
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * High-performance deep clone utility with descriptor support.
4
4
  * Supports circular ref and complex built-in types.
5
5
  *
6
- * @version 1.0.7
6
+ * @version 1.0.9
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) 2026 Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  // src/index.ts
2
2
  var EMPTY_OPTIONS = {};
3
3
  var { hasOwnProperty: HAS_OWN } = Object.prototype;
4
- var { toString: OBJECT_TO_STRING } = Object.prototype;
5
4
  function bunshinClone(source, options) {
6
5
  return clone(source, options ?? EMPTY_OPTIONS, /* @__PURE__ */ new WeakMap());
7
6
  }
@@ -83,9 +82,7 @@ function clone(node, options, ref) {
83
82
  }
84
83
  }
85
84
  if (node instanceof Error || typeof DOMException !== "undefined" && node instanceof DOMException) {
86
- const result = cloneError(node, options, ref);
87
- ref.set(node, result);
88
- return result;
85
+ return cloneError(node, options, ref);
89
86
  }
90
87
  if (typeof Blob !== "undefined" && node instanceof Blob) {
91
88
  const result = node.slice(0, node.size, node.type);
@@ -118,10 +115,18 @@ function clone(node, options, ref) {
118
115
  return node;
119
116
  }
120
117
  function cloneError(value, options, ref) {
118
+ if (value instanceof DOMException) {
119
+ const result2 = new DOMException(value.message, value.name);
120
+ ref.set(value, result2);
121
+ return result2;
122
+ }
121
123
  const name = value.name || "Error";
122
124
  const message = value.message || "";
123
125
  let result;
124
126
  switch (name) {
127
+ case "EvalError":
128
+ result = new EvalError(message);
129
+ break;
125
130
  case "RangeError":
126
131
  result = new RangeError(message);
127
132
  break;
@@ -134,36 +139,32 @@ function cloneError(value, options, ref) {
134
139
  case "TypeError":
135
140
  result = new TypeError(message);
136
141
  break;
142
+ case "URIError":
143
+ result = new URIError(message);
144
+ break;
137
145
  default:
138
146
  result = new Error(message);
139
147
  result.name = name;
140
148
  }
141
- if (!options.preserveDescriptors && "cause" in value) {
142
- const cause = value.cause;
143
- if (cause !== void 0) {
144
- result.cause = clone(cause, options, ref);
145
- }
149
+ ref.set(value, result);
150
+ if ("cause" in value && value.cause !== void 0) {
151
+ result.cause = clone(value.cause, options, ref);
146
152
  }
147
153
  if (value.stack) {
148
154
  result.stack = value.stack;
149
155
  }
150
- for (const key of Object.keys(value)) {
151
- if (key === "name" || key === "message" || key === "stack") {
152
- continue;
153
- }
154
- result[key] = value[key];
155
- }
156
156
  return result;
157
157
  }
158
158
  function cloneWithDescriptors(node, options, ref) {
159
159
  const result = Object.create(Object.getPrototypeOf(node));
160
160
  ref.set(node, result);
161
161
  const descs = Object.getOwnPropertyDescriptors(node);
162
- const keys = Reflect.ownKeys(descs);
163
- for (let i = 0, l = keys.length; i < l; i++) {
164
- const key = keys[i];
162
+ forEachOwnKey(descs, (key) => {
163
+ if (!key) {
164
+ return;
165
+ }
165
166
  if (isUnsafeKey(key)) {
166
- continue;
167
+ return;
167
168
  }
168
169
  const desc = { ...descs[key] };
169
170
  if ("value" in desc) {
@@ -176,14 +177,31 @@ function cloneWithDescriptors(node, options, ref) {
176
177
  throw error;
177
178
  }
178
179
  }
179
- }
180
+ });
180
181
  return result;
181
182
  }
183
+ function forEachOwnKey(object, callback) {
184
+ for (const key of Object.keys(object)) {
185
+ callback(key);
186
+ }
187
+ const symbols = Object.getOwnPropertySymbols(object);
188
+ for (let i = 0, l = symbols.length; i < l; i++) {
189
+ const symbol = symbols[i];
190
+ if (!symbol) {
191
+ continue;
192
+ }
193
+ callback(symbol);
194
+ }
195
+ }
182
196
  function isObject(value) {
183
197
  return typeof value === "object" && value !== null;
184
198
  }
185
199
  function isPlainObject(value) {
186
- return OBJECT_TO_STRING.call(value) === "[object Object]";
200
+ if (value === null || typeof value !== "object") {
201
+ return false;
202
+ }
203
+ const proto = Object.getPrototypeOf(value);
204
+ return proto === Object.prototype || proto === null;
187
205
  }
188
206
  function isUnsafeKey(key) {
189
207
  return typeof key === "string" && (key === "__proto__" || key === "prototype" || key === "constructor");
@@ -193,7 +211,7 @@ function isUnsafeKey(key) {
193
211
  * High-performance deep clone utility with descriptor support.
194
212
  * Supports circular ref and complex built-in types.
195
213
  *
196
- * @version 1.0.7
214
+ * @version 1.0.9
197
215
  * @author Yusuke Kamiyamane
198
216
  * @license MIT
199
217
  * @copyright Copyright (c) 2026 Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bunshin-clone",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "High-performance deep clone utility with descriptor support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",