any-serialize
Version:
Serialize / Deserialize any JavaScript objects, as long as you provides how-to. I have already provided `Date`, `RegExp`, `Set` and `Function`.
3 lines (2 loc) • 6.71 kB
JavaScript
function isClassConstructor(a){return!!(a.prototype&&a.prototype.constructor)}function isClassObject(a){return!!(a.constructor&&"string"==typeof a.constructor.name)}function compareNotFalsy(c,a){return!!c&&c===a}function getFunctionName(a){return a.toString().replace(/^function /,"").split("(")[0]}function functionToString(a){return a.toString().replace(/^.+?\{/s,"").replace(/\}.*?$/s,"").trim().replace(/[\t\n\r ]*/g," ")}function cyrb53(a,b=0){var c=Math.imul;let d=3735928559^b,e=1103547991^b;for(let f,g=0;g<a.length;g++)f=a.charCodeAt(g),d=c(d^f,2654435761),e=c(e^f,1597334677);return d=c(d^d>>>16,2246822507)^c(e^e>>>13,3266489909),e=c(e^e>>>16,2246822507)^c(d^d>>>13,3266489909),4294967296*(2097151&e)+(d>>>0)}function extractObjectFromClass(a,b=[]){return Object.getOwnPropertyNames(a).map(c=>{a[c];["constructor",...b].includes(c)}),a}function getTypeofDetailed(b){var a=Math.round;const c=typeof b,d={typeof_:c,is:[],entry:b};return"object"==c?b?(d.id=b.constructor,d.is=d.id===Object?["object"]:d.id===Array?["Array"]:["Named"]):d.is=["Null"]:"function"===c?b.prototype?(d.id=b.prototype.constructor,Object.getOwnPropertyNames(b.prototype).some(a=>"constructor"!==a)?(d.description="Can also be a class constructor in some cases",d.is=/[A-Z]/.test(b.prototype.constructor.name[0])?["Constructor","function"]:["function","Constructor"]):d.is=["Constructor"]):d.is=["function"]:"number"===c&&(isNaN(b)?d.is=["NaN"]:isFinite(b)?a(b)===b&&(d.description="Integer"):d.is=["Infinity"]),0===d.is.length&&(d.is=[c]),d}function isArray(b,a){return"Array"===(a||getTypeofDetailed(b)).is[0]}function isObject(b,a){return"object"===(a||getTypeofDetailed(b).is[0])}const MongoDateAdapter={prefix:"",key:"$date",item:Date,fromJSON:a=>new Date(a)},MongoRegExpAdapter={prefix:"",key:"$regex",item:RegExp,fromJSON(a,b){return new RegExp(a,b.$options)},toJSON(a,b){return b.$options=a.flags,a.source}};class Serialize{constructor(a={}){this.registrar=[],this.prefix="__",this.stringifyFunction=JSON.stringify,this.parseFunction=JSON.parse,this.undefinedProxy=Symbol("undefined"),this.prefix="string"==typeof a.prefix?a.prefix:this.prefix,this.stringifyFunction=a.stringify||this.stringifyFunction,this.parseFunction=a.parse||this.parseFunction,this.register({item:Date},{item:RegExp,toJSON(a){const{source:b,flags:c}=a;return{source:b,flags:c}},fromJSON(a){const{source:b,flags:c}=a;return new RegExp(b,c)}},WriteOnlyFunctionAdapter,{item:Set,toJSON(a){return Array.from(a)}},{key:"Infinity",toJSON(a){return a.toString()},fromJSON(a){return+a}},{key:"bigint",toJSON(a){return a.toString()},fromJSON(a){return BigInt(a)}},{key:"symbol",toJSON(a){return{content:a.toString(),rand:Math.random().toString(36).substr(2)}},fromJSON({content:a}){return Symbol(a.replace(/^Symbol\(/i,"").replace(/\)$/,""))}},{key:"NaN",toJSON:()=>"NaN",fromJSON:()=>NaN})}register(...a){this.registrar.unshift(...a.map(a=>{if("function"==typeof a){const{__prefix__:b,__key__:c,fromJSON:d,toJSON:e}=a;return{item:a,prefix:b,key:c,fromJSON:d,toJSON:e}}return a}).map(({item:a,prefix:b,key:c,toJSON:d,fromJSON:e})=>(e="undefined"==typeof e?b=>isClassConstructor(a)?new a(b):b:e||void 0,c=this.getKey(b,c||(isClassConstructor(a)?a.prototype.constructor.name:"function"==typeof a?getFunctionName(a):a)),{R:a,key:c,toJSON:d,fromJSON:e})))}unregister(...a){this.registrar=this.registrar.filter(({R:b,key:c})=>!a.some(a=>"function"==typeof a?!!b&&a.constructor===b.constructor:compareNotFalsy(a.key,c)||!!a.item&&!!b&&compareNotFalsy(a.item.constructor,b.constructor)))}stringify(a){const b=this.deepCloneAndFindAndReplace([a],"jsonCompatible")[0],c=new Set,d=b=>{if(b)if("object"==typeof b&&"Object"===b.constructor.name)for(const a of Object.keys(b))c.add(a),d(b[a]);else Array.isArray(b)&&b.map(a=>d(a))};return d(b),this.stringifyFunction(b,Array.from(c).sort())}hash(a){return cyrb53(this.stringify(a)).toString(36)}clone(a){return this.deepCloneAndFindAndReplace([a],"clone")[0]}deepEqual(a,b){const c=getTypeofDetailed(a),d=getTypeofDetailed(b);if("function"===c.typeof_||"object"===c.typeof_)return isArray(a,c)?a.map((a,c)=>this.deepEqual(a,b[c])).every(a=>a):isObject(a,c)?Object.entries(a).map(([a,c])=>this.deepEqual(c,b[a])).every(a=>a):this.hash(a)===this.hash(b);return"NaN"===c.is[0]&&"NaN"===d.is[0]?this.hash(a)===this.hash(b):a===b}parse(a){return this.parseFunction(a,(a,b)=>{if(b&&"object"==typeof b)for(const{key:a,fromJSON:c}of this.registrar)if(b[a])return"function"==typeof c?c(b[a],b):b;return b})}getKey(a,b){return("string"==typeof a?a:this.prefix)+(b||"")}deepCloneAndFindAndReplace(a,b){const c=getTypeofDetailed(a);if("Array"===c.is[0]){const c=[];return a.map((a,d)=>{const e=this.deepCloneAndFindAndReplace(a,b);c[d]=e===this.undefinedProxy?void 0:e}),c}if("object"===c.is[0]){const c={};return Object.entries(a).map(([a,d])=>{const e=this.deepCloneAndFindAndReplace(d,b);if(void 0===e);else c[a]=e===this.undefinedProxy?void 0:e}),c}if("Named"===c.is[0]){const c=this.getKey(a.__prefix__,a.__name__||a.constructor.name);for(const{R:d,key:e,toJSON:f,fromJSON:g}of this.registrar)if(!!d&&compareNotFalsy(a.constructor,d)||compareNotFalsy(c,e)){if(!g&&"clone"===b)continue;const c={};return c[e]=(f||!!d&&d.prototype.toJSON||a.toJSON||a.toString).bind(a)(a,c),void 0===c[e]?void 0:"clone"===b?g(c[e],c):c}return"clone"===b?a:{[c]:extractObjectFromClass(a)}}if("Constructor"===c.is[0]||"function"===c.is[0]||"Infinity"===c.is[0]||"bigint"===c.is[0]||"symbol"===c.is[0]||"NaN"===c.is[0]){let d=c.is[0];if("Constructor"===d&&(d="function"),"clone"===b&&"function"!==d)return a;const e=this.getKey(void 0,d),{R:f,toJSON:g,fromJSON:h}=this.registrar.filter(({key:a})=>a===e)[0]||{};if("clone"===b&&!h)return a;const i={};return i[e]=(g||!!f&&f.prototype.toJSON||a.toJSON||a.toString).bind(a)(a,i),"clone"===b?h(i[e],i):void 0===i[e]?void 0:i}if("undefined"===c.is[0]){if("clone"===b)return this.undefinedProxy;const d=this.getKey(void 0,c.is[0]),{R:e,toJSON:f}=this.registrar.filter(({key:a})=>a===d)[0]||{},g={};return g[d]=(f||!!e&&e.prototype.toJSON||(()=>{})).bind(a)(a,g),void 0===g[d]?void 0:g}return a}}const FullFunctionAdapter={key:"function",toJSON:a=>a.toString().trim().replace(/\[native code\]/g," ").replace(/[\t\n\r ]+/g," "),fromJSON:a=>new Function(`return ${a}`)()},WriteOnlyFunctionAdapter=Object.assign(Object.assign({},FullFunctionAdapter),{fromJSON:null}),UndefinedAdapter={key:"undefined",toJSON:()=>"undefined",fromJSON:()=>void 0};export{FullFunctionAdapter,MongoDateAdapter,MongoRegExpAdapter,Serialize,UndefinedAdapter,WriteOnlyFunctionAdapter,compareNotFalsy,cyrb53,extractObjectFromClass,functionToString,getFunctionName,isClassConstructor,isClassObject};
//# sourceMappingURL=index.min.mjs.map