progress.js
5.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ProgressCallback = exports.ProgressBar = void 0;
/*!
* node-progress
* Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
class ProgressBar {
/**
* Initialize a `ProgressBar` with the given `fmt` string and `options` or`total`.
*
* Options:
* - `curr` current completed index
* - `total` total number of ticks to complete
* - `width` the displayed width of the progress bar defaulting to total
* - `stream` the output stream defaulting to stderr
* - `head` head character defaulting to complete character
* - `complete` completion character defaulting to "="
* - `incomplete` incomplete character defaulting to "-"
* - `renderThrottle` minimum time between updates in milliseconds defaulting to 16
* - `callback` optional function to call when the progress bar completes
* - `clear` will clear the progress bar upon termination
*
* Tokens:
* - `:bar` the progress bar itself
* - `:current` current tick number
* - `:total` total ticks
* - `:elapsed` time elapsed in seconds
* - `:percent` completion percentage
* - `:eta` eta in seconds
* - `:rate` rate of ticks per second
*/
constructor(format, options = {}) {
this.format = format;
this.current = 0;
this.total = 0;
this.tokens = null;
this.lastDraw = "";
this.start = 0;
this.complete = false;
this.stream = options.stream || process.stderr;
this.total = options.total;
this.width = options.width || this.total;
this.chars = {
complete: options.complete || "=",
incomplete: options.incomplete || "-",
head: options.head || options.complete || "="
};
}
/**
* "tick" the progress bar with optional `len` and optional `tokens`.
*/
tick(delta) {
this.currentAmount = this.current + delta;
}
set currentAmount(value) {
this.current = value;
if (this.complete) {
return;
}
this.render();
if (this.current >= this.total) {
this.complete = true;
this.terminate();
}
}
render() {
// start time for eta
if (this.start === 0) {
this.start = Date.now();
}
const ratio = Math.min(Math.max(this.current / this.total, 0), 1);
const percent = ratio * 100;
const elapsed = Date.now() - this.start;
const eta = percent === 100 ? 0 : elapsed * (this.total / this.current - 1);
const rate = this.current / (elapsed / 1000);
/* populate the bar template with percentages and timestamps */
let str = this.format.replace(":current", this.current.toString()).replace(":total", this.total.toString()).replace(":elapsed", isNaN(elapsed) ? "0.0" : (elapsed / 1000).toFixed(1)).replace(":eta", isNaN(eta) || !isFinite(eta) ? "0.0" : (eta / 1000).toFixed(1)).replace(":percent", percent.toFixed(0) + "%").replace(":rate", Math.round(rate).toString()); // compute the available space (non-zero) for the bar
let availableSpace = Math.max(0, this.stream.columns - str.replace(":bar", "").length);
if (availableSpace && process.platform === "win32") {
availableSpace -= 1;
}
const width = Math.min(this.width, availableSpace);
const completeLength = Math.round(width * ratio);
let complete = Array(Math.max(0, completeLength + 1)).join(this.chars.complete);
const incomplete = Array(Math.max(0, width - completeLength + 1)).join(this.chars.incomplete);
/* add head to the complete string */
if (completeLength > 0) {
complete = complete.slice(0, -1) + this.chars.head;
}
/* fill in the actual progress bar */
str = str.replace(":bar", complete + incomplete);
/* replace the extra tokens */
if (this.tokens != null) {
for (const key of Object.keys(this.tokens)) {
str = str.replace(`:${key}`, this.tokens[key]);
}
}
if (this.lastDraw !== str) {
this.stream.cursorTo(0);
this.stream.write(str);
this.stream.clearLine(1);
this.lastDraw = str;
}
}
/**
* "update" the progress bar to represent an exact percentage.
* The ratio (between 0 and 1) specified will be multiplied by `total` and
* floored, representing the closest available "tick." For example, if a
* progress bar has a length of 3 and `update(0.5)` is called, the progress
* will be set to 1.
*
* A ratio of 0.5 will attempt to set the progress to halfway.
*/
update(ratio) {
const goal = Math.floor(ratio * this.total);
const delta = goal - this.current;
this.tick(delta);
}
/**
* "interrupt" the progress bar and write a message above it.
*/
interrupt(message) {
// clear the current line
const stream = this.stream;
stream.clearLine(); // move the cursor to the start of the line
stream.cursorTo(0); // write the message text
stream.write(message); // terminate the line after writing the message
stream.write("\n"); // re-display the progress bar with its lastDraw
stream.write(this.lastDraw);
}
}
exports.ProgressBar = ProgressBar;
class ProgressCallback {
constructor(progressBar) {
this.progressBar = progressBar;
this.start = Date.now();
this.nextUpdate = this.start + 1000;
}
update(transferred, total) {
const now = Date.now();
if (now >= this.nextUpdate || transferred >= total) {
this.nextUpdate = now + 1000;
this.progressBar.total = total;
this.progressBar.currentAmount = transferred;
}
}
} exports.ProgressCallback = ProgressCallback;
// __ts-babel@6.0.4
//# sourceMappingURL=progress.js.map