Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

util: properly indent special properties #22291

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,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 @@ -1062,17 +1065,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 @@ -1085,8 +1089,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 @@ -1101,9 +1108,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 @@ -1117,8 +1127,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 @@ -1149,11 +1162,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 @@ -1198,7 +1213,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 @@ -1362,6 +1361,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