util: unify constructor inspection in util.inspect
This makes sure that an objects constructor name is always returned in a similar fashion instead of having different outputs depending on the object shape and the code path taken. PR-URL: https://github.com/nodejs/node/pull/27733 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>
This commit is contained in:
parent
79e55f0774
commit
370ddefc14
@ -418,8 +418,15 @@ function getKeys(value, showHidden) {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCtxStyle(constructor, tag) {
|
function getCtxStyle(value, constructor, tag) {
|
||||||
return constructor || tag || 'Object';
|
let fallback = '';
|
||||||
|
if (constructor === null) {
|
||||||
|
fallback = internalGetConstructorName(value);
|
||||||
|
if (fallback === tag) {
|
||||||
|
fallback = 'Object';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getPrefix(constructor, tag, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatProxy(ctx, proxy, recurseTimes) {
|
function formatProxy(ctx, proxy, recurseTimes) {
|
||||||
@ -723,25 +730,21 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
|
|||||||
formatter = formatIterator;
|
formatter = formatIterator;
|
||||||
// Handle other regular objects again.
|
// Handle other regular objects again.
|
||||||
} else {
|
} else {
|
||||||
let fallback = '';
|
|
||||||
if (constructor === null) {
|
|
||||||
fallback = internalGetConstructorName(value);
|
|
||||||
if (fallback === tag) {
|
|
||||||
fallback = 'Object';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (keys.length === 0) {
|
if (keys.length === 0) {
|
||||||
if (isExternal(value))
|
if (isExternal(value))
|
||||||
return ctx.stylize('[External]', 'special');
|
return ctx.stylize('[External]', 'special');
|
||||||
return `${getPrefix(constructor, tag, fallback)}{}`;
|
return `${getCtxStyle(value, constructor, tag)}{}`;
|
||||||
}
|
}
|
||||||
braces[0] = `${getPrefix(constructor, tag, fallback)}{`;
|
braces[0] = `${getCtxStyle(value, constructor, tag)}{`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recurseTimes > ctx.depth && ctx.depth !== null) {
|
if (recurseTimes > ctx.depth && ctx.depth !== null) {
|
||||||
return ctx.stylize(`[${getCtxStyle(constructor, tag)}]`, 'special');
|
let constructorName = getCtxStyle(value, constructor, tag).slice(0, -1);
|
||||||
|
if (constructor !== null)
|
||||||
|
constructorName = `[${constructorName}]`;
|
||||||
|
return ctx.stylize(constructorName, 'special');
|
||||||
}
|
}
|
||||||
recurseTimes += 1;
|
recurseTimes += 1;
|
||||||
|
|
||||||
@ -756,7 +759,8 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
|
|||||||
formatProperty(ctx, value, recurseTimes, keys[i], extrasType));
|
formatProperty(ctx, value, recurseTimes, keys[i], extrasType));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return handleMaxCallStackSize(ctx, err, constructor, tag, indentationLvl);
|
const constructorName = getCtxStyle(value, constructor, tag).slice(0, -1);
|
||||||
|
return handleMaxCallStackSize(ctx, err, constructorName, indentationLvl);
|
||||||
}
|
}
|
||||||
ctx.seen.pop();
|
ctx.seen.pop();
|
||||||
|
|
||||||
@ -1016,12 +1020,12 @@ function groupArrayElements(ctx, output) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMaxCallStackSize(ctx, err, constructor, tag, indentationLvl) {
|
function handleMaxCallStackSize(ctx, err, constructorName, indentationLvl) {
|
||||||
if (isStackOverflowError(err)) {
|
if (isStackOverflowError(err)) {
|
||||||
ctx.seen.pop();
|
ctx.seen.pop();
|
||||||
ctx.indentationLvl = indentationLvl;
|
ctx.indentationLvl = indentationLvl;
|
||||||
return ctx.stylize(
|
return ctx.stylize(
|
||||||
`[${getCtxStyle(constructor, tag)}: Inspection interrupted ` +
|
`[${constructorName}: Inspection interrupted ` +
|
||||||
'prematurely. Maximum call stack size exceeded.]',
|
'prematurely. Maximum call stack size exceeded.]',
|
||||||
'special'
|
'special'
|
||||||
);
|
);
|
||||||
|
@ -1094,6 +1094,47 @@ if (typeof Symbol !== 'undefined') {
|
|||||||
'[Set Iterator] { 1, ... 1 more item, extra: true }');
|
'[Set Iterator] { 1, ... 1 more item, extra: true }');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Minimal inspection should still return as much information as possible about
|
||||||
|
// the constructor and Symbol.toStringTag.
|
||||||
|
{
|
||||||
|
class Foo {
|
||||||
|
get [Symbol.toStringTag]() {
|
||||||
|
return 'ABC';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const a = new Foo();
|
||||||
|
assert.strictEqual(inspect(a, { depth: -1 }), 'Foo [ABC] {}');
|
||||||
|
a.foo = true;
|
||||||
|
assert.strictEqual(inspect(a, { depth: -1 }), '[Foo [ABC]]');
|
||||||
|
Object.defineProperty(a, Symbol.toStringTag, {
|
||||||
|
value: 'Foo',
|
||||||
|
configurable: true,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
|
assert.strictEqual(inspect(a, { depth: -1 }), '[Foo]');
|
||||||
|
delete a[Symbol.toStringTag];
|
||||||
|
Object.setPrototypeOf(a, null);
|
||||||
|
assert.strictEqual(inspect(a, { depth: -1 }), '[Foo: null prototype]');
|
||||||
|
delete a.foo;
|
||||||
|
assert.strictEqual(inspect(a, { depth: -1 }), '[Foo: null prototype] {}');
|
||||||
|
Object.defineProperty(a, Symbol.toStringTag, {
|
||||||
|
value: 'ABC',
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
assert.strictEqual(
|
||||||
|
inspect(a, { depth: -1 }),
|
||||||
|
'[Foo: null prototype] [ABC] {}'
|
||||||
|
);
|
||||||
|
Object.defineProperty(a, Symbol.toStringTag, {
|
||||||
|
value: 'Foo',
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
assert.strictEqual(
|
||||||
|
inspect(a, { depth: -1 }),
|
||||||
|
'[Object: null prototype] [Foo] {}'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Test alignment of items in container.
|
// Test alignment of items in container.
|
||||||
// Assumes that the first numeric character is the start of an item.
|
// Assumes that the first numeric character is the start of an item.
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user