/
createVmContext.ts
101 lines (81 loc) · 2.25 KB
/
createVmContext.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import * as vm from 'vm';
import type { Window } from 'happy-dom';
import type { FeatureFlags, StrictOptions } from '@wyw-in-js/shared';
import { isFeatureEnabled } from '@wyw-in-js/shared';
import * as process from './process';
const NOOP = () => {};
function createWindow(): Window {
const { Window, GlobalWindow } = require('happy-dom');
const HappyWindow = GlobalWindow || Window;
const win = new HappyWindow();
// TODO: browser doesn't expose Buffer, but a lot of dependencies use it
win.Buffer = Buffer;
win.Uint8Array = Uint8Array;
return win;
}
function createBaseContext(
win: Window | undefined,
additionalContext: Partial<vm.Context>
): Partial<vm.Context> {
const baseContext: vm.Context = win ?? {};
baseContext.document = win?.document;
baseContext.window = win;
baseContext.self = win;
baseContext.top = win;
baseContext.parent = win;
baseContext.global = win;
baseContext.process = process;
baseContext.clearImmediate = NOOP;
baseContext.clearInterval = NOOP;
baseContext.clearTimeout = NOOP;
baseContext.setImmediate = NOOP;
baseContext.requestAnimationFrame = NOOP;
baseContext.setInterval = NOOP;
baseContext.setTimeout = NOOP;
// eslint-disable-next-line guard-for-in,no-restricted-syntax
for (const key in additionalContext) {
baseContext[key] = additionalContext[key];
}
return baseContext;
}
function createHappyDOMWindow() {
const win = createWindow();
return {
teardown: () => {
win.happyDOM.cancelAsync();
},
window: win,
};
}
function createNothing() {
return {
teardown: () => {},
window: undefined,
};
}
export function createVmContext(
filename: string,
features: FeatureFlags<'happyDOM'>,
additionalContext: Partial<vm.Context>,
overrideContext: StrictOptions['overrideContext'] = (i) => i
) {
const isHappyDOMEnabled = isFeatureEnabled(features, 'happyDOM', filename);
const { teardown, window } = isHappyDOMEnabled
? createHappyDOMWindow()
: createNothing();
const baseContext = createBaseContext(
window,
overrideContext(
{
__filename: filename,
...additionalContext,
},
filename
)
);
const context = vm.createContext(baseContext);
return {
context,
teardown,
};
}