-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
console.ts
134 lines (122 loc) · 3.72 KB
/
console.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { Writable } from 'node:stream'
import { Console } from 'node:console'
import { relative } from 'node:path'
import { getColors, getSafeTimers } from '@vitest/utils'
import { RealDate } from '../integrations/mock/date'
import type { WorkerGlobalState } from '../types'
export const UNKNOWN_TEST_ID = '__vitest__unknown_test__'
function getTaskIdByStack(root: string) {
const stack = new Error('STACK_TRACE_ERROR').stack?.split('\n')
if (!stack)
return UNKNOWN_TEST_ID
const index = stack.findIndex(line => line.includes('at Console.value (node:internal/console/'))
const line = index === -1 ? null : stack[index + 2]
if (!line)
return UNKNOWN_TEST_ID
const filepath = line.match(/at\s(.*)\s?/)?.[1]
if (filepath)
return relative(root, filepath)
return UNKNOWN_TEST_ID
}
export function createCustomConsole(state: WorkerGlobalState) {
const stdoutBuffer = new Map<string, any[]>()
const stderrBuffer = new Map<string, any[]>()
const timers = new Map<string, { stdoutTime: number; stderrTime: number; timer: any }>()
const { setTimeout, clearTimeout } = getSafeTimers()
// group sync console.log calls with macro task
function schedule(taskId: string) {
const timer = timers.get(taskId)!
const { stdoutTime, stderrTime } = timer
clearTimeout(timer.timer)
timer.timer = setTimeout(() => {
if (stderrTime < stdoutTime) {
sendStderr(taskId)
sendStdout(taskId)
}
else {
sendStdout(taskId)
sendStderr(taskId)
}
})
}
function sendStdout(taskId: string) {
const buffer = stdoutBuffer.get(taskId)
if (!buffer)
return
const content = buffer.map(i => String(i)).join('')
const timer = timers.get(taskId)!
state.rpc.onUserConsoleLog({
type: 'stdout',
content: content || '<empty line>',
taskId,
time: timer.stdoutTime || RealDate.now(),
size: buffer.length,
})
stdoutBuffer.set(taskId, [])
timer.stdoutTime = 0
}
function sendStderr(taskId: string) {
const buffer = stderrBuffer.get(taskId)
if (!buffer)
return
const content = buffer.map(i => String(i)).join('')
const timer = timers.get(taskId)!
state.rpc.onUserConsoleLog({
type: 'stderr',
content: content || '<empty line>',
taskId,
time: timer.stderrTime || RealDate.now(),
size: buffer.length,
})
stderrBuffer.set(taskId, [])
timer.stderrTime = 0
}
const stdout = new Writable({
write(data, encoding, callback) {
const id = state?.current?.id ?? getTaskIdByStack(state.ctx.config.root)
let timer = timers.get(id)
if (timer) {
timer.stdoutTime = timer.stdoutTime || RealDate.now()
}
else {
timer = { stdoutTime: RealDate.now(), stderrTime: RealDate.now(), timer: 0 }
timers.set(id, timer)
}
let buffer = stdoutBuffer.get(id)
if (!buffer) {
buffer = []
stdoutBuffer.set(id, buffer)
}
buffer.push(data)
schedule(id)
callback()
},
})
const stderr = new Writable({
write(data, encoding, callback) {
const id = state?.current?.id ?? getTaskIdByStack(state.ctx.config.root)
let timer = timers.get(id)
if (timer) {
timer.stderrTime = timer.stderrTime || RealDate.now()
}
else {
timer = { stderrTime: RealDate.now(), stdoutTime: RealDate.now(), timer: 0 }
timers.set(id, timer)
}
let buffer = stderrBuffer.get(id)
if (!buffer) {
buffer = []
stderrBuffer.set(id, buffer)
}
buffer.push(data)
schedule(id)
callback()
},
})
return new Console({
stdout,
stderr,
colorMode: getColors().isColorSupported,
groupIndentation: 2,
})
}