删除 node_modules

This commit is contained in:
2025-06-22 17:27:35 +08:00
parent ebcd00ed99
commit 912d2d4a12
3852 changed files with 0 additions and 1061355 deletions

View File

@@ -1,76 +0,0 @@
import process from 'node:process';
import {
isStream as isNodeStream,
isReadableStream as isNodeReadableStream,
isWritableStream as isNodeWritableStream,
} from 'is-stream';
import {isWritableStream} from './type.js';
// For `stdio[fdNumber]` beyond stdin/stdout/stderr, we need to guess whether the value passed is intended for inputs or outputs.
// This allows us to know whether to pipe _into_ or _from_ the stream.
// When `stdio[fdNumber]` is a single value, this guess is fairly straightforward.
// However, when it is an array instead, we also need to make sure the different values are not incompatible with each other.
export const getStreamDirection = (stdioItems, fdNumber, optionName) => {
const directions = stdioItems.map(stdioItem => getStdioItemDirection(stdioItem, fdNumber));
if (directions.includes('input') && directions.includes('output')) {
throw new TypeError(`The \`${optionName}\` option must not be an array of both readable and writable values.`);
}
return directions.find(Boolean) ?? DEFAULT_DIRECTION;
};
const getStdioItemDirection = ({type, value}, fdNumber) => KNOWN_DIRECTIONS[fdNumber] ?? guessStreamDirection[type](value);
// `stdin`/`stdout`/`stderr` have a known direction
const KNOWN_DIRECTIONS = ['input', 'output', 'output'];
const anyDirection = () => undefined;
const alwaysInput = () => 'input';
// `string` can only be added through the `input` option, i.e. does not need to be handled here
const guessStreamDirection = {
generator: anyDirection,
asyncGenerator: anyDirection,
fileUrl: anyDirection,
filePath: anyDirection,
iterable: alwaysInput,
asyncIterable: alwaysInput,
uint8Array: alwaysInput,
webStream: value => isWritableStream(value) ? 'output' : 'input',
nodeStream(value) {
if (!isNodeReadableStream(value, {checkOpen: false})) {
return 'output';
}
return isNodeWritableStream(value, {checkOpen: false}) ? undefined : 'input';
},
webTransform: anyDirection,
duplex: anyDirection,
native(value) {
const standardStreamDirection = getStandardStreamDirection(value);
if (standardStreamDirection !== undefined) {
return standardStreamDirection;
}
if (isNodeStream(value, {checkOpen: false})) {
return guessStreamDirection.nodeStream(value);
}
},
};
const getStandardStreamDirection = value => {
if ([0, process.stdin].includes(value)) {
return 'input';
}
if ([1, 2, process.stdout, process.stderr].includes(value)) {
return 'output';
}
};
// When ambiguous, we initially keep the direction as `undefined`.
// This allows arrays of `stdio` values to resolve the ambiguity.
// For example, `stdio[3]: DuplexStream` is ambiguous, but `stdio[3]: [DuplexStream, WritableStream]` is not.
// When the ambiguity remains, we default to `output` since it is the most common use case for additional file descriptors.
const DEFAULT_DIRECTION = 'output';

View File

@@ -1,116 +0,0 @@
import {
SPECIAL_DUPLICATE_TYPES_SYNC,
SPECIAL_DUPLICATE_TYPES,
FORBID_DUPLICATE_TYPES,
TYPE_TO_MESSAGE,
} from './type.js';
// Duplicates in the same file descriptor is most likely an error.
// However, this can be useful with generators.
export const filterDuplicates = stdioItems => stdioItems.filter((stdioItemOne, indexOne) =>
stdioItems.every((stdioItemTwo, indexTwo) => stdioItemOne.value !== stdioItemTwo.value
|| indexOne >= indexTwo
|| stdioItemOne.type === 'generator'
|| stdioItemOne.type === 'asyncGenerator'));
// Check if two file descriptors are sharing the same target.
// For example `{stdout: {file: './output.txt'}, stderr: {file: './output.txt'}}`.
export const getDuplicateStream = ({stdioItem: {type, value, optionName}, direction, fileDescriptors, isSync}) => {
const otherStdioItems = getOtherStdioItems(fileDescriptors, type);
if (otherStdioItems.length === 0) {
return;
}
if (isSync) {
validateDuplicateStreamSync({
otherStdioItems,
type,
value,
optionName,
direction,
});
return;
}
if (SPECIAL_DUPLICATE_TYPES.has(type)) {
return getDuplicateStreamInstance({
otherStdioItems,
type,
value,
optionName,
direction,
});
}
if (FORBID_DUPLICATE_TYPES.has(type)) {
validateDuplicateTransform({
otherStdioItems,
type,
value,
optionName,
});
}
};
// Values shared by multiple file descriptors
const getOtherStdioItems = (fileDescriptors, type) => fileDescriptors
.flatMap(({direction, stdioItems}) => stdioItems
.filter(stdioItem => stdioItem.type === type)
.map((stdioItem => ({...stdioItem, direction}))));
// With `execaSync()`, do not allow setting a file path both in input and output
const validateDuplicateStreamSync = ({otherStdioItems, type, value, optionName, direction}) => {
if (SPECIAL_DUPLICATE_TYPES_SYNC.has(type)) {
getDuplicateStreamInstance({
otherStdioItems,
type,
value,
optionName,
direction,
});
}
};
// When two file descriptors share the file or stream, we need to re-use the same underlying stream.
// Otherwise, the stream would be closed twice when piping ends.
// This is only an issue with output file descriptors.
// This is not a problem with generator functions since those create a new instance for each file descriptor.
// We also forbid input and output file descriptors sharing the same file or stream, since that does not make sense.
const getDuplicateStreamInstance = ({otherStdioItems, type, value, optionName, direction}) => {
const duplicateStdioItems = otherStdioItems.filter(stdioItem => hasSameValue(stdioItem, value));
if (duplicateStdioItems.length === 0) {
return;
}
const differentStdioItem = duplicateStdioItems.find(stdioItem => stdioItem.direction !== direction);
throwOnDuplicateStream(differentStdioItem, optionName, type);
return direction === 'output' ? duplicateStdioItems[0].stream : undefined;
};
const hasSameValue = ({type, value}, secondValue) => {
if (type === 'filePath') {
return value.file === secondValue.file;
}
if (type === 'fileUrl') {
return value.href === secondValue.href;
}
return value === secondValue;
};
// We do not allow two file descriptors to share the same Duplex or TransformStream.
// This is because those are set directly to `subprocess.std*`.
// For example, this could result in `subprocess.stdout` and `subprocess.stderr` being the same value.
// This means reading from either would get data from both stdout and stderr.
const validateDuplicateTransform = ({otherStdioItems, type, value, optionName}) => {
const duplicateStdioItem = otherStdioItems.find(({value: {transform}}) => transform === value.transform);
throwOnDuplicateStream(duplicateStdioItem, optionName, type);
};
const throwOnDuplicateStream = (stdioItem, optionName, type) => {
if (stdioItem !== undefined) {
throw new TypeError(`The \`${stdioItem.optionName}\` and \`${optionName}\` options must not target ${TYPE_TO_MESSAGE[type]} that is the same.`);
}
};

View File

@@ -1,52 +0,0 @@
import {createReadStream, createWriteStream} from 'node:fs';
import {Buffer} from 'node:buffer';
import {Readable, Writable, Duplex} from 'node:stream';
import {generatorToStream} from '../transform/generator.js';
import {handleStdio} from './handle.js';
import {TYPE_TO_MESSAGE} from './type.js';
// Handle `input`, `inputFile`, `stdin`, `stdout` and `stderr` options, before spawning, in async mode
export const handleStdioAsync = (options, verboseInfo) => handleStdio(addPropertiesAsync, options, verboseInfo, false);
const forbiddenIfAsync = ({type, optionName}) => {
throw new TypeError(`The \`${optionName}\` option cannot be ${TYPE_TO_MESSAGE[type]}.`);
};
// Create streams used internally for piping when using specific values for the `std*` options, in async mode.
// For example, `stdout: {file}` creates a file stream, which is piped from/to.
const addProperties = {
fileNumber: forbiddenIfAsync,
generator: generatorToStream,
asyncGenerator: generatorToStream,
nodeStream: ({value}) => ({stream: value}),
webTransform({value: {transform, writableObjectMode, readableObjectMode}}) {
const objectMode = writableObjectMode || readableObjectMode;
const stream = Duplex.fromWeb(transform, {objectMode});
return {stream};
},
duplex: ({value: {transform}}) => ({stream: transform}),
native() {},
};
const addPropertiesAsync = {
input: {
...addProperties,
fileUrl: ({value}) => ({stream: createReadStream(value)}),
filePath: ({value: {file}}) => ({stream: createReadStream(file)}),
webStream: ({value}) => ({stream: Readable.fromWeb(value)}),
iterable: ({value}) => ({stream: Readable.from(value)}),
asyncIterable: ({value}) => ({stream: Readable.from(value)}),
string: ({value}) => ({stream: Readable.from(value)}),
uint8Array: ({value}) => ({stream: Readable.from(Buffer.from(value))}),
},
output: {
...addProperties,
fileUrl: ({value}) => ({stream: createWriteStream(value)}),
filePath: ({value: {file, append}}) => ({stream: createWriteStream(file, append ? {flags: 'a'} : {})}),
webStream: ({value}) => ({stream: Writable.fromWeb(value)}),
iterable: forbiddenIfAsync,
asyncIterable: forbiddenIfAsync,
string: forbiddenIfAsync,
uint8Array: forbiddenIfAsync,
},
};

View File

@@ -1,57 +0,0 @@
import {readFileSync} from 'node:fs';
import {bufferToUint8Array} from '../utils/uint-array.js';
import {handleStdio} from './handle.js';
import {TYPE_TO_MESSAGE} from './type.js';
// Normalize `input`, `inputFile`, `stdin`, `stdout` and `stderr` options, before spawning, in sync mode
export const handleStdioSync = (options, verboseInfo) => handleStdio(addPropertiesSync, options, verboseInfo, true);
const forbiddenIfSync = ({type, optionName}) => {
throwInvalidSyncValue(optionName, TYPE_TO_MESSAGE[type]);
};
const forbiddenNativeIfSync = ({optionName, value}) => {
if (value === 'ipc' || value === 'overlapped') {
throwInvalidSyncValue(optionName, `"${value}"`);
}
return {};
};
const throwInvalidSyncValue = (optionName, value) => {
throw new TypeError(`The \`${optionName}\` option cannot be ${value} with synchronous methods.`);
};
// Create streams used internally for redirecting when using specific values for the `std*` options, in sync mode.
// For example, `stdin: {file}` reads the file synchronously, then passes it as the `input` option.
const addProperties = {
generator() {},
asyncGenerator: forbiddenIfSync,
webStream: forbiddenIfSync,
nodeStream: forbiddenIfSync,
webTransform: forbiddenIfSync,
duplex: forbiddenIfSync,
asyncIterable: forbiddenIfSync,
native: forbiddenNativeIfSync,
};
const addPropertiesSync = {
input: {
...addProperties,
fileUrl: ({value}) => ({contents: [bufferToUint8Array(readFileSync(value))]}),
filePath: ({value: {file}}) => ({contents: [bufferToUint8Array(readFileSync(file))]}),
fileNumber: forbiddenIfSync,
iterable: ({value}) => ({contents: [...value]}),
string: ({value}) => ({contents: [value]}),
uint8Array: ({value}) => ({contents: [value]}),
},
output: {
...addProperties,
fileUrl: ({value}) => ({path: value}),
filePath: ({value: {file, append}}) => ({path: file, append}),
fileNumber: ({value}) => ({path: value}),
iterable: forbiddenIfSync,
string: forbiddenIfSync,
uint8Array: forbiddenIfSync,
},
};

View File

@@ -1,214 +0,0 @@
import {getStreamName, isStandardStream} from '../utils/standard-stream.js';
import {normalizeTransforms} from '../transform/normalize.js';
import {getFdObjectMode} from '../transform/object-mode.js';
import {
getStdioItemType,
isRegularUrl,
isUnknownStdioString,
FILE_TYPES,
} from './type.js';
import {getStreamDirection} from './direction.js';
import {normalizeStdioOption} from './stdio-option.js';
import {handleNativeStream} from './native.js';
import {handleInputOptions} from './input-option.js';
import {filterDuplicates, getDuplicateStream} from './duplicate.js';
// Handle `input`, `inputFile`, `stdin`, `stdout` and `stderr` options, before spawning, in async/sync mode
// They are converted into an array of `fileDescriptors`.
// Each `fileDescriptor` is normalized, validated and contains all information necessary for further handling.
export const handleStdio = (addProperties, options, verboseInfo, isSync) => {
const stdio = normalizeStdioOption(options, verboseInfo, isSync);
const initialFileDescriptors = stdio.map((stdioOption, fdNumber) => getFileDescriptor({
stdioOption,
fdNumber,
options,
isSync,
}));
const fileDescriptors = getFinalFileDescriptors({
initialFileDescriptors,
addProperties,
options,
isSync,
});
options.stdio = fileDescriptors.map(({stdioItems}) => forwardStdio(stdioItems));
return fileDescriptors;
};
const getFileDescriptor = ({stdioOption, fdNumber, options, isSync}) => {
const optionName = getStreamName(fdNumber);
const {stdioItems: initialStdioItems, isStdioArray} = initializeStdioItems({
stdioOption,
fdNumber,
options,
optionName,
});
const direction = getStreamDirection(initialStdioItems, fdNumber, optionName);
const stdioItems = initialStdioItems.map(stdioItem => handleNativeStream({
stdioItem,
isStdioArray,
fdNumber,
direction,
isSync,
}));
const normalizedStdioItems = normalizeTransforms(stdioItems, optionName, direction, options);
const objectMode = getFdObjectMode(normalizedStdioItems, direction);
validateFileObjectMode(normalizedStdioItems, objectMode);
return {direction, objectMode, stdioItems: normalizedStdioItems};
};
// We make sure passing an array with a single item behaves the same as passing that item without an array.
// This is what users would expect.
// For example, `stdout: ['ignore']` behaves the same as `stdout: 'ignore'`.
const initializeStdioItems = ({stdioOption, fdNumber, options, optionName}) => {
const values = Array.isArray(stdioOption) ? stdioOption : [stdioOption];
const initialStdioItems = [
...values.map(value => initializeStdioItem(value, optionName)),
...handleInputOptions(options, fdNumber),
];
const stdioItems = filterDuplicates(initialStdioItems);
const isStdioArray = stdioItems.length > 1;
validateStdioArray(stdioItems, isStdioArray, optionName);
validateStreams(stdioItems);
return {stdioItems, isStdioArray};
};
const initializeStdioItem = (value, optionName) => ({
type: getStdioItemType(value, optionName),
value,
optionName,
});
const validateStdioArray = (stdioItems, isStdioArray, optionName) => {
if (stdioItems.length === 0) {
throw new TypeError(`The \`${optionName}\` option must not be an empty array.`);
}
if (!isStdioArray) {
return;
}
for (const {value, optionName} of stdioItems) {
if (INVALID_STDIO_ARRAY_OPTIONS.has(value)) {
throw new Error(`The \`${optionName}\` option must not include \`${value}\`.`);
}
}
};
// Using those `stdio` values 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 validateStreams = stdioItems => {
for (const stdioItem of stdioItems) {
validateFileStdio(stdioItem);
}
};
const validateFileStdio = ({type, value, optionName}) => {
if (isRegularUrl(value)) {
throw new TypeError(`The \`${optionName}: URL\` option must use the \`file:\` scheme.
For example, you can use the \`pathToFileURL()\` method of the \`url\` core module.`);
}
if (isUnknownStdioString(type, value)) {
throw new TypeError(`The \`${optionName}: { file: '...' }\` option must be used instead of \`${optionName}: '...'\`.`);
}
};
const validateFileObjectMode = (stdioItems, objectMode) => {
if (!objectMode) {
return;
}
const fileStdioItem = stdioItems.find(({type}) => FILE_TYPES.has(type));
if (fileStdioItem !== undefined) {
throw new TypeError(`The \`${fileStdioItem.optionName}\` option cannot use both files and transforms in objectMode.`);
}
};
// Some `stdio` values require Execa to create streams.
// For example, file paths create file read/write streams.
// Those transformations are specified in `addProperties`, which is both direction-specific and type-specific.
const getFinalFileDescriptors = ({initialFileDescriptors, addProperties, options, isSync}) => {
const fileDescriptors = [];
try {
for (const fileDescriptor of initialFileDescriptors) {
fileDescriptors.push(getFinalFileDescriptor({
fileDescriptor,
fileDescriptors,
addProperties,
options,
isSync,
}));
}
return fileDescriptors;
} catch (error) {
cleanupCustomStreams(fileDescriptors);
throw error;
}
};
const getFinalFileDescriptor = ({
fileDescriptor: {direction, objectMode, stdioItems},
fileDescriptors,
addProperties,
options,
isSync,
}) => {
const finalStdioItems = stdioItems.map(stdioItem => addStreamProperties({
stdioItem,
addProperties,
direction,
options,
fileDescriptors,
isSync,
}));
return {direction, objectMode, stdioItems: finalStdioItems};
};
const addStreamProperties = ({stdioItem, addProperties, direction, options, fileDescriptors, isSync}) => {
const duplicateStream = getDuplicateStream({
stdioItem,
direction,
fileDescriptors,
isSync,
});
if (duplicateStream !== undefined) {
return {...stdioItem, stream: duplicateStream};
}
return {
...stdioItem,
...addProperties[direction][stdioItem.type](stdioItem, options),
};
};
// The stream error handling is performed by the piping logic above, which cannot be performed before subprocess spawning.
// If the subprocess spawning fails (e.g. due to an invalid command), the streams need to be manually destroyed.
// We need to create those streams before subprocess spawning, in case their creation fails, e.g. when passing an invalid generator as argument.
// Like this, an exception would be thrown, which would prevent spawning a subprocess.
export const cleanupCustomStreams = fileDescriptors => {
for (const {stdioItems} of fileDescriptors) {
for (const {stream} of stdioItems) {
if (stream !== undefined && !isStandardStream(stream)) {
stream.destroy();
}
}
}
};
// When the `std*: Iterable | WebStream | URL | filePath`, `input` or `inputFile` option is used, we pipe to `subprocess.std*`.
// When the `std*: Array` option is used, we emulate some of the native values ('inherit', Node.js stream and file descriptor integer). To do so, we also need to pipe to `subprocess.std*`.
// Therefore the `std*` options must be either `pipe` or `overlapped`. Other values do not set `subprocess.std*`.
const forwardStdio = stdioItems => {
if (stdioItems.length > 1) {
return stdioItems.some(({value}) => value === 'overlapped') ? 'overlapped' : 'pipe';
}
const [{type, value}] = stdioItems;
return type === 'native' ? value : 'pipe';
};

View File

@@ -1,50 +0,0 @@
import {isReadableStream} from 'is-stream';
import {isUint8Array} from '../utils/uint-array.js';
import {isUrl, isFilePathString} from './type.js';
// Append the `stdin` option with the `input` and `inputFile` options
export const handleInputOptions = ({input, inputFile}, fdNumber) => fdNumber === 0
? [
...handleInputOption(input),
...handleInputFileOption(inputFile),
]
: [];
const handleInputOption = input => input === undefined ? [] : [{
type: getInputType(input),
value: input,
optionName: 'input',
}];
const getInputType = input => {
if (isReadableStream(input, {checkOpen: false})) {
return 'nodeStream';
}
if (typeof input === 'string') {
return 'string';
}
if (isUint8Array(input)) {
return 'uint8Array';
}
throw new Error('The `input` option must be a string, a Uint8Array or a Node.js Readable stream.');
};
const handleInputFileOption = inputFile => inputFile === undefined ? [] : [{
...getInputFileType(inputFile),
optionName: 'inputFile',
}];
const getInputFileType = inputFile => {
if (isUrl(inputFile)) {
return {type: 'fileUrl', value: inputFile};
}
if (isFilePathString(inputFile)) {
return {type: 'filePath', value: {file: inputFile}};
}
throw new Error('The `inputFile` option must be a file path string or a file URL.');
};

View File

@@ -1,106 +0,0 @@
import {readFileSync} from 'node:fs';
import tty from 'node:tty';
import {isStream as isNodeStream} from 'is-stream';
import {STANDARD_STREAMS} from '../utils/standard-stream.js';
import {bufferToUint8Array} from '../utils/uint-array.js';
import {serializeOptionValue} from '../arguments/fd-options.js';
// When we use multiple `stdio` values for the same streams, we pass 'pipe' to `child_process.spawn()`.
// We then emulate the piping done by core Node.js.
// To do so, we transform the following values:
// - Node.js streams are marked as `type: nodeStream`
// - 'inherit' becomes `process.stdin|stdout|stderr`
// - any file descriptor integer becomes `process.stdio[fdNumber]`
// All of the above transformations tell Execa to perform manual piping.
export const handleNativeStream = ({stdioItem, stdioItem: {type}, isStdioArray, fdNumber, direction, isSync}) => {
if (!isStdioArray || type !== 'native') {
return stdioItem;
}
return isSync
? handleNativeStreamSync({stdioItem, fdNumber, direction})
: handleNativeStreamAsync({stdioItem, fdNumber});
};
// Synchronous methods use a different logic.
// 'inherit', file descriptors and process.std* are handled by readFileSync()/writeFileSync().
const handleNativeStreamSync = ({stdioItem, stdioItem: {value, optionName}, fdNumber, direction}) => {
const targetFd = getTargetFd({
value,
optionName,
fdNumber,
direction,
});
if (targetFd !== undefined) {
return targetFd;
}
if (isNodeStream(value, {checkOpen: false})) {
throw new TypeError(`The \`${optionName}: Stream\` option cannot both be an array and include a stream with synchronous methods.`);
}
return stdioItem;
};
const getTargetFd = ({value, optionName, fdNumber, direction}) => {
const targetFdNumber = getTargetFdNumber(value, fdNumber);
if (targetFdNumber === undefined) {
return;
}
if (direction === 'output') {
return {type: 'fileNumber', value: targetFdNumber, optionName};
}
if (tty.isatty(targetFdNumber)) {
throw new TypeError(`The \`${optionName}: ${serializeOptionValue(value)}\` option is invalid: it cannot be a TTY with synchronous methods.`);
}
return {type: 'uint8Array', value: bufferToUint8Array(readFileSync(targetFdNumber)), optionName};
};
const getTargetFdNumber = (value, fdNumber) => {
if (value === 'inherit') {
return fdNumber;
}
if (typeof value === 'number') {
return value;
}
const standardStreamIndex = STANDARD_STREAMS.indexOf(value);
if (standardStreamIndex !== -1) {
return standardStreamIndex;
}
};
const handleNativeStreamAsync = ({stdioItem, stdioItem: {value, optionName}, fdNumber}) => {
if (value === 'inherit') {
return {type: 'nodeStream', value: getStandardStream(fdNumber, value, optionName), optionName};
}
if (typeof value === 'number') {
return {type: 'nodeStream', value: getStandardStream(value, value, optionName), optionName};
}
if (isNodeStream(value, {checkOpen: false})) {
return {type: 'nodeStream', value, optionName};
}
return stdioItem;
};
// Node.js does not allow to easily retrieve file descriptors beyond stdin/stdout/stderr as streams.
// - `fs.createReadStream()`/`fs.createWriteStream()` with the `fd` option do not work with character devices that use blocking reads/writes (such as interactive TTYs).
// - Using a TCP `Socket` would work but be rather complex to implement.
// Since this is an edge case, we simply throw an error message.
// See https://github.com/sindresorhus/execa/pull/643#discussion_r1435905707
const getStandardStream = (fdNumber, value, optionName) => {
const standardStream = STANDARD_STREAMS[fdNumber];
if (standardStream === undefined) {
throw new TypeError(`The \`${optionName}: ${value}\` option is invalid: no such standard stream.`);
}
return standardStream;
};

View File

@@ -1,60 +0,0 @@
import {STANDARD_STREAMS_ALIASES} from '../utils/standard-stream.js';
import {normalizeIpcStdioArray} from '../ipc/array.js';
import {isFullVerbose} from '../verbose/values.js';
// Add support for `stdin`/`stdout`/`stderr` as an alias for `stdio`.
// 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));
return isSync
? normalizeStdioSync(stdioArray, buffer, verboseInfo)
: normalizeIpcStdioArray(stdioArray, ipc);
};
const getStdioArray = (stdio, options) => {
if (stdio === undefined) {
return STANDARD_STREAMS_ALIASES.map(alias => options[alias]);
}
if (hasAlias(options)) {
throw new Error(`It's not possible to provide \`stdio\` in combination with one of ${STANDARD_STREAMS_ALIASES.map(alias => `\`${alias}\``).join(', ')}`);
}
if (typeof stdio === 'string') {
return [stdio, stdio, stdio];
}
if (!Array.isArray(stdio)) {
throw new TypeError(`Expected \`stdio\` to be of type \`string\` or \`Array\`, got \`${typeof stdio}\``);
}
const length = Math.max(stdio.length, STANDARD_STREAMS_ALIASES.length);
return Array.from({length}, (_, fdNumber) => stdio[fdNumber]);
};
const hasAlias = options => STANDARD_STREAMS_ALIASES.some(alias => options[alias] !== undefined);
const addDefaultValue = (stdioOption, fdNumber) => {
if (Array.isArray(stdioOption)) {
return stdioOption.map(item => addDefaultValue(item, fdNumber));
}
if (stdioOption === null || stdioOption === undefined) {
return fdNumber >= STANDARD_STREAMS_ALIASES.length ? 'ignore' : 'pipe';
}
return stdioOption;
};
// Using `buffer: false` with synchronous methods implies `stdout`/`stderr`: `ignore`.
// Unless the output is needed, e.g. due to `verbose: 'full'` or to redirecting to a file.
const normalizeStdioSync = (stdioArray, buffer, verboseInfo) => stdioArray.map((stdioOption, fdNumber) =>
!buffer[fdNumber]
&& fdNumber !== 0
&& !isFullVerbose(verboseInfo, fdNumber)
&& isOutputPipeOnly(stdioOption)
? 'ignore'
: stdioOption);
const isOutputPipeOnly = stdioOption => stdioOption === 'pipe'
|| (Array.isArray(stdioOption) && stdioOption.every(item => item === 'pipe'));

173
node_modules/execa/lib/stdio/type.js generated vendored
View File

@@ -1,173 +0,0 @@
import {isStream as isNodeStream, isDuplexStream} from 'is-stream';
import isPlainObj from 'is-plain-obj';
import {isUint8Array} from '../utils/uint-array.js';
// The `stdin`/`stdout`/`stderr` option can be of many types. This detects it.
export const getStdioItemType = (value, optionName) => {
if (isAsyncGenerator(value)) {
return 'asyncGenerator';
}
if (isSyncGenerator(value)) {
return 'generator';
}
if (isUrl(value)) {
return 'fileUrl';
}
if (isFilePathObject(value)) {
return 'filePath';
}
if (isWebStream(value)) {
return 'webStream';
}
if (isNodeStream(value, {checkOpen: false})) {
return 'native';
}
if (isUint8Array(value)) {
return 'uint8Array';
}
if (isAsyncIterableObject(value)) {
return 'asyncIterable';
}
if (isIterableObject(value)) {
return 'iterable';
}
if (isTransformStream(value)) {
return getTransformStreamType({transform: value}, optionName);
}
if (isTransformOptions(value)) {
return getTransformObjectType(value, optionName);
}
return 'native';
};
const getTransformObjectType = (value, optionName) => {
if (isDuplexStream(value.transform, {checkOpen: false})) {
return getDuplexType(value, optionName);
}
if (isTransformStream(value.transform)) {
return getTransformStreamType(value, optionName);
}
return getGeneratorObjectType(value, optionName);
};
const getDuplexType = (value, optionName) => {
validateNonGeneratorType(value, optionName, 'Duplex stream');
return 'duplex';
};
const getTransformStreamType = (value, optionName) => {
validateNonGeneratorType(value, optionName, 'web TransformStream');
return 'webTransform';
};
const validateNonGeneratorType = ({final, binary, objectMode}, optionName, typeName) => {
checkUndefinedOption(final, `${optionName}.final`, typeName);
checkUndefinedOption(binary, `${optionName}.binary`, typeName);
checkBooleanOption(objectMode, `${optionName}.objectMode`);
};
const checkUndefinedOption = (value, optionName, typeName) => {
if (value !== undefined) {
throw new TypeError(`The \`${optionName}\` option can only be defined when using a generator, not a ${typeName}.`);
}
};
const getGeneratorObjectType = ({transform, final, binary, objectMode}, optionName) => {
if (transform !== undefined && !isGenerator(transform)) {
throw new TypeError(`The \`${optionName}.transform\` option must be a generator, a Duplex stream or a web TransformStream.`);
}
if (isDuplexStream(final, {checkOpen: false})) {
throw new TypeError(`The \`${optionName}.final\` option must not be a Duplex stream.`);
}
if (isTransformStream(final)) {
throw new TypeError(`The \`${optionName}.final\` option must not be a web TransformStream.`);
}
if (final !== undefined && !isGenerator(final)) {
throw new TypeError(`The \`${optionName}.final\` option must be a generator.`);
}
checkBooleanOption(binary, `${optionName}.binary`);
checkBooleanOption(objectMode, `${optionName}.objectMode`);
return isAsyncGenerator(transform) || isAsyncGenerator(final) ? 'asyncGenerator' : 'generator';
};
const checkBooleanOption = (value, optionName) => {
if (value !== undefined && typeof value !== 'boolean') {
throw new TypeError(`The \`${optionName}\` option must use a boolean.`);
}
};
const isGenerator = value => isAsyncGenerator(value) || isSyncGenerator(value);
export const isAsyncGenerator = value => Object.prototype.toString.call(value) === '[object AsyncGeneratorFunction]';
const isSyncGenerator = value => Object.prototype.toString.call(value) === '[object GeneratorFunction]';
const isTransformOptions = value => isPlainObj(value)
&& (value.transform !== undefined || value.final !== undefined);
export const isUrl = value => Object.prototype.toString.call(value) === '[object URL]';
export const isRegularUrl = value => isUrl(value) && value.protocol !== 'file:';
const isFilePathObject = value => isPlainObj(value)
&& Object.keys(value).length > 0
&& Object.keys(value).every(key => FILE_PATH_KEYS.has(key))
&& isFilePathString(value.file);
const FILE_PATH_KEYS = new Set(['file', 'append']);
export const isFilePathString = file => typeof file === 'string';
export const isUnknownStdioString = (type, value) => type === 'native'
&& typeof value === 'string'
&& !KNOWN_STDIO_STRINGS.has(value);
const KNOWN_STDIO_STRINGS = new Set(['ipc', 'ignore', 'inherit', 'overlapped', 'pipe']);
const isReadableStream = value => Object.prototype.toString.call(value) === '[object ReadableStream]';
export const isWritableStream = value => Object.prototype.toString.call(value) === '[object WritableStream]';
const isWebStream = value => isReadableStream(value) || isWritableStream(value);
const isTransformStream = value => isReadableStream(value?.readable) && isWritableStream(value?.writable);
const isAsyncIterableObject = value => isObject(value) && typeof value[Symbol.asyncIterator] === 'function';
const isIterableObject = value => isObject(value) && typeof value[Symbol.iterator] === 'function';
const isObject = value => typeof value === 'object' && value !== null;
// Types which modify `subprocess.std*`
export const TRANSFORM_TYPES = new Set(['generator', 'asyncGenerator', 'duplex', 'webTransform']);
// Types which write to a file or a file descriptor
export const FILE_TYPES = new Set(['fileUrl', 'filePath', 'fileNumber']);
// When two file descriptors of this type share the same target, we need to do some special logic
export const SPECIAL_DUPLICATE_TYPES_SYNC = new Set(['fileUrl', 'filePath']);
export const SPECIAL_DUPLICATE_TYPES = new Set([...SPECIAL_DUPLICATE_TYPES_SYNC, 'webStream', 'nodeStream']);
// Do not allow two file descriptors of this type sharing the same target
export const FORBID_DUPLICATE_TYPES = new Set(['webTransform', 'duplex']);
// Convert types to human-friendly strings for error messages
export const TYPE_TO_MESSAGE = {
generator: 'a generator',
asyncGenerator: 'an async generator',
fileUrl: 'a file URL',
filePath: 'a file path string',
fileNumber: 'a file descriptor number',
webStream: 'a web stream',
nodeStream: 'a Node.js stream',
webTransform: 'a web TransformStream',
duplex: 'a Duplex stream',
native: 'any value',
iterable: 'an iterable',
asyncIterable: 'an async iterable',
string: 'a string',
uint8Array: 'a Uint8Array',
};