From fc0febebc96d601565917e7893e368d4624874e9 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Dec 2019 20:57:53 +0100 Subject: [PATCH] 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. Backport-PR-URL: https://github.com/nodejs/node/pull/31431 PR-URL: https://github.com/nodejs/node/pull/31113 Reviewed-By: James M Snell Reviewed-By: Rich Trott --- lib/internal/util/inspect.js | 12 +++++------- test/parallel/test-util-inspect.js | 29 +++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 04b76077bba313..4eb493dfe1fdae 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -467,10 +467,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; } @@ -508,12 +508,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) { @@ -526,8 +526,6 @@ function addPrototypeProperties(ctx, main, obj, recurseTimes, isProto, output) { builtInObjects.has(descriptor.value.name)) { return; } - } else { - isProto = false; } if (depth === 0) { diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index bba497c89683c9..b1cd48a6a83c03 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -1687,7 +1687,8 @@ util.inspect(process); ' 1,', ' 2,', ' [length]: 2', - ' ]', + ' ],', + " [Symbol(Symbol.toStringTag)]: 'Set Iterator'", ' } => [Map Iterator] {', ' Uint8Array(0) [', ' [BYTES_PER_ELEMENT]: 1,', @@ -1699,7 +1700,8 @@ util.inspect(process); ' foo: true', ' }', ' ],', - ' [Circular]', + ' [Circular],', + " [Symbol(Symbol.toStringTag)]: 'Map Iterator'", ' },', ' [size]: 2', '}' @@ -1727,7 +1729,10 @@ util.inspect(process); ' [byteOffset]: 0,', ' [buffer]: ArrayBuffer { byteLength: 0, foo: true }', ' ],', - ' [Set Iterator] { [ 1, 2, [length]: 2 ] } => [Map Iterator] {', + ' [Set Iterator] {', + ' [ 1, 2, [length]: 2 ],', + " [Symbol(Symbol.toStringTag)]: 'Set Iterator'", + ' } => [Map Iterator] {', ' Uint8Array(0) [', ' [BYTES_PER_ELEMENT]: 1,', ' [length]: 0,', @@ -1735,7 +1740,8 @@ util.inspect(process); ' [byteOffset]: 0,', ' [buffer]: ArrayBuffer { byteLength: 0, foo: true }', ' ],', - ' [Circular]', + ' [Circular],', + " [Symbol(Symbol.toStringTag)]: 'Map Iterator'", ' },', ' [size]: 2', '}' @@ -1767,7 +1773,9 @@ util.inspect(process); ' [Set Iterator] {', ' [ 1,', ' 2,', - ' [length]: 2 ] } => [Map Iterator] {', + ' [length]: 2 ],', + ' [Symbol(Symbol.toStringTag)]:', + " 'Set Iterator' } => [Map Iterator] {", ' Uint8Array(0) [', ' [BYTES_PER_ELEMENT]: 1,', ' [length]: 0,', @@ -1776,7 +1784,9 @@ util.inspect(process); ' [buffer]: ArrayBuffer {', ' byteLength: 0,', ' foo: true } ],', - ' [Circular] },', + ' [Circular],', + ' [Symbol(Symbol.toStringTag)]:', + " 'Map Iterator' },", ' [size]: 2 }' ].join('\n'); @@ -2678,4 +2688,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 }' + ); }