Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: don't rely on util package in @vitest/utils #3685

Merged
merged 2 commits into from Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/browser/src/client/logger.ts
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
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
@@ -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