Skip to content

Commit 4500ed8

Browse files
BridgeARaddaleax
authored andcommitted
util: add compact depth mode
This overloads the `compact` option from `util.inspect()`. If it's set to a number, it is going to align all most inner entries on the same lign if they adhere to the following: * The entries do not exceed the `breakLength` options value. * The entry is one of the local most inner levels up the the one provided in `compact`. PR-URL: #26269 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent 7bf6309 commit 4500ed8

File tree

3 files changed

+71
-14
lines changed

3 files changed

+71
-14
lines changed

doc/api/util.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ stream.write('With ES6');
375375
<!-- YAML
376376
added: v0.3.0
377377
changes:
378+
- version: REPLACEME
379+
pr-url: https://github.com/nodejs/node/pull/26269
380+
description: The `compact` option accepts numbers for a new output mode.
378381
- version: v11.7.0
379382
pr-url: https://github.com/nodejs/node/pull/25006
380383
description: ArrayBuffers now also show their binary contents.
@@ -444,11 +447,13 @@ changes:
444447
* `breakLength` {integer} The length at which an object's keys are split
445448
across multiple lines. Set to `Infinity` to format an object as a single
446449
line. **Default:** `60` for legacy compatibility.
447-
* `compact` {boolean} Setting this to `false` causes each object key to
448-
be displayed on a new line. It will also add new lines to text that is
449-
longer than `breakLength`. Note that no text will be reduced below 16
450-
characters, no matter the `breakLength` size. For more information, see the
451-
example below. **Default:** `true`.
450+
* `compact` {boolean|integer} Setting this to `false` causes each object key
451+
to be displayed on a new line. It will also add new lines to text that is
452+
longer than `breakLength`. If set to a number, the most `n` inner elements
453+
are united on a single line as long as all properties fit into
454+
`breakLength`. Note that no text will be reduced below 16 characters, no
455+
matter the `breakLength` size. For more information, see the example below.
456+
**Default:** `true`.
452457
* `sorted` {boolean|Function} If set to `true` or a function, all properties
453458
of an object, and `Set` and `Map` entries are sorted in the resulting
454459
string. If set to `true` the [default sort][] is used. If set to a function,

lib/internal/util/inspect.js

+25-9
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ function inspect(value, opts) {
159159
budget: {},
160160
indentationLvl: 0,
161161
seen: [],
162+
currentDepth: 0,
162163
stylize: stylizeNoColor,
163164
showHidden: inspectDefaultOptions.showHidden,
164165
depth: inspectDefaultOptions.depth,
@@ -760,6 +761,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
760761
recurseTimes += 1;
761762

762763
ctx.seen.push(value);
764+
ctx.currentDepth = recurseTimes;
763765
let output;
764766
const indentationLvl = ctx.indentationLvl;
765767
try {
@@ -783,7 +785,10 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
783785
}
784786
}
785787

786-
const res = reduceToSingleString(ctx, output, base, braces);
788+
const combine = typeof ctx.compact === 'number' &&
789+
ctx.currentDepth - recurseTimes < ctx.compact;
790+
791+
const res = reduceToSingleString(ctx, output, base, braces, combine);
787792
const budget = ctx.budget[ctx.indentationLvl] || 0;
788793
const newLength = budget + res.length;
789794
ctx.budget[ctx.indentationLvl] = newLength;
@@ -824,7 +829,7 @@ function formatBigInt(fn, value) {
824829

825830
function formatPrimitive(fn, value, ctx) {
826831
if (typeof value === 'string') {
827-
if (ctx.compact === false &&
832+
if (ctx.compact !== true &&
828833
ctx.indentationLvl + value.length > ctx.breakLength &&
829834
value.length > kMinLineLength) {
830835
const rawMaxLineLength = ctx.breakLength - ctx.indentationLvl;
@@ -1134,7 +1139,7 @@ function formatProperty(ctx, value, recurseTimes, key, type) {
11341139
const desc = Object.getOwnPropertyDescriptor(value, key) ||
11351140
{ value: value[key], enumerable: true };
11361141
if (desc.value !== undefined) {
1137-
const diff = (type !== kObjectType || ctx.compact === false) ? 2 : 3;
1142+
const diff = (type !== kObjectType || ctx.compact !== true) ? 2 : 3;
11381143
ctx.indentationLvl += diff;
11391144
str = formatValue(ctx, desc.value, recurseTimes);
11401145
if (diff === 3) {
@@ -1191,16 +1196,27 @@ function formatProperty(ctx, value, recurseTimes, key, type) {
11911196
return `${name}:${extra}${str}`;
11921197
}
11931198

1194-
function reduceToSingleString(ctx, output, base, braces) {
1199+
function reduceToSingleString(ctx, output, base, braces, combine = false) {
11951200
const breakLength = ctx.breakLength;
11961201
let i = 0;
1197-
if (ctx.compact === false) {
1198-
const indentation = ' '.repeat(ctx.indentationLvl);
1199-
let res = `${base ? `${base} ` : ''}${braces[0]}\n${indentation} `;
1202+
if (ctx.compact !== true) {
1203+
if (combine) {
1204+
const totalLength = output.reduce((sum, cur) => sum + cur.length, 0);
1205+
if (totalLength + output.length * 2 < breakLength) {
1206+
let res = `${base ? `${base} ` : ''}${braces[0]} `;
1207+
for (; i < output.length - 1; i++) {
1208+
res += `${output[i]}, `;
1209+
}
1210+
res += `${output[i]} ${braces[1]}`;
1211+
return res;
1212+
}
1213+
}
1214+
const indentation = `\n${' '.repeat(ctx.indentationLvl)}`;
1215+
let res = `${base ? `${base} ` : ''}${braces[0]}${indentation} `;
12001216
for (; i < output.length - 1; i++) {
1201-
res += `${output[i]},\n${indentation} `;
1217+
res += `${output[i]},${indentation} `;
12021218
}
1203-
res += `${output[i]}\n${indentation}${braces[1]}`;
1219+
res += `${output[i]}${indentation}${braces[1]}`;
12041220
return res;
12051221
}
12061222
if (output.length * 2 <= breakLength) {

test/parallel/test-util-inspect.js

+36
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,42 @@ util.inspect(process);
14861486

14871487
assert.strict.equal(out, expected);
14881488

1489+
out = util.inspect(map, { compact: 2, showHidden: true, depth: 9 });
1490+
1491+
expected = [
1492+
'Map {',
1493+
' Promise {',
1494+
' [',
1495+
' [',
1496+
' 1,',
1497+
' Set { [ 1, 2, [length]: 2 ], [size]: 1 },',
1498+
' [length]: 2',
1499+
' ],',
1500+
' [length]: 1',
1501+
' ]',
1502+
' } => Uint8Array [',
1503+
' [BYTES_PER_ELEMENT]: 1,',
1504+
' [length]: 0,',
1505+
' [byteLength]: 0,',
1506+
' [byteOffset]: 0,',
1507+
' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
1508+
' ],',
1509+
' [Set Iterator] { [ 1, 2, [length]: 2 ] } => [Map Iterator] {',
1510+
' Uint8Array [',
1511+
' [BYTES_PER_ELEMENT]: 1,',
1512+
' [length]: 0,',
1513+
' [byteLength]: 0,',
1514+
' [byteOffset]: 0,',
1515+
' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
1516+
' ],',
1517+
' [Circular]',
1518+
' },',
1519+
' [size]: 2',
1520+
'}'
1521+
].join('\n');
1522+
1523+
assert.strict.equal(out, expected);
1524+
14891525
out = util.inspect(map, { showHidden: true, depth: 9, breakLength: 4 });
14901526
expected = [
14911527
'Map {',

0 commit comments

Comments
 (0)