From 34905fc2b9ed263d04421e84b9bdf3a8ebccb446 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Wed, 20 Feb 2019 20:01:17 +0100 Subject: [PATCH] util: mark iterator entries as such It is possible to distinguish the entries iterator from others. Expose that information to the users as well and improve the Symbol.toStringTag handling by adding a special tag instead of replacing the existent information. PR-URL: https://github.com/nodejs/node/pull/26222 Reviewed-By: James M Snell Reviewed-By: Gus Caplan Reviewed-By: Jeremiah Senkpiel --- lib/internal/util/inspect.js | 23 +++++++++++++++++------ test/parallel/test-util-inspect.js | 18 +++++++++++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 31b9e37ef71137..77dd606deb39ee 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -539,6 +539,15 @@ function formatValue(ctx, value, recurseTimes, typedArray) { return formatRaw(ctx, value, recurseTimes, typedArray); } +function setIteratorBraces(type, tag) { + if (tag !== `${type} Iterator`) { + if (tag !== '') + tag += '] ['; + tag += `${type} Iterator`; + } + return [`[${tag}] {`, '}']; +} + function formatRaw(ctx, value, recurseTimes, typedArray) { let keys; @@ -593,11 +602,11 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { extrasType = kArrayExtrasType; } else if (isMapIterator(value)) { keys = getKeys(value, ctx.showHidden); - braces = [`[${tag}] {`, '}']; + braces = setIteratorBraces('Map', tag); formatter = formatIterator; } else if (isSetIterator(value)) { keys = getKeys(value, ctx.showHidden); - braces = [`[${tag}] {`, '}']; + braces = setIteratorBraces('Set', tag); formatter = formatIterator; } else { noIterator = true; @@ -729,10 +738,10 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { } } if (isMapIterator(value)) { - braces = [`[${tag || 'Map Iterator'}] {`, '}']; + braces = setIteratorBraces('Map', tag); formatter = formatIterator; } else if (isSetIterator(value)) { - braces = [`[${tag || 'Set Iterator'}] {`, '}']; + braces = setIteratorBraces('Set', tag); formatter = formatIterator; // Handle other regular objects again. } else if (keys.length === 0) { @@ -754,7 +763,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { let output; const indentationLvl = ctx.indentationLvl; try { - output = formatter(ctx, value, recurseTimes, keys); + output = formatter(ctx, value, recurseTimes, keys, braces); for (i = 0; i < keys.length; i++) { output.push( formatProperty(ctx, value, recurseTimes, keys[i], extrasType)); @@ -1090,9 +1099,11 @@ function formatWeakMap(ctx, value, recurseTimes) { return formatMapIterInner(ctx, recurseTimes, entries, kWeak); } -function formatIterator(ctx, value, recurseTimes) { +function formatIterator(ctx, value, recurseTimes, keys, braces) { const [entries, isKeyValue] = previewEntries(value, true); if (isKeyValue) { + // Mark entry iterators as such. + braces[0] = braces[0].replace(/ Iterator] {$/, ' Entries] {'); return formatMapIterInner(ctx, recurseTimes, entries, kMapEntries); } diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index a9afdbf8af049f..21a06343235060 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -976,10 +976,15 @@ if (typeof Symbol !== 'undefined') { { const map = new Map([['foo', 'bar']]); assert.strictEqual(util.inspect(map.keys()), '[Map Iterator] { \'foo\' }'); - assert.strictEqual(util.inspect(map.values()), '[Map Iterator] { \'bar\' }'); + const mapValues = map.values(); + Object.defineProperty(mapValues, Symbol.toStringTag, { value: 'Foo' }); + assert.strictEqual( + util.inspect(mapValues), + '[Foo] [Map Iterator] { \'bar\' }' + ); map.set('A', 'B!'); assert.strictEqual(util.inspect(map.entries(), { maxArrayLength: 1 }), - "[Map Iterator] { [ 'foo', 'bar' ], ... 1 more item }"); + "[Map Entries] { [ 'foo', 'bar' ], ... 1 more item }"); // Make sure the iterator doesn't get consumed. const keys = map.keys(); assert.strictEqual(util.inspect(keys), "[Map Iterator] { 'foo', 'A' }"); @@ -995,10 +1000,13 @@ if (typeof Symbol !== 'undefined') { const aSet = new Set([1, 3]); assert.strictEqual(util.inspect(aSet.keys()), '[Set Iterator] { 1, 3 }'); assert.strictEqual(util.inspect(aSet.values()), '[Set Iterator] { 1, 3 }'); - assert.strictEqual(util.inspect(aSet.entries()), - '[Set Iterator] { [ 1, 1 ], [ 3, 3 ] }'); + const setEntries = aSet.entries(); + Object.defineProperty(setEntries, Symbol.toStringTag, { value: 'Foo' }); + assert.strictEqual(util.inspect(setEntries), + '[Foo] [Set Entries] { [ 1, 1 ], [ 3, 3 ] }'); // Make sure the iterator doesn't get consumed. const keys = aSet.keys(); + Object.defineProperty(keys, Symbol.toStringTag, { value: null }); assert.strictEqual(util.inspect(keys), '[Set Iterator] { 1, 3 }'); assert.strictEqual(util.inspect(keys), '[Set Iterator] { 1, 3 }'); keys.extra = true; @@ -1610,7 +1618,7 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'"); [{ a: 5 }, '{ a: 5 }'], [new Set([1, 2]), 'Set { 1, 2 }'], [new Map([[1, 2]]), 'Map { 1 => 2 }'], - [new Set([1, 2]).entries(), '[Set Iterator] { [ 1, 1 ], [ 2, 2 ] }'], + [new Set([1, 2]).entries(), '[Set Entries] { [ 1, 1 ], [ 2, 2 ] }'], [new Map([[1, 2]]).keys(), '[Map Iterator] { 1 }'], [new Date(2000), '1970-01-01T00:00:02.000Z'], [new Uint8Array(2), 'Uint8Array [ 0, 0 ]'],