Skip to content

Commit 4b5515d

Browse files
committed
handle non enumerable symbols
1 parent bb5fe97 commit 4b5515d

1 file changed

Lines changed: 43 additions & 36 deletions

File tree

packages/router-core/src/utils.ts

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -217,52 +217,59 @@ export function replaceEqualDeep<T>(prev: any, _next: T): T {
217217
const next = _next as any
218218

219219
const array = isPlainArray(prev) && isPlainArray(next)
220+
const object = !array && isPlainObject(prev) && isPlainObject(next)
220221

221-
if (array || (isSimplePlainObject(prev) && isSimplePlainObject(next))) {
222-
const prevItems = array ? prev : Reflect.ownKeys(prev)
223-
const prevSize = prevItems.length
224-
const nextItems = array ? next : Reflect.ownKeys(next)
225-
const nextSize = nextItems.length
226-
const copy: any = array ? new Array(nextSize) : {}
227-
228-
let equalItems = 0
229-
230-
for (let i = 0; i < nextSize; i++) {
231-
const key = array ? i : (nextItems[i] as any)
232-
const p = prev[key]
233-
if (
234-
(array || prev.hasOwnProperty(key)) &&
235-
p === undefined &&
236-
next[key] === undefined
237-
) {
238-
copy[key] = undefined
222+
if (!array && !object) return next
223+
224+
const prevItems = array ? prev : getEnumerableOwnKeys(prev)
225+
if (!prevItems) return next
226+
const nextItems = array ? next : getEnumerableOwnKeys(next)
227+
if (!nextItems) return next
228+
const prevSize = prevItems.length
229+
const nextSize = nextItems.length
230+
const copy: any = array ? new Array(nextSize) : {}
231+
232+
let equalItems = 0
233+
234+
for (let i = 0; i < nextSize; i++) {
235+
const key = array ? i : (nextItems[i] as any)
236+
const p = prev[key]
237+
if (
238+
(array || prev.hasOwnProperty(key)) &&
239+
p === undefined &&
240+
next[key] === undefined
241+
) {
242+
copy[key] = undefined
243+
equalItems++
244+
} else {
245+
const value = replaceEqualDeep(p, next[key])
246+
copy[key] = value
247+
if (value === p && p !== undefined) {
239248
equalItems++
240-
} else {
241-
const value = replaceEqualDeep(p, next[key])
242-
copy[key] = value
243-
if (value === p && p !== undefined) {
244-
equalItems++
245-
}
246249
}
247250
}
248-
249-
return prevSize === nextSize && equalItems === prevSize ? prev : copy
250251
}
251252

252-
return next
253+
return prevSize === nextSize && equalItems === prevSize ? prev : copy
253254
}
254255

255256
/**
256-
* A wrapper around `isPlainObject` with additional checks to ensure that it is not
257-
* only a plain object, but also one that is "clone-friendly" (doesn't have any
258-
* non-enumerable properties).
257+
* Equivalent to `Reflect.ownKeys`, but ensures that objects are "clone-friendly":
258+
* will return false if object has any non-enumerable properties.
259259
*/
260-
function isSimplePlainObject(o: any) {
261-
return (
262-
// all the checks from isPlainObject are more likely to hit so we perform them first
263-
isPlainObject(o) &&
264-
Object.getOwnPropertyNames(o).length === Object.keys(o).length
265-
)
260+
function getEnumerableOwnKeys(o: object) {
261+
const keys = []
262+
const names = Object.getOwnPropertyNames(o)
263+
for (const name of names) {
264+
if (!Object.prototype.propertyIsEnumerable.call(o, name)) return false
265+
keys.push(name)
266+
}
267+
const symbols = Object.getOwnPropertySymbols(o)
268+
for (const symbol of symbols) {
269+
if (!Object.prototype.propertyIsEnumerable.call(o, symbol)) return false
270+
keys.push(symbol)
271+
}
272+
return keys
266273
}
267274

268275
// Copied from: https://github.com/jonschlinkert/is-plain-object

0 commit comments

Comments
 (0)