object-observer
Advanced tools
Comparing version 0.2.4 to 0.2.5
@@ -26,12 +26,12 @@ (() => { | ||
result = function proxiedPop() { | ||
let poppedIndex, popResult, changes; | ||
let poppedIndex, popResult, tmpTarget, changes; | ||
poppedIndex = target.length - 1; | ||
popResult = Reflect.apply(target[key], target, arguments); | ||
if (popResult && typeof popResult === 'object') { | ||
popResult = proxiesToTargetsMap.get(popResult); | ||
targetsToObserved.get(popResult).revoke(); | ||
tmpTarget = proxiesToTargetsMap.get(popResult); | ||
if (tmpTarget) { | ||
targetsToObserved.get(tmpTarget).revoke(); | ||
} | ||
changes = [new DeleteChange(observed.path.concat(poppedIndex), popResult)]; | ||
changes = [new DeleteChange(observed.path.concat(poppedIndex), tmpTarget || popResult)]; | ||
observable.notify(changes); | ||
return popResult; | ||
return tmpTarget || popResult; | ||
}; | ||
@@ -56,9 +56,11 @@ } else if (key === 'push') { | ||
result = function proxiedShift() { | ||
let shiftResult, changes, tmpObserved; | ||
let shiftResult, changes, tmpTarget; | ||
shiftResult = Reflect.apply(target[key], target, arguments); | ||
if (shiftResult && typeof shiftResult === 'object') { | ||
shiftResult = proxiesToTargetsMap.get(shiftResult); | ||
targetsToObserved.get(shiftResult).revoke(); | ||
tmpTarget = proxiesToTargetsMap.get(shiftResult); | ||
if (tmpTarget) { | ||
targetsToObserved.get(tmpTarget).revoke(); | ||
} | ||
for (let i = 0, l = target.length, item; i < l; i++) { | ||
// update indices of the remaining items | ||
for (let i = 0, l = target.length, item, tmpObserved; i < l; i++) { | ||
item = target[i]; | ||
@@ -70,9 +72,9 @@ if (item && typeof item === 'object') { | ||
} else { | ||
console.error('failed to resolve proxy -> target -> observed'); | ||
console.error('unexpectedly failed to resolve proxy -> target -> observed'); | ||
} | ||
} | ||
} | ||
changes = [new DeleteChange(observed.path.concat(0), shiftResult)]; | ||
changes = [new DeleteChange(observed.path.concat(0), tmpTarget || shiftResult)]; | ||
observable.notify(changes); | ||
return shiftResult; | ||
return tmpTarget || shiftResult; | ||
}; | ||
@@ -151,3 +153,3 @@ } else if (key === 'unshift') { | ||
Reflect.apply(target[key], target, arguments); | ||
for (let i = start, item; i < end; i++) { | ||
for (let i = start, item, tmpTarget; i < end; i++) { | ||
item = target[i]; | ||
@@ -158,6 +160,8 @@ if (item && typeof item === 'object') { | ||
if (prev.hasOwnProperty(i)) { | ||
changes.push(new UpdateChange(observed.path.concat(i), target[i], prev[i] && typeof prev[i] === 'object' ? proxiesToTargetsMap.get(prev[i]) : prev[i])); | ||
if (prev[i] && typeof prev[i] === 'object') { | ||
targetsToObserved.get(proxiesToTargetsMap.get(prev[i])).revoke(); | ||
tmpTarget = proxiesToTargetsMap.get(prev[i]); | ||
if (tmpTarget) { | ||
targetsToObserved.get(tmpTarget).revoke(); | ||
} | ||
changes.push(new UpdateChange(observed.path.concat(i), target[i], tmpTarget || prev[i])); | ||
} else { | ||
@@ -173,3 +177,3 @@ changes.push(new InsertChange(observed.path.concat(i), target[i])); | ||
let spliceContent, spliceResult, changes = [], tmpObserved, | ||
index, startIndex, removed, inserted, splLen, tarLen = target.length; | ||
startIndex, removed, inserted, splLen, tarLen = target.length; | ||
@@ -207,7 +211,8 @@ spliceContent = Array.from(arguments); | ||
// revoke removed Observed | ||
for (let i = 0, l = spliceResult.length, item; i < l; i++) { | ||
for (let i = 0, l = spliceResult.length, item, tmpTarget; i < l; i++) { | ||
item = spliceResult[i]; | ||
if (removed && typeof removed === 'object') { | ||
item = proxiesToTargetsMap.get(removed); | ||
targetsToObserved.get(item).revoke(); | ||
tmpTarget = proxiesToTargetsMap.get(item); | ||
if (tmpTarget) { | ||
targetsToObserved.get(tmpTarget).revoke(); | ||
spliceResult[i] = tmpTarget; | ||
} | ||
@@ -217,2 +222,3 @@ } | ||
// publish changes | ||
let index; | ||
for (index = 0; index < removed; index++) { | ||
@@ -242,2 +248,3 @@ if (index < inserted) { | ||
result, | ||
oldTarget, | ||
observed = targetsToObserved.get(target), | ||
@@ -253,5 +260,5 @@ observable = observedToObservable.get(observed.root); | ||
if (result) { | ||
if (proxiesToTargetsMap.has(oldValue)) { | ||
targetsToObserved.get(proxiesToTargetsMap.get(oldValue)).revoke(); | ||
proxiesToTargetsMap.delete(oldValue); | ||
oldTarget = proxiesToTargetsMap.get(oldValue); | ||
if (oldTarget) { | ||
targetsToObserved.get(oldTarget).revoke(); | ||
} | ||
@@ -261,3 +268,3 @@ | ||
let path = observed.path.concat(key), | ||
changes = [oldValuePresent ? new UpdateChange(path, value, oldValue) : new InsertChange(path, value)]; | ||
changes = [oldValuePresent ? new UpdateChange(path, value, oldTarget || oldValue) : new InsertChange(path, value)]; | ||
if (!observed.preventCallbacks) { | ||
@@ -274,2 +281,3 @@ observable.notify(changes); | ||
result, | ||
oldTarget, | ||
observed = targetsToObserved.get(target), | ||
@@ -281,5 +289,5 @@ observable = observedToObservable.get(observed.root); | ||
if (result) { | ||
if (proxiesToTargetsMap.has(oldValue)) { | ||
targetsToObserved.get(proxiesToTargetsMap.get(oldValue)).revoke(); | ||
proxiesToTargetsMap.delete(oldValue); | ||
oldTarget = proxiesToTargetsMap.get(oldValue); | ||
if (oldTarget) { | ||
targetsToObserved.get(oldTarget).revoke(); | ||
} | ||
@@ -289,3 +297,3 @@ | ||
let path = observed.path.concat(key), | ||
changes = [new DeleteChange(path, oldValue)]; | ||
changes = [new DeleteChange(path, oldTarget || oldValue)]; | ||
if (!observed.preventCallbacks) { | ||
@@ -319,4 +327,6 @@ observable.notify(changes); | ||
// CLASSES | ||
function Observed(origin, ownKey, parent) { | ||
let targetClone, revokableProxy; | ||
let targetClone, revokable, proxy; | ||
@@ -337,3 +347,3 @@ if (!origin || typeof origin !== 'object') { | ||
processArraySubgraph(targetClone, this); | ||
revokableProxy = Proxy.revocable(targetClone, { | ||
revokable = Proxy.revocable(targetClone, { | ||
set: proxiedSet, | ||
@@ -345,3 +355,3 @@ get: proxiedArrayGet, | ||
processObjectSubgraph(targetClone, this); | ||
revokableProxy = Proxy.revocable(targetClone, { | ||
revokable = Proxy.revocable(targetClone, { | ||
set: proxiedSet, | ||
@@ -351,8 +361,9 @@ deleteProperty: proxiedDelete | ||
} | ||
proxy = revokable.proxy; | ||
targetsToObserved.set(targetClone, this); | ||
proxiesToTargetsMap.set(revokableProxy.proxy, targetClone); | ||
proxiesToTargetsMap.set(proxy, targetClone); | ||
Object.defineProperties(this, { | ||
revokable: {value: revokableProxy}, | ||
proxy: {value: revokableProxy.proxy}, | ||
revokable: {value: revokable}, | ||
proxy: {value: proxy}, | ||
parent: {value: parent}, | ||
@@ -376,6 +387,6 @@ ownKey: {value: ownKey, writable: true} | ||
while (typeof pointer.ownKey !== 'undefined') { | ||
result.push(pointer.ownKey); | ||
result.unshift(pointer.ownKey); | ||
pointer = pointer.parent; | ||
} | ||
return result.reverse(); | ||
return result; | ||
} | ||
@@ -385,14 +396,23 @@ }); | ||
value: function() { | ||
let proxy = this.proxy, | ||
keys = Object.keys(proxy); | ||
for (let i = 0, l = keys.length, key, item; i < l; i++) { | ||
let target = proxiesToTargetsMap.get(this.proxy), | ||
keys = Object.keys(target); | ||
// revoke native proxy | ||
this.revokable.revoke(); | ||
// roll back observed graph to unobserved one | ||
for (let i = 0, l = keys.length, key, tmpTarget; i < l; i++) { | ||
key = keys[i]; | ||
item = proxy[key]; | ||
if (proxiesToTargetsMap.has(item)) { | ||
targetsToObserved.get(proxiesToTargetsMap.get(item)).revoke(); | ||
proxiesToTargetsMap.get(proxy)[key] = proxiesToTargetsMap.get(item); | ||
tmpTarget = proxiesToTargetsMap.get(target[key]); | ||
if (tmpTarget) { | ||
target[key] = targetsToObserved.get(tmpTarget).revoke(); | ||
} | ||
} | ||
this.revokable.revoke(); | ||
// TODO: ensure if there are any other cleanups to do here (probably remove observed?) | ||
// clean revoked Observed from the maps | ||
proxiesToTargetsMap.delete(this.proxy); | ||
targetsToObserved.delete(target); | ||
// return an unobserved graph (effectively this is an opposite of an Observed constructor logic) | ||
return target; | ||
} | ||
@@ -416,3 +436,3 @@ }); | ||
function unobserve() { | ||
if (isRevoked) { throw new TypeError('revoked Observable MAY NOT be unobserved amymore'); } | ||
if (isRevoked) { throw new TypeError('revoked Observable MAY NOT be unobserved anymore'); } | ||
if (arguments.length) { | ||
@@ -433,3 +453,3 @@ for (let i = 0, l = arguments.length, idx; i < l; i++) { | ||
} else { | ||
console.log('revokation of Observable have an effect only once'); | ||
console.log('revoking of Observable effective only once'); | ||
} | ||
@@ -448,3 +468,3 @@ } | ||
} catch (e) { | ||
console.error(e); | ||
console.error('one/some of the observing callbacks failed with ', e); | ||
} | ||
@@ -451,0 +471,0 @@ } |
@@ -1,1 +0,1 @@ | ||
(()=>{"use strict";function e(e){return u.indexOf(e.constructor.name)>=0}function t(e,t){let o,r=s.get(e),l=y.get(r.root);return o="pop"===t?function(){let o,n,f;return o=e.length-1,(n=Reflect.apply(e[t],e,arguments))&&"object"==typeof n&&(n=p.get(n),s.get(n).revoke()),f=[new c(r.path.concat(o),n)],l.notify(f),n}:"push"===t?function(){let o,a,c,i=[];o=Array.from(arguments),c=e.length;for(let e,t=0,l=o.length;t<l;t++)(e=o[t])&&"object"==typeof e&&(o[t]=new n(e,c+t,r).proxy),i.push(new f(r.path.concat(c+t),e));return a=Reflect.apply(e[t],e,o),l.notify(i),a}:"shift"===t?function(){let o,n,f;(o=Reflect.apply(e[t],e,arguments))&&"object"==typeof o&&(o=p.get(o),s.get(o).revoke());for(let t,o=0,r=e.length;o<r;o++)(t=e[o])&&"object"==typeof t&&((f=s.get(p.get(t)))?f.ownKey=o:console.error("failed to resolve proxy -> target -> observed"));return n=[new c(r.path.concat(0),o)],l.notify(n),o}:"unshift"===t?function(){let o,a,c,i=[];(o=Array.from(arguments)).forEach(function(e,t){e&&"object"==typeof e&&(o[t]=new n(e,t,r).proxy)}),a=Reflect.apply(e[t],e,o);for(let t,o=0,r=e.length;o<r;o++)(t=e[o])&&"object"==typeof t&&((c=s.get(p.get(t)))?c.ownKey=o:console.error("failed to resolve proxy -> target -> observed"));for(let t=0,n=o.length;t<n;t++)i.push(new f(r.path.concat(t),e[t]));return l.notify(i),a}:"reverse"===t?function(){let o,r;Reflect.apply(e[t],e,arguments);for(let t,o=0,n=e.length;o<n;o++)(t=e[o])&&"object"==typeof t&&((r=s.get(p.get(t)))?r.ownKey=o:console.error("failed to resolve proxy -> target -> observed"));return o=[new function(){Object.defineProperties(this,{type:{value:"reverse"}})}],l.notify(o),this}:"sort"===t?function(){let o,r;Reflect.apply(e[t],e,arguments);for(let t,o=0,n=e.length;o<n;o++)(t=e[o])&&"object"==typeof t&&((r=s.get(p.get(t)))?r.ownKey=o:console.error("failed to resolve proxy -> target -> observed"));return o=[new function(){Object.defineProperties(this,{type:{value:"shuffle"}})}],l.notify(o),this}:"fill"===t?function(){let o,c,i,y=[],u=arguments.length,h=e.length;o=u<2?0:arguments[1]<0?h+arguments[1]:arguments[1],c=u<3?h:arguments[2]<0?h+arguments[2]:arguments[2],i=e.slice(),Reflect.apply(e[t],e,arguments);for(let t,l=o;l<c;l++)(t=e[l])&&"object"==typeof t&&(e[l]=new n(t,l,r).proxy),i.hasOwnProperty(l)?(y.push(new a(r.path.concat(l),e[l],i[l]&&"object"==typeof i[l]?p.get(i[l]):i[l])),i[l]&&"object"==typeof i[l]&&s.get(p.get(i[l])).revoke()):y.push(new f(r.path.concat(l),e[l]));return l.notify(y),this}:"splice"===t?function(){let o,i,y,u,h,b,v,g,w=[],d=e.length;g=(o=Array.from(arguments)).length;for(let e,t=0;t<g;t++)e=o[t],t>1&&e&&"object"==typeof e&&(o[t]=new n(e,t,r).proxy);h=0===g?0:o[0]<0?d+o[0]:o[0],b=g<2?d-h:o[1],v=Math.max(g-2,0),i=Reflect.apply(e[t],e,o);for(let t,o=0;o<d;o++)(t=e[o])&&"object"==typeof t&&((y=s.get(p.get(t)))?y.ownKey=o:console.error("failed to resolve proxy -> target -> observed"));for(let e,t=0,o=i.length;t<o;t++)e=i[t],b&&"object"==typeof b&&(e=p.get(b),s.get(e).revoke());for(u=0;u<b;u++)u<v?w.push(new a(r.path.concat(h+u),e[h+u],i[u])):w.push(new c(r.path.concat(h+u),i[u]));for(;u<v;u++)w.push(new f(r.path.concat(h+u),e[h+u]));return l.notify(w),i}:Reflect.get(e,t)}function o(t,o,r){let l,c=t.hasOwnProperty(o),i=t[o],u=s.get(t),h=y.get(u.root);if((l=r&&"object"==typeof r&&!e(r)?Reflect.set(t,o,new n(r,o,u).proxy):Reflect.set(t,o,r))&&(p.has(i)&&(s.get(p.get(i)).revoke(),p.delete(i)),h.hasListeners)){let e=u.path.concat(o),t=[c?new a(e,r,i):new f(e,r)];u.preventCallbacks||h.notify(t)}return l}function r(e,t){let o,r=e[t],n=s.get(e),l=y.get(n.root);if((o=Reflect.deleteProperty(e,t))&&(p.has(r)&&(s.get(p.get(r)).revoke(),p.delete(r)),l.hasListeners)){let e=[new c(n.path.concat(t),r)];n.preventCallbacks||l.notify(e)}return o}function n(l,f,a){let c,i;if(!l||"object"!=typeof l)throw new Error("Observed MUST be created from a non null object origin");if(a&&(void 0===f||null===f))throw new Error("any non-root (parent-less) Observed MUST have an own path; now parent is "+a+"; key is "+f);if(a&&!(a instanceof n))throw new Error("parent, when supplied, MUST be an instance of Observed");c=function(e){return Array.isArray(e)?e.slice():Object.assign(new e.constructor,e)}(l),Array.isArray(c)?(!function(t,o){for(let r,l=0,f=t.length;l<f;l++)(r=t[l])&&"object"==typeof r&&!e(r)&&(t[l]=new n(r,l,o).proxy)}(c,this),i=Proxy.revocable(c,{set:o,get:t,deleteProperty:r})):(!function(t,o){let r=Object.keys(t);for(let l,f,a=0,c=r.length;a<c;a++)(f=t[l=r[a]])&&"object"==typeof f&&!e(f)&&(t[l]=new n(f,l,o).proxy)}(c,this),i=Proxy.revocable(c,{set:o,deleteProperty:r})),s.set(c,this),p.set(i.proxy,c),Object.defineProperties(this,{revokable:{value:i},proxy:{value:i.proxy},parent:{value:a},ownKey:{value:f,writable:!0}})}function l(e){let t=!1,o=[];Object.defineProperties(e.proxy,{observe:{value:function(e){if(t)throw new TypeError("revoked Observable MAY NOT be observed anymore");if("function"!=typeof e)throw new Error("observer (callback) parameter MUST be a function");o.indexOf(e)<0?o.push(e):console.info("observer (callback) may be bound to an observable only once")}},unobserve:{value:function(){if(t)throw new TypeError("revoked Observable MAY NOT be unobserved amymore");if(arguments.length)for(let e,t=0,r=arguments.length;t<r;t++)(e=o.indexOf(arguments[t]))>=0&&o.splice(e,1);else o.splice(0,o.length)}},revoke:{value:function(){t?console.log("revokation of Observable have an effect only once"):(t=!0,e.revoke())}}}),Object.defineProperties(this,{hasListeners:{value:function(){return o.length>0}},notify:{value:function(e){for(let t,r=0,n=o.length;r<n;r++){t=o[r];try{t(e)}catch(e){console.error(e)}}}}})}function f(e,t){Object.defineProperties(this,{type:{value:"insert"},path:{value:e},value:{value:t}})}function a(e,t,o){Object.defineProperties(this,{type:{value:"update"},path:{value:e},value:{value:t},oldValue:{value:o}})}function c(e,t){Object.defineProperties(this,{type:{value:"delete"},path:{value:e},oldValue:{value:t}})}const i=this||window,p=new Map,s=new Map,y=new Map,u=["Date","Blob","Number","String","Boolean","Error","SyntaxError","TypeError","URIError","Function","Promise","RegExp"];Object.defineProperty(n.prototype,"root",{get:function(){let e=this;for(;e.parent;)e=e.parent;return e}}),Object.defineProperty(n.prototype,"path",{get:function(){let e=[],t=this;for(;void 0!==t.ownKey;)e.push(t.ownKey),t=t.parent;return e.reverse()}}),Object.defineProperty(n.prototype,"revoke",{value:function(){let e=this.proxy,t=Object.keys(e);for(let o,r,n=0,l=t.length;n<l;n++)r=e[o=t[n]],p.has(r)&&(s.get(p.get(r)).revoke(),p.get(e)[o]=p.get(r));this.revokable.revoke()}}),Object.defineProperty(l,"from",{value:function(t){if(!t||"object"!=typeof t)throw new Error("observable MAY ONLY be created from non-null object only");if("observe"in t||"unobserve"in t||"revoke"in t)throw new Error('target object MUST NOT have nor own neither inherited properties from the following list: "observe", "unobserve", "revoke"');if(e(t))throw new Error(t+" found to be one of non-observable object types: "+u);let o=new n(t),r=new l(o);return y.set(o,r),o.proxy}}),Object.defineProperty(i,"Observable",{value:l})})(); | ||
(()=>{"use strict";const e=this||window,t=new Map,o=new Map,r=new Map,n=["Date","Blob","Number","String","Boolean","Error","SyntaxError","TypeError","URIError","Function","Promise","RegExp"];function l(e){return n.indexOf(e.constructor.name)>=0}function i(e,n){let l,i=o.get(e),f=r.get(i.root);return l="pop"===n?function(){let r,l,a,c;return r=e.length-1,l=Reflect.apply(e[n],e,arguments),(a=t.get(l))&&o.get(a).revoke(),c=[new y(i.path.concat(r),a||l)],f.notify(c),a||l}:"push"===n?function(){let t,o,r,l=[];t=Array.from(arguments),r=e.length;for(let e,o=0,n=t.length;o<n;o++)(e=t[o])&&"object"==typeof e&&(t[o]=new c(e,r+o,i).proxy),l.push(new p(i.path.concat(r+o),e));return o=Reflect.apply(e[n],e,t),f.notify(l),o}:"shift"===n?function(){let r,l,a;r=Reflect.apply(e[n],e,arguments),(a=t.get(r))&&o.get(a).revoke();for(let r,n,l=0,i=e.length;l<i;l++)(r=e[l])&&"object"==typeof r&&((n=o.get(t.get(r)))?n.ownKey=l:console.error("unexpectedly failed to resolve proxy -> target -> observed"));return l=[new y(i.path.concat(0),a||r)],f.notify(l),a||r}:"unshift"===n?function(){let r,l,a,s=[];(r=Array.from(arguments)).forEach(function(e,t){e&&"object"==typeof e&&(r[t]=new c(e,t,i).proxy)}),l=Reflect.apply(e[n],e,r);for(let r,n=0,l=e.length;n<l;n++)(r=e[n])&&"object"==typeof r&&((a=o.get(t.get(r)))?a.ownKey=n:console.error("failed to resolve proxy -> target -> observed"));for(let t=0,o=r.length;t<o;t++)s.push(new p(i.path.concat(t),e[t]));return f.notify(s),l}:"reverse"===n?function(){let r,l;Reflect.apply(e[n],e,arguments);for(let r,n=0,i=e.length;n<i;n++)(r=e[n])&&"object"==typeof r&&((l=o.get(t.get(r)))?l.ownKey=n:console.error("failed to resolve proxy -> target -> observed"));return r=[new function(){Object.defineProperties(this,{type:{value:"reverse"}})}],f.notify(r),this}:"sort"===n?function(){let r,l;Reflect.apply(e[n],e,arguments);for(let r,n=0,i=e.length;n<i;n++)(r=e[n])&&"object"==typeof r&&((l=o.get(t.get(r)))?l.ownKey=n:console.error("failed to resolve proxy -> target -> observed"));return r=[new function(){Object.defineProperties(this,{type:{value:"shuffle"}})}],f.notify(r),this}:"fill"===n?function(){let r,l,a,s=[],y=arguments.length,h=e.length;r=y<2?0:arguments[1]<0?h+arguments[1]:arguments[1],l=y<3?h:arguments[2]<0?h+arguments[2]:arguments[2],a=e.slice(),Reflect.apply(e[n],e,arguments);for(let n,f,y=r;y<l;y++)(n=e[y])&&"object"==typeof n&&(e[y]=new c(n,y,i).proxy),a.hasOwnProperty(y)?((f=t.get(a[y]))&&o.get(f).revoke(),s.push(new u(i.path.concat(y),e[y],f||a[y]))):s.push(new p(i.path.concat(y),e[y]));return f.notify(s),this}:"splice"===n?function(){let r,l,a,s,h,b,v,g,w=[],d=e.length;v=(r=Array.from(arguments)).length;for(let e,t=0;t<v;t++)e=r[t],t>1&&e&&"object"==typeof e&&(r[t]=new c(e,t,i).proxy);s=0===v?0:r[0]<0?d+r[0]:r[0],h=v<2?d-s:r[1],b=Math.max(v-2,0),l=Reflect.apply(e[n],e,r);for(let r,n=0;n<d;n++)(r=e[n])&&"object"==typeof r&&((a=o.get(t.get(r)))?a.ownKey=n:console.error("failed to resolve proxy -> target -> observed"));for(let e,r,n=0,i=l.length;n<i;n++)e=l[n],(r=t.get(e))&&(o.get(r).revoke(),l[n]=r);for(g=0;g<h;g++)g<b?w.push(new u(i.path.concat(s+g),e[s+g],l[g])):w.push(new y(i.path.concat(s+g),l[g]));for(;g<b;g++)w.push(new p(i.path.concat(s+g),e[s+g]));return f.notify(w),l}:Reflect.get(e,n)}function f(e,n,i){let f,a,s=e.hasOwnProperty(n),y=e[n],h=o.get(e),b=r.get(h.root);if((f=i&&"object"==typeof i&&!l(i)?Reflect.set(e,n,new c(i,n,h).proxy):Reflect.set(e,n,i))&&((a=t.get(y))&&o.get(a).revoke(),b.hasListeners)){let e=h.path.concat(n),t=[s?new u(e,i,a||y):new p(e,i)];h.preventCallbacks||b.notify(t)}return f}function a(e,n){let l,i,f=e[n],a=o.get(e),c=r.get(a.root);if((l=Reflect.deleteProperty(e,n))&&((i=t.get(f))&&o.get(i).revoke(),c.hasListeners)){let e=[new y(a.path.concat(n),i||f)];a.preventCallbacks||c.notify(e)}return l}function c(e,r,n){let s,p,u;if(!e||"object"!=typeof e)throw new Error("Observed MUST be created from a non null object origin");if(n&&(void 0===r||null===r))throw new Error("any non-root (parent-less) Observed MUST have an own path; now parent is "+n+"; key is "+r);if(n&&!(n instanceof c))throw new Error("parent, when supplied, MUST be an instance of Observed");var y;y=e,s=Array.isArray(y)?y.slice():Object.assign(new y.constructor,y),Array.isArray(s)?(!function(e,t){for(let o,r=0,n=e.length;r<n;r++)(o=e[r])&&"object"==typeof o&&!l(o)&&(e[r]=new c(o,r,t).proxy)}(s,this),p=Proxy.revocable(s,{set:f,get:i,deleteProperty:a})):(!function(e,t){let o=Object.keys(e);for(let r,n,i=0,f=o.length;i<f;i++)(n=e[r=o[i]])&&"object"==typeof n&&!l(n)&&(e[r]=new c(n,r,t).proxy)}(s,this),p=Proxy.revocable(s,{set:f,deleteProperty:a})),u=p.proxy,o.set(s,this),t.set(u,s),Object.defineProperties(this,{revokable:{value:p},proxy:{value:u},parent:{value:n},ownKey:{value:r,writable:!0}})}function s(e){let t=!1,o=[];Object.defineProperties(e.proxy,{observe:{value:function(e){if(t)throw new TypeError("revoked Observable MAY NOT be observed anymore");if("function"!=typeof e)throw new Error("observer (callback) parameter MUST be a function");o.indexOf(e)<0?o.push(e):console.info("observer (callback) may be bound to an observable only once")}},unobserve:{value:function(){if(t)throw new TypeError("revoked Observable MAY NOT be unobserved anymore");if(arguments.length)for(let e,t=0,r=arguments.length;t<r;t++)(e=o.indexOf(arguments[t]))>=0&&o.splice(e,1);else o.splice(0,o.length)}},revoke:{value:function(){t?console.log("revoking of Observable effective only once"):(t=!0,e.revoke())}}}),Object.defineProperties(this,{hasListeners:{value:function(){return o.length>0}},notify:{value:function(e){for(let t,r=0,n=o.length;r<n;r++){t=o[r];try{t(e)}catch(e){console.error("one/some of the observing callbacks failed with ",e)}}}}})}function p(e,t){Object.defineProperties(this,{type:{value:"insert"},path:{value:e},value:{value:t}})}function u(e,t,o){Object.defineProperties(this,{type:{value:"update"},path:{value:e},value:{value:t},oldValue:{value:o}})}function y(e,t){Object.defineProperties(this,{type:{value:"delete"},path:{value:e},oldValue:{value:t}})}Object.defineProperty(c.prototype,"root",{get:function(){let e=this;for(;e.parent;)e=e.parent;return e}}),Object.defineProperty(c.prototype,"path",{get:function(){let e=[],t=this;for(;void 0!==t.ownKey;)e.unshift(t.ownKey),t=t.parent;return e}}),Object.defineProperty(c.prototype,"revoke",{value:function(){let e=t.get(this.proxy),r=Object.keys(e);this.revokable.revoke();for(let n,l,i=0,f=r.length;i<f;i++)n=r[i],(l=t.get(e[n]))&&(e[n]=o.get(l).revoke());return t.delete(this.proxy),o.delete(e),e}}),Object.defineProperty(s,"from",{value:function(e){if(!e||"object"!=typeof e)throw new Error("observable MAY ONLY be created from non-null object only");if("observe"in e||"unobserve"in e||"revoke"in e)throw new Error('target object MUST NOT have nor own neither inherited properties from the following list: "observe", "unobserve", "revoke"');if(l(e))throw new Error(e+" found to be one of non-observable object types: "+n);let t=new c(e),o=new s(t);return r.set(t,o),t.proxy}}),Object.defineProperty(e,"Observable",{value:s})})(); |
{ | ||
"name": "object-observer", | ||
"version": "0.2.4", | ||
"version": "0.2.5", | ||
"homepage": "https://github.com/gullerya/object-observer-js/README.md", | ||
@@ -9,10 +9,10 @@ "author": { | ||
}, | ||
"description": "Object observer utility provides simple means to (deeply) observe specified object/array changes; implemented via Proxy; changes delivered in a synchronous way", | ||
"main": "dist/object-observer.js", | ||
"description": "Object observer utility provides simple means to (deeply) observe specified object/array changes; implemented via native Proxy; changes delivered in a synchronous way", | ||
"main": "dist/object-observer.min.js", | ||
"devDependencies": { | ||
"grunt": "^1.0.1", | ||
"grunt": "^1.0.2", | ||
"grunt-cli": "^1.2.0", | ||
"uglify-es": "^3.2.0", | ||
"babel-eslint": "^8.0.2", | ||
"eslint-plugin-react": "^7.5.1", | ||
"uglify-es": "^3.3.9", | ||
"babel-eslint": "^8.2.2", | ||
"eslint-plugin-react": "^7.7.0", | ||
"gruntify-eslint": "^4.0.0" | ||
@@ -19,0 +19,0 @@ }, |
@@ -6,22 +6,20 @@ [![npm version](https://badge.fury.io/js/object-observer.svg)](https://badge.fury.io/js/object-observer) | ||
Observation of a changes performed on an object (array being a subtype of it) is a **MUST HAVE** facility in JavaScript world. | ||
`object-observer` provides an __observation of a changes performed on an object__ (array being a subtype of it), hopefully in a most clean and performant way. | ||
Native facility would be the best solution for this, since it may provide non-intrusive observation wihtout 'touching' the original objects, but seems like ES is not yet mature enough for that. | ||
Present library attempts to provide this functionality in a most clean and performant way. Main aspects: | ||
- Implementation relies on __Proxy__ mechanism (specifically, revokable Proxy) | ||
- Observation is 'deep', yielding changes from a __sub-graphs__ too | ||
- Changes delivered in a __synchronous__ way | ||
- Changes delivered always as an __array__, in order to have unified callback API signature supporting also bulk changes delivery in a single call back | ||
- Original objects are __cloned__, thus not being affected; this adds one more step to the normal usage flow: | ||
Main aspects: | ||
- implementation relies on __Proxy__ mechanism (specifically, revokable Proxy) | ||
- observation is 'deep', yielding changes from a __sub-graphs__ too | ||
- changes delivered in a __synchronous__ way | ||
- changes delivered always as an __array__, in order to have unified callback API signature supporting also bulk changes delivery in a single call back | ||
- original objects are __cloned__, thus not being affected; this adds one more step to the normal usage flow: | ||
- first, create observable clone from the specified object | ||
- second, register observers on the observable (not on the original object) | ||
- Arrays: | ||
- arrays: | ||
- generic object-like mutations supported | ||
- intrinsic mutation methods supported: `pop`, `push`, `shift`, `unshift`, `reverse`, `sort`, `fill`, `splice` (see below for more info on changes delivery for these) | ||
- massive mutations delivered in a single callback, usually having an array of an atomic changes | ||
- Enhanced intrinsic methods of `Map`, `WeakMap`, `Set`, `WeakSet` like `set`, `get`, `delete` etc are not observed (see this [issue](https://github.com/gullerya/object-observer-js/issues/1) for more details) | ||
- enhanced intrinsic methods of `Map`, `WeakMap`, `Set`, `WeakSet` like `set`, `get`, `delete` etc are not observed (see this [issue](https://github.com/gullerya/object-observer-js/issues/1) for more details) | ||
#### Support matrix: ![CHROME](https://raw.githubusercontent.com/gullerya/data-tier/master/tools/browser_icons/chrome.png) <sub>49+</sub>, ![FIREFOX](https://raw.githubusercontent.com/gullerya/data-tier/master/tools/browser_icons/firefox.png) <sub>42+</sub>, ![EDGE](https://raw.githubusercontent.com/gullerya/data-tier/master/tools/browser_icons/explorer.png) <sub>13+</sub> | ||
Support matrix is mainly dependent on 2 advanced language features: `Proxy` and `Reflect`. The broader their adoption - the broader the support matrix of ObjectObserver. | ||
#### Support matrix: ![CHROME](./tools/browser_icons/chrome.png) <sub>49+</sub>, ![FIREFOX](./tools/browser_icons/firefox.png) <sub>42+</sub>, ![EDGE](./tools/browser_icons/edge.png) <sub>13+</sub> | ||
Support matrix is mainly dependent on 2 advanced language features: `Proxy` and `Reflect`. The broader their adoption - the broader the support matrix of `object-observer`. | ||
@@ -33,2 +31,9 @@ #### Backlog: | ||
#### Versions | ||
- __0.2.5__ | ||
- Fix: [issue #8](https://github.com/gullerya/object-observer-js/issues/8) - incorrect `oldValue` supplied in `update`/`delete` events when handling inner object/s sub-graph | ||
- __0.2.4__ | ||
- Minor syntactic fixes | ||
- __0.2.3__ | ||
@@ -50,5 +55,2 @@ - Fix: correct handling of removal/replacement of the non-observable objects (issues [this](https://github.com/gullerya/object-observer-js/issues/4) and [this](https://github.com/gullerya/object-observer-js/issues/3)) | ||
- __0.1.0__ | ||
- First stable API release | ||
For a short preview you may want to play with this [JSFiddle](https://jsfiddle.net/gullerya/5a4tyoqs/). | ||
@@ -55,0 +57,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
466
213
35797