UNPKG

@boost/core

Version:

Robust pipeline for creating dev tools that separate logic into routines and tasks.

97 lines (96 loc) 3.61 kB
"use strict"; /* eslint-disable no-magic-numbers */ var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const optimal_1 = __importStar(require("optimal")); const common_1 = require("@boost/common"); const terminal_1 = require("@boost/terminal"); const Output_1 = __importDefault(require("../Output")); const STYLES = { bar: ['\u2588', '\u2591'], classic: ['=', '-'], hash: ['#', '-'], pipe: ['|', '-'], square: ['\u25A0', ' '], }; class ProgressOutput extends Output_1.default { constructor() { super(...arguments); this.startTime = 0; this.stopTime = 0; } onStart() { this.concurrent(); } onFirst() { this.startTime = Date.now(); } onLast() { this.stopTime = Date.now(); } toString(state) { const { color, current, style: styleName, template, total, transparent } = optimal_1.default(state, { color: optimal_1.bool(), current: optimal_1.number() .required() .gte(0), style: optimal_1.string('bar').oneOf(Object.keys(STYLES)), template: optimal_1.string('{percent} {bar} {progress}').notEmpty(), total: optimal_1.number() .required() .gt(0), transparent: optimal_1.bool(), }, { name: 'ProgressOutput', }); // Mark as final for convenience if (current >= total) { this.markFinal(); } // Compile our template const progress = Math.min(Math.max(current / total, 0), 1); const percent = Math.floor(progress * 100); const elapsed = Date.now() - this.startTime; const estimated = percent === 100 ? 0 : elapsed * (total / current - 1); const rate = current / (elapsed / 1000); const partialTemplate = template .replace('{progress}', `${current}/${total}`) .replace('{current}', String(current)) .replace('{elapsed}', common_1.formatMs(elapsed)) .replace('{estimated}', common_1.formatMs(estimated)) .replace('{percent}', `${percent.toFixed(0)}%`) .replace('{rate}', String(rate.toFixed(2))) .replace('{total}', String(total)); // Render the progress bar const currentWidth = partialTemplate.replace('{bar}', '').length; const remainingWidth = terminal_1.screen.size().columns - currentWidth; const completed = Math.round(remainingWidth * progress); const [complete, incomplete] = STYLES[styleName]; let bar = [ complete.repeat(Math.max(0, completed)), (transparent ? ' ' : incomplete).repeat(Math.max(0, remainingWidth - completed)), ].join(''); if (color) { if (percent >= 90) { bar = terminal_1.style.green(bar); } else if (percent >= 45) { bar = terminal_1.style.yellow(bar); } else { bar = terminal_1.style.red(bar); } } return partialTemplate.replace('{bar}', bar); } } exports.default = ProgressOutput;