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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class Diff extends PureComponent {
| splitView | `boolean` | `true` | Switch between `unified` and `split` view. |
| disableWordDiff | `boolean` | `false` | Show and hide word diff in a diff line. |
| compareMethod | `DiffMethod \| (string, string) => diff.Change[]` | `DiffMethod.CHARS` | JsDiff text diff method. See [Text block diff comparison](#text-block-diff-comparison). **Important:** For JSON files use `DiffMethod.JSON`, for YAML files use `DiffMethod.YAML` - these use optimized structural comparison that is significantly faster than generic text diff for large files. |
| ignoreWhitespace | `boolean` | `false` | Ignore leading and trailing whitespace when computing the line diff. |
| renderGutter | `(diffData) => ReactNode` | `undefined` | Function that can be used to render an extra gutter with various information next to the line number. |
| hideLineNumbers | `boolean` | `false` | Show and hide line numbers. |
| alwaysShowLines | `string[]` | `[]` | List of lines to always be shown, regardless of diff status. Line numbers are prefixed with `L` and `R` for the left and right section of the diff viewer, respectively. For example, `L-20` means 20th line in the left pane. `extraLinesSurroundingDiff` applies to these lines as well. |
Expand Down
10 changes: 8 additions & 2 deletions src/compute-lines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ const computeDiff = (
* @param lineCompareMethod JsDiff text diff method from https://github.com/kpdecker/jsdiff/tree/v4.0.1#api
* @param linesOffset line number to start counting from
* @param showLines lines that are always shown, regardless of diff
* @param ignoreWhitespace Ignore leading/trailing whitespace when comparing lines
*/
const computeLineInformation = (
oldString: string | Record<string, unknown>,
Expand All @@ -451,6 +452,7 @@ const computeLineInformation = (
linesOffset = 0,
showLines: string[] = [],
deferWordDiff = false,
ignoreWhitespace = false,
): ComputedLineInformation => {
let diffArray: Change[] = [];

Expand All @@ -468,11 +470,13 @@ const computeLineInformation = (
// If YAML parsing fails, fall back to line diff
diffArray = diff.diffLines(oldString, newString, {
newlineIsToken: false,
ignoreWhitespace,
});
}
} else {
diffArray = diff.diffLines(oldString, newString, {
newlineIsToken: false,
ignoreWhitespace,
});
}
} else {
Expand Down Expand Up @@ -638,6 +642,7 @@ const computeLineInformation = (
* @param lineCompareMethod JsDiff text diff method from https://github.com/kpdecker/jsdiff/tree/v4.0.1#api
* @param linesOffset line number to start counting from
* @param showLines lines that are always shown, regardless of diff
* @param ignoreWhitespace Ignore leading/trailing whitespace when comparing lines
* @returns Promise<ComputedLineInformation> - Resolves with line-by-line diff data from the worker.
*/
// Cached Blob URL for the worker - created once and reused
Expand Down Expand Up @@ -678,8 +683,9 @@ const computeLineInformationWorker = async (
showLines: string[] = [],
deferWordDiff = false,
disableWorker = false,
ignoreWhitespace = false,
): Promise<ComputedLineInformation> => {
const fallback = () => computeLineInformation(oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff);
const fallback = () => computeLineInformation(oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff, ignoreWhitespace);

if (disableWorker) {
return Promise.resolve(fallback());
Expand Down Expand Up @@ -711,7 +717,7 @@ const computeLineInformationWorker = async (
resolve(fallback());
};

worker.postMessage({ oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff });
worker.postMessage({ oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff, ignoreWhitespace });
});
};

Expand Down
4 changes: 2 additions & 2 deletions src/computeWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { computeLineInformation } from "./compute-lines.js";
* When the main thread sends a message to this worker (via postMessage), this function is triggered.
*/
self.onmessage = (e) => {
const { oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff } = e.data;
const result = computeLineInformation(oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff);
const { oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff, ignoreWhitespace } = e.data;
const result = computeLineInformation(oldString, newString, disableWordDiff, lineCompareMethod, linesOffset, showLines, deferWordDiff, ignoreWhitespace);
self.postMessage(result);
};
8 changes: 8 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ export interface ReactDiffViewerProps {
disableWordDiff?: boolean;
// JsDiff text diff method from https://github.com/kpdecker/jsdiff/tree/v4.0.1#api
compareMethod?: DiffMethod | ((oldStr: string, newStr: string) => Change[]);
// Ignore leading/trailing whitespace when computing the line diff, so lines that
// differ only in indentation or trailing spaces are not reported as changes.
ignoreWhitespace?: boolean;
// Number of unmodified lines surrounding each line diff.
extraLinesSurroundingDiff?: number;
// Show/hide line number.
Expand Down Expand Up @@ -425,6 +428,7 @@ class DiffViewer extends React.Component<
highlightLines: [],
disableWordDiff: false,
compareMethod: DiffMethod.CHARS,
ignoreWhitespace: false,
styles: {},
hideLineNumbers: false,
extraLinesSurroundingDiff: 3,
Expand Down Expand Up @@ -1208,6 +1212,7 @@ class DiffViewer extends React.Component<
linesOffset,
alwaysShowLines,
extraLinesSurroundingDiff,
ignoreWhitespace,
} = this.props;

return JSON.stringify({
Expand All @@ -1218,6 +1223,7 @@ class DiffViewer extends React.Component<
linesOffset,
alwaysShowLines,
extraLinesSurroundingDiff,
ignoreWhitespace,
});
}

Expand Down Expand Up @@ -1270,6 +1276,7 @@ class DiffViewer extends React.Component<
this.props.alwaysShowLines,
shouldDeferWordDiff,
this.props.disableWorker,
this.props.ignoreWhitespace,
);

const rawExtraLines = this.props.extraLinesSurroundingDiff ?? 3;
Expand Down Expand Up @@ -1662,6 +1669,7 @@ class DiffViewer extends React.Component<
prevProps.newValue !== this.props.newValue ||
prevProps.compareMethod !== this.props.compareMethod ||
prevProps.disableWordDiff !== this.props.disableWordDiff ||
prevProps.ignoreWhitespace !== this.props.ignoreWhitespace ||
prevProps.linesOffset !== this.props.linesOffset
) {
// Clear word diff cache when diff changes
Expand Down
32 changes: 32 additions & 0 deletions test/compute-lines.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,38 @@ Also this info`;
diffLines: [0, 1],
});
});

describe("Ignoring whitespace", (): void => {
const oldCode = ["function example() {", " const x = 1;", " return x;", "}"].join("\n");

it("Should report indentation-only changes by default", (): void => {
const newCode = ["function example() {", " const x = 1;", " return x;", "}"].join("\n");

expect(computeLineInformation(oldCode, newCode).diffLines).toEqual([1]);
});

it("Should ignore indentation-only changes when ignoreWhitespace is set", (): void => {
const newCode = ["function example() {", " const x = 1;", " return x;", "}"].join("\n");

const result = computeLineInformation(newCode, oldCode, false, undefined, 0, [], false, true);

expect(result.diffLines).toEqual([]);
expect(result.lineInformation.every(({ left, right }) => left.type === 0 && right.type === 0)).toBe(true);
});

it("Should ignore trailing-whitespace-only changes when ignoreWhitespace is set", (): void => {
const newCode = ["function example() {", " const x = 1; ", " return x;", "}"].join("\n");

expect(computeLineInformation(oldCode, newCode).diffLines).toEqual([1]);
expect(computeLineInformation(oldCode, newCode, false, undefined, 0, [], false, true).diffLines).toEqual([]);
});

it("Should still report real changes when ignoreWhitespace is set", (): void => {
const newCode = ["function example() {", " const x = 2;", " return x;", "}"].join("\n");

expect(computeLineInformation(oldCode, newCode, false, undefined, 0, [], false, true).diffLines).toEqual([1]);
});
});
});

import * as diff from 'diff';
Expand Down