From 1a6a69a8e006d1fd202ea4899714b1974a5540ad Mon Sep 17 00:00:00 2001 From: Roman Reiss Date: Tue, 9 Aug 2016 20:48:56 +0200 Subject: [PATCH] util: add inspect.defaultOptions Adds util.inspect.defaultOptions which allows customization of the default util.inspect options, which is useful for functions like console.log or util.format which implicitly call into util.inspect. PR-URL: https://github.com/nodejs/node/pull/8013 Fixes: https://github.com/nodejs/node/issues/7566 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Evan Lucas --- doc/api/util.md | 18 +++++++++++++ lib/util.js | 42 +++++++++++++++++++----------- test/parallel/test-util-inspect.js | 41 +++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/doc/api/util.md b/doc/api/util.md index c6c31d7759..5b59824b62 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -271,6 +271,23 @@ util.inspect(obj); // "{ bar: 'baz' }" ``` +### util.inspect.defaultOptions + +The `defaultOptions` value allows customization of the default options used by +`util.inspect`. This is useful for functions like `console.log` or +`util.format` which implicitly call into `util.inspect`. It shall be set to an +object containing one or more valid [`util.inspect()`][] options. Setting +option properties directly is also supported. + +```js +const util = require('util'); +const arr = Array(101); + +console.log(arr); // logs the truncated array +util.inspect.defaultOptions.maxArrayLength = null; +console.log(arr); // logs the full array +``` + ## Deprecated APIs The following APIs have been deprecated and should no longer be used. Existing @@ -662,6 +679,7 @@ similar built-in functionality through [`Object.assign()`]. [`Array.isArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray [constructor]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor [semantically incompatible]: https://github.com/nodejs/node/issues/4179 +[`util.inspect()`]: #util_util_inspect_object_options [Customizing `util.inspect` colors]: #util_customizing_util_inspect_colors [`Error`]: errors.html#errors_class_error [`console.log()`]: console.html#console_console_log_data diff --git a/lib/util.js b/lib/util.js index 93313d443f..ed417036e8 100644 --- a/lib/util.js +++ b/lib/util.js @@ -6,7 +6,16 @@ const internalUtil = require('internal/util'); const binding = process.binding('util'); const isError = internalUtil.isError; -const kDefaultMaxLength = 100; + +const inspectDefaultOptions = Object.seal({ + showHidden: false, + depth: 2, + colors: false, + customInspect: true, + showProxy: false, + maxArrayLength: 100, + breakLength: 60 +}); var Debug; var simdFormatters; @@ -176,29 +185,31 @@ function inspect(obj, opts) { stylize: stylizeNoColor }; // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; + if (arguments[2] !== undefined) ctx.depth = arguments[2]; + if (arguments[3] !== undefined) ctx.colors = arguments[3]; if (typeof opts === 'boolean') { // legacy... ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); } - // set default options - if (ctx.showHidden === undefined) ctx.showHidden = false; - if (ctx.depth === undefined) ctx.depth = 2; - if (ctx.colors === undefined) ctx.colors = false; - if (ctx.customInspect === undefined) ctx.customInspect = true; - if (ctx.showProxy === undefined) ctx.showProxy = false; + // Set default and user-specified options + ctx = Object.assign({}, inspect.defaultOptions, ctx, opts); if (ctx.colors) ctx.stylize = stylizeWithColor; - if (ctx.maxArrayLength === undefined) ctx.maxArrayLength = kDefaultMaxLength; if (ctx.maxArrayLength === null) ctx.maxArrayLength = Infinity; - if (ctx.breakLength === undefined) ctx.breakLength = 60; return formatValue(ctx, obj, ctx.depth); } -exports.inspect = inspect; +Object.defineProperty(inspect, 'defaultOptions', { + get: function() { + return inspectDefaultOptions; + }, + set: function(options) { + if (options === null || typeof options !== 'object') { + throw new TypeError('"options" must be an object'); + } + Object.assign(inspectDefaultOptions, options); + return inspectDefaultOptions; + } +}); // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics inspect.colors = { @@ -231,6 +242,7 @@ inspect.styles = { 'regexp': 'red' }; +exports.inspect = inspect; function stylizeWithColor(str, styleType) { var style = inspect.styles[styleType]; diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 14b7929ae5..d7c8462e36 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -43,6 +43,13 @@ assert.equal(util.inspect(Object.create({}, '{ visible: 1 }' ); +assert(/Object/.test( + util.inspect({a: {a: {a: {a: {}}}}}, undefined, undefined, true) +)); +assert(!/Object/.test( + util.inspect({a: {a: {a: {a: {}}}}}, undefined, null, true) +)); + for (const showHidden of [true, false]) { const ab = new ArrayBuffer(4); const dv = new DataView(ab, 1, 2); @@ -723,3 +730,37 @@ checkAlignment(new Map(big_array.map(function(y) { return [y, null]; }))); assert.strictEqual(oneLine, util.inspect(obj, {breakLength: breakpoint + 1})); assert.strictEqual(twoLines, '{ foo: \'abc\',\n bar: \'xyz\' }'); } + +// util.inspect.defaultOptions tests +{ + const arr = Array(101); + const obj = {a: {a: {a: {a: 1}}}}; + + const oldOptions = Object.assign({}, util.inspect.defaultOptions); + + // Set single option through property assignment + util.inspect.defaultOptions.maxArrayLength = null; + assert(!/1 more item/.test(util.inspect(arr))); + util.inspect.defaultOptions.maxArrayLength = oldOptions.maxArrayLength; + assert(/1 more item/.test(util.inspect(arr))); + util.inspect.defaultOptions.depth = null; + assert(!/Object/.test(util.inspect(obj))); + util.inspect.defaultOptions.depth = oldOptions.depth; + assert(/Object/.test(util.inspect(obj))); + assert.strictEqual( + JSON.stringify(util.inspect.defaultOptions), + JSON.stringify(oldOptions) + ); + + // Set multiple options through object assignment + util.inspect.defaultOptions = {maxArrayLength: null, depth: null}; + assert(!/1 more item/.test(util.inspect(arr))); + assert(!/Object/.test(util.inspect(obj))); + util.inspect.defaultOptions = oldOptions; + assert(/1 more item/.test(util.inspect(arr))); + assert(/Object/.test(util.inspect(obj))); + assert.strictEqual( + JSON.stringify(util.inspect.defaultOptions), + JSON.stringify(oldOptions) + ); +}