UNPKG

surrial

Version:

Serialize anything. This is surreal!

158 lines 6.78 kB
"use strict"; var __spreadArrays = (this && this.__spreadArrays) || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; Object.defineProperty(exports, "__esModule", { value: true }); var helpers_1 = require("./helpers"); var os_1 = require("os"); var UID = Math.floor(Math.random() * 0x10000000000).toString(16); var PLACE_HOLDER_REGEXP = new RegExp('"@__' + UID + '-(\\d+)__@"', 'g'); var IS_NATIVE_CODE_REGEXP = /\{\s*\[native code\]\s*\}/g; var BUILD_IN_SUPPORTED_CLASSES = Object.freeze([Map, Array, Buffer, Set, Date, RegExp]); /** * A surrial template tag, useful for building templates strings while enforcing the values to be serialized using surrial. * @param templateLiterals The template literals * @param values The values to be serialized using surrial */ function surrial(templateLiterals) { var values = []; for (var _i = 1; _i < arguments.length; _i++) { values[_i - 1] = arguments[_i]; } var stringBuilder = []; for (var i = 0; i < values.length; i++) { stringBuilder.push(templateLiterals[i]); stringBuilder.push(serialize(values[i])); } stringBuilder.push(templateLiterals[templateLiterals.length - 1]); return stringBuilder.join(''); } exports.surrial = surrial; /** * Deserializes a string into it's javascript equivalent. CAUTION! Evaluates the string in the current javascript engine * (`eval` or one of its friends). Be sure the `serializedThing` comes from a trusted source! * @param serializedThing The string to deserialize * @param knownClasses A list of known classes used to provide as constructor functions */ function deserialize(serializedThing, knownClasses) { if (knownClasses === void 0) { knownClasses = []; } var evalFn = new (Function.bind.apply(Function, __spreadArrays([void 0], knownClasses.map(function (t) { return t.name; }), ["\"use strict\";" + os_1.EOL + "return (" + serializedThing + ");"])))(); return evalFn.call.apply(evalFn, __spreadArrays([null], knownClasses)); } exports.deserialize = deserialize; /** * Serializes the thing to a javascript string. This is NOT necessarily a JSON string, but will be valid javascript. * @param thing The thing to be serialized * @param knownClasses the classes of which instances are serialized as constructor calls (for example "new Person('Henry')"). */ function serialize(thing, knownClasses) { if (knownClasses === void 0) { knownClasses = []; } if (thing instanceof Date) { return serializeDate(thing); } else if (thing instanceof RegExp) { return thing.toString(); } else if (typeof thing === 'function') { return serializeFunction(thing); } else if (thing instanceof Buffer) { return serializeBuffer(thing); } else if (thing instanceof Set) { return serializeSet(thing, knownClasses); } else if (thing instanceof Map) { return serializeMap(thing, knownClasses); } else if (Array.isArray(thing)) { return serializeArray(thing, knownClasses); } else if (helpers_1.isSurrializable(thing)) { return thing.surrialize(); } else if (helpers_1.isInstanceOf(thing, knownClasses)) { return serializeClassInstance(thing, knownClasses); } else { return stringifyObject(thing, knownClasses); } } exports.serialize = serialize; function serializeArray(thing, knownClasses) { return stringifyObject(thing, knownClasses); } function stringifyObject(thing, knownClasses) { var escapedValues = []; // Returns placeholders anything JSON doesn't support (identified by index) // which are later replaced by their string representation. function replacer(key, value) { // If the value is an object w/ a toJSON method, toJSON is called before // the replacer runs, so we use this[key] to get the non-JSON'd value. var origValue = this[key]; if (origValue !== thing && (helpers_1.isInstanceOf(origValue, BUILD_IN_SUPPORTED_CLASSES) || helpers_1.isInstanceOf(origValue, knownClasses) || helpers_1.isSurrializable(origValue))) { return "@__" + UID + "-" + (escapedValues.push(origValue) - 1) + "__@"; } else { return value; } } var str = JSON.stringify(thing, replacer); // Protects against `JSON.stringify()` returning `undefined`, by serializing // to the literal string: "undefined". if (typeof str !== 'string') { return String(str); } if (escapedValues.length === 0) { return str; } else { // Replaces all occurrences of placeholders in the // JSON string with their string representations. If the original value can // not be found, then `undefined` is used. PLACE_HOLDER_REGEXP.lastIndex = 0; return str.replace(PLACE_HOLDER_REGEXP, function (_, valueIndex) { return serialize(escapedValues[valueIndex], knownClasses); }); } } function serializeSet(value, knownClasses) { var valuesArray = []; value.forEach(function (v) { return valuesArray.push(serialize(v, knownClasses)); }); return "new Set([" + valuesArray.join(', ') + "])"; } function serializeMap(map, knownClasses) { var valuesArray = []; map.forEach(function (value, key) { return valuesArray.push("[" + serialize(key, knownClasses) + ", " + serialize(value, knownClasses) + "]"); }); return "new Map([" + valuesArray.join(', ') + "])"; } function serializeDate(value) { return "new Date(\"" + value.toISOString() + "\")"; } function serializeBuffer(value) { return "Buffer.from(" + serialize(value.toString('binary')) + ", \"binary\")"; } function serializeClassInstance(instance, knownClasses) { var constructor = instance.constructor; if (constructor.name.length) { var params = helpers_1.getParamList(constructor); var paramValues = params.map(function (param) { return serialize(instance[param], knownClasses); }); var newExpression = "new " + constructor.name + "(" + paramValues.join(', ') + ")"; return newExpression; } else { throw new Error("Cannot serialize instances of nameless classes (class was defined as: " + constructor.toString() + ")"); } } function serializeFunction(fn) { var serializedFn = fn.toString(); IS_NATIVE_CODE_REGEXP.lastIndex = 0; if (IS_NATIVE_CODE_REGEXP.test(serializedFn)) { throw new TypeError("Cannot serialize native function: " + fn.name); } return serializedFn; } //# sourceMappingURL=index.js.map