Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

execa

Package Overview
Dependencies
Maintainers
2
Versions
60
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

execa - npm Package Compare versions

Comparing version 7.0.0 to 7.1.0

lib/pipe.js

448

index.d.ts
import {type Buffer} from 'node:buffer';
import {type ChildProcess} from 'node:child_process';
import {type Stream, type Readable as ReadableStream} from 'node:stream';
import {type Stream, type Readable as ReadableStream, type Writable as WritableStream} from 'node:stream';

@@ -30,3 +30,3 @@ export type StdioOption =

@default false
@default `true` with `$`/`$.sync`, `false` otherwise
*/

@@ -248,2 +248,11 @@ readonly preferLocal?: boolean;

readonly windowsHide?: boolean;
/**
Print each command on `stderr` before executing it.
This can also be enabled by setting the `NODE_DEBUG=execa` environment variable in the current process.
@default false
*/
readonly verbose?: boolean;
};

@@ -254,4 +263,13 @@

Write some input to the `stdin` of your binary.
If the input is a file, use the `inputFile` option instead.
*/
readonly input?: string | Buffer | ReadableStream;
/**
Use a file as input to the the `stdin` of your binary.
If the input is not a file, use the `input` option instead.
*/
readonly inputFile?: string;
} & CommonOptions<EncodingType>;

@@ -262,4 +280,13 @@

Write some input to the `stdin` of your binary.
If the input is a file, use the `inputFile` option instead.
*/
readonly input?: string | Buffer;
/**
Use a file as input to the the `stdin` of your binary.
If the input is not a file, use the `input` option instead.
*/
readonly inputFile?: string;
} & CommonOptions<EncodingType>;

@@ -283,3 +310,5 @@

export type ExecaReturnBase<StdoutStderrType> = {
type StdoutStderrAll = string | Buffer | undefined;
export type ExecaReturnBase<StdoutStderrType extends StdoutStderrAll> = {
/**

@@ -345,4 +374,4 @@ The file and arguments that were run, for logging purposes.

export type ExecaSyncReturnValue<StdoutErrorType = string> = {
} & ExecaReturnBase<StdoutErrorType>;
export type ExecaSyncReturnValue<StdoutStderrType extends StdoutStderrAll = string> = {
} & ExecaReturnBase<StdoutStderrType>;

@@ -359,3 +388,3 @@ /**

*/
export type ExecaReturnValue<StdoutErrorType = string> = {
export type ExecaReturnValue<StdoutStderrType extends StdoutStderrAll = string> = {
/**

@@ -368,3 +397,3 @@ The output of the process with `stdout` and `stderr` interleaved.

*/
all?: StdoutErrorType;
all?: StdoutStderrType;

@@ -377,5 +406,5 @@ /**

isCanceled: boolean;
} & ExecaSyncReturnValue<StdoutErrorType>;
} & ExecaSyncReturnValue<StdoutStderrType>;
export type ExecaSyncError<StdoutErrorType = string> = {
export type ExecaSyncError<StdoutStderrType extends StdoutStderrAll = string> = {
/**

@@ -399,5 +428,5 @@ Error message when the child process failed to run. In addition to the underlying error message, it also contains some information related to why the child process errored.

originalMessage?: string;
} & Error & ExecaReturnBase<StdoutErrorType>;
} & Error & ExecaReturnBase<StdoutStderrType>;
export type ExecaError<StdoutErrorType = string> = {
export type ExecaError<StdoutStderrType extends StdoutStderrAll = string> = {
/**

@@ -410,3 +439,3 @@ The output of the process with `stdout` and `stderr` interleaved.

*/
all?: StdoutErrorType;
all?: StdoutStderrType;

@@ -417,3 +446,3 @@ /**

isCanceled: boolean;
} & ExecaSyncError<StdoutErrorType>;
} & ExecaSyncError<StdoutStderrType>;

@@ -431,3 +460,3 @@ export type KillOptions = {

export type ExecaChildPromise<StdoutErrorType> = {
export type ExecaChildPromise<StdoutStderrType extends StdoutStderrAll> = {
/**

@@ -443,4 +472,4 @@ Stream combining/interleaving [`stdout`](https://nodejs.org/api/child_process.html#child_process_subprocess_stdout) and [`stderr`](https://nodejs.org/api/child_process.html#child_process_subprocess_stderr).

catch<ResultType = never>(
onRejected?: (reason: ExecaError<StdoutErrorType>) => ResultType | PromiseLike<ResultType>
): Promise<ExecaReturnValue<StdoutErrorType> | ResultType>;
onRejected?: (reason: ExecaError<StdoutStderrType>) => ResultType | PromiseLike<ResultType>
): Promise<ExecaReturnValue<StdoutStderrType> | ResultType>;

@@ -456,18 +485,52 @@ /**

cancel(): void;
/**
[Pipe](https://nodejs.org/api/stream.html#readablepipedestination-options) the child process's `stdout` to `target`, which can be:
- Another `execa()` return value
- A writable stream
- A file path string
If the `target` is another `execa()` return value, it is returned. Otherwise, the original `execa()` return value is returned. This allows chaining `pipeStdout()` then `await`ing the final result.
The `stdout` option] must be kept as `pipe`, its default value.
*/
pipeStdout?<Target extends ExecaChildPromise<StdoutStderrAll>>(target: Target): Target;
pipeStdout?(target: WritableStream | string): ExecaChildProcess<StdoutStderrType>;
/**
Like `pipeStdout()` but piping the child process's `stderr` instead.
The `stderr` option must be kept as `pipe`, its default value.
*/
pipeStderr?<Target extends ExecaChildPromise<StdoutStderrAll>>(target: Target): Target;
pipeStderr?(target: WritableStream | string): ExecaChildProcess<StdoutStderrType>;
/**
Combines both `pipeStdout()` and `pipeStderr()`.
Either the `stdout` option or the `stderr` option must be kept as `pipe`, their default value. Also, the `all` option must be set to `true`.
*/
pipeAll?<Target extends ExecaChildPromise<StdoutStderrAll>>(target: Target): Target;
pipeAll?(target: WritableStream | string): ExecaChildProcess<StdoutStderrType>;
};
export type ExecaChildProcess<StdoutErrorType = string> = ChildProcess &
ExecaChildPromise<StdoutErrorType> &
Promise<ExecaReturnValue<StdoutErrorType>>;
export type ExecaChildProcess<StdoutStderrType extends StdoutStderrAll = string> = ChildProcess &
ExecaChildPromise<StdoutStderrType> &
Promise<ExecaReturnValue<StdoutStderrType>>;
/**
Execute a file.
Executes a command using `file ...arguments`. `arguments` are specified as an array of strings. Returns a `childProcess`.
Think of this as a mix of `child_process.execFile` and `child_process.spawn`.
Arguments are automatically escaped. They can contain any character, including spaces.
This is the preferred method when executing single commands.
@param file - The program/script to execute.
@param arguments - Arguments to pass to `file` on execution.
@returns A [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties.
@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
@example <caption>Promise interface</caption>
```

@@ -479,21 +542,90 @@ import {execa} from 'execa';

//=> 'unicorns'
```
// Cancelling a spawned process
@example <caption>Redirect output to a file</caption>
```
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 <caption>Redirect input from a file</caption>
```
import {execa} from 'execa';
// Similar to `cat < stdin.txt` in Bash
const {stdout} = await execa('cat', {inputFile: 'stdin.txt'});
console.log(stdout);
//=> 'unicorns'
```
@example <caption>Save and pipe output from a child process</caption>
```
import {execa} from 'execa';
const {stdout} = await execa('echo', ['unicorns']).pipeStdout(process.stdout);
// Prints `unicorns`
console.log(stdout);
// Also returns 'unicorns'
```
@example <caption>Pipe multiple processes</caption>
```
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 <caption>Handling errors</caption>
```
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
}
\*\/
}
```
// Pipe the child process stdout to the current stdout
execa('echo', ['unicorns']).stdout.pipe(process.stdout);
@example <caption>Graceful termination</caption>
```
const subprocess = execa('node');
setTimeout(() => {
subprocess.kill('SIGTERM', {
forceKillAfterTimeout: 2000
});
}, 1000);
```
*/

@@ -514,9 +646,59 @@ export function execa(

/**
Execute a file synchronously.
Same as `execa()` but synchronous.
This method throws an `Error` if the command fails.
@param file - The program/script to execute.
@param arguments - Arguments to pass to `file` on execution.
@returns A result `Object` with `stdout` and `stderr` properties.
@returns A `childProcessResult` object
@throws A `childProcessResult` error
@example <caption>Promise interface</caption>
```
import {execa} from 'execa';
const {stdout} = execaSync('echo', ['unicorns']);
console.log(stdout);
//=> 'unicorns'
```
@example <caption>Redirect input from a file</caption>
```
import {execa} from 'execa';
// Similar to `cat < stdin.txt` in Bash
const {stdout} = execaSync('cat', {inputFile: 'stdin.txt'});
console.log(stdout);
//=> 'unicorns'
```
@example <caption>Handling errors</caption>
```
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
}
\*\/
}
```
*/

@@ -540,10 +722,13 @@ export function execaSync(

/**
Same as `execa()` except both file and arguments are specified in a single `command` string. For example, `execa('echo', ['unicorns'])` is the same as `execaCommand('echo unicorns')`.
Executes a command. The `command` string includes both the `file` and its `arguments`. Returns a `childProcess`.
If the file or an argument contains spaces, they must be escaped with backslashes. This matters especially if `command` is not a constant but a variable, for example with `__dirname` or `process.cwd()`. Except for spaces, no escaping/quoting is needed.
Arguments are automatically escaped. They can contain any character, but spaces must be escaped with a backslash like `execaCommand('echo has\\ space')`.
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`.
This is the preferred method when executing a user-supplied `command` string, such as in a REPL.
@param command - The program/script to execute and its arguments.
@returns A [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties.
@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

@@ -566,3 +751,13 @@ @example

@param command - The program/script to execute and its arguments.
@returns A result `Object` with `stdout` and `stderr` properties.
@returns A `childProcessResult` object
@throws A `childProcessResult` error
@example
```
import {execaCommandSync} from 'execa';
const {stdout} = execaCommandSync('echo unicorns');
console.log(stdout);
//=> 'unicorns'
```
*/

@@ -572,13 +767,172 @@ export function execaCommandSync(command: string, options?: SyncOptions): ExecaSyncReturnValue;

type TemplateExpression =
| string
| number
| ExecaReturnValue<string | Buffer>
| ExecaSyncReturnValue<string | Buffer>
| Array<string | number | ExecaReturnValue<string | Buffer> | ExecaSyncReturnValue<string | Buffer>>;
type Execa$<StdoutStderrType extends StdoutStderrAll = string> = {
/**
Returns a new instance of `$` but with different default `options`. Consecutive calls are merged to previous ones.
This can be used to either:
- Set options for a specific command: `` $(options)`command` ``
- Share options for multiple commands: `` const $$ = $(options); $$`command`; $$`otherCommand` ``
@param options - Options to set
@returns A new instance of `$` with those `options` set
@example
```
import {$} from 'execa';
const $$ = $({stdio: 'inherit'});
await $$`echo unicorns`;
//=> 'unicorns'
await $$`echo rainbows`;
//=> 'rainbows'
```
*/
(options: Options<undefined>): Execa$<StdoutStderrType>;
(options: Options): Execa$;
(options: Options<null>): Execa$<Buffer>;
(
templates: TemplateStringsArray,
...expressions: TemplateExpression[]
): ExecaChildProcess<StdoutStderrType>;
/**
Same as $\`command\` but synchronous.
@returns A `childProcessResult` object
@throws A `childProcessResult` error
@example <caption>Basic</caption>
```
import {$} from 'execa';
const branch = $.sync`git branch --show-current`;
$.sync`dep deploy --branch=${branch}`;
```
@example <caption>Multiple arguments</caption>
```
import {$} from 'execa';
const args = ['unicorns', '&', 'rainbows!'];
const {stdout} = $.sync`echo ${args}`;
console.log(stdout);
//=> 'unicorns & rainbows!'
```
@example <caption>With options</caption>
```
import {$} from 'execa';
$.sync({stdio: 'inherit'})`echo unicorns`;
//=> 'unicorns'
```
@example <caption>Shared options</caption>
```
import {$} from 'execa';
const $$ = $({stdio: 'inherit'});
$$.sync`echo unicorns`;
//=> 'unicorns'
$$.sync`echo rainbows`;
//=> 'rainbows'
```
*/
sync(
templates: TemplateStringsArray,
...expressions: TemplateExpression[]
): ExecaSyncReturnValue<StdoutStderrType>;
};
/**
Executes a command. The `command` string includes both the `file` and its `arguments`. Returns a `childProcess`.
Arguments are automatically escaped. They can contain any character, but spaces must use `${}` like `` $`echo ${'has space'}` ``.
This is the preferred method when executing multiple commands in a script file.
The `command` string can inject any `${value}` with the following types: string, number, `childProcess` or an array of those types. For example: `` $`echo one ${'two'} ${3} ${['four', 'five']}` ``. For `${childProcess}`, the process's `stdout` is used.
@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 <caption>Basic</caption>
```
import {$} from 'execa';
const branch = await $`git branch --show-current`;
await $`dep deploy --branch=${branch}`;
```
@example <caption>Multiple arguments</caption>
```
import {$} from 'execa';
const args = ['unicorns', '&', 'rainbows!'];
const {stdout} = await $`echo ${args}`;
console.log(stdout);
//=> 'unicorns & rainbows!'
```
@example <caption>With options</caption>
```
import {$} from 'execa';
await $({stdio: 'inherit'})`echo unicorns`;
//=> 'unicorns'
```
@example <caption>Shared options</caption>
```
import {$} from 'execa';
const $$ = $({stdio: 'inherit'});
await $$`echo unicorns`;
//=> 'unicorns'
await $$`echo rainbows`;
//=> 'rainbows'
```
*/
export const $: Execa$;
/**
Execute a Node.js script as a child process.
Same as `execa('node', [scriptPath, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)):
- the current Node version and options are used. This can be overridden using the `nodePath` and `nodeArguments` options.
- the `shell` option cannot be used
- an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to [`stdio`](#stdio)
Arguments are automatically escaped. They can contain any character, including spaces.
This is the preferred method when executing Node.js files.
Like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options):
- the current Node version and options are used. This can be overridden using the `nodePath` and `nodeOptions` options.
- the `shell` option cannot be used
- an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to `stdio`
@param scriptPath - Node.js script to execute.
@param arguments - Arguments to pass to `scriptPath` on execution.
@returns A [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties.
@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
```
import {execa} from 'execa';
await execaNode('scriptPath', ['argument']);
```
*/

@@ -585,0 +939,0 @@ export function execaNode(

@@ -12,5 +12,7 @@ import {Buffer} from 'node:buffer';

import {spawnedKill, spawnedCancel, setupTimeout, validateTimeout, setExitHandler} from './lib/kill.js';
import {handleInput, getSpawnedResult, makeAllStream, validateInputSync} from './lib/stream.js';
import {addPipeMethods} from './lib/pipe.js';
import {handleInput, getSpawnedResult, makeAllStream, handleInputSync} from './lib/stream.js';
import {mergePromise, getSpawnedPromise} from './lib/promise.js';
import {joinCommand, parseCommand, getEscapedCommand} from './lib/command.js';
import {joinCommand, parseCommand, parseTemplates, getEscapedCommand} from './lib/command.js';
import {logCommand, verboseDefault} from './lib/verbose.js';

@@ -48,2 +50,3 @@ const DEFAULT_MAX_BUFFER = 1000 * 1000 * 100;

windowsHide: true,
verbose: verboseDefault,
...options,

@@ -81,2 +84,3 @@ };

const escapedCommand = getEscapedCommand(file, args);
logCommand(escapedCommand, parsed.options);

@@ -103,3 +107,4 @@ validateTimeout(parsed.options);

}));
return mergePromise(dummySpawned, errorPromise);
mergePromise(dummySpawned, errorPromise);
return dummySpawned;
}

@@ -161,7 +166,9 @@

handleInput(spawned, parsed.options.input);
handleInput(spawned, parsed.options);
spawned.all = makeAllStream(spawned, parsed.options);
return mergePromise(spawned, handlePromiseOnce);
addPipeMethods(spawned);
mergePromise(spawned, handlePromiseOnce);
return spawned;
}

@@ -173,8 +180,9 @@

const escapedCommand = getEscapedCommand(file, args);
logCommand(escapedCommand, parsed.options);
validateInputSync(parsed.options);
const input = handleInputSync(parsed.options);
let result;
try {
result = childProcess.spawnSync(parsed.file, parsed.args, parsed.options);
result = childProcess.spawnSync(parsed.file, parsed.args, {...parsed.options, input});
} catch (error) {

@@ -233,2 +241,22 @@ throw makeError({

function create$(options) {
function $(templatesOrOptions, ...expressions) {
if (Array.isArray(templatesOrOptions)) {
const [file, ...args] = parseTemplates(templatesOrOptions, expressions);
return execa(file, args, options);
}
return create$({...options, ...templatesOrOptions});
}
$.sync = (templates, ...expressions) => {
const [file, ...args] = parseTemplates(templates, expressions);
return execaSync(file, args, options);
};
return $;
}
export const $ = create$({preferLocal: true});
export function execaCommand(command, options) {

@@ -235,0 +263,0 @@ const [file, ...args] = parseCommand(command);

@@ -0,1 +1,4 @@

import {Buffer} from 'node:buffer';
import {ChildProcess} from 'node:child_process';
const normalizeArgs = (file, args = []) => {

@@ -42,1 +45,53 @@ if (!Array.isArray(args)) {

};
const parseExpression = expression => {
const typeOfExpression = typeof expression;
if (typeOfExpression === 'string') {
return expression;
}
if (typeOfExpression === 'number') {
return String(expression);
}
if (
typeOfExpression === 'object'
&& expression !== null
&& !(expression instanceof ChildProcess)
&& 'stdout' in expression
) {
const typeOfStdout = typeof expression.stdout;
if (typeOfStdout === 'string') {
return expression.stdout;
}
if (Buffer.isBuffer(expression.stdout)) {
return expression.stdout.toString();
}
throw new TypeError(`Unexpected "${typeOfStdout}" stdout in template expression`);
}
throw new TypeError(`Unexpected "${typeOfExpression}" in template expression`);
};
const parseTemplate = (template, index, templates, expressions) => {
const templateString = template ?? templates.raw[index];
const templateTokens = templateString.split(SPACES_REGEXP).filter(Boolean);
if (index === expressions.length) {
return templateTokens;
}
const expression = expressions[index];
return Array.isArray(expression)
? [...templateTokens, ...expression.map(expression => parseExpression(expression))]
: [...templateTokens, parseExpression(expression)];
};
export const parseTemplates = (templates, expressions) => templates.flatMap(
(template, index) => parseTemplate(template, index, templates, expressions),
);

2

lib/promise.js

@@ -19,4 +19,2 @@ // eslint-disable-next-line unicorn/prefer-top-level-await

}
return spawned;
};

@@ -23,0 +21,0 @@

@@ -0,1 +1,2 @@

import {createReadStream, readFileSync} from 'node:fs';
import {isStream} from 'is-stream';

@@ -5,4 +6,41 @@ import getStream from 'get-stream';

// `input` option
export const handleInput = (spawned, input) => {
const validateInputOptions = input => {
if (input !== undefined) {
throw new TypeError('The `input` and `inputFile` options cannot be both set.');
}
};
const getInputSync = ({input, inputFile}) => {
if (typeof inputFile !== 'string') {
return input;
}
validateInputOptions(input);
return readFileSync(inputFile);
};
// `input` and `inputFile` option in sync mode
export const handleInputSync = options => {
const input = getInputSync(options);
if (isStream(input)) {
throw new TypeError('The `input` option cannot be a stream in sync mode');
}
return input;
};
const getInput = ({input, inputFile}) => {
if (typeof inputFile !== 'string') {
return input;
}
validateInputOptions(input);
return createReadStream(inputFile);
};
// `input` and `inputFile` option in async mode
export const handleInput = (spawned, options) => {
const input = getInput(options);
if (input === undefined) {

@@ -83,7 +121,1 @@ return;

};
export const validateInputSync = ({input}) => {
if (isStream(input)) {
throw new TypeError('The `input` option cannot be a stream in sync mode');
}
};
{
"name": "execa",
"version": "7.0.0",
"version": "7.1.0",
"description": "Process execution for humans",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -15,12 +15,15 @@ <picture>

- Promise interface.
- [Promise interface](#execacommandcommand-options).
- [Scripts interface](#scripts-interface), like `zx`.
- Improved [Windows support](https://github.com/IndigoUnited/node-cross-spawn#why), including [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) binaries.
- Executes [locally installed binaries](#preferlocal) without `npx`.
- [Cleans up](#cleanup) child processes when the parent process ends.
- [Graceful termination](#optionsforcekillaftertimeout).
- Get [interleaved output](#all) from `stdout` and `stderr` similar to what is printed on the terminal.
- [Strips the final newline](#stripfinalnewline) from the output so you don't have to do `stdout.trim()`.
- Supports [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) binaries cross-platform.
- [Improved Windows support.](https://github.com/IndigoUnited/node-cross-spawn#why)
- Higher max buffer. 100 MB instead of 200 KB.
- [Executes locally installed binaries by name.](#preferlocal)
- [Cleans up spawned processes when the parent process dies.](#cleanup)
- [Get interleaved output](#all) from `stdout` and `stderr` similar to what is printed on the terminal. [*(Async only)*](#execasyncfile-arguments-options)
- [Can specify file and arguments as a single string without a shell](#execacommandcommand-options)
- Convenience methods to pipe processes' [input](#input) and [output](#redirect-output-to-a-file).
- Can specify file and arguments [as a single string](#execacommandcommand-options) without a shell.
- [Verbose mode](#verbose-mode) for debugging.
- More descriptive errors.
- Higher max buffer: 100 MB instead of 1 MB.

@@ -35,2 +38,4 @@ ## Install

### Promise interface
```js

@@ -44,11 +49,81 @@ import {execa} from 'execa';

### Pipe the child process stdout to the parent
### Scripts interface
For more information about Execa scripts, please see [this page](docs/scripts.md).
#### Basic
```js
import {$} from 'execa';
const branch = await $`git branch --show-current`;
await $`dep deploy --branch=${branch}`;
```
#### Multiple arguments
```js
import {$} from 'execa';
const args = ['unicorns', '&', 'rainbows!'];
const {stdout} = await $`echo ${args}`;
console.log(stdout);
//=> 'unicorns & rainbows!'
```
#### With options
```js
import {$} from 'execa';
await $({stdio: 'inherit'})`echo unicorns`;
//=> 'unicorns'
```
#### Shared options
```js
import {$} from 'execa';
const $$ = $({stdio: 'inherit'});
await $$`echo unicorns`;
//=> 'unicorns'
await $$`echo rainbows`;
//=> 'rainbows'
```
#### Verbose mode
```sh
> node file.js
unicorns
rainbows
> NODE_DEBUG=execa node file.js
[16:50:03.305] echo unicorns
unicorns
[16:50:03.308] echo rainbows
rainbows
```
### Input/output
#### Redirect output to a file
```js
import {execa} from 'execa';
execa('echo', ['unicorns']).stdout.pipe(process.stdout);
// Similar to `echo unicorns > stdout.txt` in Bash
await execa('echo', ['unicorns']).pipeStdout('stdout.txt');
// 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');
```
### Handling Errors
#### Redirect input from a file

@@ -58,32 +133,9 @@ ```js

// Catching an error
try {
await execa('unknown', ['command']);
} catch (error) {
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: '',
all: '',
failed: true,
timedOut: false,
isCanceled: false,
killed: false
}
*/
}
// Similar to `cat < stdin.txt` in Bash
const {stdout} = await execa('cat', {inputFile: 'stdin.txt'});
console.log(stdout);
//=> 'unicorns'
```
### Cancelling a spawned process
#### Save and pipe output from a child process

@@ -93,24 +145,27 @@ ```js

const abortController = new AbortController();
const subprocess = execa('node', [], {signal: abortController.signal});
const {stdout} = await execa('echo', ['unicorns']).pipeStdout(process.stdout);
// Prints `unicorns`
console.log(stdout);
// Also returns 'unicorns'
```
setTimeout(() => {
abortController.abort();
}, 1000);
#### Pipe multiple processes
try {
await subprocess;
} catch (error) {
console.log(subprocess.killed); // true
console.log(error.isCanceled); // true
}
```js
import {execa} from 'execa';
// Similar to `echo unicorns | cat` in Bash
const {stdout} = await execa('echo', ['unicorns']).pipeStdout(execa('cat'));
console.log(stdout);
//=> 'unicorns'
```
### Catching an error with the sync method
### Handling Errors
```js
import {execaSync} from 'execa';
import {execa} from 'execa';
// Catching an error
try {
execaSync('unknown', ['command']);
await execa('unknown', ['command']);
} catch (error) {

@@ -120,10 +175,10 @@ console.log(error);

{
message: 'Command failed with ENOENT: unknown command spawnSync unknown ENOENT',
message: 'Command failed with ENOENT: unknown command spawn unknown ENOENT',
errno: -2,
code: 'ENOENT',
syscall: 'spawnSync unknown',
syscall: 'spawn unknown',
path: 'unknown',
spawnargs: ['command'],
originalMessage: 'spawnSync unknown ENOENT',
shortMessage: 'Command failed with ENOENT: unknown command spawnSync unknown ENOENT',
originalMessage: 'spawn unknown ENOENT',
shortMessage: 'Command failed with ENOENT: unknown command spawn unknown ENOENT',
command: 'unknown command',

@@ -133,3 +188,2 @@ escapedCommand: 'unknown command',

stderr: '',
all: '',
failed: true,

@@ -144,3 +198,3 @@ timedOut: false,

### Kill a process
### Graceful termination

@@ -161,14 +215,81 @@ Using SIGTERM, and after 2 seconds, kill it with SIGKILL.

### execa(file, arguments, options?)
### Methods
Execute a file. Think of this as a mix of [`child_process.execFile()`](https://nodejs.org/api/child_process.html#child_process_child_process_execfile_file_args_options_callback) and [`child_process.spawn()`](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options).
#### execa(file, arguments?, options?)
No escaping/quoting is needed.
Executes a command using `file ...arguments`. `arguments` are specified as an array of strings. Returns a [`childProcess`](#childprocess).
Unless the [`shell`](#shell) option is used, no shell interpreter (Bash, `cmd.exe`, etc.) is used, so shell features such as variables substitution (`echo $PATH`) are not allowed.
Arguments are [automatically escaped](#shell-syntax). They can contain any character, including spaces.
Returns a [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess) which:
- is also a `Promise` resolving or rejecting with a [`childProcessResult`](#childProcessResult).
- exposes the following additional methods and properties.
This is the preferred method when executing single commands.
#### execaNode(scriptPath, arguments?, options?)
Executes a Node.js file using `node scriptPath ...arguments`. `arguments` are specified as an array of strings. Returns a [`childProcess`](#childprocess).
Arguments are [automatically escaped](#shell-syntax). They can contain any character, including spaces.
This is the preferred method when executing Node.js files.
Like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options):
- the current Node version and options are used. This can be overridden using the [`nodePath`](#nodepath-for-node-only) and [`nodeOptions`](#nodeoptions-for-node-only) options.
- the [`shell`](#shell) option cannot be used
- an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to [`stdio`](#stdio)
#### $\`command\`
Executes a command. The `command` string includes both the `file` and its `arguments`. Returns a [`childProcess`](#childprocess).
Arguments are [automatically escaped](#shell-syntax). They can contain any character, but spaces must use `${}` like `` $`echo ${'has space'}` ``.
This is the preferred method when executing multiple commands in a script file.
The `command` string can inject any `${value}` with the following types: string, number, [`childProcess`](#childprocess) or an array of those types. For example: `` $`echo one ${'two'} ${3} ${['four', 'five']}` ``. For `${childProcess}`, the process's `stdout` is used.
For more information, please see [this section](#scripts-interface) and [this page](docs/scripts.md).
#### $(options)
Returns a new instance of [`$`](#command) but with different default `options`. Consecutive calls are merged to previous ones.
This can be used to either:
- Set options for a specific command: `` $(options)`command` ``
- Share options for multiple commands: `` const $$ = $(options); $$`command`; $$`otherCommand`; ``
#### execaCommand(command, options?)
Executes a command. The `command` string includes both the `file` and its `arguments`. Returns a [`childProcess`](#childprocess).
Arguments are [automatically escaped](#shell-syntax). They can contain any character, but spaces must be escaped with a backslash like `execaCommand('echo has\\ space')`.
This is the preferred method when executing a user-supplied `command` string, such as in a REPL.
### execaSync(file, arguments?, options?)
Same as [`execa()`](#execacommandcommand-options) but synchronous.
Returns or throws a [`childProcessResult`](#childProcessResult).
### $.sync\`command\`
Same as [$\`command\`](#command) but synchronous.
Returns or throws a [`childProcessResult`](#childProcessResult).
### execaCommandSync(command, options?)
Same as [`execaCommand()`](#execacommand-command-options) but synchronous.
Returns or throws a [`childProcessResult`](#childProcessResult).
### Shell syntax
For all the [methods above](#methods), no shell interpreter (Bash, cmd.exe, etc.) is used unless the [`shell` option](#shell) is set. This means shell-specific characters and expressions (`$variable`, `&&`, `||`, `;`, `|`, etc.) have no special meaning and do not need to be escaped.
### childProcess
The return value of all [asynchronous methods](#methods) is both:
- a `Promise` resolving or rejecting with a [`childProcessResult`](#childProcessResult).
- a [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess) with the following additional methods and properties.
#### kill(signal?, options?)

@@ -197,31 +318,25 @@

### execaSync(file, arguments?, options?)
#### pipeStdout(target)
Execute a file synchronously.
[Pipe](https://nodejs.org/api/stream.html#readablepipedestination-options) the child process's `stdout` to `target`, which can be:
- Another [`execa()` return value](#pipe-multiple-processes)
- A [writable stream](#save-and-pipe-output-from-a-child-process)
- A [file path string](#redirect-output-to-a-file)
Returns or throws a [`childProcessResult`](#childProcessResult).
If the `target` is another [`execa()` return value](#execacommandcommand-options), it is returned. Otherwise, the original `execa()` return value is returned. This allows chaining `pipeStdout()` then `await`ing the [final result](#childprocessresult).
### execaCommand(command, options?)
The [`stdout` option](#stdout-1) must be kept as `pipe`, its default value.
Same as [`execa()`](#execafile-arguments-options) except both file and arguments are specified in a single `command` string. For example, `execa('echo', ['unicorns'])` is the same as `execaCommand('echo unicorns')`.
#### pipeStderr(target)
If the file or an argument contains spaces, they must be escaped with backslashes. This matters especially if `command` is not a constant but a variable, for example with `__dirname` or `process.cwd()`. Except for spaces, no escaping/quoting is needed.
Like [`pipeStdout()`](#pipestdouttarget) but piping the child process's `stderr` instead.
The [`shell` option](#shell) must be used if the `command` uses shell-specific features (for example, `&&` or `||`), as opposed to being a simple `file` followed by its `arguments`.
The [`stderr` option](#stderr-1) must be kept as `pipe`, its default value.
### execaCommandSync(command, options?)
#### pipeAll(target)
Same as [`execaCommand()`](#execacommand-command-options) but synchronous.
Combines both [`pipeStdout()`](#pipestdouttarget) and [`pipeStderr()`](#pipestderrtarget).
Returns or throws a [`childProcessResult`](#childProcessResult).
Either the [`stdout` option](#stdout-1) or the [`stderr` option](#stderr-1) must be kept as `pipe`, their default value. Also, the [`all` option](#all-2) must be set to `true`.
### execaNode(scriptPath, arguments?, options?)
Execute a Node.js script as a child process.
Same as `execa('node', [scriptPath, ...arguments], options)` except (like [`child_process#fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)):
- the current Node version and options are used. This can be overridden using the [`nodePath`](#nodepath-for-node-only) and [`nodeOptions`](#nodeoptions-for-node-only) options.
- the [`shell`](#shell) option cannot be used
- an extra channel [`ipc`](https://nodejs.org/api/child_process.html#child_process_options_stdio) is passed to [`stdio`](#stdio)
### childProcessResult

@@ -252,3 +367,3 @@

Same as [`command`](#command) but escaped.
Same as [`command`](#command-1) but escaped.

@@ -366,3 +481,3 @@ This is meant to be copy and pasted into a shell, for debugging purposes.

Type: `boolean`\
Default: `false`
Default: `true` with [`$`](#command)/[`$.sync`](#synccommand), `false` otherwise

@@ -408,2 +523,12 @@ Prefer locally installed binaries when looking for a binary to execute.\

If the input is a file, use the [`inputFile` option](#inputfile) instead.
#### inputFile
Type: `string`
Use a file as input to the the `stdin` of your binary.
If the input is not a file, use the [`input` option](#input) instead.
#### stdin

@@ -582,2 +707,11 @@

#### verbose
Type: `boolean`\
Default: `false`
[Print each command](#verbose-mode) on `stderr` before executing it.
This can also be enabled by setting the `NODE_DEBUG=execa` environment variable in the current process.
#### nodePath *(For `.node()` only)*

@@ -614,41 +748,29 @@

### Save and pipe output from a child process
### Cancelling a spawned process
Let's say you want to show the output of a child process in real-time while also saving it to a variable.
```js
import {execa} from 'execa';
const subprocess = execa('echo', ['foo']);
subprocess.stdout.pipe(process.stdout);
const abortController = new AbortController();
const subprocess = execa('node', [], {signal: abortController.signal});
const {stdout} = await subprocess;
console.log('child output:', stdout);
```
setTimeout(() => {
abortController.abort();
}, 1000);
### Redirect output to a file
```js
import {execa} from 'execa';
const subprocess = execa('echo', ['foo'])
subprocess.stdout.pipe(fs.createWriteStream('stdout.txt'))
try {
await subprocess;
} catch (error) {
console.log(subprocess.killed); // true
console.log(error.isCanceled); // true
}
```
### Redirect input from a file
```js
import {execa} from 'execa';
const subprocess = execa('cat')
fs.createReadStream('stdin.txt').pipe(subprocess.stdin)
```
### Execute the current package's binary
```js
import {getBinPathSync} from 'get-bin-path';
import {getBinPath} from 'get-bin-path';
const binPath = getBinPathSync();
const subprocess = execa(binPath);
const binPath = await getBinPath();
await execa(binPath);
```

@@ -655,0 +777,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc