UNPKG

@gullerya/object-observer

Version:

object-observer utility provides simple means to (deeply) observe specified object/array changes; implemented via native Proxy; changes delivered in a synchronous way

3 lines (2 loc) 9 kB
var S=Object.defineProperty,$=Object.getOwnPropertyDescriptor,D=Object.getOwnPropertyNames,Y=Object.prototype.hasOwnProperty,I=(n,e)=>{for(var t in e)S(n,t,{get:e[t],enumerable:!0})},B=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of D(e))!Y.call(n,o)&&o!==t&&S(n,o,{get:()=>e[o],enumerable:!(r=$(e,o))||r.enumerable});return n},z=n=>B(S({},"__esModule",{value:!0}),n),T={};I(T,{ObjectObserver:()=>le,Observable:()=>g}),module.exports=z(T);const x="insert",m="update",E="delete",_="reverse",K="shuffle",f=Symbol.for("object-observer-meta-key-0"),q={async:1},H=n=>{if(!n||typeof n!="object")return null;const e={},t=[];for(const[r,o]of Object.entries(n))if(r==="path"){if(typeof o!="string"||o==="")throw new Error('"path" option, if/when provided, MUST be a non-empty string');e[r]=o}else if(r==="pathsOf"){if(n.path)throw new Error('"pathsOf" option MAY NOT be specified together with "path" option');if(typeof o!="string")throw new Error('"pathsOf" option, if/when provided, MUST be a string (MAY be empty)');e[r]=n.pathsOf.split(".").filter(Boolean)}else if(r==="pathsFrom"){if(n.path||n.pathsOf)throw new Error('"pathsFrom" option MAY NOT be specified together with "path"/"pathsOf" option/s');if(typeof o!="string"||o==="")throw new Error('"pathsFrom" option, if/when provided, MUST be a non-empty string');e[r]=o}else t.push(r);if(t.length)throw new Error(`'${t.join(", ")}' is/are not a valid observer option/s`);return e},J=(n,e,t)=>{const r={};r[f]=e;for(const o in n)r[o]=w(n[o],o,e,t);return r},G=(n,e,t)=>{let r=n.length;const o=new Array(r);o[f]=e;for(let i=0;i<r;i++)o[i]=w(n[i],i,e,t);return o},Q=(n,e)=>(n[f]=e,n),X=(n,e)=>{if(n===null)return e;let t=e;if(n.path){const r=n.path;t=e.filter(o=>o.path.join(".")===r)}else if(n.pathsOf){const r=n.pathsOf,o=r.join(".");t=e.filter(i=>(i.path.length===r.length+1||i.path.length===r.length&&(i.type===_||i.type===K))&&i.path.join(".").startsWith(o))}else if(n.pathsFrom){const r=n.pathsFrom;t=e.filter(o=>o.path.join(".").startsWith(r))}return t},R=(n,e)=>{try{n(e)}catch(t){console.error(`failed to notify listener ${n} with ${e}`,t)}},Z=function(){const e=this.batches;this.batches=[];for(const[t,r]of e)R(t,r)},v=(n,e)=>{let t=n,r,o,i,l,a,s;const u=e.length;do{for(r=t.options.async,o=t.observers,s=o.length;s--;)if([i,l]=o[s],a=X(l,e),a.length)if(r){t.batches.length===0&&queueMicrotask(Z.bind(t));let h;for(const c of t.batches)if(c[0]===i){h=c;break}h||(h=[i,[]],t.batches.push(h)),Array.prototype.push.apply(h[1],a)}else R(i,a);const p=t.parent;if(p){for(let h=0;h<u;h++){const c=e[h];e[h]=new b(c.type,[t.ownKey,...c.path],c.value,c.oldValue,c.object)}t=p}else t=null}while(t)},w=(n,e,t,r)=>r!==void 0&&r.has(n)?null:typeof n!="object"||n===null?n:Array.isArray(n)?new U({target:n,ownKey:e,parent:t,visited:r}).proxy:ArrayBuffer.isView(n)?new W({target:n,ownKey:e,parent:t}).proxy:n instanceof Date?n:new N({target:n,ownKey:e,parent:t,visited:r}).proxy,k=function(){const e=this[f],t=e.target,r=t.length-1;let o=t.pop();if(o&&typeof o=="object"){const l=o[f];l&&(o=l.detach())}const i=[new b(E,[r],void 0,o,this)];return v(e,i),o},ee=function(){const e=this[f],t=e.target,r=arguments.length,o=new Array(r),i=t.length;for(let s=0;s<r;s++)o[s]=w(arguments[s],i+s,e);const l=Reflect.apply(t.push,t,o),a=[];for(let s=i,u=t.length;s<u;s++)a[s-i]=new b(x,[s],t[s],void 0,this);return v(e,a),l},te=function(){const e=this[f],t=e.target;let r,o,i,l,a;for(r=t.shift(),r&&typeof r=="object"&&(a=r[f],a&&(r=a.detach())),o=0,i=t.length;o<i;o++)l=t[o],l&&typeof l=="object"&&(a=l[f],a&&(a.ownKey=o));const s=[new b(E,[0],void 0,r,this)];return v(e,s),r},re=function(){const e=this[f],t=e.target,r=arguments.length,o=new Array(r);for(let s=0;s<r;s++)o[s]=w(arguments[s],s,e);const i=Reflect.apply(t.unshift,t,o);for(let s=0,u=t.length,p;s<u;s++)if(p=t[s],p&&typeof p=="object"){const h=p[f];h&&(h.ownKey=s)}const l=o.length,a=new Array(l);for(let s=0;s<l;s++)a[s]=new b(x,[s],t[s],void 0,this);return v(e,a),i},F=function(){const e=this[f],t=e.target;let r,o,i;for(t.reverse(),r=0,o=t.length;r<o;r++)if(i=t[r],i&&typeof i=="object"){const a=i[f];a&&(a.ownKey=r)}const l=[new b(_,[],void 0,void 0,this)];return v(e,l),this},C=function(e){const t=this[f],r=t.target;let o,i,l;for(r.sort(e),o=0,i=r.length;o<i;o++)if(l=r[o],l&&typeof l=="object"){const s=l[f];s&&(s.ownKey=o)}const a=[new b(K,[],void 0,void 0,this)];return v(t,a),this},L=function(e,t,r){const o=this[f],i=o.target,l=[],a=i.length,s=i.slice(0);if(t=t===void 0?0:t<0?Math.max(a+t,0):Math.min(t,a),r=r===void 0?a:r<0?Math.max(a+r,0):Math.min(r,a),t<a&&r>t){i.fill(e,t,r);let u;for(let p=t,h,c;p<r;p++)h=i[p],i[p]=w(h,p,o),p in s?(c=s[p],c&&typeof c=="object"&&(u=c[f],u&&(c=u.detach())),l.push(new b(m,[p],i[p],c,this))):l.push(new b(x,[p],i[p],void 0,this));v(o,l)}return this},V=function(e,t,r){const o=this[f],i=o.target,l=i.length;e=e<0?Math.max(l+e,0):e,t=t===void 0?0:t<0?Math.max(l+t,0):Math.min(t,l),r=r===void 0?l:r<0?Math.max(l+r,0):Math.min(r,l);const a=Math.min(r-t,l-e);if(e<l&&e!==t&&a>0){const s=i.slice(0),u=[];i.copyWithin(e,t,r);for(let p=e,h,c,O;p<e+a;p++)h=i[p],h&&typeof h=="object"&&(h=w(h,p,o),i[p]=h),c=s[p],c&&typeof c=="object"&&(O=c[f],O&&(c=O.detach())),!(typeof h!="object"&&h===c)&&u.push(new b(m,[p],h,c,this));v(o,u)}return this},oe=function(){const e=this[f],t=e.target,r=arguments.length,o=new Array(r),i=t.length;for(let d=0;d<r;d++)o[d]=w(arguments[d],d,e);const l=r===0?0:o[0]<0?i+o[0]:o[0],a=r<2?i-l:o[1],s=Math.max(r-2,0),u=Reflect.apply(t.splice,t,o),p=t.length;let h;for(let d=0,A;d<p;d++)A=t[d],A&&typeof A=="object"&&(h=A[f],h&&(h.ownKey=d));let c,O,j;for(c=0,O=u.length;c<O;c++)j=u[c],j&&typeof j=="object"&&(h=j[f],h&&(u[c]=h.detach()));const M=[];let y;for(y=0;y<a;y++)y<s?M.push(new b(m,[l+y],t[l+y],u[y],this)):M.push(new b(E,[l+y],void 0,u[y],this));for(;y<s;y++)M.push(new b(x,[l+y],t[l+y],void 0,this));return v(e,M),u},ne=function(e,t){const r=this[f],o=r.target,i=e.length,l=o.slice(0);t=t||0,o.set(e,t);const a=new Array(i);for(let s=t;s<i+t;s++)a[s-t]=new b(m,[s],o[s],l[s],this);v(r,a)},ie={pop:k,push:ee,shift:te,unshift:re,reverse:F,sort:C,fill:L,copyWithin:V,splice:oe},se={reverse:F,sort:C,fill:L,copyWithin:V,set:ne};class b{constructor(e,t,r,o,i){this.type=e,this.path=t,this.value=r,this.oldValue=o,this.object=i}}class P{constructor(e,t){const{target:r,parent:o,ownKey:i,visited:l=new Set}=e;o&&i!==void 0?(this.parent=o,this.ownKey=i):(this.parent=null,this.ownKey=null),l.add(r);const a=t(r,this,l);l.delete(r),this.observers=[],this.revocable=Proxy.revocable(a,this),this.proxy=this.revocable.proxy,this.target=a,this.options=this.processOptions(e.options),this.options.async&&(this.batches=[])}processOptions(e){if(e){if(typeof e!="object")throw new Error(`Observable options if/when provided, MAY only be an object, got '${e}'`);const t=Object.keys(e).filter(r=>!(r in q));if(t.length)throw new Error(`'${t.join(", ")}' is/are not a valid Observable option/s`);return Object.assign({},e)}else return{}}detach(){return this.parent=null,this.target}set(e,t,r){let o=e[t];if(r!==o){const i=w(r,t,this);if(e[t]=i,o&&typeof o=="object"){const a=o[f];a&&(o=a.detach())}const l=o===void 0?[new b(x,[t],i,void 0,this.proxy)]:[new b(m,[t],i,o,this.proxy)];v(this,l)}return!0}deleteProperty(e,t){let r=e[t];if(delete e[t],r&&typeof r=="object"){const i=r[f];i&&(r=i.detach())}const o=[new b(E,[t],void 0,r,this.proxy)];return v(this,o),!0}}class N extends P{constructor(e){super(e,J)}}class U extends P{constructor(e){super(e,G)}get(e,t){return ie[t]||e[t]}}class W extends P{constructor(e){super(e,Q)}get(e,t){return se[t]||e[t]}}const g=Object.freeze({from:(n,e)=>{if(!n||typeof n!="object")throw new Error("observable MAY ONLY be created from a non-null object");if(n[f])return n;if(Array.isArray(n))return new U({target:n,ownKey:null,parent:null,options:e}).proxy;if(ArrayBuffer.isView(n))return new W({target:n,ownKey:null,parent:null,options:e}).proxy;if(n instanceof Date)throw new Error(`${n} found to be one of a non-observable types`);return new N({target:n,ownKey:null,parent:null,options:e}).proxy},isObservable:n=>!!(n&&n[f]),observe:(n,e,t)=>{if(!g.isObservable(n))throw new Error("invalid observable parameter");if(typeof e!="function")throw new Error(`observer MUST be a function, got '${e}'`);const r=n[f].observers;r.some(o=>o[0]===e)?console.warn("observer may be bound to an observable only once; will NOT rebind"):r.push([e,H(t)])},unobserve:(n,...e)=>{if(!g.isObservable(n))throw new Error("invalid observable parameter");const t=n[f].observers;let r=t.length;if(r){if(!e.length){t.splice(0);return}for(;r;)e.indexOf(t[--r][0])>=0&&t.splice(r,1)}}});class le{#t;#e;constructor(e){this.#t=e,this.#e=new Set,Object.freeze(this)}observe(e,t){const r=g.from(e);return g.observe(r,this.#t,t),this.#e.add(r),r}unobserve(e){g.unobserve(e,this.#t),this.#e.delete(e)}disconnect(){for(const e of this.#e)g.unobserve(e,this.#t);this.#e.clear()}} //# sourceMappingURL=object-observer.min.cjs.map