UNPKG

5.27 kBJavaScriptView Raw
1const ANSI_BACKGROUND_OFFSET = 10;
2
3const wrapAnsi16 = (offset = 0) => code => `\u001B[${code + offset}m`;
4
5const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`;
6
7const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
8
9const styles = {
10 modifier: {
11 reset: [0, 0],
12 // 21 isn't widely supported and 22 does the same thing
13 bold: [1, 22],
14 dim: [2, 22],
15 italic: [3, 23],
16 underline: [4, 24],
17 overline: [53, 55],
18 inverse: [7, 27],
19 hidden: [8, 28],
20 strikethrough: [9, 29],
21 },
22 color: {
23 black: [30, 39],
24 red: [31, 39],
25 green: [32, 39],
26 yellow: [33, 39],
27 blue: [34, 39],
28 magenta: [35, 39],
29 cyan: [36, 39],
30 white: [37, 39],
31
32 // Bright color
33 blackBright: [90, 39],
34 gray: [90, 39], // Alias of `blackBright`
35 grey: [90, 39], // Alias of `blackBright`
36 redBright: [91, 39],
37 greenBright: [92, 39],
38 yellowBright: [93, 39],
39 blueBright: [94, 39],
40 magentaBright: [95, 39],
41 cyanBright: [96, 39],
42 whiteBright: [97, 39],
43 },
44 bgColor: {
45 bgBlack: [40, 49],
46 bgRed: [41, 49],
47 bgGreen: [42, 49],
48 bgYellow: [43, 49],
49 bgBlue: [44, 49],
50 bgMagenta: [45, 49],
51 bgCyan: [46, 49],
52 bgWhite: [47, 49],
53
54 // Bright color
55 bgBlackBright: [100, 49],
56 bgGray: [100, 49], // Alias of `bgBlackBright`
57 bgGrey: [100, 49], // Alias of `bgBlackBright`
58 bgRedBright: [101, 49],
59 bgGreenBright: [102, 49],
60 bgYellowBright: [103, 49],
61 bgBlueBright: [104, 49],
62 bgMagentaBright: [105, 49],
63 bgCyanBright: [106, 49],
64 bgWhiteBright: [107, 49],
65 },
66};
67
68export const modifierNames = Object.keys(styles.modifier);
69export const foregroundColorNames = Object.keys(styles.color);
70export const backgroundColorNames = Object.keys(styles.bgColor);
71export const colorNames = [...foregroundColorNames, ...backgroundColorNames];
72
73function assembleStyles() {
74 const codes = new Map();
75
76 for (const [groupName, group] of Object.entries(styles)) {
77 for (const [styleName, style] of Object.entries(group)) {
78 styles[styleName] = {
79 open: `\u001B[${style[0]}m`,
80 close: `\u001B[${style[1]}m`,
81 };
82
83 group[styleName] = styles[styleName];
84
85 codes.set(style[0], style[1]);
86 }
87
88 Object.defineProperty(styles, groupName, {
89 value: group,
90 enumerable: false,
91 });
92 }
93
94 Object.defineProperty(styles, 'codes', {
95 value: codes,
96 enumerable: false,
97 });
98
99 styles.color.close = '\u001B[39m';
100 styles.bgColor.close = '\u001B[49m';
101
102 styles.color.ansi = wrapAnsi16();
103 styles.color.ansi256 = wrapAnsi256();
104 styles.color.ansi16m = wrapAnsi16m();
105 styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
106 styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
107 styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
108
109 // From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js
110 Object.defineProperties(styles, {
111 rgbToAnsi256: {
112 value: (red, green, blue) => {
113 // We use the extended greyscale palette here, with the exception of
114 // black and white. normal palette only has 4 greyscale shades.
115 if (red === green && green === blue) {
116 if (red < 8) {
117 return 16;
118 }
119
120 if (red > 248) {
121 return 231;
122 }
123
124 return Math.round(((red - 8) / 247) * 24) + 232;
125 }
126
127 return 16
128 + (36 * Math.round(red / 255 * 5))
129 + (6 * Math.round(green / 255 * 5))
130 + Math.round(blue / 255 * 5);
131 },
132 enumerable: false,
133 },
134 hexToRgb: {
135 value: hex => {
136 const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
137 if (!matches) {
138 return [0, 0, 0];
139 }
140
141 let [colorString] = matches;
142
143 if (colorString.length === 3) {
144 colorString = [...colorString].map(character => character + character).join('');
145 }
146
147 const integer = Number.parseInt(colorString, 16);
148
149 return [
150 /* eslint-disable no-bitwise */
151 (integer >> 16) & 0xFF,
152 (integer >> 8) & 0xFF,
153 integer & 0xFF,
154 /* eslint-enable no-bitwise */
155 ];
156 },
157 enumerable: false,
158 },
159 hexToAnsi256: {
160 value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
161 enumerable: false,
162 },
163 ansi256ToAnsi: {
164 value: code => {
165 if (code < 8) {
166 return 30 + code;
167 }
168
169 if (code < 16) {
170 return 90 + (code - 8);
171 }
172
173 let red;
174 let green;
175 let blue;
176
177 if (code >= 232) {
178 red = (((code - 232) * 10) + 8) / 255;
179 green = red;
180 blue = red;
181 } else {
182 code -= 16;
183
184 const remainder = code % 36;
185
186 red = Math.floor(code / 36) / 5;
187 green = Math.floor(remainder / 6) / 5;
188 blue = (remainder % 6) / 5;
189 }
190
191 const value = Math.max(red, green, blue) * 2;
192
193 if (value === 0) {
194 return 30;
195 }
196
197 // eslint-disable-next-line no-bitwise
198 let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));
199
200 if (value === 2) {
201 result += 60;
202 }
203
204 return result;
205 },
206 enumerable: false,
207 },
208 rgbToAnsi: {
209 value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
210 enumerable: false,
211 },
212 hexToAnsi: {
213 value: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
214 enumerable: false,
215 },
216 });
217
218 return styles;
219}
220
221const ansiStyles = assembleStyles();
222
223export default ansiStyles;