| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 | // Myers' Diff Algorithm// Modified from https://github.com/kpdecker/jsdiff/blob/master/src/diff/base.jsfunction Diff() {}Diff.prototype = {  diff: function (oldArr, newArr, equals) {    if (!equals) {      equals = function (a, b) {        return a === b;      };    }    this.equals = equals;    var self = this;    oldArr = oldArr.slice();    newArr = newArr.slice(); // Allow subclasses to massage the input prior to running    var newLen = newArr.length;    var oldLen = oldArr.length;    var editLength = 1;    var maxEditLength = newLen + oldLen;    var bestPath = [{      newPos: -1,      components: []    }]; // Seed editLength = 0, i.e. the content starts with the same values    var oldPos = this.extractCommon(bestPath[0], newArr, oldArr, 0);    if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) {      var indices = [];      for (var i = 0; i < newArr.length; i++) {        indices.push(i);      } // Identity per the equality and tokenizer      return [{        indices: indices,        count: newArr.length      }];    } // Main worker method. checks all permutations of a given edit length for acceptance.    function execEditLength() {      for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) {        var basePath;        var addPath = bestPath[diagonalPath - 1];        var removePath = bestPath[diagonalPath + 1];        var oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;        if (addPath) {          // No one else is going to attempt to use this value, clear it          bestPath[diagonalPath - 1] = undefined;        }        var canAdd = addPath && addPath.newPos + 1 < newLen;        var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;        if (!canAdd && !canRemove) {          // If this path is a terminal then prune          bestPath[diagonalPath] = undefined;          continue;        } // Select the diagonal that we want to branch from. We select the prior        // path whose position in the new string is the farthest from the origin        // and does not pass the bounds of the diff graph        if (!canAdd || canRemove && addPath.newPos < removePath.newPos) {          basePath = clonePath(removePath);          self.pushComponent(basePath.components, undefined, true);        } else {          basePath = addPath; // No need to clone, we've pulled it from the list          basePath.newPos++;          self.pushComponent(basePath.components, true, undefined);        }        oldPos = self.extractCommon(basePath, newArr, oldArr, diagonalPath); // If we have hit the end of both strings, then we are done        if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) {          return buildValues(self, basePath.components, newArr, oldArr);        } else {          // Otherwise track this path as a potential candidate and continue.          bestPath[diagonalPath] = basePath;        }      }      editLength++;    }    while (editLength <= maxEditLength) {      var ret = execEditLength();      if (ret) {        return ret;      }    }  },  pushComponent: function (components, added, removed) {    var last = components[components.length - 1];    if (last && last.added === added && last.removed === removed) {      // We need to clone here as the component clone operation is just      // as shallow array clone      components[components.length - 1] = {        count: last.count + 1,        added: added,        removed: removed      };    } else {      components.push({        count: 1,        added: added,        removed: removed      });    }  },  extractCommon: function (basePath, newArr, oldArr, diagonalPath) {    var newLen = newArr.length;    var oldLen = oldArr.length;    var newPos = basePath.newPos;    var oldPos = newPos - diagonalPath;    var commonCount = 0;    while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newArr[newPos + 1], oldArr[oldPos + 1])) {      newPos++;      oldPos++;      commonCount++;    }    if (commonCount) {      basePath.components.push({        count: commonCount      });    }    basePath.newPos = newPos;    return oldPos;  },  tokenize: function (value) {    return value.slice();  },  join: function (value) {    return value.slice();  }};function buildValues(diff, components, newArr, oldArr) {  var componentPos = 0;  var componentLen = components.length;  var newPos = 0;  var oldPos = 0;  for (; componentPos < componentLen; componentPos++) {    var component = components[componentPos];    if (!component.removed) {      var indices = [];      for (var i = newPos; i < newPos + component.count; i++) {        indices.push(i);      }      component.indices = indices;      newPos += component.count; // Common case      if (!component.added) {        oldPos += component.count;      }    } else {      var indices = [];      for (var i = oldPos; i < oldPos + component.count; i++) {        indices.push(i);      }      component.indices = indices;      oldPos += component.count;    }  }  return components;}function clonePath(path) {  return {    newPos: path.newPos,    components: path.components.slice(0)  };}var arrayDiff = new Diff();function _default(oldArr, newArr, callback) {  return arrayDiff.diff(oldArr, newArr, callback);}module.exports = _default;
 |