Skip to content

Commit 8cafd83

Browse files
BridgeARtargos
authored andcommitted
tty: add NO_COLOR and FORCE_COLOR support
This adds support to enforce a specific color depth by checking the `FORCE_COLOR` environment variable similar to `chalk`. On top of that we also add support for the `NO_COLOR` environment variable as suggested by https://no-color.org/. PR-URL: #26485 Refs: #26248 Reviewed-By: Roman Reiss <me@silverwind.io> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
1 parent 1073e54 commit 8cafd83

File tree

4 files changed

+70
-9
lines changed

4 files changed

+70
-9
lines changed

doc/api/tty.md

+14-6
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,9 @@ position.
144144
added: v9.9.0
145145
-->
146146

147-
* `env` {Object} An object containing the environment variables to check.
148-
**Default:** `process.env`.
147+
* `env` {Object} An object containing the environment variables to check. This
148+
enables simulating the usage of a specific terminal. **Default:**
149+
`process.env`.
149150
* Returns: {number}
150151

151152
Returns:
@@ -159,11 +160,18 @@ Use this to determine what colors the terminal supports. Due to the nature of
159160
colors in terminals it is possible to either have false positives or false
160161
negatives. It depends on process information and the environment variables that
161162
may lie about what terminal is used.
162-
To enforce a specific behavior without relying on `process.env` it is possible
163-
to pass in an object with different settings.
163+
It is possible to pass in an `env` object to simulate the usage of a specific
164+
terminal. This can be useful to check how specific environment settings behave.
165+
166+
To enforce a specific color support, use one of the below environment settings.
167+
168+
* 2 colors: `FORCE_COLOR = 0` (Disables colors)
169+
* 16 colors: `FORCE_COLOR = 1`
170+
* 256 colors: `FORCE_COLOR = 2`
171+
* 16,777,216 colors: `FORCE_COLOR = 3`
164172

165-
Use the `NODE_DISABLE_COLORS` environment variable to enforce this function to
166-
always return 1.
173+
Disabling color support is also possible by using the `NO_COLOR` and
174+
`NODE_DISABLE_COLORS` environment variables.
167175

168176
### writeStream.getWindowSize()
169177
<!-- YAML

lib/internal/tty.js

+39-1
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,49 @@ const TERM_ENVS_REG_EXP = [
7272
/^vt100/
7373
];
7474

75+
function warnOnDeactivatedColors(env) {
76+
let name;
77+
if (env.NODE_DISABLE_COLORS !== undefined)
78+
name = 'NODE_DISABLE_COLORS';
79+
if (env.NO_COLOR !== undefined)
80+
name = 'NO_COLOR';
81+
82+
if (name !== undefined) {
83+
process.emitWarning(
84+
`The '${name}' env is ignored due to the 'FORCE_COLOR' env being set.`,
85+
'Warning'
86+
);
87+
}
88+
}
89+
7590
// The `getColorDepth` API got inspired by multiple sources such as
7691
// https://github.com/chalk/supports-color,
7792
// https://github.com/isaacs/color-support.
7893
function getColorDepth(env = process.env) {
79-
if (env.NODE_DISABLE_COLORS || env.TERM === 'dumb') {
94+
// Use level 0-3 to support the same levels as `chalk` does. This is done for
95+
// consistency throughout the ecosystem.
96+
if (env.FORCE_COLOR !== undefined) {
97+
switch (env.FORCE_COLOR) {
98+
case '':
99+
case '1':
100+
case 'true':
101+
warnOnDeactivatedColors(env);
102+
return COLORS_16;
103+
case '2':
104+
warnOnDeactivatedColors(env);
105+
return COLORS_256;
106+
case '3':
107+
warnOnDeactivatedColors(env);
108+
return COLORS_16m;
109+
default:
110+
return COLORS_2;
111+
}
112+
}
113+
114+
if (env.NODE_DISABLE_COLORS !== undefined ||
115+
// See https://no-color.org/
116+
env.NO_COLOR !== undefined ||
117+
env.TERM === 'dumb') {
80118
return COLORS_2;
81119
}
82120

test/pseudo-tty/test-tty-color-support.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,18 @@ const writeStream = new WriteStream(fd);
5959
[{ TERM: 'color' }, 4],
6060
[{ TERM: 'linux' }, 4],
6161
[{ TERM: 'fail' }, 1],
62-
[{ NODE_DISABLE_COLORS: '1' }, 1],
62+
[{ TERM: 'color', NODE_DISABLE_COLORS: '1' }, 1],
6363
[{ TERM: 'dumb' }, 1],
6464
[{ TERM: 'dumb', COLORTERM: '1' }, 1],
6565
[{ TERM: 'terminator' }, 24],
66-
[{ TERM: 'console' }, 4]
66+
[{ TERM: 'console' }, 4],
67+
[{ COLORTERM: '24bit', FORCE_COLOR: '' }, 4],
68+
[{ NO_COLOR: '1', FORCE_COLOR: '2' }, 8],
69+
[{ NODE_DISABLE_COLORS: '1', FORCE_COLOR: '3' }, 24],
70+
[{ NO_COLOR: '1', COLORTERM: '24bit' }, 1],
71+
[{ NO_COLOR: '', COLORTERM: '24bit' }, 1],
72+
[{ TMUX: '1', FORCE_COLOR: 0 }, 1],
73+
[{ NO_COLOR: 'true', FORCE_COLOR: 0, COLORTERM: 'truecolor' }, 1],
6774
].forEach(([env, depth], i) => {
6875
const actual = writeStream.getColorDepth(env);
6976
assert.strictEqual(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
(node:*) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
2+
(node:*) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
3+
(node:*) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
4+
(node:*) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
5+
(node:*) Warning: The 'NODE_DISABLE_COLORS' env is ignored due to the 'FORCE_COLOR' env being set.
6+
(node:*) Warning: The 'NODE_DISABLE_COLORS' env is ignored due to the 'FORCE_COLOR' env being set.
7+
(node:*) Warning: The 'NODE_DISABLE_COLORS' env is ignored due to the 'FORCE_COLOR' env being set.
8+
(node:*) Warning: The 'NODE_DISABLE_COLORS' env is ignored due to the 'FORCE_COLOR' env being set.

0 commit comments

Comments
 (0)