91 lines
3.4 KiB
JavaScript
91 lines
3.4 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.stringify = void 0;
|
|
const stringify_1 = require("./stringify");
|
|
const quote_1 = require("./quote");
|
|
/**
|
|
* Root path node.
|
|
*/
|
|
const ROOT_SENTINEL = Symbol("root");
|
|
/**
|
|
* Stringify any JavaScript value.
|
|
*/
|
|
function stringify(value, replacer, indent, options = {}) {
|
|
const space = typeof indent === "string" ? indent : " ".repeat(indent || 0);
|
|
const path = [];
|
|
const stack = new Set();
|
|
const tracking = new Map();
|
|
const unpack = new Map();
|
|
let valueCount = 0;
|
|
const { maxDepth = 100, references = false, skipUndefinedProperties = false, maxValues = 100000, } = options;
|
|
// Wrap replacer function to support falling back on supported stringify.
|
|
const valueToString = replacerToString(replacer);
|
|
// Every time you call `next(value)` execute this function.
|
|
const onNext = (value, key) => {
|
|
if (++valueCount > maxValues)
|
|
return;
|
|
if (skipUndefinedProperties && value === undefined)
|
|
return;
|
|
if (path.length > maxDepth)
|
|
return;
|
|
// An undefined key is treated as an out-of-band "value".
|
|
if (key === undefined)
|
|
return valueToString(value, space, onNext, key);
|
|
path.push(key);
|
|
const result = builder(value, key === ROOT_SENTINEL ? undefined : key);
|
|
path.pop();
|
|
return result;
|
|
};
|
|
const builder = references
|
|
? (value, key) => {
|
|
if (value !== null &&
|
|
(typeof value === "object" ||
|
|
typeof value === "function" ||
|
|
typeof value === "symbol")) {
|
|
// Track nodes to restore later.
|
|
if (tracking.has(value)) {
|
|
unpack.set(path.slice(1), tracking.get(value));
|
|
// Use `undefined` as temporaray stand-in for referenced nodes
|
|
return valueToString(undefined, space, onNext, key);
|
|
}
|
|
// Track encountered nodes.
|
|
tracking.set(value, path.slice(1));
|
|
}
|
|
return valueToString(value, space, onNext, key);
|
|
}
|
|
: (value, key) => {
|
|
// Stop on recursion.
|
|
if (stack.has(value))
|
|
return;
|
|
stack.add(value);
|
|
const result = valueToString(value, space, onNext, key);
|
|
stack.delete(value);
|
|
return result;
|
|
};
|
|
const result = onNext(value, ROOT_SENTINEL);
|
|
// Attempt to restore circular references.
|
|
if (unpack.size) {
|
|
const sp = space ? " " : "";
|
|
const eol = space ? "\n" : "";
|
|
let wrapper = `var x${sp}=${sp}${result};${eol}`;
|
|
for (const [key, value] of unpack.entries()) {
|
|
const keyPath = quote_1.stringifyPath(key, onNext);
|
|
const valuePath = quote_1.stringifyPath(value, onNext);
|
|
wrapper += `x${keyPath}${sp}=${sp}x${valuePath};${eol}`;
|
|
}
|
|
return `(function${sp}()${sp}{${eol}${wrapper}return x;${eol}}())`;
|
|
}
|
|
return result;
|
|
}
|
|
exports.stringify = stringify;
|
|
/**
|
|
* Create `toString()` function from replacer.
|
|
*/
|
|
function replacerToString(replacer) {
|
|
if (!replacer)
|
|
return stringify_1.toString;
|
|
return (value, space, next, key) => {
|
|
return replacer(value, space, (value) => stringify_1.toString(value, space, next, key), key);
|
|
};
|
|
}
|
|
//# sourceMappingURL=index.js.map
|