Skip to content

Commit 6797b04

Browse files
authored
feat: add configuration for diff truncation (#5073) (#5333)
1 parent db98145 commit 6797b04

File tree

8 files changed

+285
-29
lines changed

8 files changed

+285
-29
lines changed

docs/config/index.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,28 @@ export default defineConfig({
20772077
```
20782078
:::
20792079

2080+
#### diff.truncateThreshold
2081+
2082+
- **Type**: `number`
2083+
- **Default**: `0`
2084+
2085+
The maximum length of diff result to be displayed. Diffs above this threshold will be truncated.
2086+
Truncation won't take effect with default value 0.
2087+
2088+
#### diff.truncateAnnotation
2089+
2090+
- **Type**: `string`
2091+
- **Default**: `'... Diff result is truncated'`
2092+
2093+
Annotation that is output at the end of diff result if it's truncated.
2094+
2095+
#### diff.truncateAnnotationColor
2096+
2097+
- **Type**: `DiffOptionsColor = (arg: string) => string`
2098+
- **Default**: `noColor = (string: string): string => string`
2099+
2100+
Color of truncate annotation, default is output with no color.
2101+
20802102
### fakeTimers
20812103

20822104
- **Type:** `FakeTimerInstallOpts`

packages/utils/src/diff/diffLines.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,24 @@ function printAnnotation({
8181
return `${aColor(a)}\n${bColor(b)}\n\n`
8282
}
8383

84-
export function printDiffLines(diffs: Array<Diff>, options: DiffOptionsNormalized): string {
84+
export function printDiffLines(diffs: Array<Diff>, truncated: boolean, options: DiffOptionsNormalized): string {
8585
return printAnnotation(options, countChanges(diffs))
86-
+ (options.expand
87-
? joinAlignedDiffsExpand(diffs, options)
88-
: joinAlignedDiffsNoExpand(diffs, options))
86+
+ (options.expand ? joinAlignedDiffsExpand(diffs, options) : joinAlignedDiffsNoExpand(diffs, options))
87+
+ (truncated ? options.truncateAnnotationColor(`\n${options.truncateAnnotation}`) : '')
8988
}
9089

9190
// Compare two arrays of strings line-by-line. Format as comparison lines.
9291
export function diffLinesUnified(aLines: Array<string>, bLines: Array<string>, options?: DiffOptions): string {
92+
const normalizedOptions = normalizeDiffOptions(options)
93+
const [diffs, truncated] = diffLinesRaw(
94+
isEmptyString(aLines) ? [] : aLines,
95+
isEmptyString(bLines) ? [] : bLines,
96+
normalizedOptions,
97+
)
9398
return printDiffLines(
94-
diffLinesRaw(
95-
isEmptyString(aLines) ? [] : aLines,
96-
isEmptyString(bLines) ? [] : bLines,
97-
),
98-
normalizeDiffOptions(options),
99+
diffs,
100+
truncated,
101+
normalizedOptions,
99102
)
100103
}
101104

@@ -120,7 +123,7 @@ export function diffLinesUnified2(aLinesDisplay: Array<string>, bLinesDisplay: A
120123
return diffLinesUnified(aLinesDisplay, bLinesDisplay, options)
121124
}
122125

123-
const diffs = diffLinesRaw(aLinesCompare, bLinesCompare)
126+
const [diffs, truncated] = diffLinesRaw(aLinesCompare, bLinesCompare, options)
124127

125128
// Replace comparison lines with displayable lines.
126129
let aIndex = 0
@@ -144,13 +147,16 @@ export function diffLinesUnified2(aLinesDisplay: Array<string>, bLinesDisplay: A
144147
}
145148
})
146149

147-
return printDiffLines(diffs, normalizeDiffOptions(options))
150+
return printDiffLines(diffs, truncated, normalizeDiffOptions(options))
148151
}
149152

150153
// Compare two arrays of strings line-by-line.
151-
export function diffLinesRaw(aLines: Array<string>, bLines: Array<string>): Array<Diff> {
152-
const aLength = aLines.length
153-
const bLength = bLines.length
154+
export function diffLinesRaw(aLines: Array<string>, bLines: Array<string>, options?: DiffOptions): [Array<Diff>, boolean] {
155+
const truncate = options?.truncateThreshold ?? false
156+
const truncateThreshold = Math.max(Math.floor(options?.truncateThreshold ?? 0), 0)
157+
const aLength = truncate ? Math.min(aLines.length, truncateThreshold) : aLines.length
158+
const bLength = truncate ? Math.min(bLines.length, truncateThreshold) : bLines.length
159+
const truncated = aLength !== aLines.length || bLength !== bLines.length
154160

155161
const isCommon = (aIndex: number, bIndex: number) => aLines[aIndex] === bLines[bIndex]
156162

@@ -185,5 +191,5 @@ export function diffLinesRaw(aLines: Array<string>, bLines: Array<string>): Arra
185191
for (; bIndex !== bLength; bIndex += 1)
186192
diffs.push(new Diff(DIFF_INSERT, bLines[bIndex]))
187193

188-
return diffs
194+
return [diffs, truncated]
189195
}

packages/utils/src/diff/diffStrings.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,31 @@
77

88
import * as diff from 'diff-sequences'
99
import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, Diff } from './cleanupSemantic'
10+
import type { DiffOptions } from './types'
11+
12+
// platforms compatible
13+
function getNewLineSymbol(string: string) {
14+
return string.includes('\r\n') ? '\r\n' : '\n'
15+
}
16+
17+
function diffStrings(a: string, b: string, options?: DiffOptions): [Array<Diff>, boolean] {
18+
const truncate = options?.truncateThreshold ?? false
19+
const truncateThreshold = Math.max(Math.floor(options?.truncateThreshold ?? 0), 0)
20+
let aLength = a.length
21+
let bLength = b.length
22+
if (truncate) {
23+
const aMultipleLines = a.includes('\n')
24+
const bMultipleLines = b.includes('\n')
25+
const aNewLineSymbol = getNewLineSymbol(a)
26+
const bNewLineSymbol = getNewLineSymbol(b)
27+
// multiple-lines string expects a newline to be appended at the end
28+
const _a = aMultipleLines ? `${a.split(aNewLineSymbol, truncateThreshold).join(aNewLineSymbol)}\n` : a
29+
const _b = bMultipleLines ? `${b.split(bNewLineSymbol, truncateThreshold).join(bNewLineSymbol)}\n` : b
30+
aLength = _a.length
31+
bLength = _b.length
32+
}
33+
const truncated = aLength !== a.length || bLength !== b.length
1034

11-
function diffStrings(a: string, b: string): Array<Diff> {
1235
const isCommon = (aIndex: number, bIndex: number) => a[aIndex] === b[bIndex]
1336

1437
let aIndex = 0
@@ -34,16 +57,16 @@ function diffStrings(a: string, b: string): Array<Diff> {
3457
// @ts-expect-error wrong bundling
3558
const diffSequences = diff.default.default || diff.default
3659

37-
diffSequences(a.length, b.length, isCommon, foundSubsequence)
60+
diffSequences(aLength, bLength, isCommon, foundSubsequence)
3861

3962
// After the last common subsequence, push remaining change items.
40-
if (aIndex !== a.length)
63+
if (aIndex !== aLength)
4164
diffs.push(new Diff(DIFF_DELETE, a.slice(aIndex)))
4265

43-
if (bIndex !== b.length)
66+
if (bIndex !== bLength)
4467
diffs.push(new Diff(DIFF_INSERT, b.slice(bIndex)))
4568

46-
return diffs
69+
return [diffs, truncated]
4770
}
4871

4972
export default diffStrings

packages/utils/src/diff/normalizeDiffOptions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { DiffOptions, DiffOptionsNormalized } from './types'
1212
export const noColor = (string: string): string => string
1313

1414
const DIFF_CONTEXT_DEFAULT = 5
15+
const DIFF_TRUNCATE_THRESHOLD_DEFAULT = 0 // not truncate
1516

1617
function getDefaultOptions(): DiffOptionsNormalized {
1718
const c = getColors()
@@ -35,6 +36,9 @@ function getDefaultOptions(): DiffOptionsNormalized {
3536
includeChangeCounts: false,
3637
omitAnnotationLines: false,
3738
patchColor: c.yellow,
39+
truncateThreshold: DIFF_TRUNCATE_THRESHOLD_DEFAULT,
40+
truncateAnnotation: '... Diff result is truncated',
41+
truncateAnnotationColor: noColor,
3842
}
3943
}
4044

packages/utils/src/diff/printDiffs.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,17 @@ export function diffStringsUnified(a: string, b: string, options?: DiffOptions):
3232
const isMultiline = a.includes('\n') || b.includes('\n')
3333

3434
// getAlignedDiffs assumes that a newline was appended to the strings.
35-
const diffs = diffStringsRaw(
35+
const [diffs, truncated] = diffStringsRaw(
3636
isMultiline ? `${a}\n` : a,
3737
isMultiline ? `${b}\n` : b,
3838
true, // cleanupSemantic
39+
options,
3940
)
4041

4142
if (hasCommonDiff(diffs, isMultiline)) {
4243
const optionsNormalized = normalizeDiffOptions(options)
4344
const lines = getAlignedDiffs(diffs, optionsNormalized.changeColor)
44-
return printDiffLines(lines, optionsNormalized)
45+
return printDiffLines(lines, truncated, optionsNormalized)
4546
}
4647
}
4748

@@ -51,11 +52,11 @@ export function diffStringsUnified(a: string, b: string, options?: DiffOptions):
5152

5253
// Compare two strings character-by-character.
5354
// Optionally clean up small common substrings, also known as chaff.
54-
export function diffStringsRaw(a: string, b: string, cleanup: boolean): Array<Diff> {
55-
const diffs = diffStrings(a, b)
55+
export function diffStringsRaw(a: string, b: string, cleanup: boolean, options?: DiffOptions): [Array<Diff>, boolean] {
56+
const [diffs, truncated] = diffStrings(a, b, options)
5657

5758
if (cleanup)
5859
cleanupSemantic(diffs) // impure function
5960

60-
return diffs
61+
return [diffs, truncated]
6162
}

packages/utils/src/diff/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ export interface DiffOptions {
2727
omitAnnotationLines?: boolean
2828
patchColor?: DiffOptionsColor
2929
compareKeys?: CompareKeys
30+
truncateThreshold?: number
31+
truncateAnnotation?: string
32+
truncateAnnotationColor?: DiffOptionsColor
3033
}
3134

3235
export interface DiffOptionsNormalized {
@@ -48,4 +51,7 @@ export interface DiffOptionsNormalized {
4851
includeChangeCounts: boolean
4952
omitAnnotationLines: boolean
5053
patchColor: DiffOptionsColor
54+
truncateThreshold: number
55+
truncateAnnotation: string
56+
truncateAnnotationColor: DiffOptionsColor
5157
}

packages/vitest/src/types/matcher-utils.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,7 @@ export interface DiffOptions {
3131
patchColor?: Formatter
3232
// pretty-format type
3333
compareKeys?: any
34+
truncateThreshold?: number
35+
truncateAnnotation?: string
36+
truncateAnnotationColor?: Formatter
3437
}

0 commit comments

Comments
 (0)