Skip to content

Commit 8f4bb19

Browse files
committed
util: improve .inspect() array grouping
This improves a couple minor things: * Arrays that contain entries other than `number` or `bigint` are ordered to the left instead of the right. * The bias towards more columns got increased. That mainly increases the number of columns for arrays that contain lots of short entries. * Columns are now more dense in case they would otherwise have extra whitespace in-between two columns. * The maximum columns got increased from 10 to 15. * The maximum number of columns per `compact` was increased from 3 to 4. PR-URL: #28070 Refs: #27690 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 42f5f27 commit 8f4bb19

2 files changed

Lines changed: 134 additions & 120 deletions

File tree

‎lib/internal/util/inspect.js‎

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
777777
}
778778

779779
constres=reduceToSingleString(
780-
ctx,output,base,braces,extrasType,recurseTimes);
780+
ctx,output,base,braces,extrasType,recurseTimes,value);
781781
constbudget=ctx.budget[ctx.indentationLvl]||0;
782782
constnewLength=budget+res.length;
783783
ctx.budget[ctx.indentationLvl]=newLength;
@@ -940,7 +940,7 @@ function formatError(err, constructor, tag, ctx) {
940940
returnstack;
941941
}
942942

943-
functiongroupArrayElements(ctx,output){
943+
functiongroupArrayElements(ctx,output,value){
944944
lettotalLength=0;
945945
letmaxLength=0;
946946
leti=0;
@@ -972,51 +972,73 @@ function groupArrayElements(ctx, output) {
972972
(totalLength/actualMax>5||maxLength<=6)){
973973

974974
constapproxCharHeights=2.5;
975-
constbias=1;
975+
constbiasedMax=Math.max(actualMax-4,1);
976976
// Dynamically check how many columns seem possible.
977977
constcolumns=Math.min(
978978
// Ideally a square should be drawn. We expect a character to be about 2.5
979979
// times as high as wide. This is the area formula to calculate a square
980980
// which contains n rectangles of size `actualMax * approxCharHeights`.
981981
// Divide that by `actualMax` to receive the correct number of columns.
982-
// The added bias slightly increases the columns for short entries.
982+
// The added bias increases the columns for short entries.
983983
Math.round(
984984
Math.sqrt(
985-
approxCharHeights*(actualMax-bias)*outputLength
986-
)/(actualMax-bias)
985+
approxCharHeights*biasedMax*outputLength
986+
)/biasedMax
987987
),
988988
// Do not exceed the breakLength.
989989
Math.floor((ctx.breakLength-ctx.indentationLvl)/actualMax),
990990
// Limit array grouping for small `compact` modes as the user requested
991991
// minimal grouping.
992-
ctx.compact*3,
993-
// Limit the columns to a maximum of ten.
994-
10
992+
ctx.compact*4,
993+
// Limit the columns to a maximum of fifteen.
994+
15
995995
);
996996
// Return with the original output if no grouping should happen.
997997
if(columns<=1){
998998
returnoutput;
999999
}
1000-
// Calculate the maximum length of all entries that are visible in the first
1001-
// column of the group.
10021000
consttmp=[];
1003-
letfirstLineMaxLength=dataLen[0];
1004-
for(i=columns;i<dataLen.length;i+=columns){
1005-
if(dataLen[i]>firstLineMaxLength)
1006-
firstLineMaxLength=dataLen[i];
1001+
constmaxLineLength=[];
1002+
for(leti=0;i<columns;i++){
1003+
letlineMaxLength=0;
1004+
for(letj=i;j<output.length;j+=columns){
1005+
if(dataLen[j]>lineMaxLength)
1006+
lineMaxLength=dataLen[j];
1007+
}
1008+
lineMaxLength+=separatorSpace;
1009+
maxLineLength[i]=lineMaxLength;
1010+
}
1011+
letorder='padStart';
1012+
if(value!==undefined){
1013+
for(leti=0;i<output.length;i++){
1014+
// eslint-disable-next-line valid-typeof
1015+
if(typeofvalue[i]!=='number'&&typeofvalue[i]!=='bigint'){
1016+
order='padEnd';
1017+
break;
1018+
}
1019+
}
10071020
}
10081021
// Each iteration creates a single line of grouped entries.
1009-
for(i=0;i<outputLength;i+=columns){
1010-
// Calculate extra color padding in case it's active. This has to be done
1011-
// line by line as some lines might contain more colors than others.
1012-
letcolorPadding=output[i].length-dataLen[i];
1013-
// Add padding to the first column of the output.
1014-
letstr=output[i].padStart(firstLineMaxLength+colorPadding,' ');
1022+
for(leti=0;i<outputLength;i+=columns){
10151023
// The last lines may contain less entries than columns.
10161024
constmax=Math.min(i+columns,outputLength);
1017-
for(varj=i+1;j<max;j++){
1018-
colorPadding=output[j].length-dataLen[j];
1019-
str+=`, ${output[j].padStart(maxLength+colorPadding,' ')}`;
1025+
letstr='';
1026+
letj=i;
1027+
for(;j<max-1;j++){
1028+
// Calculate extra color padding in case it's active. This has to be
1029+
// done line by line as some lines might contain more colors than
1030+
// others.
1031+
constpadding=maxLineLength[j-i]+output[j].length-dataLen[j];
1032+
str+=`${output[j]}, `[order](padding,' ');
1033+
}
1034+
if(order==='padStart'){
1035+
constpadding=maxLineLength[j-i]+
1036+
output[j].length-
1037+
dataLen[j]-
1038+
separatorSpace;
1039+
str+=output[j].padStart(padding,' ');
1040+
}else{
1041+
str+=output[j];
10201042
}
10211043
tmp.push(str);
10221044
}
@@ -1419,7 +1441,7 @@ function isBelowBreakLength(ctx, output, start, base) {
14191441
}
14201442

14211443
functionreduceToSingleString(
1422-
ctx,output,base,braces,extrasType,recurseTimes){
1444+
ctx,output,base,braces,extrasType,recurseTimes,value){
14231445
if(ctx.compact!==true){
14241446
if(typeofctx.compact==='number'&&ctx.compact>=1){
14251447
// Memorize the original output length. In case the the output is grouped,
@@ -1428,7 +1450,7 @@ function reduceToSingleString(
14281450
// Group array elements together if the array contains at least six
14291451
// separate entries.
14301452
if(extrasType===kArrayExtrasType&&entries>6){
1431-
output=groupArrayElements(ctx,output);
1453+
output=groupArrayElements(ctx,output,value);
14321454
}
14331455
// `ctx.currentDepth` is set to the most inner depth of the currently
14341456
// inspected object part while `recurseTimes` is the actual current depth

‎test/parallel/test-util-inspect.js‎

Lines changed: 86 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,11 +1306,11 @@ if (typeof Symbol !== 'undefined') {
13061306
{
13071307
constx=newUint8Array(101);
13081308
assert(util.inspect(x).endsWith('1 more item\n]'));
1309-
assert(!util.inspect(x,{maxArrayLength: 101}).endsWith('1 more item\n]'));
1309+
assert(!util.inspect(x,{maxArrayLength: 101}).includes('1 more item'));
13101310
assert.strictEqual(util.inspect(x,{maxArrayLength: 0}),
13111311
'Uint8Array [ ... 101 more items ]');
1312-
assert(!util.inspect(x,{maxArrayLength: null}).endsWith('1 more item\n]'));
1313-
assert(util.inspect(x,{maxArrayLength: Infinity}).endsWith(' 0, 0\n]'));
1312+
assert(!util.inspect(x,{maxArrayLength: null}).includes('1 more item'));
1313+
assert(util.inspect(x,{maxArrayLength: Infinity}).endsWith(' 0, 0\n]'));
13141314
}
13151315

13161316
{
@@ -1940,7 +1940,7 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
19401940
[WeakMap,[[[{},{}]]],'{ <items unknown> }'],
19411941
[BigInt64Array,
19421942
[10],
1943-
'[\n 0n, 0n, 0n,\n 0n, 0n, 0n,\n 0n, 0n, 0n,\n 0n\n]'],
1943+
'[\n 0n, 0n, 0n,0n, 0n,\n 0n, 0n, 0n, 0n, 0n\n]'],
19441944
[Date,['Sun, 14 Feb 2010 11:48:40 GMT'],'2010-02-14T11:48:40.000Z'],
19451945
[Date,['invalid_date'],'Invalid Date']
19461946
].forEach(([base,input,rawExpected])=>{
@@ -2180,21 +2180,18 @@ assert.strictEqual(
21802180
' b: [ 1, 2, [ 1, 2, { a: 1, b: 2, c: 3 } ] ],',
21812181
" c: [ 'foo', 4, 444444 ],",
21822182
' d: [',
2183-
' 0, 1, 4, 3, 16, 5, 36,',
2184-
' 7, 64, 9, 100, 11, 144, 13,',
2185-
' 196, 15, 256, 17, 324, 19, 400,',
2186-
' 21, 484, 23, 576, 25, 676, 27,',
2187-
' 784, 29, 900, 31, 1024, 33, 1156,',
2188-
' 35, 1296, 37, 1444, 39, 1600, 41,',
2189-
' 1764, 43, 1936, 45, 2116, 47, 2304,',
2190-
' 49, 2500, 51, 2704, 53, 2916, 55,',
2191-
' 3136, 57, 3364, 59, 3600, 61, 3844,',
2192-
' 63, 4096, 65, 4356, 67, 4624, 69,',
2193-
' 4900, 71, 5184, 73, 5476, 75, 5776,',
2194-
' 77, 6084, 79, 6400, 81, 6724, 83,',
2195-
' 7056, 85, 7396, 87, 7744, 89, 8100,',
2196-
' 91, 8464, 93, 8836, 95, 9216, 97,',
2197-
' 9604, 99,',
2183+
' 0, 1, 4, 3, 16, 5, 36, 7, 64,',
2184+
' 9, 100, 11, 144, 13, 196, 15, 256, 17,',
2185+
' 324, 19, 400, 21, 484, 23, 576, 25, 676,',
2186+
' 27, 784, 29, 900, 31, 1024, 33, 1156, 35,',
2187+
' 1296, 37, 1444, 39, 1600, 41, 1764, 43, 1936,',
2188+
' 45, 2116, 47, 2304, 49, 2500, 51, 2704, 53,',
2189+
' 2916, 55, 3136, 57, 3364, 59, 3600, 61, 3844,',
2190+
' 63, 4096, 65, 4356, 67, 4624, 69, 4900, 71,',
2191+
' 5184, 73, 5476, 75, 5776, 77, 6084, 79, 6400,',
2192+
' 81, 6724, 83, 7056, 85, 7396, 87, 7744, 89,',
2193+
' 8100, 91, 8464, 93, 8836, 95, 9216, 97, 9604,',
2194+
' 99,',
21982195
' ... 1 more item',
21992196
' ],',
22002197
' e: [',
@@ -2226,10 +2223,8 @@ assert.strictEqual(
22262223
" 'foobar baz'",
22272224
' ],',
22282225
' h: [',
2229-
' 100, 0, 1,',
2230-
' 2, 3, 4,',
2231-
' 5, 6, 7,',
2232-
' 8',
2226+
' 100, 0, 1, 2, 3,',
2227+
' 4, 5, 6, 7, 8',
22332228
' ],',
22342229
' long: [',
22352230
" 'This text is too long for grouping!',",
@@ -2257,15 +2252,15 @@ assert.strictEqual(
22572252

22582253
expected=[
22592254
'[',
2260-
' 1, 1, 1,',
2261-
' 1, 1, 1,',
2262-
' 1, 1, 1,',
2263-
' 1, 1, 1,',
2264-
' 1, 1, 1,',
2265-
' 1, 1, 1,',
2266-
' 1, 1, 1,',
2267-
' 1, 1, 1,',
2268-
' 1, 1, 123456789',
2255+
' 1, 1, 1,',
2256+
' 1, 1, 1,',
2257+
' 1, 1, 1,',
2258+
' 1, 1, 1,',
2259+
' 1, 1, 1,',
2260+
' 1, 1, 1,',
2261+
' 1, 1, 1,',
2262+
' 1, 1, 1,',
2263+
' 1, 1, 123456789',
22692264
']'
22702265
].join('\n');
22712266

@@ -2295,10 +2290,10 @@ assert.strictEqual(
22952290
' b: { x: \u001b[33m5\u001b[39m, c: \u001b[36m[Object]\u001b[39m }',
22962291
' },',
22972292
' b: [',
2298-
" \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2299-
" \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2300-
" \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2301-
" \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2293+
" \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2294+
" \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2295+
" \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2296+
" \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
23022297
" \u001b[32m'foobar'\u001b[39m",
23032298
' ]',
23042299
'}',
@@ -2311,26 +2306,23 @@ assert.strictEqual(
23112306

23122307
expected=[
23132308
'[',
2314-
' \u001b[33m0\u001b[39m, \u001b[33m1\u001b[39m, \u001b[33m2\u001b[39m,',
2315-
' \u001b[33m3\u001b[39m, \u001b[33m4\u001b[39m, \u001b[33m5\u001b[39m,',
2316-
' \u001b[33m6\u001b[39m, \u001b[33m7\u001b[39m, \u001b[33m8\u001b[39m,',
2317-
' \u001b[33m9\u001b[39m, \u001b[33m10\u001b[39m, \u001b[33m11\u001b[39m,',
2318-
' \u001b[33m12\u001b[39m, \u001b[33m13\u001b[39m, \u001b[33m14\u001b[39m,',
2319-
' \u001b[33m15\u001b[39m, \u001b[33m16\u001b[39m, \u001b[33m17\u001b[39m,',
2320-
' \u001b[33m18\u001b[39m, \u001b[33m19\u001b[39m, \u001b[33m20\u001b[39m,',
2321-
' \u001b[33m21\u001b[39m, \u001b[33m22\u001b[39m, \u001b[33m23\u001b[39m,',
2322-
' \u001b[33m24\u001b[39m, \u001b[33m25\u001b[39m, \u001b[33m26\u001b[39m,',
2323-
' \u001b[33m27\u001b[39m, \u001b[33m28\u001b[39m, \u001b[33m29\u001b[39m,',
2324-
' \u001b[33m30\u001b[39m, \u001b[33m31\u001b[39m, \u001b[33m32\u001b[39m,',
2325-
' \u001b[33m33\u001b[39m, \u001b[33m34\u001b[39m, \u001b[33m35\u001b[39m,',
2326-
' \u001b[33m36\u001b[39m, \u001b[33m37\u001b[39m, \u001b[33m38\u001b[39m,',
2327-
' \u001b[33m39\u001b[39m, \u001b[33m40\u001b[39m, \u001b[33m41\u001b[39m,',
2328-
' \u001b[33m42\u001b[39m, \u001b[33m43\u001b[39m, \u001b[33m44\u001b[39m,',
2329-
' \u001b[33m45\u001b[39m, \u001b[33m46\u001b[39m, \u001b[33m47\u001b[39m,',
2330-
' \u001b[33m48\u001b[39m, \u001b[33m49\u001b[39m, \u001b[33m50\u001b[39m,',
2331-
' \u001b[33m51\u001b[39m, \u001b[33m52\u001b[39m, \u001b[33m53\u001b[39m,',
2332-
' \u001b[33m54\u001b[39m, \u001b[33m55\u001b[39m, \u001b[33m56\u001b[39m,',
2333-
' \u001b[33m57\u001b[39m, \u001b[33m58\u001b[39m, \u001b[33m59\u001b[39m',
2309+
/* eslint-disable max-len */
2310+
' \u001b[33m0\u001b[39m, \u001b[33m1\u001b[39m, \u001b[33m2\u001b[39m, \u001b[33m3\u001b[39m,',
2311+
' \u001b[33m4\u001b[39m, \u001b[33m5\u001b[39m, \u001b[33m6\u001b[39m, \u001b[33m7\u001b[39m,',
2312+
' \u001b[33m8\u001b[39m, \u001b[33m9\u001b[39m, \u001b[33m10\u001b[39m, \u001b[33m11\u001b[39m,',
2313+
' \u001b[33m12\u001b[39m, \u001b[33m13\u001b[39m, \u001b[33m14\u001b[39m, \u001b[33m15\u001b[39m,',
2314+
' \u001b[33m16\u001b[39m, \u001b[33m17\u001b[39m, \u001b[33m18\u001b[39m, \u001b[33m19\u001b[39m,',
2315+
' \u001b[33m20\u001b[39m, \u001b[33m21\u001b[39m, \u001b[33m22\u001b[39m, \u001b[33m23\u001b[39m,',
2316+
' \u001b[33m24\u001b[39m, \u001b[33m25\u001b[39m, \u001b[33m26\u001b[39m, \u001b[33m27\u001b[39m,',
2317+
' \u001b[33m28\u001b[39m, \u001b[33m29\u001b[39m, \u001b[33m30\u001b[39m, \u001b[33m31\u001b[39m,',
2318+
' \u001b[33m32\u001b[39m, \u001b[33m33\u001b[39m, \u001b[33m34\u001b[39m, \u001b[33m35\u001b[39m,',
2319+
' \u001b[33m36\u001b[39m, \u001b[33m37\u001b[39m, \u001b[33m38\u001b[39m, \u001b[33m39\u001b[39m,',
2320+
' \u001b[33m40\u001b[39m, \u001b[33m41\u001b[39m, \u001b[33m42\u001b[39m, \u001b[33m43\u001b[39m,',
2321+
' \u001b[33m44\u001b[39m, \u001b[33m45\u001b[39m, \u001b[33m46\u001b[39m, \u001b[33m47\u001b[39m,',
2322+
' \u001b[33m48\u001b[39m, \u001b[33m49\u001b[39m, \u001b[33m50\u001b[39m, \u001b[33m51\u001b[39m,',
2323+
' \u001b[33m52\u001b[39m, \u001b[33m53\u001b[39m, \u001b[33m54\u001b[39m, \u001b[33m55\u001b[39m,',
2324+
' \u001b[33m56\u001b[39m, \u001b[33m57\u001b[39m, \u001b[33m58\u001b[39m, \u001b[33m59\u001b[39m',
2325+
/* eslint-enable max-len */
23342326
']'
23352327
].join('\n');
23362328

@@ -2389,44 +2381,44 @@ assert.strictEqual(
23892381
);
23902382
expected=[
23912383
'[',
2392-
" 'Object', 'Function', 'Array',",
2393-
" 'Number', 'parseFloat', 'parseInt',",
2394-
" 'Infinity', 'NaN', 'undefined',",
2395-
" 'Boolean', 'String', 'Symbol',",
2396-
" 'Date', 'Promise', 'RegExp',",
2397-
" 'Error', 'EvalError', 'RangeError',",
2398-
" 'ReferenceError', 'SyntaxError', 'TypeError',",
2399-
" 'URIError', 'JSON', 'Math',",
2400-
" 'console', 'Intl', 'ArrayBuffer',",
2401-
" 'Uint8Array', 'Int8Array', 'Uint16Array',",
2402-
" 'Int16Array', 'Uint32Array', 'Int32Array',",
2403-
" 'Float32Array', 'Float64Array', 'Uint8ClampedArray',",
2404-
" 'BigUint64Array', 'BigInt64Array', 'DataView',",
2405-
" 'Map', 'BigInt', 'Set',",
2406-
" 'WeakMap', 'WeakSet', 'Proxy',",
2407-
" 'Reflect', 'decodeURI', 'decodeURIComponent',",
2408-
" 'encodeURI', 'encodeURIComponent', 'escape',",
2409-
" 'unescape', 'eval', 'isFinite',",
2410-
" 'isNaN', 'SharedArrayBuffer', 'Atomics',",
2411-
" 'globalThis', 'WebAssembly', 'global',",
2412-
" 'process', 'GLOBAL', 'root',",
2413-
" 'Buffer', 'URL', 'URLSearchParams',",
2414-
" 'TextEncoder', 'TextDecoder', 'clearInterval',",
2415-
" 'clearTimeout', 'setInterval', 'setTimeout',",
2416-
" 'queueMicrotask', 'clearImmediate', 'setImmediate',",
2417-
" 'module', 'require', 'assert',",
2418-
" 'async_hooks', 'buffer', 'child_process',",
2419-
" 'cluster', 'crypto', 'dgram',",
2420-
" 'dns', 'domain', 'events',",
2421-
" 'fs', 'http', 'http2',",
2422-
" 'https', 'inspector', 'net',",
2423-
" 'os', 'path', 'perf_hooks',",
2424-
" 'punycode', 'querystring', 'readline',",
2425-
" 'repl', 'stream', 'string_decoder',",
2426-
" 'tls', 'trace_events', 'tty',",
2427-
" 'url', 'v8', 'vm',",
2428-
" 'worker_threads', 'zlib', '_',",
2429-
" '_error', 'util'",
2384+
" 'Object', 'Function', 'Array',",
2385+
" 'Number', 'parseFloat', 'parseInt',",
2386+
" 'Infinity', 'NaN', 'undefined',",
2387+
" 'Boolean', 'String', 'Symbol',",
2388+
" 'Date', 'Promise', 'RegExp',",
2389+
" 'Error', 'EvalError', 'RangeError',",
2390+
" 'ReferenceError', 'SyntaxError', 'TypeError',",
2391+
" 'URIError', 'JSON', 'Math',",
2392+
" 'console', 'Intl', 'ArrayBuffer',",
2393+
" 'Uint8Array', 'Int8Array', 'Uint16Array',",
2394+
" 'Int16Array', 'Uint32Array', 'Int32Array',",
2395+
" 'Float32Array', 'Float64Array', 'Uint8ClampedArray',",
2396+
" 'BigUint64Array', 'BigInt64Array', 'DataView',",
2397+
" 'Map', 'BigInt', 'Set',",
2398+
" 'WeakMap', 'WeakSet', 'Proxy',",
2399+
" 'Reflect', 'decodeURI', 'decodeURIComponent',",
2400+
" 'encodeURI', 'encodeURIComponent', 'escape',",
2401+
" 'unescape', 'eval', 'isFinite',",
2402+
" 'isNaN', 'SharedArrayBuffer', 'Atomics',",
2403+
" 'globalThis', 'WebAssembly', 'global',",
2404+
" 'process', 'GLOBAL', 'root',",
2405+
" 'Buffer', 'URL', 'URLSearchParams',",
2406+
" 'TextEncoder', 'TextDecoder', 'clearInterval',",
2407+
" 'clearTimeout', 'setInterval', 'setTimeout',",
2408+
" 'queueMicrotask', 'clearImmediate', 'setImmediate',",
2409+
" 'module', 'require', 'assert',",
2410+
" 'async_hooks', 'buffer', 'child_process',",
2411+
" 'cluster', 'crypto', 'dgram',",
2412+
" 'dns', 'domain', 'events',",
2413+
" 'fs', 'http', 'http2',",
2414+
" 'https', 'inspector', 'net',",
2415+
" 'os', 'path', 'perf_hooks',",
2416+
" 'punycode', 'querystring', 'readline',",
2417+
" 'repl', 'stream', 'string_decoder',",
2418+
" 'tls', 'trace_events', 'tty',",
2419+
" 'url', 'v8', 'vm',",
2420+
" 'worker_threads', 'zlib', '_',",
2421+
" '_error', 'util'",
24302422
']'
24312423
].join('\n');
24322424

0 commit comments

Comments
 (0)