UNPKG

turbowatch

Version:

Extremely fast file change detector and task orchestrator for Node.js.

109 lines 4.51 kB
"use strict"; // cspell:words nothrow var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createSpawn = void 0; const Logger_1 = require("./Logger"); const chalk_1 = __importDefault(require("chalk")); const randomcolor_1 = __importDefault(require("randomcolor")); const throttle_debounce_1 = require("throttle-debounce"); const zx_1 = require("zx"); const log = Logger_1.Logger.child({ namespace: 'createSpawn', }); const prefixLines = (subject, prefix) => { const response = []; for (const fragment of subject.split('\n')) { response.push(prefix + fragment); } return response.join('\n'); }; const createSpawn = (taskId, { cwd = process.cwd(), abortSignal, throttleOutput, } = {}) => { let stdoutBuffer = []; let stderrBuffer = []; const flush = () => { if (stdoutBuffer.length) { // eslint-disable-next-line no-console console.log(stdoutBuffer.join('\n')); } if (stderrBuffer.length) { // eslint-disable-next-line no-console console.error(stderrBuffer.join('\n')); } stdoutBuffer = []; stderrBuffer = []; }; const output = (0, throttle_debounce_1.throttle)(throttleOutput === null || throttleOutput === void 0 ? void 0 : throttleOutput.delay, () => { flush(); }, { noLeading: true, }); const colorText = chalk_1.default.hex((0, randomcolor_1.default)({ luminosity: 'dark' })); return async (pieces, ...args) => { zx_1.$.cwd = cwd; // eslint-disable-next-line promise/prefer-await-to-then const processPromise = (0, zx_1.$)(pieces, ...args) .nothrow() .quiet(); (async () => { for await (const chunk of processPromise.stdout) { // TODO we might want to make this configurable (e.g. behind a debug flag), because these logs might provide valuable context when debugging shutdown logic. if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) { return; } const message = prefixLines(chunk.toString().trimEnd(), colorText(taskId) + ' > '); if (throttleOutput === null || throttleOutput === void 0 ? void 0 : throttleOutput.delay) { stdoutBuffer.push(message); output(); } else { // eslint-disable-next-line no-console console.log(message); } } })(); (async () => { for await (const chunk of processPromise.stderr) { // TODO we might want to make this configurable (e.g. behind a debug flag), because these logs might provide valuable context when debugging shutdown logic. if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) { return; } const message = prefixLines(chunk.toString().trimEnd(), colorText(taskId) + ' > '); if (throttleOutput === null || throttleOutput === void 0 ? void 0 : throttleOutput.delay) { stderrBuffer.push(message); output(); } else { // eslint-disable-next-line no-console console.error(message); } } })(); if (abortSignal) { const kill = () => { processPromise.kill(); }; abortSignal.addEventListener('abort', kill, { once: true, }); // eslint-disable-next-line promise/prefer-await-to-then processPromise.finally(() => { abortSignal.removeEventListener('abort', kill); }); } const result = await processPromise; flush(); if (result.exitCode === 0) { return result; } if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) { return result; } log.error('task %s exited with an error', taskId); throw new Error('Program exited with code ' + result.exitCode + '.'); }; }; exports.createSpawn = createSpawn; //# sourceMappingURL=createSpawn.js.map