@vitest/utils
Advanced tools
Comparing version 0.29.8 to 0.30.0
@@ -1,11 +0,174 @@ | ||
declare function formatLine(line: string, outputTruncateLength?: number): string; | ||
type Color = (str: string) => string; | ||
import { DisplayOptions } from 'concordance'; | ||
declare function getConcordanceTheme(): { | ||
boolean: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
circular: string; | ||
date: { | ||
invalid: string; | ||
value: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
}; | ||
diffGutters: { | ||
actual: string; | ||
expected: string; | ||
padding: string; | ||
}; | ||
error: { | ||
ctor: { | ||
open: string; | ||
close: string; | ||
}; | ||
name: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
}; | ||
function: { | ||
name: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
stringTag: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
}; | ||
global: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
item: { | ||
after: string; | ||
}; | ||
list: { | ||
openBracket: string; | ||
closeBracket: string; | ||
}; | ||
mapEntry: { | ||
after: string; | ||
}; | ||
maxDepth: string; | ||
null: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
number: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
object: { | ||
openBracket: string; | ||
closeBracket: string; | ||
ctor: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
stringTag: { | ||
open: string; | ||
close: string; | ||
}; | ||
secondaryStringTag: { | ||
open: string; | ||
close: string; | ||
}; | ||
}; | ||
property: { | ||
after: string; | ||
keyBracket: { | ||
open: string; | ||
close: string; | ||
}; | ||
valueFallback: string; | ||
}; | ||
regexp: { | ||
source: { | ||
open: string; | ||
close: string; | ||
}; | ||
flags: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
}; | ||
stats: { | ||
separator: string; | ||
}; | ||
string: { | ||
open: string; | ||
close: string; | ||
line: { | ||
open: string; | ||
close: string; | ||
}; | ||
multiline: { | ||
start: string; | ||
end: string; | ||
}; | ||
controlPicture: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
diff: { | ||
insert: { | ||
open: string; | ||
close: string; | ||
}; | ||
delete: { | ||
open: string; | ||
close: string; | ||
}; | ||
equal: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
insertLine: { | ||
open: string; | ||
close: string; | ||
}; | ||
deleteLine: { | ||
open: string; | ||
close: string; | ||
}; | ||
}; | ||
}; | ||
symbol: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
typedArray: { | ||
bytes: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
}; | ||
undefined: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
}; | ||
declare function diffDescriptors(actual: unknown, expected: unknown, options: DisplayOptions): string; | ||
declare function formatDescriptor(value: unknown, options: DisplayOptions): string; | ||
interface DiffOptions { | ||
outputDiffMaxLines?: number; | ||
outputTruncateLength?: number; | ||
outputDiffLines?: number; | ||
showLegend?: boolean; | ||
colorSuccess?: Color; | ||
colorError?: Color; | ||
colorDim?: Color; | ||
} | ||
@@ -20,4 +183,4 @@ /** | ||
*/ | ||
declare function unifiedDiff(actual: string, expected: string, options?: DiffOptions): string; | ||
declare function unifiedDiff(actual: unknown, expected: unknown, options?: DiffOptions): string; | ||
export { DiffOptions, formatLine, unifiedDiff }; | ||
export { DiffOptions, diffDescriptors, formatDescriptor, getConcordanceTheme, unifiedDiff }; |
191
dist/diff.js
@@ -1,15 +0,94 @@ | ||
import * as diff from 'diff'; | ||
import cliTruncate from 'cli-truncate'; | ||
import { b as getColors } from './chunk-colors.js'; | ||
import concordance from 'concordance'; | ||
function formatLine(line, outputTruncateLength) { | ||
var _a; | ||
return cliTruncate(line, (outputTruncateLength ?? (((_a = process.stdout) == null ? void 0 : _a.columns) || 80)) - 4); | ||
function getConcordanceTheme() { | ||
const c = getColors(); | ||
return { | ||
boolean: c.yellow, | ||
circular: c.gray("[Circular]"), | ||
date: { | ||
invalid: c.red("invalid"), | ||
value: c.blue | ||
}, | ||
diffGutters: { | ||
actual: ` ${c.red("-")} `, | ||
expected: ` ${c.green("+")} `, | ||
padding: " " | ||
}, | ||
error: { | ||
ctor: { open: `${c.gray.open}(`, close: `)${c.gray.close}` }, | ||
name: c.magenta | ||
}, | ||
function: { | ||
name: c.blue, | ||
stringTag: c.magenta | ||
}, | ||
global: c.magenta, | ||
item: { after: c.gray(",") }, | ||
list: { openBracket: c.gray("["), closeBracket: c.gray("]") }, | ||
mapEntry: { after: c.gray(",") }, | ||
maxDepth: c.gray("\u2026"), | ||
null: c.yellow, | ||
number: c.yellow, | ||
object: { | ||
openBracket: c.gray("{"), | ||
closeBracket: c.gray("}"), | ||
ctor: c.magenta, | ||
stringTag: { open: `${c.magenta.open}@`, close: c.magenta.close }, | ||
secondaryStringTag: { open: `${c.gray.open}@`, close: c.gray.close } | ||
}, | ||
property: { | ||
after: c.gray(","), | ||
keyBracket: { open: c.gray("["), close: c.gray("]") }, | ||
valueFallback: c.gray("\u2026") | ||
}, | ||
regexp: { | ||
source: { open: `${c.blue.open}/`, close: `/${c.blue.close}` }, | ||
flags: c.yellow | ||
}, | ||
stats: { separator: c.gray("---") }, | ||
string: { | ||
open: c.blue.open, | ||
close: c.blue.close, | ||
line: { open: c.blue("'"), close: c.blue("'") }, | ||
multiline: { start: c.blue("`"), end: c.blue("`") }, | ||
controlPicture: c.gray, | ||
diff: { | ||
insert: { | ||
open: c.bgGreen.open + c.black.open, | ||
close: c.black.close + c.bgGreen.close | ||
}, | ||
delete: { | ||
open: c.bgRed.open + c.black.open, | ||
close: c.black.close + c.bgRed.close | ||
}, | ||
equal: c.blue, | ||
insertLine: { | ||
open: c.green.open, | ||
close: c.green.close | ||
}, | ||
deleteLine: { | ||
open: c.red.open, | ||
close: c.red.close | ||
} | ||
} | ||
}, | ||
symbol: c.yellow, | ||
typedArray: { | ||
bytes: c.yellow | ||
}, | ||
undefined: c.yellow | ||
}; | ||
} | ||
function diffDescriptors(actual, expected, options) { | ||
return concordance.diff(expected, actual, options); | ||
} | ||
function formatDescriptor(value, options) { | ||
return concordance.formatDescriptor(value, options); | ||
} | ||
function unifiedDiff(actual, expected, options = {}) { | ||
if (actual === expected) | ||
return ""; | ||
const { outputTruncateLength, outputDiffLines, outputDiffMaxLines, showLegend = true } = options; | ||
const indent = " "; | ||
const diffLimit = outputDiffLines || 15; | ||
const diffMaxLines = outputDiffMaxLines || 50; | ||
const theme = getConcordanceTheme(); | ||
const diff = diffDescriptors(actual, expected, { theme }); | ||
const { showLegend = true } = options; | ||
const counts = { | ||
@@ -19,80 +98,22 @@ "+": 0, | ||
}; | ||
let previousState = null; | ||
let previousCount = 0; | ||
const str = (str2) => str2; | ||
const dim = options.colorDim || str; | ||
const green = options.colorSuccess || str; | ||
const red = options.colorError || str; | ||
function preprocess(line) { | ||
if (!line || line.match(/\\ No newline/)) | ||
return; | ||
const char = line[0]; | ||
if ("-+".includes(char)) { | ||
if (previousState !== char) { | ||
previousState = char; | ||
previousCount = 0; | ||
} | ||
previousCount++; | ||
counts[char]++; | ||
if (previousCount === diffLimit) | ||
return dim(`${char} ...`); | ||
else if (previousCount > diffLimit) | ||
return; | ||
} | ||
return line; | ||
} | ||
const msg = diff.createPatch("string", expected, actual); | ||
let lines = msg.split("\n").slice(5).map(preprocess).filter(Boolean); | ||
let moreLines = 0; | ||
const isCompact = counts["+"] === 1 && counts["-"] === 1 && lines.length === 2; | ||
if (lines.length > diffMaxLines) { | ||
const firstDiff = lines.findIndex((line) => line[0] === "-" || line[0] === "+"); | ||
const displayLines = lines.slice(firstDiff - 2, diffMaxLines); | ||
const lastDisplayedIndex = firstDiff - 2 + diffMaxLines; | ||
if (lastDisplayedIndex < lines.length) | ||
moreLines = lines.length - lastDisplayedIndex; | ||
lines = displayLines; | ||
} | ||
let formatted = lines.map((line) => { | ||
line = line.replace(/\\"/g, '"'); | ||
if (line[0] === "-") { | ||
line = formatLine(line.slice(1), outputTruncateLength); | ||
if (isCompact) | ||
return green(line); | ||
return green(`- ${formatLine(line, outputTruncateLength)}`); | ||
} | ||
if (line[0] === "+") { | ||
line = formatLine(line.slice(1), outputTruncateLength); | ||
if (isCompact) | ||
return red(line); | ||
return red(`+ ${formatLine(line, outputTruncateLength)}`); | ||
} | ||
if (line.match(/@@/)) | ||
return "--"; | ||
return ` ${line}`; | ||
const c = getColors(); | ||
const plus = theme.diffGutters.actual; | ||
const minus = ` ${c.green("+")}`; | ||
const lines = diff.split(/\r?\n/g); | ||
lines.forEach((line) => { | ||
if (line.startsWith(plus)) | ||
counts["+"]++; | ||
else if (line.startsWith(minus)) | ||
counts["-"]++; | ||
}); | ||
if (moreLines) | ||
formatted.push(dim(`... ${moreLines} more lines`)); | ||
let legend = ""; | ||
if (showLegend) { | ||
if (isCompact) { | ||
formatted = [ | ||
`${green("- Expected")} ${formatted[0]}`, | ||
`${red("+ Received")} ${formatted[1]}` | ||
]; | ||
} else { | ||
if (formatted[0].includes('"')) | ||
formatted[0] = formatted[0].replace('"', ""); | ||
const last = formatted.length - 1; | ||
if (formatted[last].endsWith('"')) | ||
formatted[last] = formatted[last].slice(0, formatted[last].length - 1); | ||
formatted.unshift( | ||
green(`- Expected - ${counts["-"]}`), | ||
red(`+ Received + ${counts["+"]}`), | ||
"" | ||
); | ||
} | ||
legend = ` ${c.green(`- Expected - ${counts["-"]}`)} | ||
${c.red(`+ Received + ${counts["+"]}`)} | ||
`; | ||
} | ||
return formatted.map((i) => i ? indent + i : i).join("\n"); | ||
return legend + diff.replace(/␊\s*$/mg, ""); | ||
} | ||
export { formatLine, unifiedDiff }; | ||
export { diffDescriptors, formatDescriptor, getConcordanceTheme, unifiedDiff }; |
import { Nullable, Arrayable } from './types.js'; | ||
declare function notNullish<T>(v: T | null | undefined): v is NonNullable<T>; | ||
declare function assertTypes(value: unknown, name: string, types: string[]): void; | ||
declare function isPrimitive(value: unknown): boolean; | ||
declare function slash(path: string): string; | ||
@@ -19,3 +21,13 @@ declare function parseRegexp(input: string): RegExp; | ||
declare function createDefer<T>(): DeferPromise<T>; | ||
/** | ||
* If code starts with a function call, will return its last index, respecting arguments. | ||
* This will return 25 - last ending character of toMatch ")" | ||
* Also works with callbacks | ||
* ``` | ||
* toMatch({ test: '123' }); | ||
* toBeAliased('123') | ||
* ``` | ||
*/ | ||
declare function getCallLastIndex(code: string): number | null; | ||
export { assertTypes, clone, createDefer, deepClone, getOwnProperties, getType, isObject, noop, objectAttr, parseRegexp, slash, toArray }; | ||
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray }; |
@@ -0,1 +1,4 @@ | ||
function notNullish(v) { | ||
return v != null; | ||
} | ||
function assertTypes(value, name, types) { | ||
@@ -7,2 +10,5 @@ const receivedType = typeof value; | ||
} | ||
function isPrimitive(value) { | ||
return value === null || typeof value !== "function" && typeof value !== "object"; | ||
} | ||
function slash(path) { | ||
@@ -112,3 +118,31 @@ return path.replace(/\\/g, "/"); | ||
} | ||
function getCallLastIndex(code) { | ||
let charIndex = -1; | ||
let inString = null; | ||
let startedBracers = 0; | ||
let endedBracers = 0; | ||
let beforeChar = null; | ||
while (charIndex <= code.length) { | ||
beforeChar = code[charIndex]; | ||
charIndex++; | ||
const char = code[charIndex]; | ||
const isCharString = char === '"' || char === "'" || char === "`"; | ||
if (isCharString && beforeChar !== "\\") { | ||
if (inString === char) | ||
inString = null; | ||
else if (!inString) | ||
inString = char; | ||
} | ||
if (!inString) { | ||
if (char === "(") | ||
startedBracers++; | ||
if (char === ")") | ||
endedBracers++; | ||
} | ||
if (startedBracers && endedBracers && startedBracers === endedBracers) | ||
return charIndex; | ||
} | ||
return null; | ||
} | ||
export { assertTypes, clone, createDefer, deepClone, getOwnProperties, getType, isObject, noop, objectAttr, parseRegexp, slash, toArray }; | ||
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray }; |
@@ -1,2 +0,3 @@ | ||
export { assertTypes, clone, createDefer, deepClone, getOwnProperties, getType, isObject, noop, objectAttr, parseRegexp, slash, toArray } from './helpers.js'; | ||
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray } from './helpers.js'; | ||
import { ParsedStack, ErrorWithDiff } from './types.js'; | ||
export { ArgumentsType, Arrayable, Awaitable, Constructable, DeepMerge, MergeInsertions, MutableArray, Nullable } from './types.js'; | ||
@@ -59,3 +60,7 @@ import { PrettyFormatOptions } from 'pretty-format'; | ||
type ColorsMethods = { | ||
[Key in ColorName]: (input: unknown) => string; | ||
[Key in ColorName]: { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
}; | ||
}; | ||
@@ -82,2 +87,9 @@ type Colors = ColorsMethods & { | ||
export { SAFE_COLORS_SYMBOL, SAFE_TIMERS_SYMBOL, createColors, createSimpleStackTrace, format, getColors, getDefaultColors, getSafeTimers, loupeInspect, objDisplay, setSafeTimers, setupColors, shuffle, stringify, utilInspect }; | ||
declare const lineSplitRE: RegExp; | ||
declare function parseSingleStack(raw: string): ParsedStack | null; | ||
declare function parseStacktrace(stack: string, ignore?: (string | RegExp)[]): ParsedStack[]; | ||
declare function parseErrorStacktrace(e: ErrorWithDiff, ignore?: (string | RegExp)[]): ParsedStack[]; | ||
declare function positionToOffset(source: string, lineNumber: number, columnNumber: number): number; | ||
declare function offsetToLineNumber(source: string, offset: number): number; | ||
export { ErrorWithDiff, ParsedStack, SAFE_COLORS_SYMBOL, SAFE_TIMERS_SYMBOL, createColors, createSimpleStackTrace, format, getColors, getDefaultColors, getSafeTimers, lineSplitRE, loupeInspect, objDisplay, offsetToLineNumber, parseErrorStacktrace, parseSingleStack, parseStacktrace, positionToOffset, setSafeTimers, setupColors, shuffle, stringify, utilInspect }; |
@@ -1,3 +0,6 @@ | ||
export { assertTypes, clone, createDefer, deepClone, getOwnProperties, getType, isObject, noop, objectAttr, parseRegexp, slash, toArray } from './helpers.js'; | ||
import { notNullish, isPrimitive } from './helpers.js'; | ||
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, noop, objectAttr, parseRegexp, slash, toArray } from './helpers.js'; | ||
import { format as format$1, plugins } from 'pretty-format'; | ||
import { S as SAFE_TIMERS_SYMBOL } from './chunk-colors.js'; | ||
export { a as SAFE_COLORS_SYMBOL, c as createColors, b as getColors, g as getDefaultColors, s as setupColors } from './chunk-colors.js'; | ||
import util from 'util'; | ||
@@ -29,2 +32,3 @@ import loupeImport from 'loupe'; | ||
escapeString: false, | ||
// min: true, | ||
plugins: PLUGINS, | ||
@@ -38,2 +42,3 @@ ...options | ||
escapeString: false, | ||
// min: true, | ||
plugins: PLUGINS, | ||
@@ -46,5 +51,2 @@ ...options | ||
const SAFE_TIMERS_SYMBOL = Symbol("vitest:SAFE_TIMERS"); | ||
const SAFE_COLORS_SYMBOL = Symbol("vitest:SAFE_COLORS"); | ||
function getSafeTimers() { | ||
@@ -147,73 +149,2 @@ const { | ||
const colorsMap = { | ||
bold: ["\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"], | ||
dim: ["\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"], | ||
italic: ["\x1B[3m", "\x1B[23m"], | ||
underline: ["\x1B[4m", "\x1B[24m"], | ||
inverse: ["\x1B[7m", "\x1B[27m"], | ||
hidden: ["\x1B[8m", "\x1B[28m"], | ||
strikethrough: ["\x1B[9m", "\x1B[29m"], | ||
black: ["\x1B[30m", "\x1B[39m"], | ||
red: ["\x1B[31m", "\x1B[39m"], | ||
green: ["\x1B[32m", "\x1B[39m"], | ||
yellow: ["\x1B[33m", "\x1B[39m"], | ||
blue: ["\x1B[34m", "\x1B[39m"], | ||
magenta: ["\x1B[35m", "\x1B[39m"], | ||
cyan: ["\x1B[36m", "\x1B[39m"], | ||
white: ["\x1B[37m", "\x1B[39m"], | ||
gray: ["\x1B[90m", "\x1B[39m"], | ||
bgBlack: ["\x1B[40m", "\x1B[49m"], | ||
bgRed: ["\x1B[41m", "\x1B[49m"], | ||
bgGreen: ["\x1B[42m", "\x1B[49m"], | ||
bgYellow: ["\x1B[43m", "\x1B[49m"], | ||
bgBlue: ["\x1B[44m", "\x1B[49m"], | ||
bgMagenta: ["\x1B[45m", "\x1B[49m"], | ||
bgCyan: ["\x1B[46m", "\x1B[49m"], | ||
bgWhite: ["\x1B[47m", "\x1B[49m"] | ||
}; | ||
const colorsEntries = Object.entries(colorsMap); | ||
const string = (str) => String(str); | ||
string.open = ""; | ||
string.close = ""; | ||
const defaultColors = colorsEntries.reduce((acc, [key]) => { | ||
acc[key] = string; | ||
return acc; | ||
}, { isColorSupported: false }); | ||
function getDefaultColors() { | ||
return { ...defaultColors }; | ||
} | ||
function getColors() { | ||
return globalThis[SAFE_COLORS_SYMBOL] || defaultColors; | ||
} | ||
function createColors(isTTY = false) { | ||
const enabled = typeof process !== "undefined" && !("NO_COLOR" in process.env || process.argv.includes("--no-color")) && !("GITHUB_ACTIONS" in process.env) && ("FORCE_COLOR" in process.env || process.argv.includes("--color") || process.platform === "win32" || isTTY && process.env.TERM !== "dumb" || "CI" in process.env); | ||
const replaceClose = (string2, close, replace, index) => { | ||
const start = string2.substring(0, index) + replace; | ||
const end = string2.substring(index + close.length); | ||
const nextIndex = end.indexOf(close); | ||
return ~nextIndex ? start + replaceClose(end, close, replace, nextIndex) : start + end; | ||
}; | ||
const formatter = (open, close, replace = open) => { | ||
const fn = (input) => { | ||
const string2 = String(input); | ||
const index = string2.indexOf(close, open.length); | ||
return ~index ? open + replaceClose(string2, close, replace, index) + close : open + string2 + close; | ||
}; | ||
fn.open = open; | ||
fn.close = close; | ||
return fn; | ||
}; | ||
const colorsObject = { | ||
isColorSupported: enabled, | ||
reset: enabled ? (s) => `\x1B[0m${s}\x1B[0m` : string | ||
}; | ||
for (const [name, formatterArgs] of colorsEntries) { | ||
colorsObject[name] = enabled ? formatter(...formatterArgs) : string; | ||
} | ||
return colorsObject; | ||
} | ||
function setupColors(colors) { | ||
globalThis[SAFE_COLORS_SYMBOL] = colors; | ||
} | ||
function createSimpleStackTrace(options) { | ||
@@ -232,2 +163,190 @@ const { message = "error", stackTraceLimit = 1 } = options || {}; | ||
export { SAFE_COLORS_SYMBOL, SAFE_TIMERS_SYMBOL, createColors, createSimpleStackTrace, format, getColors, getDefaultColors, getSafeTimers, loupeInspect, objDisplay, setSafeTimers, setupColors, shuffle, stringify, utilInspect }; | ||
function normalizeWindowsPath(input = "") { | ||
if (!input || !input.includes("\\")) { | ||
return input; | ||
} | ||
return input.replace(/\\/g, "/"); | ||
} | ||
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/; | ||
function cwd() { | ||
if (typeof process !== "undefined") { | ||
return process.cwd().replace(/\\/g, "/"); | ||
} | ||
return "/"; | ||
} | ||
const resolve = function(...arguments_) { | ||
arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument)); | ||
let resolvedPath = ""; | ||
let resolvedAbsolute = false; | ||
for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) { | ||
const path = index >= 0 ? arguments_[index] : cwd(); | ||
if (!path || path.length === 0) { | ||
continue; | ||
} | ||
resolvedPath = `${path}/${resolvedPath}`; | ||
resolvedAbsolute = isAbsolute(path); | ||
} | ||
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute); | ||
if (resolvedAbsolute && !isAbsolute(resolvedPath)) { | ||
return `/${resolvedPath}`; | ||
} | ||
return resolvedPath.length > 0 ? resolvedPath : "."; | ||
}; | ||
function normalizeString(path, allowAboveRoot) { | ||
let res = ""; | ||
let lastSegmentLength = 0; | ||
let lastSlash = -1; | ||
let dots = 0; | ||
let char = null; | ||
for (let index = 0; index <= path.length; ++index) { | ||
if (index < path.length) { | ||
char = path[index]; | ||
} else if (char === "/") { | ||
break; | ||
} else { | ||
char = "/"; | ||
} | ||
if (char === "/") { | ||
if (lastSlash === index - 1 || dots === 1) ; else if (dots === 2) { | ||
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") { | ||
if (res.length > 2) { | ||
const lastSlashIndex = res.lastIndexOf("/"); | ||
if (lastSlashIndex === -1) { | ||
res = ""; | ||
lastSegmentLength = 0; | ||
} else { | ||
res = res.slice(0, lastSlashIndex); | ||
lastSegmentLength = res.length - 1 - res.lastIndexOf("/"); | ||
} | ||
lastSlash = index; | ||
dots = 0; | ||
continue; | ||
} else if (res.length > 0) { | ||
res = ""; | ||
lastSegmentLength = 0; | ||
lastSlash = index; | ||
dots = 0; | ||
continue; | ||
} | ||
} | ||
if (allowAboveRoot) { | ||
res += res.length > 0 ? "/.." : ".."; | ||
lastSegmentLength = 2; | ||
} | ||
} else { | ||
if (res.length > 0) { | ||
res += `/${path.slice(lastSlash + 1, index)}`; | ||
} else { | ||
res = path.slice(lastSlash + 1, index); | ||
} | ||
lastSegmentLength = index - lastSlash - 1; | ||
} | ||
lastSlash = index; | ||
dots = 0; | ||
} else if (char === "." && dots !== -1) { | ||
++dots; | ||
} else { | ||
dots = -1; | ||
} | ||
} | ||
return res; | ||
} | ||
const isAbsolute = function(p) { | ||
return _IS_ABSOLUTE_RE.test(p); | ||
}; | ||
const lineSplitRE = /\r?\n/; | ||
const stackIgnorePatterns = [ | ||
"node:internal", | ||
/\/packages\/\w+\/dist\//, | ||
/\/@vitest\/\w+\/dist\//, | ||
"/vitest/dist/", | ||
"/vitest/src/", | ||
"/vite-node/dist/", | ||
"/vite-node/src/", | ||
"/node_modules/chai/", | ||
"/node_modules/tinypool/", | ||
"/node_modules/tinyspy/" | ||
]; | ||
function extractLocation(urlLike) { | ||
if (!urlLike.includes(":")) | ||
return [urlLike]; | ||
const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/; | ||
const parts = regExp.exec(urlLike.replace(/[()]/g, "")); | ||
if (!parts) | ||
return [urlLike]; | ||
return [parts[1], parts[2] || void 0, parts[3] || void 0]; | ||
} | ||
function parseSingleStack(raw) { | ||
let line = raw.trim(); | ||
if (line.includes("(eval ")) | ||
line = line.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, ""); | ||
let sanitizedLine = line.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, ""); | ||
const location = sanitizedLine.match(/ (\(.+\)$)/); | ||
sanitizedLine = location ? sanitizedLine.replace(location[0], "") : sanitizedLine; | ||
const [url, lineNumber, columnNumber] = extractLocation(location ? location[1] : sanitizedLine); | ||
let method = location && sanitizedLine || ""; | ||
let file = url && ["eval", "<anonymous>"].includes(url) ? void 0 : url; | ||
if (!file || !lineNumber || !columnNumber) | ||
return null; | ||
if (method.startsWith("async ")) | ||
method = method.slice(6); | ||
if (file.startsWith("file://")) | ||
file = file.slice(7); | ||
file = resolve(file); | ||
return { | ||
method, | ||
file, | ||
line: parseInt(lineNumber), | ||
column: parseInt(columnNumber) | ||
}; | ||
} | ||
function parseStacktrace(stack, ignore = stackIgnorePatterns) { | ||
const stackFrames = stack.split("\n").map((raw) => { | ||
const stack2 = parseSingleStack(raw); | ||
if (!stack2 || ignore.length && ignore.some((p) => stack2.file.match(p))) | ||
return null; | ||
return stack2; | ||
}).filter(notNullish); | ||
return stackFrames; | ||
} | ||
function parseErrorStacktrace(e, ignore = stackIgnorePatterns) { | ||
if (!e || isPrimitive(e)) | ||
return []; | ||
if (e.stacks) | ||
return e.stacks; | ||
const stackStr = e.stack || e.stackStr || ""; | ||
const stackFrames = parseStacktrace(stackStr, ignore); | ||
e.stacks = stackFrames; | ||
return stackFrames; | ||
} | ||
function positionToOffset(source, lineNumber, columnNumber) { | ||
const lines = source.split(lineSplitRE); | ||
const nl = /\r\n/.test(source) ? 2 : 1; | ||
let start = 0; | ||
if (lineNumber > lines.length) | ||
return source.length; | ||
for (let i = 0; i < lineNumber - 1; i++) | ||
start += lines[i].length + nl; | ||
return start + columnNumber; | ||
} | ||
function offsetToLineNumber(source, offset) { | ||
if (offset > source.length) { | ||
throw new Error( | ||
`offset is longer than source length! offset ${offset} > length ${source.length}` | ||
); | ||
} | ||
const lines = source.split(lineSplitRE); | ||
const nl = /\r\n/.test(source) ? 2 : 1; | ||
let counted = 0; | ||
let line = 0; | ||
for (; line < lines.length; line++) { | ||
const lineLength = lines[line].length + nl; | ||
if (counted + lineLength >= offset) | ||
break; | ||
counted += lineLength; | ||
} | ||
return line + 1; | ||
} | ||
export { SAFE_TIMERS_SYMBOL, createSimpleStackTrace, format, getSafeTimers, isPrimitive, lineSplitRE, loupeInspect, notNullish, objDisplay, offsetToLineNumber, parseErrorStacktrace, parseSingleStack, parseStacktrace, positionToOffset, setSafeTimers, shuffle, stringify, utilInspect }; |
@@ -17,3 +17,23 @@ type Awaitable<T> = T | PromiseLike<T>; | ||
} | ||
interface ParsedStack { | ||
method: string; | ||
file: string; | ||
line: number; | ||
column: number; | ||
} | ||
interface ErrorWithDiff extends Error { | ||
name: string; | ||
nameStr?: string; | ||
stack?: string; | ||
stackStr?: string; | ||
stacks?: ParsedStack[]; | ||
showDiff?: boolean; | ||
actual?: any; | ||
expected?: any; | ||
operator?: string; | ||
type?: string; | ||
frame?: string; | ||
diff?: string; | ||
} | ||
export { ArgumentsType, Arrayable, Awaitable, Constructable, DeepMerge, MergeInsertions, MutableArray, Nullable }; | ||
export { ArgumentsType, Arrayable, Awaitable, Constructable, DeepMerge, ErrorWithDiff, MergeInsertions, MutableArray, Nullable, ParsedStack }; |
{ | ||
"name": "@vitest/utils", | ||
"type": "module", | ||
"version": "0.29.8", | ||
"version": "0.30.0", | ||
"description": "Shared Vitest utility functions", | ||
@@ -35,10 +35,6 @@ "license": "MIT", | ||
"dependencies": { | ||
"cli-truncate": "^3.1.0", | ||
"diff": "^5.1.0", | ||
"concordance": "^5.0.4", | ||
"loupe": "^2.3.6", | ||
"pretty-format": "^27.5.1" | ||
}, | ||
"devDependencies": { | ||
"@types/diff": "^5.0.2" | ||
}, | ||
"scripts": { | ||
@@ -45,0 +41,0 @@ "build": "rimraf dist && rollup -c", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
45078
3
0
12
1349
0
1
+ Addedconcordance@^5.0.4
+ Addedblueimp-md5@2.19.0(transitive)
+ Addedconcordance@5.0.4(transitive)
+ Addeddate-time@3.1.0(transitive)
+ Addedesutils@2.0.3(transitive)
+ Addedfast-diff@1.3.0(transitive)
+ Addedjs-string-escape@1.0.1(transitive)
+ Addedlodash@4.17.21(transitive)
+ Addedmd5-hex@3.0.1(transitive)
+ Addedsemver@7.6.3(transitive)
+ Addedtime-zone@1.0.0(transitive)
+ Addedwell-known-symbols@2.0.0(transitive)
- Removedcli-truncate@^3.1.0
- Removeddiff@^5.1.0
- Removedansi-regex@6.1.0(transitive)
- Removedansi-styles@6.2.1(transitive)
- Removedcli-truncate@3.1.0(transitive)
- Removeddiff@5.2.0(transitive)
- Removedeastasianwidth@0.2.0(transitive)
- Removedemoji-regex@9.2.2(transitive)
- Removedis-fullwidth-code-point@4.0.0(transitive)
- Removedslice-ansi@5.0.0(transitive)
- Removedstring-width@5.1.2(transitive)
- Removedstrip-ansi@7.1.0(transitive)