jsoneo
Version:
A powerful JSON enhancement library that supports all JSON primitives, Date, RegExp, Symbol, Functions, Map, Set, TypedArray and much more! Almost everything in JavaScript.
145 lines • 7.52 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringify = stringify;
exports.parse = parse;
const consts_1 = require("./utils/consts");
const deserializedCode_1 = require("./utils/deserializedCode");
const expandPrototypeChain_1 = require("./utils/expandPrototypeChain");
const get_1 = require("./utils/get");
const serializeRecursively_1 = require("./utils/serializeRecursively");
const version_1 = require("./version");
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* Notes:
*
* 1. Do not use 'closure' in the function, the function body can be serialized but the closure
* reference can't. If it's a class, set the closures to the class properties, and use 'this' to
* access them. If it's a normal function, set the closures to the function reference, and use
* the function name to access them.
* 2. Do not use anonymous Symbols in both object keys and values. Use system predefined Symbols
* instead or use `Symbol.for` to create a Symbol. The anonymous Symbols can't be serialized and
* event cannot be created.
* 3. No direct or indirect circular references are allowed.
* 4. For classes, should avoid private properties and methods, because they are not accessible from
* outside and can't be serialized. Please use a normal property or method instead, and starts
* with `_` to indicate it's a private member. If you are using TypeScript, you can use the
* `private` keyword to declare as private, which looks a little better.
* 5. Class constructors will be dropped.
* 6. All native methods will be dropped, as `toString` method just returns `[native code]`.
* 7. Do not use `function.bind`, because the bound functions become native methods.
* 8. Respect `toJSON` and `fromJSON` method, if the object has a `toJSON` method, it will be called to
* get the serialized value. If the object has a `fromJSON` method, it will be called with
* serialized json to restore the original value.
* 9. Make sure you trust the source of the serialized string, because the deserialization need to
* evaluate script codes. A carefully crafted strings may embed malicious code, thus posing a
* security threat.
* 10. Buffer is supported in Node.js environment, and will be converted to Uint8Array in web browsers.
*/
/**
* Advantages:
*
* 1. Supports serialization of complex JavaScript objects, including functions and prototypes.
* 2. Supports serialization of Map, Set, ArrayBuffer, DataView, and other complex types.
* 3. Supports serialization of circular references.
* 4. Supports serialization of Symbol keys and values.
* 5. Supports serialization of custom property descriptors.
* 6. Supports serialization of non-enumerable properties.
* 7. Supports toJSON and fromJSON methods for custom serialization and deserialization.
* 8. Supports raw JSON objects (via JSON.rawJSON() method).
*/
/**
* Serialize JavaScript object to string, support functions. Should including all fields of both
* object and prototype.
*
* @param {any} value - The value to serialize.
*
* @returns The serialized string.
*/
function stringify(value, options) {
var _a, _b;
const { debug, preserveDescriptors = true } = options !== null && options !== void 0 ? options : {};
const patches = [];
const descriptors = [];
const types = [];
const circular = new WeakMap();
const refs = [];
const apis = [];
const source = (0, expandPrototypeChain_1.expandPrototypeChain)(value, Object.assign(Object.assign({}, options), { patches, descriptors, types, apis, circular, refs }));
const serialized = (0, serializeRecursively_1.serializeRecursively)(source, Object.assign(Object.assign({}, options), { parentPath: [] }));
const result = {
startTag: (_a = options === null || options === void 0 ? void 0 : options.startTag) !== null && _a !== void 0 ? _a : consts_1.DefaultStartTag,
endTag: (_b = options === null || options === void 0 ? void 0 : options.endTag) !== null && _b !== void 0 ? _b : consts_1.DefaultEndTag,
version: version_1.version,
source: JSON.stringify(serialized),
patches: (0, serializeRecursively_1.serializeRecursively)(patches, {
parentPath: [],
debug,
printLabel: 'patches',
printPath: (options) => {
var _a, _b;
const index = Number((_a = options.parentPath) === null || _a === void 0 ? void 0 : _a[0]);
if (index >= 0) {
const patch = patches[index];
return ['.patches', ...patch.path, options.key === 'path' ? '[path]' : options.key];
}
return ['.patches', ...((_b = options.parentPath) !== null && _b !== void 0 ? _b : []), options.key];
},
}),
types,
apis,
refs,
};
if (preserveDescriptors) {
result.descriptors = descriptors;
}
if (debug) {
console.log('------------------ stringify ', ['.types'], ' ------------------');
console.log(types);
console.log('------------------ stringify ', ['.patches'], ' ------------------');
console.log(patches);
if (preserveDescriptors) {
console.log('------------------ stringify ', ['.descriptors'], ' ------------------');
}
console.log(descriptors);
console.log('------------------ stringify ', ['.refs'], ' ------------------');
console.log(refs);
console.log('------------------ stringify ', ['FINAL'], ' ------------------');
console.log(JSON.stringify(serialized));
}
return JSON.stringify(result);
}
/**
* Deserialize JavaScript object from string, support functions. Should including all fields of both
* object and prototype.
*
* @param {string} input - The string to deserialize.
* @param {object} options - The options to deserialize.
* @param {function} [options.closure] - The closure to use when deserializing the object.
*
* @returns The deserialized object.
*/
function parse(input, options) {
const { closure, get = get_1.getByPath, debug, prettyPrint = true } = options !== null && options !== void 0 ? options : {};
if (!input) {
return undefined;
}
const inputResult = JSON.parse(input);
if (inputResult.source === undefined) {
return undefined;
}
// return deserialize(inputResult, { ...options, closure });
const { variablePrefix: VP = consts_1.VariablePrefix } = inputResult;
const code = (0, deserializedCode_1.deserializedCode)(inputResult, options !== null && options !== void 0 ? options : {});
if (debug) {
const printSourceCode = (0, deserializedCode_1.deserializedCode)(inputResult, Object.assign(Object.assign({}, options), { isPrinting: true }));
const prettyPrintCode = `\`${printSourceCode.replace(/`/g, '\\`').replace(/\$\{/g, '\\${')}\``;
const realCode = `'${printSourceCode.replace(/\n/g, '\\n').replace(/'/g, "\\'")}'`;
const printCode = prettyPrint ? prettyPrintCode : realCode;
console.log('------------------ deserialize ------------------');
console.log(`new Function('${VP}context', '${VP}options', ${printCode})(${closure ? 'closure' : 'undefined'}, { get: getByPath });
${get_1.getByPath.toString()}
`, 'closure =', closure);
}
return new Function(`${VP}context`, `${VP}options`, code)(closure, { get });
}
//# sourceMappingURL=../../src/index.js.map