'use strict'; let charm = require('charm')(); charm.pipe(process.stdout); class Progress{ private _barSize: number = 20; private _percent: number = 0; private _percentIncrease: number = 0; private _current: number = 0; private _start: number = 0; private _elapsed: number = 0; private _remaining: number = 0; private _now: number = 0; private _cycle: number = 0; private _padding: string; private _pattern: string = 'Progress: {bar} | Elapsed: {elapsed} | {percent}'; private _regex = /(.*?){(.*?)}/g; /** * Creates new progress object * @param options * @returns {Progress} */ public static create(options: ProgressOptions): Progress{ return new Progress(options.total, options.pattern, options.textColor, options.title, options.updateFrequency) } /** * * @deprecated use Progress.create(options: ProgressOptions) */ constructor(private _total: number, pattern?: string, private _textColor?: string, private _title?: string, private _updateFrequency = 0){ this._padding = new Array(300).join(' '); if(pattern) this._pattern = pattern; //this._padding = new Array(300).join('▒'); this._percentIncrease = 100/_total; this.start(); } /** * Updates progress */ public update(): void{ this._now = new Date().getTime(); if(this._current == this._total){ return; }else if(this._current >= this._total - 1){ charm.up(1).erase('line').write("\r"); this._current = (this._total - 1); this.stop(); }else{ this._current++; this._percent += this._percentIncrease; if(!this.skipStep()){ charm.up(1).erase('line').write("\r"); this._elapsed = (this._now - this._start)/1000; this._remaining = (this._elapsed/this._current * (this._total - this._current)); this.write(); } } } /** * Finishes progress */ public done(): void{ this._now = new Date().getTime(); charm.up(1).erase('line').write("\r"); this._current = (this._total - 1); this.stop(); } private start = (): void =>{ charm.erase('line').write("\r"); this._start = new Date().getTime(); this._now = new Date().getTime(); this._cycle = this._start; this.renderTitle(); this.write(); }; private stop = (): void =>{ this._current++; this._percent = 100; this._elapsed = (this._now - this._start)/1000; this._remaining = 0; this.write(); }; private write = (): void =>{ let match; while (match = this._regex.exec(this._pattern)) { this.renderText(match[1]); if(match[2].indexOf('.') == -1){ this.renderPattern(match[2], match[2]); }else{ let tokens = match[2].split('.'); if(tokens.length == 4 && tokens[0] == 'bar'){ this.renderBar(tokens[1], tokens[2], tokens[3]) }else if(tokens.length == 2){ this.renderPattern(match[2], tokens[0], tokens[1]); } } } charm.write("\r\n"); }; private renderElapsed = (color?: string): void => { this.renderItem(`${this._elapsed.toFixed(1)}s`, color); }; private renderRemaining = (color?: string): void => { this.renderItem(`${this._remaining.toFixed(1)}s`, color); }; private renderMemory = (color?: string): void => { this.renderItem(`${(process.memoryUsage().rss/1024/1024).toFixed(1)}M`, color); }; private renderPercent = (color?: string): void => { this.renderItem(`${this._percent.toFixed(0)}%`, color); }; private renderCurrent = (color?: string): void => { this.renderItem(this._current.toString(), color); }; private renderTotal = (color?: string): void => { this.renderItem(this._total.toString(), color); }; private renderBar = (colorRemaining: string = 'white', colorDone: string = 'green', size?: number): void => { if(size && size !== this._barSize) this._barSize = size; charm.foreground(colorDone).background(colorDone); let done = Math.ceil(((this._current / this._total) * this._barSize)); charm.write(this._padding.substr(0, done)); charm.foreground(colorRemaining).background(colorRemaining); charm.write(this._padding.substr(0, this._barSize - done)); charm.display('reset'); }; private _patternMapping: any = { 'bar': this.renderBar, 'elapsed': this.renderElapsed, 'remaining': this.renderRemaining, 'memory': this.renderMemory, 'percent': this.renderPercent, 'current': this.renderCurrent, 'total': this.renderTotal, }; private renderPattern = (pattern: string, item: string, color?: string): void => { let renderer = this._patternMapping[item]; if(renderer) { renderer(color); }else{ charm.write(pattern); } }; private renderItem = (item: string, color?: string): void => { if(color){ charm.foreground(color).write(item).display('reset'); }else{ charm.write(item); } }; private renderText = (text: string): void =>{ if(this._textColor){ charm.display('bright').foreground(this._textColor).write(text).display('reset'); }else{ charm.display('bright').write(text).display('reset'); } }; private renderTitle = (): void => { if(this._title && this._title !== '') { charm.display('bright').write(this._title).display('reset'); charm.write("\n"); } }; private skipStep = (): boolean =>{ if(this._updateFrequency == 0) return false; let elapsed = this._now - this._cycle; if(elapsed < this._updateFrequency){ return true; }else{ this._cycle = this._now; return false; } } } //export = Progress export {Progress}; module.exports = Progress;