{"version":3,"sources":["meteor://💻app/packages/diff-sequence/diff.js"],"names":["module","export","DiffSequence","hasOwn","Object","prototype","hasOwnProperty","isObjEmpty","obj","key","call","diffQueryChanges","ordered","oldResults","newResults","observer","options","diffQueryOrderedChanges","diffQueryUnorderedChanges","projectionFn","EJSON","clone","movedBefore","Error","forEach","newDoc","id","oldDoc","get","changed","equals","projectedNew","projectedOld","changedFields","makeChangedFields","added","fields","_id","removed","has","old_results","new_results","new_presence_of_id","doc","Meteor","_debug","old_index_of_id","i","unmoved","max_seq_len","N","length","seq_ends","Array","ptrs","old_idx_seq","i_new","undefined","j","idx","push","reverse","startOfGroup","endOfGroup","groupId","addedBefore","diffObjects","left","right","callbacks","keys","leftValue","both","leftOnly","rightOnly","rightValue","diffMaps","value","applyChanges","changeFields"],"mappings":"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","file":"/packages/diff-sequence.js","sourcesContent":["export const DiffSequence = {};\n\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nfunction isObjEmpty(obj) {\n for (let key in Object(obj)) {\n if (hasOwn.call(obj, key)) {\n return false;\n }\n }\n return true;\n}\n\n// ordered: bool.\n// old_results and new_results: collections of documents.\n// if ordered, they are arrays.\n// if unordered, they are IdMaps\nDiffSequence.diffQueryChanges = function (ordered, oldResults, newResults,\n observer, options) {\n if (ordered)\n DiffSequence.diffQueryOrderedChanges(\n oldResults, newResults, observer, options);\n else\n DiffSequence.diffQueryUnorderedChanges(\n oldResults, newResults, observer, options);\n};\n\nDiffSequence.diffQueryUnorderedChanges = function (oldResults, newResults,\n observer, options) {\n options = options || {};\n var projectionFn = options.projectionFn || EJSON.clone;\n\n if (observer.movedBefore) {\n throw new Error(\"_diffQueryUnordered called with a movedBefore observer!\");\n }\n\n newResults.forEach(function (newDoc, id) {\n var oldDoc = oldResults.get(id);\n if (oldDoc) {\n if (observer.changed && !EJSON.equals(oldDoc, newDoc)) {\n var projectedNew = projectionFn(newDoc);\n var projectedOld = projectionFn(oldDoc);\n var changedFields =\n DiffSequence.makeChangedFields(projectedNew, projectedOld);\n if (! isObjEmpty(changedFields)) {\n observer.changed(id, changedFields);\n }\n }\n } else if (observer.added) {\n var fields = projectionFn(newDoc);\n delete fields._id;\n observer.added(newDoc._id, fields);\n }\n });\n\n if (observer.removed) {\n oldResults.forEach(function (oldDoc, id) {\n if (!newResults.has(id))\n observer.removed(id);\n });\n }\n};\n\nDiffSequence.diffQueryOrderedChanges = function (old_results, new_results,\n observer, options) {\n options = options || {};\n var projectionFn = options.projectionFn || EJSON.clone;\n\n var new_presence_of_id = {};\n new_results.forEach(function (doc) {\n if (new_presence_of_id[doc._id])\n Meteor._debug(\"Duplicate _id in new_results\");\n new_presence_of_id[doc._id] = true;\n });\n\n var old_index_of_id = {};\n old_results.forEach(function (doc, i) {\n if (doc._id in old_index_of_id)\n Meteor._debug(\"Duplicate _id in old_results\");\n old_index_of_id[doc._id] = i;\n });\n\n // ALGORITHM:\n //\n // To determine which docs should be considered \"moved\" (and which\n // merely change position because of other docs moving) we run\n // a \"longest common subsequence\" (LCS) algorithm. The LCS of the\n // old doc IDs and the new doc IDs gives the docs that should NOT be\n // considered moved.\n\n // To actually call the appropriate callbacks to get from the old state to the\n // new state:\n\n // First, we call removed() on all the items that only appear in the old\n // state.\n\n // Then, once we have the items that should not move, we walk through the new\n // results array group-by-group, where a \"group\" is a set of items that have\n // moved, anchored on the end by an item that should not move. One by one, we\n // move each of those elements into place \"before\" the anchoring end-of-group\n // item, and fire changed events on them if necessary. Then we fire a changed\n // event on the anchor, and move on to the next group. There is always at\n // least one group; the last group is anchored by a virtual \"null\" id at the\n // end.\n\n // Asymptotically: O(N k) where k is number of ops, or potentially\n // O(N log N) if inner loop of LCS were made to be binary search.\n\n\n //////// LCS (longest common sequence, with respect to _id)\n // (see Wikipedia article on Longest Increasing Subsequence,\n // where the LIS is taken of the sequence of old indices of the\n // docs in new_results)\n //\n // unmoved: the output of the algorithm; members of the LCS,\n // in the form of indices into new_results\n var unmoved = [];\n // max_seq_len: length of LCS found so far\n var max_seq_len = 0;\n // seq_ends[i]: the index into new_results of the last doc in a\n // common subsequence of length of i+1 <= max_seq_len\n var N = new_results.length;\n var seq_ends = new Array(N);\n // ptrs: the common subsequence ending with new_results[n] extends\n // a common subsequence ending with new_results[ptr[n]], unless\n // ptr[n] is -1.\n var ptrs = new Array(N);\n // virtual sequence of old indices of new results\n var old_idx_seq = function(i_new) {\n return old_index_of_id[new_results[i_new]._id];\n };\n // for each item in new_results, use it to extend a common subsequence\n // of length j <= max_seq_len\n for(var i=0; i 0) {\n if (old_idx_seq(seq_ends[j-1]) < old_idx_seq(i))\n break;\n j--;\n }\n\n ptrs[i] = (j === 0 ? -1 : seq_ends[j-1]);\n seq_ends[j] = i;\n if (j+1 > max_seq_len)\n max_seq_len = j+1;\n }\n }\n\n // pull out the LCS/LIS into unmoved\n var idx = (max_seq_len === 0 ? -1 : seq_ends[max_seq_len-1]);\n while (idx >= 0) {\n unmoved.push(idx);\n idx = ptrs[idx];\n }\n // the unmoved item list is built backwards, so fix that\n unmoved.reverse();\n\n // the last group is always anchored by the end of the result list, which is\n // an id of \"null\"\n unmoved.push(new_results.length);\n\n old_results.forEach(function (doc) {\n if (!new_presence_of_id[doc._id])\n observer.removed && observer.removed(doc._id);\n });\n\n // for each group of things in the new_results that is anchored by an unmoved\n // element, iterate through the things before it.\n var startOfGroup = 0;\n unmoved.forEach(function (endOfGroup) {\n var groupId = new_results[endOfGroup] ? new_results[endOfGroup]._id : null;\n var oldDoc, newDoc, fields, projectedNew, projectedOld;\n for (var i = startOfGroup; i < endOfGroup; i++) {\n newDoc = new_results[i];\n if (!hasOwn.call(old_index_of_id, newDoc._id)) {\n fields = projectionFn(newDoc);\n delete fields._id;\n observer.addedBefore && observer.addedBefore(newDoc._id, fields, groupId);\n observer.added && observer.added(newDoc._id, fields);\n } else {\n // moved\n oldDoc = old_results[old_index_of_id[newDoc._id]];\n projectedNew = projectionFn(newDoc);\n projectedOld = projectionFn(oldDoc);\n fields = DiffSequence.makeChangedFields(projectedNew, projectedOld);\n if (!isObjEmpty(fields)) {\n observer.changed && observer.changed(newDoc._id, fields);\n }\n observer.movedBefore && observer.movedBefore(newDoc._id, groupId);\n }\n }\n if (groupId) {\n newDoc = new_results[endOfGroup];\n oldDoc = old_results[old_index_of_id[newDoc._id]];\n projectedNew = projectionFn(newDoc);\n projectedOld = projectionFn(oldDoc);\n fields = DiffSequence.makeChangedFields(projectedNew, projectedOld);\n if (!isObjEmpty(fields)) {\n observer.changed && observer.changed(newDoc._id, fields);\n }\n }\n startOfGroup = endOfGroup+1;\n });\n\n\n};\n\n\n// General helper for diff-ing two objects.\n// callbacks is an object like so:\n// { leftOnly: function (key, leftValue) {...},\n// rightOnly: function (key, rightValue) {...},\n// both: function (key, leftValue, rightValue) {...},\n// }\nDiffSequence.diffObjects = function (left, right, callbacks) {\n Object.keys(left).forEach(key => {\n const leftValue = left[key];\n if (hasOwn.call(right, key)) {\n callbacks.both && callbacks.both(key, leftValue, right[key]);\n } else {\n callbacks.leftOnly && callbacks.leftOnly(key, leftValue);\n }\n });\n\n if (callbacks.rightOnly) {\n Object.keys(right).forEach(key => {\n const rightValue = right[key];\n if (! hasOwn.call(left, key)) {\n callbacks.rightOnly(key, rightValue);\n }\n });\n }\n};\n\nDiffSequence.diffMaps = function (left, right, callbacks) {\n left.forEach(function (leftValue, key) {\n if (right.has(key)){\n callbacks.both && callbacks.both(key, leftValue, right.get(key));\n } else {\n callbacks.leftOnly && callbacks.leftOnly(key, leftValue);\n }\n });\n\n if (callbacks.rightOnly) {\n right.forEach(function (rightValue, key) {\n if (!left.has(key)){\n callbacks.rightOnly(key, rightValue);\n }\n });\n }\n};\n\n\nDiffSequence.makeChangedFields = function (newDoc, oldDoc) {\n var fields = {};\n DiffSequence.diffObjects(oldDoc, newDoc, {\n leftOnly: function (key, value) {\n fields[key] = undefined;\n },\n rightOnly: function (key, value) {\n fields[key] = value;\n },\n both: function (key, leftValue, rightValue) {\n if (!EJSON.equals(leftValue, rightValue))\n fields[key] = rightValue;\n }\n });\n return fields;\n};\n\nDiffSequence.applyChanges = function (doc, changeFields) {\n Object.keys(changeFields).forEach(key => {\n const value = changeFields[key];\n if (typeof value === \"undefined\") {\n delete doc[key];\n } else {\n doc[key] = value;\n }\n });\n};\n\n"]}