From ec2f098156d7abe169aa846ba4bc51a2d9125ba7 Mon Sep 17 00:00:00 2001 From: Alexey Orlenko Date: Mon, 27 Feb 2017 09:20:27 +0200 Subject: [PATCH] util: change sparse arrays inspection format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missing elements in sparse arrays used to be serialized to empty placeholders delimited with commas by util.inspect() and in some cases the result was a syntactically correct representation of a JavaScript array with shorter length than the original one. This commit implements @TimothyGu's suggestion to change the way util.inspect() formats sparse arrays to something similar to how Firefox shows them. Fixes: https://github.com/nodejs/node/issues/11570 PR-URL: https://github.com/nodejs/node/pull/11576 Reviewed-By: James M Snell Reviewed-By: Evan Lucas Reviewed-By: Anna Henningsen Reviewed-By: Timothy Gu Reviewed-By: Michaƫl Zasso Reviewed-By: Colin Ihrig --- lib/util.js | 24 +++++++++++++++++------- test/parallel/test-util-inspect.js | 24 ++++++++++++++++++------ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/lib/util.js b/lib/util.js index 7e8d23d55e676e..d34bf9303de49d 100644 --- a/lib/util.js +++ b/lib/util.js @@ -626,16 +626,26 @@ function formatObject(ctx, value, recurseTimes, visibleKeys, keys) { function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { var output = []; - const maxLength = Math.min(Math.max(0, ctx.maxArrayLength), value.length); - const remaining = value.length - maxLength; - for (var i = 0; i < maxLength; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); + let visibleLength = 0; + let index = 0; + while (index < value.length && visibleLength < ctx.maxArrayLength) { + let emptyItems = 0; + while (index < value.length && !hasOwnProperty(value, String(index))) { + emptyItems++; + index++; + } + if (emptyItems > 0) { + const ending = emptyItems > 1 ? 's' : ''; + const message = `<${emptyItems} empty item${ending}>`; + output.push(ctx.stylize(message, 'undefined')); } else { - output.push(''); + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(index), true)); + index++; } + visibleLength++; } + const remaining = value.length - index; if (remaining > 0) { output.push(`... ${remaining} more item${remaining > 1 ? 's' : ''}`); } diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index ded4e4a47f71d5..5e359d5d7900b8 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -295,12 +295,18 @@ assert.strictEqual(util.inspect(-0), '-0'); const a = ['foo', 'bar', 'baz']; assert.strictEqual(util.inspect(a), '[ \'foo\', \'bar\', \'baz\' ]'); delete a[1]; -assert.strictEqual(util.inspect(a), '[ \'foo\', , \'baz\' ]'); +assert.strictEqual(util.inspect(a), '[ \'foo\', <1 empty item>, \'baz\' ]'); assert.strictEqual( util.inspect(a, true), - '[ \'foo\', , \'baz\', [length]: 3 ]' + '[ \'foo\', <1 empty item>, \'baz\', [length]: 3 ]' +); +assert.strictEqual(util.inspect(new Array(5)), '[ <5 empty items> ]'); +a[3] = 'bar'; +a[100] = 'qux'; +assert.strictEqual( + util.inspect(a, { breakLength: Infinity }), + '[ \'foo\', <1 empty item>, \'baz\', \'bar\', <96 empty items>, \'qux\' ]' ); -assert.strictEqual(util.inspect(new Array(5)), '[ , , , , ]'); // test for Array constructor in different context { @@ -835,15 +841,21 @@ checkAlignment(new Map(big_array.map(function(y) { return [y, null]; }))); // Do not backport to v5/v4 unless all of // https://github.com/nodejs/node/pull/6334 is backported. { - const x = Array(101); + const x = new Array(101).fill(); assert(/1 more item/.test(util.inspect(x))); } { - const x = Array(101); + const x = new Array(101).fill(); assert(!/1 more item/.test(util.inspect(x, {maxArrayLength: 101}))); } +{ + const x = new Array(101).fill(); + assert(/^\[ ... 101 more items ]$/.test( + util.inspect(x, {maxArrayLength: 0}))); +} + { const x = Array(101); assert(/^\[ ... 101 more items ]$/.test( @@ -901,7 +913,7 @@ checkAlignment(new Map(big_array.map(function(y) { return [y, null]; }))); // util.inspect.defaultOptions tests { - const arr = Array(101); + const arr = new Array(101).fill(); const obj = {a: {a: {a: {a: 1}}}}; const oldOptions = Object.assign({}, util.inspect.defaultOptions);