Skip to content

Commit 59c4a2c

Browse files
devon-wolfljharb
authored andcommitted
[New] add collapseEmpty option
New option to remove newlines in empty arrays and objects Fixes #15
1 parent cbe368f commit 59c4a2c

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ declare namespace stableStringify {
1010

1111
type StableStringifyOptions = {
1212
cmp?: Comparator;
13+
collapseEmpty?: boolean;
1314
cycles?: boolean;
1415
replacer?: (this: Node, key: Key, value: unknown) => unknown;
1516
space?: string | number;

index.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ module.exports = function stableStringify(obj) {
3434
var cycles = !!opts && typeof opts.cycles === 'boolean' && opts.cycles;
3535
/** @type {undefined | typeof defaultReplacer} */
3636
var replacer = opts && opts.replacer ? callBind(opts.replacer) : defaultReplacer;
37+
if (opts && typeof opts.collapseEmpty !== 'undefined' && typeof opts.collapseEmpty !== 'boolean') {
38+
throw new TypeError('`collapseEmpty` must be a boolean, if provided');
39+
}
40+
var collapseEmpty = !!opts && opts.collapseEmpty;
3741

3842
var cmpOpt = typeof opts === 'function' ? opts : opts && opts.cmp;
3943
/** @type {undefined | (<T extends import('.').NonArrayNode>(node: T) => (a: Exclude<keyof T, symbol | number>, b: Exclude<keyof T, symbol | number>) => number)} */
@@ -66,20 +70,27 @@ module.exports = function stableStringify(obj) {
6670
}
6771

6872
node = replacer(parent, key, node);
69-
7073
if (node === undefined) {
7174
return;
7275
}
7376
if (typeof node !== 'object' || node === null) {
7477
return jsonStringify(node);
7578
}
79+
80+
/** @type {(out: string[], brackets: '[]' | '{}') => string} */
81+
var groupOutput = function (out, brackets) {
82+
return collapseEmpty && out.length === 0
83+
? brackets
84+
: (brackets === '[]' ? '[' : '{') + $join(out, ',') + indent + (brackets === '[]' ? ']' : '}');
85+
};
86+
7687
if (isArray(node)) {
7788
var out = [];
7889
for (var i = 0; i < node.length; i++) {
7990
var item = stringify(node, i, node[i], level + 1) || jsonStringify(null);
8091
out[out.length] = indent + space + item;
8192
}
82-
return '[' + $join(out, ',') + indent + ']';
93+
return groupOutput(out, '[]');
8394
}
8495

8596
if ($indexOf(seen, node) !== -1) {
@@ -107,7 +118,7 @@ module.exports = function stableStringify(obj) {
107118
out[out.length] = indent + space + keyValue;
108119
}
109120
$splice(seen, $indexOf(seen, node), 1);
110-
return '{' + $join(out, ',') + indent + '}';
121+
return groupOutput(out, '{}');
111122
}({ '': obj }, '', obj, 0)
112123
);
113124
};

test/space.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,31 @@ test('space parameter (same as native)', function (t) {
7474
);
7575
});
7676

77+
test('space parameter base empty behavior: empty arrays and objects have added newline and space', function (t) {
78+
t.plan(1);
79+
var obj = { emptyArr: [], emptyObj: {} };
80+
t.equal(
81+
stringify(obj, { space: ' ' }),
82+
'{\n "emptyArr": [\n ],\n "emptyObj": {\n }\n}'
83+
);
84+
});
85+
86+
test('space parameter, with collapseEmpty: true', function (t) {
87+
t.plan(2);
88+
var obj = { emptyArr: [], emptyObj: {} };
89+
90+
t['throws'](
91+
// @ts-expect-error
92+
function () { stringify(obj, { collapseEmpty: 'not a boolean' }); },
93+
TypeError
94+
);
95+
96+
t.equal(
97+
stringify(obj, { collapseEmpty: true, space: ' ' }),
98+
'{\n "emptyArr": [],\n "emptyObj": {}\n}'
99+
);
100+
});
101+
77102
test('space parameter, on a cmp function', function (t) {
78103
t.plan(3);
79104
var obj = { one: 1, two: 2 };

0 commit comments

Comments
 (0)