@konfirm/decoy
Version:
Proxy objects, keeping track of mutations to commit/rollback
2 lines (1 loc) • 11.8 kB
JavaScript
;var t=require("crypto");function e(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 n(t,...e){return n=>{if(e.includes(n))return n;throw new Error(`Unknown ${t}: "${n}"`)}}"function"==typeof SuppressedError&&SuppressedError;const r=n("algorithm",...t.getHashes()),s=n("digest","hex","base64"),i={array:(t,e)=>c(t,...e),object:(t,e)=>{return(n=e,[...new Set(o(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)=>c(c(t,n),e[n])),t);var n},null:t=>c(t,"NULL"),boolean:(t,e)=>t.update(e?"true":"false")};function o(t){const{constructor:{prototype:e}}=t,n=Object.getOwnPropertyDescriptors(e);return Object.keys(n)}function c(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 i?i[e]:(t,e)=>t.update(String(e))}(e);return n(t,e)}),t)}let a=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 u=new a({date:t=>t instanceof Date,regexp:t=>t instanceof RegExp,array:t=>Array.isArray(t),null:t=>null===t}),l=new class{constructor(t=new a,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"}}(u,{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 p 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=>l.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 g(t){return e=>typeof e===t}function y(...t){return e=>t.some((t=>t(e)))}function h(...t){return e=>t.every((t=>t(e)))}function f(...t){return e=>t.every((t=>!t(e)))}const m=t=>Array.isArray(t),d=g("function"),b=h(f(m),f((t=>null===t)),g("object")),v=g("string"),k=g("symbol"),w=g("undefined");function j(t){return h(b,(e=>t in e))}function O(t,...e){return h(j(t),(n=>e.every((e=>e(n[t])))))}function x(t,...e){return y(h(b,f(j(t))),O(t,...e))}function S(t,...e){const n=e.reduce(((t,e)=>t.concat(e)),[]),r=Object.keys(t).map((e=>(n.includes(e)?x:O)(e,t[e])));return h(b,...r)}const P=function(t,...e){const n=h(...e);class r extends p{}return e=>{try{if(!n(e))throw new r(t,e)}catch(n){throw new p(t,e,...n instanceof r||!(n instanceof p)?[]:[n])}return!0}}("Invalid MutationOptions",S({target:y(b,d,m),key:y(v,k),value:()=>!0},"value")),$=new WeakMap;class A{constructor(t){P(t),$.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}=$.get(this);return t}get key(){const{key:t}=$.get(this);return t}get value(){const{value:t}=$.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 A{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 D{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 M=new D({date:t=>t instanceof Date,regexp:t=>t instanceof RegExp,array:t=>Array.isArray(t),null:t=>null===t});function L(t){return e=>typeof e===t}function N(...t){return e=>t.some((t=>t(e)))}function U(...t){return e=>t.every((t=>t(e)))}function K(...t){return e=>t.every((t=>!t(e)))}new class{constructor(t=new D,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"}}(M,{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 _=L("boolean"),z=L("function"),W=U(K((t=>Array.isArray(t))),K((t=>null===t)),L("object")),C=L("undefined");function I(t){return U(W,(e=>t in e))}function R(t,...e){return U(I(t),(n=>e.every((e=>e(n[t])))))}function H(t,...e){return N(U(W,K(I(t))),R(t,...e))}function Z(t,...e){const n=e.reduce(((t,e)=>t.concat(e)),[]),r=Object.keys(t).map((e=>(n.includes(e)?H:R)(e,t[e])));return U(W,...r)}function q(t,...e){const n=Object.keys(t);return U(Z(t,...e),(t=>Object.keys(t).every((t=>n.includes(t)))))}const B={enumerable:_,configurable:_},F=q(B,Object.keys(B)),J={configurable:_,enumerable:_,get:z,set:z},G=q(J,...Object.keys(J).filter((t=>"get"!==t))),Q={configurable:_,enumerable:_,value:()=>!0,writable:_},T=N(F,q(Q,Object.keys(Q).filter((t=>"value"!==t))),G),V="value",X="get",Y="set",tt="writable";class et{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&&!C(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;X in e||Y in e?n=this.omit(n,V,tt):(V in e||tt in e)&&(n=this.omit(n,X,Y));const r=Object.assign({},n,e);return Y in r&&!(X in r)&&(r[X]=()=>{}),tt in r&&!(V in r)&&(r[V]=void 0),r}}class nt extends A{constructor(t){if(!w(t.value)&&!T(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 et.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 rt extends A{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 et.merge(r,{value:n})}apply(){const{target:t,key:e,value:n}=this;t[e]=n}}const st=new WeakMap;class it{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 st.has(t)||st.set(t,new it),st.get(t)}}class ot{constructor(t=!1){this.onlyLastKeyMutation=t,this.mutations=it.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 nt({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 nt&&!(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 rt({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);h(S(t,...e),(t=>Object.keys(t).every((t=>n.includes(t)))))}({name:v,target:y(b,d),key:y(v,k),value:()=>!0,descriptor:y(w,T),apply:d},["value"]);const ct=new WeakMap;class at extends ot{constructor(t,e=!1){super(e),ct.set(this,{delegate:t,cache:new WeakMap})}delegate(t){const{delegate:e}=ct.get(this),n=e(t);return Object.setPrototypeOf(n,Object.getPrototypeOf(t)),n}cache(t,e){const{cache:n}=ct.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 ut=new WeakMap;function lt(t){return ut.has(t)}function pt(t,n,r){return e(this,void 0,void 0,(function*(){if(!lt(t))throw new Error(`Not a known Decoy: ${t}`);const e=ut.get(t);if(null==r?void 0:r.length){const s=r.filter((e=>gt(t,e)));return yield Promise.all(s.map((r=>lt(t[r])?pt(t[r],n):n(e,{[r]:r})))),e.target}yield n(e);const{linked:s,target:i}=e;return yield Promise.all(s.map((t=>pt(t,n)))),i}))}function gt(t,...e){if(lt(t)){const{trap:n,linked:r}=ut.get(t);return e.length?e.some((e=>n.count({key:e})>0||lt(t[e])&>(t[e]))):n.count()>0||r.some((t=>gt(t)))}return!1}exports.checksum=function(e){return function(e,n="sha256",i="hex"){return c(t.createHash(r(n)),e).digest(s(i))}(e)},exports.commit=function(t,...e){return pt(t,(({trap:t})=>t.commit()),e)},exports.create=function t(e,n){const r=[],s=new at((e=>r[r.push(t(e,n))-1]),n),i=new Proxy(e,s);return ut.set(i,{target:e,trap:s,linked:r}),i},exports.hasMutations=gt,exports.isDecoy=lt,exports.purge=function(t){return pt(t,(e=>{ut.delete(t),e.linked.length=0}))},exports.rollback=function(t,...e){return pt(t,(({trap:t})=>t.rollback()),e)};