From be3ae339360c9833a77ebf5772786d75b7a8dd78 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Wed, 12 Dec 2018 03:26:15 +0100 Subject: [PATCH] console: add `inspectOptions` option Add an `inspectOptions` option to the `console` constructor. That way it's possible to define all inspection defaults for each `console` instance instead of relying on the `inspect()` defaults. PR-URL: https://github.com/nodejs/node/pull/24978 Reviewed-By: Matteo Collina Reviewed-By: James M Snell Reviewed-By: Gus Caplan --- doc/api/console.md | 8 +++++- doc/api/errors.md | 6 +++++ lib/internal/console/constructor.js | 23 ++++++++++++++++- lib/internal/errors.js | 2 ++ test/parallel/test-console-tty-colors.js | 33 +++++++++++++++++++++--- 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/doc/api/console.md b/doc/api/console.md index 42968d2eb9ab0d..cd229c0a0f81df 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -88,6 +88,9 @@ changes: pr-url: https://github.com/nodejs/node/pull/19372 description: The `Console` constructor now supports an `options` argument, and the `colorMode` option was introduced. + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/24978 + description: The `inspectOptions` option is introduced. --> * `options` {Object} @@ -98,8 +101,11 @@ changes: * `colorMode` {boolean|string} Set color support for this `Console` instance. Setting to `true` enables coloring while inspecting values, setting to `'auto'` will make color support depend on the value of the `isTTY` property - and the value returned by `getColorDepth()` on the respective stream. + and the value returned by `getColorDepth()` on the respective stream. This + option can not be used, if `inspectOptions.colors` is set as well. **Default:** `'auto'`. + * `inspectOptions` {Object} Specifies options that are passed along to + [`util.inspect()`][]. Creates a new `Console` with one or two writable stream instances. `stdout` is a writable stream to print log or info output. `stderr` is used for warning or diff --git a/doc/api/errors.md b/doc/api/errors.md index f0c118fd59d5e9..a2ae4d32be2101 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1126,6 +1126,12 @@ is set for the `Http2Stream`. `http2.connect()` was passed a URL that uses any protocol other than `http:` or `https:`. + +### ERR_INCOMPATIBLE_OPTION_PAIR + +An option pair is incompatible with each other and can not be used at the same +time. + ### ERR_INSPECTOR_ALREADY_CONNECTED diff --git a/lib/internal/console/constructor.js b/lib/internal/console/constructor.js index d3c5ed74367b8a..da54dd11a7e60b 100644 --- a/lib/internal/console/constructor.js +++ b/lib/internal/console/constructor.js @@ -10,6 +10,7 @@ const { ERR_CONSOLE_WRITABLE_STREAM, ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, + ERR_INCOMPATIBLE_OPTION_PAIR, }, } = require('internal/errors'); const { previewEntries } = internalBinding('util'); @@ -54,6 +55,8 @@ const kBindStreamsLazy = Symbol('kBindStreamsLazy'); const kUseStdout = Symbol('kUseStdout'); const kUseStderr = Symbol('kUseStderr'); +const optionsMap = new WeakMap(); + function Console(options /* or: stdout, stderr, ignoreErrors = true */) { // We have to test new.target here to see if this function is called // with new, because we need to define a custom instanceof to accommodate @@ -74,7 +77,8 @@ function Console(options /* or: stdout, stderr, ignoreErrors = true */) { stdout, stderr = stdout, ignoreErrors = true, - colorMode = 'auto' + colorMode = 'auto', + inspectOptions } = options; if (!stdout || typeof stdout.write !== 'function') { @@ -87,6 +91,15 @@ function Console(options /* or: stdout, stderr, ignoreErrors = true */) { if (typeof colorMode !== 'boolean' && colorMode !== 'auto') throw new ERR_INVALID_ARG_VALUE('colorMode', colorMode); + if (inspectOptions) { + if (inspectOptions.colors !== undefined && + options.colorMode !== undefined) { + throw new ERR_INCOMPATIBLE_OPTION_PAIR( + 'inspectOptions.color', 'colorMode'); + } + optionsMap.set(this, inspectOptions); + } + // bind the prototype functions to this Console instance var keys = Object.keys(Console.prototype); for (var v = 0; v < keys.length; v++) { @@ -243,6 +256,14 @@ Console.prototype[kGetInspectOptions] = function(stream) { stream.getColorDepth() > 2 : true); } + const options = optionsMap.get(this); + if (options) { + if (options.colors === undefined) { + options.colors = color; + } + return options; + } + return color ? kColorInspectOptions : kNoColorInspectOptions; }; diff --git a/lib/internal/errors.js b/lib/internal/errors.js index b8f8b4cfa2d725..174281f8a27905 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -686,6 +686,8 @@ E('ERR_HTTP_INVALID_HEADER_VALUE', E('ERR_HTTP_INVALID_STATUS_CODE', 'Invalid status code: %s', RangeError); E('ERR_HTTP_TRAILER_INVALID', 'Trailers are invalid with this transfer encoding', Error); +E('ERR_INCOMPATIBLE_OPTION_PAIR', + 'Option "%s" can not be used in combination with option "%s"', TypeError); E('ERR_INSPECTOR_ALREADY_CONNECTED', '%s is already connected', Error); E('ERR_INSPECTOR_CLOSED', 'Session was closed', Error); E('ERR_INSPECTOR_NOT_AVAILABLE', 'Inspector is not available', Error); diff --git a/test/parallel/test-console-tty-colors.js b/test/parallel/test-console-tty-colors.js index 4f4064970ad6b7..85a0e61e381170 100644 --- a/test/parallel/test-console-tty-colors.js +++ b/test/parallel/test-console-tty-colors.js @@ -5,7 +5,7 @@ const util = require('util'); const { Writable } = require('stream'); const { Console } = require('console'); -function check(isTTY, colorMode, expectedColorMode) { +function check(isTTY, colorMode, expectedColorMode, inspectOptions) { const items = [ 1, { a: 2 }, @@ -18,7 +18,8 @@ function check(isTTY, colorMode, expectedColorMode) { write: common.mustCall((chunk, enc, cb) => { assert.strictEqual(chunk.trim(), util.inspect(items[i++], { - colors: expectedColorMode + colors: expectedColorMode, + ...inspectOptions })); cb(); }, items.length), @@ -31,7 +32,8 @@ function check(isTTY, colorMode, expectedColorMode) { const testConsole = new Console({ stdout: stream, ignoreErrors: false, - colorMode + colorMode, + inspectOptions }); for (const item of items) { testConsole.log(item); @@ -40,12 +42,15 @@ function check(isTTY, colorMode, expectedColorMode) { check(true, 'auto', true); check(false, 'auto', false); +check(false, undefined, true, { colors: true, compact: false }); +check(true, 'auto', true, { compact: false }); +check(true, undefined, false, { colors: false }); check(true, true, true); check(false, true, true); check(true, false, false); check(false, false, false); -// check invalid colorMode type +// Check invalid options. { const stream = new Writable({ write: common.mustNotCall() @@ -67,4 +72,24 @@ check(false, false, false); } ); }); + + [true, false, 'auto'].forEach((colorMode) => { + assert.throws( + () => { + new Console({ + stdout: stream, + ignoreErrors: false, + colorMode: colorMode, + inspectOptions: { + colors: false + } + }); + }, + { + message: 'Option "inspectOptions.color" can not be used in ' + + 'combination with option "colorMode"', + code: 'ERR_INCOMPATIBLE_OPTION_PAIR' + } + ); + }); }