| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 04f83b5 commit 4a664b5
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1800,32 +1800,63 @@ console.log(util.stripVTControlCharacters('\u001B[4mvalue\u001B[0m')); | |||
| 1800 | 1800 | // Prints "value" | |
| 1801 | 1801 | ``` | |
| 1802 | 1802 | ||
| 1803 | - ## `util.styleText(format, text)` | ||
| 1803 | + ## `util.styleText(format, text[, options])` | ||
| 1804 | 1804 | ||
| 1805 | 1805 | > Stability: 1.1 - Active development | |
| 1806 | 1806 | ||
| 1807 | 1807 | <!-- YAML | |
| 1808 | 1808 | added: | |
| 1809 | 1809 | - v21.7.0 | |
| 1810 | 1810 | - v20.12.0 | |
| 1811 | + changes: | ||
| 1812 | + - version: REPLACEME | ||
| 1813 | + pr-url: https://github.com/nodejs/node/pull/54389 | ||
| 1814 | + description: Respect isTTY and environment variables | ||
| 1815 | + such as NO_COLORS, NODE_DISABLE_COLORS, and FORCE_COLOR. | ||
| 1811 | 1816 | --> | |
| 1812 | 1817 | ||
| 1813 | 1818 | * `format` {string | Array} A text format or an Array | |
| 1814 | 1819 | of text formats defined in `util.inspect.colors`. | |
| 1815 | 1820 | * `text` {string} The text to to be formatted. | |
| 1821 | + * `options` {Object} | ||
| 1822 | + * `validateStream` {boolean} When true, `stream` is checked to see if it can handle colors. **Default:** `true`. | ||
| 1823 | + * `stream` {Stream} A stream that will be validated if it can be colored. **Default:** `process.stdout`. | ||
| 1816 | 1824 | ||
| 1817 | - This function returns a formatted text considering the `format` passed. | ||
| 1825 | + This function returns a formatted text considering the `format` passed | ||
| 1826 | + for printing in a terminal, it is aware of the terminal's capabilities | ||
| 1827 | + and act according to the configuration set via `NO_COLORS`, | ||
| 1828 | + `NODE_DISABLE_COLORS` and `FORCE_COLOR` environment variables. | ||
| 1818 | 1829 | ||
| 1819 | 1830 | ```mjs | |
| 1820 | 1831 | import { styleText } from 'node:util'; | |
| 1821 | - const errorMessage = styleText('red', 'Error! Error!'); | ||
| 1822 | - console.log(errorMessage); | ||
| 1832 | + import { stderr } from 'node:process'; | ||
| 1833 | + | ||
| 1834 | + const successMessage = styleText('green', 'Success!'); | ||
| 1835 | + console.log(successMessage); | ||
| 1836 | + | ||
| 1837 | + const errorMessage = styleText( | ||
| 1838 | + 'red', | ||
| 1839 | + 'Error! Error!', | ||
| 1840 | + // Validate if process.stderr has TTY | ||
| 1841 | + { stream: stderr }, | ||
| 1842 | + ); | ||
| 1843 | + console.error(successMessage); | ||
| 1823 | 1844 | ``` | |
| 1824 | 1845 | ||
| 1825 | 1846 | ```cjs | |
| 1826 | 1847 | const { styleText } = require('node:util'); | |
| 1827 | - const errorMessage = styleText('red', 'Error! Error!'); | ||
| 1828 | - console.log(errorMessage); | ||
| 1848 | + const { stderr } = require('node:process'); | ||
| 1849 | + | ||
| 1850 | + const successMessage = styleText('green', 'Success!'); | ||
| 1851 | + console.log(successMessage); | ||
| 1852 | + | ||
| 1853 | + const errorMessage = styleText( | ||
| 1854 | + 'red', | ||
| 1855 | + 'Error! Error!', | ||
| 1856 | + // Validate if process.stderr has TTY | ||
| 1857 | + { stream: stderr }, | ||
| 1858 | + ); | ||
| 1859 | + console.error(successMessage); | ||
| 1829 | 1860 | ``` | |
| 1830 | 1861 | ||
| 1831 | 1862 | `util.inspect.colors` also provides text formats such as `italic`, and | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -65,13 +65,26 @@ const { | |||
| 65 | 65 | } = require('internal/util/inspect'); | |
| 66 | 66 | const { debuglog } = require('internal/util/debuglog'); | |
| 67 | 67 | const { | |
| 68 | + validateBoolean, | ||
| 68 | 69 | validateFunction, | |
| 69 | 70 | validateNumber, | |
| 70 | 71 | validateString, | |
| 71 | 72 | validateOneOf, | |
| 72 | 73 | } = require('internal/validators'); | |
| 73 | 74 | const { isBuffer } = require('buffer').Buffer; | |
| 75 | + const { | ||
| 76 | + isReadableStream, | ||
| 77 | + isWritableStream, | ||
| 78 | + isNodeStream, | ||
| 79 | + } = require('internal/streams/utils'); | ||
| 74 | 80 | const types = require('internal/util/types'); | |
| 81 | + | ||
| 82 | + let utilColors; | ||
| 83 | + function lazyUtilColors() { | ||
| 84 | + utilColors ??= require('internal/util/colors'); | ||
| 85 | + return utilColors; | ||
| 86 | + } | ||
| 87 | + | ||
| 75 | 88 | const binding = internalBinding('util'); | |
| 76 | 89 | ||
| 77 | 90 | const { | |
@@ -209,10 +222,25 @@ function escapeStyleCode(code) { | |||
| 209 | 222 | /** | |
| 210 | 223 | * @param {string | string[]} format | |
| 211 | 224 | * @param {string} text | |
| 225 | + * @param {object} [options={}] | ||
| 226 | + * @param {boolean} [options.validateStream=true] - Whether to validate the stream. | ||
| 227 | + * @param {Stream} [options.stream=process.stdout] - The stream used for validation. | ||
| 212 | 228 | * @returns {string} | |
| 213 | 229 | */ | |
| 214 | - function styleText(format, text) { | ||
| 230 | + function styleText(format, text, { validateStream = true, stream = process.stdout } = {}) { | ||
| 215 | 231 | validateString(text, 'text'); | |
| 232 | + validateBoolean(validateStream, 'options.validateStream'); | ||
| 233 | + | ||
| 234 | + if (validateStream) { | ||
| 235 | + if ( | ||
| 236 | + !isReadableStream(stream) && | ||
| 237 | + !isWritableStream(stream) && | ||
| 238 | + !isNodeStream(stream) | ||
| 239 | + ) { | ||
| 240 | + throw new ERR_INVALID_ARG_TYPE('stream', ['ReadableStream', 'WritableStream', 'Stream'], stream); | ||
| 241 | + } | ||
| 242 | + } | ||
| 243 | + | ||
| 216 | 244 | if (ArrayIsArray(format)) { | |
| 217 | 245 | let left = ''; | |
| 218 | 246 | let right = ''; | |
@@ -232,6 +260,18 @@ function styleText(format, text) { | |||
| 232 | 260 | if (formatCodes == null) { | |
| 233 | 261 | validateOneOf(format, 'format', ObjectKeys(inspect.colors)); | |
| 234 | 262 | } | |
| 263 | + | ||
| 264 | + // Check colorize only after validating arg type and value | ||
| 265 | + if ( | ||
| 266 | + validateStream && | ||
| 267 | + ( | ||
| 268 | + !stream || | ||
| 269 | + !lazyUtilColors().shouldColorize(stream) | ||
| 270 | + ) | ||
| 271 | + ) { | ||
| 272 | + return text; | ||
| 273 | + } | ||
| 274 | + | ||
| 235 | 275 | return `${escapeStyleCode(formatCodes[0])}${text}${escapeStyleCode(formatCodes[1])}`; | |
| 236 | 276 | } | |
| 237 | 277 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -46,6 +46,7 @@ expected.beforePreExec = new Set([ | |||
| 46 | 46 | 'NativeModule internal/assert', | |
| 47 | 47 | 'NativeModule internal/util/inspect', | |
| 48 | 48 | 'NativeModule internal/util/debuglog', | |
| 49 | + 'NativeModule internal/streams/utils', | ||
| 49 | 50 | 'NativeModule internal/timers', | |
| 50 | 51 | 'NativeModule events', | |
| 51 | 52 | 'Internal Binding buffer', | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,12 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | - require('../common'); | ||
| 3 | - const assert = require('assert'); | ||
| 4 | - const util = require('util'); | ||
| 2 | + | ||
| 3 | + const common = require('../common'); | ||
| 4 | + const assert = require('node:assert'); | ||
| 5 | + const util = require('node:util'); | ||
| 6 | + const { WriteStream } = require('node:tty'); | ||
| 7 | + | ||
| 8 | + const styled = '\u001b[31mtest\u001b[39m'; | ||
| 9 | + const noChange = 'test'; | ||
| 5 | 10 | ||
| 6 | 11 | [ | |
| 7 | 12 | undefined, | |
@@ -31,13 +36,69 @@ assert.throws(() => { | |||
| 31 | 36 | code: 'ERR_INVALID_ARG_VALUE', | |
| 32 | 37 | }); | |
| 33 | 38 | ||
| 34 | - assert.strictEqual(util.styleText('red', 'test'), '\u001b[31mtest\u001b[39m'); | ||
| 39 | + assert.strictEqual( | ||
| 40 | + util.styleText('red', 'test', { validateStream: false }), | ||
| 41 | + '\u001b[31mtest\u001b[39m', | ||
| 42 | + ); | ||
| 43 | + | ||
| 44 | + assert.strictEqual( | ||
| 45 | + util.styleText(['bold', 'red'], 'test', { validateStream: false }), | ||
| 46 | + '\u001b[1m\u001b[31mtest\u001b[39m\u001b[22m', | ||
| 47 | + ); | ||
| 35 | 48 | ||
| 36 | - assert.strictEqual(util.styleText(['bold', 'red'], 'test'), '\u001b[1m\u001b[31mtest\u001b[39m\u001b[22m'); | ||
| 37 | - assert.strictEqual(util.styleText(['bold', 'red'], 'test'), util.styleText('bold', util.styleText('red', 'test'))); | ||
| 49 | + assert.strictEqual( | ||
| 50 | + util.styleText(['bold', 'red'], 'test', { validateStream: false }), | ||
| 51 | + util.styleText( | ||
| 52 | + 'bold', | ||
| 53 | + util.styleText('red', 'test', { validateStream: false }), | ||
| 54 | + { validateStream: false }, | ||
| 55 | + ), | ||
| 56 | + ); | ||
| 38 | 57 | ||
| 39 | 58 | assert.throws(() => { | |
| 40 | 59 | util.styleText(['invalid'], 'text'); | |
| 41 | 60 | }, { | |
| 42 | 61 | code: 'ERR_INVALID_ARG_VALUE', | |
| 43 | 62 | }); | |
| 63 | + | ||
| 64 | + assert.throws(() => { | ||
| 65 | + util.styleText('red', 'text', { stream: {} }); | ||
| 66 | + }, { | ||
| 67 | + code: 'ERR_INVALID_ARG_TYPE', | ||
| 68 | + }); | ||
| 69 | + | ||
| 70 | + // does not throw | ||
| 71 | + util.styleText('red', 'text', { stream: {}, validateStream: false }); | ||
| 72 | + | ||
| 73 | + assert.strictEqual( | ||
| 74 | + util.styleText('red', 'test', { validateStream: false }), | ||
| 75 | + styled, | ||
| 76 | + ); | ||
| 77 | + | ||
| 78 | + const fd = common.getTTYfd(); | ||
| 79 | + if (fd !== -1) { | ||
| 80 | + const writeStream = new WriteStream(fd); | ||
| 81 | + | ||
| 82 | + const originalEnv = process.env; | ||
| 83 | + [ | ||
| 84 | + { isTTY: true, env: {}, expected: styled }, | ||
| 85 | + { isTTY: false, env: {}, expected: noChange }, | ||
| 86 | + { isTTY: true, env: { NODE_DISABLE_COLORS: '1' }, expected: noChange }, | ||
| 87 | + { isTTY: true, env: { NO_COLOR: '1' }, expected: noChange }, | ||
| 88 | + { isTTY: true, env: { FORCE_COLOR: '1' }, expected: styled }, | ||
| 89 | + { isTTY: true, env: { FORCE_COLOR: '1', NODE_DISABLE_COLORS: '1' }, expected: styled }, | ||
| 90 | + { isTTY: false, env: { FORCE_COLOR: '1', NO_COLOR: '1', NODE_DISABLE_COLORS: '1' }, expected: styled }, | ||
| 91 | + { isTTY: true, env: { FORCE_COLOR: '1', NO_COLOR: '1', NODE_DISABLE_COLORS: '1' }, expected: styled }, | ||
| 92 | + ].forEach((testCase) => { | ||
| 93 | + writeStream.isTTY = testCase.isTTY; | ||
| 94 | + process.env = { | ||
| 95 | + ...process.env, | ||
| 96 | + ...testCase.env | ||
| 97 | + }; | ||
| 98 | + const output = util.styleText('red', 'test', { stream: writeStream }); | ||
| 99 | + assert.strictEqual(output, testCase.expected); | ||
| 100 | + process.env = originalEnv; | ||
| 101 | + }); | ||
| 102 | + } else { | ||
| 103 | + common.skip('Could not create TTY fd'); | ||
| 104 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments