Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/ipc/array.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// The `ipc` option adds an `ipc` item to the `stdio` option
export const normalizeIpcStdioArray = (stdioArray, ipc) => ipc && !stdioArray.includes('ipc')
export const normalizeIpcStdioArray = (stdioArray, ipc) => ipc
? [...stdioArray, 'ipc']
: stdioArray;
2 changes: 1 addition & 1 deletion lib/stdio/handle-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const forbiddenIfSync = ({type, optionName}) => {
};

const forbiddenNativeIfSync = ({optionName, value}) => {
if (value === 'ipc' || value === 'overlapped') {
if (value === 'overlapped') {
throwInvalidSyncValue(optionName, `"${value}"`);
}

Expand Down
4 changes: 2 additions & 2 deletions lib/stdio/handle.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ const validateStdioArray = (stdioItems, isStdioArray, optionName) => {
}
};

// Using those `stdio` values together with others for the same stream does not make sense, so we make it fail.
// Using the `ignore` value together with others for the same stream does not make sense, so we make it fail.
// However, we do allow it if the array has a single item.
const INVALID_STDIO_ARRAY_OPTIONS = new Set(['ignore', 'ipc']);
const INVALID_STDIO_ARRAY_OPTIONS = new Set(['ignore']);

const validateStreams = stdioItems => {
for (const stdioItem of stdioItems) {
Expand Down
8 changes: 8 additions & 0 deletions lib/stdio/stdio-option.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ import {isFullVerbose} from '../verbose/values.js';
// Also normalize the `stdio` option.
export const normalizeStdioOption = ({stdio, ipc, buffer, ...options}, verboseInfo, isSync) => {
const stdioArray = getStdioArray(stdio, options).map((stdioOption, fdNumber) => addDefaultValue(stdioOption, fdNumber));
validateIpcStdioOption(stdioArray);
return isSync
? normalizeStdioSync(stdioArray, buffer, verboseInfo)
: normalizeIpcStdioArray(stdioArray, ipc);
};

// The `stdio: 'ipc'` value (raw `child_process` syntax) was replaced by the `ipc: true` option
const validateIpcStdioOption = stdioArray => {
if (stdioArray.some(stdioOption => Array.isArray(stdioOption) ? stdioOption.includes('ipc') : stdioOption === 'ipc')) {
throw new Error('The `ipc: true` option must be used instead of `stdio: \'ipc\'`.');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice warning message.

}
};

const getStdioArray = (stdio, options) => {
if (stdio === undefined) {
return STANDARD_STREAMS_ALIASES.map(alias => options[alias]);
Expand Down
20 changes: 0 additions & 20 deletions test-d/return/ignore-other.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,6 @@ expectType<string>(inheritStderrErrorSync.stdout);
expectType<undefined>(inheritStderrErrorSync.stderr);
expectType<string>(inheritStderrErrorSync.all);

const ipcStdoutResult = await execa('unicorns', {stdout: 'ipc', all: true});
expectType<undefined>(ipcStdoutResult.stdout);
expectType<string>(ipcStdoutResult.stderr);
expectType<string>(ipcStdoutResult.all);

const ipcStderrResult = await execa('unicorns', {stderr: 'ipc', all: true});
expectType<string>(ipcStderrResult.stdout);
expectType<undefined>(ipcStderrResult.stderr);
expectType<string>(ipcStderrResult.all);

const ipcStdoutError = new Error('.') as ExecaError<{stdout: 'ipc'; all: true}>;
expectType<undefined>(ipcStdoutError.stdout);
expectType<string>(ipcStdoutError.stderr);
expectType<string>(ipcStdoutError.all);

const ipcStderrError = new Error('.') as ExecaError<{stderr: 'ipc'; all: true}>;
expectType<string>(ipcStderrError.stdout);
expectType<undefined>(ipcStderrError.stderr);
expectType<string>(ipcStderrError.all);

const streamStdoutResult = await execa('unicorns', {stdout: process.stdout, all: true});
expectType<undefined>(streamStdoutResult.stdout);
expectType<string>(streamStdoutResult.stderr);
Expand Down
15 changes: 8 additions & 7 deletions test-d/stdio/option/ipc.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {expectError, expectAssignable, expectNotAssignable} from 'tsd';
import {expectError, expectNotAssignable} from 'tsd';
import {
execa,
execaSync,
Expand All @@ -8,35 +8,36 @@ import {
type StdoutStderrSyncOption,
} from '../../../index.js';

await execa('unicorns', {stdin: 'ipc'});
// The `stdio: 'ipc'` value (raw `child_process` syntax) was replaced by the `ipc: true` option
expectError(await execa('unicorns', {stdin: 'ipc'}));
expectError(execaSync('unicorns', {stdin: 'ipc'}));
expectError(await execa('unicorns', {stdin: ['ipc']}));
expectError(execaSync('unicorns', {stdin: ['ipc']}));

await execa('unicorns', {stdout: 'ipc'});
expectError(await execa('unicorns', {stdout: 'ipc'}));
expectError(execaSync('unicorns', {stdout: 'ipc'}));
expectError(await execa('unicorns', {stdout: ['ipc']}));
expectError(execaSync('unicorns', {stdout: ['ipc']}));

await execa('unicorns', {stderr: 'ipc'});
expectError(await execa('unicorns', {stderr: 'ipc'}));
expectError(execaSync('unicorns', {stderr: 'ipc'}));
expectError(await execa('unicorns', {stderr: ['ipc']}));
expectError(execaSync('unicorns', {stderr: ['ipc']}));

expectError(await execa('unicorns', {stdio: 'ipc'}));
expectError(execaSync('unicorns', {stdio: 'ipc'}));

await execa('unicorns', {stdio: ['pipe', 'pipe', 'pipe', 'ipc']});
expectError(await execa('unicorns', {stdio: ['pipe', 'pipe', 'pipe', 'ipc']}));
expectError(execaSync('unicorns', {stdio: ['pipe', 'pipe', 'pipe', 'ipc']}));
expectError(await execa('unicorns', {stdio: ['pipe', 'pipe', 'pipe', ['ipc']]}));
expectError(execaSync('unicorns', {stdio: ['pipe', 'pipe', 'pipe', ['ipc']]}));

expectAssignable<StdinOption>('ipc');
expectNotAssignable<StdinOption>('ipc');
expectNotAssignable<StdinSyncOption>('ipc');
expectNotAssignable<StdinOption>(['ipc']);
expectNotAssignable<StdinSyncOption>(['ipc']);

expectAssignable<StdoutStderrOption>('ipc');
expectNotAssignable<StdoutStderrOption>('ipc');
expectNotAssignable<StdoutStderrSyncOption>('ipc');
expectNotAssignable<StdoutStderrOption>(['ipc']);
expectNotAssignable<StdoutStderrSyncOption>(['ipc']);
21 changes: 0 additions & 21 deletions test/arguments/fd-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -619,27 +619,6 @@ test('Cannot set "stdin" option to "inherit" to use .duplex()', testNodeStream,
message: ['stdin', '\'inherit\''],
writable: true,
});
test('Cannot set "stdout" option to "ipc" to use .pipe()', testPipeError, {
sourceOptions: {stdout: 'ipc'},
message: ['stdout', '\'ipc\''],
});
test('Cannot set "stdout" option to "ipc" to use .duplex()', testNodeStream, {
sourceOptions: {stdout: 'ipc'},
message: ['stdout', '\'ipc\''],
});
test('Cannot set "stdout" option to "ipc" to use .iterable()', testIterable, {
sourceOptions: {stdout: 'ipc'},
message: ['stdout', '\'ipc\''],
});
test('Cannot set "stdin" option to "ipc" to use .pipe()', testPipeError, {
destinationOptions: {stdin: 'ipc'},
message: ['stdin', '\'ipc\''],
});
test('Cannot set "stdin" option to "ipc" to use .duplex()', testNodeStream, {
sourceOptions: {stdin: 'ipc'},
message: ['stdin', '\'ipc\''],
writable: true,
});
test('Cannot set "stdout" option to file descriptors to use .pipe()', testPipeError, {
sourceOptions: {stdout: 1},
message: ['stdout', '1'],
Expand Down
6 changes: 0 additions & 6 deletions test/ipc/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ import test from 'ava';
import {execa} from '../../index.js';
import {setFixtureDirectory} from '../helpers/fixtures-directory.js';
import {foobarString} from '../helpers/input.js';
import {getStdio} from '../helpers/stdio.js';

setFixtureDirectory();

const stdioIpc = getStdio(3, 'ipc');

const testRequiredIpcSubprocess = async (t, methodName, options) => {
const subprocess = execa('empty.js', options);
const {message} = await t.throws(() => subprocess[methodName]());
Expand All @@ -17,13 +14,10 @@ const testRequiredIpcSubprocess = async (t, methodName, options) => {

test('Cannot use subprocess.sendMessage() without ipc option', testRequiredIpcSubprocess, 'sendMessage', {});
test('Cannot use subprocess.sendMessage() with ipc: false', testRequiredIpcSubprocess, 'sendMessage', {ipc: false});
test('Cannot use subprocess.sendMessage() with stdio: [..., "ipc"]', testRequiredIpcSubprocess, 'sendMessage', stdioIpc);
test('Cannot use subprocess.getOneMessage() without ipc option', testRequiredIpcSubprocess, 'getOneMessage', {});
test('Cannot use subprocess.getOneMessage() with ipc: false', testRequiredIpcSubprocess, 'getOneMessage', {ipc: false});
test('Cannot use subprocess.getOneMessage() with stdio: [..., "ipc"]', testRequiredIpcSubprocess, 'getOneMessage', stdioIpc);
test('Cannot use subprocess.getEachMessage() without ipc option', testRequiredIpcSubprocess, 'getEachMessage', {});
test('Cannot use subprocess.getEachMessage() with ipc: false', testRequiredIpcSubprocess, 'getEachMessage', {ipc: false});
test('Cannot use subprocess.getEachMessage() with stdio: [..., "ipc"]', testRequiredIpcSubprocess, 'getEachMessage', stdioIpc);

const testRequiredIpcExports = async (t, methodName, options) => {
const {message} = await t.throwsAsync(execa('ipc-any.js', [methodName], options));
Expand Down
1 change: 0 additions & 1 deletion test/methods/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ test('The "node" option adds an ipc channel', testIpc, runWithNodeOption, {});
test('The "ipc" option adds an ipc channel', testIpc, runWithIpc, {});
test('The "ipc" option works with "stdio: \'pipe\'"', testIpc, runWithIpc, {stdio: 'pipe'});
test('The "ipc" option works with "stdio: [\'pipe\', \'pipe\', \'pipe\']"', testIpc, runWithIpc, {stdio: ['pipe', 'pipe', 'pipe']});
test('The "ipc" option works with "stdio: [\'pipe\', \'pipe\', \'pipe\', \'ipc\']"', testIpc, runWithIpc, {stdio: ['pipe', 'pipe', 'pipe', 'ipc']});
test('The "ipc" option works with "stdout: \'pipe\'"', testIpc, runWithIpc, {stdout: 'pipe'});

const NO_SEND_MESSAGE = 'sendMessage() can only be used';
Expand Down
34 changes: 22 additions & 12 deletions test/stdio/handle-invalid.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ const testInvalidValueSync = (t, fdNumber, stdioOption) => {
t.true(message.includes(`cannot be "${stdioOption}" with synchronous methods`));
};

test('stdin cannot be "ipc", sync', testInvalidValueSync, 0, 'ipc');
test('stdout cannot be "ipc", sync', testInvalidValueSync, 1, 'ipc');
test('stderr cannot be "ipc", sync', testInvalidValueSync, 2, 'ipc');
test('stdio[*] cannot be "ipc", sync', testInvalidValueSync, 3, 'ipc');
test('stdin cannot be "overlapped", sync', testInvalidValueSync, 0, 'overlapped');
test('stdout cannot be "overlapped", sync', testInvalidValueSync, 1, 'overlapped');
test('stderr cannot be "overlapped", sync', testInvalidValueSync, 2, 'overlapped');
Expand All @@ -50,11 +46,25 @@ test('Cannot pass "ignore" and another value to stdin - sync', testInvalidArrayV
test('Cannot pass "ignore" and another value to stdout - sync', testInvalidArrayValue, 'ignore', 1, execaSync);
test('Cannot pass "ignore" and another value to stderr - sync', testInvalidArrayValue, 'ignore', 2, execaSync);
test('Cannot pass "ignore" and another value to stdio[*] - sync', testInvalidArrayValue, 'ignore', 3, execaSync);
test('Cannot pass "ipc" and another value to stdin', testInvalidArrayValue, 'ipc', 0, execa);
test('Cannot pass "ipc" and another value to stdout', testInvalidArrayValue, 'ipc', 1, execa);
test('Cannot pass "ipc" and another value to stderr', testInvalidArrayValue, 'ipc', 2, execa);
test('Cannot pass "ipc" and another value to stdio[*]', testInvalidArrayValue, 'ipc', 3, execa);
test('Cannot pass "ipc" and another value to stdin - sync', testInvalidArrayValue, 'ipc', 0, execaSync);
test('Cannot pass "ipc" and another value to stdout - sync', testInvalidArrayValue, 'ipc', 1, execaSync);
test('Cannot pass "ipc" and another value to stderr - sync', testInvalidArrayValue, 'ipc', 2, execaSync);
test('Cannot pass "ipc" and another value to stdio[*] - sync', testInvalidArrayValue, 'ipc', 3, execaSync);

// The `stdio: 'ipc'` value (raw `child_process` syntax) was replaced by the `ipc: true` option
const testIpcStdioOption = (t, fdNumber, stdioOption, execaMethod) => {
t.throws(() => {
execaMethod('empty.js', getStdio(fdNumber, stdioOption));
}, {message: /The `ipc: true` option must be used instead/});
};

test('stdin cannot be "ipc"', testIpcStdioOption, 0, 'ipc', execa);
test('stdout cannot be "ipc"', testIpcStdioOption, 1, 'ipc', execa);
test('stderr cannot be "ipc"', testIpcStdioOption, 2, 'ipc', execa);
test('stdio[*] cannot be "ipc"', testIpcStdioOption, 3, 'ipc', execa);
test('stdin cannot be "ipc" - sync', testIpcStdioOption, 0, 'ipc', execaSync);
test('stdout cannot be "ipc" - sync', testIpcStdioOption, 1, 'ipc', execaSync);
test('stderr cannot be "ipc" - sync', testIpcStdioOption, 2, 'ipc', execaSync);
test('stdio[*] cannot be "ipc" - sync', testIpcStdioOption, 3, 'ipc', execaSync);
test('stdio cannot be "ipc"', testIpcStdioOption, 'stdio', 'ipc', execa);
test('stdio cannot be "ipc" - sync', testIpcStdioOption, 'stdio', 'ipc', execaSync);
test('stdio[*] cannot be ["ipc"]', testIpcStdioOption, 3, ['ipc'], execa);
test('stdio[*] cannot be ["ipc"] - sync', testIpcStdioOption, 3, ['ipc'], execaSync);
test('Cannot pass "ipc" and another value to stdio[*]', testIpcStdioOption, 3, ['pipe', 'ipc'], execa);
test('Cannot pass "ipc" and another value to stdio[*] - sync', testIpcStdioOption, 3, ['pipe', 'ipc'], execaSync);
8 changes: 0 additions & 8 deletions test/stdio/handle-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,27 @@ const testNoPipeOption = async (t, stdioOption, fdNumber) => {
test('stdin can be "ignore"', testNoPipeOption, 'ignore', 0);
test('stdin can be ["ignore"]', testNoPipeOption, ['ignore'], 0);
test('stdin can be ["ignore", "ignore"]', testNoPipeOption, ['ignore', 'ignore'], 0);
test('stdin can be "ipc"', testNoPipeOption, 'ipc', 0);
test('stdin can be ["ipc"]', testNoPipeOption, ['ipc'], 0);
test('stdin can be "inherit"', testNoPipeOption, 'inherit', 0);
test('stdin can be ["inherit"]', testNoPipeOption, ['inherit'], 0);
test('stdin can be 0', testNoPipeOption, 0, 0);
test('stdin can be [0]', testNoPipeOption, [0], 0);
test('stdout can be "ignore"', testNoPipeOption, 'ignore', 1);
test('stdout can be ["ignore"]', testNoPipeOption, ['ignore'], 1);
test('stdout can be ["ignore", "ignore"]', testNoPipeOption, ['ignore', 'ignore'], 1);
test('stdout can be "ipc"', testNoPipeOption, 'ipc', 1);
test('stdout can be ["ipc"]', testNoPipeOption, ['ipc'], 1);
test('stdout can be "inherit"', testNoPipeOption, 'inherit', 1);
test('stdout can be ["inherit"]', testNoPipeOption, ['inherit'], 1);
test('stdout can be 1', testNoPipeOption, 1, 1);
test('stdout can be [1]', testNoPipeOption, [1], 1);
test('stderr can be "ignore"', testNoPipeOption, 'ignore', 2);
test('stderr can be ["ignore"]', testNoPipeOption, ['ignore'], 2);
test('stderr can be ["ignore", "ignore"]', testNoPipeOption, ['ignore', 'ignore'], 2);
test('stderr can be "ipc"', testNoPipeOption, 'ipc', 2);
test('stderr can be ["ipc"]', testNoPipeOption, ['ipc'], 2);
test('stderr can be "inherit"', testNoPipeOption, 'inherit', 2);
test('stderr can be ["inherit"]', testNoPipeOption, ['inherit'], 2);
test('stderr can be 2', testNoPipeOption, 2, 2);
test('stderr can be [2]', testNoPipeOption, [2], 2);
test('stdio[*] can be "ignore"', testNoPipeOption, 'ignore', 3);
test('stdio[*] can be ["ignore"]', testNoPipeOption, ['ignore'], 3);
test('stdio[*] can be ["ignore", "ignore"]', testNoPipeOption, ['ignore', 'ignore'], 3);
test('stdio[*] can be "ipc"', testNoPipeOption, 'ipc', 3);
test('stdio[*] can be ["ipc"]', testNoPipeOption, ['ipc'], 3);
test('stdio[*] can be "inherit"', testNoPipeOption, 'inherit', 3);
test('stdio[*] can be ["inherit"]', testNoPipeOption, ['inherit'], 3);
test('stdio[*] can be 3', testNoPipeOption, 3, 3);
Expand Down
4 changes: 0 additions & 4 deletions test/transform/encoding-ignored.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ const base64Options = {encoding: 'base64'};
const linesOptions = {lines: true};
test('Is ignored with other encodings and "ignore"', testIgnoredEncoding, 'ignore', true, base64Options, execa);
test('Is ignored with other encodings and ["ignore"]', testIgnoredEncoding, ['ignore'], true, base64Options, execa);
test('Is ignored with other encodings and "ipc"', testIgnoredEncoding, 'ipc', true, base64Options, execa);
test('Is ignored with other encodings and ["ipc"]', testIgnoredEncoding, ['ipc'], true, base64Options, execa);
test('Is ignored with other encodings and "inherit"', testIgnoredEncoding, 'inherit', true, base64Options, execa);
test('Is ignored with other encodings and ["inherit"]', testIgnoredEncoding, ['inherit'], true, base64Options, execa);
test('Is ignored with other encodings and 1', testIgnoredEncoding, 1, true, base64Options, execa);
Expand All @@ -47,8 +45,6 @@ test('Is not ignored with other encodings and undefined', testIgnoredEncoding, u
test('Is not ignored with other encodings and null', testIgnoredEncoding, null, false, base64Options, execa);
test('Is ignored with "lines: true" and "ignore"', testIgnoredEncoding, 'ignore', true, linesOptions, execa);
test('Is ignored with "lines: true" and ["ignore"]', testIgnoredEncoding, ['ignore'], true, linesOptions, execa);
test('Is ignored with "lines: true" and "ipc"', testIgnoredEncoding, 'ipc', true, linesOptions, execa);
test('Is ignored with "lines: true" and ["ipc"]', testIgnoredEncoding, ['ipc'], true, linesOptions, execa);
test('Is ignored with "lines: true" and "inherit"', testIgnoredEncoding, 'inherit', true, linesOptions, execa);
test('Is ignored with "lines: true" and ["inherit"]', testIgnoredEncoding, ['inherit'], true, linesOptions, execa);
test('Is ignored with "lines: true" and 1', testIgnoredEncoding, 1, true, linesOptions, execa);
Expand Down
4 changes: 1 addition & 3 deletions types/stdio/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type {ReadableStream, WritableStream, TransformStream} from 'node:stream/
import type {
Not,
And,
Or,
Unless,
AndUnless,
} from '../utils.js';
Expand All @@ -22,7 +21,6 @@ export type StandardStreams = readonly ['stdin', 'stdout', 'stderr'];
export type NoStreamStdioOption<FdNumber extends string> =
| 'ignore'
| 'inherit'
| 'ipc'
| number
| Readable
| Writable
Expand All @@ -47,7 +45,7 @@ type CommonStdioOption<
IsExtra extends boolean,
IsArray extends boolean,
> =
SimpleStdioOption<IsSync, IsExtra, IsArray> | URL | GeneratorTransform<IsSync> | GeneratorTransformFull<IsSync> | Unless<And<Not<IsSync>, IsArray>, 3 | 4 | 5 | 6 | 7 | 8 | 9> | Unless<Or<IsSync, IsArray>, 'ipc'> | Unless<IsSync, DuplexTransform | WebTransform | TransformStream> | {readonly file: string; readonly append?: boolean};
SimpleStdioOption<IsSync, IsExtra, IsArray> | URL | GeneratorTransform<IsSync> | GeneratorTransformFull<IsSync> | Unless<And<Not<IsSync>, IsArray>, 3 | 4 | 5 | 6 | 7 | 8 | 9> | Unless<IsSync, DuplexTransform | WebTransform | TransformStream> | {readonly file: string; readonly append?: boolean};

// Synchronous iterables excluding strings, Uint8Arrays and Arrays
type IterableObject<IsArray extends boolean> = Iterable<unknown>
Expand Down
2 changes: 0 additions & 2 deletions types/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ export type Not<Value extends boolean> = Value extends true ? false : true;

export type And<First extends boolean, Second extends boolean> = First extends true ? Second : false;

export type Or<First extends boolean, Second extends boolean> = First extends true ? true : Second;

export type Unless<Condition extends boolean, ThenValue, ElseValue = never> = Condition extends true ? ElseValue : ThenValue;

export type AndUnless<Condition extends boolean, ThenValue, ElseValue = unknown> = Condition extends true ? ElseValue : ThenValue;
Expand Down
Loading