codekingpro/portable-devtools
115k
1import Diff from './base.js';
2import { generateOptions } from '../util/params.js';
3class LineDiff extends Diff {
4 constructor() {
5 super(...arguments);
6 this.tokenize = tokenize;
7 }
8 equals(left, right, options) {
9 // If we're ignoring whitespace, we need to normalise lines by stripping
10 // whitespace before checking equality. (This has an annoying interaction
11 // with newlineIsToken that requires special handling: if newlines get their
12 // own token, then we DON'T want to trim the *newline* tokens down to empty
13 // strings, since this would cause us to treat whitespace-only line content
14 // as equal to a separator between lines, which would be weird and
15 // inconsistent with the documented behavior of the options.)
16 if (options.ignoreWhitespace) {
17 if (!options.newlineIsToken || !left.includes('\n')) {
18 left = left.trim();
19 }
20 if (!options.newlineIsToken || !right.includes('\n')) {
21 right = right.trim();
22 }
23 }
24 else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
25 if (left.endsWith('\n')) {
26 left = left.slice(0, -1);
27 }
28 if (right.endsWith('\n')) {
29 right = right.slice(0, -1);
30 }
31 }
32 return super.equals(left, right, options);
33 }
34}
35export const lineDiff = new LineDiff();
36export function diffLines(oldStr, newStr, options) {
37 return lineDiff.diff(oldStr, newStr, options);
38}
39export function diffTrimmedLines(oldStr, newStr, options) {
40 options = generateOptions(options, { ignoreWhitespace: true });
41 return lineDiff.diff(oldStr, newStr, options);
42}
43// Exported standalone so it can be used from jsonDiff too.
44export function tokenize(value, options) {
45 if (options.stripTrailingCr) {
46 // remove one \r before \n to match GNU diff's --strip-trailing-cr behavior
47 value = value.replace(/\r\n/g, '\n');
48 }
49 const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
50 // Ignore the final empty token that occurs if the string ends with a new line
51 if (!linesAndNewlines[linesAndNewlines.length - 1]) {
52 linesAndNewlines.pop();
53 }
54 // Merge the content and line separators into single tokens
55 for (let i = 0; i < linesAndNewlines.length; i++) {
56 const line = linesAndNewlines[i];
57 if (i % 2 && !options.newlineIsToken) {
58 retLines[retLines.length - 1] += line;
59 }
60 else {
61 retLines.push(line);
62 }
63 }
64 return retLines;
65}
66 