chore: 更新学生档案数据
This commit is contained in:
143
node_modules/@puppeteer/browsers/lib/ProgressBar.js
generated
vendored
Normal file
143
node_modules/@puppeteer/browsers/lib/ProgressBar.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
// Module-level active session. Concurrent bars share a session; a new session
|
||||
// starts whenever no bar is currently active (or the stream changes).
|
||||
let activeBar = null;
|
||||
/**
|
||||
* Manages one or more concurrent progress bars on separate terminal lines.
|
||||
* Use {@link ProgressBar.createBarTicker} to add a bar; concurrent calls
|
||||
* automatically share a session so bars don't overwrite each other.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class ProgressBar {
|
||||
#stream;
|
||||
#totalRows = 0;
|
||||
#doneCount = 0;
|
||||
#bars = [];
|
||||
#renderScheduled = false;
|
||||
#lastRenderTime = 0;
|
||||
#allDone = false;
|
||||
constructor(stream) {
|
||||
this.#stream = stream;
|
||||
}
|
||||
/**
|
||||
* Returns a `tick(delta)` function for a new progress bar. If another bar
|
||||
* is already active on the same stream, the new bar appears on the next line
|
||||
* and both update in place. The trailing newline is emitted automatically
|
||||
* once every bar in the session has reached 100%.
|
||||
*/
|
||||
static createBarTicker(title, total, stream = process.stderr) {
|
||||
// Start a fresh session when none is active or the stream changed.
|
||||
if (!activeBar || activeBar.#stream !== stream) {
|
||||
activeBar = new ProgressBar(stream);
|
||||
}
|
||||
return activeBar.#addBar(title, total);
|
||||
}
|
||||
#claimRow() {
|
||||
const row = this.#totalRows++;
|
||||
if (row > 0 && this.#stream.isTTY) {
|
||||
// Cursor is parked at col 0 of the previous bottom row; \n opens the
|
||||
// new line and moves the cursor there, establishing the new bottom row.
|
||||
this.#stream.write('\n');
|
||||
}
|
||||
return row;
|
||||
}
|
||||
#addBar(title, total) {
|
||||
const row = this.#claimRow();
|
||||
this.#bars.push({
|
||||
title,
|
||||
total,
|
||||
downloaded: 0,
|
||||
startTime: 0,
|
||||
lastRendered: '',
|
||||
});
|
||||
let doneNotified = false;
|
||||
return (delta) => {
|
||||
const bar = this.#bars[row];
|
||||
if (bar.startTime === 0) {
|
||||
bar.startTime = Date.now();
|
||||
}
|
||||
bar.downloaded += delta;
|
||||
const isDone = bar.downloaded >= bar.total;
|
||||
if (isDone || Date.now() - this.#lastRenderTime >= 100) {
|
||||
this.#scheduleRender();
|
||||
}
|
||||
if (isDone && !doneNotified) {
|
||||
doneNotified = true;
|
||||
this.#onBarDone();
|
||||
}
|
||||
};
|
||||
}
|
||||
// Defers to a microtask so multiple ticks in the same turn share one render
|
||||
// pass and the cursor only moves once.
|
||||
#scheduleRender() {
|
||||
if (!this.#renderScheduled) {
|
||||
this.#renderScheduled = true;
|
||||
queueMicrotask(() => {
|
||||
this.#renderScheduled = false;
|
||||
this.#lastRenderTime = Date.now();
|
||||
this.#renderAll();
|
||||
});
|
||||
}
|
||||
}
|
||||
#computeRendered(row) {
|
||||
const bar = this.#bars[row];
|
||||
const ratio = Math.min(1, Math.max(0, bar.downloaded / bar.total));
|
||||
const percent = Math.round(ratio * 100);
|
||||
const elapsedMs = bar.startTime > 0 ? Date.now() - bar.startTime : 0;
|
||||
const rate = elapsedMs > 0 ? bar.downloaded / elapsedMs : 0; // bytes/ms
|
||||
const etaSec = rate > 0 ? (bar.total - bar.downloaded) / rate / 1000 : 0;
|
||||
const width = 20;
|
||||
const completeCount = Math.round(width * ratio);
|
||||
const barStr = '='.repeat(completeCount) + ' '.repeat(width - completeCount);
|
||||
const status = ratio >= 1 ? 'unpacking' : `${percent}% ${etaSec.toFixed(1)}s`;
|
||||
return `${bar.title} [${barStr}] ${status} `;
|
||||
}
|
||||
// Invariant: cursor is at col 0 of the bottom row before and after this call.
|
||||
// Single top-down pass: go up to bar 0, render each bar, come back to bottom.
|
||||
#renderAll() {
|
||||
if (!this.#stream.isTTY) {
|
||||
return;
|
||||
}
|
||||
const N = this.#totalRows;
|
||||
if (N === 0) {
|
||||
return;
|
||||
}
|
||||
// Move cursor to top of bar area.
|
||||
if (N > 1) {
|
||||
this.#stream.moveCursor(0, -(N - 1));
|
||||
}
|
||||
for (let row = 0; row < N; row++) {
|
||||
const rendered = this.#computeRendered(row);
|
||||
if (rendered !== this.#bars[row].lastRendered) {
|
||||
this.#stream.cursorTo(0);
|
||||
this.#stream.write(rendered);
|
||||
this.#stream.clearLine(1);
|
||||
this.#bars[row].lastRendered = rendered;
|
||||
}
|
||||
if (row < N - 1) {
|
||||
this.#stream.moveCursor(0, 1);
|
||||
}
|
||||
}
|
||||
// Park cursor at col 0 of the bottom row.
|
||||
this.#stream.cursorTo(0);
|
||||
if (this.#allDone) {
|
||||
activeBar = null;
|
||||
this.#stream.write('\n');
|
||||
}
|
||||
}
|
||||
#onBarDone() {
|
||||
this.#doneCount++;
|
||||
if (this.#doneCount >= this.#totalRows && this.#totalRows > 0) {
|
||||
this.#allDone = true;
|
||||
// Don't emit \n here — the pending render microtask hasn't run yet.
|
||||
// #renderAll() will emit it after the final pass so the cursor is
|
||||
// already past the last bar line before the newline moves it.
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=ProgressBar.js.map
|
||||
Reference in New Issue
Block a user