From 2d6b19970b1b68b8314e913249ddceb4a39ae54a Mon Sep 17 00:00:00 2001 From: Marco Ippolito Date: Fri, 15 Mar 2024 11:42:21 +0100 Subject: [PATCH] util: support array of formats in util.styleText PR-URL: https://github.com/nodejs/node/pull/52040 Fixes: https://github.com/nodejs/node/issues/52035 Reviewed-By: Chemi Atlow Reviewed-By: Paolo Insogna --- doc/api/util.md | 14 ++++++++++++-- lib/util.js | 27 +++++++++++++++++++++++++-- test/parallel/test-util-styletext.js | 10 +++++++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/doc/api/util.md b/doc/api/util.md index 5b465f42c31840..dddfbdb0b1049a 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1800,7 +1800,8 @@ console.log(util.stripVTControlCharacters('\u001B[4mvalue\u001B[0m')); added: v20.12.0 --> -* `format` {string} A text format defined in `util.inspect.colors`. +* `format` {string | Array} A text format or an Array + of text formats defined in `util.inspect.colors`. * `text` {string} The text to to be formatted. This function returns a formatted text considering the `format` passed. @@ -1822,7 +1823,16 @@ console.log(errorMessage); ```cjs console.log( - util.styleText('underline', util.styleText('italic', 'My italic underlined message')), + util.styleText(['underline', 'italic'], 'My italic underlined message'), +); +``` + +When passing an array of formats, the order of the format applied +is left to right so the following style might overwrite the previous one. + +```cjs +console.log( + util.styleText(['red', 'green'], 'text'), // green ); ``` diff --git a/lib/util.js b/lib/util.js index e4e42298457bfd..b6c604194366ec 100644 --- a/lib/util.js +++ b/lib/util.js @@ -199,17 +199,40 @@ function pad(n) { } /** - * @param {string} format + * @param {string} code + * @returns {string} + */ +function escapeStyleCode(code) { + return `\u001b[${code}m`; +} + +/** + * @param {string | string[]} format * @param {string} text * @returns {string} */ function styleText(format, text) { validateString(text, 'text'); + if (ArrayIsArray(format)) { + let left = ''; + let right = ''; + for (const key of format) { + const formatCodes = inspect.colors[key]; + if (formatCodes == null) { + validateOneOf(key, 'format', ObjectKeys(inspect.colors)); + } + left += escapeStyleCode(formatCodes[0]); + right = `${escapeStyleCode(formatCodes[1])}${right}`; + } + + return `${left}${text}${right}`; + } + const formatCodes = inspect.colors[format]; if (formatCodes == null) { validateOneOf(format, 'format', ObjectKeys(inspect.colors)); } - return `\u001b[${formatCodes[0]}m${text}\u001b[${formatCodes[1]}m`; + return `${escapeStyleCode(formatCodes[0])}${text}${escapeStyleCode(formatCodes[1])}`; } const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', diff --git a/test/parallel/test-util-styletext.js b/test/parallel/test-util-styletext.js index 9436133916c58c..6baa6a60eac8ac 100644 --- a/test/parallel/test-util-styletext.js +++ b/test/parallel/test-util-styletext.js @@ -12,7 +12,6 @@ const util = require('util'); Symbol(), () => {}, {}, - [], ].forEach((invalidOption) => { assert.throws(() => { util.styleText(invalidOption, 'test'); @@ -33,3 +32,12 @@ assert.throws(() => { }); assert.strictEqual(util.styleText('red', 'test'), '\u001b[31mtest\u001b[39m'); + +assert.strictEqual(util.styleText(['bold', 'red'], 'test'), '\u001b[1m\u001b[31mtest\u001b[39m\u001b[22m'); +assert.strictEqual(util.styleText(['bold', 'red'], 'test'), util.styleText('bold', util.styleText('red', 'test'))); + +assert.throws(() => { + util.styleText(['invalid'], 'text'); +}, { + code: 'ERR_INVALID_ARG_VALUE', +});