duplex.mjs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*!
  2. * https://github.com/Starcounter-Jack/JSON-Patch
  3. * (c) 2017-2021 Joachim Wester
  4. * MIT license
  5. */
  6. import { _deepClone, _objectKeys, escapePathComponent, hasOwnProperty } from './helpers.mjs';
  7. import { applyPatch } from './core.mjs';
  8. var beforeDict = new WeakMap();
  9. var Mirror = /** @class */ (function () {
  10. function Mirror(obj) {
  11. this.observers = new Map();
  12. this.obj = obj;
  13. }
  14. return Mirror;
  15. }());
  16. var ObserverInfo = /** @class */ (function () {
  17. function ObserverInfo(callback, observer) {
  18. this.callback = callback;
  19. this.observer = observer;
  20. }
  21. return ObserverInfo;
  22. }());
  23. function getMirror(obj) {
  24. return beforeDict.get(obj);
  25. }
  26. function getObserverFromMirror(mirror, callback) {
  27. return mirror.observers.get(callback);
  28. }
  29. function removeObserverFromMirror(mirror, observer) {
  30. mirror.observers.delete(observer.callback);
  31. }
  32. /**
  33. * Detach an observer from an object
  34. */
  35. export function unobserve(root, observer) {
  36. observer.unobserve();
  37. }
  38. /**
  39. * Observes changes made to an object, which can then be retrieved using generate
  40. */
  41. export function observe(obj, callback) {
  42. var patches = [];
  43. var observer;
  44. var mirror = getMirror(obj);
  45. if (!mirror) {
  46. mirror = new Mirror(obj);
  47. beforeDict.set(obj, mirror);
  48. }
  49. else {
  50. var observerInfo = getObserverFromMirror(mirror, callback);
  51. observer = observerInfo && observerInfo.observer;
  52. }
  53. if (observer) {
  54. return observer;
  55. }
  56. observer = {};
  57. mirror.value = _deepClone(obj);
  58. if (callback) {
  59. observer.callback = callback;
  60. observer.next = null;
  61. var dirtyCheck = function () {
  62. generate(observer);
  63. };
  64. var fastCheck = function () {
  65. clearTimeout(observer.next);
  66. observer.next = setTimeout(dirtyCheck);
  67. };
  68. if (typeof window !== 'undefined') { //not Node
  69. window.addEventListener('mouseup', fastCheck);
  70. window.addEventListener('keyup', fastCheck);
  71. window.addEventListener('mousedown', fastCheck);
  72. window.addEventListener('keydown', fastCheck);
  73. window.addEventListener('change', fastCheck);
  74. }
  75. }
  76. observer.patches = patches;
  77. observer.object = obj;
  78. observer.unobserve = function () {
  79. generate(observer);
  80. clearTimeout(observer.next);
  81. removeObserverFromMirror(mirror, observer);
  82. if (typeof window !== 'undefined') {
  83. window.removeEventListener('mouseup', fastCheck);
  84. window.removeEventListener('keyup', fastCheck);
  85. window.removeEventListener('mousedown', fastCheck);
  86. window.removeEventListener('keydown', fastCheck);
  87. window.removeEventListener('change', fastCheck);
  88. }
  89. };
  90. mirror.observers.set(callback, new ObserverInfo(callback, observer));
  91. return observer;
  92. }
  93. /**
  94. * Generate an array of patches from an observer
  95. */
  96. export function generate(observer, invertible) {
  97. if (invertible === void 0) { invertible = false; }
  98. var mirror = beforeDict.get(observer.object);
  99. _generate(mirror.value, observer.object, observer.patches, "", invertible);
  100. if (observer.patches.length) {
  101. applyPatch(mirror.value, observer.patches);
  102. }
  103. var temp = observer.patches;
  104. if (temp.length > 0) {
  105. observer.patches = [];
  106. if (observer.callback) {
  107. observer.callback(temp);
  108. }
  109. }
  110. return temp;
  111. }
  112. // Dirty check if obj is different from mirror, generate patches and update mirror
  113. function _generate(mirror, obj, patches, path, invertible) {
  114. if (obj === mirror) {
  115. return;
  116. }
  117. if (typeof obj.toJSON === "function") {
  118. obj = obj.toJSON();
  119. }
  120. var newKeys = _objectKeys(obj);
  121. var oldKeys = _objectKeys(mirror);
  122. var changed = false;
  123. var deleted = false;
  124. //if ever "move" operation is implemented here, make sure this test runs OK: "should not generate the same patch twice (move)"
  125. for (var t = oldKeys.length - 1; t >= 0; t--) {
  126. var key = oldKeys[t];
  127. var oldVal = mirror[key];
  128. if (hasOwnProperty(obj, key) && !(obj[key] === undefined && oldVal !== undefined && Array.isArray(obj) === false)) {
  129. var newVal = obj[key];
  130. if (typeof oldVal == "object" && oldVal != null && typeof newVal == "object" && newVal != null && Array.isArray(oldVal) === Array.isArray(newVal)) {
  131. _generate(oldVal, newVal, patches, path + "/" + escapePathComponent(key), invertible);
  132. }
  133. else {
  134. if (oldVal !== newVal) {
  135. changed = true;
  136. if (invertible) {
  137. patches.push({ op: "test", path: path + "/" + escapePathComponent(key), value: _deepClone(oldVal) });
  138. }
  139. patches.push({ op: "replace", path: path + "/" + escapePathComponent(key), value: _deepClone(newVal) });
  140. }
  141. }
  142. }
  143. else if (Array.isArray(mirror) === Array.isArray(obj)) {
  144. if (invertible) {
  145. patches.push({ op: "test", path: path + "/" + escapePathComponent(key), value: _deepClone(oldVal) });
  146. }
  147. patches.push({ op: "remove", path: path + "/" + escapePathComponent(key) });
  148. deleted = true; // property has been deleted
  149. }
  150. else {
  151. if (invertible) {
  152. patches.push({ op: "test", path: path, value: mirror });
  153. }
  154. patches.push({ op: "replace", path: path, value: obj });
  155. changed = true;
  156. }
  157. }
  158. if (!deleted && newKeys.length == oldKeys.length) {
  159. return;
  160. }
  161. for (var t = 0; t < newKeys.length; t++) {
  162. var key = newKeys[t];
  163. if (!hasOwnProperty(mirror, key) && obj[key] !== undefined) {
  164. patches.push({ op: "add", path: path + "/" + escapePathComponent(key), value: _deepClone(obj[key]) });
  165. }
  166. }
  167. }
  168. /**
  169. * Create an array of patches from the differences in two objects
  170. */
  171. export function compare(tree1, tree2, invertible) {
  172. if (invertible === void 0) { invertible = false; }
  173. var patches = [];
  174. _generate(tree1, tree2, patches, '', invertible);
  175. return patches;
  176. }