Skip to content
Permalink
Browse files

util: improve prototype inspection using `inspect()` and `showHidden`

The fast path for the prototype inspection had a bug that caused some
prototype properties to be skipped that should in fact be inspected.

PR-URL: #31113
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
  • Loading branch information
BridgeAR committed Dec 26, 2019
1 parent 9b7cf09 commit 697908e8d90126f876f8291ef878c198f0eaea1f
Showing with 28 additions and 13 deletions.
  1. +5 −7 lib/internal/util/inspect.js
  2. +23 −6 test/parallel/test-util-inspect.js
@@ -465,10 +465,10 @@ function getConstructorName(obj, ctx, recurseTimes, protoProps) {
typeof descriptor.value === 'function' &&
descriptor.value.name !== '') {
if (protoProps !== undefined &&
!builtInObjects.has(descriptor.value.name)) {
const isProto = firstProto !== undefined;
(firstProto !== obj ||
!builtInObjects.has(descriptor.value.name))) {
addPrototypeProperties(
ctx, tmp, obj, recurseTimes, isProto, protoProps);
ctx, tmp, firstProto || tmp, recurseTimes, protoProps);
}
return descriptor.value.name;
}
@@ -506,12 +506,12 @@ function getConstructorName(obj, ctx, recurseTimes, protoProps) {
// This function has the side effect of adding prototype properties to the
// `output` argument (which is an array). This is intended to highlight user
// defined prototype properties.
function addPrototypeProperties(ctx, main, obj, recurseTimes, isProto, output) {
function addPrototypeProperties(ctx, main, obj, recurseTimes, output) {
let depth = 0;
let keys;
let keySet;
do {
if (!isProto) {
if (depth !== 0 || main === obj) {
obj = ObjectGetPrototypeOf(obj);
// Stop as soon as a null prototype is encountered.
if (obj === null) {
@@ -524,8 +524,6 @@ function addPrototypeProperties(ctx, main, obj, recurseTimes, isProto, output) {
builtInObjects.has(descriptor.value.name)) {
return;
}
} else {
isProto = false;
}

if (depth === 0) {
@@ -1695,7 +1695,8 @@ util.inspect(process);
' 1,',
' 2,',
' [length]: 2',
' ]',
' ],',
" [Symbol(Symbol.toStringTag)]: 'Set Iterator'",
' } => <ref *1> [Map Iterator] {',
' Uint8Array(0) [',
' [BYTES_PER_ELEMENT]: 1,',
@@ -1707,7 +1708,8 @@ util.inspect(process);
' foo: true',
' }',
' ],',
' [Circular *1]',
' [Circular *1],',
" [Symbol(Symbol.toStringTag)]: 'Map Iterator'",
' }',
'}'
].join('\n');
@@ -1734,15 +1736,19 @@ util.inspect(process);
' [byteOffset]: 0,',
' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
' ],',
' [Set Iterator] { [ 1, 2, [length]: 2 ] } => <ref *1> [Map Iterator] {',
' [Set Iterator] {',
' [ 1, 2, [length]: 2 ],',
" [Symbol(Symbol.toStringTag)]: 'Set Iterator'",
' } => <ref *1> [Map Iterator] {',
' Uint8Array(0) [',
' [BYTES_PER_ELEMENT]: 1,',
' [length]: 0,',
' [byteLength]: 0,',
' [byteOffset]: 0,',
' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
' ],',
' [Circular *1]',
' [Circular *1],',
" [Symbol(Symbol.toStringTag)]: 'Map Iterator'",
' }',
'}'
].join('\n');
@@ -1772,7 +1778,9 @@ util.inspect(process);
' [Set Iterator] {',
' [ 1,',
' 2,',
' [length]: 2 ] } => <ref *1> [Map Iterator] {',
' [length]: 2 ],',
' [Symbol(Symbol.toStringTag)]:',
" 'Set Iterator' } => <ref *1> [Map Iterator] {",
' Uint8Array(0) [',
' [BYTES_PER_ELEMENT]: 1,',
' [length]: 0,',
@@ -1781,7 +1789,9 @@ util.inspect(process);
' [buffer]: ArrayBuffer {',
' byteLength: 0,',
' foo: true } ],',
' [Circular *1] } }'
' [Circular *1],',
' [Symbol(Symbol.toStringTag)]:',
" 'Map Iterator' } }"
].join('\n');

assert.strict.equal(out, expected);
@@ -2680,4 +2690,11 @@ assert.strictEqual(
' \x1B[2m[def]: \x1B[36m[Getter/Setter]\x1B[39m\x1B[22m\n' +
'}'
);

const obj = Object.create({ abc: true, def: 5, toString() {} });
assert.strictEqual(
inspect(obj, { showHidden: true, colors: true }),
'{ \x1B[2mabc: \x1B[33mtrue\x1B[39m\x1B[22m, ' +
'\x1B[2mdef: \x1B[33m5\x1B[39m\x1B[22m }'
);
}

0 comments on commit 697908e

Please sign in to comment.
You can’t perform that action at this time.