-
-
Notifications
You must be signed in to change notification settings - Fork 97
/
Copy pathws.ts
118 lines (103 loc) · 3.36 KB
/
ws.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { pathToFileURL } from 'node:url'
import type { WebSocket, WebSocketServer } from 'ws'
import { gte } from 'semver'
import type { ResolvedMeta } from '../api'
import { log } from '../log'
import type { WorkerEvent, WorkerRunnerOptions } from '../worker/types'
import { getConfig } from '../config'
import { createVitestRpc } from './rpc'
import type { VitestPackage } from './pkg'
export type WsConnectionMetadata = Omit<ResolvedMeta, 'process'> & {
ws: WebSocket
}
export function waitForWsConnection(
wss: WebSocketServer,
pkg: VitestPackage,
debug: boolean,
shellType: 'terminal' | 'child_process',
) {
return new Promise<WsConnectionMetadata>((resolve, reject) => {
wss.once('connection', (ws) => {
function onMessage(_message: any) {
const message = JSON.parse(_message.toString()) as WorkerEvent
if (message.type === 'debug')
log.worker('info', ...message.args)
if (message.type === 'ready') {
const { api, handlers } = createVitestRpc({
on: listener => ws.on('message', listener),
send: message => ws.send(message),
})
ws.once('close', () => {
log.verbose?.('[API]', 'Vitest WebSocket connection closed, cannot call RPC anymore.')
api.$close()
})
resolve({
rpc: api,
workspaceSource: message.workspaceSource,
handlers: {
...handlers,
onStdout() {
// do nothing by default
},
},
configs: message.configs,
ws,
pkg,
})
}
if (message.type === 'error') {
const error = new Error(`Vitest failed to start: \n${message.error}`)
reject(error)
}
ws.off('error', onError)
ws.off('message', onMessage)
ws.off('close', onExit)
}
function onError(err: Error) {
log.error('[API]', err)
reject(err)
ws.off('error', onError)
ws.off('message', onMessage)
ws.off('close', onExit)
}
function onExit(code: number) {
reject(new Error(`Vitest process exited with code ${code}`))
}
wss.off('error', onUnexpectedError)
wss.off('exit', onUnexpectedExit)
ws.on('error', onError)
ws.on('message', onMessage)
ws.on('close', onExit)
const pnpLoader = pkg.loader
const pnp = pkg.pnp
const runnerOptions: WorkerRunnerOptions = {
type: 'init',
meta: {
shellType,
vitestNodePath: pkg.vitestNodePath,
env: getConfig(pkg.folder).env || undefined,
configFile: pkg.configFile,
cwd: pkg.cwd,
arguments: pkg.arguments,
workspaceFile: pkg.workspaceFile,
id: pkg.id,
pnpApi: pnp,
pnpLoader: pnpLoader && gte(process.version, '18.19.0')
? pathToFileURL(pnpLoader).toString()
: undefined,
},
debug,
astCollect: getConfig(pkg.folder).experimentalStaticAstCollect,
}
ws.send(JSON.stringify(runnerOptions))
})
function onUnexpectedExit() {
reject(new Error('Cannot establish connection with Vitest process.'))
}
function onUnexpectedError(err: Error) {
reject(err)
}
wss.on('error', onUnexpectedError)
wss.once('close', onUnexpectedExit)
})
}