diff --git a/source/index.d.ts b/source/index.d.ts index 15cb4c8..0a76e7b 100644 --- a/source/index.d.ts +++ b/source/index.d.ts @@ -3,52 +3,241 @@ import type {ChildProcess, SpawnOptions} from 'node:child_process'; type StdioOption = Readonly[number]>; type StdinOption = StdioOption | {readonly string?: string}; +/** +Options passed to `nano-spawn`. + +All `child_process.spawn()` options can be passed to `nanoSpawn()`. Please see [the `node:child_process` documentation](https://nodejs.org/api/child_process.html#child_processspawncommand-args-options) for a description of each option. +*/ export type Options = Omit & Readonly>>; }>>; +/** +When the subprocess succeeds, its promise is resolved with this object. +*/ export type Result = { + /** + The output of the subprocess on [standard output](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)). + + If the output ends with a [newline](https://en.wikipedia.org/wiki/Newline), that newline is automatically stripped. + + This is an empty string if either: + - The `stdout` option is set to another value than `'pipe'` (its default value). + - The output is being iterated using `subprocess.stdout` or `subprocess[Symbol.asyncIterator]`. + */ stdout: string; + /** + The output of the subprocess on [standard error](https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)). + + If the output ends with a [newline](https://en.wikipedia.org/wiki/Newline), that newline is automatically stripped. + + This is an empty string if either: + - The `stderr` option is set to another value than `'pipe'` (its default value). + - The output is being iterated using `subprocess.stderr` or `subprocess[Symbol.asyncIterator]`. + */ stderr: string; + /** + Like `result.stdout` but for both the [standard output](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)) and [standard error](https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)), interleaved. + */ output: string; + /** + The file and arguments that were run. + + It is intended for logging or debugging. Since the escaping is fairly basic, it should not be executed directly. + */ command: string; + /** + Duration of the subprocess, in milliseconds. + */ durationMs: number; + /** + If `subprocess.pipe()` was used, the result or error of the other subprocess that was piped into this subprocess. + */ pipedFrom?: Result | SubprocessError; }; +/** +When the subprocess fails, its promise is rejected with this error. + +Subprocesses fail either when their exit code is not `0` or when terminated by a signal. Other failure reasons include misspelling the command name or using the [`timeout`](https://nodejs.org/api/child_process.html#child_processspawncommand-args-options) option. +*/ export type SubprocessError = Error & Result & { + /** + The numeric [exit code](https://en.wikipedia.org/wiki/Exit_status) of the subprocess that was run. + + This is `undefined` when the subprocess could not be started, or when it was terminated by a signal. + */ exitCode?: number; + /** + The name of the [signal](https://en.wikipedia.org/wiki/Signal_(IPC)) (like [`SIGTERM`](https://en.wikipedia.org/wiki/Signal_(IPC)#SIGTERM)) that terminated the subprocess, sent by either: + - The current process. + - Another process. This case is [not supported on Windows](https://nodejs.org/api/process.html#signal-events). + + If a signal terminated the subprocess, this property is defined and included in the [error message](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/message). Otherwise it is `undefined`. + */ signalName?: string; }; +/** +Subprocess started by `nanoSpawn()`. + +A subprocess is a promise that is either resolved with a successful `result` object or rejected with a `subprocessError`. + +It is also an iterable, iterating over each `stdout`/`stderr` line, as soon as it is available. The iteration waits for the subprocess to end (even when using [`break`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break) or [`return`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return)). It throws if the subprocess fails. This means you do not need to call `await subprocess`. +*/ export type Subprocess = Promise & AsyncIterable & { + /** + Underlying [Node.js child process](https://nodejs.org/api/child_process.html#class-childprocess). + + Among other things, this can be used to terminate the subprocess using [`.kill()`](https://nodejs.org/api/child_process.html#subprocesskillsignal) or exchange IPC message using [`.send()`](https://nodejs.org/api/child_process.html#subprocesssendmessage-sendhandle-options-callback). + */ nodeChildProcess: Promise; + /** + Iterates over each `stdout` line, as soon as it is available. + + The iteration waits for the subprocess to end (even when using [`break`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break) or [`return`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return)). It throws if the subprocess fails. This means you do not need to call `await subprocess`. + */ stdout: AsyncIterable; + /** + Iterates over each `stderr` line, as soon as it is available. + + The iteration waits for the subprocess to end (even when using [`break`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break) or [`return`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return)). It throws if the subprocess fails. This means you do not need to call `await subprocess`. + */ stderr: AsyncIterable; + /** + Similar to the `|` symbol in shells. [Pipe](https://nodejs.org/api/stream.html#readablepipedestination-options) the subprocess's[`stdout`](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)) to a second subprocess's [`stdin`](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)). + + This resolves with that second subprocess's result. If either subprocess is rejected, this is rejected with that subprocess's error instead. + + This follows the same syntax as `nanoSpawn(file, arguments?, options?)`. It can be done multiple times in a row. + + @param file - The program/script to execute + @param arguments - Arguments to pass to `file` on execution. + @param options + @returns `Subprocess` + + @example + + ``` + const result = await spawn('npm', ['run', 'build']) + .pipe('sort') + .pipe('head', ['-n', '2']); + ``` + */ pipe(file: string, arguments?: readonly string[], options?: Options): Subprocess; pipe(file: string, options?: Options): Subprocess; }; +/** +Executes a command using `file ...arguments`. + +This has the same syntax as [`child_process.spawn()`](https://nodejs.org/api/child_process.html#child_processspawncommand-args-options). + +If `file` is `'node'`, the current Node.js version and [flags](https://nodejs.org/api/cli.html#options) are inherited. + +@param file - The program/script to execute +@param arguments - Arguments to pass to `file` on execution. +@param options +@returns `Subprocess` + +@example Run commands + +``` +import spawn from 'nano-spawn'; + +const result = await spawn('echo', ['🦄']); + +console.log(result.output); +//=> '🦄' +``` + +@example Iterate over output lines + +``` +for await (const line of spawn('ls', ['--oneline'])) { + console.log(line); +} +//=> index.d.ts +//=> index.js +//=> … +``` +*/ export default function nanoSpawn(file: string, arguments?: readonly string[], options?: Options): Subprocess; export default function nanoSpawn(file: string, options?: Options): Subprocess;