Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/diffs/src/components/FileDiff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ export class FileDiff<LAnnotation = undefined> {
this.fileDiff =
fileDiff ??
(oldFile != null && newFile != null
? parseDiffFromFile(oldFile, newFile)
? parseDiffFromFile(oldFile, newFile, this.options.diffOptions)
: undefined);

this.hunksRenderer.hydrate(this.fileDiff);
Expand Down Expand Up @@ -649,7 +649,11 @@ export class FileDiff<LAnnotation = undefined> {
this.fileDiff = fileDiff;
} else if (oldFile != null && newFile != null && filesDidChange) {
diffDidChange = true;
this.fileDiff = parseDiffFromFile(oldFile, newFile);
this.fileDiff = parseDiffFromFile(
oldFile,
newFile,
this.options.diffOptions
);
}

if (lineAnnotations != null) {
Expand Down
6 changes: 1 addition & 5 deletions packages/diffs/src/components/VirtualizedFileDiff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,7 @@ export class VirtualizedFileDiff<
this.fileDiff ??=
fileDiff ??
(oldFile != null && newFile != null
? // NOTE(amadeus): We might be forcing ourselves to double up the
// computation of fileDiff (in the super.render() call), so we might want
// to figure out a way to avoid that. That also could be just as simple as
// passing through fileDiff though... so maybe we good?
parseDiffFromFile(oldFile, newFile)
? parseDiffFromFile(oldFile, newFile, this.options.diffOptions)
: undefined);

fileContainer = this.getOrCreateFileContainer(fileContainer);
Expand Down
2 changes: 1 addition & 1 deletion packages/diffs/src/ssr/preloadDiffs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export async function preloadDiffHTML<LAnnotation = undefined>({
annotations,
}: PreloadDiffOptions<LAnnotation>): Promise<string> {
if (fileDiff == null && oldFile != null && newFile != null) {
fileDiff = parseDiffFromFile(oldFile, newFile);
fileDiff = parseDiffFromFile(oldFile, newFile, options?.diffOptions);
}
if (fileDiff == null) {
throw new Error(
Expand Down
18 changes: 17 additions & 1 deletion packages/diffs/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { CreatePatchOptionsNonabortable } from 'diff';
import type { ElementContent } from 'hast';
import type {
BundledLanguage,
Expand Down Expand Up @@ -393,10 +394,25 @@ export interface BaseDiffOptions extends BaseCodeOptions {

// How many lines to expand per click
expansionLineCount?: number; // 100 is default

/**
* Options forwarded to the underlying diff algorithm when computing diffs
* from file contents (oldFile/newFile). Has no effect on pre-parsed patches.
*
* Supported options:
* - `ignoreWhitespace`: treat lines differing only in whitespace as unchanged
* - `stripTrailingCr`: strip `\r` before diffing (useful for UNIX vs Windows)
*/
diffOptions?: DiffComputeOptions;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe not the clearest property name? diffOptions within BaseDiffOptions 🤷‍♂️

}

export type DiffComputeOptions = Pick<
CreatePatchOptionsNonabortable,
'ignoreWhitespace' | 'stripTrailingCr'
>;

export type BaseDiffOptionsWithDefaults = Required<
Omit<BaseDiffOptions, 'unsafeCSS' | 'preferredHighlighter'>
Omit<BaseDiffOptions, 'unsafeCSS' | 'preferredHighlighter' | 'diffOptions'>
>;

export type CustomPreProperties = Record<string, string | number | undefined>;
Expand Down
24 changes: 21 additions & 3 deletions packages/diffs/src/utils/areOptionsEqual.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import type { FileDiffOptions } from '../components/FileDiff';
import { DEFAULT_THEMES } from '../constants';
import type { FileOptions } from '../react';
import type { DiffComputeOptions } from '../types';
import { areObjectsEqual } from './areObjectsEqual';
import { areThemesEqual } from './areThemesEqual';

type AnyOptions<L> = FileOptions<L> | FileDiffOptions<L> | undefined;

export function areOptionsEqual<LAnnotation>(
optionsA: FileOptions<LAnnotation> | FileDiffOptions<LAnnotation> | undefined,
optionsB: FileOptions<LAnnotation> | FileDiffOptions<LAnnotation> | undefined
optionsA: AnyOptions<LAnnotation>,
optionsB: AnyOptions<LAnnotation>
): boolean {
const themeA = optionsA?.theme ?? DEFAULT_THEMES;
const themeB = optionsB?.theme ?? DEFAULT_THEMES;
const diffOptsA = getDiffOptions(optionsA);
const diffOptsB = getDiffOptions(optionsB);
return (
areThemesEqual(themeA, themeB) &&
areObjectsEqual(optionsA, optionsB, ['theme'])
areObjectsEqual(optionsA, optionsB, [
'theme',
'diffOptions' as keyof typeof optionsA,
]) &&
areObjectsEqual(diffOptsA ?? {}, diffOptsB ?? {})
);
}

function getDiffOptions<L>(
options: AnyOptions<L>
): DiffComputeOptions | undefined {
if (options != null && 'diffOptions' in options) {
return options.diffOptions;
}
return undefined;
}
19 changes: 19 additions & 0 deletions packages/diffs/test/parseDiffFromFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,23 @@ describe('parseDiffFromFile', () => {
const expectedNewLineCount = fileNew.split(/(?<=\n)/).length;
expect(result.additionLines.length).toBe(expectedNewLineCount);
});

test('ignoreWhitespace hides leading/trailing whitespace changes', () => {
const oldFile = {
name: 'test.txt',
contents: 'hello world\nfoo bar\n',
};
const newFile = {
name: 'test.txt',
contents: ' hello world\nfoo bar\n',
};

const withWhitespace = parseDiffFromFile(oldFile, newFile);
expect(withWhitespace.hunks.length).toBeGreaterThan(0);

const withoutWhitespace = parseDiffFromFile(oldFile, newFile, {
ignoreWhitespace: true,
});
expect(withoutWhitespace.hunks).toHaveLength(0);
});
});