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: https://github.com/nodejs/node/pull/22291 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
59c8abf886
commit
1abc613b32
37
lib/util.js
37
lib/util.js
@ -543,6 +543,9 @@ function findTypedConstructor(value) {
|
|||||||
|
|
||||||
const getBoxedValue = formatPrimitive.bind(null, stylizeNoColor);
|
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) {
|
function formatValue(ctx, value, recurseTimes) {
|
||||||
// Primitive types cannot have properties
|
// Primitive types cannot have properties
|
||||||
if (typeof value !== 'object' && typeof value !== 'function') {
|
if (typeof value !== 'object' && typeof value !== 'function') {
|
||||||
@ -1063,17 +1066,18 @@ function formatTypedArray(ctx, value, recurseTimes, keys) {
|
|||||||
output[i] = `... ${remaining} more item${remaining > 1 ? 's' : ''}`;
|
output[i] = `... ${remaining} more item${remaining > 1 ? 's' : ''}`;
|
||||||
if (ctx.showHidden) {
|
if (ctx.showHidden) {
|
||||||
// .buffer goes last, it's not a primitive like the others.
|
// .buffer goes last, it's not a primitive like the others.
|
||||||
const extraKeys = [
|
ctx.indentationLvl += 2;
|
||||||
|
for (const key of [
|
||||||
'BYTES_PER_ELEMENT',
|
'BYTES_PER_ELEMENT',
|
||||||
'length',
|
'length',
|
||||||
'byteLength',
|
'byteLength',
|
||||||
'byteOffset',
|
'byteOffset',
|
||||||
'buffer'
|
'buffer'
|
||||||
];
|
]) {
|
||||||
for (i = 0; i < extraKeys.length; i++) {
|
const str = formatValue(ctx, value[key], recurseTimes);
|
||||||
const str = formatValue(ctx, value[extraKeys[i]], recurseTimes);
|
output.push(`[${key}]: ${str}`);
|
||||||
output.push(`[${extraKeys[i]}]: ${str}`);
|
|
||||||
}
|
}
|
||||||
|
ctx.indentationLvl -= 2;
|
||||||
}
|
}
|
||||||
// TypedArrays cannot have holes. Therefore it is safe to assume that all
|
// TypedArrays cannot have holes. Therefore it is safe to assume that all
|
||||||
// extra keys are indexed after value.length.
|
// extra keys are indexed after value.length.
|
||||||
@ -1086,8 +1090,11 @@ function formatTypedArray(ctx, value, recurseTimes, keys) {
|
|||||||
function formatSet(ctx, value, recurseTimes, keys) {
|
function formatSet(ctx, value, recurseTimes, keys) {
|
||||||
const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
|
const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const v of value)
|
ctx.indentationLvl += 2;
|
||||||
|
for (const v of value) {
|
||||||
output[i++] = formatValue(ctx, v, recurseTimes);
|
output[i++] = formatValue(ctx, v, recurseTimes);
|
||||||
|
}
|
||||||
|
ctx.indentationLvl -= 2;
|
||||||
// With `showHidden`, `length` will display as a hidden property for
|
// With `showHidden`, `length` will display as a hidden property for
|
||||||
// arrays. For consistency's sake, do the same for `size`, even though this
|
// arrays. For consistency's sake, do the same for `size`, even though this
|
||||||
// property isn't selected by Object.getOwnPropertyNames().
|
// property isn't selected by Object.getOwnPropertyNames().
|
||||||
@ -1102,9 +1109,12 @@ function formatSet(ctx, value, recurseTimes, keys) {
|
|||||||
function formatMap(ctx, value, recurseTimes, keys) {
|
function formatMap(ctx, value, recurseTimes, keys) {
|
||||||
const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
|
const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
|
||||||
let i = 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)} => ` +
|
output[i++] = `${formatValue(ctx, k, recurseTimes)} => ` +
|
||||||
formatValue(ctx, v, recurseTimes);
|
formatValue(ctx, v, recurseTimes);
|
||||||
|
}
|
||||||
|
ctx.indentationLvl -= 2;
|
||||||
// See comment in formatSet
|
// See comment in formatSet
|
||||||
if (ctx.showHidden)
|
if (ctx.showHidden)
|
||||||
output[i++] = `[size]: ${ctx.stylize(`${value.size}`, 'number')}`;
|
output[i++] = `[size]: ${ctx.stylize(`${value.size}`, 'number')}`;
|
||||||
@ -1118,8 +1128,11 @@ function formatSetIterInner(ctx, value, recurseTimes, keys, entries, state) {
|
|||||||
const maxArrayLength = Math.max(ctx.maxArrayLength, 0);
|
const maxArrayLength = Math.max(ctx.maxArrayLength, 0);
|
||||||
const maxLength = Math.min(maxArrayLength, entries.length);
|
const maxLength = Math.min(maxArrayLength, entries.length);
|
||||||
let output = new Array(maxLength);
|
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);
|
output[i] = formatValue(ctx, entries[i], recurseTimes);
|
||||||
|
}
|
||||||
|
ctx.indentationLvl -= 2;
|
||||||
if (state === kWeak) {
|
if (state === kWeak) {
|
||||||
// Sort all entries to have a halfway reliable output (if more entries than
|
// Sort all entries to have a halfway reliable output (if more entries than
|
||||||
// retrieved ones exist, we can not reliably return the same output).
|
// retrieved ones exist, we can not reliably return the same output).
|
||||||
@ -1150,11 +1163,13 @@ function formatMapIterInner(ctx, value, recurseTimes, keys, entries, state) {
|
|||||||
end = ' ]';
|
end = ' ]';
|
||||||
middle = ', ';
|
middle = ', ';
|
||||||
}
|
}
|
||||||
|
ctx.indentationLvl += 2;
|
||||||
for (; i < maxLength; i++) {
|
for (; i < maxLength; i++) {
|
||||||
const pos = i * 2;
|
const pos = i * 2;
|
||||||
output[i] = `${start}${formatValue(ctx, entries[pos], recurseTimes)}` +
|
output[i] = `${start}${formatValue(ctx, entries[pos], recurseTimes)}` +
|
||||||
`${middle}${formatValue(ctx, entries[pos + 1], recurseTimes)}${end}`;
|
`${middle}${formatValue(ctx, entries[pos + 1], recurseTimes)}${end}`;
|
||||||
}
|
}
|
||||||
|
ctx.indentationLvl -= 2;
|
||||||
if (state === kWeak) {
|
if (state === kWeak) {
|
||||||
// Sort all entries to have a halfway reliable output (if more entries
|
// Sort all entries to have a halfway reliable output (if more entries
|
||||||
// than retrieved ones exist, we can not reliably return the same output).
|
// than retrieved ones exist, we can not reliably return the same output).
|
||||||
@ -1199,7 +1214,11 @@ function formatPromise(ctx, value, recurseTimes, keys) {
|
|||||||
if (state === kPending) {
|
if (state === kPending) {
|
||||||
output = ['<pending>'];
|
output = ['<pending>'];
|
||||||
} else {
|
} else {
|
||||||
|
// Using `formatValue` is correct here without the need to fix the
|
||||||
|
// indentation level.
|
||||||
|
ctx.indentationLvl += 2;
|
||||||
const str = formatValue(ctx, result, recurseTimes);
|
const str = formatValue(ctx, result, recurseTimes);
|
||||||
|
ctx.indentationLvl -= 2;
|
||||||
output = [state === kRejected ? `<rejected> ${str}` : str];
|
output = [state === kRejected ? `<rejected> ${str}` : str];
|
||||||
}
|
}
|
||||||
for (var n = 0; n < keys.length; n++) {
|
for (var n = 0; n < keys.length; n++) {
|
||||||
|
@ -179,7 +179,6 @@ for (const showHidden of [true, false]) {
|
|||||||
' y: 1337 }');
|
' y: 1337 }');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[ Float32Array,
|
[ Float32Array,
|
||||||
Float64Array,
|
Float64Array,
|
||||||
Int16Array,
|
Int16Array,
|
||||||
@ -195,7 +194,7 @@ for (const showHidden of [true, false]) {
|
|||||||
array[0] = 65;
|
array[0] = 65;
|
||||||
array[1] = 97;
|
array[1] = 97;
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
util.inspect(array, true),
|
util.inspect(array, { showHidden: true }),
|
||||||
`${constructor.name} [\n` +
|
`${constructor.name} [\n` +
|
||||||
' 65,\n' +
|
' 65,\n' +
|
||||||
' 97,\n' +
|
' 97,\n' +
|
||||||
@ -1362,6 +1361,107 @@ util.inspect(process);
|
|||||||
assert.strictEqual(out, expect);
|
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
|
{ // Test WeakMap
|
||||||
const obj = {};
|
const obj = {};
|
||||||
const arr = [];
|
const arr = [];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user