util: refactor inspecting long lines

Using the `util.inspect` `compact` mode set to something else than
`true` resulted in breaking long lines in case the line would exceed
the `breakLength` option and if it contained whitespace and or new
lines.

It turned out that this behavior was less useful than originally
expected and it is now changed to only break on line breaks if the
`breakLength` option is exceeded for the inspected string. This should
be align better with the user expectation than the former behavior.

PR-URL: https://github.com/nodejs/node/pull/28055
Fixes: https://github.com/nodejs/node/issues/27690
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
Ruben Bridgewater 2019-06-02 16:07:08 +02:00
parent 62ac84b5f8
commit 26de13a15c
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
2 changed files with 22 additions and 79 deletions

View File

@ -127,8 +127,6 @@ const numberRegExp = /^(0|[1-9][0-9]*)$/;
const coreModuleRegExp = /^ at (?:[^/\\(]+ \(|)((?<![/\\]).+)\.js:\d+:\d+\)?$/; const coreModuleRegExp = /^ at (?:[^/\\(]+ \(|)((?<![/\\]).+)\.js:\d+:\d+\)?$/;
const nodeModulesRegExp = /[/\\]node_modules[/\\](.+?)(?=[/\\])/g; const nodeModulesRegExp = /[/\\]node_modules[/\\](.+?)(?=[/\\])/g;
const readableRegExps = {};
const kMinLineLength = 16; const kMinLineLength = 16;
// Constants to map the iterator state. // Constants to map the iterator state.
@ -1080,37 +1078,12 @@ function formatBigInt(fn, value) {
function formatPrimitive(fn, value, ctx) { function formatPrimitive(fn, value, ctx) {
if (typeof value === 'string') { if (typeof value === 'string') {
if (ctx.compact !== true && if (ctx.compact !== true &&
ctx.indentationLvl + value.length + 4 > ctx.breakLength && value.length > kMinLineLength &&
value.length > kMinLineLength) { value.length > ctx.breakLength - ctx.indentationLvl - 4) {
// Subtract the potential quotes, the space and the plus as well (4). return value
const rawMaxLineLength = ctx.breakLength - ctx.indentationLvl - 4; .split(/(?<=\n)/)
const maxLineLength = Math.max(rawMaxLineLength, kMinLineLength); .map((line) => fn(strEscape(line), 'string'))
const lines = Math.ceil(value.length / maxLineLength); .join(` +\n${' '.repeat(ctx.indentationLvl + 2)}`);
const averageLineLength = Math.ceil(value.length / lines);
const divisor = Math.max(averageLineLength, kMinLineLength);
if (readableRegExps[divisor] === undefined) {
// Build a new RegExp that naturally breaks text into multiple lines.
//
// Rules
// 1. Greedy match all text up the max line length that ends with a
// whitespace or the end of the string.
// 2. If none matches, non-greedy match any text up to a whitespace or
// the end of the string.
//
// eslint-disable-next-line max-len, node-core/no-unescaped-regexp-dot
readableRegExps[divisor] = new RegExp(`(.|\\n){1,${divisor}}(\\s|$)|(\\n|.)+?(\\s|$)`, 'gm');
}
const matches = value.match(readableRegExps[divisor]);
if (matches.length > 1) {
const indent = ' '.repeat(ctx.indentationLvl);
let res = `${fn(strEscape(matches[0]), 'string')} +\n`;
const lastIndex = matches.length - 1;
for (let i = 1; i < lastIndex; i++) {
res += `${indent} ${fn(strEscape(matches[i]), 'string')} +\n`;
}
res += `${indent} ${fn(strEscape(matches[lastIndex]), 'string')}`;
return res;
}
} }
return fn(strEscape(value), 'string'); return fn(strEscape(value), 'string');
} }

View File

@ -93,7 +93,7 @@ assert.strictEqual(util.inspect(new Date('')), (new Date('')).toString());
assert.strictEqual(util.inspect('\n\u0001'), "'\\n\\u0001'"); assert.strictEqual(util.inspect('\n\u0001'), "'\\n\\u0001'");
assert.strictEqual( assert.strictEqual(
util.inspect(`${Array(75).fill(1)}'\n\u001d\n\u0003`), util.inspect(`${Array(75).fill(1)}'\n\u001d\n\u0003`),
`"${Array(75).fill(1)}'\\n" +\n '\\u001d\\n\\u0003'` `"${Array(75).fill(1)}'\\n" +\n '\\u001d\\n' +\n '\\u0003'`
); );
assert.strictEqual(util.inspect([]), '[]'); assert.strictEqual(util.inspect([]), '[]');
assert.strictEqual(util.inspect(Object.create([])), 'Array {}'); assert.strictEqual(util.inspect(Object.create([])), 'Array {}');
@ -1509,10 +1509,9 @@ util.inspect(process);
' 2,', ' 2,',
' [', ' [',
' [', ' [',
" 'Lorem ipsum dolor\\nsit amet,\\tconsectetur ' +", " 'Lorem ipsum dolor\\n' +",
" 'adipiscing elit, sed do eiusmod tempor ' +", " 'sit amet,\\tconsectetur adipiscing elit, sed do eiusmod " +
" 'incididunt ut labore et dolore magna ' +", "tempor incididunt ut labore et dolore magna aliqua.',",
" 'aliqua.',",
" 'test',", " 'test',",
" 'foo'", " 'foo'",
' ]', ' ]',
@ -1529,12 +1528,9 @@ util.inspect(process);
out = util.inspect(o.a[2][0][0], { compact: false, breakLength: 30 }); out = util.inspect(o.a[2][0][0], { compact: false, breakLength: 30 });
expect = [ expect = [
"'Lorem ipsum dolor\\nsit ' +", "'Lorem ipsum dolor\\n' +",
" 'amet,\\tconsectetur ' +", " 'sit amet,\\tconsectetur adipiscing elit, sed do eiusmod tempor " +
" 'adipiscing elit, sed do ' +", "incididunt ut labore et dolore magna aliqua.'"
" 'eiusmod tempor incididunt ' +",
" 'ut labore et dolore magna ' +",
" 'aliqua.'"
].join('\n'); ].join('\n');
assert.strictEqual(out, expect); assert.strictEqual(out, expect);
@ -1548,30 +1544,7 @@ util.inspect(process);
'12 45 78 01 34 67 90 23 56 89 123456789012345678901234567890', '12 45 78 01 34 67 90 23 56 89 123456789012345678901234567890',
{ compact: false, breakLength: 3 }); { compact: false, breakLength: 3 });
expect = [ expect = [
"'12 45 78 01 34 ' +", "'12 45 78 01 34 67 90 23 56 89 123456789012345678901234567890'"
" '67 90 23 56 89 ' +",
" '123456789012345678901234567890'"
].join('\n');
assert.strictEqual(out, expect);
out = util.inspect(
'12 45 78 01 34 67 90 23 56 89 1234567890123 0',
{ compact: false, breakLength: 3 });
expect = [
"'12 45 78 01 34 ' +",
" '67 90 23 56 89 ' +",
" '1234567890123 0'"
].join('\n');
assert.strictEqual(out, expect);
out = util.inspect(
'12 45 78 01 34 67 90 23 56 89 12345678901234567 0',
{ compact: false, breakLength: 3 });
expect = [
"'12 45 78 01 34 ' +",
" '67 90 23 56 89 ' +",
" '12345678901234567 ' +",
" '0'"
].join('\n'); ].join('\n');
assert.strictEqual(out, expect); assert.strictEqual(out, expect);
@ -1610,7 +1583,7 @@ util.inspect(process);
o[util.inspect.custom] = () => ({ a: '12 45 78 01 34 67 90 23' }); o[util.inspect.custom] = () => ({ a: '12 45 78 01 34 67 90 23' });
out = util.inspect(o, { compact: false, breakLength: 3 }); out = util.inspect(o, { compact: false, breakLength: 3 });
expect = "{\n a: '12 45 78 01 34 ' +\n '67 90 23'\n}"; expect = "{\n a: '12 45 78 01 34 67 90 23'\n}";
assert.strictEqual(out, expect); assert.strictEqual(out, expect);
} }
@ -2214,16 +2187,13 @@ assert.strictEqual(
' b: {', ' b: {',
' x: 5,', ' x: 5,',
' c: {', ' c: {',
" x: '10000000000000000 00000000000000000 ' +", " x: '10000000000000000 00000000000000000 10000000000000000 " +
" '10000000000000000 00000000000000000 ' +", '00000000000000000 10000000000000000 00000000000000000 ' +
" '10000000000000000 00000000000000000 ' +", '10000000000000000 00000000000000000 10000000000000000 ' +
" '10000000000000000 00000000000000000 ' +", '00000000000000000 10000000000000000 00000000000000000 ' +
" '10000000000000000 00000000000000000 ' +", '10000000000000000 00000000000000000 10000000000000000 ' +
" '10000000000000000 00000000000000000 ' +", '00000000000000000 10000000000000000 00000000000000000 ' +
" '10000000000000000 00000000000000000 ' +", "10000000000000000 00000000000000000 ',",
" '10000000000000000 00000000000000000 ' +",
" '10000000000000000 00000000000000000 ' +",
" '10000000000000000 00000000000000000 ',",
' d: 2,', ' d: 2,',
' e: 3', ' e: 3',
' }', ' }',