Skip to content

Commit 1abc613

Browse files
committed
util: properly indent special properties
Calling `formatValue()` directly requires the indentation level to be set manually. This was not the case so far in most cases and the indentation was off in all these cases. PR-URL: nodejs#22291 Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 59c8abf commit 1abc613

File tree

2 files changed

+130
-11
lines changed

2 files changed

+130
-11
lines changed

lib/util.js

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,9 @@ function findTypedConstructor(value) {
543543

544544
const getBoxedValue = formatPrimitive.bind(null, stylizeNoColor);
545545

546+
// Note: using `formatValue` directly requires the indentation level to be
547+
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
548+
// value afterwards again.
546549
function formatValue(ctx, value, recurseTimes) {
547550
// Primitive types cannot have properties
548551
if (typeof value !== 'object' && typeof value !== 'function') {
@@ -1063,17 +1066,18 @@ function formatTypedArray(ctx, value, recurseTimes, keys) {
10631066
output[i] = `... ${remaining} more item${remaining > 1 ? 's' : ''}`;
10641067
if (ctx.showHidden) {
10651068
// .buffer goes last, it's not a primitive like the others.
1066-
const extraKeys = [
1069+
ctx.indentationLvl += 2;
1070+
for (const key of [
10671071
'BYTES_PER_ELEMENT',
10681072
'length',
10691073
'byteLength',
10701074
'byteOffset',
10711075
'buffer'
1072-
];
1073-
for (i = 0; i < extraKeys.length; i++) {
1074-
const str = formatValue(ctx, value[extraKeys[i]], recurseTimes);
1075-
output.push(`[${extraKeys[i]}]: ${str}`);
1076+
]) {
1077+
const str = formatValue(ctx, value[key], recurseTimes);
1078+
output.push(`[${key}]: ${str}`);
10761079
}
1080+
ctx.indentationLvl -= 2;
10771081
}
10781082
// TypedArrays cannot have holes. Therefore it is safe to assume that all
10791083
// extra keys are indexed after value.length.
@@ -1086,8 +1090,11 @@ function formatTypedArray(ctx, value, recurseTimes, keys) {
10861090
function formatSet(ctx, value, recurseTimes, keys) {
10871091
const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
10881092
let i = 0;
1089-
for (const v of value)
1093+
ctx.indentationLvl += 2;
1094+
for (const v of value) {
10901095
output[i++] = formatValue(ctx, v, recurseTimes);
1096+
}
1097+
ctx.indentationLvl -= 2;
10911098
// With `showHidden`, `length` will display as a hidden property for
10921099
// arrays. For consistency's sake, do the same for `size`, even though this
10931100
// property isn't selected by Object.getOwnPropertyNames().
@@ -1102,9 +1109,12 @@ function formatSet(ctx, value, recurseTimes, keys) {
11021109
function formatMap(ctx, value, recurseTimes, keys) {
11031110
const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
11041111
let i = 0;
1105-
for (const [k, v] of value)
1112+
ctx.indentationLvl += 2;
1113+
for (const [k, v] of value) {
11061114
output[i++] = `${formatValue(ctx, k, recurseTimes)} => ` +
1107-
formatValue(ctx, v, recurseTimes);
1115+
formatValue(ctx, v, recurseTimes);
1116+
}
1117+
ctx.indentationLvl -= 2;
11081118
// See comment in formatSet
11091119
if (ctx.showHidden)
11101120
output[i++] = `[size]: ${ctx.stylize(`${value.size}`, 'number')}`;
@@ -1118,8 +1128,11 @@ function formatSetIterInner(ctx, value, recurseTimes, keys, entries, state) {
11181128
const maxArrayLength = Math.max(ctx.maxArrayLength, 0);
11191129
const maxLength = Math.min(maxArrayLength, entries.length);
11201130
let output = new Array(maxLength);
1121-
for (var i = 0; i < maxLength; ++i)
1131+
ctx.indentationLvl += 2;
1132+
for (var i = 0; i < maxLength; i++) {
11221133
output[i] = formatValue(ctx, entries[i], recurseTimes);
1134+
}
1135+
ctx.indentationLvl -= 2;
11231136
if (state === kWeak) {
11241137
// Sort all entries to have a halfway reliable output (if more entries than
11251138
// retrieved ones exist, we can not reliably return the same output).
@@ -1150,11 +1163,13 @@ function formatMapIterInner(ctx, value, recurseTimes, keys, entries, state) {
11501163
end = ' ]';
11511164
middle = ', ';
11521165
}
1166+
ctx.indentationLvl += 2;
11531167
for (; i < maxLength; i++) {
11541168
const pos = i * 2;
11551169
output[i] = `${start}${formatValue(ctx, entries[pos], recurseTimes)}` +
11561170
`${middle}${formatValue(ctx, entries[pos + 1], recurseTimes)}${end}`;
11571171
}
1172+
ctx.indentationLvl -= 2;
11581173
if (state === kWeak) {
11591174
// Sort all entries to have a halfway reliable output (if more entries
11601175
// than retrieved ones exist, we can not reliably return the same output).
@@ -1199,7 +1214,11 @@ function formatPromise(ctx, value, recurseTimes, keys) {
11991214
if (state === kPending) {
12001215
output = ['<pending>'];
12011216
} else {
1217+
// Using `formatValue` is correct here without the need to fix the
1218+
// indentation level.
1219+
ctx.indentationLvl += 2;
12021220
const str = formatValue(ctx, result, recurseTimes);
1221+
ctx.indentationLvl -= 2;
12031222
output = [state === kRejected ? `<rejected> ${str}` : str];
12041223
}
12051224
for (var n = 0; n < keys.length; n++) {

test/parallel/test-util-inspect.js

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ for (const showHidden of [true, false]) {
179179
' y: 1337 }');
180180
}
181181

182-
183182
[ Float32Array,
184183
Float64Array,
185184
Int16Array,
@@ -195,7 +194,7 @@ for (const showHidden of [true, false]) {
195194
array[0] = 65;
196195
array[1] = 97;
197196
assert.strictEqual(
198-
util.inspect(array, true),
197+
util.inspect(array, { showHidden: true }),
199198
`${constructor.name} [\n` +
200199
' 65,\n' +
201200
' 97,\n' +
@@ -1362,6 +1361,107 @@ util.inspect(process);
13621361
assert.strictEqual(out, expect);
13631362
}
13641363

1364+
// Check compact indentation.
1365+
{
1366+
const typed = new Uint8Array();
1367+
typed.buffer.foo = true;
1368+
const set = new Set([[1, 2]]);
1369+
const promise = Promise.resolve([[1, set]]);
1370+
const map = new Map([[promise, typed]]);
1371+
map.set(set.values(), map.values());
1372+
1373+
let out = util.inspect(map, { compact: false, showHidden: true, depth: 9 });
1374+
let expected = [
1375+
'Map {',
1376+
' Promise {',
1377+
' [',
1378+
' [',
1379+
' 1,',
1380+
' Set {',
1381+
' [',
1382+
' 1,',
1383+
' 2,',
1384+
' [length]: 2',
1385+
' ],',
1386+
' [size]: 1',
1387+
' },',
1388+
' [length]: 2',
1389+
' ],',
1390+
' [length]: 1',
1391+
' ]',
1392+
' } => Uint8Array [',
1393+
' [BYTES_PER_ELEMENT]: 1,',
1394+
' [length]: 0,',
1395+
' [byteLength]: 0,',
1396+
' [byteOffset]: 0,',
1397+
' [buffer]: ArrayBuffer {',
1398+
' byteLength: 0,',
1399+
' foo: true',
1400+
' }',
1401+
' ],',
1402+
' [Set Iterator] {',
1403+
' [',
1404+
' 1,',
1405+
' 2,',
1406+
' [length]: 2',
1407+
' ]',
1408+
' } => [Map Iterator] {',
1409+
' Uint8Array [',
1410+
' [BYTES_PER_ELEMENT]: 1,',
1411+
' [length]: 0,',
1412+
' [byteLength]: 0,',
1413+
' [byteOffset]: 0,',
1414+
' [buffer]: ArrayBuffer {',
1415+
' byteLength: 0,',
1416+
' foo: true',
1417+
' }',
1418+
' ],',
1419+
' [Circular]',
1420+
' },',
1421+
' [size]: 2',
1422+
'}'
1423+
].join('\n');
1424+
1425+
assert.strict.equal(out, expected);
1426+
1427+
out = util.inspect(map, { showHidden: true, depth: 9, breakLength: 4 });
1428+
expected = [
1429+
'Map {',
1430+
' Promise {',
1431+
' [ [ 1,',
1432+
' Set {',
1433+
' [ 1,',
1434+
' 2,',
1435+
' [length]: 2 ],',
1436+
' [size]: 1 },',
1437+
' [length]: 2 ],',
1438+
' [length]: 1 ] } => Uint8Array [',
1439+
' [BYTES_PER_ELEMENT]: 1,',
1440+
' [length]: 0,',
1441+
' [byteLength]: 0,',
1442+
' [byteOffset]: 0,',
1443+
' [buffer]: ArrayBuffer {',
1444+
' byteLength: 0,',
1445+
' foo: true } ],',
1446+
' [Set Iterator] {',
1447+
' [ 1,',
1448+
' 2,',
1449+
' [length]: 2 ] } => [Map Iterator] {',
1450+
' Uint8Array [',
1451+
' [BYTES_PER_ELEMENT]: 1,',
1452+
' [length]: 0,',
1453+
' [byteLength]: 0,',
1454+
' [byteOffset]: 0,',
1455+
' [buffer]: ArrayBuffer {',
1456+
' byteLength: 0,',
1457+
' foo: true } ],',
1458+
' [Circular] },',
1459+
' [size]: 2 }'
1460+
].join('\n');
1461+
1462+
assert.strict.equal(out, expected);
1463+
}
1464+
13651465
{ // Test WeakMap
13661466
const obj = {};
13671467
const arr = [];

0 commit comments

Comments
 (0)