mirror of
https://github.com/vitest-dev/vitest.git
synced 2026-02-01 17:36:51 +00:00
fix: skip props from prototype when cloning (#1287)
This commit is contained in:
parent
2bc2620ebc
commit
574d072c92
@ -1,18 +1,25 @@
|
||||
import type { Arrayable, DeepMerge, Nullable } from '../types'
|
||||
|
||||
function isFinalObj(obj: any) {
|
||||
return obj === Object.prototype || obj === Function.prototype || obj === RegExp.prototype
|
||||
}
|
||||
|
||||
function collectOwnProperties(obj: any, collector: Set<string | symbol>) {
|
||||
const props = Object.getOwnPropertyNames(obj)
|
||||
const symbs = Object.getOwnPropertySymbols(obj)
|
||||
|
||||
props.forEach(prop => collector.add(prop))
|
||||
symbs.forEach(symb => collector.add(symb))
|
||||
}
|
||||
|
||||
export function getAllProperties(obj: any) {
|
||||
const allProps = new Set<string | symbol>()
|
||||
let curr = obj
|
||||
do {
|
||||
// we don't need propterties from these
|
||||
if (curr === Object.prototype || curr === Function.prototype || curr === RegExp.prototype)
|
||||
if (isFinalObj(curr))
|
||||
break
|
||||
const props = Object.getOwnPropertyNames(curr)
|
||||
const symbs = Object.getOwnPropertySymbols(curr)
|
||||
|
||||
props.forEach(prop => allProps.add(prop))
|
||||
symbs.forEach(symb => allProps.add(symb))
|
||||
|
||||
collectOwnProperties(curr, allProps)
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
} while (curr = Object.getPrototypeOf(curr))
|
||||
return Array.from(allProps)
|
||||
@ -36,6 +43,14 @@ export function getType(value: unknown): string {
|
||||
return Object.prototype.toString.apply(value).slice(8, -1)
|
||||
}
|
||||
|
||||
function getOwnProperties(obj: any) {
|
||||
const ownProps = new Set<string | symbol>()
|
||||
if (isFinalObj(obj))
|
||||
return []
|
||||
collectOwnProperties(obj, ownProps)
|
||||
return Array.from(ownProps)
|
||||
}
|
||||
|
||||
export function clone<T>(val: T): T {
|
||||
let k: any, out: any, tmp: any
|
||||
|
||||
@ -49,7 +64,8 @@ export function clone<T>(val: T): T {
|
||||
|
||||
if (Object.prototype.toString.call(val) === '[object Object]') {
|
||||
out = Object.create(Object.getPrototypeOf(val))
|
||||
const props = getAllProperties(val)
|
||||
// we don't need properties from prototype
|
||||
const props = getOwnProperties(val)
|
||||
for (const k of props) {
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
out[k] = (tmp = (val as any)[k]) && typeof tmp === 'object' ? clone(tmp) : tmp
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import { assertTypes, deepMerge, toArray } from '../../../packages/vitest/src/utils'
|
||||
import { assertTypes, clone, deepMerge, toArray } from '../../../packages/vitest/src/utils'
|
||||
import { deepMergeSnapshot } from '../../../packages/vitest/src/integrations/snapshot/port/utils'
|
||||
|
||||
describe('assertTypes', () => {
|
||||
@ -121,3 +121,26 @@ describe('toArray', () => {
|
||||
expect(toArray({ a: 1, b: 1, expected: 2 })).toEqual([{ a: 1, b: 1, expected: 2 }])
|
||||
})
|
||||
})
|
||||
|
||||
describe('clone', () => {
|
||||
test('various types should be cloned correctly', () => {
|
||||
expect(clone(1)).toBe(1)
|
||||
expect(clone(true)).toBe(true)
|
||||
expect(clone(undefined)).toBe(undefined)
|
||||
expect(clone(null)).toBe(null)
|
||||
expect(clone({ a: 1 })).toEqual({ a: 1 })
|
||||
expect(clone([1, 2])).toEqual([1, 2])
|
||||
const symbolA = Symbol('a')
|
||||
expect(clone(symbolA)).toBe(symbolA)
|
||||
const objB: any = {}
|
||||
Object.defineProperty(objB, 'value', {
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
value: 1,
|
||||
writable: false,
|
||||
})
|
||||
expect(clone(objB).value).toEqual(objB.value)
|
||||
const objC = Object.create(objB)
|
||||
expect(clone(objC).value).toEqual(objC.value)
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user