Skip to content

Instantly share code, notes, and snippets.

@ironboy
Last active January 29, 2016 10:01
Show Gist options
  • Save ironboy/68c928c50dd7e70580b3 to your computer and use it in GitHub Desktop.
Save ironboy/68c928c50dd7e70580b3 to your computer and use it in GitHub Desktop.
// A cool JSON reviver
// Thomas Frank 2015
// MIT licensed
JSON.cool = (function(){
var mem, findMem, base, toFind, settings = {
circulars: true,
dates: true,
functions: false,
regExps: true,
types: {
add:function(x){
for(var i in x){this[i] = x[i];}
}
}
};
function cool(key,val){
var i, proto, valproto, tmp;
// new base object
if(!key){
base = this[""];
mem = [base];
}
if(cool.circulars){
// stringify circular
if(key && mem.indexOf(val)>=0){
toFind = val;
findMem = [];
return '->circular->' + (val == base ? "" : findPath(base).substring(2));
}
// parse circular
if(typeof val=="string" && val.indexOf('->circular->')===0){
return getDataFromPath(base,val.split('->circular->')[1]);
}
// add objects/arrays to mem for circulars
if(typeof val == "object"){ mem.push(val); }
}
if(cool.dates){
// parse date (auto stringified by js earlier)
if(val && this[key] == val && val.match && val.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?Z$/)){
return new Date(val);
}
}
if(cool.functions){
// stringify function
if(typeof val == "function"){
return '->function->' + val;
}
// parse function
if(typeof val=="string" && val.indexOf('->function->')===0){
return new construct(Function,
val.match(/\(([^\)]*)/)[1].split(',').
concat([val.substring(
val.indexOf('{')+1,val.lastIndexOf('}')
)])
);
}
}
if(cool.regExps){
// stringify regexp
if(val instanceof RegExp){
return '->regexp->' + val;
}
// parse regexp
if(typeof val=="string" && val.indexOf('->regexp->')===0){
tmp = val.substring(val.indexOf('/')+1,val.lastIndexOf('/'));
return new RegExp(tmp,val.split(tmp)[1].substring(1));
}
}
// stringify prototype
if(typeof val == "object"){
valproto = Object.getPrototypeOf(val || {});
if(valproto !== Object.prototype){
for(i in cool.types){
proto = typeof cool.types[i] == "function" ?
cool.types[i].prototype : cool.types[i];
if(proto === valproto){
val._type = i;
}
}
return val;
}
}
// parse prototype
if(val && typeof val == "object" && typeof val._type == "string"){
valproto = Object.create(
typeof cool.types[val._type] == "function" ?
cool.types[val._type].prototype : cool.types[val._type]
);
if(typeof cool.types[val._type] == "function"){
valproto.constructor = cool.types[val._type];
}
for(i in val){valproto[i] = val[i];}
delete valproto._type;
val = valproto;
}
return val;
}
function findPath(obj,path){
findMem.push(obj);
var i,f, p;
path = path || '';
for(i in obj){
p = path + '.' + i;
if(obj[i] === toFind){return "*" + p; }
f = typeof obj[i] == "object" && findMem.indexOf(obj[i])<0 && findPath(obj[i],p);
if(f[0] == "*"){ return f; }
}
return path;
}
function getDataFromPath(obj,path){
if(!path){return obj;}
path = path.split('.');
while(obj && path.length){
obj = obj[path.shift()];
}
return obj;
}
// "Apply" a constructor;
function construct(constructor, args) {
function F() {
return constructor.apply(this, args);
}
F.prototype = constructor.prototype;
return new F();
}
// Get prototype of polyfill - John Resig
if ( typeof Object.getPrototypeOf !== "function" ) {
if ( typeof "test".__proto__ === "object" ) {
Object.getPrototypeOf = function(object){
return object.__proto__;
};
} else {
Object.getPrototypeOf = function(object){
// May break if the constructor has been tampered with
return object.constructor.prototype;
};
}
}
// Cool settings
for(var i in settings){
cool[i] = settings[i];
}
return cool;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment