forked from jestjs/jest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
deep_cyclic_copy.js
87 lines (71 loc) · 2.18 KB
/
deep_cyclic_copy.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
* Copyright (c) 2017-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
const EMPTY = new Set();
// Node 6 does not have gOPDs, so we define a simple polyfill for it.
if (!Object.getOwnPropertyDescriptors) {
// $FlowFixMe: polyfill
Object.getOwnPropertyDescriptors = obj => {
const list = {};
Object.getOwnPropertyNames(obj)
.concat(Object.getOwnPropertySymbols(obj))
// $FlowFixMe: assignment with a Symbol is OK.
.forEach(key => (list[key] = Object.getOwnPropertyDescriptor(obj, key)));
return list;
};
}
export default function deepCyclicCopy(
value: any,
blacklist: Set<string> = EMPTY,
cycles: WeakMap<any, any> = new WeakMap(),
): any {
if (typeof value !== 'object' || value === null) {
return value;
} else if (cycles.has(value)) {
return cycles.get(value);
} else if (Array.isArray(value)) {
return deepCyclicCopyArray(value, blacklist, cycles);
} else {
return deepCyclicCopyObject(value, blacklist, cycles);
}
}
function deepCyclicCopyObject(
object: Object,
blacklist: Set<string>,
cycles: WeakMap<any, any>,
): Object {
const newObject = Object.create(Object.getPrototypeOf(object));
// $FlowFixMe: Object.getOwnPropertyDescriptors is polyfilled above.
const descriptors = Object.getOwnPropertyDescriptors(object);
cycles.set(object, newObject);
Object.keys(descriptors).forEach(key => {
if (blacklist.has(key)) {
delete descriptors[key];
return;
}
const descriptor = descriptors[key];
if (typeof descriptor.value !== 'undefined') {
descriptor.value = deepCyclicCopy(descriptor.value, EMPTY, cycles);
}
descriptor.configurable = true;
});
return Object.defineProperties(newObject, descriptors);
}
function deepCyclicCopyArray(
array: Array<any>,
blacklist: Set<string>,
cycles: WeakMap<any, any>,
): Array<any> {
const newArray = [];
const length = array.length;
cycles.set(array, newArray);
for (let i = 0; i < length; i++) {
newArray[i] = deepCyclicCopy(array[i], EMPTY, cycles);
}
return newArray;
}