generate-differences
Version:
Generate differences between original source and formmated source
687 lines (684 loc) • 23.8 kB
JavaScript
//#region node_modules/.pnpm/diff-match-patch-es@1.0.1/node_modules/diff-match-patch-es/dist/index.mjs
const defaultOptions = /* @__PURE__ */ Object.freeze({
diffTimeout: 1,
diffEditCost: 4,
matchThreshold: .5,
matchDistance: 1e3,
patchDeleteThreshold: .5,
patchMargin: 4,
matchMaxBits: 32
});
function resolveOptions(options) {
if (options?.__resolved) return options;
const resolved = {
...defaultOptions,
...options
};
Object.defineProperty(resolved, "__resolved", {
value: true,
enumerable: false
});
return resolved;
}
const DIFF_DELETE = -1;
const DIFF_INSERT = 1;
const DIFF_EQUAL = 0;
function createDiff(op, text) {
return [op, text];
}
function diffMain(text1, text2, options, opt_checklines = true, opt_deadline) {
const resolved = resolveOptions(options);
if (typeof opt_deadline == "undefined") if (resolved.diffTimeout <= 0) opt_deadline = Number.MAX_VALUE;
else opt_deadline = (/* @__PURE__ */ new Date()).getTime() + resolved.diffTimeout * 1e3;
const deadline = opt_deadline;
if (text1 == null || text2 == null) throw new Error("Null input. (diff_main)");
if (text1 === text2) {
if (text1) return [createDiff(DIFF_EQUAL, text1)];
return [];
}
const checklines = opt_checklines;
let commonlength = diffCommonPrefix(text1, text2);
const commonprefix = text1.substring(0, commonlength);
text1 = text1.substring(commonlength);
text2 = text2.substring(commonlength);
commonlength = diffCommonSuffix(text1, text2);
const commonsuffix = text1.substring(text1.length - commonlength);
text1 = text1.substring(0, text1.length - commonlength);
text2 = text2.substring(0, text2.length - commonlength);
const diffs = diffCompute(text1, text2, resolved, checklines, deadline);
if (commonprefix) diffs.unshift(createDiff(DIFF_EQUAL, commonprefix));
if (commonsuffix) diffs.push(createDiff(DIFF_EQUAL, commonsuffix));
diffCleanupMerge(diffs);
return diffs;
}
function diffCompute(text1, text2, options, checklines, deadline) {
let diffs;
if (!text1) return [createDiff(DIFF_INSERT, text2)];
if (!text2) return [createDiff(DIFF_DELETE, text1)];
const longtext = text1.length > text2.length ? text1 : text2;
const shorttext = text1.length > text2.length ? text2 : text1;
const i = longtext.indexOf(shorttext);
if (i !== -1) {
diffs = [
createDiff(DIFF_INSERT, longtext.substring(0, i)),
createDiff(DIFF_EQUAL, shorttext),
createDiff(DIFF_INSERT, longtext.substring(i + shorttext.length))
];
if (text1.length > text2.length) diffs[0][0] = diffs[2][0] = DIFF_DELETE;
return diffs;
}
if (shorttext.length === 1) return [createDiff(DIFF_DELETE, text1), createDiff(DIFF_INSERT, text2)];
const hm = diffHalfMatch(text1, text2, options);
if (hm) {
const text1_a = hm[0];
const text1_b = hm[1];
const text2_a = hm[2];
const text2_b = hm[3];
const mid_common = hm[4];
const diffs_a = diffMain(text1_a, text2_a, options, checklines, deadline);
const diffs_b = diffMain(text1_b, text2_b, options, checklines, deadline);
return diffs_a.concat([createDiff(DIFF_EQUAL, mid_common)], diffs_b);
}
if (checklines && text1.length > 100 && text2.length > 100) return diffLineMode(text1, text2, options, deadline);
return diffBisect(text1, text2, options, deadline);
}
function diffLineMode(text1, text2, options, deadline) {
const a = diffLinesToChars(text1, text2);
text1 = a.chars1;
text2 = a.chars2;
const linearray = a.lineArray;
const diffs = diffMain(text1, text2, options, false, deadline);
diffCharsToLines(diffs, linearray);
diffCleanupSemantic(diffs);
diffs.push(createDiff(DIFF_EQUAL, ""));
let pointer = 0;
let count_delete = 0;
let count_insert = 0;
let text_delete = "";
let text_insert = "";
while (pointer < diffs.length) {
switch (diffs[pointer][0]) {
case DIFF_INSERT:
count_insert++;
text_insert += diffs[pointer][1];
break;
case DIFF_DELETE:
count_delete++;
text_delete += diffs[pointer][1];
break;
case DIFF_EQUAL:
if (count_delete >= 1 && count_insert >= 1) {
diffs.splice(pointer - count_delete - count_insert, count_delete + count_insert);
pointer = pointer - count_delete - count_insert;
const subDiff = diffMain(text_delete, text_insert, options, false, deadline);
for (let j = subDiff.length - 1; j >= 0; j--) diffs.splice(pointer, 0, subDiff[j]);
pointer = pointer + subDiff.length;
}
count_insert = 0;
count_delete = 0;
text_delete = "";
text_insert = "";
break;
}
pointer++;
}
diffs.pop();
return diffs;
}
function diffBisect(text1, text2, options, deadline) {
const text1_length = text1.length;
const text2_length = text2.length;
const max_d = Math.ceil((text1_length + text2_length) / 2);
const v_offset = max_d;
const v_length = 2 * max_d;
const v1 = new Array(v_length);
const v2 = new Array(v_length);
for (let x = 0; x < v_length; x++) {
v1[x] = -1;
v2[x] = -1;
}
v1[v_offset + 1] = 0;
v2[v_offset + 1] = 0;
const delta = text1_length - text2_length;
const front = delta % 2 !== 0;
let k1start = 0;
let k1end = 0;
let k2start = 0;
let k2end = 0;
for (let d = 0; d < max_d; d++) {
if ((/* @__PURE__ */ new Date()).getTime() > deadline) break;
for (let k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
const k1_offset = v_offset + k1;
let x1;
if (k1 === -d || k1 !== d && v1[k1_offset - 1] < v1[k1_offset + 1]) x1 = v1[k1_offset + 1];
else x1 = v1[k1_offset - 1] + 1;
let y1 = x1 - k1;
while (x1 < text1_length && y1 < text2_length && text1.charAt(x1) === text2.charAt(y1)) {
x1++;
y1++;
}
v1[k1_offset] = x1;
if (x1 > text1_length) k1end += 2;
else if (y1 > text2_length) k1start += 2;
else if (front) {
const k2_offset = v_offset + delta - k1;
if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] !== -1) {
const x2 = text1_length - v2[k2_offset];
if (x1 >= x2) return diffBisectSplit(text1, text2, options, x1, y1, deadline);
}
}
}
for (let k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
const k2_offset = v_offset + k2;
let x2;
if (k2 === -d || k2 !== d && v2[k2_offset - 1] < v2[k2_offset + 1]) x2 = v2[k2_offset + 1];
else x2 = v2[k2_offset - 1] + 1;
let y2 = x2 - k2;
while (x2 < text1_length && y2 < text2_length && text1.charAt(text1_length - x2 - 1) === text2.charAt(text2_length - y2 - 1)) {
x2++;
y2++;
}
v2[k2_offset] = x2;
if (x2 > text1_length) k2end += 2;
else if (y2 > text2_length) k2start += 2;
else if (!front) {
const k1_offset = v_offset + delta - k2;
if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] !== -1) {
const x1 = v1[k1_offset];
const y1 = v_offset + x1 - k1_offset;
x2 = text1_length - x2;
if (x1 >= x2) return diffBisectSplit(text1, text2, options, x1, y1, deadline);
}
}
}
}
return [createDiff(DIFF_DELETE, text1), createDiff(DIFF_INSERT, text2)];
}
function diffBisectSplit(text1, text2, options, x, y, deadline) {
const text1a = text1.substring(0, x);
const text2a = text2.substring(0, y);
const text1b = text1.substring(x);
const text2b = text2.substring(y);
const diffs = diffMain(text1a, text2a, options, false, deadline);
const diffsb = diffMain(text1b, text2b, options, false, deadline);
return diffs.concat(diffsb);
}
function diffLinesToChars(text1, text2) {
const lineArray = [];
const lineHash = {};
let maxLines = 4e4;
lineArray[0] = "";
function diffLinesToCharsMunge(text) {
let chars = "";
let lineStart = 0;
let lineEnd = -1;
let lineArrayLength = lineArray.length;
while (lineEnd < text.length - 1) {
lineEnd = text.indexOf("\n", lineStart);
if (lineEnd === -1) lineEnd = text.length - 1;
let line = text.substring(lineStart, lineEnd + 1);
if (lineHash.hasOwnProperty ? Object.prototype.hasOwnProperty.call(lineHash, line) : lineHash[line] !== void 0) chars += String.fromCharCode(lineHash[line]);
else {
if (lineArrayLength === maxLines) {
line = text.substring(lineStart);
lineEnd = text.length;
}
chars += String.fromCharCode(lineArrayLength);
lineHash[line] = lineArrayLength;
lineArray[lineArrayLength++] = line;
}
lineStart = lineEnd + 1;
}
return chars;
}
const chars1 = diffLinesToCharsMunge(text1);
maxLines = 65535;
return {
chars1,
chars2: diffLinesToCharsMunge(text2),
lineArray
};
}
function diffCharsToLines(diffs, lineArray) {
for (let i = 0; i < diffs.length; i++) {
const chars = diffs[i][1];
const text = [];
for (let j = 0; j < chars.length; j++) text[j] = lineArray[chars.charCodeAt(j)];
diffs[i][1] = text.join("");
}
}
function diffCommonPrefix(text1, text2) {
if (!text1 || !text2 || text1.charAt(0) !== text2.charAt(0)) return 0;
let pointermin = 0;
let pointermax = Math.min(text1.length, text2.length);
let pointermid = pointermax;
let pointerstart = 0;
while (pointermin < pointermid) {
if (text1.substring(pointerstart, pointermid) === text2.substring(pointerstart, pointermid)) {
pointermin = pointermid;
pointerstart = pointermin;
} else pointermax = pointermid;
pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
}
return pointermid;
}
function diffCommonSuffix(text1, text2) {
if (!text1 || !text2 || text1.charAt(text1.length - 1) !== text2.charAt(text2.length - 1)) return 0;
let pointermin = 0;
let pointermax = Math.min(text1.length, text2.length);
let pointermid = pointermax;
let pointerend = 0;
while (pointermin < pointermid) {
if (text1.substring(text1.length - pointermid, text1.length - pointerend) === text2.substring(text2.length - pointermid, text2.length - pointerend)) {
pointermin = pointermid;
pointerend = pointermin;
} else pointermax = pointermid;
pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
}
return pointermid;
}
function diffCommonOverlap(text1, text2) {
const text1_length = text1.length;
const text2_length = text2.length;
if (text1_length === 0 || text2_length === 0) return 0;
if (text1_length > text2_length) text1 = text1.substring(text1_length - text2_length);
else if (text1_length < text2_length) text2 = text2.substring(0, text1_length);
const text_length = Math.min(text1_length, text2_length);
if (text1 === text2) return text_length;
let best = 0;
let length = 1;
while (true) {
const pattern = text1.substring(text_length - length);
const found = text2.indexOf(pattern);
if (found === -1) return best;
length += found;
if (found === 0 || text1.substring(text_length - length) === text2.substring(0, length)) {
best = length;
length++;
}
}
}
function diffHalfMatch(text1, text2, options) {
if (options.diffTimeout <= 0) return null;
const longtext = text1.length > text2.length ? text1 : text2;
const shorttext = text1.length > text2.length ? text2 : text1;
if (longtext.length < 4 || shorttext.length * 2 < longtext.length) return null;
function diffHalfMatchI(longtext2, shorttext2, i) {
const seed = longtext2.substring(i, i + Math.floor(longtext2.length / 4));
let j = -1;
let best_common = "";
let best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
while ((j = shorttext2.indexOf(seed, j + 1)) !== -1) {
const prefixLength = diffCommonPrefix(longtext2.substring(i), shorttext2.substring(j));
const suffixLength = diffCommonSuffix(longtext2.substring(0, i), shorttext2.substring(0, j));
if (best_common.length < suffixLength + prefixLength) {
best_common = shorttext2.substring(j - suffixLength, j) + shorttext2.substring(j, j + prefixLength);
best_longtext_a = longtext2.substring(0, i - suffixLength);
best_longtext_b = longtext2.substring(i + prefixLength);
best_shorttext_a = shorttext2.substring(0, j - suffixLength);
best_shorttext_b = shorttext2.substring(j + prefixLength);
}
}
if (best_common.length * 2 >= longtext2.length) return [
best_longtext_a,
best_longtext_b,
best_shorttext_a,
best_shorttext_b,
best_common
];
else return null;
}
const hm1 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 4));
const hm2 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 2));
let hm;
if (!hm1 && !hm2) return null;
else if (!hm2) hm = hm1;
else if (!hm1) hm = hm2;
else hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
let text1_a, text1_b, text2_a, text2_b;
if (text1.length > text2.length) {
text1_a = hm[0];
text1_b = hm[1];
text2_a = hm[2];
text2_b = hm[3];
} else {
text2_a = hm[0];
text2_b = hm[1];
text1_a = hm[2];
text1_b = hm[3];
}
const mid_common = hm[4];
return [
text1_a,
text1_b,
text2_a,
text2_b,
mid_common
];
}
function diffCleanupSemantic(diffs) {
let changes = false;
const equalities = [];
let equalitiesLength = 0;
let lastEquality = null;
let pointer = 0;
let length_insertions1 = 0;
let length_deletions1 = 0;
let length_insertions2 = 0;
let length_deletions2 = 0;
while (pointer < diffs.length) {
if (diffs[pointer][0] === DIFF_EQUAL) {
equalities[equalitiesLength++] = pointer;
length_insertions1 = length_insertions2;
length_deletions1 = length_deletions2;
length_insertions2 = 0;
length_deletions2 = 0;
lastEquality = diffs[pointer][1];
} else {
if (diffs[pointer][0] === DIFF_INSERT) length_insertions2 += diffs[pointer][1].length;
else length_deletions2 += diffs[pointer][1].length;
if (lastEquality && lastEquality.length <= Math.max(length_insertions1, length_deletions1) && lastEquality.length <= Math.max(length_insertions2, length_deletions2)) {
diffs.splice(equalities[equalitiesLength - 1], 0, createDiff(DIFF_DELETE, lastEquality));
diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
equalitiesLength--;
equalitiesLength--;
pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
length_insertions1 = 0;
length_deletions1 = 0;
length_insertions2 = 0;
length_deletions2 = 0;
lastEquality = null;
changes = true;
}
}
pointer++;
}
if (changes) diffCleanupMerge(diffs);
diffCleanupSemanticLossless(diffs);
pointer = 1;
while (pointer < diffs.length) {
if (diffs[pointer - 1][0] === DIFF_DELETE && diffs[pointer][0] === DIFF_INSERT) {
const deletion = diffs[pointer - 1][1];
const insertion = diffs[pointer][1];
const overlap_length1 = diffCommonOverlap(deletion, insertion);
const overlap_length2 = diffCommonOverlap(insertion, deletion);
if (overlap_length1 >= overlap_length2) {
if (overlap_length1 >= deletion.length / 2 || overlap_length1 >= insertion.length / 2) {
diffs.splice(pointer, 0, createDiff(DIFF_EQUAL, insertion.substring(0, overlap_length1)));
diffs[pointer - 1][1] = deletion.substring(0, deletion.length - overlap_length1);
diffs[pointer + 1][1] = insertion.substring(overlap_length1);
pointer++;
}
} else if (overlap_length2 >= deletion.length / 2 || overlap_length2 >= insertion.length / 2) {
diffs.splice(pointer, 0, createDiff(DIFF_EQUAL, deletion.substring(0, overlap_length2)));
diffs[pointer - 1][0] = DIFF_INSERT;
diffs[pointer - 1][1] = insertion.substring(0, insertion.length - overlap_length2);
diffs[pointer + 1][0] = DIFF_DELETE;
diffs[pointer + 1][1] = deletion.substring(overlap_length2);
pointer++;
}
pointer++;
}
pointer++;
}
}
const nonAlphaNumericRegex_ = /[^a-z0-9]/i;
const whitespaceRegex_ = /\s/;
const linebreakRegex_ = /[\r\n]/;
const blanklineEndRegex_ = /\n\r?\n$/;
const blanklineStartRegex_ = /^\r?\n\r?\n/;
function diffCleanupSemanticLossless(diffs) {
function diffCleanupSemanticScore(one, two) {
if (!one || !two) return 6;
const char1 = one.charAt(one.length - 1);
const char2 = two.charAt(0);
const nonAlphaNumeric1 = char1.match(nonAlphaNumericRegex_);
const nonAlphaNumeric2 = char2.match(nonAlphaNumericRegex_);
const whitespace1 = nonAlphaNumeric1 && char1.match(whitespaceRegex_);
const whitespace2 = nonAlphaNumeric2 && char2.match(whitespaceRegex_);
const lineBreak1 = whitespace1 && char1.match(linebreakRegex_);
const lineBreak2 = whitespace2 && char2.match(linebreakRegex_);
const blankLine1 = lineBreak1 && one.match(blanklineEndRegex_);
const blankLine2 = lineBreak2 && two.match(blanklineStartRegex_);
if (blankLine1 || blankLine2) return 5;
else if (lineBreak1 || lineBreak2) return 4;
else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) return 3;
else if (whitespace1 || whitespace2) return 2;
else if (nonAlphaNumeric1 || nonAlphaNumeric2) return 1;
return 0;
}
let pointer = 1;
while (pointer < diffs.length - 1) {
if (diffs[pointer - 1][0] === DIFF_EQUAL && diffs[pointer + 1][0] === DIFF_EQUAL) {
let equality1 = diffs[pointer - 1][1];
let edit = diffs[pointer][1];
let equality2 = diffs[pointer + 1][1];
const commonOffset = diffCommonSuffix(equality1, edit);
if (commonOffset) {
const commonString = edit.substring(edit.length - commonOffset);
equality1 = equality1.substring(0, equality1.length - commonOffset);
edit = commonString + edit.substring(0, edit.length - commonOffset);
equality2 = commonString + equality2;
}
let bestEquality1 = equality1;
let bestEdit = edit;
let bestEquality2 = equality2;
let bestScore = diffCleanupSemanticScore(equality1, edit) + diffCleanupSemanticScore(edit, equality2);
while (edit.charAt(0) === equality2.charAt(0)) {
equality1 += edit.charAt(0);
edit = edit.substring(1) + equality2.charAt(0);
equality2 = equality2.substring(1);
const score = diffCleanupSemanticScore(equality1, edit) + diffCleanupSemanticScore(edit, equality2);
if (score >= bestScore) {
bestScore = score;
bestEquality1 = equality1;
bestEdit = edit;
bestEquality2 = equality2;
}
}
if (diffs[pointer - 1][1] !== bestEquality1) {
if (bestEquality1) diffs[pointer - 1][1] = bestEquality1;
else {
diffs.splice(pointer - 1, 1);
pointer--;
}
diffs[pointer][1] = bestEdit;
if (bestEquality2) diffs[pointer + 1][1] = bestEquality2;
else {
diffs.splice(pointer + 1, 1);
pointer--;
}
}
}
pointer++;
}
}
function diffCleanupMerge(diffs) {
diffs.push(createDiff(DIFF_EQUAL, ""));
let pointer = 0;
let count_delete = 0;
let count_insert = 0;
let text_delete = "";
let text_insert = "";
let commonlength;
while (pointer < diffs.length) switch (diffs[pointer][0]) {
case DIFF_INSERT:
count_insert++;
text_insert += diffs[pointer][1];
pointer++;
break;
case DIFF_DELETE:
count_delete++;
text_delete += diffs[pointer][1];
pointer++;
break;
case DIFF_EQUAL:
if (count_delete + count_insert > 1) {
if (count_delete !== 0 && count_insert !== 0) {
commonlength = diffCommonPrefix(text_insert, text_delete);
if (commonlength !== 0) {
if (pointer - count_delete - count_insert > 0 && diffs[pointer - count_delete - count_insert - 1][0] === DIFF_EQUAL) diffs[pointer - count_delete - count_insert - 1][1] += text_insert.substring(0, commonlength);
else {
diffs.splice(0, 0, createDiff(DIFF_EQUAL, text_insert.substring(0, commonlength)));
pointer++;
}
text_insert = text_insert.substring(commonlength);
text_delete = text_delete.substring(commonlength);
}
commonlength = diffCommonSuffix(text_insert, text_delete);
if (commonlength !== 0) {
diffs[pointer][1] = text_insert.substring(text_insert.length - commonlength) + diffs[pointer][1];
text_insert = text_insert.substring(0, text_insert.length - commonlength);
text_delete = text_delete.substring(0, text_delete.length - commonlength);
}
}
pointer -= count_delete + count_insert;
diffs.splice(pointer, count_delete + count_insert);
if (text_delete.length) {
diffs.splice(pointer, 0, createDiff(DIFF_DELETE, text_delete));
pointer++;
}
if (text_insert.length) {
diffs.splice(pointer, 0, createDiff(DIFF_INSERT, text_insert));
pointer++;
}
pointer++;
} else if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) {
diffs[pointer - 1][1] += diffs[pointer][1];
diffs.splice(pointer, 1);
} else pointer++;
count_insert = 0;
count_delete = 0;
text_delete = "";
text_insert = "";
break;
}
if (diffs[diffs.length - 1][1] === "") diffs.pop();
let changes = false;
pointer = 1;
while (pointer < diffs.length - 1) {
if (diffs[pointer - 1][0] === DIFF_EQUAL && diffs[pointer + 1][0] === DIFF_EQUAL) {
if (diffs[pointer][1].substring(diffs[pointer][1].length - diffs[pointer - 1][1].length) === diffs[pointer - 1][1]) {
diffs[pointer][1] = diffs[pointer - 1][1] + diffs[pointer][1].substring(0, diffs[pointer][1].length - diffs[pointer - 1][1].length);
diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
diffs.splice(pointer - 1, 1);
changes = true;
} else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) === diffs[pointer + 1][1]) {
diffs[pointer - 1][1] += diffs[pointer + 1][1];
diffs[pointer][1] = diffs[pointer][1].substring(diffs[pointer + 1][1].length) + diffs[pointer + 1][1];
diffs.splice(pointer + 1, 1);
changes = true;
}
}
pointer++;
}
if (changes) diffCleanupMerge(diffs);
}
//#endregion
//#region src/constants.ts
const DIFFERENCE = {
DELETE: "delete",
INSERT: "insert",
REPLACE: "replace"
};
const DIFF = {
DELETE: -1,
EQUAL: 0,
INSERT: 1
};
const RE_LINE_ENDING = /\r\n|[\r\n\u2028\u2029]/;
//#endregion
//#region src/index.ts
/**
* Generate differences between original source and formmated source
*
* @param source - original source
* @param formatted - formatted source
* @param options - diff-match-patch options
* @returns generated differences
*
* @example
*
* ```ts
* import { generateDifferences } from 'generate-differences'
*
* const differences = generateDifferences('abc', 'edf')
*
* console.log({ differences })
* // [
* // {
* // "deleteText": "abc",
* // "insertText": "edf",
* // "offset": 0,
* // "operation": "replace",
* // },
* // ]
* ```
*/
function generateDifferences(source, formatted, options = {}) {
const differences = [];
const batch = [];
let { offset = 0, ...diffMatchPathOptions } = options;
const results = diffMain(source, formatted, diffMatchPathOptions);
function flush() {
let aheadDeleteText = "";
let aheadInsertText = "";
while (batch.length) {
const next = batch.shift();
const op = next[0];
const text = next[1];
switch (op) {
case DIFF.DELETE:
aheadDeleteText += text;
break;
case DIFF.EQUAL:
aheadDeleteText += text;
aheadInsertText += text;
break;
case DIFF.INSERT:
aheadInsertText += text;
break;
}
}
if (aheadDeleteText && aheadInsertText) differences.push({
deleteText: aheadDeleteText,
insertText: aheadInsertText,
offset,
operation: DIFFERENCE.REPLACE
});
else if (!aheadDeleteText && aheadInsertText) differences.push({
insertText: aheadInsertText,
offset,
operation: DIFFERENCE.INSERT
});
else if (aheadDeleteText && !aheadInsertText) differences.push({
deleteText: aheadDeleteText,
offset,
operation: DIFFERENCE.DELETE
});
offset += aheadDeleteText.length;
}
while (results.length) {
const result = results.shift();
const op = result[0];
const text = result[1];
switch (op) {
case DIFF.DELETE:
case DIFF.INSERT:
batch.push(result);
break;
case DIFF.EQUAL:
if (results.length) if (batch.length) if (RE_LINE_ENDING.test(text)) {
flush();
offset += text.length;
} else batch.push(result);
else offset += text.length;
break;
default: throw new Error(`Unexpected diff operation ${op}`);
}
}
if (batch.length && !results.length) flush();
return differences;
}
//#endregion
export { DIFFERENCE, generateDifferences };