删除 node_modules
This commit is contained in:
76
node_modules/execa/lib/stdio/direction.js
generated
vendored
76
node_modules/execa/lib/stdio/direction.js
generated
vendored
@@ -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';
|
||||
116
node_modules/execa/lib/stdio/duplicate.js
generated
vendored
116
node_modules/execa/lib/stdio/duplicate.js
generated
vendored
@@ -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.`);
|
||||
}
|
||||
};
|
||||
52
node_modules/execa/lib/stdio/handle-async.js
generated
vendored
52
node_modules/execa/lib/stdio/handle-async.js
generated
vendored
@@ -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,
|
||||
},
|
||||
};
|
||||
57
node_modules/execa/lib/stdio/handle-sync.js
generated
vendored
57
node_modules/execa/lib/stdio/handle-sync.js
generated
vendored
@@ -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,
|
||||
},
|
||||
};
|
||||
214
node_modules/execa/lib/stdio/handle.js
generated
vendored
214
node_modules/execa/lib/stdio/handle.js
generated
vendored
@@ -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';
|
||||
};
|
||||
50
node_modules/execa/lib/stdio/input-option.js
generated
vendored
50
node_modules/execa/lib/stdio/input-option.js
generated
vendored
@@ -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.');
|
||||
};
|
||||
106
node_modules/execa/lib/stdio/native.js
generated
vendored
106
node_modules/execa/lib/stdio/native.js
generated
vendored
@@ -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;
|
||||
};
|
||||
60
node_modules/execa/lib/stdio/stdio-option.js
generated
vendored
60
node_modules/execa/lib/stdio/stdio-option.js
generated
vendored
@@ -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
173
node_modules/execa/lib/stdio/type.js
generated
vendored
@@ -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',
|
||||
};
|
||||
Reference in New Issue
Block a user