react-diff-viewer
Version:
A simple and beautiful text diff viewer component made with diff and React
217 lines (216 loc) • 8.87 kB
JavaScript
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
Object.defineProperty(exports, "__esModule", { value: true });
var diff = require("diff");
var jsDiff = diff;
var DiffType;
(function (DiffType) {
DiffType[DiffType["DEFAULT"] = 0] = "DEFAULT";
DiffType[DiffType["ADDED"] = 1] = "ADDED";
DiffType[DiffType["REMOVED"] = 2] = "REMOVED";
})(DiffType = exports.DiffType || (exports.DiffType = {}));
// See https://github.com/kpdecker/jsdiff/tree/v4.0.1#api for more info on the below JsDiff methods
var DiffMethod;
(function (DiffMethod) {
DiffMethod["CHARS"] = "diffChars";
DiffMethod["WORDS"] = "diffWords";
DiffMethod["WORDS_WITH_SPACE"] = "diffWordsWithSpace";
DiffMethod["LINES"] = "diffLines";
DiffMethod["TRIMMED_LINES"] = "diffTrimmedLines";
DiffMethod["SENTENCES"] = "diffSentences";
DiffMethod["CSS"] = "diffCss";
})(DiffMethod = exports.DiffMethod || (exports.DiffMethod = {}));
/**
* Splits diff text by new line and computes final list of diff lines based on
* conditions.
*
* @param value Diff text from the js diff module.
*/
var constructLines = function (value) {
var lines = value.split('\n');
var isAllEmpty = lines.every(function (val) { return !val; });
if (isAllEmpty) {
// This is to avoid added an extra new line in the UI.
if (lines.length === 2) {
return [];
}
lines.pop();
return lines;
}
var lastLine = lines[lines.length - 1];
var firstLine = lines[0];
// Remove the first and last element if they are new line character. This is
// to avoid addition of extra new line in the UI.
if (!lastLine) {
lines.pop();
}
if (!firstLine) {
lines.shift();
}
return lines;
};
/**
* Computes word diff information in the line.
* [TODO]: Consider adding options argument for JsDiff text block comparison
*
* @param oldValue Old word in the line.
* @param newValue New word in the line.
* @param compareMethod JsDiff text diff method from https://github.com/kpdecker/jsdiff/tree/v4.0.1#api
*/
var computeDiff = function (oldValue, newValue, compareMethod) {
if (compareMethod === void 0) { compareMethod = DiffMethod.CHARS; }
var diffArray = jsDiff[compareMethod](oldValue, newValue);
var computedDiff = {
left: [],
right: [],
};
diffArray.forEach(function (_a) {
var added = _a.added, removed = _a.removed, value = _a.value;
var diffInformation = {};
if (added) {
diffInformation.type = DiffType.ADDED;
diffInformation.value = value;
computedDiff.right.push(diffInformation);
}
if (removed) {
diffInformation.type = DiffType.REMOVED;
diffInformation.value = value;
computedDiff.left.push(diffInformation);
}
if (!removed && !added) {
diffInformation.type = DiffType.DEFAULT;
diffInformation.value = value;
computedDiff.right.push(diffInformation);
computedDiff.left.push(diffInformation);
}
return diffInformation;
});
return computedDiff;
};
/**
* [TODO]: Think about moving common left and right value assignment to a
* common place. Better readability?
*
* Computes line wise information based in the js diff information passed. Each
* line contains information about left and right section. Left side denotes
* deletion and right side denotes addition.
*
* @param oldString Old string to compare.
* @param newString New string to compare with old string.
* @param disableWordDiff Flag to enable/disable word diff.
* @param compareMethod JsDiff text diff method from https://github.com/kpdecker/jsdiff/tree/v4.0.1#api
* @param linesOffset line number to start counting from
*/
var computeLineInformation = function (oldString, newString, disableWordDiff, compareMethod, linesOffset) {
if (disableWordDiff === void 0) { disableWordDiff = false; }
if (compareMethod === void 0) { compareMethod = DiffMethod.CHARS; }
if (linesOffset === void 0) { linesOffset = 0; }
var diffArray = diff.diffLines(oldString.trimRight(), newString.trimRight(), {
newlineIsToken: true,
ignoreWhitespace: false,
ignoreCase: false,
});
var rightLineNumber = linesOffset;
var leftLineNumber = linesOffset;
var lineInformation = [];
var counter = 0;
var diffLines = [];
var ignoreDiffIndexes = [];
var getLineInformation = function (value, diffIndex, added, removed, evaluateOnlyFirstLine) {
var lines = constructLines(value);
return lines
.map(function (line, lineIndex) {
var left = {};
var right = {};
if (ignoreDiffIndexes.includes(diffIndex + "-" + lineIndex) ||
(evaluateOnlyFirstLine && lineIndex !== 0)) {
return undefined;
}
if (added || removed) {
if (!diffLines.includes(counter)) {
diffLines.push(counter);
}
if (removed) {
leftLineNumber += 1;
left.lineNumber = leftLineNumber;
left.type = DiffType.REMOVED;
left.value = line || ' ';
// When the current line is of type REMOVED, check the next item in
// the diff array whether it is of type ADDED. If true, the current
// diff will be marked as both REMOVED and ADDED. Meaning, the
// current line is a modification.
var nextDiff = diffArray[diffIndex + 1];
if (nextDiff && nextDiff.added) {
var nextDiffLines = constructLines(nextDiff.value)[lineIndex];
if (nextDiffLines) {
var _a = getLineInformation(nextDiff.value, diffIndex, true, false, true)[0].right, rightValue = _a.value, lineNumber = _a.lineNumber, type = _a.type;
// When identified as modification, push the next diff to ignore
// list as the next value will be added in this line computation as
// right and left values.
ignoreDiffIndexes.push(diffIndex + 1 + "-" + lineIndex);
right.lineNumber = lineNumber;
right.type = type;
// Do word level diff and assign the corresponding values to the
// left and right diff information object.
if (disableWordDiff) {
right.value = rightValue;
}
else {
var computedDiff = computeDiff(line, rightValue, compareMethod);
right.value = computedDiff.right;
left.value = computedDiff.left;
}
}
}
}
else {
rightLineNumber += 1;
right.lineNumber = rightLineNumber;
right.type = DiffType.ADDED;
right.value = line;
}
}
else {
leftLineNumber += 1;
rightLineNumber += 1;
left.lineNumber = leftLineNumber;
left.type = DiffType.DEFAULT;
left.value = line;
right.lineNumber = rightLineNumber;
right.type = DiffType.DEFAULT;
right.value = line;
}
counter += 1;
return { right: right, left: left };
})
.filter(Boolean);
};
diffArray.forEach(function (_a, index) {
var added = _a.added, removed = _a.removed, value = _a.value;
lineInformation = __spread(lineInformation, getLineInformation(value, index, added, removed));
});
return {
lineInformation: lineInformation,
diffLines: diffLines,
};
};
exports.computeLineInformation = computeLineInformation;
;