diff --git a/index.d.ts b/index.d.ts index 90d91f1272..b39464e2f6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -515,31 +515,100 @@ Think of this as a mix of `child_process.execFile` and `child_process.spawn`. - a [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess) with some additional methods and properties. @throws A `childProcessResult` error -@example +@example Promise interface ``` import {execa} from 'execa'; const {stdout} = await execa('echo', ['unicorns']); console.log(stdout); //=> 'unicorns' +``` -// Cancelling a spawned process +@example Redirect output to a file +``` +import {execa} from 'execa'; -const subprocess = execa('node'); +// Similar to `echo unicorns > stdout.txt` in Bash +await execa('echo', ['unicorns']).pipeStdout('stdout.txt'); -setTimeout(() => { - subprocess.cancel() -}, 1000); +// Similar to `echo unicorns 2> stdout.txt` in Bash +await execa('echo', ['unicorns']).pipeStderr('stderr.txt'); + +// Similar to `echo unicorns &> stdout.txt` in Bash +await execa('echo', ['unicorns'], {all:true}).pipeAll('all.txt'); +``` + +@example Redirect input from a file +``` +import {execa} from 'execa'; + +// Similar to `cat < stdin.txt` in Bash +const {stdout} = await execa('cat', {inputFile:'stdin.txt'}); +console.log(stdout); +//=> 'unicorns' +``` + +@example Save and pipe output from a child process +``` +import {execa} from 'execa'; + +const {stdout} = await execa('echo', ['unicorns']).pipeStdout(process.stdout); +// Prints `unicorns` +console.log(stdout); +// Also returns 'unicorns' +``` +@example Pipe multiple processes +``` +import {execa} from 'execa'; + +// Similar to `echo unicorns | cat` in Bash +const {stdout} = await execa('echo', ['unicorns']).pipeStdout(execa('cat')); +console.log(stdout); +//=> 'unicorns' +``` + +@example Handling errors +``` +import {execa} from 'execa'; + +// Catching an error try { - await subprocess; + await execa('unknown', ['command']); } catch (error) { - console.log(subprocess.killed); // true - console.log(error.isCanceled); // true + console.log(error); + /* + { + message: 'Command failed with ENOENT: unknown command spawn unknown ENOENT', + errno: -2, + code: 'ENOENT', + syscall: 'spawn unknown', + path: 'unknown', + spawnargs: ['command'], + originalMessage: 'spawn unknown ENOENT', + shortMessage: 'Command failed with ENOENT: unknown command spawn unknown ENOENT', + command: 'unknown command', + escapedCommand: 'unknown command', + stdout: '', + stderr: '', + failed: true, + timedOut: false, + isCanceled: false, + killed: false + } + \*\/ } +``` + +@example Graceful termination +``` +const subprocess = execa('node'); -// Pipe the child process stdout to the current stdout -execa('echo', ['unicorns']).stdout.pipe(process.stdout); +setTimeout(() => { + subprocess.kill('SIGTERM', { + forceKillAfterTimeout: 2000 + }); +}, 1000); ``` */ export function execa( @@ -562,6 +631,57 @@ Same as `execa()` but synchronous. @param arguments - Arguments to pass to `file` on execution. @returns A `childProcessResult` object @throws A `childProcessResult` error + +@example Promise interface +``` +import {execa} from 'execa'; + +const {stdout} = execaSync('echo', ['unicorns']); +console.log(stdout); +//=> 'unicorns' +``` + +@example Redirect input from a file +``` +import {execa} from 'execa'; + +// Similar to `cat < stdin.txt` in Bash +const {stdout} = execaSync('cat', {inputFile:'stdin.txt'}); +console.log(stdout); +//=> 'unicorns' +``` + +@example Handling errors +``` +import {execa} from 'execa'; + +// Catching an error +try { + execaSync('unknown', ['command']); +} catch (error) { + console.log(error); + /* + { + message: 'Command failed with ENOENT: unknown command spawnSync unknown ENOENT', + errno: -2, + code: 'ENOENT', + syscall: 'spawnSync unknown', + path: 'unknown', + spawnargs: ['command'], + originalMessage: 'spawnSync unknown ENOENT', + shortMessage: 'Command failed with ENOENT: unknown command spawnSync unknown ENOENT', + command: 'unknown command', + escapedCommand: 'unknown command', + stdout: '', + stderr: '', + failed: true, + timedOut: false, + isCanceled: false, + killed: false + } + \*\/ +} +``` */ export function execaSync( file: string, @@ -604,6 +724,25 @@ console.log(stdout); export function execaCommand(command: string, options?: Options): ExecaChildProcess; export function execaCommand(command: string, options?: Options): ExecaChildProcess; +/** +Same as `execaCommand()` but synchronous. + +@param command - The program/script to execute and its arguments. +@returns A `childProcessResult` object +@throws A `childProcessResult` error + +@example +``` +import {execaCommandSync} from 'execa'; + +const {stdout} = execaCommandSync('echo unicorns'); +console.log(stdout); +//=> 'unicorns' +``` +*/ +export function execaCommandSync(command: string, options?: SyncOptions): ExecaSyncReturnValue; +export function execaCommandSync(command: string, options?: SyncOptions): ExecaSyncReturnValue; + type TemplateExpression = | string | number @@ -613,72 +752,25 @@ type TemplateExpression = type Execa$ = { /** - Same as `execa()` (including its return value) except both file and arguments are specified in a single tagged template string. For example, `` $`echo unicorns` `` is the same as `execa('echo', ['unicorns'])`. - - It's important to note that quotes, backslashes, and spaces are automatically escaped and have no special meaning unless the `shell` option is used. This escaping behavior also applies to interpolated expressions such as strings (`` $`echo ${'string'}` ``), arrays of strings (`` $`echo ${['array', 'of strings']}` ``), and so on. - - The `shell` option must be used if the `command` uses shell-specific features (for example, `&&` or `||`), as opposed to being a simple `file` followed by its `arguments`. - - As a convenience, the result from previous `` $`command` `` or `` $.sync`command` `` calls can be used as template expressions in subsequent commands and `$`/`$.sync` will use the `stdout` value. See the example below `` with results from `$` or `$.sync` `` for more details. + Binds options to the `$` API. For example, you can use `$(options)` to create a new `$` instance with specific default options, which are then bound to both the asynchronous `` $`command` `` and synchronous `` $.sync`command` `` APIs. - @returns An `ExecaChildProcess` that is both: - - a `Promise` resolving or rejecting with a `childProcessResult`. - - a [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess) with some additional methods and properties. - @throws A `childProcessResult` error - - @example Basic - ``` - import {$} from 'execa'; + > **Note:** Consecutive calls to this API will shallow merge the options. - const {stdout} = await $`echo unicorns`; - // const {stdout} = await $`echo ${'unicorns'}`; - // const {stdout} = await $`echo ${['unicorns', 'rainbows']}`; + @param options - Options to set + @returns A new instance of `$` with those `options` set - console.log(stdout); - //=> 'unicorns' - ``` - - @example With options - ``` - import {$} from 'execa'; - - await $({stdio: 'inherit'})`echo unicorns`; - //=> 'unicorns' - ``` - - @example With pre-defined options + @example ``` import {$} from 'execa'; const $$ = $({stdio: 'inherit'}); - await $$`echo unicorns`; - //=> 'unicorns' - await $$({shell: true})`echo unicorns && echo rainbows`; - //=> 'unicorns' - //=> 'rainbows' - ``` - @example Synchronous - ``` - import {$} from 'execa'; - - const {stdout} = $.sync`echo unicorns`; - console.log(stdout); + await $$`echo unicorns`; //=> 'unicorns' - $({stdio: 'inherit'}).sync`echo rainbows`; + await $$`echo rainbows`; //=> 'rainbows' ``` - - @example With results from `$` or `$.sync` - ``` - import {$} from 'execa'; - - const unicorns = await $`echo unicorns`; - - $({stdio: 'inherit'}).sync`echo ${unicorns} rainbows`; - //=> 'unicorns rainbows' - ``` */ (options: Options): Execa$; (options: Options): Execa$; @@ -694,15 +786,42 @@ type Execa$ = { @returns A `childProcessResult` object @throws A `childProcessResult` error - @example + @example Basic ``` import {$} from 'execa'; - const {stdout} = $.sync`echo unicorns`; + const branch = $.sync`git branch --show-current` + $.sync`dep deploy --branch=${branch}` + ``` + + @example Multiple arguments + ``` + import {$} from 'execa'; + + const args = ['unicorns', '&', 'rainbows!'] + const {stdout} = $.sync`echo ${args}`; console.log(stdout); + //=> 'unicorns & rainbows!' + ``` + + @example With options + ``` + import {$} from 'execa'; + + $.sync({stdio: 'inherit'})`echo unicorns`; + //=> 'unicorns' + ``` + + @example Shared options + ``` + import {$} from 'execa'; + + const $$ = $({stdio: 'inherit'}); + + $$.sync`echo unicorns`; //=> 'unicorns' - $({stdio: 'inherit'}).sync`echo rainbows`; + $$.sync`echo rainbows`; //=> 'rainbows' ``` */ @@ -730,12 +849,18 @@ As a convenience, the result from previous `` $`command` `` or `` $.sync`command ``` import {$} from 'execa'; -const {stdout} = await $`echo unicorns`; -// const {stdout} = await $`echo ${'unicorns'}`; -// const {stdout} = await $`echo ${['unicorns', 'rainbows']}`; +const branch = await $`git branch --show-current` +await $`dep deploy --branch=${branch}` +``` +@example Multiple arguments +``` +import {$} from 'execa'; + +const args = ['unicorns', '&', 'rainbows!'] +const {stdout} = await $`echo ${args}`; console.log(stdout); -//=> 'unicorns' +//=> 'unicorns & rainbows!' ``` @example With options @@ -746,52 +871,21 @@ await $({stdio: 'inherit'})`echo unicorns`; //=> 'unicorns' ``` -@example With pre-defined options +@example Shared options ``` import {$} from 'execa'; const $$ = $({stdio: 'inherit'}); -await $$`echo unicorns`; -//=> 'unicorns' -await $$({shell: true})`echo unicorns && echo rainbows`; -//=> 'unicorns' -//=> 'rainbows' -``` -@example Synchronous -``` -import {$} from 'execa'; - -const {stdout} = $.sync`echo unicorns`; -console.log(stdout); +await $$`echo unicorns`; //=> 'unicorns' -$({stdio: 'inherit'}).sync`echo rainbows`; +await $$`echo rainbows`; //=> 'rainbows' ``` - -@example With results from `$` or `$.sync` -``` -import {$} from 'execa'; - -const unicorns = await $`echo unicorns`; - -$({stdio: 'inherit'}).sync`echo ${unicorns} rainbows`; -//=> 'unicorns rainbows' -``` */ export const $: Execa$; -/** -Same as `execaCommand()` but synchronous. - -@param command - The program/script to execute and its arguments. -@returns A `childProcessResult` object -@throws A `childProcessResult` error -*/ -export function execaCommandSync(command: string, options?: SyncOptions): ExecaSyncReturnValue; -export function execaCommandSync(command: string, options?: SyncOptions): ExecaSyncReturnValue; - /** Execute a Node.js script as a child process. @@ -806,6 +900,13 @@ Same as `execa('node', [scriptPath, ...arguments], options)` except (like [`chil - a `Promise` resolving or rejecting with a `childProcessResult`. - a [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess) with some additional methods and properties. @throws A `childProcessResult` error + +@example +``` +import {execa} from 'execa'; + +await execaNode('scriptPath', ['argument']); +``` */ export function execaNode( scriptPath: string, diff --git a/readme.md b/readme.md index 4f820e21c6..2572efd118 100644 --- a/readme.md +++ b/readme.md @@ -179,7 +179,6 @@ try { escapedCommand: 'unknown command', stdout: '', stderr: '', - all: '', failed: true, timedOut: false, isCanceled: false,