Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sindresorhus/execa
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v8.0.0
Choose a base ref
...
head repository: sindresorhus/execa
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v8.0.1
Choose a head ref
  • 2 commits
  • 6 files changed
  • 2 contributors

Commits on Aug 19, 2023

  1. Verified

    This commit was signed with the committer’s verified signature.
    Okeanos Nikolas Grottendieck
    Copy the full SHA
    89c69fe View commit details
  2. 8.0.1

    ehmicky committed Aug 19, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f4b8b3a View commit details
Showing with 101 additions and 37 deletions.
  1. +34 −14 index.d.ts
  2. +44 −18 index.test-d.ts
  3. +1 −1 lib/stream.js
  4. +1 −1 package.json
  5. +1 −1 readme.md
  6. +20 −2 test/stream.js
48 changes: 34 additions & 14 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -12,7 +12,27 @@ export type StdioOption =
| number
| undefined;

export type CommonOptions<EncodingType> = {
type EncodingOption =
| 'utf8'
// eslint-disable-next-line unicorn/text-encoding-identifier-case
| 'utf-8'
| 'utf16le'
| 'utf-16le'
| 'ucs2'
| 'ucs-2'
| 'latin1'
| 'binary'
| 'ascii'
| 'hex'
| 'base64'
| 'base64url'
| 'buffer'
| null
| undefined;
type DefaultEncodingOption = 'utf8';
type BufferEncodingOption = 'buffer' | null;

export type CommonOptions<EncodingType extends EncodingOption = DefaultEncodingOption> = {
/**
Kill the spawned process when the parent process exits unless either:
- the spawned process is [`detached`](https://nodejs.org/api/child_process.html#child_process_options_detached)
@@ -176,7 +196,7 @@ export type CommonOptions<EncodingType> = {
readonly shell?: boolean | string;

/**
Specify the character encoding used to decode the `stdout` and `stderr` output. If set to `null`, then `stdout` and `stderr` will be a `Buffer` instead of a string.
Specify the character encoding used to decode the `stdout` and `stderr` output. If set to `'buffer'` or `null`, then `stdout` and `stderr` will be a `Buffer` instead of a string.
@default 'utf8'
*/
@@ -253,7 +273,7 @@ export type CommonOptions<EncodingType> = {
readonly verbose?: boolean;
};

export type Options<EncodingType = string> = {
export type Options<EncodingType extends EncodingOption = DefaultEncodingOption> = {
/**
Write some input to the `stdin` of your binary.
@@ -269,7 +289,7 @@ export type Options<EncodingType = string> = {
readonly inputFile?: string;
} & CommonOptions<EncodingType>;

export type SyncOptions<EncodingType = string> = {
export type SyncOptions<EncodingType extends EncodingOption = DefaultEncodingOption> = {
/**
Write some input to the `stdin` of your binary.
@@ -285,7 +305,7 @@ export type SyncOptions<EncodingType = string> = {
readonly inputFile?: string;
} & CommonOptions<EncodingType>;

export type NodeOptions<EncodingType = string> = {
export type NodeOptions<EncodingType extends EncodingOption = DefaultEncodingOption> = {
/**
The Node.js executable to use.
@@ -625,10 +645,10 @@ export function execa(
export function execa(
file: string,
arguments?: readonly string[],
options?: Options<null>
options?: Options<BufferEncodingOption>
): ExecaChildProcess<Buffer>;
export function execa(file: string, options?: Options): ExecaChildProcess;
export function execa(file: string, options?: Options<null>): ExecaChildProcess<Buffer>;
export function execa(file: string, options?: Options<BufferEncodingOption>): ExecaChildProcess<Buffer>;

/**
Same as `execa()` but synchronous.
@@ -698,12 +718,12 @@ export function execaSync(
export function execaSync(
file: string,
arguments?: readonly string[],
options?: SyncOptions<null>
options?: SyncOptions<BufferEncodingOption>
): ExecaSyncReturnValue<Buffer>;
export function execaSync(file: string, options?: SyncOptions): ExecaSyncReturnValue;
export function execaSync(
file: string,
options?: SyncOptions<null>
options?: SyncOptions<BufferEncodingOption>
): ExecaSyncReturnValue<Buffer>;

/**
@@ -729,7 +749,7 @@ console.log(stdout);
```
*/
export function execaCommand(command: string, options?: Options): ExecaChildProcess;
export function execaCommand(command: string, options?: Options<null>): ExecaChildProcess<Buffer>;
export function execaCommand(command: string, options?: Options<BufferEncodingOption>): ExecaChildProcess<Buffer>;

/**
Same as `execaCommand()` but synchronous.
@@ -748,7 +768,7 @@ console.log(stdout);
```
*/
export function execaCommandSync(command: string, options?: SyncOptions): ExecaSyncReturnValue;
export function execaCommandSync(command: string, options?: SyncOptions<null>): ExecaSyncReturnValue<Buffer>;
export function execaCommandSync(command: string, options?: SyncOptions<BufferEncodingOption>): ExecaSyncReturnValue<Buffer>;

type TemplateExpression =
| string
@@ -783,7 +803,7 @@ type Execa$<StdoutStderrType extends StdoutStderrAll = string> = {
*/
(options: Options<undefined>): Execa$<StdoutStderrType>;
(options: Options): Execa$;
(options: Options<null>): Execa$<Buffer>;
(options: Options<BufferEncodingOption>): Execa$<Buffer>;
(
templates: TemplateStringsArray,
...expressions: TemplateExpression[]
@@ -929,7 +949,7 @@ export function execaNode(
export function execaNode(
scriptPath: string,
arguments?: readonly string[],
options?: NodeOptions<null>
options?: NodeOptions<BufferEncodingOption>
): ExecaChildProcess<Buffer>;
export function execaNode(scriptPath: string, options?: NodeOptions): ExecaChildProcess;
export function execaNode(scriptPath: string, options?: NodeOptions<null>): ExecaChildProcess<Buffer>;
export function execaNode(scriptPath: string, options?: NodeOptions<BufferEncodingOption>): ExecaChildProcess<Buffer>;
62 changes: 44 additions & 18 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ try {
execaPromise.cancel();
expectType<ReadableStream | undefined>(execaPromise.all);

const execaBufferPromise = execa('unicorns', {encoding: null});
const execaBufferPromise = execa('unicorns', {encoding: 'buffer'});
const writeStream = createWriteStream('output.txt');

expectAssignable<Function | undefined>(execaPromise.pipeStdout);
@@ -133,6 +133,7 @@ execa('unicorns', {cleanup: false});
execa('unicorns', {preferLocal: false});
execa('unicorns', {localDir: '.'});
execa('unicorns', {localDir: new URL('file:///test')});
expectError(execa('unicorns', {encoding: 'unknownEncoding'}));
execa('unicorns', {execPath: '/path'});
execa('unicorns', {buffer: false});
execa('unicorns', {input: ''});
@@ -207,10 +208,14 @@ expectType<ExecaReturnValue>(await execa('unicorns'));
expectType<ExecaReturnValue>(
await execa('unicorns', {encoding: 'utf8'}),
);
expectType<ExecaReturnValue<Buffer>>(await execa('unicorns', {encoding: 'buffer'}));
expectType<ExecaReturnValue<Buffer>>(await execa('unicorns', {encoding: null}));
expectType<ExecaReturnValue>(
await execa('unicorns', ['foo'], {encoding: 'utf8'}),
);
expectType<ExecaReturnValue<Buffer>>(
await execa('unicorns', ['foo'], {encoding: 'buffer'}),
);
expectType<ExecaReturnValue<Buffer>>(
await execa('unicorns', ['foo'], {encoding: null}),
);
@@ -219,47 +224,67 @@ expectType<ExecaSyncReturnValue>(execaSync('unicorns'));
expectType<ExecaSyncReturnValue>(
execaSync('unicorns', {encoding: 'utf8'}),
);
expectType<ExecaSyncReturnValue<Buffer>>(
execaSync('unicorns', {encoding: 'buffer'}),
);
expectType<ExecaSyncReturnValue<Buffer>>(
execaSync('unicorns', {encoding: null}),
);
expectType<ExecaSyncReturnValue>(
execaSync('unicorns', ['foo'], {encoding: 'utf8'}),
);
expectType<ExecaSyncReturnValue<Buffer>>(
execaSync('unicorns', ['foo'], {encoding: 'buffer'}),
);
expectType<ExecaSyncReturnValue<Buffer>>(
execaSync('unicorns', ['foo'], {encoding: null}),
);

expectType<ExecaChildProcess>(execaCommand('unicorns'));
expectType<ExecaReturnValue>(await execaCommand('unicorns'));
expectType<ExecaReturnValue>(await execaCommand('unicorns', {encoding: 'utf8'}));
expectType<ExecaReturnValue<Buffer>>(await execaCommand('unicorns', {encoding: 'buffer'}));
expectType<ExecaReturnValue<Buffer>>(await execaCommand('unicorns', {encoding: null}));
expectType<ExecaReturnValue>(await execaCommand('unicorns foo', {encoding: 'utf8'}));
expectType<ExecaReturnValue<Buffer>>(await execaCommand('unicorns foo', {encoding: 'buffer'}));
expectType<ExecaReturnValue<Buffer>>(await execaCommand('unicorns foo', {encoding: null}));

expectType<ExecaSyncReturnValue>(execaCommandSync('unicorns'));
expectType<ExecaSyncReturnValue>(execaCommandSync('unicorns', {encoding: 'utf8'}));
expectType<ExecaSyncReturnValue<Buffer>>(execaCommandSync('unicorns', {encoding: 'buffer'}));
expectType<ExecaSyncReturnValue<Buffer>>(execaCommandSync('unicorns', {encoding: null}));
expectType<ExecaSyncReturnValue>(execaCommandSync('unicorns foo', {encoding: 'utf8'}));
expectType<ExecaSyncReturnValue<Buffer>>(execaCommandSync('unicorns foo', {encoding: 'buffer'}));
expectType<ExecaSyncReturnValue<Buffer>>(execaCommandSync('unicorns foo', {encoding: null}));

expectType<ExecaChildProcess>(execaNode('unicorns'));
expectType<ExecaReturnValue>(await execaNode('unicorns'));
expectType<ExecaReturnValue>(
await execaNode('unicorns', {encoding: 'utf8'}),
);
expectType<ExecaReturnValue<Buffer>>(await execaNode('unicorns', {encoding: 'buffer'}));
expectType<ExecaReturnValue<Buffer>>(await execaNode('unicorns', {encoding: null}));
expectType<ExecaReturnValue>(
await execaNode('unicorns', ['foo'], {encoding: 'utf8'}),
);
expectType<ExecaReturnValue<Buffer>>(
await execaNode('unicorns', ['foo'], {encoding: 'buffer'}),
);
expectType<ExecaReturnValue<Buffer>>(
await execaNode('unicorns', ['foo'], {encoding: null}),
);

expectType<ExecaChildProcess>(execaNode('unicorns', {nodeOptions: ['--async-stack-traces']}));
expectType<ExecaChildProcess>(execaNode('unicorns', ['foo'], {nodeOptions: ['--async-stack-traces']}));
expectType<ExecaChildProcess<Buffer>>(
execaNode('unicorns', {nodeOptions: ['--async-stack-traces'], encoding: 'buffer'}),
);
expectType<ExecaChildProcess<Buffer>>(
execaNode('unicorns', {nodeOptions: ['--async-stack-traces'], encoding: null}),
);
expectType<ExecaChildProcess<Buffer>>(
execaNode('unicorns', ['foo'], {nodeOptions: ['--async-stack-traces'], encoding: 'buffer'}),
);
expectType<ExecaChildProcess<Buffer>>(
execaNode('unicorns', ['foo'], {nodeOptions: ['--async-stack-traces'], encoding: null}),
);
@@ -277,28 +302,29 @@ expectType<ExecaReturnValue>(await $({encoding: 'utf8'})`unicorns foo`);
expectType<ExecaSyncReturnValue>($({encoding: 'utf8'}).sync`unicorns foo`);

expectType<ExecaChildProcess<Buffer>>($({encoding: null})`unicorns`);
expectType<ExecaReturnValue<Buffer>>(await $({encoding: null})`unicorns`);
expectType<ExecaSyncReturnValue<Buffer>>($({encoding: null}).sync`unicorns`);
expectType<ExecaChildProcess<Buffer>>($({encoding: 'buffer'})`unicorns`);
expectType<ExecaReturnValue<Buffer>>(await $({encoding: 'buffer'})`unicorns`);
expectType<ExecaSyncReturnValue<Buffer>>($({encoding: 'buffer'}).sync`unicorns`);

expectType<ExecaChildProcess<Buffer>>($({encoding: null})`unicorns foo`);
expectType<ExecaReturnValue<Buffer>>(await $({encoding: null})`unicorns foo`);
expectType<ExecaSyncReturnValue<Buffer>>($({encoding: null}).sync`unicorns foo`);
expectType<ExecaChildProcess<Buffer>>($({encoding: 'buffer'})`unicorns foo`);
expectType<ExecaReturnValue<Buffer>>(await $({encoding: 'buffer'})`unicorns foo`);
expectType<ExecaSyncReturnValue<Buffer>>($({encoding: 'buffer'}).sync`unicorns foo`);

expectType<ExecaChildProcess>($({encoding: null})({encoding: 'utf8'})`unicorns`);
expectType<ExecaReturnValue>(await $({encoding: null})({encoding: 'utf8'})`unicorns`);
expectType<ExecaSyncReturnValue>($({encoding: null})({encoding: 'utf8'}).sync`unicorns`);
expectType<ExecaChildProcess>($({encoding: 'buffer'})({encoding: 'utf8'})`unicorns`);
expectType<ExecaReturnValue>(await $({encoding: 'buffer'})({encoding: 'utf8'})`unicorns`);
expectType<ExecaSyncReturnValue>($({encoding: 'buffer'})({encoding: 'utf8'}).sync`unicorns`);

expectType<ExecaChildProcess>($({encoding: null})({encoding: 'utf8'})`unicorns foo`);
expectType<ExecaReturnValue>(await $({encoding: null})({encoding: 'utf8'})`unicorns foo`);
expectType<ExecaSyncReturnValue>($({encoding: null})({encoding: 'utf8'}).sync`unicorns foo`);
expectType<ExecaChildProcess>($({encoding: 'buffer'})({encoding: 'utf8'})`unicorns foo`);
expectType<ExecaReturnValue>(await $({encoding: 'buffer'})({encoding: 'utf8'})`unicorns foo`);
expectType<ExecaSyncReturnValue>($({encoding: 'buffer'})({encoding: 'utf8'}).sync`unicorns foo`);

expectType<ExecaChildProcess<Buffer>>($({encoding: null})({})`unicorns`);
expectType<ExecaReturnValue<Buffer>>(await $({encoding: null})({})`unicorns`);
expectType<ExecaSyncReturnValue<Buffer>>($({encoding: null})({}).sync`unicorns`);
expectType<ExecaChildProcess<Buffer>>($({encoding: 'buffer'})({})`unicorns`);
expectType<ExecaReturnValue<Buffer>>(await $({encoding: 'buffer'})({})`unicorns`);
expectType<ExecaSyncReturnValue<Buffer>>($({encoding: 'buffer'})({}).sync`unicorns`);

expectType<ExecaChildProcess<Buffer>>($({encoding: null})({})`unicorns foo`);
expectType<ExecaReturnValue<Buffer>>(await $({encoding: null})({})`unicorns foo`);
expectType<ExecaSyncReturnValue<Buffer>>($({encoding: null})({}).sync`unicorns foo`);
expectType<ExecaChildProcess<Buffer>>($({encoding: 'buffer'})({})`unicorns foo`);
expectType<ExecaReturnValue<Buffer>>(await $({encoding: 'buffer'})({})`unicorns foo`);
expectType<ExecaSyncReturnValue<Buffer>>($({encoding: 'buffer'})({}).sync`unicorns foo`);

expectType<ExecaReturnValue>(await $`unicorns ${'foo'}`);
expectType<ExecaSyncReturnValue>($.sync`unicorns ${'foo'}`);
2 changes: 1 addition & 1 deletion lib/stream.js
Original file line number Diff line number Diff line change
@@ -102,7 +102,7 @@ const getStreamPromise = (stream, {encoding, buffer, maxBuffer}) => {
return getStream(stream, {maxBuffer});
}

if (encoding === null) {
if (encoding === null || encoding === 'buffer') {
return getStreamAsBuffer(stream, {maxBuffer});
}

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "execa",
"version": "8.0.0",
"version": "8.0.1",
"description": "Process execution for humans",
"license": "MIT",
"repository": "sindresorhus/execa",
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
@@ -682,7 +682,7 @@ We recommend against using this option since it is:
Type: `string | null`\
Default: `utf8`

Specify the character encoding used to decode the `stdout` and `stderr` output. If set to `null`, then `stdout` and `stderr` will be a `Buffer` instead of a string.
Specify the character encoding used to decode the `stdout` and `stderr` output. If set to `'buffer'` or `null`, then `stdout` and `stderr` will be a `Buffer` instead of a string.

#### timeout

22 changes: 20 additions & 2 deletions test/stream.js
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@ import tempfile from 'tempfile';
import {execa, execaSync, $} from '../index.js';
import {setFixtureDir, FIXTURES_DIR} from './helpers/fixtures-dir.js';

const pExec = promisify(exec);

setFixtureDir();

test('buffer', async t => {
@@ -21,14 +23,15 @@ test('buffer', async t => {

const checkEncoding = async (t, encoding) => {
const {stdout} = await execa('noop-no-newline.js', [STRING_TO_ENCODE], {encoding});
t.is(stdout, Buffer.from(STRING_TO_ENCODE).toString(encoding));
t.is(stdout, BUFFER_TO_ENCODE.toString(encoding));

const {stdout: nativeStdout} = await promisify(exec)(`node noop-no-newline.js ${STRING_TO_ENCODE}`, {encoding, cwd: FIXTURES_DIR});
const {stdout: nativeStdout} = await pExec(`node noop-no-newline.js ${STRING_TO_ENCODE}`, {encoding, cwd: FIXTURES_DIR});
t.is(stdout, nativeStdout);
};

// This string gives different outputs with each encoding type
const STRING_TO_ENCODE = '\u1000.';
const BUFFER_TO_ENCODE = Buffer.from(STRING_TO_ENCODE);

test('can pass encoding "utf8"', checkEncoding, 'utf8');
test('can pass encoding "utf-8"', checkEncoding, 'utf8');
@@ -43,6 +46,21 @@ test('can pass encoding "hex"', checkEncoding, 'hex');
test('can pass encoding "base64"', checkEncoding, 'base64');
test('can pass encoding "base64url"', checkEncoding, 'base64url');

const checkBufferEncoding = async (t, encoding) => {
const {stdout} = await execa('noop-no-newline.js', [STRING_TO_ENCODE], {encoding});
t.true(BUFFER_TO_ENCODE.equals(stdout));

const {stdout: nativeStdout} = await pExec(`node noop-no-newline.js ${STRING_TO_ENCODE}`, {encoding, cwd: FIXTURES_DIR});
t.true(BUFFER_TO_ENCODE.equals(nativeStdout));
};

test('can pass encoding "buffer"', checkBufferEncoding, 'buffer');
test('can pass encoding null', checkBufferEncoding, null);

test('validate unknown encodings', async t => {
await t.throwsAsync(execa('noop.js', {encoding: 'unknownEncoding'}), {code: 'ERR_UNKNOWN_ENCODING'});
});

test('pass `stdout` to a file descriptor', async t => {
const file = tempfile({extension: '.txt'});
await execa('noop.js', ['foo bar'], {stdout: fs.openSync(file, 'w')});