Comparing version 5.2.0 to 5.4.0
@@ -1,1 +0,750 @@ | ||
module.exports=function(e){function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var t={};return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n(n.s=0)}([function(e,n,t){"use strict";function r(e){if(Array.isArray(e)){for(var n=0,t=Array(e.length);n<e.length;n++)t[n]=e[n];return t}return Array.from(e)}function i(e,n){return f.isObject(e)&&"function"==typeof e.then&&(!n||"function"==typeof e.catch)}function c(e){return w.call(e).slice(8,-1)}function o(e,n){if(!e||"object"!==(void 0===e?"undefined":O(e)))return!1;var t=j(e);if(!t)return!1;var r=S.call(t,"constructor")&&t.constructor;return"function"!=typeof r?null===n:"function"==typeof r&&null!==n&&T.call(r)===T.call(n)}function u(e){return!(!e||"Object"!==c(e))&&(!j(e)||o(e,Object))}function a(e){if(!e||"Object"!==c(e))return!1;var n=j(e);return!n||(o(e,Object)||a(n))}function s(e){return e&&"object"===(void 0===e?"undefined":O(e))}function f(e){var n=[],t=[],c={},a=this.types={},p=this.stringify=function(n,t,r,i){i=Object.assign({},e,i,{stringification:!0});var c=j(n,null,i);return m(c)?JSON.stringify(c[0],t,r):c.then(function(e){return JSON.stringify(e,t,r)})};this.stringifySync=function(e,n,t,r){return p(e,n,t,Object.assign({},{throwOnBadSyncType:!0},r,{sync:!0}))},this.stringifyAsync=function(e,n,t,r){return p(e,n,t,Object.assign({},{throwOnBadSyncType:!0},r,{sync:!1}))};var w=this.parse=function(n,t,r){return r=Object.assign({},e,r,{parse:!0}),S(JSON.parse(n,t),r)};this.parseSync=function(e,n,t){return w(e,n,Object.assign({},{throwOnBadSyncType:!0},t,{sync:!0}))},this.parseAsync=function(e,n,t){return w(e,n,Object.assign({},{throwOnBadSyncType:!0},t,{sync:!1}))},this.specialTypeNames=function(e,n){var t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return t.returnTypeNames=!0,this.encapsulate(e,n,t)},this.rootTypeName=function(e,n){var t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return t.iterateNone=!0,this.encapsulate(e,n,t)};var j=this.encapsulate=function(i,a,y){function p(e){if(y.iterateNone){var n=Object.values(S);return n.length?n[0]:f.getJSONType(e)}var t=Object.values(S);if(t.length){if(y.returnTypeNames)return[].concat(r(new Set(t)));e&&u(e)&&!e.hasOwnProperty("$types")?e.$types=S:e={$:e,$types:{$:S}}}else s(e)&&e.hasOwnProperty("$types")&&(e={$:e,$types:!0});return!y.returnTypeNames&&e}function v(e,n){return Promise.all(n.map(function(e){return e[1].p})).then(function(t){return Promise.all(t.map(function(t){var r=[],i=n.splice(0,1)[0],c=b(i,7),u=c[0],a=c[2],s=c[3],f=c[4],y=c[5],l=c[6],p=d(u,t,a,s,r,!0,l),O=o(p,h);return u&&O?p.p.then(function(n){return f[y]=n,v(e,r)}):(u?f[y]=p:e=O?p.p:p,v(e,r))}))}).then(function(){return e})}function d(e,t,r,i,c,a,s){var p=void 0,v={},b=void 0===t?"undefined":O(t),j=$?function(n){var u=s||i.type||f.getJSONType(t);$(Object.assign(n||v,{keypath:e,value:t,cyclic:r,stateObj:i,promisesData:c,resolvingTypesonPromise:a,awaitingTypesonPromise:o(t,h)},void 0!==u?{type:u}:{}))}:null;if(b in{string:1,boolean:1,number:1,undefined:1})return void 0===t||"number"===b&&(isNaN(t)||t===-1/0||t===1/0)?(p=w(e,t,i,c,!1,a,j))!==t&&(v={replaced:p}):p=t,j&&j(),p;if(null===t)return j&&j(),t;if(r&&!i.iterateIn&&!i.iterateUnsetNumeric){var P=T.indexOf(t);if(!(P<0))return S[e]="#",j&&j({cyclicKeypath:A[P]}),"#"+A[P];!0===r&&(T.push(t),A.push(e))}var N=u(t),E=m(t),B=(N||E)&&(!n.length||i.replaced)||i.iterateIn?t:w(e,t,i,c,N||E,null,j),x=void 0;if(B!==t?(p=B,v={replaced:B}):E||"array"===i.iterateIn?(x=new Array(t.length),v={clone:x}):N||"object"===i.iterateIn?(x={},v={clone:x}):""===e&&o(t,h)?(c.push([e,t,r,i,void 0,void 0,i.type]),p=t):p=t,j&&j(),y.iterateNone)return x||p;if(!x)return p;if(i.iterateIn){for(var I in t){var J={ownKeys:t.hasOwnProperty(I)},K=e+(e?".":"")+l(I),k=d(K,t[I],!!r,J,c,a);o(k,h)?c.push([K,k,!!r,J,x,I,J.type]):void 0!==k&&(x[I]=k)}j&&j({endIterateIn:!0,end:!0})}else g(t).forEach(function(n){var i=e+(e?".":"")+l(n),u={ownKeys:!0},s=d(i,t[n],!!r,u,c,a);o(s,h)?c.push([i,s,!!r,u,x,n,u.type]):void 0!==s&&(x[n]=s)}),j&&j({endIterateOwn:!0,end:!0});if(i.iterateUnsetNumeric){for(var U=t.length,_=0;_<U;_++)if(!(_ in t)){var q=e+(e?".":"")+_,C={ownKeys:!1},D=d(q,void 0,!!r,C,c,a);o(D,h)?c.push([q,D,!!r,C,x,_,C.type]):void 0!==D&&(x[_]=D)}j&&j({endIterateUnsetNumeric:!0,end:!0})}return x}function w(e,r,i,o,u,a,s){for(var f=u?n:t,y=f.length;y--;){var l=f[y];if(l.test(r,i)){var p=l.type;if(c[p]){var v=S[e];S[e]=v?[p].concat(v):p}if(i=Object.assign(i,{type:p,replaced:!0}),(j||!l.replaceAsync)&&!l.replace)return s&&s({typeDetected:!0}),d(e,r,N&&"readonly",i,o,a,p);s&&s({replacing:!0});return d(e,l[j||!l.replaceAsync?"replace":"replaceAsync"](r,i),N&&"readonly",i,o,a,p)}}return r}y=Object.assign({sync:!0},e,y);var j=y.sync,S={},T=[],A=[],P=[],N=!(y&&"cyclic"in y)||y.cyclic,$=y.encapsulateObserver,E=d("",i,N,a||{},P);return P.length?j&&y.throwOnBadSyncType?function(){throw new TypeError("Sync method requested but async result obtained")}():Promise.resolve(v(E,P)).then(p):!j&&y.throwOnBadSyncType?function(){throw new TypeError("Async method requested but sync result obtained")}():y.stringification&&j?[p(E)]:j?p(E):Promise.resolve(p(E))};this.encapsulateSync=function(e,n,t){return j(e,n,Object.assign({},{throwOnBadSyncType:!0},t,{sync:!0}))},this.encapsulateAsync=function(e,n,t){return j(e,n,Object.assign({},{throwOnBadSyncType:!0},t,{sync:!1}))};var S=this.revive=function(n,t){function r(e,n,t,i,a,p){if(!f||"$types"!==e){var h=s[e];if(m(n)||u(n)){var O=m(n)?new Array(n.length):{};for(g(n).forEach(function(c){var u=r(e+(e?".":"")+l(c),n[c],t||O,i,O,c);o(u,d)?O[c]=void 0:void 0!==u&&(O[c]=u)}),n=O;y.length;){var w=b(y[0],4),j=w[0],S=w[1],T=w[2],A=w[3],P=v(j,S);if(o(P,d))T[A]=void 0;else{if(void 0===P)break;T[A]=P}y.splice(0,1)}}if(!h)return n;if("#"===h){var N=v(t,n.substr(1));return void 0===N&&y.push([t,n.substr(1),a,p]),N}var $=i.sync;return[].concat(h).reduce(function(e,n){var t=c[n];if(!t)throw new Error("Unregistered type: "+n);return t[$&&t.revive?"revive":!$&&t.reviveAsync?"reviveAsync":"revive"](e)},n)}}t=Object.assign({sync:!0},e,t);var a=t.sync,s=n&&n.$types,f=!0;if(!s)return n;if(!0===s)return n.$;s.$&&u(s.$)&&(n=n.$,s=s.$,f=!1);var y=[],p=r("",n,null,t);return p=o(p,d)?void 0:p,i(p)?a&&t.throwOnBadSyncType?function(){throw new TypeError("Sync method requested but async result obtained")}():p:!a&&t.throwOnBadSyncType?function(){throw new TypeError("Async method requested but sync result obtained")}():a?p:Promise.resolve(p)};this.reviveSync=function(e,n){return S(e,Object.assign({},{throwOnBadSyncType:!0},n,{sync:!0}))},this.reviveAsync=function(e,n){return S(e,Object.assign({},{throwOnBadSyncType:!0},n,{sync:!1}))},this.register=function(e,r){return r=r||{},[].concat(e).forEach(function e(i){if(m(i))return i.map(e);i&&g(i).forEach(function(e){if("#"===e)throw new TypeError("# cannot be used as a type name as it is reserved for cyclic objects");if(f.JSON_TYPES.includes(e))throw new TypeError("Plain JSON object types are reserved as type names");var o=i[e],u=o.testPlainObjects?n:t,s=u.filter(function(n){return n.type===e});if(s.length&&(u.splice(u.indexOf(s[0]),1),delete c[e],delete a[e]),o){if("function"==typeof o){var l=o;o={test:function(e){return e&&e.constructor===l},replace:function(e){return y({},e)},revive:function(e){return y(Object.create(l.prototype),e)}}}else m(o)&&(o={test:o[0],replace:o[1],revive:o[2]});var p={type:e,test:o.test.bind(o)};o.replace&&(p.replace=o.replace.bind(o)),o.replaceAsync&&(p.replaceAsync=o.replaceAsync.bind(o));var v="number"==typeof r.fallback?r.fallback:r.fallback?0:1/0;if(o.testPlainObjects?n.splice(v,0,p):t.splice(v,0,p),o.revive||o.reviveAsync){var d={};o.revive&&(d.revive=o.revive.bind(o)),o.reviveAsync&&(d.reviveAsync=o.reviveAsync.bind(o)),c[e]=d}a[e]=o}})}),this}}function y(e,n){return g(n).map(function(t){e[t]=n[t]}),e}function l(e){return e.replace(/~/g,"~0").replace(/\./g,"~1")}function p(e){return e.replace(/~1/g,".").replace(/~0/g,"~")}function v(e,n){if(""===n)return e;var t=n.indexOf(".");if(t>-1){var r=e[p(n.substr(0,t))];return void 0===r?void 0:v(r,n.substr(t+1))}return e[p(n)]}function d(){}function h(e){this.p=new Promise(e)}Object.defineProperty(n,"__esModule",{value:!0});var b=function(){function e(e,n){var t=[],r=!0,i=!1,c=void 0;try{for(var o,u=e[Symbol.iterator]();!(r=(o=u.next()).done)&&(t.push(o.value),!n||t.length!==n);r=!0);}catch(e){i=!0,c=e}finally{try{!r&&u.return&&u.return()}finally{if(i)throw c}}return t}return function(n,t){if(Array.isArray(n))return n;if(Symbol.iterator in Object(n))return e(n,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),O="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},g=Object.keys,m=Array.isArray,w={}.toString,j=Object.getPrototypeOf,S={}.hasOwnProperty,T=S.toString;h.prototype.then=function(e,n){var t=this;return new h(function(r,i){t.p.then(function(n){r(e?e(n):n)},function(e){t.p.catch(function(e){return n?n(e):Promise.reject(e)}).then(r,i)})})},h.prototype.catch=function(e){return this.then(null,e)},h.resolve=function(e){return new h(function(n){n(e)})},h.reject=function(e){return new h(function(n,t){t(e)})},["all","race"].map(function(e){h[e]=function(n){return new h(function(t,r){Promise[e](n.map(function(e){return e.p})).then(t,r)})}}),f.Undefined=d,f.Promise=h,f.isThenable=i,f.toStringTag=c,f.hasConstructorOf=o,f.isObject=s,f.isPlainObject=u,f.isUserObject=a,f.escapeKeyPathComponent=l,f.unescapeKeyPathComponent=p,f.getByKeyPath=v,f.getJSONType=function(e){return null===e?"null":m(e)?"array":void 0===e?"undefined":O(e)},f.JSON_TYPES=["null","boolean","number","string","array","object"],n.default=f,e.exports=n.default}]); | ||
'use strict'; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { | ||
return typeof obj; | ||
} : function (obj) { | ||
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; | ||
}; | ||
var slicedToArray = function () { | ||
function sliceIterator(arr, i) { | ||
var _arr = []; | ||
var _n = true; | ||
var _d = false; | ||
var _e = undefined; | ||
try { | ||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { | ||
_arr.push(_s.value); | ||
if (i && _arr.length === i) break; | ||
} | ||
} catch (err) { | ||
_d = true; | ||
_e = err; | ||
} finally { | ||
try { | ||
if (!_n && _i["return"]) _i["return"](); | ||
} finally { | ||
if (_d) throw _e; | ||
} | ||
} | ||
return _arr; | ||
} | ||
return function (arr, i) { | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} else if (Symbol.iterator in Object(arr)) { | ||
return sliceIterator(arr, i); | ||
} else { | ||
throw new TypeError("Invalid attempt to destructure non-iterable instance"); | ||
} | ||
}; | ||
}(); | ||
var toConsumableArray = function (arr) { | ||
if (Array.isArray(arr)) { | ||
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | ||
return arr2; | ||
} else { | ||
return Array.from(arr); | ||
} | ||
}; | ||
var keys = Object.keys; | ||
var isArray = Array.isArray; | ||
var toString = {}.toString; | ||
var getProto = Object.getPrototypeOf; | ||
var hasOwn = {}.hasOwnProperty; | ||
var fnToString = hasOwn.toString; | ||
function isThenable(v, catchCheck) { | ||
return Typeson.isObject(v) && typeof v.then === 'function' && (!catchCheck || typeof v.catch === 'function'); | ||
} | ||
function toStringTag(val) { | ||
return toString.call(val).slice(8, -1); | ||
} | ||
function hasConstructorOf(a, b) { | ||
if (!a || (typeof a === 'undefined' ? 'undefined' : _typeof(a)) !== 'object') { | ||
return false; | ||
} | ||
var proto = getProto(a); | ||
if (!proto) { | ||
return false; | ||
} | ||
var Ctor = hasOwn.call(proto, 'constructor') && proto.constructor; | ||
if (typeof Ctor !== 'function') { | ||
return b === null; | ||
} | ||
return typeof Ctor === 'function' && b !== null && fnToString.call(Ctor) === fnToString.call(b); | ||
} | ||
function isPlainObject(val) { | ||
// Mirrors jQuery's | ||
if (!val || toStringTag(val) !== 'Object') { | ||
return false; | ||
} | ||
var proto = getProto(val); | ||
if (!proto) { | ||
// `Object.create(null)` | ||
return true; | ||
} | ||
return hasConstructorOf(val, Object); | ||
} | ||
function isUserObject(val) { | ||
if (!val || toStringTag(val) !== 'Object') { | ||
return false; | ||
} | ||
var proto = getProto(val); | ||
if (!proto) { | ||
// `Object.create(null)` | ||
return true; | ||
} | ||
return hasConstructorOf(val, Object) || isUserObject(proto); | ||
} | ||
function isObject(v) { | ||
return v && (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object'; | ||
} | ||
/* Typeson - JSON with types | ||
* License: The MIT License (MIT) | ||
* Copyright (c) 2016 David Fahlander | ||
*/ | ||
/** An instance of this class can be used to call stringify() and parse(). | ||
* Typeson resolves cyclic references by default. Can also be extended to | ||
* support custom types using the register() method. | ||
* | ||
* @constructor | ||
* @param {{cyclic: boolean}} [options] - if cyclic (default true), cyclic references will be handled gracefully. | ||
*/ | ||
function Typeson(options) { | ||
// Replacers signature: replace (value). Returns falsy if not replacing. Otherwise ['Date', value.getTime()] | ||
var plainObjectReplacers = []; | ||
var nonplainObjectReplacers = []; | ||
// Revivers: map {type => reviver}. Sample: {'Date': value => new Date(value)} | ||
var revivers = {}; | ||
/** Types registered via register() */ | ||
var regTypes = this.types = {}; | ||
/** Serialize given object to Typeson. | ||
* | ||
* Arguments works identical to those of JSON.stringify(). | ||
*/ | ||
var stringify = this.stringify = function (obj, replacer, space, opts) { | ||
// replacer here has nothing to do with our replacers. | ||
opts = Object.assign({}, options, opts, { stringification: true }); | ||
var encapsulated = encapsulate(obj, null, opts); | ||
if (isArray(encapsulated)) { | ||
return JSON.stringify(encapsulated[0], replacer, space); | ||
} | ||
return encapsulated.then(function (res) { | ||
return JSON.stringify(res, replacer, space); | ||
}); | ||
}; | ||
// Also sync but throws on non-sync result | ||
this.stringifySync = function (obj, replacer, space, opts) { | ||
return stringify(obj, replacer, space, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: true })); | ||
}; | ||
this.stringifyAsync = function (obj, replacer, space, opts) { | ||
return stringify(obj, replacer, space, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: false })); | ||
}; | ||
/** Parse Typeson back into an obejct. | ||
* | ||
* Arguments works identical to those of JSON.parse(). | ||
*/ | ||
var parse = this.parse = function (text, reviver, opts) { | ||
opts = Object.assign({}, options, opts, { parse: true }); | ||
return revive(JSON.parse(text, reviver), opts); // This reviver has nothing to do with our revivers. | ||
}; | ||
// Also sync but throws on non-sync result | ||
this.parseSync = function (text, reviver, opts) { | ||
return parse(text, reviver, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: true })); // This reviver has nothing to do with our revivers. | ||
}; | ||
this.parseAsync = function (text, reviver, opts) { | ||
return parse(text, reviver, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: false })); // This reviver has nothing to do with our revivers. | ||
}; | ||
this.specialTypeNames = function (obj, stateObj) { | ||
var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
opts.returnTypeNames = true; | ||
return this.encapsulate(obj, stateObj, opts); | ||
}; | ||
this.rootTypeName = function (obj, stateObj) { | ||
var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
opts.iterateNone = true; | ||
return this.encapsulate(obj, stateObj, opts); | ||
}; | ||
/** Encapsulate a complex object into a plain Object by replacing registered types with | ||
* plain objects representing the types data. | ||
* | ||
* This method is used internally by Typeson.stringify(). | ||
* @param {Object} obj - Object to encapsulate. | ||
*/ | ||
var encapsulate = this.encapsulate = function (obj, stateObj, opts) { | ||
opts = Object.assign({ sync: true }, options, opts); | ||
var sync = opts.sync; | ||
var types = {}, | ||
refObjs = [], | ||
// For checking cyclic references | ||
refKeys = [], | ||
// For checking cyclic references | ||
promisesDataRoot = []; | ||
// Clone the object deeply while at the same time replacing any special types or cyclic reference: | ||
var cyclic = opts && 'cyclic' in opts ? opts.cyclic : true; | ||
var encapsulateObserver = opts.encapsulateObserver; | ||
var ret = _encapsulate('', obj, cyclic, stateObj || {}, promisesDataRoot); | ||
function finish(ret) { | ||
// Add $types to result only if we ever bumped into a special type (or special case where object has own `$types`) | ||
if (opts.iterateNone) { | ||
var _typeNames = Object.values(types); | ||
if (_typeNames.length) { | ||
return _typeNames[0]; | ||
} | ||
return Typeson.getJSONType(ret); | ||
} | ||
var typeNames = Object.values(types); | ||
if (typeNames.length) { | ||
if (opts.returnTypeNames) { | ||
return [].concat(toConsumableArray(new Set(typeNames))); | ||
} | ||
if (!ret || !isPlainObject(ret) || // Special if array (or a primitive) was serialized because JSON would ignore custom `$types` prop on it | ||
ret.hasOwnProperty('$types') // Also need to handle if this is an object with its own `$types` property (to avoid ambiguity) | ||
) { | ||
ret = { $: ret, $types: { $: types } }; | ||
} else { | ||
ret.$types = types; | ||
} | ||
} else if (isObject(ret) && ret.hasOwnProperty('$types')) { | ||
// No special types | ||
ret = { $: ret, $types: true }; | ||
} | ||
if (opts.returnTypeNames) { | ||
return false; | ||
} | ||
return ret; | ||
} | ||
function checkPromises(ret, promisesData) { | ||
return Promise.all(promisesData.map(function (pd) { | ||
return pd[1].p; | ||
})).then(function (promResults) { | ||
return Promise.all(promResults.map(function (promResult) { | ||
var newPromisesData = []; | ||
var prData = promisesData.splice(0, 1)[0]; | ||
var _prData = slicedToArray(prData, 7), | ||
keyPath = _prData[0], | ||
cyclic = _prData[2], | ||
stateObj = _prData[3], | ||
parentObj = _prData[4], | ||
key = _prData[5], | ||
detectedType = _prData[6]; | ||
var encaps = _encapsulate(keyPath, promResult, cyclic, stateObj, newPromisesData, true, detectedType); | ||
var isTypesonPromise = hasConstructorOf(encaps, TypesonPromise); | ||
if (keyPath && isTypesonPromise) { | ||
// Handle case where an embedded custom type itself returns a `Typeson.Promise` | ||
return encaps.p.then(function (encaps2) { | ||
parentObj[key] = encaps2; | ||
return checkPromises(ret, newPromisesData); | ||
}); | ||
} | ||
if (keyPath) parentObj[key] = encaps;else if (isTypesonPromise) { | ||
ret = encaps.p; | ||
} else ret = encaps; // If this is itself a `Typeson.Promise` (because the original value supplied was a promise or because the supplied custom type value resolved to one), returning it below will be fine since a promise is expected anyways given current config (and if not a promise, it will be ready as the resolve value) | ||
return checkPromises(ret, newPromisesData); | ||
})); | ||
}).then(function () { | ||
return ret; | ||
}); | ||
} | ||
return promisesDataRoot.length ? sync && opts.throwOnBadSyncType ? function () { | ||
throw new TypeError('Sync method requested but async result obtained'); | ||
}() : Promise.resolve(checkPromises(ret, promisesDataRoot)).then(finish) : !sync && opts.throwOnBadSyncType ? function () { | ||
throw new TypeError('Async method requested but sync result obtained'); | ||
}() : opts.stringification && sync // If this is a synchronous request for stringification, yet a promise is the result, we don't want to resolve leading to an async result, so we return an array to avoid ambiguity | ||
? [finish(ret)] : sync ? finish(ret) : Promise.resolve(finish(ret)); | ||
function _encapsulate(keypath, value, cyclic, stateObj, promisesData, resolvingTypesonPromise, detectedType) { | ||
var ret = void 0; | ||
var observerData = {}; | ||
var $typeof = typeof value === 'undefined' ? 'undefined' : _typeof(value); | ||
var runObserver = encapsulateObserver ? function (obj) { | ||
var type = detectedType || stateObj.type || Typeson.getJSONType(value); | ||
encapsulateObserver(Object.assign(obj || observerData, { | ||
keypath: keypath, | ||
value: value, | ||
cyclic: cyclic, | ||
stateObj: stateObj, | ||
promisesData: promisesData, | ||
resolvingTypesonPromise: resolvingTypesonPromise, | ||
awaitingTypesonPromise: hasConstructorOf(value, TypesonPromise) | ||
}, type !== undefined ? { type: type } : {})); | ||
} : null; | ||
if ($typeof in { string: 1, boolean: 1, number: 1, undefined: 1 }) { | ||
if (value === undefined || $typeof === 'number' && (isNaN(value) || value === -Infinity || value === Infinity)) { | ||
ret = replace(keypath, value, stateObj, promisesData, false, resolvingTypesonPromise, runObserver); | ||
if (ret !== value) { | ||
observerData = { replaced: ret }; | ||
} | ||
} else { | ||
ret = value; | ||
} | ||
if (runObserver) runObserver(); | ||
return ret; | ||
} | ||
if (value === null) { | ||
if (runObserver) runObserver(); | ||
return value; | ||
} | ||
if (cyclic && !stateObj.iterateIn && !stateObj.iterateUnsetNumeric) { | ||
// Options set to detect cyclic references and be able to rewrite them. | ||
var refIndex = refObjs.indexOf(value); | ||
if (refIndex < 0) { | ||
if (cyclic === true) { | ||
refObjs.push(value); | ||
refKeys.push(keypath); | ||
} | ||
} else { | ||
types[keypath] = '#'; | ||
if (runObserver) { | ||
runObserver({ | ||
cyclicKeypath: refKeys[refIndex] | ||
}); | ||
} | ||
return '#' + refKeys[refIndex]; | ||
} | ||
} | ||
var isPlainObj = isPlainObject(value); | ||
var isArr = isArray(value); | ||
var replaced = (isPlainObj || isArr) && (!plainObjectReplacers.length || stateObj.replaced) || stateObj.iterateIn // Running replace will cause infinite loop as will test positive again | ||
? | ||
// Optimization: if plain object and no plain-object replacers, don't try finding a replacer | ||
value : replace(keypath, value, stateObj, promisesData, isPlainObj || isArr, null, runObserver); | ||
var clone = void 0; | ||
if (replaced !== value) { | ||
ret = replaced; | ||
observerData = { replaced: replaced }; | ||
} else { | ||
if (isArr || stateObj.iterateIn === 'array') { | ||
clone = new Array(value.length); | ||
observerData = { clone: clone }; | ||
} else if (isPlainObj || stateObj.iterateIn === 'object') { | ||
clone = {}; | ||
observerData = { clone: clone }; | ||
} else if (keypath === '' && hasConstructorOf(value, TypesonPromise)) { | ||
promisesData.push([keypath, value, cyclic, stateObj, undefined, undefined, stateObj.type]); | ||
ret = value; | ||
} else { | ||
ret = value; // Only clone vanilla objects and arrays | ||
} | ||
} | ||
if (runObserver) runObserver(); | ||
if (opts.iterateNone) { | ||
return clone || ret; | ||
} | ||
if (!clone) { | ||
return ret; | ||
} | ||
// Iterate object or array | ||
if (stateObj.iterateIn) { | ||
for (var key in value) { | ||
var ownKeysObj = { ownKeys: value.hasOwnProperty(key) }; | ||
var kp = keypath + (keypath ? '.' : '') + escapeKeyPathComponent(key); | ||
var val = _encapsulate(kp, value[key], !!cyclic, ownKeysObj, promisesData, resolvingTypesonPromise); | ||
if (hasConstructorOf(val, TypesonPromise)) { | ||
promisesData.push([kp, val, !!cyclic, ownKeysObj, clone, key, ownKeysObj.type]); | ||
} else if (val !== undefined) clone[key] = val; | ||
} | ||
if (runObserver) runObserver({ endIterateIn: true, end: true }); | ||
} else { | ||
// Note: Non-indexes on arrays won't survive stringify so somewhat wasteful for arrays, but so too is iterating all numeric indexes on sparse arrays when not wanted or filtering own keys for positive integers | ||
keys(value).forEach(function (key) { | ||
var kp = keypath + (keypath ? '.' : '') + escapeKeyPathComponent(key); | ||
var ownKeysObj = { ownKeys: true }; | ||
var val = _encapsulate(kp, value[key], !!cyclic, ownKeysObj, promisesData, resolvingTypesonPromise); | ||
if (hasConstructorOf(val, TypesonPromise)) { | ||
promisesData.push([kp, val, !!cyclic, ownKeysObj, clone, key, ownKeysObj.type]); | ||
} else if (val !== undefined) clone[key] = val; | ||
}); | ||
if (runObserver) runObserver({ endIterateOwn: true, end: true }); | ||
} | ||
// Iterate array for non-own numeric properties (we can't replace the prior loop though as it iterates non-integer keys) | ||
if (stateObj.iterateUnsetNumeric) { | ||
var vl = value.length; | ||
for (var i = 0; i < vl; i++) { | ||
if (!(i in value)) { | ||
var _kp = keypath + (keypath ? '.' : '') + i; // No need to escape numeric | ||
var _ownKeysObj = { ownKeys: false }; | ||
var _val = _encapsulate(_kp, undefined, !!cyclic, _ownKeysObj, promisesData, resolvingTypesonPromise); | ||
if (hasConstructorOf(_val, TypesonPromise)) { | ||
promisesData.push([_kp, _val, !!cyclic, _ownKeysObj, clone, i, _ownKeysObj.type]); | ||
} else if (_val !== undefined) clone[i] = _val; | ||
} | ||
} | ||
if (runObserver) runObserver({ endIterateUnsetNumeric: true, end: true }); | ||
} | ||
return clone; | ||
} | ||
function replace(keypath, value, stateObj, promisesData, plainObject, resolvingTypesonPromise, runObserver) { | ||
// Encapsulate registered types | ||
var replacers = plainObject ? plainObjectReplacers : nonplainObjectReplacers; | ||
var i = replacers.length; | ||
while (i--) { | ||
var replacer = replacers[i]; | ||
if (replacer.test(value, stateObj)) { | ||
var type = replacer.type; | ||
if (revivers[type]) { | ||
// Record the type only if a corresponding reviver exists. | ||
// This is to support specs where only replacement is done. | ||
// For example ensuring deep cloning of the object, or | ||
// replacing a type to its equivalent without the need to revive it. | ||
var existing = types[keypath]; | ||
// type can comprise an array of types (see test shouldSupportIntermediateTypes) | ||
types[keypath] = existing ? [type].concat(existing) : type; | ||
} | ||
// Now, also traverse the result in case it contains its own types to replace | ||
stateObj = Object.assign(stateObj, { type: type, replaced: true }); | ||
if ((sync || !replacer.replaceAsync) && !replacer.replace) { | ||
if (runObserver) runObserver({ typeDetected: true }); | ||
return _encapsulate(keypath, value, cyclic && 'readonly', stateObj, promisesData, resolvingTypesonPromise, type); | ||
} | ||
if (runObserver) runObserver({ replacing: true }); | ||
var replaceMethod = sync || !replacer.replaceAsync ? 'replace' : 'replaceAsync'; | ||
return _encapsulate(keypath, replacer[replaceMethod](value, stateObj), cyclic && 'readonly', stateObj, promisesData, resolvingTypesonPromise, type); | ||
} | ||
} | ||
return value; | ||
} | ||
}; | ||
// Also sync but throws on non-sync result | ||
this.encapsulateSync = function (obj, stateObj, opts) { | ||
return encapsulate(obj, stateObj, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: true })); | ||
}; | ||
this.encapsulateAsync = function (obj, stateObj, opts) { | ||
return encapsulate(obj, stateObj, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: false })); | ||
}; | ||
/** Revive an encapsulated object. | ||
* This method is used internally by Typeson.parse(). | ||
* @param {Object} obj - Object to revive. If it has $types member, the properties that are listed there | ||
* will be replaced with its true type instead of just plain objects. | ||
*/ | ||
var revive = this.revive = function (obj, opts) { | ||
opts = Object.assign({ sync: true }, options, opts); | ||
var sync = opts.sync; | ||
var types = obj && obj.$types, | ||
ignore$Types = true; | ||
if (!types) return obj; // No type info added. Revival not needed. | ||
if (types === true) return obj.$; // Object happened to have own `$types` property but with no actual types, so we unescape and return that object | ||
if (types.$ && isPlainObject(types.$)) { | ||
// Special when root object is not a trivial Object, it will be encapsulated in $. It will also be encapsulated in $ if it has its own `$` property to avoid ambiguity | ||
obj = obj.$; | ||
types = types.$; | ||
ignore$Types = false; | ||
} | ||
var keyPathResolutions = []; | ||
var ret = _revive('', obj, null, opts); | ||
ret = hasConstructorOf(ret, Undefined) ? undefined : ret; | ||
return isThenable(ret) ? sync && opts.throwOnBadSyncType ? function () { | ||
throw new TypeError('Sync method requested but async result obtained'); | ||
}() : ret : !sync && opts.throwOnBadSyncType ? function () { | ||
throw new TypeError('Async method requested but sync result obtained'); | ||
}() : sync ? ret : Promise.resolve(ret); | ||
function _revive(keypath, value, target, opts, clone, key) { | ||
if (ignore$Types && keypath === '$types') return; | ||
var type = types[keypath]; | ||
if (isArray(value) || isPlainObject(value)) { | ||
var _clone = isArray(value) ? new Array(value.length) : {}; | ||
// Iterate object or array | ||
keys(value).forEach(function (key) { | ||
var val = _revive(keypath + (keypath ? '.' : '') + escapeKeyPathComponent(key), value[key], target || _clone, opts, _clone, key); | ||
if (hasConstructorOf(val, Undefined)) _clone[key] = undefined;else if (val !== undefined) _clone[key] = val; | ||
}); | ||
value = _clone; | ||
while (keyPathResolutions.length) { | ||
// Try to resolve cyclic reference as soon as available | ||
var _keyPathResolutions$ = slicedToArray(keyPathResolutions[0], 4), | ||
_target = _keyPathResolutions$[0], | ||
keyPath = _keyPathResolutions$[1], | ||
_clone2 = _keyPathResolutions$[2], | ||
_key = _keyPathResolutions$[3]; | ||
var val = getByKeyPath(_target, keyPath); | ||
if (hasConstructorOf(val, Undefined)) _clone2[_key] = undefined;else if (val !== undefined) _clone2[_key] = val;else break; | ||
keyPathResolutions.splice(0, 1); | ||
} | ||
} | ||
if (!type) return value; | ||
if (type === '#') { | ||
var _ret = getByKeyPath(target, value.substr(1)); | ||
if (_ret === undefined) { | ||
// Cyclic reference not yet available | ||
keyPathResolutions.push([target, value.substr(1), clone, key]); | ||
} | ||
return _ret; | ||
} | ||
var sync = opts.sync; | ||
return [].concat(type).reduce(function (val, type) { | ||
var reviver = revivers[type]; | ||
if (!reviver) throw new Error('Unregistered type: ' + type); | ||
return reviver[// eslint-disable-line standard/computed-property-even-spacing | ||
sync && reviver.revive ? 'revive' : !sync && reviver.reviveAsync ? 'reviveAsync' : 'revive'](val); | ||
}, value); | ||
} | ||
}; | ||
// Also sync but throws on non-sync result | ||
this.reviveSync = function (obj, opts) { | ||
return revive(obj, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: true })); | ||
}; | ||
this.reviveAsync = function (obj, opts) { | ||
return revive(obj, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: false })); | ||
}; | ||
/** Register types. | ||
* For examples how to use this method, see https://github.com/dfahlander/typeson-registry/tree/master/types | ||
* @param {Array.<Object.<string,Function[]>>} typeSpec - Types and their functions [test, encapsulate, revive]; | ||
*/ | ||
this.register = function (typeSpecSets, opts) { | ||
opts = opts || {}; | ||
[].concat(typeSpecSets).forEach(function R(typeSpec) { | ||
if (isArray(typeSpec)) return typeSpec.map(R); // Allow arrays of arrays of arrays... | ||
typeSpec && keys(typeSpec).forEach(function (typeId) { | ||
if (typeId === '#') { | ||
throw new TypeError('# cannot be used as a type name as it is reserved for cyclic objects'); | ||
} else if (Typeson.JSON_TYPES.includes(typeId)) { | ||
throw new TypeError('Plain JSON object types are reserved as type names'); | ||
} | ||
var spec = typeSpec[typeId]; | ||
var replacers = spec.testPlainObjects ? plainObjectReplacers : nonplainObjectReplacers; | ||
var existingReplacer = replacers.filter(function (r) { | ||
return r.type === typeId; | ||
}); | ||
if (existingReplacer.length) { | ||
// Remove existing spec and replace with this one. | ||
replacers.splice(replacers.indexOf(existingReplacer[0]), 1); | ||
delete revivers[typeId]; | ||
delete regTypes[typeId]; | ||
} | ||
if (spec) { | ||
if (typeof spec === 'function') { | ||
// Support registering just a class without replacer/reviver | ||
var Class = spec; | ||
spec = { | ||
test: function test(x) { | ||
return x && x.constructor === Class; | ||
}, | ||
replace: function replace(x) { | ||
return assign({}, x); | ||
}, | ||
revive: function revive(x) { | ||
return assign(Object.create(Class.prototype), x); | ||
} | ||
}; | ||
} else if (isArray(spec)) { | ||
spec = { | ||
test: spec[0], | ||
replace: spec[1], | ||
revive: spec[2] | ||
}; | ||
} | ||
var replacerObj = { | ||
type: typeId, | ||
test: spec.test.bind(spec) | ||
}; | ||
if (spec.replace) { | ||
replacerObj.replace = spec.replace.bind(spec); | ||
} | ||
if (spec.replaceAsync) { | ||
replacerObj.replaceAsync = spec.replaceAsync.bind(spec); | ||
} | ||
var start = typeof opts.fallback === 'number' ? opts.fallback : opts.fallback ? 0 : Infinity; | ||
if (spec.testPlainObjects) { | ||
plainObjectReplacers.splice(start, 0, replacerObj); | ||
} else { | ||
nonplainObjectReplacers.splice(start, 0, replacerObj); | ||
} | ||
// Todo: We might consider a testAsync type | ||
if (spec.revive || spec.reviveAsync) { | ||
var reviverObj = {}; | ||
if (spec.revive) reviverObj.revive = spec.revive.bind(spec); | ||
if (spec.reviveAsync) reviverObj.reviveAsync = spec.reviveAsync.bind(spec); | ||
revivers[typeId] = reviverObj; | ||
} | ||
regTypes[typeId] = spec; // Record to be retrieved via public types property. | ||
} | ||
}); | ||
}); | ||
return this; | ||
}; | ||
} | ||
function assign(t, s) { | ||
keys(s).map(function (k) { | ||
t[k] = s[k]; | ||
}); | ||
return t; | ||
} | ||
/** escapeKeyPathComponent() utility */ | ||
function escapeKeyPathComponent(keyPathComponent) { | ||
return keyPathComponent.replace(/~/g, '~0').replace(/\./g, '~1'); | ||
} | ||
/** unescapeKeyPathComponent() utility */ | ||
function unescapeKeyPathComponent(keyPathComponent) { | ||
return keyPathComponent.replace(/~1/g, '.').replace(/~0/g, '~'); | ||
} | ||
/** getByKeyPath() utility */ | ||
function getByKeyPath(obj, keyPath) { | ||
if (keyPath === '') return obj; | ||
var period = keyPath.indexOf('.'); | ||
if (period > -1) { | ||
var innerObj = obj[unescapeKeyPathComponent(keyPath.substr(0, period))]; | ||
return innerObj === undefined ? undefined : getByKeyPath(innerObj, keyPath.substr(period + 1)); | ||
} | ||
return obj[unescapeKeyPathComponent(keyPath)]; | ||
} | ||
function Undefined() {} | ||
// With ES6 classes, we may be able to simply use `class TypesonPromise extends Promise` and add a string tag for detection | ||
function TypesonPromise(f) { | ||
this.p = new Promise(f); | ||
} | ||
TypesonPromise.prototype.then = function (onFulfilled, onRejected) { | ||
var _this = this; | ||
return new TypesonPromise(function (typesonResolve, typesonReject) { | ||
_this.p.then(function (res) { | ||
typesonResolve(onFulfilled ? onFulfilled(res) : res); | ||
}, function (r) { | ||
_this.p['catch'](function (res) { | ||
return onRejected ? onRejected(res) : Promise.reject(res); | ||
}).then(typesonResolve, typesonReject); | ||
}); | ||
}); | ||
}; | ||
TypesonPromise.prototype['catch'] = function (onRejected) { | ||
return this.then(null, onRejected); | ||
}; | ||
TypesonPromise.resolve = function (v) { | ||
return new TypesonPromise(function (typesonResolve) { | ||
typesonResolve(v); | ||
}); | ||
}; | ||
TypesonPromise.reject = function (v) { | ||
return new TypesonPromise(function (typesonResolve, typesonReject) { | ||
typesonReject(v); | ||
}); | ||
}; | ||
['all', 'race'].map(function (meth) { | ||
TypesonPromise[meth] = function (promArr) { | ||
return new TypesonPromise(function (typesonResolve, typesonReject) { | ||
Promise[meth](promArr.map(function (prom) { | ||
return prom.p; | ||
})).then(typesonResolve, typesonReject); | ||
}); | ||
}; | ||
}); | ||
// The following provide classes meant to avoid clashes with other values | ||
Typeson.Undefined = Undefined; // To insist `undefined` should be added | ||
Typeson.Promise = TypesonPromise; // To support async encapsulation/stringification | ||
// Some fundamental type-checking utilities | ||
Typeson.isThenable = isThenable; | ||
Typeson.toStringTag = toStringTag; | ||
Typeson.hasConstructorOf = hasConstructorOf; | ||
Typeson.isObject = isObject; | ||
Typeson.isPlainObject = isPlainObject; | ||
Typeson.isUserObject = isUserObject; | ||
Typeson.escapeKeyPathComponent = escapeKeyPathComponent; | ||
Typeson.unescapeKeyPathComponent = unescapeKeyPathComponent; | ||
Typeson.getByKeyPath = getByKeyPath; | ||
Typeson.getJSONType = function (value) { | ||
return value === null ? 'null' : isArray(value) ? 'array' : typeof value === 'undefined' ? 'undefined' : _typeof(value); | ||
}; | ||
Typeson.JSON_TYPES = ['null', 'boolean', 'number', 'string', 'array', 'object']; | ||
module.exports = Typeson; |
@@ -1,1 +0,756 @@ | ||
!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.Typeson=n():e.Typeson=n()}("undefined"!=typeof self?self:this,function(){return function(e){function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var t={};return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n(n.s=0)}([function(e,n,t){"use strict";function r(e){if(Array.isArray(e)){for(var n=0,t=Array(e.length);n<e.length;n++)t[n]=e[n];return t}return Array.from(e)}function i(e,n){return f.isObject(e)&&"function"==typeof e.then&&(!n||"function"==typeof e.catch)}function o(e){return w.call(e).slice(8,-1)}function c(e,n){if(!e||"object"!==(void 0===e?"undefined":O(e)))return!1;var t=j(e);if(!t)return!1;var r=S.call(t,"constructor")&&t.constructor;return"function"!=typeof r?null===n:"function"==typeof r&&null!==n&&T.call(r)===T.call(n)}function u(e){return!(!e||"Object"!==o(e))&&(!j(e)||c(e,Object))}function a(e){if(!e||"Object"!==o(e))return!1;var n=j(e);return!n||(c(e,Object)||a(n))}function s(e){return e&&"object"===(void 0===e?"undefined":O(e))}function f(e){var n=[],t=[],o={},a=this.types={},l=this.stringify=function(n,t,r,i){i=Object.assign({},e,i,{stringification:!0});var o=j(n,null,i);return m(o)?JSON.stringify(o[0],t,r):o.then(function(e){return JSON.stringify(e,t,r)})};this.stringifySync=function(e,n,t,r){return l(e,n,t,Object.assign({},{throwOnBadSyncType:!0},r,{sync:!0}))},this.stringifyAsync=function(e,n,t,r){return l(e,n,t,Object.assign({},{throwOnBadSyncType:!0},r,{sync:!1}))};var w=this.parse=function(n,t,r){return r=Object.assign({},e,r,{parse:!0}),S(JSON.parse(n,t),r)};this.parseSync=function(e,n,t){return w(e,n,Object.assign({},{throwOnBadSyncType:!0},t,{sync:!0}))},this.parseAsync=function(e,n,t){return w(e,n,Object.assign({},{throwOnBadSyncType:!0},t,{sync:!1}))},this.specialTypeNames=function(e,n){var t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return t.returnTypeNames=!0,this.encapsulate(e,n,t)},this.rootTypeName=function(e,n){var t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return t.iterateNone=!0,this.encapsulate(e,n,t)};var j=this.encapsulate=function(i,a,y){function l(e){if(y.iterateNone){var n=Object.values(S);return n.length?n[0]:f.getJSONType(e)}var t=Object.values(S);if(t.length){if(y.returnTypeNames)return[].concat(r(new Set(t)));e&&u(e)&&!e.hasOwnProperty("$types")?e.$types=S:e={$:e,$types:{$:S}}}else s(e)&&e.hasOwnProperty("$types")&&(e={$:e,$types:!0});return!y.returnTypeNames&&e}function v(e,n){return Promise.all(n.map(function(e){return e[1].p})).then(function(t){return Promise.all(t.map(function(t){var r=[],i=n.splice(0,1)[0],o=b(i,7),u=o[0],a=o[2],s=o[3],f=o[4],y=o[5],p=o[6],l=d(u,t,a,s,r,!0,p),O=c(l,h);return u&&O?l.p.then(function(n){return f[y]=n,v(e,r)}):(u?f[y]=l:e=O?l.p:l,v(e,r))}))}).then(function(){return e})}function d(e,t,r,i,o,a,s){var l=void 0,v={},b=void 0===t?"undefined":O(t),j=$?function(n){var u=s||i.type||f.getJSONType(t);$(Object.assign(n||v,{keypath:e,value:t,cyclic:r,stateObj:i,promisesData:o,resolvingTypesonPromise:a,awaitingTypesonPromise:c(t,h)},void 0!==u?{type:u}:{}))}:null;if(b in{string:1,boolean:1,number:1,undefined:1})return void 0===t||"number"===b&&(isNaN(t)||t===-1/0||t===1/0)?(l=w(e,t,i,o,!1,a,j))!==t&&(v={replaced:l}):l=t,j&&j(),l;if(null===t)return j&&j(),t;if(r&&!i.iterateIn&&!i.iterateUnsetNumeric){var P=T.indexOf(t);if(!(P<0))return S[e]="#",j&&j({cyclicKeypath:A[P]}),"#"+A[P];!0===r&&(T.push(t),A.push(e))}var N=u(t),x=m(t),E=(N||x)&&(!n.length||i.replaced)||i.iterateIn?t:w(e,t,i,o,N||x,null,j),B=void 0;if(E!==t?(l=E,v={replaced:E}):x||"array"===i.iterateIn?(B=new Array(t.length),v={clone:B}):N||"object"===i.iterateIn?(B={},v={clone:B}):""===e&&c(t,h)?(o.push([e,t,r,i,void 0,void 0,i.type]),l=t):l=t,j&&j(),y.iterateNone)return B||l;if(!B)return l;if(i.iterateIn){for(var I in t){var J={ownKeys:t.hasOwnProperty(I)},K=e+(e?".":"")+p(I),k=d(K,t[I],!!r,J,o,a);c(k,h)?o.push([K,k,!!r,J,B,I,J.type]):void 0!==k&&(B[I]=k)}j&&j({endIterateIn:!0,end:!0})}else g(t).forEach(function(n){var i=e+(e?".":"")+p(n),u={ownKeys:!0},s=d(i,t[n],!!r,u,o,a);c(s,h)?o.push([i,s,!!r,u,B,n,u.type]):void 0!==s&&(B[n]=s)}),j&&j({endIterateOwn:!0,end:!0});if(i.iterateUnsetNumeric){for(var U=t.length,_=0;_<U;_++)if(!(_ in t)){var q=e+(e?".":"")+_,C={ownKeys:!1},D=d(q,void 0,!!r,C,o,a);c(D,h)?o.push([q,D,!!r,C,B,_,C.type]):void 0!==D&&(B[_]=D)}j&&j({endIterateUnsetNumeric:!0,end:!0})}return B}function w(e,r,i,c,u,a,s){for(var f=u?n:t,y=f.length;y--;){var p=f[y];if(p.test(r,i)){var l=p.type;if(o[l]){var v=S[e];S[e]=v?[l].concat(v):l}if(i=Object.assign(i,{type:l,replaced:!0}),(j||!p.replaceAsync)&&!p.replace)return s&&s({typeDetected:!0}),d(e,r,N&&"readonly",i,c,a,l);s&&s({replacing:!0});return d(e,p[j||!p.replaceAsync?"replace":"replaceAsync"](r,i),N&&"readonly",i,c,a,l)}}return r}y=Object.assign({sync:!0},e,y);var j=y.sync,S={},T=[],A=[],P=[],N=!(y&&"cyclic"in y)||y.cyclic,$=y.encapsulateObserver,x=d("",i,N,a||{},P);return P.length?j&&y.throwOnBadSyncType?function(){throw new TypeError("Sync method requested but async result obtained")}():Promise.resolve(v(x,P)).then(l):!j&&y.throwOnBadSyncType?function(){throw new TypeError("Async method requested but sync result obtained")}():y.stringification&&j?[l(x)]:j?l(x):Promise.resolve(l(x))};this.encapsulateSync=function(e,n,t){return j(e,n,Object.assign({},{throwOnBadSyncType:!0},t,{sync:!0}))},this.encapsulateAsync=function(e,n,t){return j(e,n,Object.assign({},{throwOnBadSyncType:!0},t,{sync:!1}))};var S=this.revive=function(n,t){function r(e,n,t,i,a,l){if(!f||"$types"!==e){var h=s[e];if(m(n)||u(n)){var O=m(n)?new Array(n.length):{};for(g(n).forEach(function(o){var u=r(e+(e?".":"")+p(o),n[o],t||O,i,O,o);c(u,d)?O[o]=void 0:void 0!==u&&(O[o]=u)}),n=O;y.length;){var w=b(y[0],4),j=w[0],S=w[1],T=w[2],A=w[3],P=v(j,S);if(c(P,d))T[A]=void 0;else{if(void 0===P)break;T[A]=P}y.splice(0,1)}}if(!h)return n;if("#"===h){var N=v(t,n.substr(1));return void 0===N&&y.push([t,n.substr(1),a,l]),N}var $=i.sync;return[].concat(h).reduce(function(e,n){var t=o[n];if(!t)throw new Error("Unregistered type: "+n);return t[$&&t.revive?"revive":!$&&t.reviveAsync?"reviveAsync":"revive"](e)},n)}}t=Object.assign({sync:!0},e,t);var a=t.sync,s=n&&n.$types,f=!0;if(!s)return n;if(!0===s)return n.$;s.$&&u(s.$)&&(n=n.$,s=s.$,f=!1);var y=[],l=r("",n,null,t);return l=c(l,d)?void 0:l,i(l)?a&&t.throwOnBadSyncType?function(){throw new TypeError("Sync method requested but async result obtained")}():l:!a&&t.throwOnBadSyncType?function(){throw new TypeError("Async method requested but sync result obtained")}():a?l:Promise.resolve(l)};this.reviveSync=function(e,n){return S(e,Object.assign({},{throwOnBadSyncType:!0},n,{sync:!0}))},this.reviveAsync=function(e,n){return S(e,Object.assign({},{throwOnBadSyncType:!0},n,{sync:!1}))},this.register=function(e,r){return r=r||{},[].concat(e).forEach(function e(i){if(m(i))return i.map(e);i&&g(i).forEach(function(e){if("#"===e)throw new TypeError("# cannot be used as a type name as it is reserved for cyclic objects");if(f.JSON_TYPES.includes(e))throw new TypeError("Plain JSON object types are reserved as type names");var c=i[e],u=c.testPlainObjects?n:t,s=u.filter(function(n){return n.type===e});if(s.length&&(u.splice(u.indexOf(s[0]),1),delete o[e],delete a[e]),c){if("function"==typeof c){var p=c;c={test:function(e){return e&&e.constructor===p},replace:function(e){return y({},e)},revive:function(e){return y(Object.create(p.prototype),e)}}}else m(c)&&(c={test:c[0],replace:c[1],revive:c[2]});var l={type:e,test:c.test.bind(c)};c.replace&&(l.replace=c.replace.bind(c)),c.replaceAsync&&(l.replaceAsync=c.replaceAsync.bind(c));var v="number"==typeof r.fallback?r.fallback:r.fallback?0:1/0;if(c.testPlainObjects?n.splice(v,0,l):t.splice(v,0,l),c.revive||c.reviveAsync){var d={};c.revive&&(d.revive=c.revive.bind(c)),c.reviveAsync&&(d.reviveAsync=c.reviveAsync.bind(c)),o[e]=d}a[e]=c}})}),this}}function y(e,n){return g(n).map(function(t){e[t]=n[t]}),e}function p(e){return e.replace(/~/g,"~0").replace(/\./g,"~1")}function l(e){return e.replace(/~1/g,".").replace(/~0/g,"~")}function v(e,n){if(""===n)return e;var t=n.indexOf(".");if(t>-1){var r=e[l(n.substr(0,t))];return void 0===r?void 0:v(r,n.substr(t+1))}return e[l(n)]}function d(){}function h(e){this.p=new Promise(e)}Object.defineProperty(n,"__esModule",{value:!0});var b=function(){function e(e,n){var t=[],r=!0,i=!1,o=void 0;try{for(var c,u=e[Symbol.iterator]();!(r=(c=u.next()).done)&&(t.push(c.value),!n||t.length!==n);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&u.return&&u.return()}finally{if(i)throw o}}return t}return function(n,t){if(Array.isArray(n))return n;if(Symbol.iterator in Object(n))return e(n,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),O="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},g=Object.keys,m=Array.isArray,w={}.toString,j=Object.getPrototypeOf,S={}.hasOwnProperty,T=S.toString;h.prototype.then=function(e,n){var t=this;return new h(function(r,i){t.p.then(function(n){r(e?e(n):n)},function(e){t.p.catch(function(e){return n?n(e):Promise.reject(e)}).then(r,i)})})},h.prototype.catch=function(e){return this.then(null,e)},h.resolve=function(e){return new h(function(n){n(e)})},h.reject=function(e){return new h(function(n,t){t(e)})},["all","race"].map(function(e){h[e]=function(n){return new h(function(t,r){Promise[e](n.map(function(e){return e.p})).then(t,r)})}}),f.Undefined=d,f.Promise=h,f.isThenable=i,f.toStringTag=o,f.hasConstructorOf=c,f.isObject=s,f.isPlainObject=u,f.isUserObject=a,f.escapeKeyPathComponent=p,f.unescapeKeyPathComponent=l,f.getByKeyPath=v,f.getJSONType=function(e){return null===e?"null":m(e)?"array":void 0===e?"undefined":O(e)},f.JSON_TYPES=["null","boolean","number","string","array","object"],n.default=f,e.exports=n.default}])}); | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.Typeson = factory()); | ||
}(this, (function () { 'use strict'; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { | ||
return typeof obj; | ||
} : function (obj) { | ||
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; | ||
}; | ||
var slicedToArray = function () { | ||
function sliceIterator(arr, i) { | ||
var _arr = []; | ||
var _n = true; | ||
var _d = false; | ||
var _e = undefined; | ||
try { | ||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { | ||
_arr.push(_s.value); | ||
if (i && _arr.length === i) break; | ||
} | ||
} catch (err) { | ||
_d = true; | ||
_e = err; | ||
} finally { | ||
try { | ||
if (!_n && _i["return"]) _i["return"](); | ||
} finally { | ||
if (_d) throw _e; | ||
} | ||
} | ||
return _arr; | ||
} | ||
return function (arr, i) { | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} else if (Symbol.iterator in Object(arr)) { | ||
return sliceIterator(arr, i); | ||
} else { | ||
throw new TypeError("Invalid attempt to destructure non-iterable instance"); | ||
} | ||
}; | ||
}(); | ||
var toConsumableArray = function (arr) { | ||
if (Array.isArray(arr)) { | ||
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | ||
return arr2; | ||
} else { | ||
return Array.from(arr); | ||
} | ||
}; | ||
var keys = Object.keys; | ||
var isArray = Array.isArray; | ||
var toString = {}.toString; | ||
var getProto = Object.getPrototypeOf; | ||
var hasOwn = {}.hasOwnProperty; | ||
var fnToString = hasOwn.toString; | ||
function isThenable(v, catchCheck) { | ||
return Typeson.isObject(v) && typeof v.then === 'function' && (!catchCheck || typeof v.catch === 'function'); | ||
} | ||
function toStringTag(val) { | ||
return toString.call(val).slice(8, -1); | ||
} | ||
function hasConstructorOf(a, b) { | ||
if (!a || (typeof a === 'undefined' ? 'undefined' : _typeof(a)) !== 'object') { | ||
return false; | ||
} | ||
var proto = getProto(a); | ||
if (!proto) { | ||
return false; | ||
} | ||
var Ctor = hasOwn.call(proto, 'constructor') && proto.constructor; | ||
if (typeof Ctor !== 'function') { | ||
return b === null; | ||
} | ||
return typeof Ctor === 'function' && b !== null && fnToString.call(Ctor) === fnToString.call(b); | ||
} | ||
function isPlainObject(val) { | ||
// Mirrors jQuery's | ||
if (!val || toStringTag(val) !== 'Object') { | ||
return false; | ||
} | ||
var proto = getProto(val); | ||
if (!proto) { | ||
// `Object.create(null)` | ||
return true; | ||
} | ||
return hasConstructorOf(val, Object); | ||
} | ||
function isUserObject(val) { | ||
if (!val || toStringTag(val) !== 'Object') { | ||
return false; | ||
} | ||
var proto = getProto(val); | ||
if (!proto) { | ||
// `Object.create(null)` | ||
return true; | ||
} | ||
return hasConstructorOf(val, Object) || isUserObject(proto); | ||
} | ||
function isObject(v) { | ||
return v && (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object'; | ||
} | ||
/* Typeson - JSON with types | ||
* License: The MIT License (MIT) | ||
* Copyright (c) 2016 David Fahlander | ||
*/ | ||
/** An instance of this class can be used to call stringify() and parse(). | ||
* Typeson resolves cyclic references by default. Can also be extended to | ||
* support custom types using the register() method. | ||
* | ||
* @constructor | ||
* @param {{cyclic: boolean}} [options] - if cyclic (default true), cyclic references will be handled gracefully. | ||
*/ | ||
function Typeson(options) { | ||
// Replacers signature: replace (value). Returns falsy if not replacing. Otherwise ['Date', value.getTime()] | ||
var plainObjectReplacers = []; | ||
var nonplainObjectReplacers = []; | ||
// Revivers: map {type => reviver}. Sample: {'Date': value => new Date(value)} | ||
var revivers = {}; | ||
/** Types registered via register() */ | ||
var regTypes = this.types = {}; | ||
/** Serialize given object to Typeson. | ||
* | ||
* Arguments works identical to those of JSON.stringify(). | ||
*/ | ||
var stringify = this.stringify = function (obj, replacer, space, opts) { | ||
// replacer here has nothing to do with our replacers. | ||
opts = Object.assign({}, options, opts, { stringification: true }); | ||
var encapsulated = encapsulate(obj, null, opts); | ||
if (isArray(encapsulated)) { | ||
return JSON.stringify(encapsulated[0], replacer, space); | ||
} | ||
return encapsulated.then(function (res) { | ||
return JSON.stringify(res, replacer, space); | ||
}); | ||
}; | ||
// Also sync but throws on non-sync result | ||
this.stringifySync = function (obj, replacer, space, opts) { | ||
return stringify(obj, replacer, space, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: true })); | ||
}; | ||
this.stringifyAsync = function (obj, replacer, space, opts) { | ||
return stringify(obj, replacer, space, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: false })); | ||
}; | ||
/** Parse Typeson back into an obejct. | ||
* | ||
* Arguments works identical to those of JSON.parse(). | ||
*/ | ||
var parse = this.parse = function (text, reviver, opts) { | ||
opts = Object.assign({}, options, opts, { parse: true }); | ||
return revive(JSON.parse(text, reviver), opts); // This reviver has nothing to do with our revivers. | ||
}; | ||
// Also sync but throws on non-sync result | ||
this.parseSync = function (text, reviver, opts) { | ||
return parse(text, reviver, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: true })); // This reviver has nothing to do with our revivers. | ||
}; | ||
this.parseAsync = function (text, reviver, opts) { | ||
return parse(text, reviver, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: false })); // This reviver has nothing to do with our revivers. | ||
}; | ||
this.specialTypeNames = function (obj, stateObj) { | ||
var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
opts.returnTypeNames = true; | ||
return this.encapsulate(obj, stateObj, opts); | ||
}; | ||
this.rootTypeName = function (obj, stateObj) { | ||
var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
opts.iterateNone = true; | ||
return this.encapsulate(obj, stateObj, opts); | ||
}; | ||
/** Encapsulate a complex object into a plain Object by replacing registered types with | ||
* plain objects representing the types data. | ||
* | ||
* This method is used internally by Typeson.stringify(). | ||
* @param {Object} obj - Object to encapsulate. | ||
*/ | ||
var encapsulate = this.encapsulate = function (obj, stateObj, opts) { | ||
opts = Object.assign({ sync: true }, options, opts); | ||
var sync = opts.sync; | ||
var types = {}, | ||
refObjs = [], | ||
// For checking cyclic references | ||
refKeys = [], | ||
// For checking cyclic references | ||
promisesDataRoot = []; | ||
// Clone the object deeply while at the same time replacing any special types or cyclic reference: | ||
var cyclic = opts && 'cyclic' in opts ? opts.cyclic : true; | ||
var encapsulateObserver = opts.encapsulateObserver; | ||
var ret = _encapsulate('', obj, cyclic, stateObj || {}, promisesDataRoot); | ||
function finish(ret) { | ||
// Add $types to result only if we ever bumped into a special type (or special case where object has own `$types`) | ||
if (opts.iterateNone) { | ||
var _typeNames = Object.values(types); | ||
if (_typeNames.length) { | ||
return _typeNames[0]; | ||
} | ||
return Typeson.getJSONType(ret); | ||
} | ||
var typeNames = Object.values(types); | ||
if (typeNames.length) { | ||
if (opts.returnTypeNames) { | ||
return [].concat(toConsumableArray(new Set(typeNames))); | ||
} | ||
if (!ret || !isPlainObject(ret) || // Special if array (or a primitive) was serialized because JSON would ignore custom `$types` prop on it | ||
ret.hasOwnProperty('$types') // Also need to handle if this is an object with its own `$types` property (to avoid ambiguity) | ||
) { | ||
ret = { $: ret, $types: { $: types } }; | ||
} else { | ||
ret.$types = types; | ||
} | ||
} else if (isObject(ret) && ret.hasOwnProperty('$types')) { | ||
// No special types | ||
ret = { $: ret, $types: true }; | ||
} | ||
if (opts.returnTypeNames) { | ||
return false; | ||
} | ||
return ret; | ||
} | ||
function checkPromises(ret, promisesData) { | ||
return Promise.all(promisesData.map(function (pd) { | ||
return pd[1].p; | ||
})).then(function (promResults) { | ||
return Promise.all(promResults.map(function (promResult) { | ||
var newPromisesData = []; | ||
var prData = promisesData.splice(0, 1)[0]; | ||
var _prData = slicedToArray(prData, 7), | ||
keyPath = _prData[0], | ||
cyclic = _prData[2], | ||
stateObj = _prData[3], | ||
parentObj = _prData[4], | ||
key = _prData[5], | ||
detectedType = _prData[6]; | ||
var encaps = _encapsulate(keyPath, promResult, cyclic, stateObj, newPromisesData, true, detectedType); | ||
var isTypesonPromise = hasConstructorOf(encaps, TypesonPromise); | ||
if (keyPath && isTypesonPromise) { | ||
// Handle case where an embedded custom type itself returns a `Typeson.Promise` | ||
return encaps.p.then(function (encaps2) { | ||
parentObj[key] = encaps2; | ||
return checkPromises(ret, newPromisesData); | ||
}); | ||
} | ||
if (keyPath) parentObj[key] = encaps;else if (isTypesonPromise) { | ||
ret = encaps.p; | ||
} else ret = encaps; // If this is itself a `Typeson.Promise` (because the original value supplied was a promise or because the supplied custom type value resolved to one), returning it below will be fine since a promise is expected anyways given current config (and if not a promise, it will be ready as the resolve value) | ||
return checkPromises(ret, newPromisesData); | ||
})); | ||
}).then(function () { | ||
return ret; | ||
}); | ||
} | ||
return promisesDataRoot.length ? sync && opts.throwOnBadSyncType ? function () { | ||
throw new TypeError('Sync method requested but async result obtained'); | ||
}() : Promise.resolve(checkPromises(ret, promisesDataRoot)).then(finish) : !sync && opts.throwOnBadSyncType ? function () { | ||
throw new TypeError('Async method requested but sync result obtained'); | ||
}() : opts.stringification && sync // If this is a synchronous request for stringification, yet a promise is the result, we don't want to resolve leading to an async result, so we return an array to avoid ambiguity | ||
? [finish(ret)] : sync ? finish(ret) : Promise.resolve(finish(ret)); | ||
function _encapsulate(keypath, value, cyclic, stateObj, promisesData, resolvingTypesonPromise, detectedType) { | ||
var ret = void 0; | ||
var observerData = {}; | ||
var $typeof = typeof value === 'undefined' ? 'undefined' : _typeof(value); | ||
var runObserver = encapsulateObserver ? function (obj) { | ||
var type = detectedType || stateObj.type || Typeson.getJSONType(value); | ||
encapsulateObserver(Object.assign(obj || observerData, { | ||
keypath: keypath, | ||
value: value, | ||
cyclic: cyclic, | ||
stateObj: stateObj, | ||
promisesData: promisesData, | ||
resolvingTypesonPromise: resolvingTypesonPromise, | ||
awaitingTypesonPromise: hasConstructorOf(value, TypesonPromise) | ||
}, type !== undefined ? { type: type } : {})); | ||
} : null; | ||
if ($typeof in { string: 1, boolean: 1, number: 1, undefined: 1 }) { | ||
if (value === undefined || $typeof === 'number' && (isNaN(value) || value === -Infinity || value === Infinity)) { | ||
ret = replace(keypath, value, stateObj, promisesData, false, resolvingTypesonPromise, runObserver); | ||
if (ret !== value) { | ||
observerData = { replaced: ret }; | ||
} | ||
} else { | ||
ret = value; | ||
} | ||
if (runObserver) runObserver(); | ||
return ret; | ||
} | ||
if (value === null) { | ||
if (runObserver) runObserver(); | ||
return value; | ||
} | ||
if (cyclic && !stateObj.iterateIn && !stateObj.iterateUnsetNumeric) { | ||
// Options set to detect cyclic references and be able to rewrite them. | ||
var refIndex = refObjs.indexOf(value); | ||
if (refIndex < 0) { | ||
if (cyclic === true) { | ||
refObjs.push(value); | ||
refKeys.push(keypath); | ||
} | ||
} else { | ||
types[keypath] = '#'; | ||
if (runObserver) { | ||
runObserver({ | ||
cyclicKeypath: refKeys[refIndex] | ||
}); | ||
} | ||
return '#' + refKeys[refIndex]; | ||
} | ||
} | ||
var isPlainObj = isPlainObject(value); | ||
var isArr = isArray(value); | ||
var replaced = (isPlainObj || isArr) && (!plainObjectReplacers.length || stateObj.replaced) || stateObj.iterateIn // Running replace will cause infinite loop as will test positive again | ||
? | ||
// Optimization: if plain object and no plain-object replacers, don't try finding a replacer | ||
value : replace(keypath, value, stateObj, promisesData, isPlainObj || isArr, null, runObserver); | ||
var clone = void 0; | ||
if (replaced !== value) { | ||
ret = replaced; | ||
observerData = { replaced: replaced }; | ||
} else { | ||
if (isArr || stateObj.iterateIn === 'array') { | ||
clone = new Array(value.length); | ||
observerData = { clone: clone }; | ||
} else if (isPlainObj || stateObj.iterateIn === 'object') { | ||
clone = {}; | ||
observerData = { clone: clone }; | ||
} else if (keypath === '' && hasConstructorOf(value, TypesonPromise)) { | ||
promisesData.push([keypath, value, cyclic, stateObj, undefined, undefined, stateObj.type]); | ||
ret = value; | ||
} else { | ||
ret = value; // Only clone vanilla objects and arrays | ||
} | ||
} | ||
if (runObserver) runObserver(); | ||
if (opts.iterateNone) { | ||
return clone || ret; | ||
} | ||
if (!clone) { | ||
return ret; | ||
} | ||
// Iterate object or array | ||
if (stateObj.iterateIn) { | ||
for (var key in value) { | ||
var ownKeysObj = { ownKeys: value.hasOwnProperty(key) }; | ||
var kp = keypath + (keypath ? '.' : '') + escapeKeyPathComponent(key); | ||
var val = _encapsulate(kp, value[key], !!cyclic, ownKeysObj, promisesData, resolvingTypesonPromise); | ||
if (hasConstructorOf(val, TypesonPromise)) { | ||
promisesData.push([kp, val, !!cyclic, ownKeysObj, clone, key, ownKeysObj.type]); | ||
} else if (val !== undefined) clone[key] = val; | ||
} | ||
if (runObserver) runObserver({ endIterateIn: true, end: true }); | ||
} else { | ||
// Note: Non-indexes on arrays won't survive stringify so somewhat wasteful for arrays, but so too is iterating all numeric indexes on sparse arrays when not wanted or filtering own keys for positive integers | ||
keys(value).forEach(function (key) { | ||
var kp = keypath + (keypath ? '.' : '') + escapeKeyPathComponent(key); | ||
var ownKeysObj = { ownKeys: true }; | ||
var val = _encapsulate(kp, value[key], !!cyclic, ownKeysObj, promisesData, resolvingTypesonPromise); | ||
if (hasConstructorOf(val, TypesonPromise)) { | ||
promisesData.push([kp, val, !!cyclic, ownKeysObj, clone, key, ownKeysObj.type]); | ||
} else if (val !== undefined) clone[key] = val; | ||
}); | ||
if (runObserver) runObserver({ endIterateOwn: true, end: true }); | ||
} | ||
// Iterate array for non-own numeric properties (we can't replace the prior loop though as it iterates non-integer keys) | ||
if (stateObj.iterateUnsetNumeric) { | ||
var vl = value.length; | ||
for (var i = 0; i < vl; i++) { | ||
if (!(i in value)) { | ||
var _kp = keypath + (keypath ? '.' : '') + i; // No need to escape numeric | ||
var _ownKeysObj = { ownKeys: false }; | ||
var _val = _encapsulate(_kp, undefined, !!cyclic, _ownKeysObj, promisesData, resolvingTypesonPromise); | ||
if (hasConstructorOf(_val, TypesonPromise)) { | ||
promisesData.push([_kp, _val, !!cyclic, _ownKeysObj, clone, i, _ownKeysObj.type]); | ||
} else if (_val !== undefined) clone[i] = _val; | ||
} | ||
} | ||
if (runObserver) runObserver({ endIterateUnsetNumeric: true, end: true }); | ||
} | ||
return clone; | ||
} | ||
function replace(keypath, value, stateObj, promisesData, plainObject, resolvingTypesonPromise, runObserver) { | ||
// Encapsulate registered types | ||
var replacers = plainObject ? plainObjectReplacers : nonplainObjectReplacers; | ||
var i = replacers.length; | ||
while (i--) { | ||
var replacer = replacers[i]; | ||
if (replacer.test(value, stateObj)) { | ||
var type = replacer.type; | ||
if (revivers[type]) { | ||
// Record the type only if a corresponding reviver exists. | ||
// This is to support specs where only replacement is done. | ||
// For example ensuring deep cloning of the object, or | ||
// replacing a type to its equivalent without the need to revive it. | ||
var existing = types[keypath]; | ||
// type can comprise an array of types (see test shouldSupportIntermediateTypes) | ||
types[keypath] = existing ? [type].concat(existing) : type; | ||
} | ||
// Now, also traverse the result in case it contains its own types to replace | ||
stateObj = Object.assign(stateObj, { type: type, replaced: true }); | ||
if ((sync || !replacer.replaceAsync) && !replacer.replace) { | ||
if (runObserver) runObserver({ typeDetected: true }); | ||
return _encapsulate(keypath, value, cyclic && 'readonly', stateObj, promisesData, resolvingTypesonPromise, type); | ||
} | ||
if (runObserver) runObserver({ replacing: true }); | ||
var replaceMethod = sync || !replacer.replaceAsync ? 'replace' : 'replaceAsync'; | ||
return _encapsulate(keypath, replacer[replaceMethod](value, stateObj), cyclic && 'readonly', stateObj, promisesData, resolvingTypesonPromise, type); | ||
} | ||
} | ||
return value; | ||
} | ||
}; | ||
// Also sync but throws on non-sync result | ||
this.encapsulateSync = function (obj, stateObj, opts) { | ||
return encapsulate(obj, stateObj, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: true })); | ||
}; | ||
this.encapsulateAsync = function (obj, stateObj, opts) { | ||
return encapsulate(obj, stateObj, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: false })); | ||
}; | ||
/** Revive an encapsulated object. | ||
* This method is used internally by Typeson.parse(). | ||
* @param {Object} obj - Object to revive. If it has $types member, the properties that are listed there | ||
* will be replaced with its true type instead of just plain objects. | ||
*/ | ||
var revive = this.revive = function (obj, opts) { | ||
opts = Object.assign({ sync: true }, options, opts); | ||
var sync = opts.sync; | ||
var types = obj && obj.$types, | ||
ignore$Types = true; | ||
if (!types) return obj; // No type info added. Revival not needed. | ||
if (types === true) return obj.$; // Object happened to have own `$types` property but with no actual types, so we unescape and return that object | ||
if (types.$ && isPlainObject(types.$)) { | ||
// Special when root object is not a trivial Object, it will be encapsulated in $. It will also be encapsulated in $ if it has its own `$` property to avoid ambiguity | ||
obj = obj.$; | ||
types = types.$; | ||
ignore$Types = false; | ||
} | ||
var keyPathResolutions = []; | ||
var ret = _revive('', obj, null, opts); | ||
ret = hasConstructorOf(ret, Undefined) ? undefined : ret; | ||
return isThenable(ret) ? sync && opts.throwOnBadSyncType ? function () { | ||
throw new TypeError('Sync method requested but async result obtained'); | ||
}() : ret : !sync && opts.throwOnBadSyncType ? function () { | ||
throw new TypeError('Async method requested but sync result obtained'); | ||
}() : sync ? ret : Promise.resolve(ret); | ||
function _revive(keypath, value, target, opts, clone, key) { | ||
if (ignore$Types && keypath === '$types') return; | ||
var type = types[keypath]; | ||
if (isArray(value) || isPlainObject(value)) { | ||
var _clone = isArray(value) ? new Array(value.length) : {}; | ||
// Iterate object or array | ||
keys(value).forEach(function (key) { | ||
var val = _revive(keypath + (keypath ? '.' : '') + escapeKeyPathComponent(key), value[key], target || _clone, opts, _clone, key); | ||
if (hasConstructorOf(val, Undefined)) _clone[key] = undefined;else if (val !== undefined) _clone[key] = val; | ||
}); | ||
value = _clone; | ||
while (keyPathResolutions.length) { | ||
// Try to resolve cyclic reference as soon as available | ||
var _keyPathResolutions$ = slicedToArray(keyPathResolutions[0], 4), | ||
_target = _keyPathResolutions$[0], | ||
keyPath = _keyPathResolutions$[1], | ||
_clone2 = _keyPathResolutions$[2], | ||
_key = _keyPathResolutions$[3]; | ||
var val = getByKeyPath(_target, keyPath); | ||
if (hasConstructorOf(val, Undefined)) _clone2[_key] = undefined;else if (val !== undefined) _clone2[_key] = val;else break; | ||
keyPathResolutions.splice(0, 1); | ||
} | ||
} | ||
if (!type) return value; | ||
if (type === '#') { | ||
var _ret = getByKeyPath(target, value.substr(1)); | ||
if (_ret === undefined) { | ||
// Cyclic reference not yet available | ||
keyPathResolutions.push([target, value.substr(1), clone, key]); | ||
} | ||
return _ret; | ||
} | ||
var sync = opts.sync; | ||
return [].concat(type).reduce(function (val, type) { | ||
var reviver = revivers[type]; | ||
if (!reviver) throw new Error('Unregistered type: ' + type); | ||
return reviver[// eslint-disable-line standard/computed-property-even-spacing | ||
sync && reviver.revive ? 'revive' : !sync && reviver.reviveAsync ? 'reviveAsync' : 'revive'](val); | ||
}, value); | ||
} | ||
}; | ||
// Also sync but throws on non-sync result | ||
this.reviveSync = function (obj, opts) { | ||
return revive(obj, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: true })); | ||
}; | ||
this.reviveAsync = function (obj, opts) { | ||
return revive(obj, Object.assign({}, { throwOnBadSyncType: true }, opts, { sync: false })); | ||
}; | ||
/** Register types. | ||
* For examples how to use this method, see https://github.com/dfahlander/typeson-registry/tree/master/types | ||
* @param {Array.<Object.<string,Function[]>>} typeSpec - Types and their functions [test, encapsulate, revive]; | ||
*/ | ||
this.register = function (typeSpecSets, opts) { | ||
opts = opts || {}; | ||
[].concat(typeSpecSets).forEach(function R(typeSpec) { | ||
if (isArray(typeSpec)) return typeSpec.map(R); // Allow arrays of arrays of arrays... | ||
typeSpec && keys(typeSpec).forEach(function (typeId) { | ||
if (typeId === '#') { | ||
throw new TypeError('# cannot be used as a type name as it is reserved for cyclic objects'); | ||
} else if (Typeson.JSON_TYPES.includes(typeId)) { | ||
throw new TypeError('Plain JSON object types are reserved as type names'); | ||
} | ||
var spec = typeSpec[typeId]; | ||
var replacers = spec.testPlainObjects ? plainObjectReplacers : nonplainObjectReplacers; | ||
var existingReplacer = replacers.filter(function (r) { | ||
return r.type === typeId; | ||
}); | ||
if (existingReplacer.length) { | ||
// Remove existing spec and replace with this one. | ||
replacers.splice(replacers.indexOf(existingReplacer[0]), 1); | ||
delete revivers[typeId]; | ||
delete regTypes[typeId]; | ||
} | ||
if (spec) { | ||
if (typeof spec === 'function') { | ||
// Support registering just a class without replacer/reviver | ||
var Class = spec; | ||
spec = { | ||
test: function test(x) { | ||
return x && x.constructor === Class; | ||
}, | ||
replace: function replace(x) { | ||
return assign({}, x); | ||
}, | ||
revive: function revive(x) { | ||
return assign(Object.create(Class.prototype), x); | ||
} | ||
}; | ||
} else if (isArray(spec)) { | ||
spec = { | ||
test: spec[0], | ||
replace: spec[1], | ||
revive: spec[2] | ||
}; | ||
} | ||
var replacerObj = { | ||
type: typeId, | ||
test: spec.test.bind(spec) | ||
}; | ||
if (spec.replace) { | ||
replacerObj.replace = spec.replace.bind(spec); | ||
} | ||
if (spec.replaceAsync) { | ||
replacerObj.replaceAsync = spec.replaceAsync.bind(spec); | ||
} | ||
var start = typeof opts.fallback === 'number' ? opts.fallback : opts.fallback ? 0 : Infinity; | ||
if (spec.testPlainObjects) { | ||
plainObjectReplacers.splice(start, 0, replacerObj); | ||
} else { | ||
nonplainObjectReplacers.splice(start, 0, replacerObj); | ||
} | ||
// Todo: We might consider a testAsync type | ||
if (spec.revive || spec.reviveAsync) { | ||
var reviverObj = {}; | ||
if (spec.revive) reviverObj.revive = spec.revive.bind(spec); | ||
if (spec.reviveAsync) reviverObj.reviveAsync = spec.reviveAsync.bind(spec); | ||
revivers[typeId] = reviverObj; | ||
} | ||
regTypes[typeId] = spec; // Record to be retrieved via public types property. | ||
} | ||
}); | ||
}); | ||
return this; | ||
}; | ||
} | ||
function assign(t, s) { | ||
keys(s).map(function (k) { | ||
t[k] = s[k]; | ||
}); | ||
return t; | ||
} | ||
/** escapeKeyPathComponent() utility */ | ||
function escapeKeyPathComponent(keyPathComponent) { | ||
return keyPathComponent.replace(/~/g, '~0').replace(/\./g, '~1'); | ||
} | ||
/** unescapeKeyPathComponent() utility */ | ||
function unescapeKeyPathComponent(keyPathComponent) { | ||
return keyPathComponent.replace(/~1/g, '.').replace(/~0/g, '~'); | ||
} | ||
/** getByKeyPath() utility */ | ||
function getByKeyPath(obj, keyPath) { | ||
if (keyPath === '') return obj; | ||
var period = keyPath.indexOf('.'); | ||
if (period > -1) { | ||
var innerObj = obj[unescapeKeyPathComponent(keyPath.substr(0, period))]; | ||
return innerObj === undefined ? undefined : getByKeyPath(innerObj, keyPath.substr(period + 1)); | ||
} | ||
return obj[unescapeKeyPathComponent(keyPath)]; | ||
} | ||
function Undefined() {} | ||
// With ES6 classes, we may be able to simply use `class TypesonPromise extends Promise` and add a string tag for detection | ||
function TypesonPromise(f) { | ||
this.p = new Promise(f); | ||
} | ||
TypesonPromise.prototype.then = function (onFulfilled, onRejected) { | ||
var _this = this; | ||
return new TypesonPromise(function (typesonResolve, typesonReject) { | ||
_this.p.then(function (res) { | ||
typesonResolve(onFulfilled ? onFulfilled(res) : res); | ||
}, function (r) { | ||
_this.p['catch'](function (res) { | ||
return onRejected ? onRejected(res) : Promise.reject(res); | ||
}).then(typesonResolve, typesonReject); | ||
}); | ||
}); | ||
}; | ||
TypesonPromise.prototype['catch'] = function (onRejected) { | ||
return this.then(null, onRejected); | ||
}; | ||
TypesonPromise.resolve = function (v) { | ||
return new TypesonPromise(function (typesonResolve) { | ||
typesonResolve(v); | ||
}); | ||
}; | ||
TypesonPromise.reject = function (v) { | ||
return new TypesonPromise(function (typesonResolve, typesonReject) { | ||
typesonReject(v); | ||
}); | ||
}; | ||
['all', 'race'].map(function (meth) { | ||
TypesonPromise[meth] = function (promArr) { | ||
return new TypesonPromise(function (typesonResolve, typesonReject) { | ||
Promise[meth](promArr.map(function (prom) { | ||
return prom.p; | ||
})).then(typesonResolve, typesonReject); | ||
}); | ||
}; | ||
}); | ||
// The following provide classes meant to avoid clashes with other values | ||
Typeson.Undefined = Undefined; // To insist `undefined` should be added | ||
Typeson.Promise = TypesonPromise; // To support async encapsulation/stringification | ||
// Some fundamental type-checking utilities | ||
Typeson.isThenable = isThenable; | ||
Typeson.toStringTag = toStringTag; | ||
Typeson.hasConstructorOf = hasConstructorOf; | ||
Typeson.isObject = isObject; | ||
Typeson.isPlainObject = isPlainObject; | ||
Typeson.isUserObject = isUserObject; | ||
Typeson.escapeKeyPathComponent = escapeKeyPathComponent; | ||
Typeson.unescapeKeyPathComponent = unescapeKeyPathComponent; | ||
Typeson.getByKeyPath = getByKeyPath; | ||
Typeson.getJSONType = function (value) { | ||
return value === null ? 'null' : isArray(value) ? 'array' : typeof value === 'undefined' ? 'undefined' : _typeof(value); | ||
}; | ||
Typeson.JSON_TYPES = ['null', 'boolean', 'number', 'string', 'array', 'object']; | ||
return Typeson; | ||
}))); |
{ | ||
"name": "typeson", | ||
"version": "5.2.0", | ||
"version": "5.4.0", | ||
"description": "Preserves types over JSON, BSON or socket.io", | ||
"main": "./dist/typeson-commonjs2.js", | ||
"browser": "./dist/typeson.js", | ||
"module": "./typeson.js", | ||
"scripts": { | ||
"eslint": "eslint *.js", | ||
"test": "node test.js", | ||
"prepublish": "npm run build", | ||
"build": "node_modules/.bin/webpack --optimize-minimize" | ||
"eslint": "eslint *.js test/test.js", | ||
"browser-test": "npm run eslint && npm run rollup && npm start test/", | ||
"test": "npm run eslint && npm run rollup && node test/test-polyglot.js", | ||
"rollup": "rollup -c" | ||
}, | ||
@@ -36,6 +37,4 @@ "repository": { | ||
"babel-core": "6.26.0", | ||
"babel-loader": "7.1.2", | ||
"babel-plugin-add-module-exports": "0.2.1", | ||
"babel-polyfill": "6.26.0", | ||
"babel-preset-es2015": "6.24.1", | ||
"babel-plugin-external-helpers": "^6.22.0", | ||
"babel-preset-env": "^1.6.1", | ||
"base64-arraybuffer": "0.1.5", | ||
@@ -49,6 +48,11 @@ "eslint": "4.12.1", | ||
"eslint-plugin-standard": "3.0.1", | ||
"uglify-js": "3.2.0", | ||
"webpack": "3.9.1" | ||
"node-static": "0.7.10", | ||
"opn": "5.1.0", | ||
"rollup": "0.52.0", | ||
"rollup-plugin-babel": "^3.0.2", | ||
"rollup-plugin-commonjs": "^8.2.6", | ||
"rollup-plugin-node-resolve": "^3.0.0", | ||
"uglify-js": "3.2.0" | ||
}, | ||
"tonicExample": "var Typeson = require('typeson');\nvar TSON = new Typeson().register(require('typeson-registry/presets/builtin'));\n\nTSON.stringify({foo: new Date()}, null, 2);" | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
136562
1967
18
2