Skip to content

Commit a218a8a

Browse files
committed
Set newline and indentation to defaults for empty objects/arrays
Noticed that in my tests when I do "echo {} > package.json", I was then getting an unformatted package.json after doing installs, which is unexpected. Treat empty objects as if they had the default indentation, since that is the result "JSON.stringify({}, null, 2)".
1 parent c680f17 commit a218a8a

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

index.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ const kIndent = Symbol.for('indent')
6666
const kNewline = Symbol.for('newline')
6767
// only respect indentation if we got a line break, otherwise squash it
6868
// things other than objects and arrays aren't indented, so ignore those
69+
// Important: in both of these regexps, the $1 capture group is the newline
70+
// or undefined, and the $2 capture group is the indent, or undefined.
6971
const formatRE = /^\s*[{\[]((?:\r?\n)+)([\s\t]*)/
72+
const emptyRE = /^(?:\{\}|\[\])((?:\r?\n)+)?$/
7073

7174
const parseJson = (txt, reviver, context) => {
7275
const parseText = stripBOM(txt)
@@ -77,7 +80,11 @@ const parseJson = (txt, reviver, context) => {
7780
// otherwise, pick the indentation of the next line after the first \n
7881
// If the pattern doesn't match, then it means no indentation.
7982
// JSON.stringify ignores symbols, so this is reasonably safe.
80-
const [, newline, indent] = parseText.match(formatRE) || [, '', '']
83+
// if the string is '{}' or '[]', then use the default 2-space indent.
84+
const [, newline = '\n', indent = ' '] = parseText.match(emptyRE) ||
85+
parseText.match(formatRE) ||
86+
[, '', '']
87+
8188
const result = JSON.parse(parseText, reviver)
8289
if (result && typeof result === 'object') {
8390
result[kNewline] = newline

test/index.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@ t.test('preserves indentation and newline styles', t => {
4747
t.end()
4848
})
4949

50+
t.test('indentation is the default when object/array is empty', t => {
51+
const kIndent = Symbol.for('indent')
52+
const kNewline = Symbol.for('newline')
53+
const obj = '{}'
54+
const arr = '[]'
55+
for (const newline of ['', '\n', '\r\n', '\n\n', '\r\n\r\n']) {
56+
const expect = newline || '\n'
57+
for (const str of [obj, arr]) {
58+
t.test(JSON.stringify({str, newline, expect}), t => {
59+
const res = parseJson(str + newline)
60+
t.equal(res[kNewline], expect, 'got expected newline')
61+
t.equal(res[kIndent], ' ', 'got expected default indentation')
62+
t.end()
63+
})
64+
}
65+
}
66+
t.end()
67+
})
68+
5069
t.test('parses JSON if it is a Buffer, removing BOM bytes', t => {
5170
const str = JSON.stringify({
5271
foo: 1,

0 commit comments

Comments
 (0)