zcatalyst-cli
Version:
Command Line Tool for CATALYST
218 lines (217 loc) • 8.63 kB
JavaScript
'use strict';
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ansi_colors_1 = __importDefault(require("ansi-colors"));
const cli_cursor_1 = __importDefault(require("cli-cursor"));
const readline_1 = require("readline");
const strip_ansi_1 = __importDefault(require("strip-ansi"));
const index_1 = __importDefault(require("../error/index"));
const utils_js_1 = require("../util_modules/logger/utils.js");
const shell_js_1 = require("../util_modules/shell.js");
const spinners_json_1 = require("./spinners.json");
const utils_1 = require("./utils");
const logger_1 = require("../util_modules/logger");
const env_1 = require("../util_modules/env");
class Throbber {
constructor(options) {
this.options = options;
this.spinners = {};
this.isCursorHidden = false;
this.currentInterval = null;
this.stream = env_1.isVsCode ? logger_1.LogStreamFactory.getStream() : process.stderr;
this.lineCount = 0;
this.currentFrameIndex = 0;
this.spin =
!this.options.disableSpins &&
!process.env.CI &&
((process.stderr && process.stderr.isTTY) || env_1.isVsCode);
this.bindSigint();
Throbber.instance = this;
}
static getInstance(options = {}) {
if (Throbber.instance !== undefined) {
return Throbber.instance;
}
const instance = new Throbber(Object.assign({ spinnerColor: 'cyanBright', spinner: (0, shell_js_1.supportsUnicode)() ? spinners_json_1.dots : spinners_json_1.dashes, disableSpins: false, status: 'spinning', succeedPrefix: utils_js_1.CHAR.success, failPrefix: utils_js_1.CHAR.error }, options));
Throbber.instance = instance;
return instance;
}
pick(name) {
return this.spinners[name];
}
add(name, options = {}) {
if (!options.text) {
options.text = name;
}
const spinnerProperties = Object.assign(Object.assign({}, this.options), options);
if (this.spin) {
this.spinners[name] = spinnerProperties;
}
this.updateSpinnerState();
return spinnerProperties;
}
update(name, options = {}) {
const { status } = options;
this.setSpinnerProperties(name, options, status);
this.updateSpinnerState();
return this.spinners[name];
}
succeed(name, options = {}) {
this.setSpinnerProperties(name, options, 'succeed');
this.updateSpinnerState();
return this.spinners[name];
}
fail(name, options = {}) {
this.setSpinnerProperties(name, options, 'fail');
this.updateSpinnerState();
return this.spinners[name];
}
remove(name) {
const spinner = this.spinners[name];
delete this.spinners[name];
this.checkIfActiveSpinners();
return spinner;
}
stopAll(newStatus = 'stopped') {
Object.keys(this.spinners).forEach((name) => {
const { status: currentStatus } = this.spinners[name];
if (currentStatus !== 'fail' &&
currentStatus !== 'succeed' &&
currentStatus !== 'non-spinnable') {
if (newStatus === 'succeed' || newStatus === 'fail') {
this.spinners[name].status = newStatus;
this.spinners[name].color =
newStatus === 'succeed'
? this.options.succeedColor
: this.options.failColor;
}
else {
this.spinners[name].status = 'stopped';
this.spinners[name].color = 'grey';
}
}
});
this.checkIfActiveSpinners();
return this.spinners;
}
hasActiveSpinners() {
return !!Object.values(this.spinners).find(({ status }) => status === 'spinning');
}
setSpinnerProperties(name, options, status = 'spinning') {
if (!this.spin) {
return;
}
if (!this.spinners[name]) {
throw new index_1.default(`No spinner initialized with name ${name}`);
}
status = status || 'spinning';
this.spinners[name] = Object.assign(Object.assign(Object.assign({}, this.spinners[name]), options), { status });
}
updateSpinnerState() {
if (this.spin) {
if (this.currentInterval !== null) {
clearInterval(this.currentInterval);
}
this.currentInterval = this.loopStream();
if (!this.isCursorHidden) {
cli_cursor_1.default.hide();
}
this.isCursorHidden = true;
this.checkIfActiveSpinners();
}
else {
this.setRawStreamOutput();
}
}
loopStream() {
if (this.options.spinner === undefined) {
throw new index_1.default('LoopStream must be called only with valid spinner object', {
exit: 2
});
}
const { frames, interval } = this.options.spinner;
return setInterval(() => {
this.setStreamOutput(frames[this.currentFrameIndex]);
this.currentFrameIndex =
this.currentFrameIndex === frames.length - 1 ? 0 : ++this.currentFrameIndex;
}, interval);
}
setStreamOutput(frame = '') {
let output = '';
const linesLength = [];
const hasActiveSpinners = this.hasActiveSpinners();
Object.values(this.spinners).map(({ text, status, color, spinnerColor, succeedPrefix, failPrefix, indent }) => {
text = text === undefined ? '' : text;
let line;
let prefixLength = indent || 0;
if (status === 'spinning') {
prefixLength += frame.length + 1;
text = (0, utils_1.breakText)(text, prefixLength);
line = `${ansi_colors_1.default[spinnerColor](frame)} ${color ? ansi_colors_1.default[color](text) : text}`;
}
else {
if (status === 'succeed') {
prefixLength += (0, strip_ansi_1.default)(succeedPrefix).length + 1;
if (hasActiveSpinners) {
text = (0, utils_1.breakText)(text, prefixLength);
}
line = `${succeedPrefix} ${text}`;
}
else if (status === 'fail') {
prefixLength += (0, strip_ansi_1.default)(failPrefix).length + 1;
if (hasActiveSpinners) {
text = (0, utils_1.breakText)(text, prefixLength);
}
line = `${failPrefix} ${text}`;
}
else {
if (hasActiveSpinners) {
text = (0, utils_1.breakText)(text, prefixLength);
}
line = color ? ansi_colors_1.default[color](text) : text;
}
}
linesLength.push(...(0, utils_1.getLinesLength)(text, prefixLength));
output += indent ? `${' '.repeat(indent)}${line}\n` : `${line}\n`;
});
if (!hasActiveSpinners) {
(0, readline_1.clearScreenDown)(this.stream);
}
(0, utils_1.writeStream)(this.stream, output, linesLength);
if (hasActiveSpinners) {
(0, utils_1.cleanStream)(this.stream, linesLength);
}
this.lineCount = linesLength.length;
}
setRawStreamOutput() {
Object.values(this.spinners).forEach((i) => {
process.stderr.write(`- ${i.text}\n`);
});
}
checkIfActiveSpinners() {
if (!this.hasActiveSpinners()) {
if (this.spin) {
this.setStreamOutput();
(0, readline_1.moveCursor)(this.stream, 0, this.lineCount);
if (this.currentInterval !== null) {
clearInterval(this.currentInterval);
}
this.isCursorHidden = false;
cli_cursor_1.default.show();
}
this.spinners = {};
}
}
bindSigint() {
process.prependOnceListener('SIGINT', () => {
if (!this.hasActiveSpinners()) {
return;
}
cli_cursor_1.default.show();
(0, readline_1.moveCursor)(process.stderr, 0, this.lineCount);
});
}
}
exports.default = Throbber;