typeson
Advanced tools
Comparing version 1.0.2 to 1.0.3
{ | ||
"name": "typeson", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"description": "JSON with types", | ||
@@ -5,0 +5,0 @@ "main": "typeson.js", |
@@ -7,2 +7,8 @@ # Typeson | ||
# Compatibility | ||
* Node | ||
* Browser | ||
* Worker | ||
* ES5 | ||
# Features | ||
@@ -36,6 +42,8 @@ * Can stringify Dates, RegExps, Errors by default (will support more times soon...) | ||
##### options (optional): | ||
``` | ||
{ | ||
cyclic?: boolean, // Default true | ||
types?: {TypeName: [tester, encapsulator, reviver]} // Defaults to the built-in types (currently Date, RegExp and Error) | ||
types?: {TypeName: [tester, encapsulator, reviver]} | ||
} | ||
``` | ||
@@ -46,11 +54,11 @@ ##### cyclic | ||
##### types | ||
A map of {TypeName: string => [tester, encapsulator reviver]. | ||
A map of TypeName:string to an array of three functions; tester, encapsulator and reviver `{TypeName: string => [tester, encapsulator, reviver]}`. The functions are described below. | ||
##### tester | ||
##### tester (obj : any) : boolean | ||
Function that tests whether an instance is of your type and returns a truthy value if it is. | ||
##### encapsulator | ||
##### encapsulator (obj: YourType) : Object | ||
Function that maps you instance to a JSON-serializable object. | ||
##### reviver | ||
##### reviver (obj: Object) : YourType | ||
Function that maps you JSON-serializable object into a real instance of your type. | ||
@@ -57,0 +65,0 @@ |
@@ -16,3 +16,3 @@ var Typeson = require('./typeson'); | ||
var tson = typeson.stringify(x, null, 2); | ||
console.log(tson); | ||
//console.log(tson); | ||
return typeson.parse(tson); | ||
@@ -36,3 +36,2 @@ } | ||
assert (res.g instanceof Date && res.g.toString() == date.toString(), "Date value"); | ||
assert (res.h instanceof RegExp && res.h.ignoreCase && res.h.global && !res.h.multiline, "Regexp value"); | ||
@@ -55,3 +54,3 @@ }, function shouldResolveCyclics() { | ||
var tson = typeson.stringify(data,null, 2); | ||
console.log(tson); | ||
//console.log(tson); | ||
var result = typeson.parse(tson); | ||
@@ -58,0 +57,0 @@ |
@@ -6,3 +6,4 @@ (function (global, factory) { | ||
}(this, function () { 'use strict'; | ||
var keys = Object.keys; | ||
var keys = Object.keys, | ||
isArray = Array.isArray; | ||
@@ -18,2 +19,3 @@ /* Typeson - JSON with types | ||
* Typeson also resolves cyclic references. | ||
* | ||
* @constructor | ||
@@ -67,3 +69,3 @@ * @param {{cyclic: boolean, types: Object}} [options] - if cyclic (default true), cyclic references will be handled gracefully. | ||
// Special if array was serialized because JSON would ignore custom $types prop on an array. | ||
if (Array.isArray(ret)) { | ||
if (isArray(ret)) { | ||
var rv = {}; | ||
@@ -131,28 +133,31 @@ ret.forEach(function(v,i){rv[i] = v;}); | ||
}; | ||
/** Register custom types. | ||
* For examples how to use this method, search for "Register built-in types" in typeson.js. | ||
* @param {Object.<string,Function[]} typeSpec - Types and their functions [test, encapsulate, revive]; | ||
* @param {Array.<Object.<string,Function[]>>} typeSpec - Types and their functions [test, encapsulate, revive]; | ||
*/ | ||
this.register = function (typeSpec) { | ||
keys(typeSpec).forEach(function (typeIdentifyer) { | ||
var spec = typeSpec[typeIdentifyer], | ||
test = spec[0], | ||
replace = spec[1], | ||
revive = spec[2], | ||
existingReviver = revivers[typeSpec]; | ||
if (existingReviver) { | ||
if (existingReviver.toString() !== revive.toString()) | ||
throw new Error ("Type " + typeIdentifyer + " is already registered with incompatible behaviour"); | ||
// Ignore re-registration if identical | ||
return; | ||
} | ||
function replacer (value) { | ||
return test(value) && [typeIdentifyer, replace(value)]; | ||
} | ||
replacers.push(replacer); | ||
revivers[typeIdentifyer] = revive; | ||
regTypes[typeIdentifyer] = spec; // Record to be retrueved via public types property. | ||
var register = this.register = function (typeSpecSets) { | ||
[].concat(typeSpecSets).forEach(function (typeSpec) { | ||
keys(typeSpec).forEach(function (typeIdentifyer) { | ||
var spec = typeSpec[typeIdentifyer], | ||
test = spec[0], | ||
replace = spec[1], | ||
revive = spec[2], | ||
existingReviver = revivers[typeSpec]; | ||
if (existingReviver) { | ||
if (existingReviver.toString() !== revive.toString()) | ||
throw new Error ("Type " + typeIdentifyer + " is already registered with incompatible behaviour"); | ||
// Ignore re-registration if identical | ||
return; | ||
} | ||
function replacer (value) { | ||
return test(value) && [typeIdentifyer, replace(value)]; | ||
} | ||
replacers.push(replacer); | ||
revivers[typeIdentifyer] = revive; | ||
regTypes[typeIdentifyer] = spec; // Record to be retrueved via public types property. | ||
}); | ||
}); | ||
} | ||
return this; | ||
}; | ||
@@ -166,2 +171,3 @@ // | ||
revivers["[]"] = function(a) { return keys(a).map(function (i){return a[i]}); }; // If root obj is an array (special) | ||
// Register option.types, or if not specified, the built-in types. | ||
@@ -175,9 +181,2 @@ this.register(options.types || { | ||
RegExp: [ | ||
function (x) { return x instanceof RegExp; }, | ||
function (rexp) { | ||
return {source: rexp.source, flags: (rexp.global?'g':'')+(rexp.ignoreCase?'i':'')+(rexp.multiLine?'m':'') }; }, | ||
function (data) { return new RegExp (data.source, data.flags); } | ||
], | ||
Error: [ | ||
@@ -187,6 +186,4 @@ function (x) { return x instanceof Error; }, | ||
function (data) { var e = new Error (data.message); e.name = data.name; return e; } | ||
], | ||
// TODO: Add more built-in types here! | ||
}); | ||
] | ||
}); | ||
} | ||
@@ -231,3 +228,3 @@ | ||
} | ||
var clone = Array.isArray(value) ? new Array(value.length) : {}; | ||
var clone = isArray(value) ? new Array(value.length) : {}; | ||
if (!target) target = clone; | ||
@@ -253,3 +250,8 @@ // Iterate object or array | ||
// Mixin all instance properties to also be static properties so that | ||
// the Typeson constructor can be used as the default instance itself. | ||
var instance = new Typeson(); | ||
keys(instance).map(function(key){ Typeson[key] = instance[key];}); | ||
return Typeson; | ||
})); |
@@ -1,2 +0,2 @@ | ||
(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 keys=Object.keys;function Typeson(options){options=options||{};var replacers=[];var revivers={};var regTypes=this.types={};this.stringify=function(obj,replacer,space){return JSON.stringify(encapsulate(obj),replacer,space)};this.parse=function(text,reviver){return revive(JSON.parse(text,reviver))};var encapsulate=this.encapsulate=function(obj){var types={};var ret=traverse(obj,encapsulator,"cyclic"in options?options.cyclic:true,types);if(keys(types).length){if(Array.isArray(ret)){var rv={};ret.forEach(function(v,i){rv[i]=v});types[""]="[]";ret=rv}ret.$types=types}return ret;function encapsulator(key,value,clone,$typeof){if($typeof in{string:1,"boolean":1,undefined:1})return value;if($typeof==="number"){if(isNaN(value)){return types[key]="NaN"}if(value===Infinity){return types[key]="Infinity"}if(value===-Infinity){return types[key]="-Infinity"}return value}if(value.constructor===Object)return clone;var i=replacers.length;while(i--){var replacement=replacers[i](value);if(replacement){types[key]=replacement[0];return continueTraversing(replacement[1],key)}}return clone}};var revive=this.revive=function(obj){var types=obj.$types;if(!types)return obj;return traverse(obj,function(key,value,clone,$typeof){if(key==="$types")return;var type=types[key];if(!type)return clone;if(type==="#")return getByKeyPath(target,value.substr(1));var reviver=revivers[type];if(!reviver)throw new Error("Unregistered Type: "+type);return reviver(clone)})};this.register=function(typeSpec){keys(typeSpec).forEach(function(typeIdentifyer){var spec=typeSpec[typeIdentifyer],test=spec[0],replace=spec[1],revive=spec[2],existingReviver=revivers[typeSpec];if(existingReviver){if(existingReviver.toString()!==revive.toString())throw new Error("Type "+typeIdentifyer+" is already registered with incompatible behaviour");return}function replacer(value){return test(value)&&[typeIdentifyer,replace(value)]}replacers.push(replacer);revivers[typeIdentifyer]=revive;regTypes[typeIdentifyer]=spec})};revivers.NaN=function(){return NaN};revivers.Infinity=function(){return Infinity};revivers["-Infinity"]=function(){return-Infinity};revivers["[]"]=function(a){return keys(a).map(function(i){return a[i]})};this.register(options.types||{Date:[function(x){return x instanceof Date},function(date){return date.getTime()},function(time){return new Date(time)}],RegExp:[function(x){return x instanceof RegExp},function(rexp){return{source:rexp.source,flags:(rexp.global?"g":"")+(rexp.ignoreCase?"i":"")+(rexp.multiLine?"m":"")}},function(data){return new RegExp(data.source,data.flags)}],Error:[function(x){return x instanceof Error},function(error){return{name:error.name,message:error.message}},function(data){var e=new Error(data.message);e.name=data.name;return e}]})}var refObjs,refKeys,target,replacer,types;function resetTraverse(){refObjs=[];refKeys=[];target=null;replacer=null;types=null}function traverse(value,_replacer,cyclic,outTypes){resetTraverse();replacer=_replacer;types=outTypes||{};var ret=continueTraversing(value,"",cyclic);resetTraverse();return ret}function continueTraversing(value,keypath,cyclic){var type=typeof value;if(type in{number:1,string:1,"boolean":1,undefined:1,"function":1,symbol:1})return replacer(keypath,value,value,type);if(value===null)return null;if(cyclic){var refIndex=refObjs.indexOf(value);if(refIndex<0){refObjs.push(value);refKeys.push(keypath)}else{types[keypath]="#";return"#"+refKeys[refIndex]}}var clone=Array.isArray(value)?new Array(value.length):{};if(!target)target=clone;keys(value).forEach(function(key){var val=continueTraversing(value[key],keypath+(keypath?".":"")+key,cyclic);if(val!==undefined)clone[key]=val});return replacer(keypath,value,clone,type)}function getByKeyPath(obj,keyPath){if(keyPath==="")return obj;var period=keyPath.indexOf(".");if(period!==-1){var innerObj=obj[keyPath.substr(0,period)];return innerObj===undefined?undefined:getByKeyPath(innerObj,keyPath.substr(period+1))}return obj[keyPath]}return Typeson}); | ||
(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 keys=Object.keys,isArray=Array.isArray;function Typeson(options){options=options||{};var replacers=[];var revivers={};var regTypes=this.types={};this.stringify=function(obj,replacer,space){return JSON.stringify(encapsulate(obj),replacer,space)};this.parse=function(text,reviver){return revive(JSON.parse(text,reviver))};var encapsulate=this.encapsulate=function(obj){var types={};var ret=traverse(obj,encapsulator,"cyclic"in options?options.cyclic:true,types);if(keys(types).length){if(isArray(ret)){var rv={};ret.forEach(function(v,i){rv[i]=v});types[""]="[]";ret=rv}ret.$types=types}return ret;function encapsulator(key,value,clone,$typeof){if($typeof in{string:1,"boolean":1,undefined:1})return value;if($typeof==="number"){if(isNaN(value)){return types[key]="NaN"}if(value===Infinity){return types[key]="Infinity"}if(value===-Infinity){return types[key]="-Infinity"}return value}if(value.constructor===Object)return clone;var i=replacers.length;while(i--){var replacement=replacers[i](value);if(replacement){types[key]=replacement[0];return continueTraversing(replacement[1],key)}}return clone}};var revive=this.revive=function(obj){var types=obj.$types;if(!types)return obj;return traverse(obj,function(key,value,clone,$typeof){if(key==="$types")return;var type=types[key];if(!type)return clone;if(type==="#")return getByKeyPath(target,value.substr(1));var reviver=revivers[type];if(!reviver)throw new Error("Unregistered Type: "+type);return reviver(clone)})};var register=this.register=function(typeSpecSets){[].concat(typeSpecSets).forEach(function(typeSpec){keys(typeSpec).forEach(function(typeIdentifyer){var spec=typeSpec[typeIdentifyer],test=spec[0],replace=spec[1],revive=spec[2],existingReviver=revivers[typeSpec];if(existingReviver){if(existingReviver.toString()!==revive.toString())throw new Error("Type "+typeIdentifyer+" is already registered with incompatible behaviour");return}function replacer(value){return test(value)&&[typeIdentifyer,replace(value)]}replacers.push(replacer);revivers[typeIdentifyer]=revive;regTypes[typeIdentifyer]=spec})});return this};revivers.NaN=function(){return NaN};revivers.Infinity=function(){return Infinity};revivers["-Infinity"]=function(){return-Infinity};revivers["[]"]=function(a){return keys(a).map(function(i){return a[i]})};this.register(options.types||{Date:[function(x){return x instanceof Date},function(date){return date.getTime()},function(time){return new Date(time)}],Error:[function(x){return x instanceof Error},function(error){return{name:error.name,message:error.message}},function(data){var e=new Error(data.message);e.name=data.name;return e}]})}var refObjs,refKeys,target,replacer,types;function resetTraverse(){refObjs=[];refKeys=[];target=null;replacer=null;types=null}function traverse(value,_replacer,cyclic,outTypes){resetTraverse();replacer=_replacer;types=outTypes||{};var ret=continueTraversing(value,"",cyclic);resetTraverse();return ret}function continueTraversing(value,keypath,cyclic){var type=typeof value;if(type in{number:1,string:1,"boolean":1,undefined:1,"function":1,symbol:1})return replacer(keypath,value,value,type);if(value===null)return null;if(cyclic){var refIndex=refObjs.indexOf(value);if(refIndex<0){refObjs.push(value);refKeys.push(keypath)}else{types[keypath]="#";return"#"+refKeys[refIndex]}}var clone=isArray(value)?new Array(value.length):{};if(!target)target=clone;keys(value).forEach(function(key){var val=continueTraversing(value[key],keypath+(keypath?".":"")+key,cyclic);if(val!==undefined)clone[key]=val});return replacer(keypath,value,clone,type)}function getByKeyPath(obj,keyPath){if(keyPath==="")return obj;var period=keyPath.indexOf(".");if(period!==-1){var innerObj=obj[keyPath.substr(0,period)];return innerObj===undefined?undefined:getByKeyPath(innerObj,keyPath.substr(period+1))}return obj[keyPath]}var instance=new Typeson;keys(instance).map(function(key){Typeson[key]=instance[key]});return Typeson}); | ||
//# sourceMappingURL=typeson.min.js.map |
Sorry, the diff of this file is not supported yet
30530
361
118