Repository navigation
Expand file tree
/
Copy pathordered-stringify.js
More file actions
99 lines (85 loc) · 2.77 KB
/
Copy pathordered-stringify.js
File metadata and controls
99 lines (85 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
'use strict';
/*
Like JSON.stringify, but allows you to specify the order of keys per-object.
Limitations:
- does not handle boxed primitives well
- replacer cannot be an array (an inherent limitation - replacer-as-array serves a similar purpose to this function)
*/
module.exports = function orderedKeysStringify(value, replacer, space, getKeys) {
if (typeof getKeys === 'undefined') {
return JSON.stringify(value, replacer, space);
}
if (typeof getKeys !== 'function') {
throw new TypeError('The getKeys argument to orderedKeysStringify must be undefined or a function');
}
if (Array.isArray(replacer)) {
throw new TypeError('orderedKeysStringify does not support an array as the replacer');
}
if (typeof replacer !== 'function') {
replacer = null;
}
// TODO support boxed primitives as space
let gap = '';
if (typeof space === 'number') {
for (let i = 0; i < ct; ++i) {
gap += ' ';
}
} else if (typeof space === 'string') {
if (space.length > 10) {
gap = space.substring(0, 10);
} else {
gap = space;
}
}
const seen = new WeakSet;
const colon = gap === '' ? ':' : ': ';
const linebreak = gap === '' ? '' : '\n';
return (function internalStringify(parent, key, node, currentIndent) {
if (node != null) {
const toJSON = node.toJSON;
if (typeof toJSON === 'function') {
node = toJSON.call(node, key);
}
}
if (replacer) {
node = replacer.call(parent, key, node);
}
if (typeof node !== 'object' || node === null) { // TODO also go this route for boxed primitives
return JSON.stringify(node);
}
if (seen.has(node)) {
throw new TypeError('Converting circular structure to JSON');
}
seen.add(node);
if (Array.isArray(node)) {
const out = [];
for (let i = 0; i < node.length; ++i) {
const v = node[i];
out.push(linebreak + currentIndent + gap + (internalStringify(node, i, v, currentIndent + gap) || 'null'));
}
seen.delete(node);
if (out.length === 0) {
return '[]';
}
return '[' + out.join(',') + linebreak + currentIndent + ']';
}
const keys = getKeys(node);
const out = [];
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
if (typeof key !== 'string') {
throw new TypeError('getKeys returned a key which is not string');
}
const valStr = internalStringify(node, key, node[key], currentIndent + gap);
if (valStr === void 0) {
continue;
}
out.push(linebreak + currentIndent + gap + JSON.stringify(key) + colon + valStr);
}
seen.delete(node);
if (out.length === 0) {
return '{}';
}
return '{' + out.join(',') + linebreak + currentIndent + '}';
})(null, '', value, '');
};