UNPKG

node-console-progress-bar-tqdm

Version:

Progress bar in console for Node.js in the style of TQDM Python library

276 lines 9.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TqdmProgress = exports.Tqdm = exports.tqdm = exports.TqdmSyncResultIterator = exports.TqdmAsyncResultIterator = void 0; const supply_1 = require("./supply"); const term_1 = require("./term"); const utils_1 = require("./utils"); var supply_2 = require("./supply"); Object.defineProperty(exports, "TqdmAsyncResultIterator", { enumerable: true, get: function () { return supply_2.TqdmAsyncResultIterator; } }); Object.defineProperty(exports, "TqdmSyncResultIterator", { enumerable: true, get: function () { return supply_2.TqdmSyncResultIterator; } }); const defaultOptions = { description: '', maxColWidth: -1, progressBraces: ['|', '|'], progressSymbol: '█', progressColor: '', unit: 'it', unitScale: false, initial: 0, total: -1, step: 1, stream: process.stderr, minInterval: 50, forceTerminal: false, }; function tqdm(input, opts = {}) { return new Tqdm(input, opts); } exports.tqdm = tqdm; class Tqdm { input; iterator; progress; constructor(input, options = {}) { this.input = input; if (typeof this.input == 'number') { this.iterator = new supply_1.TqdmNumericIterator(this.input); } else if ((0, utils_1.isIterable)(this.input)) { this.iterator = this.input[Symbol.iterator](); } else if ((0, utils_1.isAsyncIterable)(this.input)) { this.iterator = this.input[Symbol.asyncIterator](); } else if ((0, utils_1.isIterator)(this.input)) { this.iterator = this.input; } else { throw new Error('Unknown TQDM input type'); } if (options.total === undefined || options.total < 0) { if ((0, utils_1.hasLength)(this.input)) { options.total = this.input.length; } else if (typeof this.input == 'number') { options.total = this.input; } } this.progress = new TqdmProgress(options); this.progress.render(); } [Symbol.iterator]() { return new supply_1.TqdmSyncResultIterator(this); } [Symbol.asyncIterator]() { return new supply_1.TqdmAsyncResultIterator(this); } nextSync() { const res = this.iterator.next(); if (res instanceof Promise) { throw new Error('Async value in sync iterator'); } if (res.done) { this.progress.close(); } else { this.progress.update(); } return res; } nextAsync() { const pRes = this.iterator.next(); if (!(pRes instanceof Promise)) { throw new Error('Sync value in async iterator'); } return new Promise((resolve, reject) => { pRes.then((res) => { if (res.done) { this.progress.close(); } else { this.progress.update(); } resolve(res); }).catch(reject); }); } } exports.Tqdm = Tqdm; class TqdmProgress { description; unit; maxColWidth; progressLeftBrace; progressRightBrace; progressSymbol; progressColor = ''; progressColorReset = ''; stream; minInterval; total; totalDigits = 0; initial; step; unitScale; unitDelimiter = ''; totalScaled = ''; haveCorrectTotal; startTime = Date.now(); lastRenderTime = 0; timeSpent = 0; position; itCounter = 0; num; static withProgress(fn, options = {}) { const progressBar = new TqdmProgress(options); try { progressBar.render(); return fn(progressBar); } finally { progressBar.close(); } } static async withAsyncProgress(fn, options = {}) { const progressBar = new TqdmProgress(options); try { progressBar.render(); return await fn(progressBar); } finally { progressBar.close(); } } constructor(options) { const fullOptions = { ...defaultOptions, ...options, }; this.description = fullOptions.description; this.unit = (0, utils_1.handleUnit)(fullOptions.unit); this.maxColWidth = fullOptions.maxColWidth; [this.progressLeftBrace, this.progressRightBrace] = fullOptions.progressBraces; this.progressSymbol = fullOptions.progressSymbol; this.stream = new supply_1.TqdmWriteStream(fullOptions.stream, fullOptions.forceTerminal); this.minInterval = fullOptions.minInterval; if (this.stream.isTty) { this.progressColor = (0, term_1.getTermColor)(fullOptions.progressColor); if (this.progressColor) { this.progressColorReset = (0, term_1.getTermColorReset)(); } } this.initial = this.position = fullOptions.initial; this.total = fullOptions.total; this.haveCorrectTotal = isFinite(this.total) && !isNaN(this.total) && this.total > 0; if (this.haveCorrectTotal) { this.totalDigits = Math.trunc(Math.log10(this.total)) + 1; } this.step = fullOptions.step; this.unitScale = fullOptions.unitScale; if (fullOptions.unitScale) { this.num = this.numScale; this.unitDelimiter = ' '; if (this.haveCorrectTotal) { this.totalScaled = (0, utils_1.scaleUnit)(this.total); } } else { this.num = this.numNoScale; } } update(by = this.step) { this.position += by; ++this.itCounter; this.timeSpent = Date.now() - this.startTime; this.render(); } render(force = false) { const now = Date.now(); if (!force && now - this.lastRenderTime < this.minInterval) { return; } this.lastRenderTime = now; const left = this.generateLeft(); const right = this.generateRight(); const progressBar = this.generateProgressBar(left.length + right.length); this.stream.resetLine(); this.stream.write(`${left}${progressBar}${right}`); } close() { this.render(true); this.stream.finalize(); } numScale(x) { return (0, utils_1.scaleUnit)(x); } numNoScale(x) { return x.toString(); } doesPositionFitTotal() { return this.haveCorrectTotal && this.position <= this.total; } generateLeft() { let countStr; if (this.doesPositionFitTotal()) { const percent = Math.round(Math.min(this.position, this.total) * 100 / this.total); countStr = percent == -1 ? '' : `${String(percent).padStart(3, ' ')}% `; } else { const unitKey = utils_1.pluralService.select(this.position); countStr = `${this.num(this.position)}${this.unitDelimiter}${this.unit[unitKey]}`; } const descStr = this.description ? `${this.description}: ` : ''; return ` ${descStr}${countStr}`; } generateRight() { const res = ['']; if (this.doesPositionFitTotal()) { if (this.unitScale) { res.push(`${this.num(this.position)}/${this.totalScaled}`); } else { const countStr = String(this.position).padStart(this.totalDigits, ' '); res.push(`${countStr}/${this.total}`); } } if (this.timeSpent) { const timePerIt = this.timeSpent / this.itCounter; const timePerItStr = (timePerIt / 1000).toFixed(3); const timeSpentStr = (0, utils_1.formatTimeDelta)(this.timeSpent, true); let elapsedTime = ''; if (this.doesPositionFitTotal()) { const elapsedItems = this.step > 0 ? Math.max(0, this.total - this.position) : Math.max(0, this.total - (this.initial - this.position)); elapsedTime = '<' + (0, utils_1.formatTimeDelta)(timePerIt * elapsedItems, true); } res.push(`[${timeSpentStr}${elapsedTime}, ${timePerItStr}s/${this.unit['one']}]`); } if (res.length > 1) { res.push(''); } return res.join(' '); } generateProgressBar(reduceBy) { if (!this.doesPositionFitTotal()) { return ''; } const ttyColumns = this.stream.columns; const baseColumns = this.maxColWidth > 0 ? Math.min(this.maxColWidth, ttyColumns) : ttyColumns; const columns = baseColumns - reduceBy - 2; if (columns < 4) { return ''; } const cnt = Math.trunc(columns * Math.min(this.position, this.total) / this.total); return [ this.progressLeftBrace, this.progressColor, this.progressSymbol.repeat(cnt), ' '.repeat(columns - cnt), this.progressColorReset, this.progressRightBrace, ].join(''); } } exports.TqdmProgress = TqdmProgress; //# sourceMappingURL=index.js.map