From 697908e8d90126f876f8291ef878c198f0eaea1f 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. 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 cda8839eb17633..5ef5d37e09242f 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/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) { diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 75587ddf4e79d6..c6159a4c13d7a1 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -1695,7 +1695,8 @@ util.inspect(process); ' 1,', ' 2,', ' [length]: 2', - ' ]', + ' ],', + " [Symbol(Symbol.toStringTag)]: 'Set Iterator'", ' } => [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,7 +1736,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,', @@ -1742,7 +1747,8 @@ util.inspect(process); ' [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 ] } => [Map Iterator] {', + ' [length]: 2 ],', + ' [Symbol(Symbol.toStringTag)]:', + " 'Set Iterator' } => [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 }' + ); }