bunshin-clone 1.7.1 → 1.8.0

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
@@ -36,6 +36,7 @@ bunshinClone<T>(value, options);
36
36
  interface BunshinCloneOptions {
37
37
  preserveBufferSharing: boolean; // default: false
38
38
  preserveDescriptors: boolean; // default: false
39
+ preserveSymbolKeys: boolean; // default: false
39
40
  strictDescriptors: boolean; // default: false
40
41
  }
41
42
  ```
@@ -48,9 +49,13 @@ If `true`, preserves shared backing buffers between TypedArray and DataView inst
48
49
 
49
50
  If `true`, preserves property descriptors (getters/setters, etc.).
50
51
 
52
+ ### `preserveSymbolKeys`
53
+
54
+ If `true`, preserves symbol keys (slower).
55
+
51
56
  ### `strictDescriptors`
52
57
 
53
- If `true`, throws if descriptor cannot be merged (e.g. non-configurable or non-writable)
58
+ If `true`, throws if descriptor cannot be merged (e.g. non-configurable or non-writable).
54
59
 
55
60
  ## 📖 Details
56
61
 
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  var EMPTY_OPTIONS = {};
5
- var { propertyIsEnumerable: IS_ENUMERABLE } = Object.prototype;
5
+ var { hasOwnProperty: HAS_OWN, propertyIsEnumerable: IS_ENUMERABLE } = Object.prototype;
6
6
  function bunshinClone(value, options = EMPTY_OPTIONS, refs = /* @__PURE__ */ new WeakMap()) {
7
7
  return clone(value, resolveOptions(options), refs);
8
8
  }
@@ -18,7 +18,7 @@ function clone(value, settings, refs) {
18
18
  return cloneWithDescriptors(value, settings, refs);
19
19
  }
20
20
  if (Array.isArray(value)) {
21
- if (isShallowClonableArray(value)) {
21
+ if (isShallowArray(value)) {
22
22
  const result2 = value.slice();
23
23
  refs.set(value, result2);
24
24
  return result2;
@@ -34,11 +34,20 @@ function clone(value, settings, refs) {
34
34
  if (isPlainObject(value)) {
35
35
  const result = Object.create(Object.getPrototypeOf(value));
36
36
  refs.set(value, result);
37
- for (const key of Reflect.ownKeys(value)) {
38
- if (isUnsafeKey(key) || !IS_ENUMERABLE.call(value, key)) {
39
- continue;
37
+ if (!settings.preserveSymbolKeys) {
38
+ for (const key in value) {
39
+ if (isUnsafeKey(key) || !HAS_OWN.call(value, key)) {
40
+ continue;
41
+ }
42
+ result[key] = clone(value[key], settings, refs);
43
+ }
44
+ } else {
45
+ for (const key of Reflect.ownKeys(value)) {
46
+ if (isUnsafeKey(key) || !IS_ENUMERABLE.call(value, key)) {
47
+ continue;
48
+ }
49
+ result[key] = clone(value[key], settings, refs);
40
50
  }
41
- result[key] = clone(value[key], settings, refs);
42
51
  }
43
52
  return result;
44
53
  }
@@ -209,14 +218,6 @@ function createErrorInstance(error, settings, refs) {
209
218
  result.name = name;
210
219
  return result;
211
220
  }
212
- function isShallowClonableArray(array) {
213
- for (let i = 0, l = array.length; i < l; i++) {
214
- if (isObject(array[i])) {
215
- return false;
216
- }
217
- }
218
- return true;
219
- }
220
221
  function forEachOwnKey(object, callback) {
221
222
  for (const key of Object.keys(object)) {
222
223
  callback(key);
@@ -235,6 +236,14 @@ function isPlainObject(value) {
235
236
  const proto = Object.getPrototypeOf(value);
236
237
  return proto === Object.prototype || proto === null;
237
238
  }
239
+ function isShallowArray(array) {
240
+ for (let i = 0, l = array.length; i < l; i++) {
241
+ if (isObject(array[i])) {
242
+ return false;
243
+ }
244
+ }
245
+ return true;
246
+ }
238
247
  function isUnsafeKey(key) {
239
248
  return typeof key === "string" && (key === "__proto__" || key === "prototype" || key === "constructor");
240
249
  }
@@ -242,8 +251,13 @@ function resolveOptions(options) {
242
251
  let {
243
252
  preserveBufferSharing = false,
244
253
  preserveDescriptors = false,
245
- strictDescriptors = false
254
+ strictDescriptors = false,
255
+ preserveSymbolKeys = false
246
256
  } = options;
257
+ if (typeof preserveSymbolKeys !== "boolean") {
258
+ console.warn("Invalid preserveSymbolKeys option. Fallback: false.");
259
+ preserveSymbolKeys = false;
260
+ }
247
261
  if (typeof preserveBufferSharing !== "boolean") {
248
262
  console.warn("Invalid preserveBufferSharing option. Fallback: false.");
249
263
  preserveBufferSharing = false;
@@ -256,11 +270,17 @@ function resolveOptions(options) {
256
270
  console.warn("Invalid strictDescriptors option. Fallback: false.");
257
271
  strictDescriptors = false;
258
272
  }
259
- return { preserveBufferSharing, preserveDescriptors, strictDescriptors };
273
+ return {
274
+ preserveBufferSharing,
275
+ preserveDescriptors,
276
+ preserveSymbolKeys,
277
+ strictDescriptors
278
+ };
260
279
  }
261
280
 
262
281
  exports.bunshinClone = bunshinClone;
263
282
  exports.forEachOwnKey = forEachOwnKey;
264
283
  exports.isObject = isObject;
265
284
  exports.isPlainObject = isPlainObject;
285
+ exports.isShallowArray = isShallowArray;
266
286
  exports.isUnsafeKey = isUnsafeKey;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  interface BunshinCloneOptions {
2
2
  preserveBufferSharing: boolean;
3
3
  preserveDescriptors: boolean;
4
+ preserveSymbolKeys: boolean;
4
5
  strictDescriptors: boolean;
5
6
  }
6
7
  type PlainObject = Record<PropertyKey, unknown>;
@@ -9,6 +10,7 @@ declare function bunshinClone<T>(value: T, options?: Partial<BunshinCloneOptions
9
10
  declare function forEachOwnKey(object: PlainObject, callback: (key: string | symbol) => void): void;
10
11
  declare function isObject(value: unknown): value is object;
11
12
  declare function isPlainObject(value: unknown): value is PlainObject;
13
+ declare function isShallowArray(array: unknown[]): boolean;
12
14
  declare function isUnsafeKey(key: PropertyKey): boolean;
13
15
 
14
- export { type BunshinCloneOptions, bunshinClone, forEachOwnKey, isObject, isPlainObject, isUnsafeKey };
16
+ export { type BunshinCloneOptions, bunshinClone, forEachOwnKey, isObject, isPlainObject, isShallowArray, isUnsafeKey };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  interface BunshinCloneOptions {
2
2
  preserveBufferSharing: boolean;
3
3
  preserveDescriptors: boolean;
4
+ preserveSymbolKeys: boolean;
4
5
  strictDescriptors: boolean;
5
6
  }
6
7
  type PlainObject = Record<PropertyKey, unknown>;
@@ -9,6 +10,7 @@ declare function bunshinClone<T>(value: T, options?: Partial<BunshinCloneOptions
9
10
  declare function forEachOwnKey(object: PlainObject, callback: (key: string | symbol) => void): void;
10
11
  declare function isObject(value: unknown): value is object;
11
12
  declare function isPlainObject(value: unknown): value is PlainObject;
13
+ declare function isShallowArray(array: unknown[]): boolean;
12
14
  declare function isUnsafeKey(key: PropertyKey): boolean;
13
15
 
14
- export { type BunshinCloneOptions, bunshinClone, forEachOwnKey, isObject, isPlainObject, isUnsafeKey };
16
+ export { type BunshinCloneOptions, bunshinClone, forEachOwnKey, isObject, isPlainObject, isShallowArray, isUnsafeKey };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
2
  var EMPTY_OPTIONS = {};
3
- var { propertyIsEnumerable: IS_ENUMERABLE } = Object.prototype;
3
+ var { hasOwnProperty: HAS_OWN, propertyIsEnumerable: IS_ENUMERABLE } = Object.prototype;
4
4
  function bunshinClone(value, options = EMPTY_OPTIONS, refs = /* @__PURE__ */ new WeakMap()) {
5
5
  return clone(value, resolveOptions(options), refs);
6
6
  }
@@ -16,7 +16,7 @@ function clone(value, settings, refs) {
16
16
  return cloneWithDescriptors(value, settings, refs);
17
17
  }
18
18
  if (Array.isArray(value)) {
19
- if (isShallowClonableArray(value)) {
19
+ if (isShallowArray(value)) {
20
20
  const result2 = value.slice();
21
21
  refs.set(value, result2);
22
22
  return result2;
@@ -32,11 +32,20 @@ function clone(value, settings, refs) {
32
32
  if (isPlainObject(value)) {
33
33
  const result = Object.create(Object.getPrototypeOf(value));
34
34
  refs.set(value, result);
35
- for (const key of Reflect.ownKeys(value)) {
36
- if (isUnsafeKey(key) || !IS_ENUMERABLE.call(value, key)) {
37
- continue;
35
+ if (!settings.preserveSymbolKeys) {
36
+ for (const key in value) {
37
+ if (isUnsafeKey(key) || !HAS_OWN.call(value, key)) {
38
+ continue;
39
+ }
40
+ result[key] = clone(value[key], settings, refs);
41
+ }
42
+ } else {
43
+ for (const key of Reflect.ownKeys(value)) {
44
+ if (isUnsafeKey(key) || !IS_ENUMERABLE.call(value, key)) {
45
+ continue;
46
+ }
47
+ result[key] = clone(value[key], settings, refs);
38
48
  }
39
- result[key] = clone(value[key], settings, refs);
40
49
  }
41
50
  return result;
42
51
  }
@@ -207,14 +216,6 @@ function createErrorInstance(error, settings, refs) {
207
216
  result.name = name;
208
217
  return result;
209
218
  }
210
- function isShallowClonableArray(array) {
211
- for (let i = 0, l = array.length; i < l; i++) {
212
- if (isObject(array[i])) {
213
- return false;
214
- }
215
- }
216
- return true;
217
- }
218
219
  function forEachOwnKey(object, callback) {
219
220
  for (const key of Object.keys(object)) {
220
221
  callback(key);
@@ -233,6 +234,14 @@ function isPlainObject(value) {
233
234
  const proto = Object.getPrototypeOf(value);
234
235
  return proto === Object.prototype || proto === null;
235
236
  }
237
+ function isShallowArray(array) {
238
+ for (let i = 0, l = array.length; i < l; i++) {
239
+ if (isObject(array[i])) {
240
+ return false;
241
+ }
242
+ }
243
+ return true;
244
+ }
236
245
  function isUnsafeKey(key) {
237
246
  return typeof key === "string" && (key === "__proto__" || key === "prototype" || key === "constructor");
238
247
  }
@@ -240,8 +249,13 @@ function resolveOptions(options) {
240
249
  let {
241
250
  preserveBufferSharing = false,
242
251
  preserveDescriptors = false,
243
- strictDescriptors = false
252
+ strictDescriptors = false,
253
+ preserveSymbolKeys = false
244
254
  } = options;
255
+ if (typeof preserveSymbolKeys !== "boolean") {
256
+ console.warn("Invalid preserveSymbolKeys option. Fallback: false.");
257
+ preserveSymbolKeys = false;
258
+ }
245
259
  if (typeof preserveBufferSharing !== "boolean") {
246
260
  console.warn("Invalid preserveBufferSharing option. Fallback: false.");
247
261
  preserveBufferSharing = false;
@@ -254,7 +268,12 @@ function resolveOptions(options) {
254
268
  console.warn("Invalid strictDescriptors option. Fallback: false.");
255
269
  strictDescriptors = false;
256
270
  }
257
- return { preserveBufferSharing, preserveDescriptors, strictDescriptors };
271
+ return {
272
+ preserveBufferSharing,
273
+ preserveDescriptors,
274
+ preserveSymbolKeys,
275
+ strictDescriptors
276
+ };
258
277
  }
259
278
 
260
- export { bunshinClone, forEachOwnKey, isObject, isPlainObject, isUnsafeKey };
279
+ export { bunshinClone, forEachOwnKey, isObject, isPlainObject, isShallowArray, isUnsafeKey };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bunshin-clone",
3
- "version": "1.7.1",
3
+ "version": "1.8.0",
4
4
  "description": "High-performance deep clone utility with descriptor support",
5
5
  "keywords": [
6
6
  "array",