UNPKG

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
"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