Skip to content

Commit

Permalink
util: add compact depth mode
Browse files Browse the repository at this point in the history
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 <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
  • Loading branch information
BridgeAR authored and addaleax committed Mar 1, 2019
1 parent 7bf6309 commit 4500ed8
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 14 deletions.
15 changes: 10 additions & 5 deletions doc/api/util.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ stream.write('With ES6');
<!-- YAML
added: v0.3.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/26269
description: The `compact` option accepts numbers for a new output mode.
- version: v11.7.0
pr-url: https://github.com/nodejs/node/pull/25006
description: ArrayBuffers now also show their binary contents.
Expand Down Expand Up @@ -444,11 +447,13 @@ changes:
* `breakLength` {integer} The length at which an object's keys are split
across multiple lines. Set to `Infinity` to format an object as a single
line. **Default:** `60` for legacy compatibility.
* `compact` {boolean} Setting this to `false` causes each object key to
be displayed on a new line. It will also add new lines to text that is
longer than `breakLength`. Note that no text will be reduced below 16
characters, no matter the `breakLength` size. For more information, see the
example below. **Default:** `true`.
* `compact` {boolean|integer} Setting this to `false` causes each object key
to be displayed on a new line. It will also add new lines to text that is
longer than `breakLength`. If set to a number, the most `n` inner elements
are united on a single line as long as all properties fit into
`breakLength`. Note that no text will be reduced below 16 characters, no
matter the `breakLength` size. For more information, see the example below.
**Default:** `true`.
* `sorted` {boolean|Function} If set to `true` or a function, all properties
of an object, and `Set` and `Map` entries are sorted in the resulting
string. If set to `true` the [default sort][] is used. If set to a function,
Expand Down
34 changes: 25 additions & 9 deletions lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ function inspect(value, opts) {
budget: {},
indentationLvl: 0,
seen: [],
currentDepth: 0,
stylize: stylizeNoColor,
showHidden: inspectDefaultOptions.showHidden,
depth: inspectDefaultOptions.depth,
Expand Down Expand Up @@ -760,6 +761,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
recurseTimes += 1;

ctx.seen.push(value);
ctx.currentDepth = recurseTimes;
let output;
const indentationLvl = ctx.indentationLvl;
try {
Expand All @@ -783,7 +785,10 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
}
}

const res = reduceToSingleString(ctx, output, base, braces);
const combine = typeof ctx.compact === 'number' &&
ctx.currentDepth - recurseTimes < ctx.compact;

const res = reduceToSingleString(ctx, output, base, braces, combine);
const budget = ctx.budget[ctx.indentationLvl] || 0;
const newLength = budget + res.length;
ctx.budget[ctx.indentationLvl] = newLength;
Expand Down Expand Up @@ -824,7 +829,7 @@ function formatBigInt(fn, value) {

function formatPrimitive(fn, value, ctx) {
if (typeof value === 'string') {
if (ctx.compact === false &&
if (ctx.compact !== true &&
ctx.indentationLvl + value.length > ctx.breakLength &&
value.length > kMinLineLength) {
const rawMaxLineLength = ctx.breakLength - ctx.indentationLvl;
Expand Down Expand Up @@ -1134,7 +1139,7 @@ function formatProperty(ctx, value, recurseTimes, key, type) {
const desc = Object.getOwnPropertyDescriptor(value, key) ||
{ value: value[key], enumerable: true };
if (desc.value !== undefined) {
const diff = (type !== kObjectType || ctx.compact === false) ? 2 : 3;
const diff = (type !== kObjectType || ctx.compact !== true) ? 2 : 3;
ctx.indentationLvl += diff;
str = formatValue(ctx, desc.value, recurseTimes);
if (diff === 3) {
Expand Down Expand Up @@ -1191,16 +1196,27 @@ function formatProperty(ctx, value, recurseTimes, key, type) {
return `${name}:${extra}${str}`;
}

function reduceToSingleString(ctx, output, base, braces) {
function reduceToSingleString(ctx, output, base, braces, combine = false) {
const breakLength = ctx.breakLength;
let i = 0;
if (ctx.compact === false) {
const indentation = ' '.repeat(ctx.indentationLvl);
let res = `${base ? `${base} ` : ''}${braces[0]}\n${indentation} `;
if (ctx.compact !== true) {
if (combine) {
const totalLength = output.reduce((sum, cur) => sum + cur.length, 0);
if (totalLength + output.length * 2 < breakLength) {
let res = `${base ? `${base} ` : ''}${braces[0]} `;
for (; i < output.length - 1; i++) {
res += `${output[i]}, `;
}
res += `${output[i]} ${braces[1]}`;
return res;
}
}
const indentation = `\n${' '.repeat(ctx.indentationLvl)}`;
let res = `${base ? `${base} ` : ''}${braces[0]}${indentation} `;
for (; i < output.length - 1; i++) {
res += `${output[i]},\n${indentation} `;
res += `${output[i]},${indentation} `;
}
res += `${output[i]}\n${indentation}${braces[1]}`;
res += `${output[i]}${indentation}${braces[1]}`;
return res;
}
if (output.length * 2 <= breakLength) {
Expand Down
36 changes: 36 additions & 0 deletions test/parallel/test-util-inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,42 @@ util.inspect(process);

assert.strict.equal(out, expected);

out = util.inspect(map, { compact: 2, showHidden: true, depth: 9 });

expected = [
'Map {',
' Promise {',
' [',
' [',
' 1,',
' Set { [ 1, 2, [length]: 2 ], [size]: 1 },',
' [length]: 2',
' ],',
' [length]: 1',
' ]',
' } => Uint8Array [',
' [BYTES_PER_ELEMENT]: 1,',
' [length]: 0,',
' [byteLength]: 0,',
' [byteOffset]: 0,',
' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
' ],',
' [Set Iterator] { [ 1, 2, [length]: 2 ] } => [Map Iterator] {',
' Uint8Array [',
' [BYTES_PER_ELEMENT]: 1,',
' [length]: 0,',
' [byteLength]: 0,',
' [byteOffset]: 0,',
' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
' ],',
' [Circular]',
' },',
' [size]: 2',
'}'
].join('\n');

assert.strict.equal(out, expected);

out = util.inspect(map, { showHidden: true, depth: 9, breakLength: 4 });
expected = [
'Map {',
Expand Down

0 comments on commit 4500ed8

Please sign in to comment.