@rightcapital/phpdoc-parser
Version:
TypeScript version of PHPDoc parser with support for intersection types and generics
112 lines (111 loc) • 3.68 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Differ = void 0;
const diff_elem_1 = require("./diff-elem");
class Differ {
constructor(isEqual) {
this.isEqual = isEqual;
}
diff(old, newElements) {
const [trace, x, y] = this.calculateTrace(old, newElements);
return this.extractDiff(trace, x, y, old, newElements);
}
diffWithReplacements(old, newElements) {
return this.coalesceReplacements(this.diff(old, newElements));
}
calculateTrace(old, newElements) {
const n = old.length;
const m = newElements.length;
const max = n + m;
const v = { 1: 0 };
const trace = [];
for (let d = 0; d <= max; d++) {
trace.push(Object.assign({}, v));
for (let k = -d; k <= d; k += 2) {
let x;
if (k === -d || (k !== d && v[k - 1] < v[k + 1])) {
x = v[k + 1];
}
else {
x = v[k - 1] + 1;
}
let y = x - k;
while (x < n && y < m && this.isEqual(old[x], newElements[y])) {
x++;
y++;
}
v[k] = x;
if (x >= n && y >= m) {
return [trace, x, y];
}
}
}
throw new Error('Should not happen');
}
extractDiff(trace, x, y, old, newElements) {
const result = [];
for (let d = trace.length - 1; d >= 0; d--) {
const v = trace[d];
const k = x - y;
let prevK;
if (k === -d || (k !== d && v[k - 1] < v[k + 1])) {
prevK = k + 1;
}
else {
prevK = k - 1;
}
const prevX = v[prevK];
const prevY = prevX - prevK;
while (x > prevX && y > prevY) {
result.push(new diff_elem_1.DiffElem(diff_elem_1.DiffElemType.KEEP, old[x - 1], newElements[y - 1]));
x--;
y--;
}
if (d === 0) {
break;
}
while (x > prevX) {
result.push(new diff_elem_1.DiffElem(diff_elem_1.DiffElemType.REMOVE, old[x - 1], null));
x--;
}
while (y > prevY) {
result.push(new diff_elem_1.DiffElem(diff_elem_1.DiffElemType.ADD, null, newElements[y - 1]));
y--;
}
}
return result.reverse();
}
coalesceReplacements(diff) {
const newDiff = [];
const c = diff.length;
for (let i = 0; i < c; i++) {
const diffType = diff[i].type;
if (diffType !== diff_elem_1.DiffElemType.REMOVE) {
newDiff.push(diff[i]);
continue;
}
let j = i;
while (j < c && diff[j].type === diff_elem_1.DiffElemType.REMOVE) {
j++;
}
let k = j;
while (k < c && diff[k].type === diff_elem_1.DiffElemType.ADD) {
k++;
}
if (j - i === k - j) {
const len = j - i;
for (let n = 0; n < len; n++) {
newDiff.push(new diff_elem_1.DiffElem(diff_elem_1.DiffElemType.REPLACE, diff[i + n].old, diff[j + n].new));
}
}
else {
for (; i < k; i++) {
newDiff.push(diff[i]);
}
}
i = k - 1;
}
return newDiff;
}
}
exports.Differ = Differ;