f-xyz-diff
Version:
Difference between two arrays|strings.
137 lines (110 loc) • 10.5 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.diff = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
;
var DIFF_NOT_MODIFIED = 0;
var DIFF_CREATED = 1;
var DIFF_MOVED = 2;
var DIFF_DELETED = -1;
var lastUniqueId = 0;
/**
* Returns auto incremental unique ID as integer.
* @returns {number} integers starting from 0
*/
function getUniqueId() {
return lastUniqueId++;
}
/**
* Returns x if it is not undefined, y otherwise.
* @param x
* @param y
* @returns {*}
*/
function maybe(x, y) {
if (x !== undefined) return x;
return y;
}
/**
* @param {Array} list
* @param {string} primaryKey
* @returns {{}}
*/
function buildHashToIndexMap(list, primaryKey) {
var map = {};
for (var i = 0; i < list.length; ++i) {
var item = list[i];
map[item[primaryKey]] = i;
}
return map;
}
/**
* Calculates difference between two arrays.
* Returns array of { item: T, state: int }.
* Where state means: 0 - not modified, 1 - created, -1 - deleted.
* @param {Array} newList
* @param {Array} oldList
* @param {string} primaryKey item's unique index field name
*/
function diff(newList, oldList, primaryKey) {
var diff = [];
var newIndex = 0;
var oldIndex = 0;
var newIndexMap = buildHashToIndexMap(newList, primaryKey);
var oldIndexMap = buildHashToIndexMap(oldList, primaryKey);
function addEntry(item, state, newIndex, prevIndex) {
diff.push({
item: item,
state: state,
oldIndex: prevIndex,
newIndex: newIndex
});
}
for (; newIndex < newList.length || oldIndex < oldList.length;) {
var newItem = newList[newIndex];
var oldItem = oldList[oldIndex];
if (newIndex >= newList.length) {
addEntry(oldItem, DIFF_DELETED, -1, oldIndex);
++oldIndex;
} else if (oldIndex >= oldList.length) {
addEntry(newItem, DIFF_CREATED, newIndex, -1);
++newIndex;
} else if (newItem !== oldItem) {
var indexOfNewItemInOldList =
maybe(oldIndexMap[newItem[primaryKey]], -1);
var indexOfOldItemInNewList =
maybe(newIndexMap[oldItem[primaryKey]], -1);
var isCreated = indexOfNewItemInOldList === -1;
var isDeleted = indexOfOldItemInNewList === -1;
// created
if (isCreated) {
addEntry(newItem, DIFF_CREATED, newIndex, -1);
++newIndex;
}
// moved
if (!isCreated && !isDeleted) {
addEntry(newItem, DIFF_MOVED, newIndex, indexOfOldItemInNewList);
++newIndex;
++oldIndex;
}
// deleted
if (isDeleted) {
addEntry(oldItem, DIFF_DELETED, -1, oldIndex);
++oldIndex;
}
} else {
addEntry(oldItem, DIFF_NOT_MODIFIED, newIndex, oldIndex);
++newIndex;
++oldIndex;
}
}
return diff;
}
// exports ////////////////////////////////////////////////////////////////
diff.NOT_MODIFIED = DIFF_NOT_MODIFIED;
diff.CREATED = DIFF_CREATED;
diff.MOVED = DIFF_MOVED;
diff.DELETED = DIFF_DELETED;
diff.getUniqueId = getUniqueId;
diff.buildHashToIndexMap = buildHashToIndexMap;
module.exports = diff;
},{}]},{},[1])(1)
});
//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJpbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCc7XG5cbnZhciBESUZGX05PVF9NT0RJRklFRCA9IDA7XG52YXIgRElGRl9DUkVBVEVEID0gMTtcbnZhciBESUZGX01PVkVEID0gMjtcbnZhciBESUZGX0RFTEVURUQgPSAtMTtcblxudmFyIGxhc3RVbmlxdWVJZCA9IDA7XG5cbi8qKlxuICogUmV0dXJucyBhdXRvIGluY3JlbWVudGFsIHVuaXF1ZSBJRCBhcyBpbnRlZ2VyLlxuICogQHJldHVybnMge251bWJlcn0gaW50ZWdlcnMgc3RhcnRpbmcgZnJvbSAwXG4gKi9cbmZ1bmN0aW9uIGdldFVuaXF1ZUlkKCkge1xuICAgIHJldHVybiBsYXN0VW5pcXVlSWQrKztcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHggaWYgaXQgaXMgbm90IHVuZGVmaW5lZCwgeSBvdGhlcndpc2UuXG4gKiBAcGFyYW0geFxuICogQHBhcmFtIHlcbiAqIEByZXR1cm5zIHsqfVxuICovXG5mdW5jdGlvbiBtYXliZSh4LCB5KSB7XG4gICAgaWYgKHggIT09IHVuZGVmaW5lZCkgcmV0dXJuIHg7XG4gICAgcmV0dXJuIHk7XG59XG5cbi8qKlxuICogQHBhcmFtIHtBcnJheX0gbGlzdFxuICogQHBhcmFtIHtzdHJpbmd9IHByaW1hcnlLZXlcbiAqIEByZXR1cm5zIHt7fX1cbiAqL1xuZnVuY3Rpb24gYnVpbGRIYXNoVG9JbmRleE1hcChsaXN0LCBwcmltYXJ5S2V5KSB7XG4gICAgdmFyIG1hcCA9IHt9O1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7ICsraSkge1xuICAgICAgICB2YXIgaXRlbSA9IGxpc3RbaV07XG4gICAgICAgIG1hcFtpdGVtW3ByaW1hcnlLZXldXSA9IGk7XG4gICAgfVxuICAgIHJldHVybiBtYXA7XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlcyBkaWZmZXJlbmNlIGJldHdlZW4gdHdvIGFycmF5cy5cbiAqIFJldHVybnMgYXJyYXkgb2YgeyBpdGVtOiBULCBzdGF0ZTogaW50IH0uXG4gKiBXaGVyZSBzdGF0ZSBtZWFuczogMCAtIG5vdCBtb2RpZmllZCwgMSAtIGNyZWF0ZWQsIC0xIC0gZGVsZXRlZC5cbiAqIEBwYXJhbSB7QXJyYXl9IG5ld0xpc3RcbiAqIEBwYXJhbSB7QXJyYXl9IG9sZExpc3RcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmltYXJ5S2V5IGl0ZW0ncyB1bmlxdWUgaW5kZXggZmllbGQgbmFtZVxuICovXG5mdW5jdGlvbiBkaWZmKG5ld0xpc3QsIG9sZExpc3QsIHByaW1hcnlLZXkpIHtcbiAgICB2YXIgZGlmZiA9IFtdO1xuICAgIHZhciBuZXdJbmRleCA9IDA7XG4gICAgdmFyIG9sZEluZGV4ID0gMDtcblxuICAgIHZhciBuZXdJbmRleE1hcCA9IGJ1aWxkSGFzaFRvSW5kZXhNYXAobmV3TGlzdCwgcHJpbWFyeUtleSk7XG4gICAgdmFyIG9sZEluZGV4TWFwID0gYnVpbGRIYXNoVG9JbmRleE1hcChvbGRMaXN0LCBwcmltYXJ5S2V5KTtcblxuICAgIGZ1bmN0aW9uIGFkZEVudHJ5KGl0ZW0sIHN0YXRlLCBuZXdJbmRleCwgcHJldkluZGV4KSB7XG4gICAgICAgIGRpZmYucHVzaCh7XG4gICAgICAgICAgICBpdGVtOiBpdGVtLFxuICAgICAgICAgICAgc3RhdGU6IHN0YXRlLFxuICAgICAgICAgICAgb2xkSW5kZXg6IHByZXZJbmRleCxcbiAgICAgICAgICAgIG5ld0luZGV4OiBuZXdJbmRleFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBmb3IgKDsgbmV3SW5kZXggPCBuZXdMaXN0Lmxlbmd0aCB8fCBvbGRJbmRleCA8IG9sZExpc3QubGVuZ3RoOykge1xuICAgICAgICB2YXIgbmV3SXRlbSA9IG5ld0xpc3RbbmV3SW5kZXhdO1xuICAgICAgICB2YXIgb2xkSXRlbSA9IG9sZExpc3Rbb2xkSW5kZXhdO1xuXG4gICAgICAgIGlmIChuZXdJbmRleCA+PSBuZXdMaXN0Lmxlbmd0aCkge1xuXG4gICAgICAgICAgICBhZGRFbnRyeShvbGRJdGVtLCBESUZGX0RFTEVURUQsIC0xLCBvbGRJbmRleCk7XG4gICAgICAgICAgICArK29sZEluZGV4O1xuXG4gICAgICAgIH0gZWxzZSBpZiAob2xkSW5kZXggPj0gb2xkTGlzdC5sZW5ndGgpIHtcblxuICAgICAgICAgICAgYWRkRW50cnkobmV3SXRlbSwgRElGRl9DUkVBVEVELCBuZXdJbmRleCwgLTEpO1xuICAgICAgICAgICAgKytuZXdJbmRleDtcblxuICAgICAgICB9IGVsc2UgaWYgKG5ld0l0ZW0gIT09IG9sZEl0ZW0pIHtcblxuICAgICAgICAgICAgdmFyIGluZGV4T2ZOZXdJdGVtSW5PbGRMaXN0ID1cbiAgICAgICAgICAgICAgICBtYXliZShvbGRJbmRleE1hcFtuZXdJdGVtW3ByaW1hcnlLZXldXSwgLTEpO1xuXG4gICAgICAgICAgICB2YXIgaW5kZXhPZk9sZEl0ZW1Jbk5ld0xpc3QgPVxuICAgICAgICAgICAgICAgIG1heWJlKG5ld0luZGV4TWFwW29sZEl0ZW1bcHJpbWFyeUtleV1dLCAtMSk7XG5cbiAgICAgICAgICAgIHZhciBpc0NyZWF0ZWQgPSBpbmRleE9mTmV3SXRlbUluT2xkTGlzdCA9PT0gLTE7XG4gICAgICAgICAgICB2YXIgaXNEZWxldGVkID0gaW5kZXhPZk9sZEl0ZW1Jbk5ld0xpc3QgPT09IC0xO1xuXG4gICAgICAgICAgICAvLyBjcmVhdGVkXG4gICAgICAgICAgICBpZiAoaXNDcmVhdGVkKSB7XG4gICAgICAgICAgICAgICAgYWRkRW50cnkobmV3SXRlbSwgRElGRl9DUkVBVEVELCBuZXdJbmRleCwgLTEpO1xuICAgICAgICAgICAgICAgICsrbmV3SW5kZXg7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG1vdmVkXG4gICAgICAgICAgICBpZiAoIWlzQ3JlYXRlZCAmJiAhaXNEZWxldGVkKSB7XG4gICAgICAgICAgICAgICAgYWRkRW50cnkobmV3SXRlbSwgRElGRl9NT1ZFRCwgbmV3SW5kZXgsIGluZGV4T2ZPbGRJdGVtSW5OZXdMaXN0KTtcbiAgICAgICAgICAgICAgICArK25ld0luZGV4O1xuICAgICAgICAgICAgICAgICsrb2xkSW5kZXg7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGRlbGV0ZWRcbiAgICAgICAgICAgIGlmIChpc0RlbGV0ZWQpIHtcbiAgICAgICAgICAgICAgICBhZGRFbnRyeShvbGRJdGVtLCBESUZGX0RFTEVURUQsIC0xLCBvbGRJbmRleCk7XG4gICAgICAgICAgICAgICAgKytvbGRJbmRleDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWRkRW50cnkob2xkSXRlbSwgRElGRl9OT1RfTU9ESUZJRUQsIG5ld0luZGV4LCBvbGRJbmRleCk7XG4gICAgICAgICAgICArK25ld0luZGV4O1xuICAgICAgICAgICAgKytvbGRJbmRleDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkaWZmO1xufVxuXG4vLyBleHBvcnRzIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuZGlmZi5OT1RfTU9ESUZJRUQgPSBESUZGX05PVF9NT0RJRklFRDtcbmRpZmYuQ1JFQVRFRCA9IERJRkZfQ1JFQVRFRDtcbmRpZmYuTU9WRUQgPSBESUZGX01PVkVEO1xuZGlmZi5ERUxFVEVEID0gRElGRl9ERUxFVEVEO1xuZGlmZi5nZXRVbmlxdWVJZCA9IGdldFVuaXF1ZUlkO1xuZGlmZi5idWlsZEhhc2hUb0luZGV4TWFwID0gYnVpbGRIYXNoVG9JbmRleE1hcDtcblxubW9kdWxlLmV4cG9ydHMgPSBkaWZmO1xuIl19