/
utils.ts
90 lines (80 loc) · 3.07 KB
/
utils.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
import type { WorkerGlobalState } from 'vitest'
import ponyfillStructuredClone from '@ungap/structured-clone'
import createDebug from 'debug'
import type { CloneOption } from './types'
export const debug = createDebug('vitest:web-worker')
export function getWorkerState(): WorkerGlobalState {
// @ts-expect-error untyped global
return globalThis.__vitest_worker__
}
export function assertGlobalExists(name: string) {
if (!(name in globalThis))
throw new Error(`[@vitest/web-worker] Cannot initiate a custom Web Worker. "${name}" is not supported in this environment. Please, consider using jsdom or happy-dom environment.`)
}
function createClonedMessageEvent(data: any, transferOrOptions: StructuredSerializeOptions | Transferable[] | undefined, clone: CloneOption) {
const transfer = Array.isArray(transferOrOptions) ? transferOrOptions : transferOrOptions?.transfer
debug('clone worker message %o', data)
const origin = typeof location === 'undefined' ? undefined : location.origin
if (typeof structuredClone === 'function' && clone === 'native') {
debug('create message event, using native structured clone')
return new MessageEvent('message', {
data: structuredClone(data, { transfer }),
origin,
})
}
if (clone !== 'none') {
debug('create message event, using polyfilled structured clone')
transfer?.length && console.warn(
'[@vitest/web-worker] `structuredClone` is not supported in this environment. '
+ 'Falling back to polyfill, your transferable options will be lost. '
+ 'Set `VITEST_WEB_WORKER_CLONE` environmental variable to "none", if you don\'t want to loose it,'
+ 'or update to Node 17+.',
)
return new MessageEvent('message', {
data: ponyfillStructuredClone(data, { lossy: true } as any),
origin,
})
}
debug('create message event without cloning an object')
return new MessageEvent('message', {
data,
origin,
})
}
export function createMessageEvent(data: any, transferOrOptions: StructuredSerializeOptions | Transferable[] | undefined, clone: CloneOption) {
try {
return createClonedMessageEvent(data, transferOrOptions, clone)
}
catch (error) {
debug('failed to clone message, dispatch "messageerror" event: %o', error)
return new MessageEvent('messageerror', {
data: error,
})
}
}
export function getRunnerOptions(): any {
const state = getWorkerState()
const { config, rpc, mockMap, moduleCache } = state
return {
fetchModule(id: string) {
return rpc.fetch(id, 'web')
},
resolveId(id: string, importer?: string) {
return rpc.resolveId(id, importer, 'web')
},
moduleCache,
mockMap,
interopDefault: config.deps.interopDefault ?? true,
moduleDirectories: config.deps.moduleDirectories,
root: config.root,
base: config.base,
state,
}
}
export function getFileIdFromUrl(url: URL | string) {
if (!(url instanceof URL))
url = new URL(url, self.location.origin)
if (url.protocol === 'http:' || url.protocol === 'https:')
return url.pathname
return url.toString().replace(/^file:\/+/, '/')
}