diff --git a/lib/ipc/array.js b/lib/ipc/array.js index de9e219478..3b54c41a1d 100644 --- a/lib/ipc/array.js +++ b/lib/ipc/array.js @@ -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; diff --git a/lib/stdio/handle-sync.js b/lib/stdio/handle-sync.js index 07b8c2b752..57f62c4dff 100644 --- a/lib/stdio/handle-sync.js +++ b/lib/stdio/handle-sync.js @@ -11,7 +11,7 @@ const forbiddenIfSync = ({type, optionName}) => { }; const forbiddenNativeIfSync = ({optionName, value}) => { - if (value === 'ipc' || value === 'overlapped') { + if (value === 'overlapped') { throwInvalidSyncValue(optionName, `"${value}"`); } diff --git a/lib/stdio/handle.js b/lib/stdio/handle.js index 903134fe00..21ae627ca0 100644 --- a/lib/stdio/handle.js +++ b/lib/stdio/handle.js @@ -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) { diff --git a/lib/stdio/stdio-option.js b/lib/stdio/stdio-option.js index 192cea5b4b..3734f7b7e1 100644 --- a/lib/stdio/stdio-option.js +++ b/lib/stdio/stdio-option.js @@ -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\'`.'); + } +}; + const getStdioArray = (stdio, options) => { if (stdio === undefined) { return STANDARD_STREAMS_ALIASES.map(alias => options[alias]); diff --git a/test-d/return/ignore-other.test-d.ts b/test-d/return/ignore-other.test-d.ts index a4acc0edb7..971ff18fd1 100644 --- a/test-d/return/ignore-other.test-d.ts +++ b/test-d/return/ignore-other.test-d.ts @@ -57,26 +57,6 @@ expectType(inheritStderrErrorSync.stdout); expectType(inheritStderrErrorSync.stderr); expectType(inheritStderrErrorSync.all); -const ipcStdoutResult = await execa('unicorns', {stdout: 'ipc', all: true}); -expectType(ipcStdoutResult.stdout); -expectType(ipcStdoutResult.stderr); -expectType(ipcStdoutResult.all); - -const ipcStderrResult = await execa('unicorns', {stderr: 'ipc', all: true}); -expectType(ipcStderrResult.stdout); -expectType(ipcStderrResult.stderr); -expectType(ipcStderrResult.all); - -const ipcStdoutError = new Error('.') as ExecaError<{stdout: 'ipc'; all: true}>; -expectType(ipcStdoutError.stdout); -expectType(ipcStdoutError.stderr); -expectType(ipcStdoutError.all); - -const ipcStderrError = new Error('.') as ExecaError<{stderr: 'ipc'; all: true}>; -expectType(ipcStderrError.stdout); -expectType(ipcStderrError.stderr); -expectType(ipcStderrError.all); - const streamStdoutResult = await execa('unicorns', {stdout: process.stdout, all: true}); expectType(streamStdoutResult.stdout); expectType(streamStdoutResult.stderr); diff --git a/test-d/stdio/option/ipc.test-d.ts b/test-d/stdio/option/ipc.test-d.ts index 3792a26c97..9f37d9270f 100644 --- a/test-d/stdio/option/ipc.test-d.ts +++ b/test-d/stdio/option/ipc.test-d.ts @@ -1,4 +1,4 @@ -import {expectError, expectAssignable, expectNotAssignable} from 'tsd'; +import {expectError, expectNotAssignable} from 'tsd'; import { execa, execaSync, @@ -8,17 +8,18 @@ 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']})); @@ -26,17 +27,17 @@ 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('ipc'); +expectNotAssignable('ipc'); expectNotAssignable('ipc'); expectNotAssignable(['ipc']); expectNotAssignable(['ipc']); -expectAssignable('ipc'); +expectNotAssignable('ipc'); expectNotAssignable('ipc'); expectNotAssignable(['ipc']); expectNotAssignable(['ipc']); diff --git a/test/arguments/fd-options.js b/test/arguments/fd-options.js index b1653cf5f0..50bcfe0c34 100644 --- a/test/arguments/fd-options.js +++ b/test/arguments/fd-options.js @@ -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'], diff --git a/test/ipc/validation.js b/test/ipc/validation.js index b7e4d72a52..3d76c8fb91 100644 --- a/test/ipc/validation.js +++ b/test/ipc/validation.js @@ -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]()); @@ -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)); diff --git a/test/methods/node.js b/test/methods/node.js index a9bca52933..8411475194 100644 --- a/test/methods/node.js +++ b/test/methods/node.js @@ -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'; diff --git a/test/stdio/handle-invalid.js b/test/stdio/handle-invalid.js index 6e82caa585..e0ea599394 100644 --- a/test/stdio/handle-invalid.js +++ b/test/stdio/handle-invalid.js @@ -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'); @@ -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); diff --git a/test/stdio/handle-options.js b/test/stdio/handle-options.js index 487c764904..62b0928b0e 100644 --- a/test/stdio/handle-options.js +++ b/test/stdio/handle-options.js @@ -14,8 +14,6 @@ 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); @@ -23,8 +21,6 @@ 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); @@ -32,8 +28,6 @@ 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); @@ -41,8 +35,6 @@ 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); diff --git a/test/transform/encoding-ignored.js b/test/transform/encoding-ignored.js index 0a8ffe5cc1..efab68de17 100644 --- a/test/transform/encoding-ignored.js +++ b/test/transform/encoding-ignored.js @@ -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); @@ -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); diff --git a/types/stdio/type.d.ts b/types/stdio/type.d.ts index 52c9d4c973..e85c7b97e4 100644 --- a/types/stdio/type.d.ts +++ b/types/stdio/type.d.ts @@ -3,7 +3,6 @@ import type {ReadableStream, WritableStream, TransformStream} from 'node:stream/ import type { Not, And, - Or, Unless, AndUnless, } from '../utils.js'; @@ -22,7 +21,6 @@ export type StandardStreams = readonly ['stdin', 'stdout', 'stderr']; export type NoStreamStdioOption = | 'ignore' | 'inherit' - | 'ipc' | number | Readable | Writable @@ -47,7 +45,7 @@ type CommonStdioOption< IsExtra extends boolean, IsArray extends boolean, > = - SimpleStdioOption | URL | GeneratorTransform | GeneratorTransformFull | Unless, IsArray>, 3 | 4 | 5 | 6 | 7 | 8 | 9> | Unless, 'ipc'> | Unless | {readonly file: string; readonly append?: boolean}; + SimpleStdioOption | URL | GeneratorTransform | GeneratorTransformFull | Unless, IsArray>, 3 | 4 | 5 | 6 | 7 | 8 | 9> | Unless | {readonly file: string; readonly append?: boolean}; // Synchronous iterables excluding strings, Uint8Arrays and Arrays type IterableObject = Iterable diff --git a/types/utils.d.ts b/types/utils.d.ts index 7aed97deb2..98a831545b 100644 --- a/types/utils.d.ts +++ b/types/utils.d.ts @@ -2,8 +2,6 @@ export type Not = Value extends true ? false : true; export type And = First extends true ? Second : false; -export type Or = First extends true ? true : Second; - export type Unless = Condition extends true ? ElseValue : ThenValue; export type AndUnless = Condition extends true ? ElseValue : ThenValue;