UNPKG

@konfirm/decoy

Version:

Proxy objects, keeping track of mutations to commit/rollback

2 lines (1 loc) 11.8 kB
var Decoy=function(t,e){"use strict";function n(t,e,n,r){return new(n||(n=Promise))((function(s,i){function o(t){try{a(r.next(t))}catch(t){i(t)}}function c(t){try{a(r.throw(t))}catch(t){i(t)}}function a(t){var e;t.done?s(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(o,c)}a((r=r.apply(t,e||[])).next())}))}function r(t,...e){return n=>{if(e.includes(n))return n;throw new Error(`Unknown ${t}: "${n}"`)}}"function"==typeof SuppressedError&&SuppressedError;const s=r("algorithm",...e.getHashes()),i=r("digest","hex","base64"),o={array:(t,e)=>a(t,...e),object:(t,e)=>{return(n=e,[...new Set(c(n).concat(Object.keys(n)))].filter((t=>"__proto__"!==t&&"function"!=typeof n[t])).sort(((t,e)=>-Number(t<e)||Number(t>e)))).reduce(((t,n)=>a(a(t,n),e[n])),t);var n},null:t=>a(t,"NULL"),boolean:(t,e)=>t.update(e?"true":"false")};function c(t){const{constructor:{prototype:e}}=t,n=Object.getOwnPropertyDescriptors(e);return Object.keys(n)}function a(t,...e){return e.reduce(((t,e)=>{const n=function(t){const e=null===t?"null":Array.isArray(t)?"array":typeof t;return e in o?o[e]:(t,e)=>t.update(String(e))}(e);return n(t,e)}),t)}let u=class{constructor(t={}){this.mapping=Object.keys(t).map((e=>n=>t[e](n)?e:void 0)).concat((t=>typeof t))}map(t){return this.mapping.reduce(((e,n)=>e||n(t)),void 0)}};const l=new u({date:t=>t instanceof Date,regexp:t=>t instanceof RegExp,array:t=>Array.isArray(t),null:t=>null===t}),p=new class{constructor(t=new u,e={}){this.types=t,this.mapping=e}map(t){const e=this.types.map(t);return e in this.mapping?this.mapping[e](t,(t=>this.map(t))):(null==t?void 0:t.toString())||"undefined"}}(l,{string:t=>t?`"${t}"`:"EmptyString",date:(t,e)=>e(t.toISOString()),object:(t,e)=>{const n=String(t);if(/^\[([a-z]+) \1\]$/i.test(n)){return`{${Object.keys(t).map((n=>`${n}:${e(t[n])}`)).join(",")}}`}return n},array:(t,e)=>`[${t.map(e).join(",")}]`,null:()=>"NULL",undefined:()=>"Undefined",function:t=>{const{constructor:{name:e},name:n}=t,[,r,s,i]=e.match(/^(async)?(generator)?(function)$/i),[,o,c]=t.toString().match(/^(?:async)?(?:[\s\*]+)?(class|function)?(?:[\s\*]+)?([a-z_]\w*)?\s*[\(\{]?/i);return[[].concat(!o||n||c?[]:"anonymous").concat(n&&!o&&c?"shorthand":[]).concat(r||[],s||[]).concat(o||c?[]:"arrow").concat(o||i).map((t=>t[0].toUpperCase()+t.slice(1))).join("")].concat(n||[]).join(" ")}});class g extends Error{constructor(t,e,n){super(t),this.value=e,this.trigger=n,Object.setPrototypeOf(this,new.target.prototype)}get reasons(){const{message:t,value:e,trigger:n}=this;return((null==n?void 0:n.reasons)||[]).concat(`${(t=>p.map(t))(e)} ${t}`)}get cause(){const{message:t,value:e,trigger:n}=this;return[{value:e,message:t}].concat((null==n?void 0:n.cause)||[])}get reason(){return String(this)}toString(t="​←​"){return this.reasons.reverse().join(t)}}function y(t){return e=>typeof e===t}function h(...t){return e=>t.some((t=>t(e)))}function f(...t){return e=>t.every((t=>t(e)))}function m(...t){return e=>t.every((t=>!t(e)))}const d=t=>Array.isArray(t),b=y("function"),v=f(m(d),m((t=>null===t)),y("object")),k=y("string"),w=y("symbol"),j=y("undefined");function O(t){return f(v,(e=>t in e))}function S(t,...e){return f(O(t),(n=>e.every((e=>e(n[t])))))}function P(t,...e){return h(f(v,m(O(t))),S(t,...e))}function $(t,...e){const n=e.reduce(((t,e)=>t.concat(e)),[]),r=Object.keys(t).map((e=>(n.includes(e)?P:S)(e,t[e])));return f(v,...r)}const x=function(t,...e){const n=f(...e);class r extends g{}return e=>{try{if(!n(e))throw new r(t,e)}catch(n){throw new g(t,e,...n instanceof r||!(n instanceof g)?[]:[n])}return!0}}("Invalid MutationOptions",$({target:h(v,b,d),key:h(k,w),value:()=>!0},"value")),A=new WeakMap;class D{constructor(t){x(t),A.set(this,t)}get name(){const{constructor:{name:t}}=Object.getPrototypeOf(this);return t.replace(/([^A-Z]+)([A-Z]+)/g,"$1-$2").toLowerCase()}get target(){const{target:t}=A.get(this);return t}get key(){const{key:t}=A.get(this);return t}get value(){const{value:t}=A.get(this);return t}get descriptor(){}apply(){throw new Error("Not implemented")}toString(t="{name}: {key} = {value}"){return t.replace(/\{([^\}]+)\}/g,((t,e)=>this[e]))}toJSON(){const{name:t,key:e,value:n}=this;return{name:t,key:e,value:n}}}class E extends D{get name(){return"deletion-mutation"}get value(){}apply(){const{target:t,key:e}=this;delete t[e]}toString(t="{name}: {key}"){return super.toString(t)}}class M{constructor(t={}){this.mapping=Object.keys(t).map((e=>n=>t[e](n)?e:void 0)).concat((t=>typeof t))}map(t){return this.mapping.reduce(((e,n)=>e||n(t)),void 0)}}const L=new M({date:t=>t instanceof Date,regexp:t=>t instanceof RegExp,array:t=>Array.isArray(t),null:t=>null===t});function N(t){return e=>typeof e===t}function U(...t){return e=>t.some((t=>t(e)))}function K(...t){return e=>t.every((t=>t(e)))}function _(...t){return e=>t.every((t=>!t(e)))}new class{constructor(t=new M,e={}){this.types=t,this.mapping=e}map(t){const e=this.types.map(t);return e in this.mapping?this.mapping[e](t,(t=>this.map(t))):(null==t?void 0:t.toString())||"undefined"}}(L,{string:t=>t?`"${t}"`:"EmptyString",date:(t,e)=>e(t.toISOString()),object:(t,e)=>{const n=String(t);if(/^\[([a-z]+) \1\]$/i.test(n)){return`{${Object.keys(t).map((n=>`${n}:${e(t[n])}`)).join(",")}}`}return n},array:(t,e)=>`[${t.map(e).join(",")}]`,null:()=>"NULL",undefined:()=>"Undefined",function:t=>{const{constructor:{name:e},name:n}=t,[,r,s,i]=e.match(/^(async)?(generator)?(function)$/i),[,o,c]=t.toString().match(/^(?:async)?(?:[\s\*]+)?(class|function)?(?:[\s\*]+)?([a-z_]\w*)?\s*[\(\{]?/i);return[[].concat(!o||n||c?[]:"anonymous").concat(n&&!o&&c?"shorthand":[]).concat(r||[],s||[]).concat(o||c?[]:"arrow").concat(o||i).map((t=>t[0].toUpperCase()+t.slice(1))).join("")].concat(n||[]).join(" ")}});const z=N("boolean"),W=N("function"),C=K(_((t=>Array.isArray(t))),_((t=>null===t)),N("object")),I=N("undefined");function R(t){return K(C,(e=>t in e))}function H(t,...e){return K(R(t),(n=>e.every((e=>e(n[t])))))}function Z(t,...e){return U(K(C,_(R(t))),H(t,...e))}function B(t,...e){const n=e.reduce(((t,e)=>t.concat(e)),[]),r=Object.keys(t).map((e=>(n.includes(e)?Z:H)(e,t[e])));return K(C,...r)}function F(t,...e){const n=Object.keys(t);return K(B(t,...e),(t=>Object.keys(t).every((t=>n.includes(t)))))}const J={enumerable:z,configurable:z},q=F(J,Object.keys(J)),G={configurable:z,enumerable:z,get:W,set:W},Q=F(G,...Object.keys(G).filter((t=>"get"!==t))),T={configurable:z,enumerable:z,value:()=>!0,writable:z},V=U(q,F(T,Object.keys(T).filter((t=>"value"!==t))),Q),X="value",Y="get",tt="set",et="writable";class nt{static get(t,e){const n=Object.getOwnPropertyDescriptor(t,e);return n||{value:void 0,writable:!Object.isFrozen(t),enumerable:!0,configurable:Object.isExtensible(t)}}static only(t,...e){return e.filter((e=>e in t&&!I(t[e]))).reduce(((e,n)=>Object.assign(e,{[n]:t[n]})),{})}static omit(t,...e){return this.only(t,...Object.keys(t).filter((t=>!e.includes(t))))}static merge(...t){return t.reduce(((t,e)=>this.combine(t,e)),void 0)}static combine(t,e){if(!t||!e)return e;let n=t;Y in e||tt in e?n=this.omit(n,X,et):(X in e||et in e)&&(n=this.omit(n,Y,tt));const r=Object.assign({},n,e);return tt in r&&!(Y in r)&&(r[Y]=()=>{}),et in r&&!(X in r)&&(r[X]=void 0),r}}class rt extends D{constructor(t){if(!j(t.value)&&!V(t.value))throw new Error("Not a valid PropertyDescriptor");super(t)}get name(){return"property-mutation"}get descriptor(){const{target:t,key:e}=this;return nt.merge(Object.getOwnPropertyDescriptor(t,e),super.value)}get value(){const{value:t,get:e}=super.value;return e?e():t}apply(){const{target:t,key:e,descriptor:n}=this;Object.defineProperty(t,e,n)}}class st extends D{get name(){return"value-mutation"}get descriptor(){const{target:t,key:e,value:n}=this,r=Object.getOwnPropertyDescriptor(t,e)||{writable:!0,enumerable:!0,configurable:!0};return nt.merge(r,{value:n})}apply(){const{target:t,key:e,value:n}=this;t[e]=n}}const it=new WeakMap;class ot{constructor(...t){this.items=[],this.push(...t)}push(...t){const{length:e}=this.items;return this.items.push(...t.filter((t=>!this.items.includes(t)))),this.items.length-e}pull(...t){return t.reduce(((t,e)=>t.concat(this.items.splice(this.items.indexOf(e),1))),[])}count(t){return(t?this.items.filter(this.seeker(t)):this.items).length}find(t){return this.items.find(this.seeker(t))}findAll(t){return this.items.filter(this.seeker(t))}seeker(t){const e=Object.keys(t);return n=>e.every((e=>n[e]===t[e]))}static for(t){return it.has(t)||it.set(t,new ot),it.get(t)}}class ct{constructor(t=!1){this.onlyLastKeyMutation=t,this.mutations=ot.for(this)}defineProperty(t,e,n){const{enumerable:r=Array.from(this.ownKeys(t)).indexOf(e)>=0}=n||{},s=n&&Object.assign({enumerable:r},n);return this.insert(new rt({target:t,key:e,value:s}))}deleteProperty(t,e){const n=new E({target:t,key:e});return this.onlyLastKeyMutation&&this.purge(n)>=0&&!Object.getOwnPropertyDescriptor(t,e)||this.insert(n)}get(t,e){const{[e]:n}=t;return this.mutations.findAll({target:t,key:e}).reduce(((t,{value:e})=>e),n)}getOwnPropertyDescriptor(t,e){return this.mutations.findAll({target:t,key:e}).reduce(((t,{descriptor:e})=>e),Object.getOwnPropertyDescriptor(t,e))}has(t,e){return this.mutations.findAll({target:t,key:e}).reduce(((t,e)=>!(e instanceof E)),e in t)}ownKeys(t){return this.mutations.findAll({target:t}).reduce(((t,e)=>{var n;return e instanceof E||e instanceof rt&&!(null===(n=e.descriptor)||void 0===n?void 0:n.enumerable)?t.filter((t=>t!==e.key)):t.concat(e.key)}),Reflect.ownKeys(t)).filter(((t,e,n)=>n.indexOf(t)===e))}set(t,e,n){const r=new st({target:t,key:e,value:n});return this.onlyLastKeyMutation&&this.purge(r)>=0&&t[e]===n||this.insert(r)}count(t){return this.mutations.count(t)}commit(t={}){this.eject(t).forEach((t=>t.apply()))}rollback(t={}){this.eject(t)}insert(t){return this.purge(t),Boolean(this.mutations.push(t))}eject(t){return this.mutations.pull(...this.mutations.findAll(t))}purge({target:t,key:e}){return this.onlyLastKeyMutation?this.eject({target:t,key:e}).length:0}}!function(t,...e){const n=Object.keys(t);f($(t,...e),(t=>Object.keys(t).every((t=>n.includes(t)))))}({name:k,target:h(v,b),key:h(k,w),value:()=>!0,descriptor:h(j,V),apply:b},["value"]);const at=new WeakMap;class ut extends ct{constructor(t,e=!1){super(e),at.set(this,{delegate:t,cache:new WeakMap})}delegate(t){const{delegate:e}=at.get(this),n=e(t);return Object.setPrototypeOf(n,Object.getPrototypeOf(t)),n}cache(t,e){const{cache:n}=at.get(this);n.has(e)||n.set(e,new Map);const r=n.get(e);return r.has(t)||r.set(t,this.delegate(e)),r.get(t)}get(t,e){if(e===Symbol.toPrimitive&&e in t)return t[Symbol.toPrimitive].bind(t);const n=super.get(t,e);return"object"==typeof n?this.cache(t,n):n}}const lt=new WeakMap;function pt(t){return lt.has(t)}function gt(t,e,r){return n(this,void 0,void 0,(function*(){if(!pt(t))throw new Error(`Not a known Decoy: ${t}`);const n=lt.get(t);if(null==r?void 0:r.length){const s=r.filter((e=>yt(t,e)));return yield Promise.all(s.map((r=>pt(t[r])?gt(t[r],e):e(n,{[r]:r})))),n.target}yield e(n);const{linked:s,target:i}=n;return yield Promise.all(s.map((t=>gt(t,e)))),i}))}function yt(t,...e){if(pt(t)){const{trap:n,linked:r}=lt.get(t);return e.length?e.some((e=>n.count({key:e})>0||pt(t[e])&&yt(t[e]))):n.count()>0||r.some((t=>yt(t)))}return!1}return t.checksum=function(t){return function(t,n="sha256",r="hex"){return a(e.createHash(s(n)),t).digest(i(r))}(t)},t.commit=function(t,...e){return gt(t,(({trap:t})=>t.commit()),e)},t.create=function t(e,n){const r=[],s=new ut((e=>r[r.push(t(e,n))-1]),n),i=new Proxy(e,s);return lt.set(i,{target:e,trap:s,linked:r}),i},t.hasMutations=yt,t.isDecoy=pt,t.purge=function(t){return gt(t,(e=>{lt.delete(t),e.linked.length=0}))},t.rollback=function(t,...e){return gt(t,(({trap:t})=>t.rollback()),e)},t}({},crypto);