|
| 1 | +// Clone deep utility for cloning initial state of the store |
| 2 | +// REFERENCE: https://github.com/pvorb/clone |
| 3 | + |
| 4 | +let NativeMap |
| 5 | +try { |
| 6 | + NativeMap = Map |
| 7 | +} catch (_) { |
| 8 | + // maybe a reference error because no `Map`. Give it a dummy value that no |
| 9 | + // value will ever be an instanceof. |
| 10 | + NativeMap = function () {} |
| 11 | +} |
| 12 | + |
| 13 | +let NativeSet |
| 14 | +try { |
| 15 | + NativeSet = Set |
| 16 | +} catch (_) { |
| 17 | + NativeSet = function () {} |
| 18 | +} |
| 19 | + |
| 20 | +let NativePromise |
| 21 | +try { |
| 22 | + NativePromise = Promise |
| 23 | +} catch (_) { |
| 24 | + NativePromise = function () {} |
| 25 | +} |
| 26 | + |
| 27 | +export default function clone (parent, { circular = true, depth = Infinity, prototype, includeNonEnumerable } = {}) { |
| 28 | + // maintain two arrays for circular references, where corresponding parents |
| 29 | + // and children have the same index |
| 30 | + var allParents = [] |
| 31 | + var allChildren = [] |
| 32 | + |
| 33 | + var useBuffer = typeof Buffer !== 'undefined' && typeof Buffer.isBuffer === 'function' |
| 34 | + |
| 35 | + // recurse this function so we don't reset allParents and allChildren |
| 36 | + function _clone (parent, depth) { |
| 37 | + // cloning null always returns null |
| 38 | + if (parent === null) { return null } |
| 39 | + |
| 40 | + if (depth === 0) { return parent } |
| 41 | + |
| 42 | + var child |
| 43 | + var proto |
| 44 | + if (typeof parent !== 'object') { |
| 45 | + return parent |
| 46 | + } |
| 47 | + |
| 48 | + if (_instanceof(parent, NativeMap)) { |
| 49 | + child = new NativeMap() |
| 50 | + } else if (_instanceof(parent, NativeSet)) { |
| 51 | + child = new NativeSet() |
| 52 | + } else if (_instanceof(parent, NativePromise)) { |
| 53 | + child = new NativePromise(function (resolve, reject) { |
| 54 | + parent.then(function (value) { |
| 55 | + resolve(_clone(value, depth - 1)) |
| 56 | + }, function (err) { |
| 57 | + reject(_clone(err, depth - 1)) |
| 58 | + }) |
| 59 | + }) |
| 60 | + } else if (clone.__isArray(parent)) { |
| 61 | + child = [] |
| 62 | + } else if (clone.__isRegExp(parent)) { |
| 63 | + child = new RegExp(parent.source, __getRegExpFlags(parent)) |
| 64 | + if (parent.lastIndex) child.lastIndex = parent.lastIndex |
| 65 | + } else if (clone.__isDate(parent)) { |
| 66 | + child = new Date(parent.getTime()) |
| 67 | + } else if (useBuffer && Buffer.isBuffer(parent)) { |
| 68 | + if (Buffer.from) { |
| 69 | + // Node.js >= 5.10.0 |
| 70 | + child = Buffer.from(parent) |
| 71 | + } else { |
| 72 | + // Older Node.js versions |
| 73 | + // eslint-disable-next-line node/no-deprecated-api |
| 74 | + child = new Buffer(parent.length) |
| 75 | + parent.copy(child) |
| 76 | + } |
| 77 | + return child |
| 78 | + } else if (_instanceof(parent, Error)) { |
| 79 | + child = Object.create(parent) |
| 80 | + } else { |
| 81 | + if (typeof prototype === 'undefined') { |
| 82 | + proto = Object.getPrototypeOf(parent) |
| 83 | + child = Object.create(proto) |
| 84 | + } else { |
| 85 | + child = Object.create(prototype) |
| 86 | + proto = prototype |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + if (circular) { |
| 91 | + var index = allParents.indexOf(parent) |
| 92 | + |
| 93 | + if (index !== -1) { |
| 94 | + return allChildren[index] |
| 95 | + } |
| 96 | + allParents.push(parent) |
| 97 | + allChildren.push(child) |
| 98 | + } |
| 99 | + |
| 100 | + if (_instanceof(parent, NativeMap)) { |
| 101 | + parent.forEach(function (value, key) { |
| 102 | + var keyChild = _clone(key, depth - 1) |
| 103 | + var valueChild = _clone(value, depth - 1) |
| 104 | + child.set(keyChild, valueChild) |
| 105 | + }) |
| 106 | + } |
| 107 | + if (_instanceof(parent, NativeSet)) { |
| 108 | + parent.forEach(function (value) { |
| 109 | + var entryChild = _clone(value, depth - 1) |
| 110 | + child.add(entryChild) |
| 111 | + }) |
| 112 | + } |
| 113 | + |
| 114 | + for (var i in parent) { |
| 115 | + var attrs = Object.getOwnPropertyDescriptor(parent, i) |
| 116 | + if (attrs) { |
| 117 | + if (attrs.hasOwnProperty('get') && attrs.get.name === 'computedGetter') { |
| 118 | + Object.defineProperty(child, i, attrs) |
| 119 | + continue |
| 120 | + } |
| 121 | + |
| 122 | + child[i] = _clone(parent[i], depth - 1) |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + if (Object.getOwnPropertySymbols) { |
| 127 | + var symbols = Object.getOwnPropertySymbols(parent) |
| 128 | + for (let i = 0; i < symbols.length; i++) { |
| 129 | + // Don't need to worry about cloning a symbol because it is a primitive, |
| 130 | + // like a number or string. |
| 131 | + var symbol = symbols[i] |
| 132 | + var descriptor = Object.getOwnPropertyDescriptor(parent, symbol) |
| 133 | + if (descriptor && !descriptor.enumerable && !includeNonEnumerable) { |
| 134 | + continue |
| 135 | + } |
| 136 | + child[symbol] = _clone(parent[symbol], depth - 1) |
| 137 | + Object.defineProperty(child, symbol, descriptor) |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + if (includeNonEnumerable) { |
| 142 | + var allPropertyNames = Object.getOwnPropertyNames(parent) |
| 143 | + for (let i = 0; i < allPropertyNames.length; i++) { |
| 144 | + const propertyName = allPropertyNames[i] |
| 145 | + let descriptor = Object.getOwnPropertyDescriptor(parent, propertyName) |
| 146 | + if (descriptor && descriptor.enumerable) { |
| 147 | + continue |
| 148 | + } |
| 149 | + child[propertyName] = _clone(parent[propertyName], depth - 1) |
| 150 | + Object.defineProperty(child, propertyName, descriptor) |
| 151 | + } |
| 152 | + } |
| 153 | + |
| 154 | + return child |
| 155 | + } |
| 156 | + |
| 157 | + return _clone(parent, depth) |
| 158 | +} |
| 159 | + |
| 160 | +// private utility functions |
| 161 | + |
| 162 | +function __objToStr (o) { |
| 163 | + return Object.prototype.toString.call(o) |
| 164 | +} |
| 165 | +clone.__objToStr = __objToStr |
| 166 | + |
| 167 | +function __isDate (o) { |
| 168 | + return typeof o === 'object' && __objToStr(o) === '[object Date]' |
| 169 | +} |
| 170 | +clone.__isDate = __isDate |
| 171 | + |
| 172 | +function __isArray (o) { |
| 173 | + return typeof o === 'object' && __objToStr(o) === '[object Array]' |
| 174 | +} |
| 175 | +clone.__isArray = __isArray |
| 176 | + |
| 177 | +function __isRegExp (o) { |
| 178 | + return typeof o === 'object' && __objToStr(o) === '[object RegExp]' |
| 179 | +} |
| 180 | +clone.__isRegExp = __isRegExp |
| 181 | + |
| 182 | +function __getRegExpFlags (re) { |
| 183 | + var flags = '' |
| 184 | + if (re.global) flags += 'g' |
| 185 | + if (re.ignoreCase) flags += 'i' |
| 186 | + if (re.multiline) flags += 'm' |
| 187 | + return flags |
| 188 | +} |
| 189 | +clone.__getRegExpFlags = __getRegExpFlags |
| 190 | + |
| 191 | +function _instanceof (obj, type) { |
| 192 | + return type != null && obj instanceof type |
| 193 | +} |
0 commit comments