123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- /*!
- * https://github.com/Starcounter-Jack/JSON-Patch
- * (c) 2017-2021 Joachim Wester
- * MIT license
- */
- import { _deepClone, _objectKeys, escapePathComponent, hasOwnProperty } from './helpers.mjs';
- import { applyPatch } from './core.mjs';
- var beforeDict = new WeakMap();
- var Mirror = /** @class */ (function () {
- function Mirror(obj) {
- this.observers = new Map();
- this.obj = obj;
- }
- return Mirror;
- }());
- var ObserverInfo = /** @class */ (function () {
- function ObserverInfo(callback, observer) {
- this.callback = callback;
- this.observer = observer;
- }
- return ObserverInfo;
- }());
- function getMirror(obj) {
- return beforeDict.get(obj);
- }
- function getObserverFromMirror(mirror, callback) {
- return mirror.observers.get(callback);
- }
- function removeObserverFromMirror(mirror, observer) {
- mirror.observers.delete(observer.callback);
- }
- /**
- * Detach an observer from an object
- */
- export function unobserve(root, observer) {
- observer.unobserve();
- }
- /**
- * Observes changes made to an object, which can then be retrieved using generate
- */
- export function observe(obj, callback) {
- var patches = [];
- var observer;
- var mirror = getMirror(obj);
- if (!mirror) {
- mirror = new Mirror(obj);
- beforeDict.set(obj, mirror);
- }
- else {
- var observerInfo = getObserverFromMirror(mirror, callback);
- observer = observerInfo && observerInfo.observer;
- }
- if (observer) {
- return observer;
- }
- observer = {};
- mirror.value = _deepClone(obj);
- if (callback) {
- observer.callback = callback;
- observer.next = null;
- var dirtyCheck = function () {
- generate(observer);
- };
- var fastCheck = function () {
- clearTimeout(observer.next);
- observer.next = setTimeout(dirtyCheck);
- };
- if (typeof window !== 'undefined') { //not Node
- window.addEventListener('mouseup', fastCheck);
- window.addEventListener('keyup', fastCheck);
- window.addEventListener('mousedown', fastCheck);
- window.addEventListener('keydown', fastCheck);
- window.addEventListener('change', fastCheck);
- }
- }
- observer.patches = patches;
- observer.object = obj;
- observer.unobserve = function () {
- generate(observer);
- clearTimeout(observer.next);
- removeObserverFromMirror(mirror, observer);
- if (typeof window !== 'undefined') {
- window.removeEventListener('mouseup', fastCheck);
- window.removeEventListener('keyup', fastCheck);
- window.removeEventListener('mousedown', fastCheck);
- window.removeEventListener('keydown', fastCheck);
- window.removeEventListener('change', fastCheck);
- }
- };
- mirror.observers.set(callback, new ObserverInfo(callback, observer));
- return observer;
- }
- /**
- * Generate an array of patches from an observer
- */
- export function generate(observer, invertible) {
- if (invertible === void 0) { invertible = false; }
- var mirror = beforeDict.get(observer.object);
- _generate(mirror.value, observer.object, observer.patches, "", invertible);
- if (observer.patches.length) {
- applyPatch(mirror.value, observer.patches);
- }
- var temp = observer.patches;
- if (temp.length > 0) {
- observer.patches = [];
- if (observer.callback) {
- observer.callback(temp);
- }
- }
- return temp;
- }
- // Dirty check if obj is different from mirror, generate patches and update mirror
- function _generate(mirror, obj, patches, path, invertible) {
- if (obj === mirror) {
- return;
- }
- if (typeof obj.toJSON === "function") {
- obj = obj.toJSON();
- }
- var newKeys = _objectKeys(obj);
- var oldKeys = _objectKeys(mirror);
- var changed = false;
- var deleted = false;
- //if ever "move" operation is implemented here, make sure this test runs OK: "should not generate the same patch twice (move)"
- for (var t = oldKeys.length - 1; t >= 0; t--) {
- var key = oldKeys[t];
- var oldVal = mirror[key];
- if (hasOwnProperty(obj, key) && !(obj[key] === undefined && oldVal !== undefined && Array.isArray(obj) === false)) {
- var newVal = obj[key];
- if (typeof oldVal == "object" && oldVal != null && typeof newVal == "object" && newVal != null && Array.isArray(oldVal) === Array.isArray(newVal)) {
- _generate(oldVal, newVal, patches, path + "/" + escapePathComponent(key), invertible);
- }
- else {
- if (oldVal !== newVal) {
- changed = true;
- if (invertible) {
- patches.push({ op: "test", path: path + "/" + escapePathComponent(key), value: _deepClone(oldVal) });
- }
- patches.push({ op: "replace", path: path + "/" + escapePathComponent(key), value: _deepClone(newVal) });
- }
- }
- }
- else if (Array.isArray(mirror) === Array.isArray(obj)) {
- if (invertible) {
- patches.push({ op: "test", path: path + "/" + escapePathComponent(key), value: _deepClone(oldVal) });
- }
- patches.push({ op: "remove", path: path + "/" + escapePathComponent(key) });
- deleted = true; // property has been deleted
- }
- else {
- if (invertible) {
- patches.push({ op: "test", path: path, value: mirror });
- }
- patches.push({ op: "replace", path: path, value: obj });
- changed = true;
- }
- }
- if (!deleted && newKeys.length == oldKeys.length) {
- return;
- }
- for (var t = 0; t < newKeys.length; t++) {
- var key = newKeys[t];
- if (!hasOwnProperty(mirror, key) && obj[key] !== undefined) {
- patches.push({ op: "add", path: path + "/" + escapePathComponent(key), value: _deepClone(obj[key]) });
- }
- }
- }
- /**
- * Create an array of patches from the differences in two objects
- */
- export function compare(tree1, tree2, invertible) {
- if (invertible === void 0) { invertible = false; }
- var patches = [];
- _generate(tree1, tree2, patches, '', invertible);
- return patches;
- }
|