Socket
Socket
Sign inDemoInstall

typeson

Package Overview
Dependencies
Maintainers
2
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

typeson - npm Package Compare versions

Comparing version 5.2.0 to 5.4.0

rollup.config.js

751

dist/typeson-commonjs2.js

@@ -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;
})));

26

package.json
{
"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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc