UNPKG

ultra-runner

Version:

Smart and beautiful script runner that hijacks any `npm run`, `yarn` and `npx` calls for ultra fast execution

138 lines 5.26 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Terminal = exports.hideCursor = exports.showCursor = void 0; const tslib_1 = require("tslib"); /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const ansi_split_1 = tslib_1.__importDefault(require("ansi-split")); const readline_1 = tslib_1.__importDefault(require("readline")); // eslint-disable-next-line import/default const string_width_1 = tslib_1.__importDefault(require("string-width")); function showCursor(stream = process.stderr) { stream.isTTY && stream.write("\u001B[?25h"); } exports.showCursor = showCursor; function hideCursor(stream = process.stderr) { if (!stream.isTTY) return; ["SIGTERM", "SIGINT"].forEach((event) => process.once(event, () => showCursor(stream))); process.once("exit", () => showCursor(stream)); stream.write("\u001B[?25l"); } exports.hideCursor = hideCursor; class Terminal { constructor(stream = process.stdout, options = { clearScreen: false }) { this.stream = stream; this.options = options; this.lines = []; this.output = ""; this.resized = false; stream.setMaxListeners(50); stream.on("resize", () => (this.resized = true)); hideCursor(stream); if (options.clearScreen) this.clearScreen(); } clearScreen() { readline_1.default.cursorTo(this.stream, 0, 0); readline_1.default.clearScreenDown(this.stream); this.lines = []; } diff(from, to) { if (!from || !to || from.length !== to.length) return; const fromParts = ansi_split_1.default(from); const toParts = ansi_split_1.default(to); let left = 0; let leftP = 0; let leftWidth = 0; let right = 0; if (fromParts.length == toParts.length) { // eslint-disable-next-line unicorn/no-for-loop for (let i = 0; i < toParts.length; i++) { if (fromParts[i] == toParts[i]) { leftP = i + 1; left += toParts[i].length; leftWidth += string_width_1.default(toParts[i]); } else break; } // eslint-disable-next-line unicorn/no-for-loop for (let i = toParts.length - 1; i >= 0; i--) { if (fromParts[i] == toParts[i]) { right += toParts[i].length; } else break; } } else return; // Even idx is a non-ansi string, so add previous ansi string to result if (leftP > 0 && leftP % 2 == 0) { left -= toParts[leftP - 1].length; } return left > 0 || right > 0 ? { left: leftWidth, str: to.slice(left), // FIX: str: to.slice(left, -right + 1), } : undefined; } update(text) { this.output = ""; if (this.resized) { this.lines = []; this.resized = false; if (this.options.clearScreen) { this.clearScreen(); } else { readline_1.default.moveCursor(this.stream, 0, -this.lines.length + 1); readline_1.default.cursorTo(this.stream, 0); readline_1.default.clearScreenDown(this.stream); } } const lines = Array.isArray(text) ? text : text.split("\n"); // Check if we will write the same lines if (lines.length == this.lines.length && lines.every((line, idx) => this.lines[idx] == line)) return this.output; // Move cursor to first line if (this.lines.length) readline_1.default.moveCursor(this.stream, 0, -this.lines.length + 1); // Update existing lines for (let l = 0; l < this.lines.length; l++) { const line = lines[l]; if (line != this.lines[l]) { const diff = this.diff(line, this.lines[l]); if (diff) { readline_1.default.cursorTo(this.stream, diff.left); this.stream.write(diff.str); } else { readline_1.default.cursorTo(this.stream, 0); if (!line || string_width_1.default(line) < string_width_1.default(this.lines[l])) readline_1.default.clearLine(this.stream, 0); if (line) this.stream.write(line); } } if (l < this.lines.length - 1) readline_1.default.moveCursor(this.stream, 0, 1); } // Render remaining lines if (lines.length > this.lines.length) { if (this.lines.length > 0) this.stream.write("\n"); this.stream.write(lines.slice(this.lines.length).join("\n")); } this.lines = lines; } } exports.Terminal = Terminal; //# sourceMappingURL=terminal.js.map