@peteanderson/ansi 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -19
- package/dist/ansi.d.ts +41 -8
- package/dist/ansi.js +44 -18
- package/dist/caret.d.ts +28 -25
- package/dist/caret.js +31 -1
- package/dist/erase.d.ts +13 -14
- package/dist/erase.js +16 -1
- package/dist/features/build.d.ts +11 -0
- package/dist/features/build.js +50 -0
- package/dist/features/detect.d.ts +4 -0
- package/dist/features/detect.js +33 -0
- package/dist/features/features.d.ts +5 -0
- package/dist/features/features.js +39 -0
- package/dist/features/index.d.ts +2 -0
- package/dist/features/index.js +2 -0
- package/dist/index.d.ts +12 -62
- package/dist/scroll.d.ts +6 -2
- package/dist/scroll.js +7 -1
- package/dist/sgr/color/color.d.ts +9 -0
- package/dist/sgr/color/color.js +76 -0
- package/dist/sgr/color/index.d.ts +2 -0
- package/dist/sgr/color/index.js +2 -0
- package/dist/sgr/color/utils.d.ts +27 -0
- package/dist/sgr/color/utils.js +67 -0
- package/dist/sgr/index.d.ts +5 -55
- package/dist/sgr/reset.d.ts +1 -1
- package/dist/sgr/reset.js +2 -2
- package/dist/sgr/sgr.d.ts +3 -3
- package/dist/sgr/sgr.js +18 -8
- package/dist/sgr/style.d.ts +13 -13
- package/dist/sgr/style.js +18 -15
- package/package.json +1 -1
- package/src/ansi.js +54 -24
- package/src/caret.js +40 -3
- package/src/erase.js +18 -1
- package/src/features/build.js +60 -0
- package/src/features/detect.js +39 -0
- package/src/features/features.js +53 -0
- package/src/features/index.js +1 -0
- package/src/features/types.d.ts +9 -0
- package/src/scroll.js +9 -1
- package/src/sgr/color/color.js +104 -0
- package/src/sgr/color/index.js +1 -0
- package/src/sgr/color/types.d.ts +28 -0
- package/src/sgr/color/utils.js +81 -0
- package/src/sgr/reset.js +2 -2
- package/src/sgr/sgr.js +25 -14
- package/src/sgr/style.js +19 -15
- package/dist/sgr/color.d.ts +0 -62
- package/dist/sgr/color.js +0 -111
- package/src/sgr/color.js +0 -130
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# @peteanderson/ansi
|
|
2
2
|
|
|
3
|
-
ANSI escape sequence helpers for Node.js terminal output.
|
|
3
|
+
ANSI escape sequence helpers for Node.js terminal output. Automatically detects terminal
|
|
4
|
+
capabilities and adapts output accordingly.
|
|
4
5
|
|
|
5
6
|
## Installation
|
|
6
7
|
|
|
@@ -17,47 +18,80 @@ console.log(ansi.fg.red("error: something went wrong"));
|
|
|
17
18
|
console.log(ansi.bg.blue.combine(ansi.fg.white)("highlighted"));
|
|
18
19
|
console.log(ansi.style.bold("important"));
|
|
19
20
|
console.log(ansi.fg.rgb(5, 2, 0)("custom color"));
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
console.log(
|
|
21
|
+
|
|
22
|
+
// Disable colors for a specific stream
|
|
23
|
+
const ansiNoColor = ansi(1); // force 1-bit (no color)
|
|
24
|
+
console.log(ansiNoColor.fg.red("this won't be colored"));
|
|
25
|
+
|
|
26
|
+
// Override specific features
|
|
27
|
+
const customAnsi = ansi({colorDepth: 8, caret: false});
|
|
24
28
|
```
|
|
25
29
|
|
|
30
|
+
## Feature Detection
|
|
31
|
+
|
|
32
|
+
The module automatically detects:
|
|
33
|
+
|
|
34
|
+
- **Color depth**: 1 (none), 4 (16 colors), 8 (256 colors), 24 (true color)
|
|
35
|
+
- **Style support**: enabled if color depth > 1
|
|
36
|
+
- **Other features**: caret, erase, scroll — enabled if output is a TTY and `TERM` is not `dumb`
|
|
37
|
+
|
|
38
|
+
When disabled, features output empty strings. Color outputs plain text. This can be overridden:
|
|
39
|
+
|
|
40
|
+
- Pass a boolean to force color on/off
|
|
41
|
+
- Pass a number to set specific color depth (1, 3, 4, 8, or 24)
|
|
42
|
+
- Pass a stream to use for detection
|
|
43
|
+
- Pass a partial features object to override individual features
|
|
44
|
+
|
|
26
45
|
## API
|
|
27
46
|
|
|
47
|
+
### Default Export
|
|
48
|
+
|
|
49
|
+
The module exports a callable function with detection-based properties:
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
const ansi = require("@peteanderson/ansi");
|
|
53
|
+
const customAnsi = ansi(options); // returns configured instance
|
|
54
|
+
```
|
|
55
|
+
|
|
28
56
|
### `fg` — foreground colors
|
|
29
57
|
|
|
30
|
-
Functions that wrap text with color codes:
|
|
58
|
+
Functions that wrap text with color codes (or plain text if disabled):
|
|
31
59
|
|
|
32
60
|
- Basic colors: `black` `red` `green` `yellow` `blue` `magenta` `cyan` `white` `default`
|
|
33
61
|
- Bright colors: `brightBlack` `brightRed` `brightGreen` `brightYellow` `brightBlue` `brightMagenta`
|
|
34
62
|
`brightCyan` `brightWhite`
|
|
35
|
-
- `fg.rgb(r, g, b)(text)` - 24-bit RGB color
|
|
36
|
-
- `fg.x256(code)(text)` or `fg.x256(r, g, b)(text)` - 256-color palette
|
|
63
|
+
- `fg.rgb(r, g, b)(text)` - 24-bit RGB color, downscaled for lower color depths
|
|
64
|
+
- `fg.x256(code)(text)` or `fg.x256(r, g, b)(text)` - 256-color palette, downscaled as needed
|
|
37
65
|
|
|
38
66
|
All return functions with `open` and `close` properties for raw sequences.
|
|
39
67
|
|
|
40
68
|
### `bg` — background colors
|
|
41
69
|
|
|
42
|
-
Functions that wrap text with color codes:
|
|
70
|
+
Functions that wrap text with color codes (or plain text if disabled):
|
|
43
71
|
|
|
44
72
|
- Basic colors: `black` `red` `green` `yellow` `blue` `magenta` `cyan` `white` `default`
|
|
45
73
|
- Bright colors: `brightBlack` `brightRed` `brightGreen` `brightYellow` `brightBlue` `brightMagenta`
|
|
46
74
|
`brightCyan` `brightWhite`
|
|
47
|
-
- `bg.rgb(r, g, b)(text)` - 24-bit RGB color
|
|
48
|
-
- `bg.x256(code)(text)` or `bg.x256(r, g, b)(text)` - 256-color palette
|
|
75
|
+
- `bg.rgb(r, g, b)(text)` - 24-bit RGB color, downscaled for lower color depths
|
|
76
|
+
- `bg.x256(code)(text)` or `bg.x256(r, g, b)(text)` - 256-color palette, downscaled as needed
|
|
49
77
|
|
|
50
78
|
### `style`
|
|
51
79
|
|
|
52
|
-
Functions that wrap text with style codes:
|
|
80
|
+
Functions that wrap text with style codes (disabled if color depth = 1):
|
|
53
81
|
|
|
54
82
|
`bold` `dim` `italic` `underline` `inverse` `hidden` `strikethrough` `doubleUnderline` `framed`
|
|
55
83
|
`encircled` `overline`
|
|
56
84
|
|
|
57
85
|
All return functions with `open` and `close` properties for raw sequences.
|
|
58
86
|
|
|
87
|
+
### `reset`
|
|
88
|
+
|
|
89
|
+
The SGR reset sequence. Empty string if color is disabled.
|
|
90
|
+
|
|
59
91
|
### `caret`
|
|
60
92
|
|
|
93
|
+
Available if feature is enabled:
|
|
94
|
+
|
|
61
95
|
- `caret.show` / `caret.hide` - show or hide the cursor
|
|
62
96
|
- `caret.position.get` - get the current cursor position (terminal sends position to stdin)
|
|
63
97
|
- `caret.position.set(row, col)` - set cursor position (1-based indexing)
|
|
@@ -69,36 +103,53 @@ All return functions with `open` and `close` properties for raw sequences.
|
|
|
69
103
|
|
|
70
104
|
### `erase`
|
|
71
105
|
|
|
106
|
+
Available if feature is enabled:
|
|
107
|
+
|
|
72
108
|
- `erase.line.toStart` / `erase.line.toEnd` / `erase.line.full` - erase line
|
|
73
109
|
- `erase.screen.toStart` / `erase.screen.toEnd` / `erase.screen.full` - erase screen
|
|
74
110
|
- `erase.screen.scrollback` - erase screen and scrollback buffer
|
|
75
111
|
|
|
76
112
|
### `scroll`
|
|
77
113
|
|
|
114
|
+
Available if feature is enabled:
|
|
115
|
+
|
|
78
116
|
- `scroll.up(lines)` - scroll up (default 1 line)
|
|
79
117
|
- `scroll.down(lines)` - scroll down (default 1 line)
|
|
80
118
|
|
|
81
119
|
### `strip(text)`
|
|
82
120
|
|
|
83
|
-
Removes all ANSI CSI sequences from a string.
|
|
121
|
+
Removes all ANSI CSI sequences from a string (always available).
|
|
84
122
|
|
|
85
123
|
### `slice(text, start, end)`
|
|
86
124
|
|
|
87
|
-
Slices a string by visible characters, ignoring ANSI sequences
|
|
88
|
-
but counts only visible characters. Properly maintains terminal state at slice boundaries.
|
|
125
|
+
Slices a string by visible characters, ignoring ANSI sequences (always available).
|
|
89
126
|
|
|
90
127
|
### `sanitize(text)`
|
|
91
128
|
|
|
92
|
-
Removes "unsafe" CSI sequences
|
|
129
|
+
Removes "unsafe" CSI sequences, leaving only color and style codes (always available).
|
|
93
130
|
|
|
94
131
|
### `simplify(text)`
|
|
95
132
|
|
|
96
|
-
Simplifies ANSI SGR sequences by combining adjacent sequences and removing redundant codes
|
|
97
|
-
|
|
133
|
+
Simplifies ANSI SGR sequences by combining adjacent sequences and removing redundant codes (always
|
|
134
|
+
available).
|
|
98
135
|
|
|
99
136
|
### `visibleLength(text)`
|
|
100
137
|
|
|
101
|
-
Returns the visible length of a string with all ANSI sequences removed.
|
|
138
|
+
Returns the visible length of a string with all ANSI sequences removed (always available).
|
|
139
|
+
|
|
140
|
+
### `features`
|
|
141
|
+
|
|
142
|
+
Object containing the detected feature configuration:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
{
|
|
146
|
+
colorDepth : 1 | 3 | 4 | 8 | 24;
|
|
147
|
+
style : boolean;
|
|
148
|
+
caret : boolean;
|
|
149
|
+
erase : boolean;
|
|
150
|
+
scroll : boolean;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
102
153
|
|
|
103
154
|
## License
|
|
104
155
|
|
package/dist/ansi.d.ts
CHANGED
|
@@ -1,13 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
export = ansi;
|
|
2
|
+
declare const ansi: typeof makeAnsi & {
|
|
3
|
+
fg: Channel;
|
|
4
|
+
bg: Channel;
|
|
5
|
+
} & {
|
|
6
|
+
caret: ReturnType<typeof makeCaret>;
|
|
7
|
+
erase: ReturnType<typeof makeErase>;
|
|
8
|
+
scroll: ReturnType<typeof makeScroll>;
|
|
9
|
+
reset: string;
|
|
10
|
+
style: ReturnType<typeof makeStyle>;
|
|
11
|
+
strip: typeof strip;
|
|
12
|
+
visibleLength: typeof visibleLength;
|
|
13
|
+
sanitize: typeof sanitize;
|
|
14
|
+
slice: typeof slice;
|
|
15
|
+
simplify: typeof simplify;
|
|
16
|
+
features: ReturnType<typeof getFeatures>;
|
|
17
|
+
};
|
|
18
|
+
declare namespace ansi {
|
|
19
|
+
export { Args, Ansi };
|
|
20
|
+
}
|
|
21
|
+
declare function makeAnsi(...args: Args): Ansi;
|
|
22
|
+
import { makeCaret } from "./caret";
|
|
23
|
+
import { makeErase } from "./erase";
|
|
24
|
+
import { makeScroll } from "./scroll";
|
|
25
|
+
import { makeStyle } from "./sgr/style";
|
|
8
26
|
import { strip } from "./strip";
|
|
9
27
|
import { visibleLength } from "./strip";
|
|
10
28
|
import { sanitize } from "./strip";
|
|
11
29
|
import { slice } from "./slice";
|
|
12
30
|
import { simplify } from "./simplify/simplify";
|
|
13
|
-
|
|
31
|
+
import { getFeatures } from "./features/features";
|
|
32
|
+
type Args = import("./features/features").Args;
|
|
33
|
+
type Ansi = ReturnType<typeof makeColor> & {
|
|
34
|
+
caret: ReturnType<typeof makeCaret>;
|
|
35
|
+
erase: ReturnType<typeof makeErase>;
|
|
36
|
+
scroll: ReturnType<typeof makeScroll>;
|
|
37
|
+
reset: string;
|
|
38
|
+
style: ReturnType<typeof makeStyle>;
|
|
39
|
+
strip: typeof strip;
|
|
40
|
+
visibleLength: typeof visibleLength;
|
|
41
|
+
sanitize: typeof sanitize;
|
|
42
|
+
slice: typeof slice;
|
|
43
|
+
simplify: typeof simplify;
|
|
44
|
+
features: ReturnType<typeof getFeatures>;
|
|
45
|
+
};
|
|
46
|
+
import { makeColor } from "./sgr/color/color";
|
package/dist/ansi.js
CHANGED
|
@@ -1,23 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const {
|
|
2
|
+
const { makeCaret } = require("./caret");
|
|
3
|
+
const { makeErase } = require("./erase");
|
|
4
|
+
const { getFeatures } = require("./features");
|
|
5
|
+
const { makeScroll } = require("./scroll");
|
|
6
|
+
const { makeColor, makeReset, makeStyle } = require("./sgr");
|
|
6
7
|
const { simplify } = require("./simplify");
|
|
7
8
|
const { slice } = require("./slice");
|
|
8
9
|
const { sanitize, strip, visibleLength } = require("./strip");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
10
|
+
/**
|
|
11
|
+
@typedef {import("./features/features").Args} Args
|
|
12
|
+
|
|
13
|
+
@typedef {ReturnType<typeof makeColor> & {
|
|
14
|
+
caret : ReturnType<typeof makeCaret>;
|
|
15
|
+
erase : ReturnType<typeof makeErase>;
|
|
16
|
+
scroll : ReturnType<typeof makeScroll>;
|
|
17
|
+
|
|
18
|
+
reset : string;
|
|
19
|
+
style : ReturnType<typeof makeStyle>;
|
|
20
|
+
|
|
21
|
+
strip : typeof strip;
|
|
22
|
+
visibleLength : typeof visibleLength;
|
|
23
|
+
sanitize : typeof sanitize;
|
|
24
|
+
slice : typeof slice;
|
|
25
|
+
simplify : typeof simplify;
|
|
26
|
+
|
|
27
|
+
features : ReturnType<typeof getFeatures>;
|
|
28
|
+
}} Ansi
|
|
29
|
+
*/
|
|
30
|
+
/** @type {(...args: Args) => Ansi}*/
|
|
31
|
+
function makeAnsi(...args) {
|
|
32
|
+
const features = getFeatures(...args);
|
|
33
|
+
return {
|
|
34
|
+
caret: makeCaret(features.caret),
|
|
35
|
+
erase: makeErase(features.erase),
|
|
36
|
+
scroll: makeScroll(features.scroll),
|
|
37
|
+
reset: makeReset(features.colorDepth > 1),
|
|
38
|
+
style: makeStyle(features.style),
|
|
39
|
+
...makeColor(features.colorDepth),
|
|
40
|
+
strip,
|
|
41
|
+
visibleLength,
|
|
42
|
+
sanitize,
|
|
43
|
+
slice,
|
|
44
|
+
simplify,
|
|
45
|
+
features,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const ansi = Object.assign(makeAnsi, makeAnsi());
|
|
23
49
|
module.exports = ansi;
|
package/dist/caret.d.ts
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
export function makeCaret(enabled?: boolean): {
|
|
2
|
+
up: (count?: number) => string;
|
|
3
|
+
down: (count?: number) => string;
|
|
4
|
+
forward: (count?: number) => string;
|
|
5
|
+
backward: (count?: number) => string;
|
|
6
|
+
nextLine: (count?: number) => string;
|
|
7
|
+
prevLine: (count?: number) => string;
|
|
8
|
+
/** @type {(x: number) => string} */
|
|
9
|
+
x: (x: number) => string;
|
|
10
|
+
save: string;
|
|
11
|
+
restore: string;
|
|
12
|
+
hide: string;
|
|
13
|
+
show: string;
|
|
14
|
+
position: {
|
|
15
|
+
get: string;
|
|
16
|
+
/** @type {(x: number, y: number) => string} */
|
|
17
|
+
set: (x: number, y: number) => string;
|
|
18
|
+
};
|
|
19
|
+
shape: {
|
|
20
|
+
steadyBlock: string;
|
|
21
|
+
steadyBar: string;
|
|
22
|
+
steadyUnderline: string;
|
|
23
|
+
blinkingBlock: string;
|
|
24
|
+
blinkingBar: string;
|
|
25
|
+
blinkingUnderline: string;
|
|
26
|
+
default: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
package/dist/caret.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/** @type {(code: string) => (count?: number) => string} */
|
|
3
3
|
const move = code => count => `\x1b[${count === undefined ? "" : count ? count : "?"}${code}`;
|
|
4
|
+
/** @type {(count?: number) => string} */
|
|
5
|
+
const noop = () => "";
|
|
4
6
|
const caret = {
|
|
5
7
|
up: move("A"),
|
|
6
8
|
down: move("B"),
|
|
@@ -37,4 +39,32 @@ const caret = {
|
|
|
37
39
|
default: "\x1b[0 q",
|
|
38
40
|
},
|
|
39
41
|
};
|
|
40
|
-
|
|
42
|
+
/** @type {typeof caret} */
|
|
43
|
+
const disabled = {
|
|
44
|
+
up: noop,
|
|
45
|
+
down: noop,
|
|
46
|
+
forward: noop,
|
|
47
|
+
backward: noop,
|
|
48
|
+
nextLine: noop,
|
|
49
|
+
prevLine: noop,
|
|
50
|
+
x: noop,
|
|
51
|
+
save: "",
|
|
52
|
+
restore: "",
|
|
53
|
+
hide: "",
|
|
54
|
+
show: "",
|
|
55
|
+
position: {
|
|
56
|
+
get: "",
|
|
57
|
+
set: noop,
|
|
58
|
+
},
|
|
59
|
+
shape: {
|
|
60
|
+
steadyBlock: "",
|
|
61
|
+
steadyBar: "",
|
|
62
|
+
steadyUnderline: "",
|
|
63
|
+
blinkingBlock: "",
|
|
64
|
+
blinkingBar: "",
|
|
65
|
+
blinkingUnderline: "",
|
|
66
|
+
default: "",
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const makeCaret = (enabled = true) => enabled ? caret : disabled;
|
|
70
|
+
module.exports = { makeCaret };
|
package/dist/erase.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
1
|
+
export function makeErase(enabled?: boolean): {
|
|
2
|
+
line: {
|
|
3
|
+
toStart: string;
|
|
4
|
+
toEnd: string;
|
|
5
|
+
full: string;
|
|
6
|
+
};
|
|
7
|
+
screen: {
|
|
8
|
+
toStart: string;
|
|
9
|
+
toEnd: string;
|
|
10
|
+
full: string;
|
|
11
|
+
scrollback: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
package/dist/erase.js
CHANGED
|
@@ -12,4 +12,19 @@ const erase = {
|
|
|
12
12
|
scrollback: "\x1b[3J",
|
|
13
13
|
},
|
|
14
14
|
};
|
|
15
|
-
|
|
15
|
+
/** @type {typeof erase} */
|
|
16
|
+
const disabled = {
|
|
17
|
+
line: {
|
|
18
|
+
toStart: "",
|
|
19
|
+
toEnd: "",
|
|
20
|
+
full: "",
|
|
21
|
+
},
|
|
22
|
+
screen: {
|
|
23
|
+
toStart: "",
|
|
24
|
+
toEnd: "",
|
|
25
|
+
full: "",
|
|
26
|
+
scrollback: "",
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const makeErase = (enabled = true) => enabled ? erase : disabled;
|
|
30
|
+
module.exports = { makeErase };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ColorDepth = import("./types").ColorDepth;
|
|
2
|
+
export type Features = import("./types").Features;
|
|
3
|
+
export function build(isTTY: boolean, colorDepth: ColorDepth, style?: boolean, caret?: boolean, erase?: boolean, scroll?: boolean): Features;
|
|
4
|
+
/** @type {(isTTY: boolean, enabled: boolean) => Features} */
|
|
5
|
+
export const boolean: (isTTY: boolean, enabled: boolean) => Features;
|
|
6
|
+
/** @type {(isTTY: boolean, colorDepth: ColorDepth) => Features} */
|
|
7
|
+
export const number: (isTTY: boolean, colorDepth: ColorDepth) => Features;
|
|
8
|
+
/** @type {(stream: NodeJS.WriteStream) => Features} */
|
|
9
|
+
export const tty: (stream: NodeJS.WriteStream) => Features;
|
|
10
|
+
/** @type {() => Features} */
|
|
11
|
+
export const pipe: () => Features;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { getColorDepth, detectFeatureSupport } = require("./detect");
|
|
3
|
+
/** @typedef {import("./types").ColorDepth} ColorDepth */
|
|
4
|
+
/** @typedef {import("./types").Features} Features */
|
|
5
|
+
/** @type {(colorDepth: number) => ColorDepth} */
|
|
6
|
+
function normalizeColorDepth(colorDepth) {
|
|
7
|
+
colorDepth = Math.floor(colorDepth);
|
|
8
|
+
if (colorDepth >= 24)
|
|
9
|
+
return 24;
|
|
10
|
+
if (colorDepth >= 8)
|
|
11
|
+
return 8;
|
|
12
|
+
if (colorDepth >= 4)
|
|
13
|
+
return 4;
|
|
14
|
+
if (colorDepth === 3)
|
|
15
|
+
return 3;
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
@type {
|
|
20
|
+
(
|
|
21
|
+
isTTY : boolean,
|
|
22
|
+
colorDepth : ColorDepth,
|
|
23
|
+
style? : boolean,
|
|
24
|
+
caret? : boolean,
|
|
25
|
+
erase? : boolean,
|
|
26
|
+
scroll? : boolean,
|
|
27
|
+
) => Features
|
|
28
|
+
}
|
|
29
|
+
*/
|
|
30
|
+
function build(isTTY, colorDepth, style, caret, erase, scroll) {
|
|
31
|
+
if (style !== undefined && caret !== undefined && erase !== undefined && scroll !== undefined)
|
|
32
|
+
return { colorDepth: normalizeColorDepth(colorDepth), style, caret, erase, scroll };
|
|
33
|
+
const support = detectFeatureSupport(isTTY, colorDepth);
|
|
34
|
+
return {
|
|
35
|
+
colorDepth: normalizeColorDepth(colorDepth),
|
|
36
|
+
style: style ?? support.style,
|
|
37
|
+
caret: caret ?? support.caret,
|
|
38
|
+
erase: erase ?? support.erase,
|
|
39
|
+
scroll: scroll ?? support.scroll,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** @type {(isTTY: boolean, enabled: boolean) => Features} */
|
|
43
|
+
const boolean = (isTTY, enabled) => build(isTTY, enabled ? 4 : 1);
|
|
44
|
+
/** @type {(isTTY: boolean, colorDepth: ColorDepth) => Features} */
|
|
45
|
+
const number = (isTTY, colorDepth) => build(isTTY, colorDepth);
|
|
46
|
+
/** @type {(stream: NodeJS.WriteStream) => Features} */
|
|
47
|
+
const tty = stream => build(true, getColorDepth(stream));
|
|
48
|
+
/** @type {() => Features} */
|
|
49
|
+
const pipe = () => build(false, getColorDepth());
|
|
50
|
+
module.exports = { build, boolean, number, tty, pipe };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type ColorDepth = import("./types").ColorDepth;
|
|
2
|
+
export type Features = import("./types").Features;
|
|
3
|
+
export function detectFeatureSupport(isTTY: boolean, colorDepth: ColorDepth): Omit<Features, "colorDepth">;
|
|
4
|
+
export function getColorDepth(stream?: NodeJS.WriteStream): ColorDepth;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** @typedef {import("./types").ColorDepth} ColorDepth */
|
|
3
|
+
/** @typedef {import("./types").Features} Features */
|
|
4
|
+
/** @type {(stream?: NodeJS.WriteStream) => ColorDepth} */
|
|
5
|
+
function getColorDepth(stream) {
|
|
6
|
+
if (stream?.isTTY)
|
|
7
|
+
return /** @type {ColorDepth} */ (stream.getColorDepth());
|
|
8
|
+
if (process.env.NO_COLOR || process.env.NODE_DISABLE_COLORS)
|
|
9
|
+
return 1;
|
|
10
|
+
switch (process.env.FORCE_COLOR) {
|
|
11
|
+
case "":
|
|
12
|
+
case "true":
|
|
13
|
+
case "1":
|
|
14
|
+
return 4;
|
|
15
|
+
case "2":
|
|
16
|
+
return 8;
|
|
17
|
+
case "3":
|
|
18
|
+
return 24;
|
|
19
|
+
default:
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** @type {(isTTY: boolean, colorDepth: ColorDepth) => Omit<Features, "colorDepth">} */
|
|
24
|
+
function detectFeatureSupport(isTTY, colorDepth) {
|
|
25
|
+
const enabled = process.env.TERM !== "dumb" && isTTY;
|
|
26
|
+
return {
|
|
27
|
+
style: colorDepth > 1,
|
|
28
|
+
caret: enabled,
|
|
29
|
+
erase: enabled,
|
|
30
|
+
scroll: enabled,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
module.exports = { detectFeatureSupport, getColorDepth };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type ColorDepth = import("./types").ColorDepth;
|
|
2
|
+
export type Features = import("./types").Features;
|
|
3
|
+
export type Args = [enabled: boolean, stream?: NodeJS.WriteStream] | [colorDepth: ColorDepth, stream?: NodeJS.WriteStream] | [features: Partial<Features>, stream?: NodeJS.WriteStream] | [socket: Socket] | [stream?: NodeJS.WriteStream];
|
|
4
|
+
export function getFeatures(...args: Args): Features;
|
|
5
|
+
import { Socket } from "node:net";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { Socket } = require("node:net");
|
|
3
|
+
const { WriteStream } = require("node:tty");
|
|
4
|
+
const { build, boolean, number, tty, pipe } = require("./build");
|
|
5
|
+
const { getColorDepth } = require("./detect");
|
|
6
|
+
/**
|
|
7
|
+
@typedef {import("./types").ColorDepth} ColorDepth
|
|
8
|
+
@typedef {import("./types").Features} Features
|
|
9
|
+
|
|
10
|
+
@typedef {
|
|
11
|
+
| [enabled : boolean, stream?: NodeJS.WriteStream]
|
|
12
|
+
| [colorDepth : ColorDepth, stream?: NodeJS.WriteStream]
|
|
13
|
+
| [features : Partial<Features>, stream?: NodeJS.WriteStream]
|
|
14
|
+
| [socket : Socket]
|
|
15
|
+
| [stream? : NodeJS.WriteStream]
|
|
16
|
+
} Args
|
|
17
|
+
*/
|
|
18
|
+
/** @type {(...args: Args) => Features} */
|
|
19
|
+
function getFeatures(...args) {
|
|
20
|
+
let [features, stream] = args;
|
|
21
|
+
if (typeof features === "boolean")
|
|
22
|
+
return boolean((stream ?? process.stdout).isTTY, features);
|
|
23
|
+
if (typeof features === "number")
|
|
24
|
+
return number((stream ?? process.stdout).isTTY, features);
|
|
25
|
+
if (!features || typeof features !== "object")
|
|
26
|
+
features = (stream ?? process.stdout);
|
|
27
|
+
if (features instanceof WriteStream)
|
|
28
|
+
return tty(features);
|
|
29
|
+
if (features instanceof Socket)
|
|
30
|
+
return pipe();
|
|
31
|
+
const { colorDepth, style, caret, erase, scroll } = features;
|
|
32
|
+
stream ??= process.stdout;
|
|
33
|
+
if (colorDepth)
|
|
34
|
+
build(stream.isTTY, colorDepth, style, caret, erase, scroll);
|
|
35
|
+
if (stream.isTTY)
|
|
36
|
+
return build(true, getColorDepth(stream), style, caret, erase, scroll);
|
|
37
|
+
return build(false, getColorDepth(), style, caret, erase, scroll);
|
|
38
|
+
}
|
|
39
|
+
module.exports = { getFeatures };
|