@vitest/utils
Advanced tools
Comparing version 2.0.1 to 2.0.2
@@ -1,2 +0,2 @@ | ||
import { format as format$1, plugins } from 'pretty-format'; | ||
import { format as format$1, plugins } from '@vitest/pretty-format'; | ||
import * as loupe from 'loupe'; | ||
@@ -3,0 +3,0 @@ |
@@ -1,4 +0,4 @@ | ||
import { D as DiffOptions } from './types-DyShQl4f.js'; | ||
export { a as DiffOptionsColor } from './types-DyShQl4f.js'; | ||
import 'pretty-format'; | ||
import { D as DiffOptions } from './types-Bxe-2Udy.js'; | ||
export { a as DiffOptionsColor } from './types-Bxe-2Udy.js'; | ||
import '@vitest/pretty-format'; | ||
@@ -5,0 +5,0 @@ /** |
825
dist/diff.js
@@ -1,4 +0,3 @@ | ||
import { format, plugins } from 'pretty-format'; | ||
import * as diff$1 from 'diff-sequences'; | ||
import { g as getColors } from './chunk-colors.js'; | ||
import { format, plugins } from '@vitest/pretty-format'; | ||
import c from 'tinyrainbow'; | ||
@@ -401,2 +400,801 @@ function getType(value) { | ||
var build = {}; | ||
Object.defineProperty(build, '__esModule', { | ||
value: true | ||
}); | ||
var _default = build.default = diffSequence; | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
*/ | ||
// This diff-sequences package implements the linear space variation in | ||
// An O(ND) Difference Algorithm and Its Variations by Eugene W. Myers | ||
// Relationship in notation between Myers paper and this package: | ||
// A is a | ||
// N is aLength, aEnd - aStart, and so on | ||
// x is aIndex, aFirst, aLast, and so on | ||
// B is b | ||
// M is bLength, bEnd - bStart, and so on | ||
// y is bIndex, bFirst, bLast, and so on | ||
// Δ = N - M is negative of baDeltaLength = bLength - aLength | ||
// D is d | ||
// k is kF | ||
// k + Δ is kF = kR - baDeltaLength | ||
// V is aIndexesF or aIndexesR (see comment below about Indexes type) | ||
// index intervals [1, N] and [1, M] are [0, aLength) and [0, bLength) | ||
// starting point in forward direction (0, 0) is (-1, -1) | ||
// starting point in reverse direction (N + 1, M + 1) is (aLength, bLength) | ||
// The “edit graph” for sequences a and b corresponds to items: | ||
// in a on the horizontal axis | ||
// in b on the vertical axis | ||
// | ||
// Given a-coordinate of a point in a diagonal, you can compute b-coordinate. | ||
// | ||
// Forward diagonals kF: | ||
// zero diagonal intersects top left corner | ||
// positive diagonals intersect top edge | ||
// negative diagonals insersect left edge | ||
// | ||
// Reverse diagonals kR: | ||
// zero diagonal intersects bottom right corner | ||
// positive diagonals intersect right edge | ||
// negative diagonals intersect bottom edge | ||
// The graph contains a directed acyclic graph of edges: | ||
// horizontal: delete an item from a | ||
// vertical: insert an item from b | ||
// diagonal: common item in a and b | ||
// | ||
// The algorithm solves dual problems in the graph analogy: | ||
// Find longest common subsequence: path with maximum number of diagonal edges | ||
// Find shortest edit script: path with minimum number of non-diagonal edges | ||
// Input callback function compares items at indexes in the sequences. | ||
// Output callback function receives the number of adjacent items | ||
// and starting indexes of each common subsequence. | ||
// Either original functions or wrapped to swap indexes if graph is transposed. | ||
// Indexes in sequence a of last point of forward or reverse paths in graph. | ||
// Myers algorithm indexes by diagonal k which for negative is bad deopt in V8. | ||
// This package indexes by iF and iR which are greater than or equal to zero. | ||
// and also updates the index arrays in place to cut memory in half. | ||
// kF = 2 * iF - d | ||
// kR = d - 2 * iR | ||
// Division of index intervals in sequences a and b at the middle change. | ||
// Invariant: intervals do not have common items at the start or end. | ||
const pkg = 'diff-sequences'; // for error messages | ||
const NOT_YET_SET = 0; // small int instead of undefined to avoid deopt in V8 | ||
// Return the number of common items that follow in forward direction. | ||
// The length of what Myers paper calls a “snake” in a forward path. | ||
const countCommonItemsF = (aIndex, aEnd, bIndex, bEnd, isCommon) => { | ||
let nCommon = 0; | ||
while (aIndex < aEnd && bIndex < bEnd && isCommon(aIndex, bIndex)) { | ||
aIndex += 1; | ||
bIndex += 1; | ||
nCommon += 1; | ||
} | ||
return nCommon; | ||
}; | ||
// Return the number of common items that precede in reverse direction. | ||
// The length of what Myers paper calls a “snake” in a reverse path. | ||
const countCommonItemsR = (aStart, aIndex, bStart, bIndex, isCommon) => { | ||
let nCommon = 0; | ||
while (aStart <= aIndex && bStart <= bIndex && isCommon(aIndex, bIndex)) { | ||
aIndex -= 1; | ||
bIndex -= 1; | ||
nCommon += 1; | ||
} | ||
return nCommon; | ||
}; | ||
// A simple function to extend forward paths from (d - 1) to d changes | ||
// when forward and reverse paths cannot yet overlap. | ||
const extendPathsF = ( | ||
d, | ||
aEnd, | ||
bEnd, | ||
bF, | ||
isCommon, | ||
aIndexesF, | ||
iMaxF // return the value because optimization might decrease it | ||
) => { | ||
// Unroll the first iteration. | ||
let iF = 0; | ||
let kF = -d; // kF = 2 * iF - d | ||
let aFirst = aIndexesF[iF]; // in first iteration always insert | ||
let aIndexPrev1 = aFirst; // prev value of [iF - 1] in next iteration | ||
aIndexesF[iF] += countCommonItemsF( | ||
aFirst + 1, | ||
aEnd, | ||
bF + aFirst - kF + 1, | ||
bEnd, | ||
isCommon | ||
); | ||
// Optimization: skip diagonals in which paths cannot ever overlap. | ||
const nF = d < iMaxF ? d : iMaxF; | ||
// The diagonals kF are odd when d is odd and even when d is even. | ||
for (iF += 1, kF += 2; iF <= nF; iF += 1, kF += 2) { | ||
// To get first point of path segment, move one change in forward direction | ||
// from last point of previous path segment in an adjacent diagonal. | ||
// In last possible iteration when iF === d and kF === d always delete. | ||
if (iF !== d && aIndexPrev1 < aIndexesF[iF]) { | ||
aFirst = aIndexesF[iF]; // vertical to insert from b | ||
} else { | ||
aFirst = aIndexPrev1 + 1; // horizontal to delete from a | ||
if (aEnd <= aFirst) { | ||
// Optimization: delete moved past right of graph. | ||
return iF - 1; | ||
} | ||
} | ||
// To get last point of path segment, move along diagonal of common items. | ||
aIndexPrev1 = aIndexesF[iF]; | ||
aIndexesF[iF] = | ||
aFirst + | ||
countCommonItemsF(aFirst + 1, aEnd, bF + aFirst - kF + 1, bEnd, isCommon); | ||
} | ||
return iMaxF; | ||
}; | ||
// A simple function to extend reverse paths from (d - 1) to d changes | ||
// when reverse and forward paths cannot yet overlap. | ||
const extendPathsR = ( | ||
d, | ||
aStart, | ||
bStart, | ||
bR, | ||
isCommon, | ||
aIndexesR, | ||
iMaxR // return the value because optimization might decrease it | ||
) => { | ||
// Unroll the first iteration. | ||
let iR = 0; | ||
let kR = d; // kR = d - 2 * iR | ||
let aFirst = aIndexesR[iR]; // in first iteration always insert | ||
let aIndexPrev1 = aFirst; // prev value of [iR - 1] in next iteration | ||
aIndexesR[iR] -= countCommonItemsR( | ||
aStart, | ||
aFirst - 1, | ||
bStart, | ||
bR + aFirst - kR - 1, | ||
isCommon | ||
); | ||
// Optimization: skip diagonals in which paths cannot ever overlap. | ||
const nR = d < iMaxR ? d : iMaxR; | ||
// The diagonals kR are odd when d is odd and even when d is even. | ||
for (iR += 1, kR -= 2; iR <= nR; iR += 1, kR -= 2) { | ||
// To get first point of path segment, move one change in reverse direction | ||
// from last point of previous path segment in an adjacent diagonal. | ||
// In last possible iteration when iR === d and kR === -d always delete. | ||
if (iR !== d && aIndexesR[iR] < aIndexPrev1) { | ||
aFirst = aIndexesR[iR]; // vertical to insert from b | ||
} else { | ||
aFirst = aIndexPrev1 - 1; // horizontal to delete from a | ||
if (aFirst < aStart) { | ||
// Optimization: delete moved past left of graph. | ||
return iR - 1; | ||
} | ||
} | ||
// To get last point of path segment, move along diagonal of common items. | ||
aIndexPrev1 = aIndexesR[iR]; | ||
aIndexesR[iR] = | ||
aFirst - | ||
countCommonItemsR( | ||
aStart, | ||
aFirst - 1, | ||
bStart, | ||
bR + aFirst - kR - 1, | ||
isCommon | ||
); | ||
} | ||
return iMaxR; | ||
}; | ||
// A complete function to extend forward paths from (d - 1) to d changes. | ||
// Return true if a path overlaps reverse path of (d - 1) changes in its diagonal. | ||
const extendOverlappablePathsF = ( | ||
d, | ||
aStart, | ||
aEnd, | ||
bStart, | ||
bEnd, | ||
isCommon, | ||
aIndexesF, | ||
iMaxF, | ||
aIndexesR, | ||
iMaxR, | ||
division // update prop values if return true | ||
) => { | ||
const bF = bStart - aStart; // bIndex = bF + aIndex - kF | ||
const aLength = aEnd - aStart; | ||
const bLength = bEnd - bStart; | ||
const baDeltaLength = bLength - aLength; // kF = kR - baDeltaLength | ||
// Range of diagonals in which forward and reverse paths might overlap. | ||
const kMinOverlapF = -baDeltaLength - (d - 1); // -(d - 1) <= kR | ||
const kMaxOverlapF = -baDeltaLength + (d - 1); // kR <= (d - 1) | ||
let aIndexPrev1 = NOT_YET_SET; // prev value of [iF - 1] in next iteration | ||
// Optimization: skip diagonals in which paths cannot ever overlap. | ||
const nF = d < iMaxF ? d : iMaxF; | ||
// The diagonals kF = 2 * iF - d are odd when d is odd and even when d is even. | ||
for (let iF = 0, kF = -d; iF <= nF; iF += 1, kF += 2) { | ||
// To get first point of path segment, move one change in forward direction | ||
// from last point of previous path segment in an adjacent diagonal. | ||
// In first iteration when iF === 0 and kF === -d always insert. | ||
// In last possible iteration when iF === d and kF === d always delete. | ||
const insert = iF === 0 || (iF !== d && aIndexPrev1 < aIndexesF[iF]); | ||
const aLastPrev = insert ? aIndexesF[iF] : aIndexPrev1; | ||
const aFirst = insert | ||
? aLastPrev // vertical to insert from b | ||
: aLastPrev + 1; // horizontal to delete from a | ||
// To get last point of path segment, move along diagonal of common items. | ||
const bFirst = bF + aFirst - kF; | ||
const nCommonF = countCommonItemsF( | ||
aFirst + 1, | ||
aEnd, | ||
bFirst + 1, | ||
bEnd, | ||
isCommon | ||
); | ||
const aLast = aFirst + nCommonF; | ||
aIndexPrev1 = aIndexesF[iF]; | ||
aIndexesF[iF] = aLast; | ||
if (kMinOverlapF <= kF && kF <= kMaxOverlapF) { | ||
// Solve for iR of reverse path with (d - 1) changes in diagonal kF: | ||
// kR = kF + baDeltaLength | ||
// kR = (d - 1) - 2 * iR | ||
const iR = (d - 1 - (kF + baDeltaLength)) / 2; | ||
// If this forward path overlaps the reverse path in this diagonal, | ||
// then this is the middle change of the index intervals. | ||
if (iR <= iMaxR && aIndexesR[iR] - 1 <= aLast) { | ||
// Unlike the Myers algorithm which finds only the middle “snake” | ||
// this package can find two common subsequences per division. | ||
// Last point of previous path segment is on an adjacent diagonal. | ||
const bLastPrev = bF + aLastPrev - (insert ? kF + 1 : kF - 1); | ||
// Because of invariant that intervals preceding the middle change | ||
// cannot have common items at the end, | ||
// move in reverse direction along a diagonal of common items. | ||
const nCommonR = countCommonItemsR( | ||
aStart, | ||
aLastPrev, | ||
bStart, | ||
bLastPrev, | ||
isCommon | ||
); | ||
const aIndexPrevFirst = aLastPrev - nCommonR; | ||
const bIndexPrevFirst = bLastPrev - nCommonR; | ||
const aEndPreceding = aIndexPrevFirst + 1; | ||
const bEndPreceding = bIndexPrevFirst + 1; | ||
division.nChangePreceding = d - 1; | ||
if (d - 1 === aEndPreceding + bEndPreceding - aStart - bStart) { | ||
// Optimization: number of preceding changes in forward direction | ||
// is equal to number of items in preceding interval, | ||
// therefore it cannot contain any common items. | ||
division.aEndPreceding = aStart; | ||
division.bEndPreceding = bStart; | ||
} else { | ||
division.aEndPreceding = aEndPreceding; | ||
division.bEndPreceding = bEndPreceding; | ||
} | ||
division.nCommonPreceding = nCommonR; | ||
if (nCommonR !== 0) { | ||
division.aCommonPreceding = aEndPreceding; | ||
division.bCommonPreceding = bEndPreceding; | ||
} | ||
division.nCommonFollowing = nCommonF; | ||
if (nCommonF !== 0) { | ||
division.aCommonFollowing = aFirst + 1; | ||
division.bCommonFollowing = bFirst + 1; | ||
} | ||
const aStartFollowing = aLast + 1; | ||
const bStartFollowing = bFirst + nCommonF + 1; | ||
division.nChangeFollowing = d - 1; | ||
if (d - 1 === aEnd + bEnd - aStartFollowing - bStartFollowing) { | ||
// Optimization: number of changes in reverse direction | ||
// is equal to number of items in following interval, | ||
// therefore it cannot contain any common items. | ||
division.aStartFollowing = aEnd; | ||
division.bStartFollowing = bEnd; | ||
} else { | ||
division.aStartFollowing = aStartFollowing; | ||
division.bStartFollowing = bStartFollowing; | ||
} | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}; | ||
// A complete function to extend reverse paths from (d - 1) to d changes. | ||
// Return true if a path overlaps forward path of d changes in its diagonal. | ||
const extendOverlappablePathsR = ( | ||
d, | ||
aStart, | ||
aEnd, | ||
bStart, | ||
bEnd, | ||
isCommon, | ||
aIndexesF, | ||
iMaxF, | ||
aIndexesR, | ||
iMaxR, | ||
division // update prop values if return true | ||
) => { | ||
const bR = bEnd - aEnd; // bIndex = bR + aIndex - kR | ||
const aLength = aEnd - aStart; | ||
const bLength = bEnd - bStart; | ||
const baDeltaLength = bLength - aLength; // kR = kF + baDeltaLength | ||
// Range of diagonals in which forward and reverse paths might overlap. | ||
const kMinOverlapR = baDeltaLength - d; // -d <= kF | ||
const kMaxOverlapR = baDeltaLength + d; // kF <= d | ||
let aIndexPrev1 = NOT_YET_SET; // prev value of [iR - 1] in next iteration | ||
// Optimization: skip diagonals in which paths cannot ever overlap. | ||
const nR = d < iMaxR ? d : iMaxR; | ||
// The diagonals kR = d - 2 * iR are odd when d is odd and even when d is even. | ||
for (let iR = 0, kR = d; iR <= nR; iR += 1, kR -= 2) { | ||
// To get first point of path segment, move one change in reverse direction | ||
// from last point of previous path segment in an adjacent diagonal. | ||
// In first iteration when iR === 0 and kR === d always insert. | ||
// In last possible iteration when iR === d and kR === -d always delete. | ||
const insert = iR === 0 || (iR !== d && aIndexesR[iR] < aIndexPrev1); | ||
const aLastPrev = insert ? aIndexesR[iR] : aIndexPrev1; | ||
const aFirst = insert | ||
? aLastPrev // vertical to insert from b | ||
: aLastPrev - 1; // horizontal to delete from a | ||
// To get last point of path segment, move along diagonal of common items. | ||
const bFirst = bR + aFirst - kR; | ||
const nCommonR = countCommonItemsR( | ||
aStart, | ||
aFirst - 1, | ||
bStart, | ||
bFirst - 1, | ||
isCommon | ||
); | ||
const aLast = aFirst - nCommonR; | ||
aIndexPrev1 = aIndexesR[iR]; | ||
aIndexesR[iR] = aLast; | ||
if (kMinOverlapR <= kR && kR <= kMaxOverlapR) { | ||
// Solve for iF of forward path with d changes in diagonal kR: | ||
// kF = kR - baDeltaLength | ||
// kF = 2 * iF - d | ||
const iF = (d + (kR - baDeltaLength)) / 2; | ||
// If this reverse path overlaps the forward path in this diagonal, | ||
// then this is a middle change of the index intervals. | ||
if (iF <= iMaxF && aLast - 1 <= aIndexesF[iF]) { | ||
const bLast = bFirst - nCommonR; | ||
division.nChangePreceding = d; | ||
if (d === aLast + bLast - aStart - bStart) { | ||
// Optimization: number of changes in reverse direction | ||
// is equal to number of items in preceding interval, | ||
// therefore it cannot contain any common items. | ||
division.aEndPreceding = aStart; | ||
division.bEndPreceding = bStart; | ||
} else { | ||
division.aEndPreceding = aLast; | ||
division.bEndPreceding = bLast; | ||
} | ||
division.nCommonPreceding = nCommonR; | ||
if (nCommonR !== 0) { | ||
// The last point of reverse path segment is start of common subsequence. | ||
division.aCommonPreceding = aLast; | ||
division.bCommonPreceding = bLast; | ||
} | ||
division.nChangeFollowing = d - 1; | ||
if (d === 1) { | ||
// There is no previous path segment. | ||
division.nCommonFollowing = 0; | ||
division.aStartFollowing = aEnd; | ||
division.bStartFollowing = bEnd; | ||
} else { | ||
// Unlike the Myers algorithm which finds only the middle “snake” | ||
// this package can find two common subsequences per division. | ||
// Last point of previous path segment is on an adjacent diagonal. | ||
const bLastPrev = bR + aLastPrev - (insert ? kR - 1 : kR + 1); | ||
// Because of invariant that intervals following the middle change | ||
// cannot have common items at the start, | ||
// move in forward direction along a diagonal of common items. | ||
const nCommonF = countCommonItemsF( | ||
aLastPrev, | ||
aEnd, | ||
bLastPrev, | ||
bEnd, | ||
isCommon | ||
); | ||
division.nCommonFollowing = nCommonF; | ||
if (nCommonF !== 0) { | ||
// The last point of reverse path segment is start of common subsequence. | ||
division.aCommonFollowing = aLastPrev; | ||
division.bCommonFollowing = bLastPrev; | ||
} | ||
const aStartFollowing = aLastPrev + nCommonF; // aFirstPrev | ||
const bStartFollowing = bLastPrev + nCommonF; // bFirstPrev | ||
if (d - 1 === aEnd + bEnd - aStartFollowing - bStartFollowing) { | ||
// Optimization: number of changes in forward direction | ||
// is equal to number of items in following interval, | ||
// therefore it cannot contain any common items. | ||
division.aStartFollowing = aEnd; | ||
division.bStartFollowing = bEnd; | ||
} else { | ||
division.aStartFollowing = aStartFollowing; | ||
division.bStartFollowing = bStartFollowing; | ||
} | ||
} | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}; | ||
// Given index intervals and input function to compare items at indexes, | ||
// divide at the middle change. | ||
// | ||
// DO NOT CALL if start === end, because interval cannot contain common items | ||
// and because this function will throw the “no overlap” error. | ||
const divide = ( | ||
nChange, | ||
aStart, | ||
aEnd, | ||
bStart, | ||
bEnd, | ||
isCommon, | ||
aIndexesF, | ||
aIndexesR, | ||
division // output | ||
) => { | ||
const bF = bStart - aStart; // bIndex = bF + aIndex - kF | ||
const bR = bEnd - aEnd; // bIndex = bR + aIndex - kR | ||
const aLength = aEnd - aStart; | ||
const bLength = bEnd - bStart; | ||
// Because graph has square or portrait orientation, | ||
// length difference is minimum number of items to insert from b. | ||
// Corresponding forward and reverse diagonals in graph | ||
// depend on length difference of the sequences: | ||
// kF = kR - baDeltaLength | ||
// kR = kF + baDeltaLength | ||
const baDeltaLength = bLength - aLength; | ||
// Optimization: max diagonal in graph intersects corner of shorter side. | ||
let iMaxF = aLength; | ||
let iMaxR = aLength; | ||
// Initialize no changes yet in forward or reverse direction: | ||
aIndexesF[0] = aStart - 1; // at open start of interval, outside closed start | ||
aIndexesR[0] = aEnd; // at open end of interval | ||
if (baDeltaLength % 2 === 0) { | ||
// The number of changes in paths is 2 * d if length difference is even. | ||
const dMin = (nChange || baDeltaLength) / 2; | ||
const dMax = (aLength + bLength) / 2; | ||
for (let d = 1; d <= dMax; d += 1) { | ||
iMaxF = extendPathsF(d, aEnd, bEnd, bF, isCommon, aIndexesF, iMaxF); | ||
if (d < dMin) { | ||
iMaxR = extendPathsR(d, aStart, bStart, bR, isCommon, aIndexesR, iMaxR); | ||
} else if ( | ||
// If a reverse path overlaps a forward path in the same diagonal, | ||
// return a division of the index intervals at the middle change. | ||
extendOverlappablePathsR( | ||
d, | ||
aStart, | ||
aEnd, | ||
bStart, | ||
bEnd, | ||
isCommon, | ||
aIndexesF, | ||
iMaxF, | ||
aIndexesR, | ||
iMaxR, | ||
division | ||
) | ||
) { | ||
return; | ||
} | ||
} | ||
} else { | ||
// The number of changes in paths is 2 * d - 1 if length difference is odd. | ||
const dMin = ((nChange || baDeltaLength) + 1) / 2; | ||
const dMax = (aLength + bLength + 1) / 2; | ||
// Unroll first half iteration so loop extends the relevant pairs of paths. | ||
// Because of invariant that intervals have no common items at start or end, | ||
// and limitation not to call divide with empty intervals, | ||
// therefore it cannot be called if a forward path with one change | ||
// would overlap a reverse path with no changes, even if dMin === 1. | ||
let d = 1; | ||
iMaxF = extendPathsF(d, aEnd, bEnd, bF, isCommon, aIndexesF, iMaxF); | ||
for (d += 1; d <= dMax; d += 1) { | ||
iMaxR = extendPathsR( | ||
d - 1, | ||
aStart, | ||
bStart, | ||
bR, | ||
isCommon, | ||
aIndexesR, | ||
iMaxR | ||
); | ||
if (d < dMin) { | ||
iMaxF = extendPathsF(d, aEnd, bEnd, bF, isCommon, aIndexesF, iMaxF); | ||
} else if ( | ||
// If a forward path overlaps a reverse path in the same diagonal, | ||
// return a division of the index intervals at the middle change. | ||
extendOverlappablePathsF( | ||
d, | ||
aStart, | ||
aEnd, | ||
bStart, | ||
bEnd, | ||
isCommon, | ||
aIndexesF, | ||
iMaxF, | ||
aIndexesR, | ||
iMaxR, | ||
division | ||
) | ||
) { | ||
return; | ||
} | ||
} | ||
} | ||
/* istanbul ignore next */ | ||
throw new Error( | ||
`${pkg}: no overlap aStart=${aStart} aEnd=${aEnd} bStart=${bStart} bEnd=${bEnd}` | ||
); | ||
}; | ||
// Given index intervals and input function to compare items at indexes, | ||
// return by output function the number of adjacent items and starting indexes | ||
// of each common subsequence. Divide and conquer with only linear space. | ||
// | ||
// The index intervals are half open [start, end) like array slice method. | ||
// DO NOT CALL if start === end, because interval cannot contain common items | ||
// and because divide function will throw the “no overlap” error. | ||
const findSubsequences = ( | ||
nChange, | ||
aStart, | ||
aEnd, | ||
bStart, | ||
bEnd, | ||
transposed, | ||
callbacks, | ||
aIndexesF, | ||
aIndexesR, | ||
division // temporary memory, not input nor output | ||
) => { | ||
if (bEnd - bStart < aEnd - aStart) { | ||
// Transpose graph so it has portrait instead of landscape orientation. | ||
// Always compare shorter to longer sequence for consistency and optimization. | ||
transposed = !transposed; | ||
if (transposed && callbacks.length === 1) { | ||
// Lazily wrap callback functions to swap args if graph is transposed. | ||
const {foundSubsequence, isCommon} = callbacks[0]; | ||
callbacks[1] = { | ||
foundSubsequence: (nCommon, bCommon, aCommon) => { | ||
foundSubsequence(nCommon, aCommon, bCommon); | ||
}, | ||
isCommon: (bIndex, aIndex) => isCommon(aIndex, bIndex) | ||
}; | ||
} | ||
const tStart = aStart; | ||
const tEnd = aEnd; | ||
aStart = bStart; | ||
aEnd = bEnd; | ||
bStart = tStart; | ||
bEnd = tEnd; | ||
} | ||
const {foundSubsequence, isCommon} = callbacks[transposed ? 1 : 0]; | ||
// Divide the index intervals at the middle change. | ||
divide( | ||
nChange, | ||
aStart, | ||
aEnd, | ||
bStart, | ||
bEnd, | ||
isCommon, | ||
aIndexesF, | ||
aIndexesR, | ||
division | ||
); | ||
const { | ||
nChangePreceding, | ||
aEndPreceding, | ||
bEndPreceding, | ||
nCommonPreceding, | ||
aCommonPreceding, | ||
bCommonPreceding, | ||
nCommonFollowing, | ||
aCommonFollowing, | ||
bCommonFollowing, | ||
nChangeFollowing, | ||
aStartFollowing, | ||
bStartFollowing | ||
} = division; | ||
// Unless either index interval is empty, they might contain common items. | ||
if (aStart < aEndPreceding && bStart < bEndPreceding) { | ||
// Recursely find and return common subsequences preceding the division. | ||
findSubsequences( | ||
nChangePreceding, | ||
aStart, | ||
aEndPreceding, | ||
bStart, | ||
bEndPreceding, | ||
transposed, | ||
callbacks, | ||
aIndexesF, | ||
aIndexesR, | ||
division | ||
); | ||
} | ||
// Return common subsequences that are adjacent to the middle change. | ||
if (nCommonPreceding !== 0) { | ||
foundSubsequence(nCommonPreceding, aCommonPreceding, bCommonPreceding); | ||
} | ||
if (nCommonFollowing !== 0) { | ||
foundSubsequence(nCommonFollowing, aCommonFollowing, bCommonFollowing); | ||
} | ||
// Unless either index interval is empty, they might contain common items. | ||
if (aStartFollowing < aEnd && bStartFollowing < bEnd) { | ||
// Recursely find and return common subsequences following the division. | ||
findSubsequences( | ||
nChangeFollowing, | ||
aStartFollowing, | ||
aEnd, | ||
bStartFollowing, | ||
bEnd, | ||
transposed, | ||
callbacks, | ||
aIndexesF, | ||
aIndexesR, | ||
division | ||
); | ||
} | ||
}; | ||
const validateLength = (name, arg) => { | ||
if (typeof arg !== 'number') { | ||
throw new TypeError(`${pkg}: ${name} typeof ${typeof arg} is not a number`); | ||
} | ||
if (!Number.isSafeInteger(arg)) { | ||
throw new RangeError(`${pkg}: ${name} value ${arg} is not a safe integer`); | ||
} | ||
if (arg < 0) { | ||
throw new RangeError(`${pkg}: ${name} value ${arg} is a negative integer`); | ||
} | ||
}; | ||
const validateCallback = (name, arg) => { | ||
const type = typeof arg; | ||
if (type !== 'function') { | ||
throw new TypeError(`${pkg}: ${name} typeof ${type} is not a function`); | ||
} | ||
}; | ||
// Compare items in two sequences to find a longest common subsequence. | ||
// Given lengths of sequences and input function to compare items at indexes, | ||
// return by output function the number of adjacent items and starting indexes | ||
// of each common subsequence. | ||
function diffSequence(aLength, bLength, isCommon, foundSubsequence) { | ||
validateLength('aLength', aLength); | ||
validateLength('bLength', bLength); | ||
validateCallback('isCommon', isCommon); | ||
validateCallback('foundSubsequence', foundSubsequence); | ||
// Count common items from the start in the forward direction. | ||
const nCommonF = countCommonItemsF(0, aLength, 0, bLength, isCommon); | ||
if (nCommonF !== 0) { | ||
foundSubsequence(nCommonF, 0, 0); | ||
} | ||
// Unless both sequences consist of common items only, | ||
// find common items in the half-trimmed index intervals. | ||
if (aLength !== nCommonF || bLength !== nCommonF) { | ||
// Invariant: intervals do not have common items at the start. | ||
// The start of an index interval is closed like array slice method. | ||
const aStart = nCommonF; | ||
const bStart = nCommonF; | ||
// Count common items from the end in the reverse direction. | ||
const nCommonR = countCommonItemsR( | ||
aStart, | ||
aLength - 1, | ||
bStart, | ||
bLength - 1, | ||
isCommon | ||
); | ||
// Invariant: intervals do not have common items at the end. | ||
// The end of an index interval is open like array slice method. | ||
const aEnd = aLength - nCommonR; | ||
const bEnd = bLength - nCommonR; | ||
// Unless one sequence consists of common items only, | ||
// therefore the other trimmed index interval consists of changes only, | ||
// find common items in the trimmed index intervals. | ||
const nCommonFR = nCommonF + nCommonR; | ||
if (aLength !== nCommonFR && bLength !== nCommonFR) { | ||
const nChange = 0; // number of change items is not yet known | ||
const transposed = false; // call the original unwrapped functions | ||
const callbacks = [ | ||
{ | ||
foundSubsequence, | ||
isCommon | ||
} | ||
]; | ||
// Indexes in sequence a of last points in furthest reaching paths | ||
// from outside the start at top left in the forward direction: | ||
const aIndexesF = [NOT_YET_SET]; | ||
// from the end at bottom right in the reverse direction: | ||
const aIndexesR = [NOT_YET_SET]; | ||
// Initialize one object as output of all calls to divide function. | ||
const division = { | ||
aCommonFollowing: NOT_YET_SET, | ||
aCommonPreceding: NOT_YET_SET, | ||
aEndPreceding: NOT_YET_SET, | ||
aStartFollowing: NOT_YET_SET, | ||
bCommonFollowing: NOT_YET_SET, | ||
bCommonPreceding: NOT_YET_SET, | ||
bEndPreceding: NOT_YET_SET, | ||
bStartFollowing: NOT_YET_SET, | ||
nChangeFollowing: NOT_YET_SET, | ||
nChangePreceding: NOT_YET_SET, | ||
nCommonFollowing: NOT_YET_SET, | ||
nCommonPreceding: NOT_YET_SET | ||
}; | ||
// Find and return common subsequences in the trimmed index intervals. | ||
findSubsequences( | ||
nChange, | ||
aStart, | ||
aEnd, | ||
bStart, | ||
bEnd, | ||
transposed, | ||
callbacks, | ||
aIndexesF, | ||
aIndexesR, | ||
division | ||
); | ||
} | ||
if (nCommonR !== 0) { | ||
foundSubsequence(nCommonR, aEnd, bEnd); | ||
} | ||
} | ||
} | ||
function formatTrailingSpaces(line, trailingSpaceFormatter) { | ||
@@ -616,3 +1414,2 @@ return line.replace(/\s+$/, (match) => trailingSpaceFormatter(match)); | ||
function getDefaultOptions() { | ||
const c = getColors(); | ||
return { | ||
@@ -663,4 +1460,4 @@ aAnnotation: "Expected", | ||
let b = 0; | ||
diffs.forEach((diff2) => { | ||
switch (diff2[0]) { | ||
diffs.forEach((diff) => { | ||
switch (diff[0]) { | ||
case DIFF_DELETE: | ||
@@ -742,14 +1539,14 @@ a += 1; | ||
let bIndex = 0; | ||
diffs.forEach((diff2) => { | ||
switch (diff2[0]) { | ||
diffs.forEach((diff) => { | ||
switch (diff[0]) { | ||
case DIFF_DELETE: | ||
diff2[1] = aLinesDisplay[aIndex]; | ||
diff[1] = aLinesDisplay[aIndex]; | ||
aIndex += 1; | ||
break; | ||
case DIFF_INSERT: | ||
diff2[1] = bLinesDisplay[bIndex]; | ||
diff[1] = bLinesDisplay[bIndex]; | ||
bIndex += 1; | ||
break; | ||
default: | ||
diff2[1] = bLinesDisplay[bIndex]; | ||
diff[1] = bLinesDisplay[bIndex]; | ||
aIndex += 1; | ||
@@ -785,4 +1582,3 @@ bIndex += 1; | ||
}; | ||
const diffSequences = diff$1.default.default || diff$1.default; | ||
diffSequences(aLength, bLength, isCommon, foundSubsequence); | ||
_default(aLength, bLength, isCommon, foundSubsequence); | ||
for (; aIndex !== aLength; aIndex += 1) { | ||
@@ -836,4 +1632,3 @@ diffs.push(new Diff(DIFF_DELETE, aLines[aIndex])); | ||
}; | ||
const diffSequences = diff$1.default.default || diff$1.default; | ||
diffSequences(aLength, bLength, isCommon, foundSubsequence); | ||
_default(aLength, bLength, isCommon, foundSubsequence); | ||
if (aIndex !== aLength) { | ||
@@ -840,0 +1635,0 @@ diffs.push(new Diff(DIFF_DELETE, a.slice(aIndex))); |
@@ -1,3 +0,3 @@ | ||
import { D as DiffOptions } from './types-DyShQl4f.js'; | ||
import 'pretty-format'; | ||
import { D as DiffOptions } from './types-Bxe-2Udy.js'; | ||
import '@vitest/pretty-format'; | ||
@@ -4,0 +4,0 @@ declare function serializeError(val: any, seen?: WeakMap<WeakKey, any>): any; |
import { diff } from './diff.js'; | ||
import { f as format, s as stringify } from './chunk-display.js'; | ||
import { deepClone, getOwnProperties, getType } from './helpers.js'; | ||
import 'pretty-format'; | ||
import 'diff-sequences'; | ||
import './chunk-colors.js'; | ||
import '@vitest/pretty-format'; | ||
import 'tinyrainbow'; | ||
import 'loupe'; | ||
@@ -8,0 +7,0 @@ |
export { DeferPromise, assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isNegativeNaN, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray } from './helpers.js'; | ||
export { ArgumentsType, Arrayable, Awaitable, Constructable, DeepMerge, ErrorWithDiff, MergeInsertions, MutableArray, Nullable, ParsedStack } from './types.js'; | ||
import { PrettyFormatOptions } from 'pretty-format'; | ||
import { PrettyFormatOptions } from '@vitest/pretty-format'; | ||
import { Colors } from 'tinyrainbow'; | ||
@@ -44,46 +45,2 @@ declare function stringify(object: unknown, maxDepth?: number, { maxLength, ...options }?: PrettyFormatOptions & { | ||
declare const colorsMap: { | ||
readonly bold: readonly ["\u001B[1m", "\u001B[22m", "\u001B[22m\u001B[1m"]; | ||
readonly dim: readonly ["\u001B[2m", "\u001B[22m", "\u001B[22m\u001B[2m"]; | ||
readonly italic: readonly ["\u001B[3m", "\u001B[23m"]; | ||
readonly underline: readonly ["\u001B[4m", "\u001B[24m"]; | ||
readonly inverse: readonly ["\u001B[7m", "\u001B[27m"]; | ||
readonly hidden: readonly ["\u001B[8m", "\u001B[28m"]; | ||
readonly strikethrough: readonly ["\u001B[9m", "\u001B[29m"]; | ||
readonly black: readonly ["\u001B[30m", "\u001B[39m"]; | ||
readonly red: readonly ["\u001B[31m", "\u001B[39m"]; | ||
readonly green: readonly ["\u001B[32m", "\u001B[39m"]; | ||
readonly yellow: readonly ["\u001B[33m", "\u001B[39m"]; | ||
readonly blue: readonly ["\u001B[34m", "\u001B[39m"]; | ||
readonly magenta: readonly ["\u001B[35m", "\u001B[39m"]; | ||
readonly cyan: readonly ["\u001B[36m", "\u001B[39m"]; | ||
readonly white: readonly ["\u001B[37m", "\u001B[39m"]; | ||
readonly gray: readonly ["\u001B[90m", "\u001B[39m"]; | ||
readonly bgBlack: readonly ["\u001B[40m", "\u001B[49m"]; | ||
readonly bgRed: readonly ["\u001B[41m", "\u001B[49m"]; | ||
readonly bgGreen: readonly ["\u001B[42m", "\u001B[49m"]; | ||
readonly bgYellow: readonly ["\u001B[43m", "\u001B[49m"]; | ||
readonly bgBlue: readonly ["\u001B[44m", "\u001B[49m"]; | ||
readonly bgMagenta: readonly ["\u001B[45m", "\u001B[49m"]; | ||
readonly bgCyan: readonly ["\u001B[46m", "\u001B[49m"]; | ||
readonly bgWhite: readonly ["\u001B[47m", "\u001B[49m"]; | ||
}; | ||
type ColorName = keyof typeof colorsMap; | ||
interface ColorMethod { | ||
(input: unknown): string; | ||
open: string; | ||
close: string; | ||
} | ||
type ColorsMethods = { | ||
[Key in ColorName]: ColorMethod; | ||
}; | ||
type Colors$1 = ColorsMethods & { | ||
isColorSupported: boolean; | ||
reset: (input: unknown) => string; | ||
}; | ||
declare function getDefaultColors(): Colors$1; | ||
declare function getColors(): Colors$1; | ||
declare function createColors(isTTY?: boolean): Colors$1; | ||
declare function setupColors(colors: Colors$1): void; | ||
interface ErrorOptions { | ||
@@ -104,3 +61,2 @@ message?: string; | ||
type Colors = Record<ColorName, (input: string) => string>; | ||
interface HighlightOptions { | ||
@@ -112,2 +68,2 @@ jsx?: boolean; | ||
export { type ColorMethod, type ColorName, type Colors$1 as Colors, type ColorsMethods, SAFE_COLORS_SYMBOL, SAFE_TIMERS_SYMBOL, createColors, createSimpleStackTrace, format, getColors, getDefaultColors, getSafeTimers, highlight, inspect, lineSplitRE, objDisplay, offsetToLineNumber, positionToOffset, setSafeTimers, setupColors, shuffle, stringify }; | ||
export { SAFE_COLORS_SYMBOL, SAFE_TIMERS_SYMBOL, createSimpleStackTrace, format, getSafeTimers, highlight, inspect, lineSplitRE, objDisplay, offsetToLineNumber, positionToOffset, setSafeTimers, shuffle, stringify }; |
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isNegativeNaN, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray } from './helpers.js'; | ||
export { f as format, i as inspect, o as objDisplay, s as stringify } from './chunk-display.js'; | ||
import { S as SAFE_TIMERS_SYMBOL, g as getColors } from './chunk-colors.js'; | ||
export { a as SAFE_COLORS_SYMBOL, c as createColors, b as getDefaultColors, s as setupColors } from './chunk-colors.js'; | ||
import 'pretty-format'; | ||
import c from 'tinyrainbow'; | ||
import '@vitest/pretty-format'; | ||
import 'loupe'; | ||
const SAFE_TIMERS_SYMBOL = Symbol("vitest:SAFE_TIMERS"); | ||
const SAFE_COLORS_SYMBOL = Symbol("vitest:SAFE_COLORS"); | ||
function getSafeTimers() { | ||
@@ -613,24 +615,24 @@ const { | ||
function getDefs(c) { | ||
const Invalid = (text) => c.white(c.bgRed(c.bold(text))); | ||
function getDefs(c2) { | ||
const Invalid = (text) => c2.white(c2.bgRed(c2.bold(text))); | ||
return { | ||
Keyword: c.magenta, | ||
IdentifierCapitalized: c.yellow, | ||
Punctuator: c.yellow, | ||
StringLiteral: c.green, | ||
NoSubstitutionTemplate: c.green, | ||
MultiLineComment: c.gray, | ||
SingleLineComment: c.gray, | ||
RegularExpressionLiteral: c.cyan, | ||
NumericLiteral: c.blue, | ||
TemplateHead: (text) => c.green(text.slice(0, text.length - 2)) + c.cyan(text.slice(-2)), | ||
TemplateTail: (text) => c.cyan(text.slice(0, 1)) + c.green(text.slice(1)), | ||
TemplateMiddle: (text) => c.cyan(text.slice(0, 1)) + c.green(text.slice(1, text.length - 2)) + c.cyan(text.slice(-2)), | ||
IdentifierCallable: c.blue, | ||
PrivateIdentifierCallable: (text) => `#${c.blue(text.slice(1))}`, | ||
Keyword: c2.magenta, | ||
IdentifierCapitalized: c2.yellow, | ||
Punctuator: c2.yellow, | ||
StringLiteral: c2.green, | ||
NoSubstitutionTemplate: c2.green, | ||
MultiLineComment: c2.gray, | ||
SingleLineComment: c2.gray, | ||
RegularExpressionLiteral: c2.cyan, | ||
NumericLiteral: c2.blue, | ||
TemplateHead: (text) => c2.green(text.slice(0, text.length - 2)) + c2.cyan(text.slice(-2)), | ||
TemplateTail: (text) => c2.cyan(text.slice(0, 1)) + c2.green(text.slice(1)), | ||
TemplateMiddle: (text) => c2.cyan(text.slice(0, 1)) + c2.green(text.slice(1, text.length - 2)) + c2.cyan(text.slice(-2)), | ||
IdentifierCallable: c2.blue, | ||
PrivateIdentifierCallable: (text) => `#${c2.blue(text.slice(1))}`, | ||
Invalid, | ||
JSXString: c.green, | ||
JSXIdentifier: c.yellow, | ||
JSXString: c2.green, | ||
JSXIdentifier: c2.yellow, | ||
JSXInvalid: Invalid, | ||
JSXPunctuator: c.yellow | ||
JSXPunctuator: c2.yellow | ||
}; | ||
@@ -641,6 +643,6 @@ } | ||
jsx: options.jsx, | ||
colors: getDefs(options.colors || getColors()) | ||
colors: getDefs(options.colors || c) | ||
}); | ||
} | ||
export { SAFE_TIMERS_SYMBOL, createSimpleStackTrace, getColors, getSafeTimers, highlight, lineSplitRE, offsetToLineNumber, positionToOffset, setSafeTimers, shuffle }; | ||
export { SAFE_COLORS_SYMBOL, SAFE_TIMERS_SYMBOL, createSimpleStackTrace, getSafeTimers, highlight, lineSplitRE, offsetToLineNumber, positionToOffset, setSafeTimers, shuffle }; |
{ | ||
"name": "@vitest/utils", | ||
"type": "module", | ||
"version": "2.0.1", | ||
"version": "2.0.2", | ||
"description": "Shared Vitest utility functions", | ||
@@ -63,6 +63,6 @@ "license": "MIT", | ||
"dependencies": { | ||
"diff-sequences": "^29.6.3", | ||
"estree-walker": "^3.0.3", | ||
"loupe": "^3.1.1", | ||
"pretty-format": "^29.7.0" | ||
"tinyrainbow": "^1.2.0", | ||
"@vitest/pretty-format": "2.0.2" | ||
}, | ||
@@ -72,2 +72,3 @@ "devDependencies": { | ||
"@types/estree": "^1.0.5", | ||
"diff-sequences": "^29.6.3", | ||
"tinyhighlight": "^0.3.2" | ||
@@ -74,0 +75,0 @@ }, |
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
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
179331
5153
4
21
+ Added@vitest/pretty-format@2.0.2
+ Addedtinyrainbow@^1.2.0
+ Added@vitest/pretty-format@2.0.2(transitive)
+ Addedtinyrainbow@1.2.0(transitive)
- Removeddiff-sequences@^29.6.3
- Removedpretty-format@^29.7.0
- Removed@jest/schemas@29.6.3(transitive)
- Removed@sinclair/typebox@0.27.8(transitive)
- Removedansi-styles@5.2.0(transitive)
- Removeddiff-sequences@29.6.3(transitive)
- Removedpretty-format@29.7.0(transitive)
- Removedreact-is@18.3.1(transitive)