UNPKG

promisify-child-process

Version:

seriously like the best async child process library

141 lines 5.24 kB
import child_process from 'child_process'; function joinChunks(chunks, encoding) { if (!chunks) return undefined; const buffer = Buffer.concat(chunks); return encoding && encoding !== 'buffer' ? buffer.toString(encoding) : buffer; } export function promisifyChildProcess(child, options) { var _promise$finally; const promise = new Promise((resolve, reject) => { var _child$stdout, _child$stderr; const encoding = options === null || options === void 0 ? void 0 : options.encoding; const killSignal = options === null || options === void 0 ? void 0 : options.killSignal; const captureStdio = encoding != null || (options === null || options === void 0 ? void 0 : options.maxBuffer) != null; const maxBuffer = (options === null || options === void 0 ? void 0 : options.maxBuffer) ?? 1024 * 1024; let bufferSize = 0; let error; const stdoutChunks = captureStdio && child.stdout ? [] : undefined; const stderrChunks = captureStdio && child.stderr ? [] : undefined; const capture = chunks => data => { if (typeof data === 'string') data = Buffer.from(data); const remaining = Math.max(0, maxBuffer - bufferSize); bufferSize += Math.min(remaining, data.length); if (data.length > remaining) { error = new Error('maxBuffer exceeded'); child.kill(killSignal ?? 'SIGTERM'); data = data.subarray(0, remaining); } chunks.push(data); }; const captureStdout = stdoutChunks ? capture(stdoutChunks) : undefined; const captureStderr = stderrChunks ? capture(stderrChunks) : undefined; if (captureStdout) (_child$stdout = child.stdout) === null || _child$stdout === void 0 || _child$stdout.on('data', captureStdout); if (captureStderr) (_child$stderr = child.stderr) === null || _child$stderr === void 0 || _child$stderr.on('data', captureStderr); function onError(err) { error = err; done(); } child.on('error', onError); function done(code = null, signal = null) { var _child$stdout2, _child$stderr2; child.removeListener('error', onError); child.removeListener('close', done); if (captureStdout) (_child$stdout2 = child.stdout) === null || _child$stdout2 === void 0 || _child$stdout2.removeListener('data', captureStdout); if (captureStderr) (_child$stderr2 = child.stderr) === null || _child$stderr2 === void 0 || _child$stderr2.removeListener('data', captureStderr); const stdout = joinChunks(stdoutChunks, encoding); const stderr = joinChunks(stderrChunks, encoding); if (error || code != null && code != 0 || signal != null) { reject(Object.assign(error || new Error(signal != null ? `Process was killed with ${signal}` : `Process exited with code ${code}`), { code, signal, killed: signal != null, stdout, stderr })); } else { resolve({ stderr, stdout, code, signal, killed: false }); } } child.on('close', done); }); return Object.create(child, { then: { value: promise.then.bind(promise) }, catch: { value: promise.catch.bind(promise) }, // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition finally: { value: (_promise$finally = promise.finally) === null || _promise$finally === void 0 ? void 0 : _promise$finally.bind(promise) } }); } function isArray(t) { return Array.isArray(t); } export function spawn(command, args, options) { if (!isArray(args)) { options = args; args = []; } return promisifyChildProcess(child_process.spawn(command, args, options), options); } export function fork(module, args, options) { if (!isArray(args)) { options = args; args = []; } return promisifyChildProcess(child_process.fork(module, args, options), options); } function promisifyExecMethod(method) { return (...args) => { var _promise$finally2; let child; const promise = new Promise((resolve, reject) => { child = method(...args, (err, stdout, stderr) => { if (err) { reject(Object.assign(err, { stdout, stderr })); } else { resolve({ code: 0, signal: null, killed: false, stdout: stdout, stderr: stderr }); } }); }); if (!child) { throw new Error('unexpected error: child has not been initialized'); } return Object.create(child, { then: { value: promise.then.bind(promise) }, catch: { value: promise.catch.bind(promise) }, // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition finally: { value: (_promise$finally2 = promise.finally) === null || _promise$finally2 === void 0 ? void 0 : _promise$finally2.bind(promise) } }); }; } export const exec = promisifyExecMethod(child_process.exec); export const execFile = promisifyExecMethod(child_process.execFile); export function isChildProcessError(error) { return error instanceof Error && 'code' in error && 'signal' in error; } //# sourceMappingURL=index.js.map