Skip to content

Commit 720fa4f

Browse files
SchnizKikobeats
authored andcommitted
fix ({}).constructor===Object
this resolves #899 with a caveat that an object that was created outside of the VM will obviously won't satisfy this requirement. However, it will still be `instaceof Object` which is interesting. I am not sure it'll be easy to solve.
1 parent 77be36e commit 720fa4f

File tree

2 files changed

+62
-2
lines changed

2 files changed

+62
-2
lines changed

packages/vm/src/edge-vm.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,25 @@ const transferableConstructors = [
117117
'TypeError',
118118
] as const
119119

120-
function patchInstanceOf(item: string, ctx: any) {
120+
const patchedPrototypes = new Set<(typeof transferableConstructors)[number]>([
121+
'Array',
122+
'Object',
123+
'RegExp',
124+
])
125+
126+
function patchInstanceOf(
127+
item: (typeof transferableConstructors)[number],
128+
ctx: any,
129+
) {
121130
// @ts-ignore
122131
ctx[Symbol.for(`node:${item}`)] = eval(item)
123132

133+
const shouldPatchPrototype = patchedPrototypes.has(item)
134+
124135
return runInContext(
125136
`
126-
globalThis.${item} = new Proxy(${item}, {
137+
(() => {
138+
const proxy = new Proxy(${item}, {
127139
get(target, prop, receiver) {
128140
if (prop === Symbol.hasInstance && receiver === globalThis.${item}) {
129141
const nodeTarget = globalThis[Symbol.for('node:${item}')];
@@ -137,8 +149,27 @@ function patchInstanceOf(item: string, ctx: any) {
137149
}
138150
139151
return Reflect.get(target, prop, receiver);
152+
},
153+
construct(target, args, newTarget) {
154+
return Object.assign(
155+
Reflect.construct(target, args, newTarget),
156+
{ constructor: proxy }
157+
);
140158
}
141159
})
160+
161+
globalThis.${item} = proxy;
162+
163+
${
164+
!shouldPatchPrototype
165+
? ''
166+
: `Object.assign(globalThis.${item}.prototype, {
167+
get constructor() {
168+
return proxy;
169+
}
170+
})`
171+
}
172+
})()
142173
`,
143174
ctx,
144175
)

packages/vm/tests/instanceof.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,35 @@ it('handles prototype chain correctly', () => {
9191
})
9292
})
9393

94+
describe('.constructor ===', () => {
95+
describe('created inside the vm', () => {
96+
test('new Object().constructor === Object', () => {
97+
const vm = new EdgeVM()
98+
expect(vm.evaluate(`new Object().constructor === Object`)).toBe(true)
99+
})
100+
test('({}).constructor === Object', () => {
101+
const vm = new EdgeVM()
102+
expect(vm.evaluate(`({}).constructor === Object`)).toBe(true)
103+
})
104+
test('new Array().constructor === Array', () => {
105+
const vm = new EdgeVM()
106+
expect(vm.evaluate(`new Array().constructor === Array`)).toBe(true)
107+
})
108+
test('[].constructor === Array', () => {
109+
const vm = new EdgeVM()
110+
expect(vm.evaluate(`[].constructor === Array`)).toBe(true)
111+
})
112+
test('new RegExp("").constructor === Array', () => {
113+
const vm = new EdgeVM()
114+
expect(vm.evaluate(`new RegExp("").constructor === RegExp`)).toBe(true)
115+
})
116+
test('[].constructor === Array', () => {
117+
const vm = new EdgeVM()
118+
expect(vm.evaluate(`/./.constructor === RegExp`)).toBe(true)
119+
})
120+
})
121+
})
122+
94123
describe('instanceof overriding', () => {
95124
test('binary array created outside of the VM is `instanceof` Object inside the VM', () => {
96125
const vm = new EdgeVM()

0 commit comments

Comments
 (0)