|
|
'use strict';
Object.defineProperty(exports, '__esModule', { value: true }); exports.default = void 0;
var _cleanupSemantic = require('./cleanupSemantic');
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
// Given change op and array of diffs, return concatenated string:
// * include common strings
// * include change strings which have argument op with changeColor
// * exclude change strings which have opposite op
const concatenateRelevantDiffs = (op, diffs, changeColor) => diffs.reduce( (reduced, diff) => reduced + (diff[0] === _cleanupSemantic.DIFF_EQUAL ? diff[1] : diff[0] === op && diff[1].length !== 0 // empty if change is newline
? changeColor(diff[1]) : ''), '' ); // Encapsulate change lines until either a common newline or the end.
class ChangeBuffer { // incomplete line
// complete lines
constructor(op, changeColor) { _defineProperty(this, 'op', void 0);
_defineProperty(this, 'line', void 0);
_defineProperty(this, 'lines', void 0);
_defineProperty(this, 'changeColor', void 0);
this.op = op; this.line = []; this.lines = []; this.changeColor = changeColor; }
pushSubstring(substring) { this.pushDiff(new _cleanupSemantic.Diff(this.op, substring)); }
pushLine() { // Assume call only if line has at least one diff,
// therefore an empty line must have a diff which has an empty string.
// If line has multiple diffs, then assume it has a common diff,
// therefore change diffs have change color;
// otherwise then it has line color only.
this.lines.push( this.line.length !== 1 ? new _cleanupSemantic.Diff( this.op, concatenateRelevantDiffs(this.op, this.line, this.changeColor) ) : this.line[0][0] === this.op ? this.line[0] // can use instance
: new _cleanupSemantic.Diff(this.op, this.line[0][1]) // was common diff
); this.line.length = 0; }
isLineEmpty() { return this.line.length === 0; } // Minor input to buffer.
pushDiff(diff) { this.line.push(diff); } // Main input to buffer.
align(diff) { const string = diff[1];
if (string.includes('\n')) { const substrings = string.split('\n'); const iLast = substrings.length - 1; substrings.forEach((substring, i) => { if (i < iLast) { // The first substring completes the current change line.
// A middle substring is a change line.
this.pushSubstring(substring); this.pushLine(); } else if (substring.length !== 0) { // The last substring starts a change line, if it is not empty.
// Important: This non-empty condition also automatically omits
// the newline appended to the end of expected and received strings.
this.pushSubstring(substring); } }); } else { // Append non-multiline string to current change line.
this.pushDiff(diff); } } // Output from buffer.
moveLinesTo(lines) { if (!this.isLineEmpty()) { this.pushLine(); }
lines.push(...this.lines); this.lines.length = 0; } } // Encapsulate common and change lines.
class CommonBuffer { constructor(deleteBuffer, insertBuffer) { _defineProperty(this, 'deleteBuffer', void 0);
_defineProperty(this, 'insertBuffer', void 0);
_defineProperty(this, 'lines', void 0);
this.deleteBuffer = deleteBuffer; this.insertBuffer = insertBuffer; this.lines = []; }
pushDiffCommonLine(diff) { this.lines.push(diff); }
pushDiffChangeLines(diff) { const isDiffEmpty = diff[1].length === 0; // An empty diff string is redundant, unless a change line is empty.
if (!isDiffEmpty || this.deleteBuffer.isLineEmpty()) { this.deleteBuffer.pushDiff(diff); }
if (!isDiffEmpty || this.insertBuffer.isLineEmpty()) { this.insertBuffer.pushDiff(diff); } }
flushChangeLines() { this.deleteBuffer.moveLinesTo(this.lines); this.insertBuffer.moveLinesTo(this.lines); } // Input to buffer.
align(diff) { const op = diff[0]; const string = diff[1];
if (string.includes('\n')) { const substrings = string.split('\n'); const iLast = substrings.length - 1; substrings.forEach((substring, i) => { if (i === 0) { const subdiff = new _cleanupSemantic.Diff(op, substring);
if ( this.deleteBuffer.isLineEmpty() && this.insertBuffer.isLineEmpty() ) { // If both current change lines are empty,
// then the first substring is a common line.
this.flushChangeLines(); this.pushDiffCommonLine(subdiff); } else { // If either current change line is non-empty,
// then the first substring completes the change lines.
this.pushDiffChangeLines(subdiff); this.flushChangeLines(); } } else if (i < iLast) { // A middle substring is a common line.
this.pushDiffCommonLine(new _cleanupSemantic.Diff(op, substring)); } else if (substring.length !== 0) { // The last substring starts a change line, if it is not empty.
// Important: This non-empty condition also automatically omits
// the newline appended to the end of expected and received strings.
this.pushDiffChangeLines(new _cleanupSemantic.Diff(op, substring)); } }); } else { // Append non-multiline string to current change lines.
// Important: It cannot be at the end following empty change lines,
// because newline appended to the end of expected and received strings.
this.pushDiffChangeLines(diff); } } // Output from buffer.
getLines() { this.flushChangeLines(); return this.lines; } } // Given diffs from expected and received strings,
// return new array of diffs split or joined into lines.
//
// To correctly align a change line at the end, the algorithm:
// * assumes that a newline was appended to the strings
// * omits the last newline from the output array
//
// Assume the function is not called:
// * if either expected or received is empty string
// * if neither expected nor received is multiline string
const getAlignedDiffs = (diffs, changeColor) => { const deleteBuffer = new ChangeBuffer( _cleanupSemantic.DIFF_DELETE, changeColor ); const insertBuffer = new ChangeBuffer( _cleanupSemantic.DIFF_INSERT, changeColor ); const commonBuffer = new CommonBuffer(deleteBuffer, insertBuffer); diffs.forEach(diff => { switch (diff[0]) { case _cleanupSemantic.DIFF_DELETE: deleteBuffer.align(diff); break;
case _cleanupSemantic.DIFF_INSERT: insertBuffer.align(diff); break;
default: commonBuffer.align(diff); } }); return commonBuffer.getLines(); };
var _default = getAlignedDiffs; exports.default = _default;
|