Skip to content

Commit

Permalink
feat: don't rely on util package in @vitest/utils (#3685)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va authored Jun 27, 2023
1 parent e3c0c43 commit f91da48
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 24 deletions.
4 changes: 2 additions & 2 deletions packages/browser/src/client/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { importId } from './utils'
const { Date, console } = globalThis

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

console.dir = (item, options) => {
sendLog('stdout', utilInspect(item, options))
sendLog('stdout', inspect(item, options))
return dir(item, options)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/runner/src/suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ function formatTitle(template: string, items: any[], idx: number) {
let formatted = format(template, ...items.slice(0, count))
if (isObject(items[0])) {
formatted = formatted.replace(/\$([$\w_.]+)/g,
(_, key) => objDisplay(objectAttr(items[0], key), runner?.config?.chaiConfig) as unknown as string,
(_, key) => objDisplay(objectAttr(items[0], key), { truncate: runner?.config?.chaiConfig?.truncateThreshold }) as unknown as string,
// https://github.com/chaijs/chai/pull/1490
)
}
Expand Down
105 changes: 84 additions & 21 deletions packages/utils/src/display.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,99 @@
// eslint-disable-next-line unicorn/prefer-node-protocol
import * as util from 'util'

// since this is already part of Vitest via Chai, we can just reuse it without increasing the size of bundle
// @ts-expect-error doesn't have types
import loupeImport from 'loupe'
import { inspect as loupe } from 'loupe'

interface LoupeOptions {
truncateThreshold?: number
showHidden?: boolean | undefined
depth?: number | null | undefined
colors?: boolean | undefined
customInspect?: boolean | undefined
showProxy?: boolean | undefined
maxArrayLength?: number | null | undefined
maxStringLength?: number | null | undefined
breakLength?: number | undefined
compact?: boolean | number | undefined
sorted?: boolean | ((a: string, b: string) => number) | undefined
getters?: 'get' | 'set' | boolean | undefined
numericSeparator?: boolean | undefined
truncate?: number
}

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

export function format(...args: any[]) {
return util.format(...args)
}
export function format(...args: unknown[]) {
if (typeof args[0] !== 'string') {
const objects = []
for (let i = 0; i < args.length; i++)
objects.push(inspect(args[i]))
return objects.join(' ')
}

const len = args.length
let i = 1
const template = args[0]
let str = String(template).replace(formatRegExp, (x) => {
if (x === '%%')
return '%'
if (i >= len)
return x
switch (x) {
case '%s': {
const value = args[i++]
if (typeof value === 'bigint')
return `${value.toString()}n`
if (typeof value === 'number' && value === 0 && 1 / value < 0)
return '-0'
if (typeof value === 'object' && value !== null)
return inspect(value, { depth: 0, colors: false, compact: 3 })
return String(value)
}
case '%d': {
const value = args[i++]
if (typeof value === 'bigint')
return `${value.toString()}n`
return Number(value).toString()
}
case '%i': {
const value = args[i++]
if (typeof value === 'bigint')
return `${value.toString()}n`
return Number.parseInt(String(value)).toString()
}
case '%f': return Number.parseFloat(String(args[i++])).toString()
case '%o': return inspect(args[i++], { showHidden: true, showProxy: true })
case '%O': return inspect(args[i++])
case '%c': return ''
case '%j':
try {
return JSON.stringify(args[i++])
}
catch (_) {
return '[Circular]'
}
default:
return x
}
})

for (let x = args[i]; i < len; x = args[++i]) {
if (x === null || typeof x !== 'object')
str += ` ${x}`

export function utilInspect(item: unknown, options?: util.InspectOptions) {
return util.inspect(item, options)
else
str += ` ${inspect(x)}`
}
return str
}

// chai utils
export function loupeInspect(obj: unknown, options: LoupeOptions = {}): string {
return loupe(obj, {
depth: 2,
truncate: options.truncateThreshold === 0
? Infinity
: (options.truncateThreshold ?? 40),
})
export function inspect(obj: unknown, options: LoupeOptions = {}) {
if (options.truncate === 0)
options.truncate = Infinity
return loupe(obj, options)
}

export function objDisplay(obj: unknown, options: LoupeOptions = {}): string {
const truncateThreshold = options.truncateThreshold ?? 40
const str = loupeInspect(obj, options)
const truncateThreshold = options.truncate ?? 40
const str = inspect(obj, options)
const type = Object.prototype.toString.call(obj)

if (truncateThreshold && str.length >= truncateThreshold) {
Expand Down

0 comments on commit f91da48

Please sign in to comment.