UNPKG

@ayonli/jsext

Version:

A JavaScript extension package for building strong and modern applications.

116 lines (113 loc) 3.79 kB
import bytes, { equals } from '../../bytes.js'; import '../../string/constants.js'; import '../../env.js'; import '../../external/event-target-polyfill/index.js'; import '../../path.js'; import { ControlKeys, ControlSequences } from '../../cli/constants.js'; import { writeStdoutSync, getWindowSize, stringWidth } from '../../cli/common.js'; const { CTRL_C, ESC, LF } = ControlKeys; const { CLR } = ControlSequences; const ongoingIndicators = [ " ", "= ", "== ", "=== ", " === ", " === ", " ===", " ==", " =", " ", ]; async function handleTerminalProgress(message, fn, options) { const { signal, abort, listenForAbort } = options; let lastMessage = message; let lastPosition = 0; let lastPercent = undefined; const renderSimpleBar = (position = undefined) => { position !== null && position !== void 0 ? position : (position = lastPosition++); const ongoingIndicator = ongoingIndicators[position]; writeStdoutSync(CLR); writeStdoutSync(bytes(`${lastMessage} [${ongoingIndicator}]`)); if (lastPosition === ongoingIndicators.length) { lastPosition = 0; } }; const renderPercentageBar = (percent) => { const { width } = getWindowSize(); const percentage = percent + "%"; const barWidth = width - stringWidth(lastMessage) - percentage.length - 5; const filled = "".padStart(Math.floor(barWidth * percent / 100), "#"); const empty = "".padStart(barWidth - filled.length, "-"); writeStdoutSync(CLR); writeStdoutSync(bytes(`${lastMessage} [${filled}${empty}] ${percentage}`)); }; renderSimpleBar(); const waitingTimer = setInterval(renderSimpleBar, 200); const set = (state) => { if (signal.aborted) { return; } if (state.message) { lastMessage = state.message; } if (state.percent !== undefined) { lastPercent = state.percent; } if (lastPercent !== undefined) { renderPercentageBar(lastPercent); clearInterval(waitingTimer); } else if (state.message) { renderSimpleBar(lastPosition); } }; const nodeReader = typeof Deno === "object" ? null : (buf) => { if (equals(buf, ESC) || equals(buf, CTRL_C)) { abort === null || abort === void 0 ? void 0 : abort(); } }; const denoReader = typeof Deno === "object" ? Deno.stdin.readable.getReader() : null; if (abort) { if (nodeReader) { process.stdin.on("data", nodeReader); } else if (denoReader) { (async () => { while (true) { try { const { done, value } = await denoReader.read(); if (done || equals(value, ESC) || equals(value, CTRL_C)) { signal.aborted || abort(); break; } } catch (_a) { signal.aborted || abort(); break; } } denoReader.releaseLock(); })(); } } let job = fn(set, signal); if (listenForAbort) { job = Promise.race([job, listenForAbort()]); } try { return await job; } finally { writeStdoutSync(LF); clearInterval(waitingTimer); if (nodeReader) { process.stdin.off("data", nodeReader); } else if (denoReader) { denoReader.releaseLock(); } } } export { handleTerminalProgress }; //# sourceMappingURL=progress.js.map