Skip to content

Commit

Permalink
fix: handle cloning proxied classes w/ enumerable getters (#3026)
Browse files Browse the repository at this point in the history
  • Loading branch information
tgriesser committed Mar 24, 2023
1 parent 6efe61a commit 196a067
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 2 deletions.
22 changes: 20 additions & 2 deletions packages/utils/src/helpers.ts
Expand Up @@ -86,8 +86,26 @@ export function clone<T>(val: T, seen: WeakMap<any, any>): T {
seen.set(val, out)
// we don't need properties from prototype
const props = getOwnProperties(val)
for (const k of props)
out[k] = clone((val as any)[k], seen)
for (const k of props) {
const descriptor = Object.getOwnPropertyDescriptor(val, k)
if (!descriptor)
continue
const cloned = clone((val as any)[k], seen)
if ('get' in descriptor) {
Object.defineProperty(out, k, {
...descriptor,
get() {
return cloned
},
})
}
else {
Object.defineProperty(out, k, {
...descriptor,
value: cloned,
})
}
}
return out
}

Expand Down
41 changes: 41 additions & 0 deletions test/core/test/utils.spec.ts
Expand Up @@ -149,6 +149,47 @@ describe('deepClone', () => {
objD.ref = objD
expect(deepClone(objD)).toEqual(objD)
})

test('can clone classes with proxied enumerable getters', () => {
const obj = Symbol.for('aClass')
interface TestShape { a: number; b: string }
class A {
[obj]: TestShape
constructor(data: TestShape) {
this[obj] = data
return new Proxy(this, {
ownKeys() {
return Reflect.ownKeys(data)
},
getOwnPropertyDescriptor(target, p) {
return {
...Reflect.getOwnPropertyDescriptor(data, p),
enumerable: true,
}
},
})
}

get a() {
return this[obj].a
}

get b() {
return this[obj].b
}
}
const shape = { a: 1 } as TestShape
Object.defineProperty(shape, 'b', {
configurable: true,
enumerable: true,
get: () => 'B',
})
const aClass = new A(shape)
expect(aClass.a).toEqual(1)
expect(aClass.b).toEqual('B')
expect(Object.keys(aClass)).toEqual(['a', 'b'])
expect(deepClone({ aClass })).toEqual({ aClass: new A({ a: 1, b: 'B' }) })
})
})

describe('resetModules doesn\'t resets only user modules', () => {
Expand Down

0 comments on commit 196a067

Please sign in to comment.