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: https://github.com/nodejs/node/pull/26269
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
Ruben Bridgewater 2019-02-22 23:26:25 +01:00
parent f4257a2af1
commit 4db10ed9ad
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
3 changed files with 72 additions and 15 deletions

View File

@ -388,6 +388,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: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24971
description: Internal properties no longer appear in the context argument
@ -461,11 +464,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,

View File

@ -164,6 +164,7 @@ function inspect(value, opts) {
budget: {},
indentationLvl: 0,
seen: [],
currentDepth: 0,
stylize: stylizeNoColor,
showHidden: inspectDefaultOptions.showHidden,
depth: inspectDefaultOptions.depth,
@ -769,6 +770,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
recurseTimes += 1;
ctx.seen.push(value);
ctx.currentDepth = recurseTimes;
let output;
const indentationLvl = ctx.indentationLvl;
try {
@ -792,7 +794,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;
@ -833,7 +838,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;
@ -1143,7 +1148,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) {
@ -1200,16 +1205,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]},\n${indentation} `;
res += `${output[i]}, `;
}
res += `${output[i]}\n${indentation}${braces[1]}`;
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]},${indentation} `;
}
res += `${output[i]}${indentation}${braces[1]}`;
return res;
}
if (output.length * 2 <= breakLength) {

View File

@ -1498,6 +1498,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 {',