@data-client/normalizr
Version:
Normalizes and denormalizes JSON according to schema for Redux and Flux applications
2 lines (1 loc) • 9.5 kB
JavaScript
const e=Symbol("INVALID");function t(e){return!("function"!=typeof e.hasOwnProperty||!(Object.hasOwnProperty.call(e,"__ownerID")||e._map&&Object.hasOwnProperty.call(e._map,"__ownerID")))}function n(e){return t(e)?({key:t,pk:n})=>e.getIn([t,n]):({key:t,pk:n})=>{var s;return null==(s=e[t])?void 0:s[n]}}class s{constructor(){this.localCache=new Map}getEntity(e,t,n,s){const r=t.key;this.localCache.has(r)||this.localCache.set(r,new Map);const i=this.localCache.get(r);return i.get(e)||s(i),i.get(e)}getResults(e,t,n){return{data:n(),paths:[]}}}const r={};function i(e){return null!==e&&void 0!==e.pk}const o=e=>{if("production"!==process.env.NODE_ENV){if(Array.isArray(e)&&e.length>1)throw new Error(`Expected schema definition to be a single schema, but found ${e.length}.`)}return e[0]},c=e=>void 0!==e&&"symbol"!=typeof e,a=(e,t,n,s,r,i,c,a,u)=>{e=o(e);const l=(e=>Array.isArray(e)?e:Object.keys(e).map((t=>e[t])))(t);return l.map(((t,o)=>i(e,t,n,s,r)))},u=(e,t,n,s)=>(e=o(e),t.map?t.map((t=>s(e,t))).filter(c):t);function l(e,t,n,s,r){}function h(){return h=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var s in n)({}).hasOwnProperty.call(n,s)&&(e[s]=n[s])}return e},h.apply(null,arguments)}const y=(e,t,n,s,r,i,o,c,a)=>{const u=h({},t);return Object.keys(e).forEach((n=>{const s=e[n],o=i(s,t[n],t,n,r);void 0===o?delete u[n]:u[n]=o})),u},p=(n,s,r,i)=>{if(t(s))return function(t,n,s,r){let i=!1;const o=Object.keys(t).reduce(((e,n)=>{const s=`${n}`,o=r(t[s],e.get(s));return"symbol"==typeof o&&(i=!0),e.has(s)?e.set(s,o):e}),n);return i?e:o}(n,s,0,i);const o=h({},s);let c=!1;return Object.keys(n).forEach((e=>{const t=i(n[e],o[e]);void 0!==o[e]&&(o[e]=t),"symbol"==typeof t&&(c=!0)})),c?e:o};function f(e,t,n,s,r){const i={};for(const o of Object.keys(e))i[o]=n(e[o],t,s,r);return i}function d(e,n,s,i,o,c){const a="object"==typeof n?n:o({key:e.key,pk:n});if("symbol"==typeof a&&"function"==typeof e.denormalize)return e.denormalize(a,s,i);if(void 0===a&&"object"!=typeof n&&""!==n&&"undefined"!==n)return c.getEntity(n,e,r,(e=>{e.set(n,void 0)}));if("object"!=typeof a||null===a)return a;let u="object"!=typeof n?n:e.pk(t(a)?a.toJS():a,void 0,void 0,s);return void 0===u||""===u||"undefined"===u?function(e){const t=new Map;return e(t),t.get("")}((t=>g(a,e,i,"",t,s))):("string"!=typeof u&&(u=`${u}`),c.getEntity(u,e,a,(t=>g(a,e,i,u,t,s))))}function g(n,s,r,i,o,c){const a=t(n)?s.createIfValid(n.toObject()):s.createIfValid(n);o.set(i,a),void 0===a?o.set(i,e):"function"==typeof s.denormalize&&o.set(i,s.denormalize(a,c,r))}const v=(e,t,n)=>{function s(r,o){if(!r)return o;if(null==o)return o;if("function"==typeof r.denormalize)return i(r)?d(r,o,n,s,e,t):r.denormalize(o,n,s);if("function"==typeof r)return r(o);if("object"==typeof r){return(Array.isArray(r)?u:p)(r,o,n,s)}return o}return(e,n)=>{const r=Object(n)===n&&Object(e)===e;return t.getResults(n,r,(()=>s(e,n)))}};function m(e,t,r,i=[]){return void 0===e||void 0===t?t:v(n(r),new s,i)(e,t).data}class b{constructor(){this.next=new WeakMap,this.nextPath=void 0}get(e,t){let n=this.next.get(e);if(!n)return w;for(;n.nextPath;){var s;const e=null!=(s=t(n.nextPath))?s:r;if(n=n.next.get(e),!n)return w}return[n.value,n.journey]}set(e,t){if(e.length<1)throw new k;let n=this;for(const{entity:t,path:s}of e){let e=n.next.get(t);e||(e=new x,n.next.set(null!=t?t:r,e)),n.nextPath=s,n=e}n.nextPath=void 0,n.value=t,n.journey=e.map((e=>e.path))}}const w=[void 0,void 0];class x{constructor(){this.next=new WeakMap,this.value=void 0,this.journey=[],this.nextPath=void 0}}class k extends Error{constructor(...e){super(...e),this.message="Keys must include at least one member"}}const j=(t,n,s,r,i,o)=>(c,a,u)=>{const l=c.key;t.has(l)||(t.set(l,new Map),s[l]=h({},s[l]),i[l]=h({},i[l]));const y=t.get(l),p=y.get(u);if(p)y.set(u,c.merge(p,a));else{const e=s[l][u];let t;e&&(t=i[l][u])?(y.set(u,c.mergeWithStore(t,o,e,a)),i[l][u]=c.mergeMetaWithStore(t,o,e,a)):(y.set(u,a),i[l][u]=o)}c.indexes&&(n.has(l)||(n.set(l,new Map),r[l]=h({},r[l])),function(t,n,s,r,i,o){for(const c of n){s.has(c)||s.set(c,r[c]={});const n=s.get(c);o[t]&&delete n[o[t][c]],o&&o[t]&&o[t][c]!==i[c]&&(n[o[t][c]]=e),c in i?n[i[c]]=t:"production"!==process.env.NODE_ENV&&console.warn(`Index not found in entity. Indexes must be top-level members of your entity.\nIndex: ${c}\nEntity: ${JSON.stringify(i,void 0,2)}`)}}(u,c.indexes,n.get(l),r[l],y.get(u),s[l])),s[l][u]=y.get(u)};const O=(e,t)=>{const n=function(){const e=new Map;return function(t,n,s){e.has(t)||e.set(t,new Map);const r=e.get(t);r.has(n)||r.set(n,[]);const i=r.get(n);return!!i.some((e=>e===s))||(i.push(s),!1)}}(),s=(r,i,o,c,u)=>{if(!i||!r)return i;if(r.normalize&&"function"==typeof r.normalize)return"object"!=typeof i?r.pk?`${i}`:i:r.normalize(i,o,c,u,s,e,t,n);if("object"!=typeof i||"object"!=typeof r)return i;return(Array.isArray(r)?a:y)(r,i,o,c,u,s)};return s};class E{constructor(e,t,n){this.dependencies=[],this.cycleCache=new Map,this.cycleIndex=-1,this.localCache=new Map,this._getEntity=e,this.getCache=M(t),this.resultCache=n}getEntity(e,t,n,s){const r=t.key,{localCacheKey:i,cycleCacheKey:o}=this.getCacheKey(r);if(i.get(e))o.has(e)?this.cycleIndex=o.get(e):this.dependencies.push({entity:n,path:{key:r,pk:e}});else{const c=this.getCache(e,t),[a,u]=c.get(n,this._getEntity);if(u)return i.set(e,a.value),this.dependencies.push(...a.dependencies),a.value;{const t=this.dependencies.length;o.set(e,t),this.dependencies.push({entity:n,path:{key:r,pk:e}}),s(i),o.delete(e);const a=this.dependencies.slice(-1===this.cycleIndex?t:this.cycleIndex),u={dependencies:a,value:i.get(e)};c.set(a,u),this.cycleIndex===t&&(this.cycleIndex=-1)}}return i.get(e)}getCacheKey(e){this.localCache.has(e)||this.localCache.set(e,new Map),this.cycleCache.has(e)||this.cycleCache.set(e,new Map);return{localCacheKey:this.localCache.get(e),cycleCacheKey:this.cycleCache.get(e)}}getResults(e,t,n){if(!t)return{data:n(),paths:this.paths()};let[s,r]=this.resultCache.get(e,this._getEntity);return void 0===r?(s=n(),r=this.paths(),this.dependencies.unshift({entity:e,path:{key:"",pk:""}}),this.resultCache.set(this.dependencies,s)):r.shift(),{data:s,paths:r}}paths(){return this.dependencies.map((e=>e.path))}}const M=e=>(t,n)=>{var s;const r=n.key,i=null!=(s=n.cacheWith)?s:n;e.has(r)||e.set(r,new Map);const o=e.get(r);o.get(t)||o.set(t,new WeakMap);const c=o.get(t);let a=c.get(i);return a||(a=new b,c.set(i,a)),a};function C(e,t,n,s){if(function(e){return!!e&&"function"==typeof e.queryKey}(e))return e.queryKey(t,C,n,s);if("object"==typeof e&&e){return(Array.isArray(e)?l:f)(e,t,C,n,s)}return e}function I(e){return void 0!==e&&(!(e&&"object"==typeof e&&!Array.isArray(e))||Object.values(e).every(I))}class S{constructor(){this.entities=new Map,this.endpoints=new b,this.queryKeys=new Map}denormalize(e,t,s,r=[]){if(void 0===e)return{data:t,paths:[]};if(void 0===t)return{data:void 0,paths:[]};const i=n(s);return v(i,new E(i,this.entities,this.endpoints),r)(e,t)}query(e,t,n,s,r=JSON.stringify(t)){const i=this.buildQueryKey(e,t,n,s,r);if(!i)return;const{data:o}=this.denormalize(e,i,n,t);return"symbol"==typeof o?void 0:o}buildQueryKey(e,n,s,r,i=JSON.stringify(n)){if("object"!=typeof e&&"function"!=typeof e.queryKey||!e)return e;this.queryKeys.get(i)||this.queryKeys.set(i,new b);const o=this.queryKeys.get(i),c=N(s),a=function(e){const n=t(e);return n?(t,n,s)=>{var r;return null==(r=e.getIn([t,n]))||null==r.toJS?void 0:r.toJS()}:(t,n,s)=>e[t]?e[t][n]:{}}(r);let[u,l]=o.get(e,function(e,t){return n=>3===n.length?t(...n):e(...n)}(c,a));if(!l){const t=[{path:[""],entity:e}];u=C(e,n,K(c,t),K(a,t)),o.set(t,u)}return u}}function K(e,t){return(...n)=>{const s=e(...n);return t.push({path:n,entity:s}),s}}function N(e){return t(e)?(...t)=>{var n;return null==(n=e.getIn(t))||null==n.toJS?void 0:n.toJS()}:(t,n)=>{var s;return n?null==(s=e[t])?void 0:s[n]:e[t]}}const A=(e,t,n=[],{entities:s,indexes:r,entityMeta:i}=z,o={fetchedAt:0,date:Date.now(),expiresAt:1/0})=>{if(null==e)return{result:t,entities:s,indexes:r,entityMeta:i};const c=function(e){return["object","function"].includes(typeof e)?"object":typeof e}(e);if(null===t||typeof t!==c&&(void 0===e.key||void 0!==e.pk||"string"!=typeof t)){if("production"!==process.env.NODE_ENV){const n=e=>{try{return"string"!=typeof JSON.parse(e)}catch(e){return!1}};throw"string"==typeof t&&n(t)?new Error(`Normalizing a string, but this does match schema.\n\nParsing this input string as JSON worked. This likely indicates fetch function did not parse\nthe JSON. By default, this only happens if "content-type" header includes "json".\nSee https://dataclient.io/rest/api/RestEndpoint#parseResponse for more information\n\n Schema: ${JSON.stringify(e,void 0,2)}\n Input: "${t}"`):new Error(`Unexpected input given to normalize. Expected type to be "${c}", found "${null===t?"null":typeof t}".\n\n Schema: ${JSON.stringify(e,void 0,2)}\n Input: "${t}"`)}throw new Error(`Unexpected input given to normalize. Expected type to be "${c}", found "${null===t?"null":typeof t}".`)}const a=new Map,u=new Map,l={result:"",entities:h({},s),indexes:h({},r),entityMeta:h({},i)},y=j(a,u,l.entities,l.indexes,l.entityMeta,o),p=O(y,N(s));return l.result=p(e,t,t,void 0,n),l};const z={entities:{},indexes:{},entityMeta:{}};var $={Invalid:1,InvalidIfStale:2,Valid:3};export{$ as ExpiryStatus,e as INVALID,S as MemoCache,b as WeakDependencyMap,m as denormalize,i as isEntity,A as normalize,I as validateQueryKey};