@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) • 10.3 kB
JavaScript
var f=Symbol.for("object-observer-meta-key-0"),v="insert",w="update",x="delete",T="reverse",R="shuffle";var c=class{#e;#t;#o;#i;#n;#r;constructor(e,t,o,n,i){this.#e=e,this.#t=t,this.#o=o,this.#i=n,this.#n=i}get type(){return this.#e}get path(){return this.#t}get value(){return this.#o}get oldValue(){return this.#i}get object(){return this.#n}get pathAsString(){return this.#r===void 0&&(this.#r=this.#t.join(".")),this.#r}};var M=class r{static#e=Symbol("ValidatorPrivateConstructorKey");#t;constructor(e,t){if(e!==r.#e)throw new Error("Validator class cannot be instantiated directly; use provided factory methods");this.#t=t}get validate(){return this.#t}static custom(e){if(typeof e!="function")throw new Error("custom Validator requires a function as argument");return new r(r.#e,e)}};function W(r,e){let t=r[e],o=[new c(x,[e],void 0,t,this.proxy)];d(this,o),delete r[e];let n=g(t),i=[new c(x,[e],void 0,n,this.proxy)];return u(this,i),!0}function $(r,e,t){let o=r[e];if(t!==o){let n=o===void 0?[new c(v,[e],t,void 0,this.proxy)]:[new c(w,[e],t,o,this.proxy)];d(this,n);let i=y(t,e,this);r[e]=i;let s=g(o),p=s===void 0?[new c(v,[e],i,void 0,this.proxy)]:[new c(w,[e],i,s,this.proxy)];u(this,p)}return!0}var z={async:1,validators:1},E=class{#e;ownKey;#t;#o;#i;#n=!1;batches=new Map;set;deleteProperty;#r=[];#s=[];constructor(e){this.set=$,this.deleteProperty=W;let{target:t,parent:o,ownKey:n,options:i,visited:s=new Set}=e;o&&n!==void 0?(this.#e=o,this.ownKey=n):(this.#e=null,this.ownKey=null),s.add(t),this.#t=this.observedGraphProcessor(t,this,s),s.delete(t);let p=Proxy.revocable(this.#t,this);this.#o=p.proxy,this.#i=p.revoke,this.#a(i)}detach(){return this.#e=null,this.#t}get parent(){return this.#e}get target(){return this.#t}get proxy(){return this.#o}get async(){return this.#n}get validators(){return this.#r}get observers(){return this.#s}#a(e){if(!e)return;if(typeof e!="object")throw new Error(`Observable options if/when provided, MAY only be an object, got '${e}'`);let t=Object.keys(e).filter(o=>!(o in z));if(t.length)throw new Error(`'${t.join(", ")}' is/are not a valid Observable option/s`);if(this.#n=!!e.async,e.validators!==void 0){if(!Array.isArray(e.validators)||e.validators.length===0)throw new Error('"validators" option, if/when provided, MUST be a non-empty array of Validator instances');for(let o of e.validators)if(!(o instanceof M))throw new Error('"validators" option, if/when provided, MUST be a non-empty array of Validator instances');this.#r.push(...e.validators)}}};function S(r,e,t){let o=this[f],n=o.target,i=n.length;r=r<0?Math.max(i+r,0):r,e=e===void 0?0:e<0?Math.max(i+e,0):Math.min(e,i),t=t===void 0?i:t<0?Math.max(i+t,0):Math.min(t,i);let s=Math.min(t-e,i-r);if(r<i&&r!==e&&s>0){let p=n.slice(0),a=[];n.copyWithin(r,e,t);for(let l=r;l<r+s;l++){let b=n[l];b&&typeof b=="object"&&(b=y(b,l,o),n[l]=b);let h=g(p[l]);typeof b!="object"&&b===h||a.push(new c(w,[l],b,h,this))}u(o,a)}return this}function C(r,e,t){let o=this[f],n=o.target,i=[],s=n.length,p=n.slice(0);if(e=e===void 0?0:e<0?Math.max(s+e,0):Math.min(e,s),t=t===void 0?s:t<0?Math.max(s+t,0):Math.min(t,s),e<s&&t>e){n.fill(r,e,t);for(let a=e;a<t;a++)if(n[a]=y(n[a],a,o),a in p){let l=g(p[a]);i.push(new c(w,[a],n[a],l,this))}else i.push(new c(v,[a],n[a],void 0,this));u(o,i)}return this}function L(){let r=this[f],e=r.target,t=e.length-1,o=e[t],n=[new c(x,[t],void 0,o,this)];d(r,n);let i=g(e.pop()),s=[new c(x,[t],void 0,i,this)];return u(r,s),i}function B(...r){let e=this[f],t=e.target,o=r.length,n=t.length,i=new Array(o);for(let l=0;l<o;l++)i[l]=new c(v,[n+l],r[l],void 0,this);d(e,i);let s=new Array(o);for(let l=0;l<o;l++)s[l]=y(r[l],n+l,e);let p=Reflect.apply(t.push,t,s),a=new Array(o);for(let l=0;l<o;l++)a[l]=new c(v,[n+l],t[n+l],void 0,this);return u(e,a),p}function F(){let r=this[f],e=r.target,t=[new c(T,[],void 0,void 0,this)];return d(r,t),e.reverse(),O(e),u(r,t),this}function U(){let r=this[f],e=r.target,t=e[0],o=[new c(x,[0],void 0,t,this)];d(r,o);let n=g(e.shift());O(e);let i=[new c(x,[0],void 0,n,this)];return u(r,i),n}function V(r){let e=this[f],t=e.target,o=[new c(R,[],void 0,void 0,this)];return d(e,o),t.sort(r),O(t),u(e,o),this}function D(...r){let e=this[f],t=e.target,o=r.length,n=new Array(o),i=t.length;for(let m=0;m<o;m++)n[m]=y(r[m],m,e);let s=o===0?0:n[0]<0?i+n[0]:n[0],p=o<2?i-s:n[1],a=Math.max(o-2,0),l=Reflect.apply(t.splice,t,n);O(t);for(let m=0,Y=l.length;m<Y;m++)l[m]=g(l[m]);let b=[],h;for(h=0;h<p;h++)h<a?b.push(new c(w,[s+h],t[s+h],l[h],this)):b.push(new c(x,[s+h],void 0,l[h],this));for(;h<a;h++)b.push(new c(v,[s+h],t[s+h],void 0,this));return u(e,b),l}function I(...r){let e=this[f],t=e.target,o=r.length,n=new Array(o);for(let a=0;a<o;a++)n[a]=new c(v,[a],r[a],void 0,this);d(e,n);let i=new Array(o);for(let a=0;a<o;a++)i[a]=y(r[a],a,e);let s=Reflect.apply(t.unshift,t,i);O(t);let p=new Array(o);for(let a=0;a<o;a++)p[a]=new c(v,[a],t[a],void 0,this);return u(e,p),s}var J={copyWithin:S,fill:C,pop:L,push:B,reverse:F,shift:U,sort:V,splice:D,unshift:I},j=class extends E{get(e,t){return J[t]||e[t]}observedGraphProcessor(e,t,o){let n=e.length,i=new Array(n);for(let s=0;s<n;s++)i[s]=y(e[s],s,t,o);return i[f]=t,i}};var K=class extends E{observedGraphProcessor(e,t,o){let n={};n[f]=t;for(let i in e)n[i]=y(e[i],i,t,o);return n}};function N(r,e){let t=this[f],o=t.target,n=r.length;if(e=e||0,n>0){let i=o.slice(e,e+n),s=new Array(n);for(let a=0;a<n;a++)s[a]=new c(w,[e+a],r[a],i[a],this);d(t,s),o.set(r,e);let p=new Array(n);for(let a=0;a<n;a++)p[a]=new c(w,[e+a],o[e+a],i[a],this);u(t,p)}}var Q={copyWithin:S,fill:C,reverse:F,sort:V,set:N},P=class extends E{get(e,t){return Q[t]||e[t]}observedGraphProcessor(e,t){return e[f]=t,e}};function y(r,e,t,o){return o!==void 0&&o.has(r)?null:typeof r!="object"||r===null?r:Array.isArray(r)?new j({target:r,ownKey:e,parent:t,visited:o}).proxy:ArrayBuffer.isView(r)?new P({target:r,ownKey:e,parent:t}).proxy:r instanceof Date?r:new K({target:r,ownKey:e,parent:t,visited:o}).proxy}function q(r,e=void 0){if(!r||typeof r!="object")throw new Error("observable MAY ONLY be created from a non-null object");if(r[f])return r;if(Array.isArray(r))return new j({target:r,ownKey:null,parent:null,options:e}).proxy;if(ArrayBuffer.isView(r))return new P({target:r,ownKey:null,parent:null,options:e}).proxy;if(r instanceof Date)throw new Error(`${r} found to be one of a non-observable types`);return new K({target:r,ownKey:null,parent:null,options:e}).proxy}function O(r,e=0){for(let t=e,o=r.length;t<o;t++){let n=r[t];if(n&&typeof n=="object"){let i=n[f];i&&(i.ownKey=t)}}}function g(r){if(r&&typeof r=="object"){let e=r[f];if(e)return e.detach()}return r}function d(r,e){let t=[],o=r;for(;o.parent;)t.unshift(o.ownKey),o=o.parent;let n=o.validators;if(n.length===0)return;let i=t.length===0?e:e.map(s=>new c(s.type,[...t,...s.path],s.value,s.oldValue,s.object));for(let s=0,p=n.length;s<p;s++)n[s].validate(i)}function u(r,e){let t=r,o,n,i,s,p,a,l=e.length;do{for(o=t.async,n=t.observers,a=n.length;a--;)if([i,s]=n[a],p=X(s,e),p.length)if(o){t.batches.size===0&&queueMicrotask(Z.bind(t));let h=t.batches.get(i);h||(h=[],t.batches.set(i,h)),h.push(...p)}else G(i,p);let b=t.parent;if(b){for(let h=0;h<l;h++){let m=e[h];e[h]=new c(m.type,[t.ownKey,...m.path],m.value,m.oldValue,m.object)}t=b}else break}while(t)}function X(r,e){if(r===null||!r.filters)return e;let t=e,o=r.filters;for(let n=0,i=o.length;n<i&&t.length;n++)t=o[n](t);return t}function G(r,e){try{r(e)}catch(t){console.error(`failed to notify listener ${r} with ${e}`,t)}}function Z(){let r=this.batches;this.batches=new Map;for(let[e,t]of r)G(e,t)}var k=class r{static#e=Symbol("FilterPrivateConstructorKey");#t;constructor(e,t){if(e!==r.#e)throw new Error("Filter class cannot be instantiated directly; use provided factory methods");this.#t=t}get fn(){return this.#t}static custom(e){if(typeof e!="function")throw new Error("custom Filter requires a function as argument");return new r(r.#e,e)}static exactPaths(e){if(!Array.isArray(e)||e.length===0)throw new Error("exactPaths Filter requires a non-empty array as argument");let t=new Set(e);return new r(r.#e,o=>o.filter(n=>t.has(n.pathAsString)))}static pathsStartWith(e){if(typeof e!="string"||e==="")throw new Error("pathsStartWith Filter requires a non-empty string as argument");return new r(r.#e,t=>t.filter(o=>o.pathAsString.startsWith(e)))}static directChildrenOf(e){if(typeof e!="string")throw new Error("directChildrenOf Filter requires a string as argument (MAY be empty)");let t=e.split(".").filter(Boolean),o=t.length,n=t.join(".");return new r(r.#e,i=>i.filter(s=>{let p=s.path,a=p.length;if(a===o+1){for(let l=0;l<o;l++)if(p[l]!==t[l])return!1;return!0}return a===o&&(s.type===T||s.type===R)?s.pathAsString===n:!1}))}};var _=r=>{if(!r||typeof r!="object")return null;let e={},t=[];for(let[o,n]of Object.entries(r))if(o==="filters"){if(!Array.isArray(n)||n.length===0)throw new Error('"filters" option, if/when provided, MUST be a non-empty array of Filter instances');let i=new Array(n.length);for(let s=0;s<n.length;s++){let p=n[s];if(!(p instanceof k))throw new Error('"filters" option, if/when provided, MUST be a non-empty array of Filter instances');i[s]=p.fn}e.filters=i}else t.push(o);if(t.length)throw new Error(`'${t.join(", ")}' is/are not a valid observer option/s`);return Object.keys(e).length===0?null:e},A=Object.freeze({from:q,isObservable:r=>!!(r&&r[f]),observe:(r,e,t)=>{if(!A.isObservable(r))throw new Error("invalid observable parameter");if(typeof e!="function")throw new Error(`observer MUST be a function, got '${e}'`);let o=r[f].observers;o.some(n=>n[0]===e)?console.warn("observer may be bound to an observable only once; will NOT rebind"):o.push([e,_(t)])},unobserve:(r,...e)=>{if(!A.isObservable(r))throw new Error("invalid observable parameter");let t=r[f].observers,o=t.length;if(o){if(!e.length){t.splice(0);return}for(;o;)e.indexOf(t[--o][0])>=0&&t.splice(o,1)}}}),H=class{#e;#t;constructor(e){this.#e=e,this.#t=new Set,Object.freeze(this)}observe(e,t){let o=A.from(e);return A.observe(o,this.#e,t),this.#t.add(o),o}unobserve(e){A.unobserve(e,this.#e),this.#t.delete(e)}disconnect(){for(let e of this.#t)A.unobserve(e,this.#e);this.#t.clear()}};export{k as Filter,H as ObjectObserver,A as Observable,M as Validator};
//# sourceMappingURL=object-observer.min.js.map