From 0646ee4f2cfab9abd3071b2775368d62ec6dc316 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 21 Nov 2019 15:12:58 +0100 Subject: [PATCH 1/5] util: improve inspect's customInspect performance This improves the performance to copy user options that are then passed through to the custom inspect function. The performance improvement depends on the complexity of the custom inspect function. For very basic cases this is 100% faster than before. --- lib/internal/util/inspect.js | 21 ++++++++++++++------- test/parallel/test-util-inspect.js | 9 +++++++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 3e93a41795c8d8..896d8319b18375 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -173,13 +173,20 @@ const meta = [ ]; function getUserOptions(ctx) { - const obj = { stylize: ctx.stylize }; - for (const key of ObjectKeys(inspectDefaultOptions)) { - obj[key] = ctx[key]; - } - if (ctx.userOptions === undefined) - return obj; - return { ...obj, ...ctx.userOptions }; + return { + stylize: ctx.stylize, + showHidden: ctx.showHidden, + depth: ctx.depth, + colors: ctx.colors, + customInspect: ctx.customInspect, + showProxy: ctx.showProxy, + maxArrayLength: ctx.maxArrayLength, + breakLength: ctx.breakLength, + compact: ctx.compact, + sorted: ctx.sorted, + getters: ctx.getters, + ...ctx.userOptions + }; } /** diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index b48bb56736da47..7dd151f289418e 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -855,6 +855,10 @@ util.inspect({ hasOwnProperty: null }); assert.strictEqual(opts.budget, undefined); assert.strictEqual(opts.indentationLvl, undefined); assert.strictEqual(opts.showHidden, false); + assert.deepStrictEqual( + new Set(Object.keys(util.inspect.defaultOptions).concat(['stylize'])), + new Set(Object.keys(opts)) + ); opts.showHidden = true; return { [util.inspect.custom]: common.mustCall((depth, opts2) => { assert.deepStrictEqual(clone, opts2); @@ -881,10 +885,11 @@ util.inspect({ hasOwnProperty: null }); } { - const subject = { [util.inspect.custom]: common.mustCall((depth) => { + const subject = { [util.inspect.custom]: common.mustCall((depth, opts) => { assert.strictEqual(depth, null); + assert.strictEqual(opts.compact, true); }) }; - util.inspect(subject, { depth: null }); + util.inspect(subject, { depth: null, compact: true }); } { From de5d3a581c7a0c12d9157d1e531051f6ce823a4d Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Tue, 26 Nov 2019 00:32:16 +0100 Subject: [PATCH 2/5] util: add more predefined color codes to inspect.colors This adds most commonly used ANSI color codes to `util.inspect.colors`. --- doc/api/util.md | 66 +++++++++++++++++++++-- lib/internal/util/inspect.js | 85 ++++++++++++++++++++++++++---- test/parallel/test-util-inspect.js | 28 ++++++++++ 3 files changed, 164 insertions(+), 15 deletions(-) diff --git a/doc/api/util.md b/doc/api/util.md index ac23f138ad0d17..c564ded67aef19 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -678,13 +678,71 @@ The default styles and associated colors are: * `symbol`: `green` * `undefined`: `grey` -The predefined color codes are: `white`, `grey`, `black`, `blue`, `cyan`, -`green`, `magenta`, `red` and `yellow`. There are also `bold`, `italic`, -`underline` and `inverse` codes. - Color styling uses ANSI control codes that may not be supported on all terminals. To verify color support use [`tty.hasColors()`][]. +The predefined color codes are: + +#### Modifiers + +Modifier support varies throughout different terminals. They will mostly be +ignored, if not supported. + +* `reset` - Resets all (color) modifiers to their defaults +* **bold** - Make text bold +* _italic_ - Make text italic +* underline - Make text underlined +* ~~strikethrough~~ - Puts a horizontal line through the center of the text + (Alias: `strikeThrough`, `crossedout`, `crossedOut`) +* `hidden` - Prints the text, but makes it invisible (Alias: conceal) +* dim - Decreased color intensity (Alias: + `faint`) +* overlined - Make text overlined +* blink - Hides and shows the text in an interval +* inverse - Swap foreground and + background colors (Alias: `swapcolors`, `swapColors`) +* doubleunderline - Make text + double underlined (Alias: `doubleUnderline`) +* framed - Draw a frame around the text + +#### Colors + +* `black` +* `red` +* `green` +* `yellow` +* `blue` +* `magenta` +* `cyan` +* `white` +* `gray` (alias: `grey`, `blackBright`) +* `redBright` +* `greenBright` +* `yellowBright` +* `blueBright` +* `magentaBright` +* `cyanBright` +* `whiteBright` + +#### Background colors + +* `bgBlack` +* `bgRed` +* `bgGreen` +* `bgYellow` +* `bgBlue` +* `bgMagenta` +* `bgCyan` +* `bgWhite` +* `bgGray` (alias: `bgGrey`, `bgBlackBright`) +* `bgRedBright` +* `bgGreenBright` +* `bgYellowBright` +* `bgBlueBright` +* `bgMagentaBright` +* `bgCyanBright` +* `bgWhiteBright` + ### Custom inspection functions on Objects diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 896d8319b18375..a6668f6da86e2a 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -264,23 +264,85 @@ ObjectDefineProperty(inspect, 'defaultOptions', { } }); -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +// Set Graphics Rendition http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +// Each color consists of an array with the color code as first entry and the +// reset code as second entry. +const defaultFG = 39; +const defaultBG = 49; inspect.colors = ObjectAssign(ObjectCreate(null), { + reset: [0, 0], bold: [1, 22], + dim: [2, 22], // Alias: faint 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] + blink: [5, 25], + inverse: [7, 27], // Alias: swapcolors, swapColors; Swap forground and background colors + hidden: [8, 28], // Alias: conceal + strikethrough: [9, 29], // Alias: strikeThrough, crossedout, crossedOut + doubleunderline: [21, 24], // Alias: doubleUnderline + black: [30, defaultFG], + red: [31, defaultFG], + green: [32, defaultFG], + yellow: [33, defaultFG], + blue: [34, defaultFG], + magenta: [35, defaultFG], + cyan: [36, defaultFG], + white: [37, defaultFG], + bgBlack: [40, defaultBG], + bgRed: [41, defaultBG], + bgGreen: [42, defaultBG], + bgYellow: [43, defaultBG], + bgBlue: [44, defaultBG], + bgMagenta: [45, defaultBG], + bgCyan: [46, defaultBG], + bgWhite: [47, defaultBG], + framed: [51, 54], + overlined: [53, 55], + gray: [90, defaultFG], // Alias: grey, blackBright + redBright: [91, defaultFG], + greenBright: [92, defaultFG], + yellowBright: [93, defaultFG], + blueBright: [94, defaultFG], + magentaBright: [95, defaultFG], + cyanBright: [96, defaultFG], + whiteBright: [97, defaultFG], + bgGray: [100, defaultBG], // Alias: bgGrey, bgBlackBright + bgRedBright: [101, defaultBG], + bgGreenBright: [102, defaultBG], + bgYellowBright: [103, defaultBG], + bgBlueBright: [104, defaultBG], + bgMagentaBright: [105, defaultBG], + bgCyanBright: [106, defaultBG], + bgWhiteBright: [107, defaultBG], }); +function defineColorAlias(target, alias) { + Object.defineProperty(inspect.colors, alias, { + get() { + return this[target]; + }, + set(value) { + this[target] = value; + }, + configurable: true, + enumerable: false + }); +} + +defineColorAlias('gray', 'grey'); +defineColorAlias('gray', 'blackBright'); +defineColorAlias('bgGray', 'bgGrey'); +defineColorAlias('bgGray', 'bgBlackBright'); +defineColorAlias('dim', 'faint'); +defineColorAlias('strikethrough', 'crossedout'); +defineColorAlias('strikethrough', 'strikeThrough'); +defineColorAlias('strikethrough', 'crossedOut'); +defineColorAlias('hidden', 'conceal'); +defineColorAlias('inverse', 'swapColors'); +defineColorAlias('inverse', 'swapcolors'); +defineColorAlias('doubleunderline', 'doubleUnderline'); + +// TODO(BridgeAR): Add function style support for more complex styles. // Don't use 'blue' not visible on cmd.exe inspect.styles = ObjectAssign(ObjectCreate(null), { special: 'cyan', @@ -293,6 +355,7 @@ inspect.styles = ObjectAssign(ObjectCreate(null), { symbol: 'green', date: 'magenta', // "name": intentionally not styling + // TODO(BridgeAR): Highlight regular expressions properly. regexp: 'red', module: 'underline' }); diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 7dd151f289418e..40d9ee3fe6c6ca 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -2047,6 +2047,34 @@ assert.strictEqual(inspect(new BigUint64Array([0n])), 'BigUint64Array [ 0n ]'); `\u001b[${string[0]}m'Oh no!'\u001b[${string[1]}m }` ); rejection.catch(() => {}); + + // Verify that aliases do not show up as key while checking `inspect.colors`. + const colors = Object.keys(inspect.colors); + const aliases = Object.getOwnPropertyNames(inspect.colors) + .filter((c) => !colors.includes(c)); + assert(!colors.includes('grey')); + assert(colors.includes('gray')); + // Verify that all aliases are correctly mapped. + for (const alias of aliases) { + assert(Array.isArray(inspect.colors[alias])); + } + // Check consistent naming. + [ + 'black', + 'red', + 'green', + 'yellow', + 'blue', + 'magenta', + 'cyan', + 'white' + ].forEach((color, i) => { + assert.deepStrictEqual(inspect.colors[color], [30 + i, 39]); + assert.deepStrictEqual(inspect.colors[`${color}Bright`], [90 + i, 39]); + const bgColor = `bg${color[0].toUpperCase()}${color.slice(1)}`; + assert.deepStrictEqual(inspect.colors[bgColor], [40 + i, 49]); + assert.deepStrictEqual(inspect.colors[`${bgColor}Bright`], [100 + i, 49]); + }); } assert.strictEqual( From 6d6b860561b8209cab62d5200d9d6e881ed7d223 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Tue, 26 Nov 2019 16:04:25 +0100 Subject: [PATCH 3/5] fixup: util: add more predefined color codes to inspect.colors --- lib/internal/util/inspect.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index a6668f6da86e2a..c52715f88dfc1d 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -276,7 +276,8 @@ inspect.colors = ObjectAssign(ObjectCreate(null), { italic: [3, 23], underline: [4, 24], blink: [5, 25], - inverse: [7, 27], // Alias: swapcolors, swapColors; Swap forground and background colors + // Swap forground and background colors + inverse: [7, 27], // Alias: swapcolors, swapColors hidden: [8, 28], // Alias: conceal strikethrough: [9, 29], // Alias: strikeThrough, crossedout, crossedOut doubleunderline: [21, 24], // Alias: doubleUnderline @@ -317,7 +318,7 @@ inspect.colors = ObjectAssign(ObjectCreate(null), { }); function defineColorAlias(target, alias) { - Object.defineProperty(inspect.colors, alias, { + ObjectDefineProperty(inspect.colors, alias, { get() { return this[target]; }, From 87e609103f31abb2631b52e7b7db1723c8695892 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 28 Nov 2019 15:41:29 +0100 Subject: [PATCH 4/5] fixup: improve doc wording --- doc/api/util.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/api/util.md b/doc/api/util.md index c564ded67aef19..88e2f34b7c8b26 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -681,7 +681,8 @@ The default styles and associated colors are: Color styling uses ANSI control codes that may not be supported on all terminals. To verify color support use [`tty.hasColors()`][]. -The predefined color codes are: +Predefined control codes are listed below (grouped as "Modifiers", "Foreground +colors", and "Background colors"). #### Modifiers @@ -705,7 +706,7 @@ ignored, if not supported. double underlined (Alias: `doubleUnderline`) * framed - Draw a frame around the text -#### Colors +#### Foreground colors * `black` * `red` From 8f5432d59727a9d127211e8ee9235cc8a0933685 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 6 Dec 2019 18:08:38 +0100 Subject: [PATCH 5/5] fixup: util: improve inspect's customInspect performance --- lib/internal/util/inspect.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index c52715f88dfc1d..74777445f8c927 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -116,6 +116,8 @@ const builtInObjects = new Set( ObjectGetOwnPropertyNames(global).filter((e) => /^([A-Z][a-z]+)+$/.test(e)) ); +// These options must stay in sync with `getUserOptions`. So if any option will +// be added or removed, `getUserOptions` must also be updated accordingly. const inspectDefaultOptions = ObjectSeal({ showHidden: false, depth: 2,