UNPKG

7.15 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const chalk_1 = require("chalk");
4const cliTruncate = require("cli-truncate");
5const elegantSpinner = require("elegant-spinner");
6const figures = require("figures");
7const indentString = require("indent-string");
8const logSymbols = require("log-symbols");
9const logUpdate = require("log-update");
10const stringWidth = require("string-width");
11const stripAnsi = require("strip-ansi");
12const pointer = chalk_1.default.yellow(figures.pointer);
13const skipped = chalk_1.default.yellow(figures.arrowDown);
14const isDefined = x => x !== null && x !== undefined;
15function getSymbol(task, options) {
16 if (!task.spinner) {
17 task.spinner = elegantSpinner();
18 }
19 if (task.isPending()) {
20 return options.showSubtasks !== false && task.subtasks.length > 0 ? pointer : chalk_1.default.yellow(task.spinner());
21 }
22 if (task.isCompleted()) {
23 return logSymbols.success;
24 }
25 if (task.hasFailed()) {
26 return task.subtasks.length > 0 ? pointer : logSymbols.error;
27 }
28 if (task.isSkipped()) {
29 return skipped;
30 }
31 return '';
32}
33function getBranchStatus(porcelainLines) {
34 const ret = {
35 currentBranch: 'Unknown',
36 };
37 const branchLine = porcelainLines.find(str => str.startsWith('##'));
38 const currentBranchRE = /## (.+?)\.\.\./gi;
39 const upstreamRE = /\[(.+)\]$/gi;
40 const currentBranchMatch = currentBranchRE.exec(branchLine);
41 const upstreamMatch = upstreamRE.exec(branchLine);
42 if (currentBranchMatch) {
43 let currentBranch = currentBranchMatch[1];
44 if (currentBranch === 'master') {
45 currentBranch = chalk_1.default.red(currentBranch);
46 }
47 ret.currentBranch = currentBranch;
48 }
49 if (upstreamMatch) {
50 ret.upstreamStatus = upstreamMatch[1];
51 }
52 return ret;
53}
54function getModifications(porcelainLines) {
55 const modificationLines = porcelainLines.filter(str => !str.startsWith('##'));
56 if (modificationLines.length === 0) {
57 return '';
58 }
59 return modificationLines.reduce((acc, str) => {
60 const symb = str.charAt(0);
61 if (!acc.includes(symb)) {
62 acc += symb;
63 }
64 return acc;
65 }, '');
66}
67function getGitStatus(task) {
68 if (!task.output) {
69 return;
70 }
71 const porcelainLines = `${task.output}`.replace('git status:', '')
72 .split('\u0000')
73 .map(str => str.trim())
74 .filter(str => str.length !== 0);
75 if (porcelainLines.length === 0) {
76 return;
77 }
78 return {
79 branchStatus: getBranchStatus(porcelainLines),
80 modifications: getModifications(porcelainLines),
81 };
82}
83function stripHyperlinkANSI(str) {
84 const OSC = '\u001B]';
85 const BEL = '\u0007';
86 const stripper1 = new RegExp(`${OSC}8;;.+?${BEL}(.+)${OSC}8;;${BEL}`, 'i');
87 return str.replace(stripper1, '$1');
88}
89function padANSI(str, length, char, dir = 'start') {
90 const stripped = stripHyperlinkANSI(str);
91 const widthPad = (str.length - stringWidth(stripped)) + length;
92 if (dir === 'end') {
93 return str.padEnd(widthPad, char);
94 }
95 return str.padStart(widthPad, char);
96}
97const renderHelper = (tasks, options, level = 0, isFinal) => {
98 let output = [];
99 for (const task of tasks) {
100 if (task.isEnabled()) {
101 const { showSubtasks, collapse, padTitleLength, } = options;
102 const skipped = task.isSkipped() ? ` ${chalk_1.default.dim('[skipped]')}` : '';
103 const gitStatus = getGitStatus(task);
104 let currentBranch = '';
105 let upstreamStatus = '';
106 if (gitStatus) {
107 currentBranch = chalk_1.default.gray(gitStatus.branchStatus.currentBranch);
108 if (gitStatus.branchStatus.upstreamStatus) {
109 upstreamStatus = chalk_1.default.yellow(gitStatus.branchStatus.upstreamStatus)
110 .replace('behind', figures.arrowDown)
111 .replace('ahead', figures.arrowUp);
112 }
113 }
114 let title = task.title;
115 if (!isFinal) {
116 title = stripHyperlinkANSI(title);
117 }
118 if (gitStatus) {
119 title = gitStatus.modifications.length ? chalk_1.default.yellow(title) : chalk_1.default.gray(title);
120 }
121 if (padTitleLength) {
122 title = padANSI(title, padTitleLength, ' ', 'end');
123 }
124 let lineSymbol;
125 if (gitStatus && gitStatus.modifications.length) {
126 lineSymbol = chalk_1.default `{yellow ${figures.warning}} {red ${gitStatus.modifications}}`;
127 }
128 else {
129 lineSymbol = getSymbol(task, options);
130 }
131 lineSymbol = padANSI(lineSymbol, 4);
132 output.push(indentString(`${lineSymbol} ${title}${skipped} ${currentBranch} ${upstreamStatus}`, level, ' '));
133 if ((task.isPending() || task.isSkipped() || task.hasFailed()) && isDefined(task.output)) {
134 let data = task.output;
135 if (typeof data === 'string') {
136 data = stripAnsi(data.trim().split('\n').filter(Boolean).pop());
137 if (data === '') {
138 data = undefined;
139 }
140 }
141 if (isDefined(data)) {
142 const out = indentString(`${figures.arrowRight} ${data}`, level, ' ');
143 output.push(` ${chalk_1.default.gray(cliTruncate(out, process.stdout.columns - 3))}`);
144 }
145 }
146 if ((task.isPending() || task.hasFailed() || collapse === false) && (task.hasFailed() || showSubtasks !== false) && task.subtasks.length > 0) {
147 output = output.concat(renderHelper(task.subtasks, options, level + 1, isFinal));
148 }
149 }
150 }
151 return output.join('\n');
152};
153const render = (tasks, options, level, isFinal) => {
154 logUpdate(renderHelper(tasks, options, level, isFinal));
155};
156class StatusRenderer {
157 constructor(tasks, options) {
158 this.nonTTY = false;
159 this._tasks = tasks;
160 this._options = Object.assign({ showSubtasks: true, collapse: true, clearOutput: false, padTitleLength: undefined, updateInterval: 100 }, options);
161 }
162 render() {
163 if (this._id) {
164 // Do not render if we are already rendering
165 return;
166 }
167 this._id = setInterval(() => {
168 render(this._tasks, this._options);
169 }, this._options.updateInterval);
170 }
171 end(err) {
172 if (this._id) {
173 clearInterval(this._id);
174 this._id = undefined;
175 }
176 render(this._tasks, this._options, 0, true);
177 if (this._options.clearOutput && err === undefined) {
178 logUpdate.clear();
179 }
180 else {
181 logUpdate.done();
182 }
183 }
184}
185StatusRenderer.nonTTY = false; //static members to shut tsc up
186StatusRenderer.render = () => { }; //static members to shut tsc up
187StatusRenderer.end = () => { }; //static members to shut tsc up
188exports.default = StatusRenderer;