Skip to content

Commit f91da48

Browse files
authored
feat: don't rely on util package in @vitest/utils (#3685)
1 parent e3c0c43 commit f91da48

File tree

3 files changed

+87
-24
lines changed

3 files changed

+87
-24
lines changed

packages/browser/src/client/logger.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { importId } from './utils'
44
const { Date, console } = globalThis
55

66
export async function setupConsoleLogSpy() {
7-
const { stringify, format, utilInspect } = await importId('vitest/utils') as typeof import('vitest/utils')
7+
const { stringify, format, inspect } = await importId('vitest/utils') as typeof import('vitest/utils')
88
const { log, info, error, dir, dirxml, trace, time, timeEnd, timeLog, warn, debug, count, countReset } = console
99
const formatInput = (input: unknown) => {
1010
if (input instanceof Node)
@@ -42,7 +42,7 @@ export async function setupConsoleLogSpy() {
4242
console.warn = stderr(warn)
4343

4444
console.dir = (item, options) => {
45-
sendLog('stdout', utilInspect(item, options))
45+
sendLog('stdout', inspect(item, options))
4646
return dir(item, options)
4747
}
4848

packages/runner/src/suite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ function formatTitle(template: string, items: any[], idx: number) {
298298
let formatted = format(template, ...items.slice(0, count))
299299
if (isObject(items[0])) {
300300
formatted = formatted.replace(/\$([$\w_.]+)/g,
301-
(_, key) => objDisplay(objectAttr(items[0], key), runner?.config?.chaiConfig) as unknown as string,
301+
(_, key) => objDisplay(objectAttr(items[0], key), { truncate: runner?.config?.chaiConfig?.truncateThreshold }) as unknown as string,
302302
// https://github.com/chaijs/chai/pull/1490
303303
)
304304
}

packages/utils/src/display.ts

Lines changed: 84 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,99 @@
1-
// eslint-disable-next-line unicorn/prefer-node-protocol
2-
import * as util from 'util'
3-
1+
// since this is already part of Vitest via Chai, we can just reuse it without increasing the size of bundle
42
// @ts-expect-error doesn't have types
5-
import loupeImport from 'loupe'
3+
import { inspect as loupe } from 'loupe'
64

75
interface LoupeOptions {
8-
truncateThreshold?: number
6+
showHidden?: boolean | undefined
7+
depth?: number | null | undefined
8+
colors?: boolean | undefined
9+
customInspect?: boolean | undefined
10+
showProxy?: boolean | undefined
11+
maxArrayLength?: number | null | undefined
12+
maxStringLength?: number | null | undefined
13+
breakLength?: number | undefined
14+
compact?: boolean | number | undefined
15+
sorted?: boolean | ((a: string, b: string) => number) | undefined
16+
getters?: 'get' | 'set' | boolean | undefined
17+
numericSeparator?: boolean | undefined
18+
truncate?: number
919
}
1020

11-
const loupe = (typeof loupeImport.default === 'function' ? loupeImport.default : loupeImport)
21+
const formatRegExp = /%[sdj%]/g
1222

13-
export function format(...args: any[]) {
14-
return util.format(...args)
15-
}
23+
export function format(...args: unknown[]) {
24+
if (typeof args[0] !== 'string') {
25+
const objects = []
26+
for (let i = 0; i < args.length; i++)
27+
objects.push(inspect(args[i]))
28+
return objects.join(' ')
29+
}
30+
31+
const len = args.length
32+
let i = 1
33+
const template = args[0]
34+
let str = String(template).replace(formatRegExp, (x) => {
35+
if (x === '%%')
36+
return '%'
37+
if (i >= len)
38+
return x
39+
switch (x) {
40+
case '%s': {
41+
const value = args[i++]
42+
if (typeof value === 'bigint')
43+
return `${value.toString()}n`
44+
if (typeof value === 'number' && value === 0 && 1 / value < 0)
45+
return '-0'
46+
if (typeof value === 'object' && value !== null)
47+
return inspect(value, { depth: 0, colors: false, compact: 3 })
48+
return String(value)
49+
}
50+
case '%d': {
51+
const value = args[i++]
52+
if (typeof value === 'bigint')
53+
return `${value.toString()}n`
54+
return Number(value).toString()
55+
}
56+
case '%i': {
57+
const value = args[i++]
58+
if (typeof value === 'bigint')
59+
return `${value.toString()}n`
60+
return Number.parseInt(String(value)).toString()
61+
}
62+
case '%f': return Number.parseFloat(String(args[i++])).toString()
63+
case '%o': return inspect(args[i++], { showHidden: true, showProxy: true })
64+
case '%O': return inspect(args[i++])
65+
case '%c': return ''
66+
case '%j':
67+
try {
68+
return JSON.stringify(args[i++])
69+
}
70+
catch (_) {
71+
return '[Circular]'
72+
}
73+
default:
74+
return x
75+
}
76+
})
77+
78+
for (let x = args[i]; i < len; x = args[++i]) {
79+
if (x === null || typeof x !== 'object')
80+
str += ` ${x}`
1681

17-
export function utilInspect(item: unknown, options?: util.InspectOptions) {
18-
return util.inspect(item, options)
82+
else
83+
str += ` ${inspect(x)}`
84+
}
85+
return str
1986
}
2087

21-
// chai utils
22-
export function loupeInspect(obj: unknown, options: LoupeOptions = {}): string {
23-
return loupe(obj, {
24-
depth: 2,
25-
truncate: options.truncateThreshold === 0
26-
? Infinity
27-
: (options.truncateThreshold ?? 40),
28-
})
88+
export function inspect(obj: unknown, options: LoupeOptions = {}) {
89+
if (options.truncate === 0)
90+
options.truncate = Infinity
91+
return loupe(obj, options)
2992
}
3093

3194
export function objDisplay(obj: unknown, options: LoupeOptions = {}): string {
32-
const truncateThreshold = options.truncateThreshold ?? 40
33-
const str = loupeInspect(obj, options)
95+
const truncateThreshold = options.truncate ?? 40
96+
const str = inspect(obj, options)
3497
const type = Object.prototype.toString.call(obj)
3598

3699
if (truncateThreshold && str.length >= truncateThreshold) {

0 commit comments

Comments
 (0)