1 | 'use strict';
|
2 |
|
3 |
|
4 | var jsonStringify = (typeof JSON !== 'undefined' ? JSON : require('jsonify')).stringify;
|
5 |
|
6 | var isArray = require('isarray');
|
7 | var objectKeys = require('object-keys');
|
8 | var callBind = require('call-bind');
|
9 | var callBound = require('call-bound');
|
10 |
|
11 | var $join = callBound('Array.prototype.join');
|
12 | var $indexOf = callBound('Array.prototype.indexOf');
|
13 | var $splice = callBound('Array.prototype.splice');
|
14 | var $sort = callBound('Array.prototype.sort');
|
15 |
|
16 |
|
17 | var strRepeat = function repeat(n, char) {
|
18 | var str = '';
|
19 | for (var i = 0; i < n; i += 1) {
|
20 | str += char;
|
21 | }
|
22 | return str;
|
23 | };
|
24 |
|
25 |
|
26 | var defaultReplacer = function (_parent, _key, value) { return value; };
|
27 |
|
28 |
|
29 | module.exports = function stableStringify(obj) {
|
30 |
|
31 | var opts = arguments.length > 1 ? arguments[1] : void undefined;
|
32 | var space = (opts && opts.space) || '';
|
33 | if (typeof space === 'number') { space = strRepeat(space, ' '); }
|
34 | var cycles = !!opts && typeof opts.cycles === 'boolean' && opts.cycles;
|
35 |
|
36 | var replacer = opts && opts.replacer ? callBind(opts.replacer) : defaultReplacer;
|
37 |
|
38 | var cmpOpt = typeof opts === 'function' ? opts : opts && opts.cmp;
|
39 |
|
40 | var cmp = cmpOpt && function (node) {
|
41 |
|
42 | var get = /** @type {NonNullable<typeof cmpOpt>} */ (cmpOpt).length > 2
|
43 | && function get(k) { return node[k]; };
|
44 | return function (a, b) {
|
45 |
|
46 | return (cmpOpt)(
|
47 | { key: a, value: node[a] },
|
48 | { key: b, value: node[b] },
|
49 |
|
50 | get ? /** @type {import('.').Getter} */ { __proto__: null, get: get } : void undefined
|
51 | );
|
52 | };
|
53 | };
|
54 |
|
55 |
|
56 | var seen = [];
|
57 | return (/** @type {(parent: import('.').Node, key: string | number, node: unknown, level: number) => string | undefined} */
|
58 | function stringify(parent, key, node, level) {
|
59 | var indent = space ? '\n' + strRepeat(level, space) : '';
|
60 | var colonSeparator = space ? ': ' : ':';
|
61 |
|
62 | // eslint-disable-next-line no-extra-parens
|
63 | if (node && /** @type {{ toJSON?: unknown }} */ (node).toJSON && typeof /** @type {{ toJSON?: unknown }} */ (node).toJSON === 'function') {
|
64 | // eslint-disable-next-line no-extra-parens
|
65 | node = /** @type {{ toJSON: Function }} */ (node).toJSON();
|
66 | }
|
67 |
|
68 | node = replacer(parent, key, node);
|
69 |
|
70 | if (node === undefined) {
|
71 | return;
|
72 | }
|
73 | if (typeof node !== 'object' || node === null) {
|
74 | return jsonStringify(node);
|
75 | }
|
76 | if (isArray(node)) {
|
77 | var out = [];
|
78 | for (var i = 0; i < node.length; i++) {
|
79 | var item = stringify(node, i, node[i], level + 1) || jsonStringify(null);
|
80 | out[out.length] = indent + space + item;
|
81 | }
|
82 | return '[' + $join(out, ',') + indent + ']';
|
83 | }
|
84 |
|
85 | if ($indexOf(seen, node) !== -1) {
|
86 | if (cycles) { return jsonStringify('__cycle__'); }
|
87 | throw new TypeError('Converting circular structure to JSON');
|
88 | } else {
|
89 | seen[seen.length] = /** @type {import('.').NonArrayNode} */ (node);
|
90 | }
|
91 |
|
92 | /** @type {import('.').Key[]} */
|
93 | // eslint-disable-next-line no-extra-parens
|
94 | var keys = $sort(objectKeys(node), cmp && cmp(/** @type {import('.').NonArrayNode} */ (node)));
|
95 | var out = [];
|
96 | for (var i = 0; i < keys.length; i++) {
|
97 | var key = keys[i];
|
98 | // eslint-disable-next-line no-extra-parens
|
99 | var value = stringify(/** @type {import('.').Node} */ (node), key, /** @type {import('.').NonArrayNode} */ (node)[key], level + 1);
|
100 |
|
101 | if (!value) { continue; }
|
102 |
|
103 | var keyValue = jsonStringify(key)
|
104 | + colonSeparator
|
105 | + value;
|
106 |
|
107 | out[out.length] = indent + space + keyValue;
|
108 | }
|
109 | $splice(seen, $indexOf(seen, node), 1);
|
110 | return '{' + $join(out, ',') + indent + '}';
|
111 | }({ '': obj }, '', obj, 0)
|
112 | );
|
113 | };
|
114 |
|
\ | No newline at end of file |