From 17aa99f367bca778b30943ca983945be81f22781 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 28 Dec 2018 02:27:14 +0100 Subject: [PATCH 1/5] util: switch recurseTimes counter This makes sure the counter goes up instead of going down. This allows to properly track the current inspection depth no matter what the `depth` option was set to. --- lib/internal/util/inspect.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 19eb165b780fe3..4a9f2d3e60b845 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -191,7 +191,7 @@ function inspect(value, opts) { } if (ctx.colors) ctx.stylize = stylizeWithColor; if (ctx.maxArrayLength === null) ctx.maxArrayLength = Infinity; - return formatValue(ctx, value, ctx.depth); + return formatValue(ctx, value, 0); } inspect.custom = customInspectSymbol; @@ -405,11 +405,10 @@ function getCtxStyle(constructor, tag) { } function formatProxy(ctx, proxy, recurseTimes) { - if (recurseTimes != null) { - if (recurseTimes < 0) - return ctx.stylize('Proxy [Array]', 'special'); - recurseTimes -= 1; + if (recurseTimes > ctx.depth && ctx.depth !== null) { + return ctx.stylize('Proxy [Array]', 'special'); } + recurseTimes += 1; ctx.indentationLvl += 2; const res = [ formatValue(ctx, proxy[0], recurseTimes), @@ -524,7 +523,10 @@ function formatValue(ctx, value, recurseTimes) { maybeCustom !== inspect && // Also filter out any prototype objects using the circular check. !(value.constructor && value.constructor.prototype === value)) { - const ret = maybeCustom.call(value, recurseTimes, ctx); + // This makes sure the recurseTimes are reported as before while using + // a counter internally. + const depth = ctx.depth === null ? null : ctx.depth - recurseTimes; + const ret = maybeCustom.call(value, depth, ctx); // If the custom inspection method returned `this`, don't go into // infinite recursion. @@ -638,7 +640,7 @@ function formatRaw(ctx, value, recurseTimes) { const prefix = getPrefix(constructor, tag, 'RegExp'); if (prefix !== 'RegExp ') base = `${prefix}${base}`; - if (keys.length === 0 || recurseTimes < 0) + if (keys.length === 0 || recurseTimes > ctx.depth && ctx.depth !== null) return ctx.stylize(base, 'regexp'); } else if (isDate(value)) { // Make dates with properties first say the date @@ -746,11 +748,10 @@ function formatRaw(ctx, value, recurseTimes) { } } - if (recurseTimes != null) { - if (recurseTimes < 0) - return ctx.stylize(`[${getCtxStyle(constructor, tag)}]`, 'special'); - recurseTimes -= 1; + if (recurseTimes > ctx.depth && ctx.depth !== null) { + return ctx.stylize(`[${getCtxStyle(constructor, tag)}]`, 'special'); } + recurseTimes += 1; ctx.seen.push(value); let output; From e73a36cbfad472ba17065ecd3c1c49c814a70648 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 28 Dec 2018 02:28:49 +0100 Subject: [PATCH 2/5] util: code cleanup Remove some dead code plus some minor refactoring for readability. The constructor can not be an empty string anymore, so just remove that check. --- lib/internal/util/inspect.js | 70 +++++++++++++----------------- test/parallel/test-util-inspect.js | 1 - 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 4a9f2d3e60b845..e0f23ab4b9d27a 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -209,34 +209,34 @@ Object.defineProperty(inspect, 'defaultOptions', { // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics inspect.colors = Object.assign(Object.create(null), { - 'bold': [1, 22], - 'italic': [3, 23], - 'underline': [4, 24], - 'inverse': [7, 27], - 'white': [37, 39], - 'grey': [90, 39], - 'black': [30, 39], - 'blue': [34, 39], - 'cyan': [36, 39], - 'green': [32, 39], - 'magenta': [35, 39], - 'red': [31, 39], - 'yellow': [33, 39] + bold: [1, 22], + italic: [3, 23], + underline: [4, 24], + inverse: [7, 27], + white: [37, 39], + grey: [90, 39], + black: [30, 39], + blue: [34, 39], + cyan: [36, 39], + green: [32, 39], + magenta: [35, 39], + red: [31, 39], + yellow: [33, 39] }); // Don't use 'blue' not visible on cmd.exe inspect.styles = Object.assign(Object.create(null), { - 'special': 'cyan', - 'number': 'yellow', - 'bigint': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'symbol': 'green', - 'date': 'magenta', + special: 'cyan', + number: 'yellow', + bigint: 'yellow', + boolean: 'yellow', + undefined: 'grey', + null: 'bold', + string: 'green', + symbol: 'green', + date: 'magenta', // "name": intentionally not styling - 'regexp': 'red' + regexp: 'red' }); function addQuotes(str, quotes) { @@ -356,14 +356,10 @@ function getPrefix(constructor, tag, fallback) { return `[${fallback}: null prototype] `; } - if (constructor !== '') { - if (tag !== '' && constructor !== tag) { - return `${constructor} [${tag}] `; - } - return `${constructor} `; + if (tag !== '' && constructor !== tag) { + return `${constructor} [${tag}] `; } - - return ''; + return `${constructor} `; } const getBoxedValue = formatPrimitive.bind(null, stylizeNoColor); @@ -617,16 +613,12 @@ function formatRaw(ctx, value, recurseTimes) { braces = ['{', '}']; if (constructor === 'Object') { if (isArgumentsObject(value)) { - if (keys.length === 0) - return '[Arguments] {}'; braces[0] = '[Arguments] {'; } else if (tag !== '') { braces[0] = `${getPrefix(constructor, tag, 'Object')}{`; - if (keys.length === 0) { - return `${braces[0]}}`; - } - } else if (keys.length === 0) { - return '{}'; + } + if (keys.length === 0) { + return `${braces[0]}}`; } } else if (typeof value === 'function') { const type = constructor || tag || 'Function'; @@ -811,9 +803,7 @@ function handleMaxCallStackSize(ctx, err, constructor, tag, indentationLvl) { function formatNumber(fn, value) { // Format -0 as '-0'. Checking `value === -0` won't distinguish 0 from -0. - if (Object.is(value, -0)) - return fn('-0', 'number'); - return fn(`${value}`, 'number'); + return fn(Object.is(value, -0) ? '-0' : `${value}`, 'number'); } function formatBigInt(fn, value) { diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 66887a10f48cd3..d06f748ba15c64 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -1791,7 +1791,6 @@ assert.strictEqual( util.inspect(new StorageObject()), '<[Object: null prototype] {}> {}' ); - } // Check that the fallback always works. From 65cad907580b2f36927b60e30593d5fe9c69da7b Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 28 Dec 2018 02:29:18 +0100 Subject: [PATCH 3/5] util: simpler module namespace code This removes a special casing for this data type in the main function. --- lib/internal/util/inspect.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index e0f23ab4b9d27a..db7ca06e251721 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -555,7 +555,6 @@ function formatRaw(ctx, value, recurseTimes) { let braces; let noIterator = true; let i = 0; - let skip = false; const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE; let extrasType = kObjectType; @@ -690,7 +689,6 @@ function formatRaw(ctx, value, recurseTimes) { } else if (isModuleNamespaceObject(value)) { braces[0] = `[${tag}] {`; formatter = formatNamespaceObject; - skip = true; } else if (isBoxedPrimitive(value)) { let type; if (isNumberObject(value)) { @@ -750,11 +748,9 @@ function formatRaw(ctx, value, recurseTimes) { const indentationLvl = ctx.indentationLvl; try { output = formatter(ctx, value, recurseTimes, keys); - if (skip === false) { - for (i = 0; i < keys.length; i++) { - output.push( - formatProperty(ctx, value, recurseTimes, keys[i], extrasType)); - } + for (i = 0; i < keys.length; i++) { + output.push( + formatProperty(ctx, value, recurseTimes, keys[i], extrasType)); } } catch (err) { return handleMaxCallStackSize(ctx, err, constructor, tag, indentationLvl); @@ -864,9 +860,8 @@ function formatError(value) { } function formatNamespaceObject(ctx, value, recurseTimes, keys) { - const len = keys.length; - const output = new Array(len); - for (var i = 0; i < len; i++) { + const output = new Array(keys.length); + for (var i = 0; i < keys.length; i++) { try { output[i] = formatProperty(ctx, value, recurseTimes, keys[i], kObjectType); @@ -886,6 +881,8 @@ function formatNamespaceObject(ctx, value, recurseTimes, keys) { ctx.stylize('', 'special'); } } + // Reset the keys to an empty array. This prevents duplicated inspection. + keys.length = 0; return output; } From 057882e179320d442f90dc84debf393c7f179d53 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 28 Dec 2018 02:30:40 +0100 Subject: [PATCH 4/5] util: remove outdated comment This comment is not correct anymore. --- lib/internal/util/inspect.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index db7ca06e251721..797cf4b539c026 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -1092,8 +1092,6 @@ function formatPromise(ctx, value, recurseTimes) { if (state === kPending) { output = [ctx.stylize('', 'special')]; } else { - // Using `formatValue` is correct here without the need to fix the - // indentation level. ctx.indentationLvl += 2; const str = formatValue(ctx, result, recurseTimes); ctx.indentationLvl -= 2; From 669c2f4cc207cad87c4fb7143e746298802d46bf Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 28 Dec 2018 02:42:27 +0100 Subject: [PATCH 5/5] util: remove eslint comments and rename variables This should improve the readability of the code. --- lib/internal/util/inspect.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 797cf4b539c026..609bb1bd260130 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -811,12 +811,11 @@ function formatPrimitive(fn, value, ctx) { if (ctx.compact === false && ctx.indentationLvl + value.length > ctx.breakLength && value.length > kMinLineLength) { - // eslint-disable-next-line max-len - const minLineLength = Math.max(ctx.breakLength - ctx.indentationLvl, kMinLineLength); - // eslint-disable-next-line max-len - const averageLineLength = Math.ceil(value.length / Math.ceil(value.length / minLineLength)); + const rawMaxLineLength = ctx.breakLength - ctx.indentationLvl; + const maxLineLength = Math.max(rawMaxLineLength, kMinLineLength); + const lines = Math.ceil(value.length / maxLineLength); + const averageLineLength = Math.ceil(value.length / lines); const divisor = Math.max(averageLineLength, kMinLineLength); - let res = ''; if (readableRegExps[divisor] === undefined) { // Build a new RegExp that naturally breaks text into multiple lines. // @@ -832,7 +831,7 @@ function formatPrimitive(fn, value, ctx) { const matches = value.match(readableRegExps[divisor]); if (matches.length > 1) { const indent = ' '.repeat(ctx.indentationLvl); - res += `${fn(strEscape(matches[0]), 'string')} +\n`; + let res = `${fn(strEscape(matches[0]), 'string')} +\n`; for (var i = 1; i < matches.length - 1; i++) { res += `${indent} ${fn(strEscape(matches[i]), 'string')} +\n`; }