Skip to content

Commit cf74ad3

Browse files
author
Guillaume Chau
committed
fix: update clone code to fix 'illegal invocation' error
1 parent ebfccde commit cf74ad3

File tree

1 file changed

+91
-52
lines changed

1 file changed

+91
-52
lines changed

src/backend/hook.js

Lines changed: 91 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,36 @@ export function installHook (target) {
108108
})
109109

110110
// Clone deep utility for cloning initial state of the store
111-
// REFERENCE: https://github.com/buunguyen/node-clone/commit/63afda9de9d94b9332586e34a646a13e8d719244
111+
// REFERENCE: https://github.com/pvorb/clone
112+
113+
let NativeMap
114+
try {
115+
NativeMap = Map
116+
} catch (_) {
117+
// maybe a reference error because no `Map`. Give it a dummy value that no
118+
// value will ever be an instanceof.
119+
NativeMap = function () {}
120+
}
121+
122+
let NativeSet
123+
try {
124+
NativeSet = Set
125+
} catch (_) {
126+
NativeSet = function () {}
127+
}
112128

113-
function clone (parent, circular, depth, prototype) {
129+
let NativePromise
130+
try {
131+
NativePromise = Promise
132+
} catch (_) {
133+
NativePromise = function () {}
134+
}
135+
136+
function clone (parent, circular, depth, prototype, includeNonEnumerable) {
114137
if (typeof circular === 'object') {
115138
depth = circular.depth
116139
prototype = circular.prototype
140+
includeNonEnumerable = circular.includeNonEnumerable
117141
circular = circular.circular
118142
}
119143
// maintain two arrays for circular references, where corresponding parents
@@ -140,30 +164,37 @@ export function installHook (target) {
140164
return parent
141165
}
142166

143-
if (parent instanceof Map) {
144-
child = new Map()
145-
} else if (parent instanceof Set) {
146-
child = new Set()
147-
} else if (parent instanceof Promise) {
148-
child = new Promise(function (resolve, reject) {
167+
if (_instanceof(parent, NativeMap)) {
168+
child = new NativeMap()
169+
} else if (_instanceof(parent, NativeSet)) {
170+
child = new NativeSet()
171+
} else if (_instanceof(parent, NativePromise)) {
172+
child = new NativePromise(function (resolve, reject) {
149173
parent.then(function (value) {
150174
resolve(_clone(value, depth - 1))
151175
}, function (err) {
152176
reject(_clone(err, depth - 1))
153177
})
154178
})
155-
} else if (_isArray(parent)) {
179+
} else if (clone.__isArray(parent)) {
156180
child = []
157-
} else if (_isRegExp(parent)) {
158-
child = new RegExp(parent.source, _getRegExpFlags(parent))
181+
} else if (clone.__isRegExp(parent)) {
182+
child = new RegExp(parent.source, __getRegExpFlags(parent))
159183
if (parent.lastIndex) child.lastIndex = parent.lastIndex
160-
} else if (_isDate(parent)) {
184+
} else if (clone.__isDate(parent)) {
161185
child = new Date(parent.getTime())
162186
} else if (useBuffer && Buffer.isBuffer(parent)) {
163-
child = Buffer.alloc(parent.length)
164-
parent.copy(child)
187+
if (Buffer.from) {
188+
// Node.js >= 5.10.0
189+
child = Buffer.from(parent)
190+
} else {
191+
// Older Node.js versions
192+
// eslint-disable-next-line node/no-deprecated-api
193+
child = new Buffer(parent.length)
194+
parent.copy(child)
195+
}
165196
return child
166-
} else if (parent instanceof Error) {
197+
} else if (_instanceof(parent, Error)) {
167198
child = Object.create(parent)
168199
} else {
169200
if (typeof prototype === 'undefined') {
@@ -185,40 +216,25 @@ export function installHook (target) {
185216
allChildren.push(child)
186217
}
187218

188-
if (parent instanceof Map) {
189-
var keyIterator = parent.keys()
190-
while (true) {
191-
let next = keyIterator.next()
192-
if (next.done) {
193-
break
194-
}
195-
var keyChild = _clone(next.value, depth - 1)
196-
var valueChild = _clone(parent.get(next.value), depth - 1)
219+
if (_instanceof(parent, NativeMap)) {
220+
parent.forEach(function (value, key) {
221+
var keyChild = _clone(key, depth - 1)
222+
var valueChild = _clone(value, depth - 1)
197223
child.set(keyChild, valueChild)
198-
}
224+
})
199225
}
200-
if (parent instanceof Set) {
201-
var iterator = parent.keys()
202-
while (true) {
203-
let next = iterator.next()
204-
if (next.done) {
205-
break
206-
}
207-
var entryChild = _clone(next.value, depth - 1)
226+
if (_instanceof(parent, NativeSet)) {
227+
parent.forEach(function (value) {
228+
var entryChild = _clone(value, depth - 1)
208229
child.add(entryChild)
209-
}
230+
})
210231
}
211232

212-
for (let i in parent) {
213-
var attrs
214-
if (proto) {
215-
attrs = Object.getOwnPropertyDescriptor(proto, i)
216-
}
217-
218-
if (attrs && attrs.set == null) {
219-
continue
233+
for (var i in parent) {
234+
var attrs = Object.getOwnPropertyDescriptor(parent, i)
235+
if (attrs) {
236+
child[i] = _clone(parent[i], depth - 1)
220237
}
221-
child[i] = _clone(parent[i], depth - 1)
222238
}
223239

224240
if (Object.getOwnPropertySymbols) {
@@ -228,10 +244,24 @@ export function installHook (target) {
228244
// like a number or string.
229245
var symbol = symbols[i]
230246
var descriptor = Object.getOwnPropertyDescriptor(parent, symbol)
231-
if (descriptor && !descriptor.enumerable) {
247+
if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
232248
continue
233249
}
234250
child[symbol] = _clone(parent[symbol], depth - 1)
251+
Object.defineProperty(child, symbol, descriptor)
252+
}
253+
}
254+
255+
if (includeNonEnumerable) {
256+
var allPropertyNames = Object.getOwnPropertyNames(parent)
257+
for (let i = 0; i < allPropertyNames.length; i++) {
258+
const propertyName = allPropertyNames[i]
259+
let descriptor = Object.getOwnPropertyDescriptor(parent, propertyName)
260+
if (descriptor && descriptor.enumerable) {
261+
continue
262+
}
263+
child[propertyName] = _clone(parent[propertyName], depth - 1)
264+
Object.defineProperty(child, propertyName, descriptor)
235265
}
236266
}
237267

@@ -243,27 +273,36 @@ export function installHook (target) {
243273

244274
// private utility functions
245275

246-
function _objToStr (o) {
276+
function __objToStr (o) {
247277
return Object.prototype.toString.call(o)
248278
}
279+
clone.__objToStr = __objToStr
249280

250-
function _isDate (o) {
251-
return typeof o === 'object' && _objToStr(o) === '[object Date]'
281+
function __isDate (o) {
282+
return typeof o === 'object' && __objToStr(o) === '[object Date]'
252283
}
284+
clone.__isDate = __isDate
253285

254-
function _isArray (o) {
255-
return typeof o === 'object' && _objToStr(o) === '[object Array]'
286+
function __isArray (o) {
287+
return typeof o === 'object' && __objToStr(o) === '[object Array]'
256288
}
289+
clone.__isArray = __isArray
257290

258-
function _isRegExp (o) {
259-
return typeof o === 'object' && _objToStr(o) === '[object RegExp]'
291+
function __isRegExp (o) {
292+
return typeof o === 'object' && __objToStr(o) === '[object RegExp]'
260293
}
294+
clone.__isRegExp = __isRegExp
261295

262-
function _getRegExpFlags (re) {
296+
function __getRegExpFlags (re) {
263297
var flags = ''
264298
if (re.global) flags += 'g'
265299
if (re.ignoreCase) flags += 'i'
266300
if (re.multiline) flags += 'm'
267301
return flags
268302
}
303+
clone.__getRegExpFlags = __getRegExpFlags
304+
305+
function _instanceof (obj, type) {
306+
return type != null && obj instanceof type
307+
}
269308
}

0 commit comments

Comments
 (0)