Skip to content

Commit

Permalink
util: properly indent special properties
Browse files Browse the repository at this point in the history
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: #22291
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
BridgeAR authored and targos committed Sep 3, 2018
1 parent 459d676 commit e9ac683
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 11 deletions.
37 changes: 28 additions & 9 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,9 @@ function findTypedConstructor(value) {

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

// Note: using `formatValue` directly requires the indentation level to be
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
// value afterwards again.
function formatValue(ctx, value, recurseTimes) {
// Primitive types cannot have properties
if (typeof value !== 'object' && typeof value !== 'function') {
Expand Down Expand Up @@ -1011,17 +1014,18 @@ function formatTypedArray(ctx, value, recurseTimes, keys) {
output[i] = `... ${remaining} more item${remaining > 1 ? 's' : ''}`;
if (ctx.showHidden) {
// .buffer goes last, it's not a primitive like the others.
const extraKeys = [
ctx.indentationLvl += 2;
for (const key of [
'BYTES_PER_ELEMENT',
'length',
'byteLength',
'byteOffset',
'buffer'
];
for (i = 0; i < extraKeys.length; i++) {
const str = formatValue(ctx, value[extraKeys[i]], recurseTimes);
output.push(`[${extraKeys[i]}]: ${str}`);
]) {
const str = formatValue(ctx, value[key], recurseTimes);
output.push(`[${key}]: ${str}`);
}
ctx.indentationLvl -= 2;
}
// TypedArrays cannot have holes. Therefore it is safe to assume that all
// extra keys are indexed after value.length.
Expand All @@ -1034,8 +1038,11 @@ function formatTypedArray(ctx, value, recurseTimes, keys) {
function formatSet(ctx, value, recurseTimes, keys) {
const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
let i = 0;
for (const v of value)
ctx.indentationLvl += 2;
for (const v of value) {
output[i++] = formatValue(ctx, v, recurseTimes);
}
ctx.indentationLvl -= 2;
// With `showHidden`, `length` will display as a hidden property for
// arrays. For consistency's sake, do the same for `size`, even though this
// property isn't selected by Object.getOwnPropertyNames().
Expand All @@ -1050,9 +1057,12 @@ function formatSet(ctx, value, recurseTimes, keys) {
function formatMap(ctx, value, recurseTimes, keys) {
const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
let i = 0;
for (const [k, v] of value)
ctx.indentationLvl += 2;
for (const [k, v] of value) {
output[i++] = `${formatValue(ctx, k, recurseTimes)} => ` +
formatValue(ctx, v, recurseTimes);
formatValue(ctx, v, recurseTimes);
}
ctx.indentationLvl -= 2;
// See comment in formatSet
if (ctx.showHidden)
output[i++] = `[size]: ${ctx.stylize(`${value.size}`, 'number')}`;
Expand All @@ -1066,8 +1076,11 @@ function formatSetIterInner(ctx, value, recurseTimes, keys, entries, state) {
const maxArrayLength = Math.max(ctx.maxArrayLength, 0);
const maxLength = Math.min(maxArrayLength, entries.length);
let output = new Array(maxLength);
for (var i = 0; i < maxLength; ++i)
ctx.indentationLvl += 2;
for (var i = 0; i < maxLength; i++) {
output[i] = formatValue(ctx, entries[i], recurseTimes);
}
ctx.indentationLvl -= 2;
if (state === kWeak) {
// Sort all entries to have a halfway reliable output (if more entries than
// retrieved ones exist, we can not reliably return the same output).
Expand Down Expand Up @@ -1098,11 +1111,13 @@ function formatMapIterInner(ctx, value, recurseTimes, keys, entries, state) {
end = ' ]';
middle = ', ';
}
ctx.indentationLvl += 2;
for (; i < maxLength; i++) {
const pos = i * 2;
output[i] = `${start}${formatValue(ctx, entries[pos], recurseTimes)}` +
`${middle}${formatValue(ctx, entries[pos + 1], recurseTimes)}${end}`;
}
ctx.indentationLvl -= 2;
if (state === kWeak) {
// Sort all entries to have a halfway reliable output (if more entries
// than retrieved ones exist, we can not reliably return the same output).
Expand Down Expand Up @@ -1147,7 +1162,11 @@ function formatPromise(ctx, value, recurseTimes, keys) {
if (state === kPending) {
output = ['<pending>'];
} else {
// Using `formatValue` is correct here without the need to fix the
// indentation level.
ctx.indentationLvl += 2;
const str = formatValue(ctx, result, recurseTimes);
ctx.indentationLvl -= 2;
output = [state === kRejected ? `<rejected> ${str}` : str];
}
for (var n = 0; n < keys.length; n++) {
Expand Down
104 changes: 102 additions & 2 deletions test/parallel/test-util-inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ for (const showHidden of [true, false]) {
' y: 1337 }');
}


[ Float32Array,
Float64Array,
Int16Array,
Expand All @@ -195,7 +194,7 @@ for (const showHidden of [true, false]) {
array[0] = 65;
array[1] = 97;
assert.strictEqual(
util.inspect(array, true),
util.inspect(array, { showHidden: true }),
`${constructor.name} [\n` +
' 65,\n' +
' 97,\n' +
Expand Down Expand Up @@ -1424,6 +1423,107 @@ util.inspect(process);
assert.strictEqual(out, expect);
}

// Check compact indentation.
{
const typed = new Uint8Array();
typed.buffer.foo = true;
const set = new Set([[1, 2]]);
const promise = Promise.resolve([[1, set]]);
const map = new Map([[promise, typed]]);
map.set(set.values(), map.values());

let out = util.inspect(map, { compact: false, showHidden: true, depth: 9 });
let 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 {',
' 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);
}

{ // Test WeakMap
const obj = {};
const arr = [];
Expand Down

0 comments on commit e9ac683

Please sign in to comment.