Files
2025-02-26 14:49:25 +07:00

308 lines
11 KiB
JavaScript

//////////////////////////////////////////////////////////////////////////
// //
// This is a generated file. You can view the original //
// source in your browser if your browser supports source maps. //
// Source maps are supported by all recent versions of Chrome, Safari, //
// and Firefox, and by Internet Explorer 11. //
// //
//////////////////////////////////////////////////////////////////////////
(function () {
/* Imports */
var Meteor = Package.meteor.Meteor;
var global = Package.meteor.global;
var meteorEnv = Package.meteor.meteorEnv;
var EJSON = Package.ejson.EJSON;
var meteorInstall = Package.modules.meteorInstall;
var meteorBabelHelpers = Package['babel-runtime'].meteorBabelHelpers;
var Promise = Package.promise.Promise;
var Symbol = Package['ecmascript-runtime-client'].Symbol;
var Map = Package['ecmascript-runtime-client'].Map;
var Set = Package['ecmascript-runtime-client'].Set;
/* Package-scope variables */
var DiffSequence;
var require = meteorInstall({"node_modules":{"meteor":{"diff-sequence":{"diff.js":function(require,exports,module){
/////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// packages/diff-sequence/diff.js //
// //
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
module.export({
DiffSequence: function () {
return DiffSequence;
}
});
var DiffSequence = {};
var hasOwn = Object.prototype.hasOwnProperty;
function isObjEmpty(obj) {
for (var key in meteorBabelHelpers.sanitizeForInObject(Object(obj))) {
if (hasOwn.call(obj, key)) {
return false;
}
}
return true;
} // ordered: bool.
// old_results and new_results: collections of documents.
// if ordered, they are arrays.
// if unordered, they are IdMaps
DiffSequence.diffQueryChanges = function (ordered, oldResults, newResults, observer, options) {
if (ordered) DiffSequence.diffQueryOrderedChanges(oldResults, newResults, observer, options);else DiffSequence.diffQueryUnorderedChanges(oldResults, newResults, observer, options);
};
DiffSequence.diffQueryUnorderedChanges = function (oldResults, newResults, observer, options) {
options = options || {};
var projectionFn = options.projectionFn || EJSON.clone;
if (observer.movedBefore) {
throw new Error("_diffQueryUnordered called with a movedBefore observer!");
}
newResults.forEach(function (newDoc, id) {
var oldDoc = oldResults.get(id);
if (oldDoc) {
if (observer.changed && !EJSON.equals(oldDoc, newDoc)) {
var projectedNew = projectionFn(newDoc);
var projectedOld = projectionFn(oldDoc);
var changedFields = DiffSequence.makeChangedFields(projectedNew, projectedOld);
if (!isObjEmpty(changedFields)) {
observer.changed(id, changedFields);
}
}
} else if (observer.added) {
var fields = projectionFn(newDoc);
delete fields._id;
observer.added(newDoc._id, fields);
}
});
if (observer.removed) {
oldResults.forEach(function (oldDoc, id) {
if (!newResults.has(id)) observer.removed(id);
});
}
};
DiffSequence.diffQueryOrderedChanges = function (old_results, new_results, observer, options) {
options = options || {};
var projectionFn = options.projectionFn || EJSON.clone;
var new_presence_of_id = {};
new_results.forEach(function (doc) {
if (new_presence_of_id[doc._id]) Meteor._debug("Duplicate _id in new_results");
new_presence_of_id[doc._id] = true;
});
var old_index_of_id = {};
old_results.forEach(function (doc, i) {
if (doc._id in old_index_of_id) Meteor._debug("Duplicate _id in old_results");
old_index_of_id[doc._id] = i;
}); // ALGORITHM:
//
// To determine which docs should be considered "moved" (and which
// merely change position because of other docs moving) we run
// a "longest common subsequence" (LCS) algorithm. The LCS of the
// old doc IDs and the new doc IDs gives the docs that should NOT be
// considered moved.
// To actually call the appropriate callbacks to get from the old state to the
// new state:
// First, we call removed() on all the items that only appear in the old
// state.
// Then, once we have the items that should not move, we walk through the new
// results array group-by-group, where a "group" is a set of items that have
// moved, anchored on the end by an item that should not move. One by one, we
// move each of those elements into place "before" the anchoring end-of-group
// item, and fire changed events on them if necessary. Then we fire a changed
// event on the anchor, and move on to the next group. There is always at
// least one group; the last group is anchored by a virtual "null" id at the
// end.
// Asymptotically: O(N k) where k is number of ops, or potentially
// O(N log N) if inner loop of LCS were made to be binary search.
//////// LCS (longest common sequence, with respect to _id)
// (see Wikipedia article on Longest Increasing Subsequence,
// where the LIS is taken of the sequence of old indices of the
// docs in new_results)
//
// unmoved: the output of the algorithm; members of the LCS,
// in the form of indices into new_results
var unmoved = []; // max_seq_len: length of LCS found so far
var max_seq_len = 0; // seq_ends[i]: the index into new_results of the last doc in a
// common subsequence of length of i+1 <= max_seq_len
var N = new_results.length;
var seq_ends = new Array(N); // ptrs: the common subsequence ending with new_results[n] extends
// a common subsequence ending with new_results[ptr[n]], unless
// ptr[n] is -1.
var ptrs = new Array(N); // virtual sequence of old indices of new results
var old_idx_seq = function (i_new) {
return old_index_of_id[new_results[i_new]._id];
}; // for each item in new_results, use it to extend a common subsequence
// of length j <= max_seq_len
for (var i = 0; i < N; i++) {
if (old_index_of_id[new_results[i]._id] !== undefined) {
var j = max_seq_len; // this inner loop would traditionally be a binary search,
// but scanning backwards we will likely find a subseq to extend
// pretty soon, bounded for example by the total number of ops.
// If this were to be changed to a binary search, we'd still want
// to scan backwards a bit as an optimization.
while (j > 0) {
if (old_idx_seq(seq_ends[j - 1]) < old_idx_seq(i)) break;
j--;
}
ptrs[i] = j === 0 ? -1 : seq_ends[j - 1];
seq_ends[j] = i;
if (j + 1 > max_seq_len) max_seq_len = j + 1;
}
} // pull out the LCS/LIS into unmoved
var idx = max_seq_len === 0 ? -1 : seq_ends[max_seq_len - 1];
while (idx >= 0) {
unmoved.push(idx);
idx = ptrs[idx];
} // the unmoved item list is built backwards, so fix that
unmoved.reverse(); // the last group is always anchored by the end of the result list, which is
// an id of "null"
unmoved.push(new_results.length);
old_results.forEach(function (doc) {
if (!new_presence_of_id[doc._id]) observer.removed && observer.removed(doc._id);
}); // for each group of things in the new_results that is anchored by an unmoved
// element, iterate through the things before it.
var startOfGroup = 0;
unmoved.forEach(function (endOfGroup) {
var groupId = new_results[endOfGroup] ? new_results[endOfGroup]._id : null;
var oldDoc, newDoc, fields, projectedNew, projectedOld;
for (var i = startOfGroup; i < endOfGroup; i++) {
newDoc = new_results[i];
if (!hasOwn.call(old_index_of_id, newDoc._id)) {
fields = projectionFn(newDoc);
delete fields._id;
observer.addedBefore && observer.addedBefore(newDoc._id, fields, groupId);
observer.added && observer.added(newDoc._id, fields);
} else {
// moved
oldDoc = old_results[old_index_of_id[newDoc._id]];
projectedNew = projectionFn(newDoc);
projectedOld = projectionFn(oldDoc);
fields = DiffSequence.makeChangedFields(projectedNew, projectedOld);
if (!isObjEmpty(fields)) {
observer.changed && observer.changed(newDoc._id, fields);
}
observer.movedBefore && observer.movedBefore(newDoc._id, groupId);
}
}
if (groupId) {
newDoc = new_results[endOfGroup];
oldDoc = old_results[old_index_of_id[newDoc._id]];
projectedNew = projectionFn(newDoc);
projectedOld = projectionFn(oldDoc);
fields = DiffSequence.makeChangedFields(projectedNew, projectedOld);
if (!isObjEmpty(fields)) {
observer.changed && observer.changed(newDoc._id, fields);
}
}
startOfGroup = endOfGroup + 1;
});
}; // General helper for diff-ing two objects.
// callbacks is an object like so:
// { leftOnly: function (key, leftValue) {...},
// rightOnly: function (key, rightValue) {...},
// both: function (key, leftValue, rightValue) {...},
// }
DiffSequence.diffObjects = function (left, right, callbacks) {
Object.keys(left).forEach(function (key) {
var leftValue = left[key];
if (hasOwn.call(right, key)) {
callbacks.both && callbacks.both(key, leftValue, right[key]);
} else {
callbacks.leftOnly && callbacks.leftOnly(key, leftValue);
}
});
if (callbacks.rightOnly) {
Object.keys(right).forEach(function (key) {
var rightValue = right[key];
if (!hasOwn.call(left, key)) {
callbacks.rightOnly(key, rightValue);
}
});
}
};
DiffSequence.makeChangedFields = function (newDoc, oldDoc) {
var fields = {};
DiffSequence.diffObjects(oldDoc, newDoc, {
leftOnly: function (key, value) {
fields[key] = undefined;
},
rightOnly: function (key, value) {
fields[key] = value;
},
both: function (key, leftValue, rightValue) {
if (!EJSON.equals(leftValue, rightValue)) fields[key] = rightValue;
}
});
return fields;
};
DiffSequence.applyChanges = function (doc, changeFields) {
Object.keys(changeFields).forEach(function (key) {
var value = changeFields[key];
if (typeof value === "undefined") {
delete doc[key];
} else {
doc[key] = value;
}
});
};
/////////////////////////////////////////////////////////////////////////////////////////////////////
}}}}},{
"extensions": [
".js",
".json"
]
});
var exports = require("/node_modules/meteor/diff-sequence/diff.js");
/* Exports */
Package._define("diff-sequence", exports, {
DiffSequence: DiffSequence
});
})();