UNPKG

7.47 kBJavaScriptView Raw
1'use strict';
2
3const chalk = require('chalk');
4const readline = require('readline');
5const prettyError = require('./utils/prettyError');
6const emoji = require('./utils/emoji');
7
8var _require = require('grapheme-breaker');
9
10const countBreaks = _require.countBreaks;
11
12const stripAnsi = require('strip-ansi');
13
14class Logger {
15 constructor(options) {
16 this.lines = 0;
17 this.statusLine = null;
18 this.setOptions(options);
19 }
20
21 setOptions(options) {
22 this.logLevel = options && isNaN(options.logLevel) === false ? Number(options.logLevel) : 3;
23 this.color = options && typeof options.color === 'boolean' ? options.color : chalk.supportsColor;
24 this.chalk = new chalk.constructor({ enabled: this.color });
25 this.isTest = options && typeof options.isTest === 'boolean' ? options.isTest : process.env.NODE_ENV === 'test';
26 }
27
28 countLines(message) {
29 return message.split('\n').reduce((p, line) => {
30 if (process.stdout.columns) {
31 return p + Math.ceil((line.length || 1) / process.stdout.columns);
32 }
33
34 return p + 1;
35 }, 0);
36 }
37
38 writeRaw(message) {
39 this.lines += this.countLines(message) - 1;
40 process.stdout.write(message);
41 }
42
43 write(message, persistent = false) {
44 if (!persistent) {
45 this.lines += this.countLines(message);
46 }
47
48 this._log(message);
49 }
50
51 log(message) {
52 if (this.logLevel < 3) {
53 return;
54 }
55
56 this.write(message);
57 }
58
59 persistent(message) {
60 if (this.logLevel < 3) {
61 return;
62 }
63
64 this.write(this.chalk.bold(message), true);
65 }
66
67 warn(err) {
68 if (this.logLevel < 2) {
69 return;
70 }
71
72 var _prettyError = prettyError(err, { color: this.color });
73
74 let message = _prettyError.message,
75 stack = _prettyError.stack;
76
77 this.write(this.chalk.yellow(`${emoji.warning} ${message}`));
78 if (stack) {
79 this.write(stack);
80 }
81 }
82
83 error(err) {
84 if (this.logLevel < 1) {
85 return;
86 }
87
88 var _prettyError2 = prettyError(err, { color: this.color });
89
90 let message = _prettyError2.message,
91 stack = _prettyError2.stack;
92
93
94 this.status(emoji.error, message, 'red');
95 if (stack) {
96 this.write(stack);
97 }
98 }
99
100 clear() {
101 if (!this.color || this.isTest) {
102 return;
103 }
104
105 while (this.lines > 0) {
106 readline.clearLine(process.stdout, 0);
107 readline.moveCursor(process.stdout, 0, -1);
108 this.lines--;
109 }
110
111 readline.cursorTo(process.stdout, 0);
112 this.statusLine = null;
113 }
114
115 writeLine(line, msg) {
116 if (!this.color) {
117 return this.log(msg);
118 }
119
120 let n = this.lines - line;
121 let stdout = process.stdout;
122 readline.cursorTo(stdout, 0);
123 readline.moveCursor(stdout, 0, -n);
124 stdout.write(msg);
125 readline.clearLine(stdout, 1);
126 readline.cursorTo(stdout, 0);
127 readline.moveCursor(stdout, 0, n);
128 }
129
130 status(emoji, message, color = 'gray') {
131 if (this.logLevel < 3) {
132 return;
133 }
134
135 let hasStatusLine = this.statusLine != null;
136 if (!hasStatusLine) {
137 this.statusLine = this.lines;
138 }
139
140 this.writeLine(this.statusLine, this.chalk[color].bold(`${emoji} ${message}`));
141
142 if (!hasStatusLine) {
143 process.stdout.write('\n');
144 this.lines++;
145 }
146 }
147
148 handleMessage(options) {
149 this[options.method](...options.args);
150 }
151
152 _log(message) {
153 console.log(message);
154 }
155
156 table(columns, table) {
157 // Measure column widths
158 let colWidths = [];
159 var _iteratorNormalCompletion = true;
160 var _didIteratorError = false;
161 var _iteratorError = undefined;
162
163 try {
164 for (var _iterator = table[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
165 let row = _step.value;
166
167 let i = 0;
168 var _iteratorNormalCompletion3 = true;
169 var _didIteratorError3 = false;
170 var _iteratorError3 = undefined;
171
172 try {
173 for (var _iterator3 = row[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
174 let item = _step3.value;
175
176 colWidths[i] = Math.max(colWidths[i] || 0, stringWidth(item));
177 i++;
178 }
179 } catch (err) {
180 _didIteratorError3 = true;
181 _iteratorError3 = err;
182 } finally {
183 try {
184 if (!_iteratorNormalCompletion3 && _iterator3.return) {
185 _iterator3.return();
186 }
187 } finally {
188 if (_didIteratorError3) {
189 throw _iteratorError3;
190 }
191 }
192 }
193 }
194
195 // Render rows
196 } catch (err) {
197 _didIteratorError = true;
198 _iteratorError = err;
199 } finally {
200 try {
201 if (!_iteratorNormalCompletion && _iterator.return) {
202 _iterator.return();
203 }
204 } finally {
205 if (_didIteratorError) {
206 throw _iteratorError;
207 }
208 }
209 }
210
211 var _iteratorNormalCompletion2 = true;
212 var _didIteratorError2 = false;
213 var _iteratorError2 = undefined;
214
215 try {
216 for (var _iterator2 = table[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
217 let row = _step2.value;
218
219 let items = row.map((item, i) => {
220 // Add padding between columns unless the alignment is the opposite to the
221 // next column and pad to the column width.
222 let padding = !columns[i + 1] || columns[i + 1].align === columns[i].align ? 4 : 0;
223 return pad(item, colWidths[i] + padding, columns[i].align);
224 });
225
226 this.log(items.join(''));
227 }
228 } catch (err) {
229 _didIteratorError2 = true;
230 _iteratorError2 = err;
231 } finally {
232 try {
233 if (!_iteratorNormalCompletion2 && _iterator2.return) {
234 _iterator2.return();
235 }
236 } finally {
237 if (_didIteratorError2) {
238 throw _iteratorError2;
239 }
240 }
241 }
242 }
243}
244
245// Pad a string with spaces on either side
246function pad(text, length, align = 'left') {
247 let pad = ' '.repeat(length - stringWidth(text));
248 if (align === 'right') {
249 return pad + text;
250 }
251
252 return text + pad;
253}
254
255// Count visible characters in a string
256function stringWidth(string) {
257 return countBreaks(stripAnsi('' + string));
258}
259
260// If we are in a worker, make a proxy class which will
261// send the logger calls to the main process via IPC.
262// These are handled in WorkerFarm and directed to handleMessage above.
263if (process.send) {
264 class LoggerProxy {}
265 var _iteratorNormalCompletion4 = true;
266 var _didIteratorError4 = false;
267 var _iteratorError4 = undefined;
268
269 try {
270 for (var _iterator4 = Object.getOwnPropertyNames(Logger.prototype)[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
271 let method = _step4.value;
272
273 LoggerProxy.prototype[method] = (...args) => {
274 process.send({
275 type: 'logger',
276 method,
277 args
278 });
279 };
280 }
281 } catch (err) {
282 _didIteratorError4 = true;
283 _iteratorError4 = err;
284 } finally {
285 try {
286 if (!_iteratorNormalCompletion4 && _iterator4.return) {
287 _iterator4.return();
288 }
289 } finally {
290 if (_didIteratorError4) {
291 throw _iteratorError4;
292 }
293 }
294 }
295
296 module.exports = new LoggerProxy();
297} else {
298 module.exports = new Logger();
299}
\No newline at end of file