Skip to content

Commit 099c9ce

Browse files
BridgeARtargos
authored andcommittedMay 20, 2019
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: #27733 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michaël Zasso <[email protected]>
1 parent d8b4867 commit 099c9ce

File tree

2 files changed

+60
-15
lines changed

2 files changed

+60
-15
lines changed
 

‎lib/internal/util/inspect.js

+19-15
Original file line numberDiff line numberDiff line change
@@ -418,8 +418,15 @@ function getKeys(value, showHidden) {
418418
return keys;
419419
}
420420

421-
function getCtxStyle(constructor, tag) {
422-
return constructor || tag || 'Object';
421+
function getCtxStyle(value, constructor, tag) {
422+
let fallback = '';
423+
if (constructor === null) {
424+
fallback = internalGetConstructorName(value);
425+
if (fallback === tag) {
426+
fallback = 'Object';
427+
}
428+
}
429+
return getPrefix(constructor, tag, fallback);
423430
}
424431

425432
function formatProxy(ctx, proxy, recurseTimes) {
@@ -723,25 +730,21 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
723730
formatter = formatIterator;
724731
// Handle other regular objects again.
725732
} else {
726-
let fallback = '';
727-
if (constructor === null) {
728-
fallback = internalGetConstructorName(value);
729-
if (fallback === tag) {
730-
fallback = 'Object';
731-
}
732-
}
733733
if (keys.length === 0) {
734734
if (isExternal(value))
735735
return ctx.stylize('[External]', 'special');
736-
return `${getPrefix(constructor, tag, fallback)}{}`;
736+
return `${getCtxStyle(value, constructor, tag)}{}`;
737737
}
738-
braces[0] = `${getPrefix(constructor, tag, fallback)}{`;
738+
braces[0] = `${getCtxStyle(value, constructor, tag)}{`;
739739
}
740740
}
741741
}
742742

743743
if (recurseTimes > ctx.depth && ctx.depth !== null) {
744-
return ctx.stylize(`[${getCtxStyle(constructor, tag)}]`, 'special');
744+
let constructorName = getCtxStyle(value, constructor, tag).slice(0, -1);
745+
if (constructor !== null)
746+
constructorName = `[${constructorName}]`;
747+
return ctx.stylize(constructorName, 'special');
745748
}
746749
recurseTimes += 1;
747750

@@ -756,7 +759,8 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
756759
formatProperty(ctx, value, recurseTimes, keys[i], extrasType));
757760
}
758761
} catch (err) {
759-
return handleMaxCallStackSize(ctx, err, constructor, tag, indentationLvl);
762+
const constructorName = getCtxStyle(value, constructor, tag).slice(0, -1);
763+
return handleMaxCallStackSize(ctx, err, constructorName, indentationLvl);
760764
}
761765
ctx.seen.pop();
762766

@@ -1014,12 +1018,12 @@ function groupArrayElements(ctx, output) {
10141018
return output;
10151019
}
10161020

1017-
function handleMaxCallStackSize(ctx, err, constructor, tag, indentationLvl) {
1021+
function handleMaxCallStackSize(ctx, err, constructorName, indentationLvl) {
10181022
if (isStackOverflowError(err)) {
10191023
ctx.seen.pop();
10201024
ctx.indentationLvl = indentationLvl;
10211025
return ctx.stylize(
1022-
`[${getCtxStyle(constructor, tag)}: Inspection interrupted ` +
1026+
`[${constructorName}: Inspection interrupted ` +
10231027
'prematurely. Maximum call stack size exceeded.]',
10241028
'special'
10251029
);

‎test/parallel/test-util-inspect.js

+41
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,47 @@ if (typeof Symbol !== 'undefined') {
10941094
'[Set Iterator] { 1, ... 1 more item, extra: true }');
10951095
}
10961096

1097+
// Minimal inspection should still return as much information as possible about
1098+
// the constructor and Symbol.toStringTag.
1099+
{
1100+
class Foo {
1101+
get [Symbol.toStringTag]() {
1102+
return 'ABC';
1103+
}
1104+
}
1105+
const a = new Foo();
1106+
assert.strictEqual(inspect(a, { depth: -1 }), 'Foo [ABC] {}');
1107+
a.foo = true;
1108+
assert.strictEqual(inspect(a, { depth: -1 }), '[Foo [ABC]]');
1109+
Object.defineProperty(a, Symbol.toStringTag, {
1110+
value: 'Foo',
1111+
configurable: true,
1112+
writable: true
1113+
});
1114+
assert.strictEqual(inspect(a, { depth: -1 }), '[Foo]');
1115+
delete a[Symbol.toStringTag];
1116+
Object.setPrototypeOf(a, null);
1117+
assert.strictEqual(inspect(a, { depth: -1 }), '[Foo: null prototype]');
1118+
delete a.foo;
1119+
assert.strictEqual(inspect(a, { depth: -1 }), '[Foo: null prototype] {}');
1120+
Object.defineProperty(a, Symbol.toStringTag, {
1121+
value: 'ABC',
1122+
configurable: true
1123+
});
1124+
assert.strictEqual(
1125+
inspect(a, { depth: -1 }),
1126+
'[Foo: null prototype] [ABC] {}'
1127+
);
1128+
Object.defineProperty(a, Symbol.toStringTag, {
1129+
value: 'Foo',
1130+
configurable: true
1131+
});
1132+
assert.strictEqual(
1133+
inspect(a, { depth: -1 }),
1134+
'[Object: null prototype] [Foo] {}'
1135+
);
1136+
}
1137+
10971138
// Test alignment of items in container.
10981139
// Assumes that the first numeric character is the start of an item.
10991140
{

0 commit comments

Comments
 (0)
Please sign in to comment.