index.js 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.stringify = void 0;
  4. const stringify_1 = require("./stringify");
  5. const quote_1 = require("./quote");
  6. /**
  7. * Root path node.
  8. */
  9. const ROOT_SENTINEL = Symbol("root");
  10. /**
  11. * Stringify any JavaScript value.
  12. */
  13. function stringify(value, replacer, indent, options = {}) {
  14. const space = typeof indent === "string" ? indent : " ".repeat(indent || 0);
  15. const path = [];
  16. const stack = new Set();
  17. const tracking = new Map();
  18. const unpack = new Map();
  19. let valueCount = 0;
  20. const { maxDepth = 100, references = false, skipUndefinedProperties = false, maxValues = 100000, } = options;
  21. // Wrap replacer function to support falling back on supported stringify.
  22. const valueToString = replacerToString(replacer);
  23. // Every time you call `next(value)` execute this function.
  24. const onNext = (value, key) => {
  25. if (++valueCount > maxValues)
  26. return;
  27. if (skipUndefinedProperties && value === undefined)
  28. return;
  29. if (path.length > maxDepth)
  30. return;
  31. // An undefined key is treated as an out-of-band "value".
  32. if (key === undefined)
  33. return valueToString(value, space, onNext, key);
  34. path.push(key);
  35. const result = builder(value, key === ROOT_SENTINEL ? undefined : key);
  36. path.pop();
  37. return result;
  38. };
  39. const builder = references
  40. ? (value, key) => {
  41. if (value !== null &&
  42. (typeof value === "object" ||
  43. typeof value === "function" ||
  44. typeof value === "symbol")) {
  45. // Track nodes to restore later.
  46. if (tracking.has(value)) {
  47. unpack.set(path.slice(1), tracking.get(value));
  48. // Use `undefined` as temporaray stand-in for referenced nodes
  49. return valueToString(undefined, space, onNext, key);
  50. }
  51. // Track encountered nodes.
  52. tracking.set(value, path.slice(1));
  53. }
  54. return valueToString(value, space, onNext, key);
  55. }
  56. : (value, key) => {
  57. // Stop on recursion.
  58. if (stack.has(value))
  59. return;
  60. stack.add(value);
  61. const result = valueToString(value, space, onNext, key);
  62. stack.delete(value);
  63. return result;
  64. };
  65. const result = onNext(value, ROOT_SENTINEL);
  66. // Attempt to restore circular references.
  67. if (unpack.size) {
  68. const sp = space ? " " : "";
  69. const eol = space ? "\n" : "";
  70. let wrapper = `var x${sp}=${sp}${result};${eol}`;
  71. for (const [key, value] of unpack.entries()) {
  72. const keyPath = quote_1.stringifyPath(key, onNext);
  73. const valuePath = quote_1.stringifyPath(value, onNext);
  74. wrapper += `x${keyPath}${sp}=${sp}x${valuePath};${eol}`;
  75. }
  76. return `(function${sp}()${sp}{${eol}${wrapper}return x;${eol}}())`;
  77. }
  78. return result;
  79. }
  80. exports.stringify = stringify;
  81. /**
  82. * Create `toString()` function from replacer.
  83. */
  84. function replacerToString(replacer) {
  85. if (!replacer)
  86. return stringify_1.toString;
  87. return (value, space, next, key) => {
  88. return replacer(value, space, (value) => stringify_1.toString(value, space, next, key), key);
  89. };
  90. }
  91. //# sourceMappingURL=index.js.map