UNPKG

62.2 kBJavaScriptView Raw
1import Webpack from 'webpack';
2import { isMinimal } from 'std-env';
3import prettyTime from 'pretty-time';
4import path, { sep, delimiter } from 'path';
5import chalk from 'chalk';
6import _consola from 'consola';
7
8function first(arr) {
9 return arr[0];
10}
11function last(arr) {
12 return arr.length ? arr[arr.length - 1] : null;
13}
14function startCase(str) {
15 return str[0].toUpperCase() + str.substr(1);
16}
17function firstMatch(regex, str) {
18 const m = regex.exec(str);
19 return m ? m[0] : null;
20}
21function hasValue(s) {
22 return s && s.length;
23}
24function removeAfter(delimiter, str) {
25 return first(str.split(delimiter)) || "";
26}
27function removeBefore(delimiter, str) {
28 return last(str.split(delimiter)) || "";
29}
30function range(len) {
31 const arr = [];
32 for (let i = 0; i < len; i++) {
33 arr.push(i);
34 }
35 return arr;
36}
37function shortenPath(path = "") {
38 const cwd = process.cwd() + sep;
39 return String(path).replace(cwd, "");
40}
41function objectValues(obj) {
42 return Object.keys(obj).map((key) => obj[key]);
43}
44
45/**
46 * @typedef MarkdownTableOptions
47 * @property {string|null|Array.<string|null|undefined>} [align]
48 * @property {boolean} [padding=true]
49 * @property {boolean} [delimiterStart=true]
50 * @property {boolean} [delimiterStart=true]
51 * @property {boolean} [delimiterEnd=true]
52 * @property {boolean} [alignDelimiters=true]
53 * @property {(value: string) => number} [stringLength]
54 */
55
56/**
57 * Create a table from a matrix of strings.
58 *
59 * @param {Array.<Array.<string|null|undefined>>} table
60 * @param {MarkdownTableOptions} [options]
61 * @returns {string}
62 */
63function markdownTable(table, options) {
64 const settings = options || {};
65 const align = (settings.align || []).concat();
66 const stringLength = settings.stringLength || defaultStringLength;
67 /** @type {number[]} Character codes as symbols for alignment per column. */
68 const alignments = [];
69 let rowIndex = -1;
70 /** @type {string[][]} Cells per row. */
71 const cellMatrix = [];
72 /** @type {number[][]} Sizes of each cell per row. */
73 const sizeMatrix = [];
74 /** @type {number[]} */
75 const longestCellByColumn = [];
76 let mostCellsPerRow = 0;
77 /** @type {number} */
78 let columnIndex;
79 /** @type {string[]} Cells of current row */
80 let row;
81 /** @type {number[]} Sizes of current row */
82 let sizes;
83 /** @type {number} Sizes of current cell */
84 let size;
85 /** @type {string} Current cell */
86 let cell;
87 /** @type {string[]} Chunks of current line. */
88 let line;
89 /** @type {string} */
90 let before;
91 /** @type {string} */
92 let after;
93 /** @type {number} */
94 let code;
95
96 // This is a superfluous loop if we don’t align delimiters, but otherwise we’d
97 // do superfluous work when aligning, so optimize for aligning.
98 while (++rowIndex < table.length) {
99 columnIndex = -1;
100 row = [];
101 sizes = [];
102
103 if (table[rowIndex].length > mostCellsPerRow) {
104 mostCellsPerRow = table[rowIndex].length;
105 }
106
107 while (++columnIndex < table[rowIndex].length) {
108 cell = serialize(table[rowIndex][columnIndex]);
109
110 if (settings.alignDelimiters !== false) {
111 size = stringLength(cell);
112 sizes[columnIndex] = size;
113
114 if (
115 longestCellByColumn[columnIndex] === undefined ||
116 size > longestCellByColumn[columnIndex]
117 ) {
118 longestCellByColumn[columnIndex] = size;
119 }
120 }
121
122 row.push(cell);
123 }
124
125 cellMatrix[rowIndex] = row;
126 sizeMatrix[rowIndex] = sizes;
127 }
128
129 // Figure out which alignments to use.
130 columnIndex = -1;
131
132 if (typeof align === 'object' && 'length' in align) {
133 while (++columnIndex < mostCellsPerRow) {
134 alignments[columnIndex] = toAlignment(align[columnIndex]);
135 }
136 } else {
137 code = toAlignment(align);
138
139 while (++columnIndex < mostCellsPerRow) {
140 alignments[columnIndex] = code;
141 }
142 }
143
144 // Inject the alignment row.
145 columnIndex = -1;
146 row = [];
147 sizes = [];
148
149 while (++columnIndex < mostCellsPerRow) {
150 code = alignments[columnIndex];
151 before = '';
152 after = '';
153
154 if (code === 99 /* `c` */) {
155 before = ':';
156 after = ':';
157 } else if (code === 108 /* `l` */) {
158 before = ':';
159 } else if (code === 114 /* `r` */) {
160 after = ':';
161 }
162
163 // There *must* be at least one hyphen-minus in each alignment cell.
164 size =
165 settings.alignDelimiters === false
166 ? 1
167 : Math.max(
168 1,
169 longestCellByColumn[columnIndex] - before.length - after.length
170 );
171
172 cell = before + '-'.repeat(size) + after;
173
174 if (settings.alignDelimiters !== false) {
175 size = before.length + size + after.length;
176
177 if (size > longestCellByColumn[columnIndex]) {
178 longestCellByColumn[columnIndex] = size;
179 }
180
181 sizes[columnIndex] = size;
182 }
183
184 row[columnIndex] = cell;
185 }
186
187 // Inject the alignment row.
188 cellMatrix.splice(1, 0, row);
189 sizeMatrix.splice(1, 0, sizes);
190
191 rowIndex = -1;
192 /** @type {string[]} */
193 const lines = [];
194
195 while (++rowIndex < cellMatrix.length) {
196 row = cellMatrix[rowIndex];
197 sizes = sizeMatrix[rowIndex];
198 columnIndex = -1;
199 line = [];
200
201 while (++columnIndex < mostCellsPerRow) {
202 cell = row[columnIndex] || '';
203 before = '';
204 after = '';
205
206 if (settings.alignDelimiters !== false) {
207 size = longestCellByColumn[columnIndex] - (sizes[columnIndex] || 0);
208 code = alignments[columnIndex];
209
210 if (code === 114 /* `r` */) {
211 before = ' '.repeat(size);
212 } else if (code === 99 /* `c` */) {
213 if (size % 2) {
214 before = ' '.repeat(size / 2 + 0.5);
215 after = ' '.repeat(size / 2 - 0.5);
216 } else {
217 before = ' '.repeat(size / 2);
218 after = before;
219 }
220 } else {
221 after = ' '.repeat(size);
222 }
223 }
224
225 if (settings.delimiterStart !== false && !columnIndex) {
226 line.push('|');
227 }
228
229 if (
230 settings.padding !== false &&
231 // Don’t add the opening space if we’re not aligning and the cell is
232 // empty: there will be a closing space.
233 !(settings.alignDelimiters === false && cell === '') &&
234 (settings.delimiterStart !== false || columnIndex)
235 ) {
236 line.push(' ');
237 }
238
239 if (settings.alignDelimiters !== false) {
240 line.push(before);
241 }
242
243 line.push(cell);
244
245 if (settings.alignDelimiters !== false) {
246 line.push(after);
247 }
248
249 if (settings.padding !== false) {
250 line.push(' ');
251 }
252
253 if (
254 settings.delimiterEnd !== false ||
255 columnIndex !== mostCellsPerRow - 1
256 ) {
257 line.push('|');
258 }
259 }
260
261 lines.push(
262 settings.delimiterEnd === false
263 ? line.join('').replace(/ +$/, '')
264 : line.join('')
265 );
266 }
267
268 return lines.join('\n')
269}
270
271/**
272 * @param {string|null|undefined} [value]
273 * @returns {string}
274 */
275function serialize(value) {
276 return value === null || value === undefined ? '' : String(value)
277}
278
279/**
280 * @param {string} value
281 * @returns {number}
282 */
283function defaultStringLength(value) {
284 return value.length
285}
286
287/**
288 * @param {string|null|undefined} value
289 * @returns {number}
290 */
291function toAlignment(value) {
292 const code = typeof value === 'string' ? value.charCodeAt(0) : 0;
293
294 return code === 67 /* `C` */ || code === 99 /* `c` */
295 ? 99 /* `c` */
296 : code === 76 /* `L` */ || code === 108 /* `l` */
297 ? 108 /* `l` */
298 : code === 82 /* `R` */ || code === 114 /* `r` */
299 ? 114 /* `r` */
300 : 0
301}
302
303function isUnicodeSupported() {
304 if (process.platform !== 'win32') {
305 return process.env.TERM !== 'linux'; // Linux console (kernel)
306 }
307
308 return Boolean(process.env.CI) ||
309 Boolean(process.env.WT_SESSION) || // Windows Terminal
310 process.env.ConEmuTask === '{cmd::Cmder}' || // ConEmu and cmder
311 process.env.TERM_PROGRAM === 'vscode' ||
312 process.env.TERM === 'xterm-256color' ||
313 process.env.TERM === 'alacritty';
314}
315
316const {platform} = process;
317
318const common = {
319 square: '█',
320 squareDarkShade: '▓',
321 squareMediumShade: '▒',
322 squareLightShade: '░',
323 squareTop: '▀',
324 squareBottom: '▄',
325 squareLeft: '▌',
326 squareRight: '▐',
327 squareCenter: '■',
328 bullet: '●',
329 dot: '․',
330 ellipsis: '…',
331 pointerSmall: '›',
332 triangleUp: '▲',
333 triangleUpSmall: '▴',
334 triangleDown: '▼',
335 triangleDownSmall: '▾',
336 triangleLeftSmall: '◂',
337 triangleRightSmall: '▸',
338 home: '⌂',
339 heart: '♥',
340 musicNote: '♪',
341 musicNoteBeamed: '♫',
342 arrowUp: '↑',
343 arrowDown: '↓',
344 arrowLeft: '←',
345 arrowRight: '→',
346 arrowLeftRight: '↔',
347 arrowUpDown: '↕',
348 almostEqual: '≈',
349 notEqual: '≠',
350 lessOrEqual: '≤',
351 greaterOrEqual: '≥',
352 identical: '≡',
353 infinity: '∞',
354 subscriptZero: '₀',
355 subscriptOne: '₁',
356 subscriptTwo: '₂',
357 subscriptThree: '₃',
358 subscriptFour: '₄',
359 subscriptFive: '₅',
360 subscriptSix: '₆',
361 subscriptSeven: '₇',
362 subscriptEight: '₈',
363 subscriptNine: '₉',
364 oneHalf: '½',
365 oneThird: '⅓',
366 oneQuarter: '¼',
367 oneFifth: '⅕',
368 oneSixth: '⅙',
369 oneEighth: '⅛',
370 twoThirds: '⅔',
371 twoFifths: '⅖',
372 threeQuarters: '¾',
373 threeFifths: '⅗',
374 threeEighths: '⅜',
375 fourFifths: '⅘',
376 fiveSixths: '⅚',
377 fiveEighths: '⅝',
378 sevenEighths: '⅞',
379 line: '─',
380 lineBold: '━',
381 lineDouble: '═',
382 lineDashed0: '┄',
383 lineDashed1: '┅',
384 lineDashed2: '┈',
385 lineDashed3: '┉',
386 lineDashed4: '╌',
387 lineDashed5: '╍',
388 lineDashed6: '╴',
389 lineDashed7: '╶',
390 lineDashed8: '╸',
391 lineDashed9: '╺',
392 lineDashed10: '╼',
393 lineDashed11: '╾',
394 lineDashed12: '−',
395 lineDashed13: '–',
396 lineDashed14: '‐',
397 lineDashed15: '⁃',
398 lineVertical: '│',
399 lineVerticalBold: '┃',
400 lineVerticalDouble: '║',
401 lineVerticalDashed0: '┆',
402 lineVerticalDashed1: '┇',
403 lineVerticalDashed2: '┊',
404 lineVerticalDashed3: '┋',
405 lineVerticalDashed4: '╎',
406 lineVerticalDashed5: '╏',
407 lineVerticalDashed6: '╵',
408 lineVerticalDashed7: '╷',
409 lineVerticalDashed8: '╹',
410 lineVerticalDashed9: '╻',
411 lineVerticalDashed10: '╽',
412 lineVerticalDashed11: '╿',
413 lineDownLeft: '┐',
414 lineDownLeftArc: '╮',
415 lineDownBoldLeftBold: '┓',
416 lineDownBoldLeft: '┒',
417 lineDownLeftBold: '┑',
418 lineDownDoubleLeftDouble: '╗',
419 lineDownDoubleLeft: '╖',
420 lineDownLeftDouble: '╕',
421 lineDownRight: '┌',
422 lineDownRightArc: '╭',
423 lineDownBoldRightBold: '┏',
424 lineDownBoldRight: '┎',
425 lineDownRightBold: '┍',
426 lineDownDoubleRightDouble: '╔',
427 lineDownDoubleRight: '╓',
428 lineDownRightDouble: '╒',
429 lineUpLeft: '┘',
430 lineUpLeftArc: '╯',
431 lineUpBoldLeftBold: '┛',
432 lineUpBoldLeft: '┚',
433 lineUpLeftBold: '┙',
434 lineUpDoubleLeftDouble: '╝',
435 lineUpDoubleLeft: '╜',
436 lineUpLeftDouble: '╛',
437 lineUpRight: '└',
438 lineUpRightArc: '╰',
439 lineUpBoldRightBold: '┗',
440 lineUpBoldRight: '┖',
441 lineUpRightBold: '┕',
442 lineUpDoubleRightDouble: '╚',
443 lineUpDoubleRight: '╙',
444 lineUpRightDouble: '╘',
445 lineUpDownLeft: '┤',
446 lineUpBoldDownBoldLeftBold: '┫',
447 lineUpBoldDownBoldLeft: '┨',
448 lineUpDownLeftBold: '┥',
449 lineUpBoldDownLeftBold: '┩',
450 lineUpDownBoldLeftBold: '┪',
451 lineUpDownBoldLeft: '┧',
452 lineUpBoldDownLeft: '┦',
453 lineUpDoubleDownDoubleLeftDouble: '╣',
454 lineUpDoubleDownDoubleLeft: '╢',
455 lineUpDownLeftDouble: '╡',
456 lineUpDownRight: '├',
457 lineUpBoldDownBoldRightBold: '┣',
458 lineUpBoldDownBoldRight: '┠',
459 lineUpDownRightBold: '┝',
460 lineUpBoldDownRightBold: '┡',
461 lineUpDownBoldRightBold: '┢',
462 lineUpDownBoldRight: '┟',
463 lineUpBoldDownRight: '┞',
464 lineUpDoubleDownDoubleRightDouble: '╠',
465 lineUpDoubleDownDoubleRight: '╟',
466 lineUpDownRightDouble: '╞',
467 lineDownLeftRight: '┬',
468 lineDownBoldLeftBoldRightBold: '┳',
469 lineDownLeftBoldRightBold: '┯',
470 lineDownBoldLeftRight: '┰',
471 lineDownBoldLeftBoldRight: '┱',
472 lineDownBoldLeftRightBold: '┲',
473 lineDownLeftRightBold: '┮',
474 lineDownLeftBoldRight: '┭',
475 lineDownDoubleLeftDoubleRightDouble: '╦',
476 lineDownDoubleLeftRight: '╥',
477 lineDownLeftDoubleRightDouble: '╤',
478 lineUpLeftRight: '┴',
479 lineUpBoldLeftBoldRightBold: '┻',
480 lineUpLeftBoldRightBold: '┷',
481 lineUpBoldLeftRight: '┸',
482 lineUpBoldLeftBoldRight: '┹',
483 lineUpBoldLeftRightBold: '┺',
484 lineUpLeftRightBold: '┶',
485 lineUpLeftBoldRight: '┵',
486 lineUpDoubleLeftDoubleRightDouble: '╩',
487 lineUpDoubleLeftRight: '╨',
488 lineUpLeftDoubleRightDouble: '╧',
489 lineUpDownLeftRight: '┼',
490 lineUpBoldDownBoldLeftBoldRightBold: '╋',
491 lineUpDownBoldLeftBoldRightBold: '╈',
492 lineUpBoldDownLeftBoldRightBold: '╇',
493 lineUpBoldDownBoldLeftRightBold: '╊',
494 lineUpBoldDownBoldLeftBoldRight: '╉',
495 lineUpBoldDownLeftRight: '╀',
496 lineUpDownBoldLeftRight: '╁',
497 lineUpDownLeftBoldRight: '┽',
498 lineUpDownLeftRightBold: '┾',
499 lineUpBoldDownBoldLeftRight: '╂',
500 lineUpDownLeftBoldRightBold: '┿',
501 lineUpBoldDownLeftBoldRight: '╃',
502 lineUpBoldDownLeftRightBold: '╄',
503 lineUpDownBoldLeftBoldRight: '╅',
504 lineUpDownBoldLeftRightBold: '╆',
505 lineUpDoubleDownDoubleLeftDoubleRightDouble: '╬',
506 lineUpDoubleDownDoubleLeftRight: '╫',
507 lineUpDownLeftDoubleRightDouble: '╪',
508 lineCross: '╳',
509 lineBackslash: '╲',
510 lineSlash: '╱'
511};
512
513const mainSymbols = {
514 ...common,
515 // The main symbols for those do not look that good on Ubuntu.
516 ...(
517 platform === 'linux' ?
518 {
519 circleQuestionMark: '?⃝',
520 questionMarkPrefix: '?⃝'
521 } :
522 {
523 circleQuestionMark: '?',
524 questionMarkPrefix: '?'
525 }
526 ),
527 tick: '✔',
528 info: 'ℹ',
529 warning: '⚠',
530 cross: '✖',
531 squareSmall: '◻',
532 squareSmallFilled: '◼',
533 circle: '◯',
534 circleFilled: '◉',
535 circleDotted: '◌',
536 circleDouble: '◎',
537 circleCircle: 'ⓞ',
538 circleCross: 'ⓧ',
539 circlePipe: 'Ⓘ',
540 radioOn: '◉',
541 radioOff: '◯',
542 checkboxOn: '☒',
543 checkboxOff: '☐',
544 checkboxCircleOn: 'ⓧ',
545 checkboxCircleOff: 'Ⓘ',
546 pointer: '❯',
547 triangleUpOutline: '△',
548 triangleLeft: '◀',
549 triangleRight: '▶',
550 lozenge: '◆',
551 lozengeOutline: '◇',
552 hamburger: '☰',
553 smiley: '㋡',
554 mustache: '෴',
555 star: '★',
556 play: '▶',
557 nodejs: '⬢',
558 oneSeventh: '⅐',
559 oneNinth: '⅑',
560 oneTenth: '⅒'
561};
562
563const fallbackSymbols = {
564 ...common,
565 tick: '√',
566 info: 'i',
567 warning: '‼',
568 cross: '×',
569 squareSmall: '□',
570 squareSmallFilled: '■',
571 circle: '( )',
572 circleFilled: '(*)',
573 circleDotted: '( )',
574 circleDouble: '( )',
575 circleCircle: '(○)',
576 circleCross: '(×)',
577 circlePipe: '(│)',
578 circleQuestionMark: '(?)',
579 radioOn: '(*)',
580 radioOff: '( )',
581 checkboxOn: '[×]',
582 checkboxOff: '[ ]',
583 checkboxCircleOn: '(×)',
584 checkboxCircleOff: '( )',
585 questionMarkPrefix: '?',
586 pointer: '>',
587 triangleUpOutline: '∆',
588 triangleLeft: '◄',
589 triangleRight: '►',
590 lozenge: '♦',
591 lozengeOutline: '◊',
592 hamburger: '≡',
593 smiley: '☺',
594 mustache: '┌─┐',
595 star: '✶',
596 play: '►',
597 nodejs: '♦',
598 oneSeventh: '1/7',
599 oneNinth: '1/9',
600 oneTenth: '1/10'
601};
602
603const shouldUseMain = isUnicodeSupported();
604const figures = shouldUseMain ? mainSymbols : fallbackSymbols;
605
606const { bullet, tick, cross, pointerSmall, radioOff } = figures;
607const nodeModules = `${delimiter}node_modules${delimiter}`;
608const BAR_LENGTH = 25;
609const BLOCK_CHAR = "\u2588";
610const BLOCK_CHAR2 = "\u2588";
611const NEXT = " " + chalk.blue(pointerSmall) + " ";
612const BULLET = bullet;
613const TICK = tick;
614const CROSS = cross;
615const CIRCLE_OPEN = radioOff;
616
617const consola = _consola.withTag("webpackbar");
618const colorize = (color) => {
619 if (color[0] === "#") {
620 return chalk.hex(color);
621 }
622 return chalk[color] || chalk.keyword(color);
623};
624const renderBar = (progress, color) => {
625 const w = progress * (BAR_LENGTH / 100);
626 const bg = chalk.white(BLOCK_CHAR);
627 const fg = colorize(color)(BLOCK_CHAR2);
628 return range(BAR_LENGTH).map((i) => i < w ? fg : bg).join("");
629};
630function createTable(data) {
631 return markdownTable(data);
632}
633function ellipsisLeft(str, n) {
634 if (str.length <= n - 3) {
635 return str;
636 }
637 return `...${str.substr(str.length - n - 1)}`;
638}
639
640const parseRequest = (requestStr) => {
641 const parts = (requestStr || "").split("!");
642 const file = path.relative(process.cwd(), removeAfter("?", removeBefore(nodeModules, parts.pop())));
643 const loaders = parts.map((part) => firstMatch(/[a-z0-9-@]+-loader/, part)).filter(hasValue);
644 return {
645 file: hasValue(file) ? file : null,
646 loaders
647 };
648};
649const formatRequest = (request) => {
650 const loaders = request.loaders.join(NEXT);
651 if (!loaders.length) {
652 return request.file || "";
653 }
654 return `${loaders}${NEXT}${request.file}`;
655};
656function hook(compiler, hookName, fn) {
657 if (compiler.hooks) {
658 compiler.hooks[hookName].tap("WebpackBar:" + hookName, fn);
659 } else {
660 compiler.plugin(hookName, fn);
661 }
662}
663
664const ESC = '\u001B[';
665const OSC = '\u001B]';
666const BEL = '\u0007';
667const SEP = ';';
668const isTerminalApp = process.env.TERM_PROGRAM === 'Apple_Terminal';
669
670const ansiEscapes = {};
671
672ansiEscapes.cursorTo = (x, y) => {
673 if (typeof x !== 'number') {
674 throw new TypeError('The `x` argument is required');
675 }
676
677 if (typeof y !== 'number') {
678 return ESC + (x + 1) + 'G';
679 }
680
681 return ESC + (y + 1) + ';' + (x + 1) + 'H';
682};
683
684ansiEscapes.cursorMove = (x, y) => {
685 if (typeof x !== 'number') {
686 throw new TypeError('The `x` argument is required');
687 }
688
689 let returnValue = '';
690
691 if (x < 0) {
692 returnValue += ESC + (-x) + 'D';
693 } else if (x > 0) {
694 returnValue += ESC + x + 'C';
695 }
696
697 if (y < 0) {
698 returnValue += ESC + (-y) + 'A';
699 } else if (y > 0) {
700 returnValue += ESC + y + 'B';
701 }
702
703 return returnValue;
704};
705
706ansiEscapes.cursorUp = (count = 1) => ESC + count + 'A';
707ansiEscapes.cursorDown = (count = 1) => ESC + count + 'B';
708ansiEscapes.cursorForward = (count = 1) => ESC + count + 'C';
709ansiEscapes.cursorBackward = (count = 1) => ESC + count + 'D';
710
711ansiEscapes.cursorLeft = ESC + 'G';
712ansiEscapes.cursorSavePosition = isTerminalApp ? '\u001B7' : ESC + 's';
713ansiEscapes.cursorRestorePosition = isTerminalApp ? '\u001B8' : ESC + 'u';
714ansiEscapes.cursorGetPosition = ESC + '6n';
715ansiEscapes.cursorNextLine = ESC + 'E';
716ansiEscapes.cursorPrevLine = ESC + 'F';
717ansiEscapes.cursorHide = ESC + '?25l';
718ansiEscapes.cursorShow = ESC + '?25h';
719
720ansiEscapes.eraseLines = count => {
721 let clear = '';
722
723 for (let i = 0; i < count; i++) {
724 clear += ansiEscapes.eraseLine + (i < count - 1 ? ansiEscapes.cursorUp() : '');
725 }
726
727 if (count) {
728 clear += ansiEscapes.cursorLeft;
729 }
730
731 return clear;
732};
733
734ansiEscapes.eraseEndLine = ESC + 'K';
735ansiEscapes.eraseStartLine = ESC + '1K';
736ansiEscapes.eraseLine = ESC + '2K';
737ansiEscapes.eraseDown = ESC + 'J';
738ansiEscapes.eraseUp = ESC + '1J';
739ansiEscapes.eraseScreen = ESC + '2J';
740ansiEscapes.scrollUp = ESC + 'S';
741ansiEscapes.scrollDown = ESC + 'T';
742
743ansiEscapes.clearScreen = '\u001Bc';
744
745ansiEscapes.clearTerminal = process.platform === 'win32' ?
746 `${ansiEscapes.eraseScreen}${ESC}0f` :
747 // 1. Erases the screen (Only done in case `2` is not supported)
748 // 2. Erases the whole screen including scrollback buffer
749 // 3. Moves cursor to the top-left position
750 // More info: https://www.real-world-systems.com/docs/ANSIcode.html
751 `${ansiEscapes.eraseScreen}${ESC}3J${ESC}H`;
752
753ansiEscapes.beep = BEL;
754
755ansiEscapes.link = (text, url) => {
756 return [
757 OSC,
758 '8',
759 SEP,
760 SEP,
761 url,
762 BEL,
763 text,
764 OSC,
765 '8',
766 SEP,
767 SEP,
768 BEL
769 ].join('');
770};
771
772ansiEscapes.image = (buffer, options = {}) => {
773 let returnValue = `${OSC}1337;File=inline=1`;
774
775 if (options.width) {
776 returnValue += `;width=${options.width}`;
777 }
778
779 if (options.height) {
780 returnValue += `;height=${options.height}`;
781 }
782
783 if (options.preserveAspectRatio === false) {
784 returnValue += ';preserveAspectRatio=0';
785 }
786
787 return returnValue + ':' + buffer.toString('base64') + BEL;
788};
789
790ansiEscapes.iTerm = {
791 setCwd: (cwd = process.cwd()) => `${OSC}50;CurrentDir=${cwd}${BEL}`,
792
793 annotation: (message, options = {}) => {
794 let returnValue = `${OSC}1337;`;
795
796 const hasX = typeof options.x !== 'undefined';
797 const hasY = typeof options.y !== 'undefined';
798 if ((hasX || hasY) && !(hasX && hasY && typeof options.length !== 'undefined')) {
799 throw new Error('`x`, `y` and `length` must be defined when `x` or `y` is defined');
800 }
801
802 message = message.replace(/\|/g, '');
803
804 returnValue += options.isHidden ? 'AddHiddenAnnotation=' : 'AddAnnotation=';
805
806 if (options.length > 0) {
807 returnValue +=
808 (hasX ?
809 [message, options.length, options.x, options.y] :
810 [options.length, message]).join('|');
811 } else {
812 returnValue += message;
813 }
814
815 return returnValue + BEL;
816 }
817};
818
819function ansiRegex({onlyFirst = false} = {}) {
820 const pattern = [
821 '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
822 '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
823 ].join('|');
824
825 return new RegExp(pattern, onlyFirst ? undefined : 'g');
826}
827
828function stripAnsi(string) {
829 if (typeof string !== 'string') {
830 throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
831 }
832
833 return string.replace(ansiRegex(), '');
834}
835
836/* eslint-disable yoda */
837
838function isFullwidthCodePoint(codePoint) {
839 if (!Number.isInteger(codePoint)) {
840 return false;
841 }
842
843 // Code points are derived from:
844 // https://unicode.org/Public/UNIDATA/EastAsianWidth.txt
845 return codePoint >= 0x1100 && (
846 codePoint <= 0x115F || // Hangul Jamo
847 codePoint === 0x2329 || // LEFT-POINTING ANGLE BRACKET
848 codePoint === 0x232A || // RIGHT-POINTING ANGLE BRACKET
849 // CJK Radicals Supplement .. Enclosed CJK Letters and Months
850 (0x2E80 <= codePoint && codePoint <= 0x3247 && codePoint !== 0x303F) ||
851 // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
852 (0x3250 <= codePoint && codePoint <= 0x4DBF) ||
853 // CJK Unified Ideographs .. Yi Radicals
854 (0x4E00 <= codePoint && codePoint <= 0xA4C6) ||
855 // Hangul Jamo Extended-A
856 (0xA960 <= codePoint && codePoint <= 0xA97C) ||
857 // Hangul Syllables
858 (0xAC00 <= codePoint && codePoint <= 0xD7A3) ||
859 // CJK Compatibility Ideographs
860 (0xF900 <= codePoint && codePoint <= 0xFAFF) ||
861 // Vertical Forms
862 (0xFE10 <= codePoint && codePoint <= 0xFE19) ||
863 // CJK Compatibility Forms .. Small Form Variants
864 (0xFE30 <= codePoint && codePoint <= 0xFE6B) ||
865 // Halfwidth and Fullwidth Forms
866 (0xFF01 <= codePoint && codePoint <= 0xFF60) ||
867 (0xFFE0 <= codePoint && codePoint <= 0xFFE6) ||
868 // Kana Supplement
869 (0x1B000 <= codePoint && codePoint <= 0x1B001) ||
870 // Enclosed Ideographic Supplement
871 (0x1F200 <= codePoint && codePoint <= 0x1F251) ||
872 // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
873 (0x20000 <= codePoint && codePoint <= 0x3FFFD)
874 );
875}
876
877var emojiRegex = function () {
878 // https://mths.be/emoji
879 return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
880};
881
882function stringWidth(string) {
883 if (typeof string !== 'string' || string.length === 0) {
884 return 0;
885 }
886
887 string = stripAnsi(string);
888
889 if (string.length === 0) {
890 return 0;
891 }
892
893 string = string.replace(emojiRegex(), ' ');
894
895 let width = 0;
896
897 for (let index = 0; index < string.length; index++) {
898 const codePoint = string.codePointAt(index);
899
900 // Ignore control characters
901 if (codePoint <= 0x1F || (codePoint >= 0x7F && codePoint <= 0x9F)) {
902 continue;
903 }
904
905 // Ignore combining characters
906 if (codePoint >= 0x300 && codePoint <= 0x36F) {
907 continue;
908 }
909
910 // Surrogates
911 if (codePoint > 0xFFFF) {
912 index++;
913 }
914
915 width += isFullwidthCodePoint(codePoint) ? 2 : 1;
916 }
917
918 return width;
919}
920
921const ANSI_BACKGROUND_OFFSET = 10;
922
923const wrapAnsi16 = (offset = 0) => code => `\u001B[${code + offset}m`;
924
925const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`;
926
927const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
928
929function assembleStyles() {
930 const codes = new Map();
931 const styles = {
932 modifier: {
933 reset: [0, 0],
934 // 21 isn't widely supported and 22 does the same thing
935 bold: [1, 22],
936 dim: [2, 22],
937 italic: [3, 23],
938 underline: [4, 24],
939 overline: [53, 55],
940 inverse: [7, 27],
941 hidden: [8, 28],
942 strikethrough: [9, 29]
943 },
944 color: {
945 black: [30, 39],
946 red: [31, 39],
947 green: [32, 39],
948 yellow: [33, 39],
949 blue: [34, 39],
950 magenta: [35, 39],
951 cyan: [36, 39],
952 white: [37, 39],
953
954 // Bright color
955 blackBright: [90, 39],
956 redBright: [91, 39],
957 greenBright: [92, 39],
958 yellowBright: [93, 39],
959 blueBright: [94, 39],
960 magentaBright: [95, 39],
961 cyanBright: [96, 39],
962 whiteBright: [97, 39]
963 },
964 bgColor: {
965 bgBlack: [40, 49],
966 bgRed: [41, 49],
967 bgGreen: [42, 49],
968 bgYellow: [43, 49],
969 bgBlue: [44, 49],
970 bgMagenta: [45, 49],
971 bgCyan: [46, 49],
972 bgWhite: [47, 49],
973
974 // Bright color
975 bgBlackBright: [100, 49],
976 bgRedBright: [101, 49],
977 bgGreenBright: [102, 49],
978 bgYellowBright: [103, 49],
979 bgBlueBright: [104, 49],
980 bgMagentaBright: [105, 49],
981 bgCyanBright: [106, 49],
982 bgWhiteBright: [107, 49]
983 }
984 };
985
986 // Alias bright black as gray (and grey)
987 styles.color.gray = styles.color.blackBright;
988 styles.bgColor.bgGray = styles.bgColor.bgBlackBright;
989 styles.color.grey = styles.color.blackBright;
990 styles.bgColor.bgGrey = styles.bgColor.bgBlackBright;
991
992 for (const [groupName, group] of Object.entries(styles)) {
993 for (const [styleName, style] of Object.entries(group)) {
994 styles[styleName] = {
995 open: `\u001B[${style[0]}m`,
996 close: `\u001B[${style[1]}m`
997 };
998
999 group[styleName] = styles[styleName];
1000
1001 codes.set(style[0], style[1]);
1002 }
1003
1004 Object.defineProperty(styles, groupName, {
1005 value: group,
1006 enumerable: false
1007 });
1008 }
1009
1010 Object.defineProperty(styles, 'codes', {
1011 value: codes,
1012 enumerable: false
1013 });
1014
1015 styles.color.close = '\u001B[39m';
1016 styles.bgColor.close = '\u001B[49m';
1017
1018 styles.color.ansi = wrapAnsi16();
1019 styles.color.ansi256 = wrapAnsi256();
1020 styles.color.ansi16m = wrapAnsi16m();
1021 styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
1022 styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
1023 styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
1024
1025 // From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js
1026 Object.defineProperties(styles, {
1027 rgbToAnsi256: {
1028 value: (red, green, blue) => {
1029 // We use the extended greyscale palette here, with the exception of
1030 // black and white. normal palette only has 4 greyscale shades.
1031 if (red === green && green === blue) {
1032 if (red < 8) {
1033 return 16;
1034 }
1035
1036 if (red > 248) {
1037 return 231;
1038 }
1039
1040 return Math.round(((red - 8) / 247) * 24) + 232;
1041 }
1042
1043 return 16 +
1044 (36 * Math.round(red / 255 * 5)) +
1045 (6 * Math.round(green / 255 * 5)) +
1046 Math.round(blue / 255 * 5);
1047 },
1048 enumerable: false
1049 },
1050 hexToRgb: {
1051 value: hex => {
1052 const matches = /(?<colorString>[a-f\d]{6}|[a-f\d]{3})/i.exec(hex.toString(16));
1053 if (!matches) {
1054 return [0, 0, 0];
1055 }
1056
1057 let {colorString} = matches.groups;
1058
1059 if (colorString.length === 3) {
1060 colorString = colorString.split('').map(character => character + character).join('');
1061 }
1062
1063 const integer = Number.parseInt(colorString, 16);
1064
1065 return [
1066 (integer >> 16) & 0xFF,
1067 (integer >> 8) & 0xFF,
1068 integer & 0xFF
1069 ];
1070 },
1071 enumerable: false
1072 },
1073 hexToAnsi256: {
1074 value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
1075 enumerable: false
1076 },
1077 ansi256ToAnsi: {
1078 value: code => {
1079 if (code < 8) {
1080 return 30 + code;
1081 }
1082
1083 if (code < 16) {
1084 return 90 + (code - 8);
1085 }
1086
1087 let red;
1088 let green;
1089 let blue;
1090
1091 if (code >= 232) {
1092 red = (((code - 232) * 10) + 8) / 255;
1093 green = red;
1094 blue = red;
1095 } else {
1096 code -= 16;
1097
1098 const remainder = code % 36;
1099
1100 red = Math.floor(code / 36) / 5;
1101 green = Math.floor(remainder / 6) / 5;
1102 blue = (remainder % 6) / 5;
1103 }
1104
1105 const value = Math.max(red, green, blue) * 2;
1106
1107 if (value === 0) {
1108 return 30;
1109 }
1110
1111 let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));
1112
1113 if (value === 2) {
1114 result += 60;
1115 }
1116
1117 return result;
1118 },
1119 enumerable: false
1120 },
1121 rgbToAnsi: {
1122 value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
1123 enumerable: false
1124 },
1125 hexToAnsi: {
1126 value: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
1127 enumerable: false
1128 }
1129 });
1130
1131 return styles;
1132}
1133
1134const ansiStyles = assembleStyles();
1135
1136const ESCAPES = new Set([
1137 '\u001B',
1138 '\u009B',
1139]);
1140
1141const END_CODE = 39;
1142const ANSI_ESCAPE_BELL = '\u0007';
1143const ANSI_CSI = '[';
1144const ANSI_OSC = ']';
1145const ANSI_SGR_TERMINATOR = 'm';
1146const ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
1147
1148const wrapAnsiCode = code => `${ESCAPES.values().next().value}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
1149const wrapAnsiHyperlink = uri => `${ESCAPES.values().next().value}${ANSI_ESCAPE_LINK}${uri}${ANSI_ESCAPE_BELL}`;
1150
1151// Calculate the length of words split on ' ', ignoring
1152// the extra characters added by ansi escape codes
1153const wordLengths = string => string.split(' ').map(character => stringWidth(character));
1154
1155// Wrap a long word across multiple rows
1156// Ansi escape codes do not count towards length
1157const wrapWord = (rows, word, columns) => {
1158 const characters = [...word];
1159
1160 let isInsideEscape = false;
1161 let isInsideLinkEscape = false;
1162 let visible = stringWidth(stripAnsi(rows[rows.length - 1]));
1163
1164 for (const [index, character] of characters.entries()) {
1165 const characterLength = stringWidth(character);
1166
1167 if (visible + characterLength <= columns) {
1168 rows[rows.length - 1] += character;
1169 } else {
1170 rows.push(character);
1171 visible = 0;
1172 }
1173
1174 if (ESCAPES.has(character)) {
1175 isInsideEscape = true;
1176 isInsideLinkEscape = characters.slice(index + 1).join('').startsWith(ANSI_ESCAPE_LINK);
1177 }
1178
1179 if (isInsideEscape) {
1180 if (isInsideLinkEscape) {
1181 if (character === ANSI_ESCAPE_BELL) {
1182 isInsideEscape = false;
1183 isInsideLinkEscape = false;
1184 }
1185 } else if (character === ANSI_SGR_TERMINATOR) {
1186 isInsideEscape = false;
1187 }
1188
1189 continue;
1190 }
1191
1192 visible += characterLength;
1193
1194 if (visible === columns && index < characters.length - 1) {
1195 rows.push('');
1196 visible = 0;
1197 }
1198 }
1199
1200 // It's possible that the last row we copy over is only
1201 // ansi escape characters, handle this edge-case
1202 if (!visible && rows[rows.length - 1].length > 0 && rows.length > 1) {
1203 rows[rows.length - 2] += rows.pop();
1204 }
1205};
1206
1207// Trims spaces from a string ignoring invisible sequences
1208const stringVisibleTrimSpacesRight = string => {
1209 const words = string.split(' ');
1210 let last = words.length;
1211
1212 while (last > 0) {
1213 if (stringWidth(words[last - 1]) > 0) {
1214 break;
1215 }
1216
1217 last--;
1218 }
1219
1220 if (last === words.length) {
1221 return string;
1222 }
1223
1224 return words.slice(0, last).join(' ') + words.slice(last).join('');
1225};
1226
1227// The wrap-ansi module can be invoked in either 'hard' or 'soft' wrap mode
1228//
1229// 'hard' will never allow a string to take up more than columns characters
1230//
1231// 'soft' allows long words to expand past the column length
1232const exec = (string, columns, options = {}) => {
1233 if (options.trim !== false && string.trim() === '') {
1234 return '';
1235 }
1236
1237 let returnValue = '';
1238 let escapeCode;
1239 let escapeUrl;
1240
1241 const lengths = wordLengths(string);
1242 let rows = [''];
1243
1244 for (const [index, word] of string.split(' ').entries()) {
1245 if (options.trim !== false) {
1246 rows[rows.length - 1] = rows[rows.length - 1].trimStart();
1247 }
1248
1249 let rowLength = stringWidth(rows[rows.length - 1]);
1250
1251 if (index !== 0) {
1252 if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
1253 // If we start with a new word but the current row length equals the length of the columns, add a new row
1254 rows.push('');
1255 rowLength = 0;
1256 }
1257
1258 if (rowLength > 0 || options.trim === false) {
1259 rows[rows.length - 1] += ' ';
1260 rowLength++;
1261 }
1262 }
1263
1264 // In 'hard' wrap mode, the length of a line is never allowed to extend past 'columns'
1265 if (options.hard && lengths[index] > columns) {
1266 const remainingColumns = (columns - rowLength);
1267 const breaksStartingThisLine = 1 + Math.floor((lengths[index] - remainingColumns - 1) / columns);
1268 const breaksStartingNextLine = Math.floor((lengths[index] - 1) / columns);
1269 if (breaksStartingNextLine < breaksStartingThisLine) {
1270 rows.push('');
1271 }
1272
1273 wrapWord(rows, word, columns);
1274 continue;
1275 }
1276
1277 if (rowLength + lengths[index] > columns && rowLength > 0 && lengths[index] > 0) {
1278 if (options.wordWrap === false && rowLength < columns) {
1279 wrapWord(rows, word, columns);
1280 continue;
1281 }
1282
1283 rows.push('');
1284 }
1285
1286 if (rowLength + lengths[index] > columns && options.wordWrap === false) {
1287 wrapWord(rows, word, columns);
1288 continue;
1289 }
1290
1291 rows[rows.length - 1] += word;
1292 }
1293
1294 if (options.trim !== false) {
1295 rows = rows.map(row => stringVisibleTrimSpacesRight(row));
1296 }
1297
1298 const pre = [...rows.join('\n')];
1299
1300 for (const [index, character] of pre.entries()) {
1301 returnValue += character;
1302
1303 if (ESCAPES.has(character)) {
1304 const {groups} = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`).exec(pre.slice(index).join('')) || {groups: {}};
1305 if (groups.code !== undefined) {
1306 const code = Number.parseFloat(groups.code);
1307 escapeCode = code === END_CODE ? undefined : code;
1308 } else if (groups.uri !== undefined) {
1309 escapeUrl = groups.uri.length === 0 ? undefined : groups.uri;
1310 }
1311 }
1312
1313 const code = ansiStyles.codes.get(Number(escapeCode));
1314
1315 if (pre[index + 1] === '\n') {
1316 if (escapeUrl) {
1317 returnValue += wrapAnsiHyperlink('');
1318 }
1319
1320 if (escapeCode && code) {
1321 returnValue += wrapAnsiCode(code);
1322 }
1323 } else if (character === '\n') {
1324 if (escapeCode && code) {
1325 returnValue += wrapAnsiCode(escapeCode);
1326 }
1327
1328 if (escapeUrl) {
1329 returnValue += wrapAnsiHyperlink(escapeUrl);
1330 }
1331 }
1332 }
1333
1334 return returnValue;
1335};
1336
1337// For each newline, invoke the method separately
1338function wrapAnsi(string, columns, options) {
1339 return String(string)
1340 .normalize()
1341 .replace(/\r\n/g, '\n')
1342 .split('\n')
1343 .map(line => exec(line, columns, options))
1344 .join('\n');
1345}
1346
1347const originalWrite = Symbol("webpackbarWrite");
1348class LogUpdate {
1349 constructor() {
1350 this.prevLineCount = 0;
1351 this.listening = false;
1352 this.extraLines = "";
1353 this._onData = this._onData.bind(this);
1354 this._streams = [process.stdout, process.stderr];
1355 }
1356 render(lines) {
1357 this.listen();
1358 const wrappedLines = wrapAnsi(lines, this.columns, {
1359 trim: false,
1360 hard: true,
1361 wordWrap: false
1362 });
1363 const data = ansiEscapes.eraseLines(this.prevLineCount) + wrappedLines + "\n" + this.extraLines;
1364 this.write(data);
1365 const _lines = data.split("\n");
1366 this.prevLineCount = _lines.length;
1367 }
1368 get columns() {
1369 return (process.stderr.columns || 80) - 2;
1370 }
1371 write(data) {
1372 const stream = process.stderr;
1373 if (stream.write[originalWrite]) {
1374 stream.write[originalWrite].call(stream, data, "utf-8");
1375 } else {
1376 stream.write(data, "utf-8");
1377 }
1378 }
1379 clear() {
1380 this.done();
1381 this.write(ansiEscapes.eraseLines(this.prevLineCount));
1382 }
1383 done() {
1384 this.stopListen();
1385 this.prevLineCount = 0;
1386 this.extraLines = "";
1387 }
1388 _onData(data) {
1389 const str = String(data);
1390 const lines = str.split("\n").length - 1;
1391 if (lines > 0) {
1392 this.prevLineCount += lines;
1393 this.extraLines += data;
1394 }
1395 }
1396 listen() {
1397 if (this.listening) {
1398 return;
1399 }
1400 for (const stream of this._streams) {
1401 if (stream.write[originalWrite]) {
1402 continue;
1403 }
1404 const write = (data, ...args) => {
1405 if (!stream.write[originalWrite]) {
1406 return stream.write(data, ...args);
1407 }
1408 this._onData(data);
1409 return stream.write[originalWrite].call(stream, data, ...args);
1410 };
1411 write[originalWrite] = stream.write;
1412 stream.write = write;
1413 }
1414 this.listening = true;
1415 }
1416 stopListen() {
1417 for (const stream of this._streams) {
1418 if (stream.write[originalWrite]) {
1419 stream.write = stream.write[originalWrite];
1420 }
1421 }
1422 this.listening = false;
1423 }
1424}
1425
1426const logUpdate = new LogUpdate();
1427let lastRender = Date.now();
1428class FancyReporter {
1429 allDone() {
1430 logUpdate.done();
1431 }
1432 done(context) {
1433 this._renderStates(context.statesArray);
1434 if (context.hasErrors) {
1435 logUpdate.done();
1436 }
1437 }
1438 progress(context) {
1439 if (Date.now() - lastRender > 50) {
1440 this._renderStates(context.statesArray);
1441 }
1442 }
1443 _renderStates(statesArray) {
1444 lastRender = Date.now();
1445 const renderedStates = statesArray.map((c) => this._renderState(c)).join("\n\n");
1446 logUpdate.render("\n" + renderedStates + "\n");
1447 }
1448 _renderState(state) {
1449 const color = colorize(state.color);
1450 let line1;
1451 let line2;
1452 if (state.progress >= 0 && state.progress < 100) {
1453 line1 = [
1454 color(BULLET),
1455 color(state.name),
1456 renderBar(state.progress, state.color),
1457 state.message,
1458 `(${state.progress || 0}%)`,
1459 chalk.grey(state.details[0] || ""),
1460 chalk.grey(state.details[1] || "")
1461 ].join(" ");
1462 line2 = state.request ? " " + chalk.grey(ellipsisLeft(formatRequest(state.request), logUpdate.columns)) : "";
1463 } else {
1464 let icon = " ";
1465 if (state.hasErrors) {
1466 icon = CROSS;
1467 } else if (state.progress === 100) {
1468 icon = TICK;
1469 } else if (state.progress === -1) {
1470 icon = CIRCLE_OPEN;
1471 }
1472 line1 = color(`${icon} ${state.name}`);
1473 line2 = chalk.grey(" " + state.message);
1474 }
1475 return line1 + "\n" + line2;
1476 }
1477}
1478
1479class SimpleReporter {
1480 start(context) {
1481 consola.info(`Compiling ${context.state.name}`);
1482 }
1483 change(context, { shortPath }) {
1484 consola.debug(`${shortPath} changed.`, `Rebuilding ${context.state.name}`);
1485 }
1486 done(context) {
1487 const { hasError, message, name } = context.state;
1488 consola[hasError ? "error" : "success"](`${name}: ${message}`);
1489 }
1490}
1491
1492const DB = {
1493 loader: {
1494 get: (loader) => startCase(loader)
1495 },
1496 ext: {
1497 get: (ext) => `${ext} files`,
1498 vue: "Vue Single File components",
1499 js: "JavaScript files",
1500 sass: "SASS files",
1501 scss: "SASS files",
1502 unknown: "Unknown files"
1503 }
1504};
1505function getDescription(category, keyword) {
1506 if (!DB[category]) {
1507 return startCase(keyword);
1508 }
1509 if (DB[category][keyword]) {
1510 return DB[category][keyword];
1511 }
1512 if (DB[category].get) {
1513 return DB[category].get(keyword);
1514 }
1515 return "-";
1516}
1517
1518function formatStats(allStats) {
1519 const lines = [];
1520 Object.keys(allStats).forEach((category) => {
1521 const stats = allStats[category];
1522 lines.push(`> Stats by ${chalk.bold(startCase(category))}`);
1523 let totalRequests = 0;
1524 const totalTime = [0, 0];
1525 const data = [
1526 [startCase(category), "Requests", "Time", "Time/Request", "Description"]
1527 ];
1528 Object.keys(stats).forEach((item) => {
1529 const stat = stats[item];
1530 totalRequests += stat.count || 0;
1531 const description = getDescription(category, item);
1532 totalTime[0] += stat.time[0];
1533 totalTime[1] += stat.time[1];
1534 const avgTime = [stat.time[0] / stat.count, stat.time[1] / stat.count];
1535 data.push([
1536 item,
1537 stat.count || "-",
1538 prettyTime(stat.time),
1539 prettyTime(avgTime),
1540 description
1541 ]);
1542 });
1543 data.push(["Total", totalRequests, prettyTime(totalTime), "", ""]);
1544 lines.push(createTable(data));
1545 });
1546 return `${lines.join("\n\n")}
1547`;
1548}
1549
1550class Profiler {
1551 constructor() {
1552 this.requests = [];
1553 }
1554 onRequest(request) {
1555 if (!request) {
1556 return;
1557 }
1558 if (this.requests.length) {
1559 const lastReq = this.requests[this.requests.length - 1];
1560 if (lastReq.start) {
1561 lastReq.time = process.hrtime(lastReq.start);
1562 delete lastReq.start;
1563 }
1564 }
1565 if (!request.file || !request.loaders.length) {
1566 return;
1567 }
1568 this.requests.push({
1569 request,
1570 start: process.hrtime()
1571 });
1572 }
1573 getStats() {
1574 const loaderStats = {};
1575 const extStats = {};
1576 const getStat = (stats, name) => {
1577 if (!stats[name]) {
1578 stats[name] = {
1579 count: 0,
1580 time: [0, 0]
1581 };
1582 }
1583 return stats[name];
1584 };
1585 const addToStat = (stats, name, count, time) => {
1586 const stat = getStat(stats, name);
1587 stat.count += count;
1588 stat.time[0] += time[0];
1589 stat.time[1] += time[1];
1590 };
1591 this.requests.forEach(({ request, time = [0, 0] }) => {
1592 request.loaders.forEach((loader) => {
1593 addToStat(loaderStats, loader, 1, time);
1594 });
1595 const ext = request.file && path.extname(request.file).substr(1);
1596 addToStat(extStats, ext && ext.length ? ext : "unknown", 1, time);
1597 });
1598 return {
1599 ext: extStats,
1600 loader: loaderStats
1601 };
1602 }
1603 getFormattedStats() {
1604 return formatStats(this.getStats());
1605 }
1606}
1607
1608class ProfileReporter {
1609 progress(context) {
1610 if (!context.state.profiler) {
1611 context.state.profiler = new Profiler();
1612 }
1613 context.state.profiler.onRequest(context.state.request);
1614 }
1615 done(context) {
1616 if (context.state.profiler) {
1617 context.state.profile = context.state.profiler.getFormattedStats();
1618 delete context.state.profiler;
1619 }
1620 }
1621 allDone(context) {
1622 let str = "";
1623 for (const state of context.statesArray) {
1624 const color = colorize(state.color);
1625 if (state.profile) {
1626 str += color(`
1627Profile results for ${chalk.bold(state.name)}
1628`) + `
1629${state.profile}
1630`;
1631 delete state.profile;
1632 }
1633 }
1634 process.stderr.write(str);
1635 }
1636}
1637
1638class StatsReporter {
1639 constructor(options) {
1640 this.options = Object.assign({
1641 chunks: false,
1642 children: false,
1643 modules: false,
1644 colors: true,
1645 warnings: true,
1646 errors: true
1647 }, options);
1648 }
1649 done(context, { stats }) {
1650 const str = stats.toString(this.options);
1651 if (context.hasErrors) {
1652 process.stderr.write("\n" + str + "\n");
1653 } else {
1654 context.state.statsString = str;
1655 }
1656 }
1657 allDone(context) {
1658 let str = "";
1659 for (const state of context.statesArray) {
1660 if (state.statsString) {
1661 str += "\n" + state.statsString + "\n";
1662 delete state.statsString;
1663 }
1664 }
1665 process.stderr.write(str);
1666 }
1667}
1668
1669const reporters = {
1670 __proto__: null,
1671 fancy: FancyReporter,
1672 basic: SimpleReporter,
1673 profile: ProfileReporter,
1674 stats: StatsReporter
1675};
1676
1677const DEFAULTS = {
1678 name: "webpack",
1679 color: "green",
1680 reporters: isMinimal ? ["basic"] : ["fancy"],
1681 reporter: null
1682};
1683const DEFAULT_STATE = {
1684 start: null,
1685 progress: -1,
1686 done: false,
1687 message: "",
1688 details: [],
1689 request: null,
1690 hasErrors: false
1691};
1692const globalStates = {};
1693class WebpackBarPlugin extends Webpack.ProgressPlugin {
1694 constructor(options) {
1695 super({ activeModules: true });
1696 this.options = Object.assign({}, DEFAULTS, options);
1697 this.handler = (percent, message, ...details) => {
1698 this.updateProgress(percent, message, details);
1699 };
1700 const _reporters = Array.from(this.options.reporters || []).concat(this.options.reporter).filter(Boolean).map((reporter) => {
1701 if (Array.isArray(reporter)) {
1702 return { reporter: reporter[0], options: reporter[1] };
1703 }
1704 if (typeof reporter === "string") {
1705 return { reporter };
1706 }
1707 return { reporter };
1708 });
1709 this.reporters = _reporters.map(({ reporter, options: options2 = {} }) => {
1710 if (typeof reporter === "string") {
1711 if (this.options[reporter] === false) {
1712 return void 0;
1713 }
1714 options2 = { ...this.options[reporter], ...options2 };
1715 reporter = reporters[reporter] || require(reporter);
1716 }
1717 if (typeof reporter === "function") {
1718 try {
1719 reporter = new reporter(options2);
1720 } catch (err) {
1721 reporter = reporter(options2);
1722 }
1723 }
1724 return reporter;
1725 }).filter(Boolean);
1726 }
1727 callReporters(fn, payload = {}) {
1728 for (const reporter of this.reporters) {
1729 if (typeof reporter[fn] === "function") {
1730 try {
1731 reporter[fn](this, payload);
1732 } catch (e) {
1733 process.stdout.write(e.stack + "\n");
1734 }
1735 }
1736 }
1737 }
1738 get hasRunning() {
1739 return objectValues(this.states).some((state) => !state.done);
1740 }
1741 get hasErrors() {
1742 return objectValues(this.states).some((state) => state.hasErrors);
1743 }
1744 get statesArray() {
1745 return objectValues(this.states).sort((s1, s2) => s1.name.localeCompare(s2.name));
1746 }
1747 get states() {
1748 return globalStates;
1749 }
1750 get state() {
1751 return globalStates[this.options.name];
1752 }
1753 _ensureState() {
1754 if (!this.states[this.options.name]) {
1755 this.states[this.options.name] = {
1756 ...DEFAULT_STATE,
1757 color: this.options.color,
1758 name: startCase(this.options.name)
1759 };
1760 }
1761 }
1762 apply(compiler) {
1763 if (compiler.webpackbar) {
1764 return;
1765 }
1766 compiler.webpackbar = this;
1767 super.apply(compiler);
1768 hook(compiler, "afterPlugins", () => {
1769 this._ensureState();
1770 });
1771 hook(compiler, "compile", () => {
1772 this._ensureState();
1773 Object.assign(this.state, {
1774 ...DEFAULT_STATE,
1775 start: process.hrtime()
1776 });
1777 this.callReporters("start");
1778 });
1779 hook(compiler, "invalid", (fileName, changeTime) => {
1780 this._ensureState();
1781 this.callReporters("change", {
1782 path: fileName,
1783 shortPath: shortenPath(fileName),
1784 time: changeTime
1785 });
1786 });
1787 hook(compiler, "done", (stats) => {
1788 this._ensureState();
1789 if (this.state.done) {
1790 return;
1791 }
1792 const hasErrors = stats.hasErrors();
1793 const status = hasErrors ? "with some errors" : "successfully";
1794 const time = this.state.start ? " in " + prettyTime(process.hrtime(this.state.start), 2) : "";
1795 Object.assign(this.state, {
1796 ...DEFAULT_STATE,
1797 progress: 100,
1798 done: true,
1799 message: `Compiled ${status}${time}`,
1800 hasErrors
1801 });
1802 this.callReporters("progress");
1803 this.callReporters("done", { stats });
1804 if (!this.hasRunning) {
1805 this.callReporters("beforeAllDone");
1806 this.callReporters("allDone");
1807 this.callReporters("afterAllDone");
1808 }
1809 });
1810 }
1811 updateProgress(percent = 0, message = "", details = []) {
1812 const progress = Math.floor(percent * 100);
1813 const activeModule = details.pop();
1814 Object.assign(this.state, {
1815 progress,
1816 message: message || "",
1817 details,
1818 request: parseRequest(activeModule)
1819 });
1820 this.callReporters("progress");
1821 }
1822}
1823
1824export { WebpackBarPlugin as default };
1825
\No newline at end of file