-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
index.js
188 lines (151 loc) · 4.8 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// eslint-disable-next-line unicorn/import-style
import chalk, {chalkStderr} from 'chalk';
const TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.))|(?:{(~)?(#?[\w:]+(?:\([^)]*\))?(?:\.#?[\w:]+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(})|((?:.|[\r\n\f])+?)/gi;
const STYLE_REGEX = /(?:^|\.)(?:(?:(\w+)(?:\(([^)]*)\))?)|(?:#(?=[:a-fA-F\d]{2,})([a-fA-F\d]{6})?(?::([a-fA-F\d]{6}))?))/g;
const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/;
const ESCAPE_REGEX = /\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi;
const ESCAPES = new Map([
['n', '\n'],
['r', '\r'],
['t', '\t'],
['b', '\b'],
['f', '\f'],
['v', '\v'],
['0', '\0'],
['\\', '\\'],
['e', '\u001B'],
['a', '\u0007'],
]);
function unescape(c) {
const u = c[0] === 'u';
const bracket = c[1] === '{';
if ((u && !bracket && c.length === 5) || (c[0] === 'x' && c.length === 3)) {
return String.fromCodePoint(Number.parseInt(c.slice(1), 16));
}
if (u && bracket) {
return String.fromCodePoint(Number.parseInt(c.slice(2, -1), 16));
}
return ESCAPES.get(c) || c;
}
function parseArguments(name, arguments_) {
const results = [];
const chunks = arguments_.trim().split(/\s*,\s*/g);
let matches;
for (const chunk of chunks) {
const number = Number(chunk);
if (!Number.isNaN(number)) {
results.push(number);
} else if ((matches = chunk.match(STRING_REGEX))) {
results.push(matches[2].replace(ESCAPE_REGEX, (_, escape, character) => escape ? unescape(escape) : character));
} else {
throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`);
}
}
return results;
}
function parseHex(hex) {
const n = Number.parseInt(hex, 16);
return [
// eslint-disable-next-line no-bitwise
(n >> 16) & 0xFF,
// eslint-disable-next-line no-bitwise
(n >> 8) & 0xFF,
// eslint-disable-next-line no-bitwise
n & 0xFF,
];
}
function parseStyle(style) {
STYLE_REGEX.lastIndex = 0;
const results = [];
let matches;
while ((matches = STYLE_REGEX.exec(style)) !== null) {
const name = matches[1];
if (matches[2]) {
results.push([name, ...parseArguments(name, matches[2])]);
} else if (matches[3] || matches[4]) {
if (matches[3]) {
results.push(['rgb', ...parseHex(matches[3])]);
}
if (matches[4]) {
results.push(['bgRgb', ...parseHex(matches[4])]);
}
} else {
results.push([name]);
}
}
return results;
}
export function makeTemplate(chalk) {
function buildStyle(styles) {
const enabled = {};
for (const layer of styles) {
for (const style of layer.styles) {
enabled[style[0]] = layer.inverse ? null : style.slice(1);
}
}
let current = chalk;
for (const [styleName, styles] of Object.entries(enabled)) {
if (!Array.isArray(styles)) {
continue;
}
if (!(styleName in current)) {
throw new Error(`Unknown Chalk style: ${styleName}`);
}
current = styles.length > 0 ? current[styleName](...styles) : current[styleName];
}
return current;
}
function template(string) {
const styles = [];
const chunks = [];
let chunk = [];
// eslint-disable-next-line max-params
string.replace(TEMPLATE_REGEX, (_, escapeCharacter, inverse, style, close, character) => {
if (escapeCharacter) {
chunk.push(unescape(escapeCharacter));
} else if (style) {
const string = chunk.join('');
chunk = [];
chunks.push(styles.length === 0 ? string : buildStyle(styles)(string));
styles.push({inverse, styles: parseStyle(style)});
} else if (close) {
if (styles.length === 0) {
throw new Error('Found extraneous } in Chalk template literal');
}
chunks.push(buildStyle(styles)(chunk.join('')));
chunk = [];
styles.pop();
} else {
chunk.push(character);
}
});
chunks.push(chunk.join(''));
if (styles.length > 0) {
throw new Error(`Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`);
}
return chunks.join('');
}
return template;
}
function makeChalkTemplate(template) {
function chalkTemplate(firstString, ...arguments_) {
if (!Array.isArray(firstString) || !Array.isArray(firstString.raw)) {
// If chalkTemplate() was called by itself or with a string
throw new TypeError('A tagged template literal must be provided');
}
const parts = [firstString.raw[0]];
for (let index = 1; index < firstString.raw.length; index++) {
parts.push(
String(arguments_[index - 1]).replace(/[{}\\]/g, '\\$&'),
String(firstString.raw[index]),
);
}
return template(parts.join(''));
}
return chalkTemplate;
}
export const makeTaggedTemplate = chalkInstance => makeChalkTemplate(makeTemplate(chalkInstance));
export const template = makeTemplate(chalk);
export default makeChalkTemplate(template);
export const templateStderr = makeTemplate(chalkStderr);
export const chalkTemplateStderr = makeChalkTemplate(templateStderr);