加入了node_modules
添加了新的功能项
This commit is contained in:
23
node_modules/execa/lib/methods/bind.js
generated
vendored
Normal file
23
node_modules/execa/lib/methods/bind.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import isPlainObject from 'is-plain-obj';
|
||||
import {FD_SPECIFIC_OPTIONS} from '../arguments/specific.js';
|
||||
|
||||
// Deep merge specific options like `env`. Shallow merge the other ones.
|
||||
export const mergeOptions = (boundOptions, options) => {
|
||||
const newOptions = Object.fromEntries(
|
||||
Object.entries(options).map(([optionName, optionValue]) => [
|
||||
optionName,
|
||||
mergeOption(optionName, boundOptions[optionName], optionValue),
|
||||
]),
|
||||
);
|
||||
return {...boundOptions, ...newOptions};
|
||||
};
|
||||
|
||||
const mergeOption = (optionName, boundOptionValue, optionValue) => {
|
||||
if (DEEP_OPTIONS.has(optionName) && isPlainObject(boundOptionValue) && isPlainObject(optionValue)) {
|
||||
return {...boundOptionValue, ...optionValue};
|
||||
}
|
||||
|
||||
return optionValue;
|
||||
};
|
||||
|
||||
const DEEP_OPTIONS = new Set(['env', ...FD_SPECIFIC_OPTIONS]);
|
||||
43
node_modules/execa/lib/methods/command.js
generated
vendored
Normal file
43
node_modules/execa/lib/methods/command.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Main logic for `execaCommand()`
|
||||
export const mapCommandAsync = ({file, commandArguments}) => parseCommand(file, commandArguments);
|
||||
|
||||
// Main logic for `execaCommandSync()`
|
||||
export const mapCommandSync = ({file, commandArguments}) => ({...parseCommand(file, commandArguments), isSync: true});
|
||||
|
||||
// Convert `execaCommand(command)` into `execa(file, ...commandArguments)`
|
||||
const parseCommand = (command, unusedArguments) => {
|
||||
if (unusedArguments.length > 0) {
|
||||
throw new TypeError(`The command and its arguments must be passed as a single string: ${command} ${unusedArguments}.`);
|
||||
}
|
||||
|
||||
const [file, ...commandArguments] = parseCommandString(command);
|
||||
return {file, commandArguments};
|
||||
};
|
||||
|
||||
// Convert `command` string into an array of file or arguments to pass to $`${...fileOrCommandArguments}`
|
||||
export const parseCommandString = command => {
|
||||
if (typeof command !== 'string') {
|
||||
throw new TypeError(`The command must be a string: ${String(command)}.`);
|
||||
}
|
||||
|
||||
const trimmedCommand = command.trim();
|
||||
if (trimmedCommand === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const tokens = [];
|
||||
for (const token of trimmedCommand.split(SPACES_REGEXP)) {
|
||||
// Allow spaces to be escaped by a backslash if not meant as a delimiter
|
||||
const previousToken = tokens.at(-1);
|
||||
if (previousToken && previousToken.endsWith('\\')) {
|
||||
// Merge previous token with current one
|
||||
tokens[tokens.length - 1] = `${previousToken.slice(0, -1)} ${token}`;
|
||||
} else {
|
||||
tokens.push(token);
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
};
|
||||
|
||||
const SPACES_REGEXP = / +/g;
|
||||
65
node_modules/execa/lib/methods/create.js
generated
vendored
Normal file
65
node_modules/execa/lib/methods/create.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
import isPlainObject from 'is-plain-obj';
|
||||
import {normalizeParameters} from './parameters.js';
|
||||
import {isTemplateString, parseTemplates} from './template.js';
|
||||
import {execaCoreSync} from './main-sync.js';
|
||||
import {execaCoreAsync} from './main-async.js';
|
||||
import {mergeOptions} from './bind.js';
|
||||
|
||||
// Wraps every exported methods to provide the following features:
|
||||
// - template string syntax: execa`command argument`
|
||||
// - options binding: boundExeca = execa(options)
|
||||
// - optional argument/options: execa(file), execa(file, args), execa(file, options), execa(file, args, options)
|
||||
// `mapArguments()` and `setBoundExeca()` allows for method-specific logic.
|
||||
export const createExeca = (mapArguments, boundOptions, deepOptions, setBoundExeca) => {
|
||||
const createNested = (mapArguments, boundOptions, setBoundExeca) => createExeca(mapArguments, boundOptions, deepOptions, setBoundExeca);
|
||||
const boundExeca = (...execaArguments) => callBoundExeca({
|
||||
mapArguments,
|
||||
deepOptions,
|
||||
boundOptions,
|
||||
setBoundExeca,
|
||||
createNested,
|
||||
}, ...execaArguments);
|
||||
|
||||
if (setBoundExeca !== undefined) {
|
||||
setBoundExeca(boundExeca, createNested, boundOptions);
|
||||
}
|
||||
|
||||
return boundExeca;
|
||||
};
|
||||
|
||||
const callBoundExeca = ({mapArguments, deepOptions = {}, boundOptions = {}, setBoundExeca, createNested}, firstArgument, ...nextArguments) => {
|
||||
if (isPlainObject(firstArgument)) {
|
||||
return createNested(mapArguments, mergeOptions(boundOptions, firstArgument), setBoundExeca);
|
||||
}
|
||||
|
||||
const {file, commandArguments, options, isSync} = parseArguments({
|
||||
mapArguments,
|
||||
firstArgument,
|
||||
nextArguments,
|
||||
deepOptions,
|
||||
boundOptions,
|
||||
});
|
||||
return isSync
|
||||
? execaCoreSync(file, commandArguments, options)
|
||||
: execaCoreAsync(file, commandArguments, options, createNested);
|
||||
};
|
||||
|
||||
const parseArguments = ({mapArguments, firstArgument, nextArguments, deepOptions, boundOptions}) => {
|
||||
const callArguments = isTemplateString(firstArgument)
|
||||
? parseTemplates(firstArgument, nextArguments)
|
||||
: [firstArgument, ...nextArguments];
|
||||
const [initialFile, initialArguments, initialOptions] = normalizeParameters(...callArguments);
|
||||
const mergedOptions = mergeOptions(mergeOptions(deepOptions, boundOptions), initialOptions);
|
||||
const {
|
||||
file = initialFile,
|
||||
commandArguments = initialArguments,
|
||||
options = mergedOptions,
|
||||
isSync = false,
|
||||
} = mapArguments({file: initialFile, commandArguments: initialArguments, options: mergedOptions});
|
||||
return {
|
||||
file,
|
||||
commandArguments,
|
||||
options,
|
||||
isSync,
|
||||
};
|
||||
};
|
||||
193
node_modules/execa/lib/methods/main-async.js
generated
vendored
Normal file
193
node_modules/execa/lib/methods/main-async.js
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
import {setMaxListeners} from 'node:events';
|
||||
import {spawn} from 'node:child_process';
|
||||
import {MaxBufferError} from 'get-stream';
|
||||
import {handleCommand} from '../arguments/command.js';
|
||||
import {normalizeOptions} from '../arguments/options.js';
|
||||
import {SUBPROCESS_OPTIONS} from '../arguments/fd-options.js';
|
||||
import {addIpcMethods} from '../ipc/methods.js';
|
||||
import {makeError, makeSuccessResult} from '../return/result.js';
|
||||
import {handleResult} from '../return/reject.js';
|
||||
import {handleEarlyError} from '../return/early-error.js';
|
||||
import {handleStdioAsync} from '../stdio/handle-async.js';
|
||||
import {stripNewline} from '../io/strip-newline.js';
|
||||
import {pipeOutputAsync} from '../io/output-async.js';
|
||||
import {subprocessKill} from '../terminate/kill.js';
|
||||
import {cleanupOnExit} from '../terminate/cleanup.js';
|
||||
import {pipeToSubprocess} from '../pipe/setup.js';
|
||||
import {makeAllStream} from '../resolve/all-async.js';
|
||||
import {waitForSubprocessResult} from '../resolve/wait-subprocess.js';
|
||||
import {addConvertedStreams} from '../convert/add.js';
|
||||
import {createDeferred} from '../utils/deferred.js';
|
||||
import {mergePromise} from './promise.js';
|
||||
|
||||
// Main shared logic for all async methods: `execa()`, `$`, `execaNode()`
|
||||
export const execaCoreAsync = (rawFile, rawArguments, rawOptions, createNested) => {
|
||||
const {file, commandArguments, command, escapedCommand, startTime, verboseInfo, options, fileDescriptors} = handleAsyncArguments(rawFile, rawArguments, rawOptions);
|
||||
const {subprocess, promise} = spawnSubprocessAsync({
|
||||
file,
|
||||
commandArguments,
|
||||
options,
|
||||
startTime,
|
||||
verboseInfo,
|
||||
command,
|
||||
escapedCommand,
|
||||
fileDescriptors,
|
||||
});
|
||||
subprocess.pipe = pipeToSubprocess.bind(undefined, {
|
||||
source: subprocess,
|
||||
sourcePromise: promise,
|
||||
boundOptions: {},
|
||||
createNested,
|
||||
});
|
||||
mergePromise(subprocess, promise);
|
||||
SUBPROCESS_OPTIONS.set(subprocess, {options, fileDescriptors});
|
||||
return subprocess;
|
||||
};
|
||||
|
||||
// Compute arguments to pass to `child_process.spawn()`
|
||||
const handleAsyncArguments = (rawFile, rawArguments, rawOptions) => {
|
||||
const {command, escapedCommand, startTime, verboseInfo} = handleCommand(rawFile, rawArguments, rawOptions);
|
||||
const {file, commandArguments, options: normalizedOptions} = normalizeOptions(rawFile, rawArguments, rawOptions);
|
||||
const options = handleAsyncOptions(normalizedOptions);
|
||||
const fileDescriptors = handleStdioAsync(options, verboseInfo);
|
||||
return {
|
||||
file,
|
||||
commandArguments,
|
||||
command,
|
||||
escapedCommand,
|
||||
startTime,
|
||||
verboseInfo,
|
||||
options,
|
||||
fileDescriptors,
|
||||
};
|
||||
};
|
||||
|
||||
// Options normalization logic specific to async methods.
|
||||
// Prevent passing the `timeout` option directly to `child_process.spawn()`.
|
||||
const handleAsyncOptions = ({timeout, signal, ...options}) => {
|
||||
if (signal !== undefined) {
|
||||
throw new TypeError('The "signal" option has been renamed to "cancelSignal" instead.');
|
||||
}
|
||||
|
||||
return {...options, timeoutDuration: timeout};
|
||||
};
|
||||
|
||||
const spawnSubprocessAsync = ({file, commandArguments, options, startTime, verboseInfo, command, escapedCommand, fileDescriptors}) => {
|
||||
let subprocess;
|
||||
try {
|
||||
subprocess = spawn(file, commandArguments, options);
|
||||
} catch (error) {
|
||||
return handleEarlyError({
|
||||
error,
|
||||
command,
|
||||
escapedCommand,
|
||||
fileDescriptors,
|
||||
options,
|
||||
startTime,
|
||||
verboseInfo,
|
||||
});
|
||||
}
|
||||
|
||||
const controller = new AbortController();
|
||||
setMaxListeners(Number.POSITIVE_INFINITY, controller.signal);
|
||||
|
||||
const originalStreams = [...subprocess.stdio];
|
||||
pipeOutputAsync(subprocess, fileDescriptors, controller);
|
||||
cleanupOnExit(subprocess, options, controller);
|
||||
|
||||
const context = {};
|
||||
const onInternalError = createDeferred();
|
||||
subprocess.kill = subprocessKill.bind(undefined, {
|
||||
kill: subprocess.kill.bind(subprocess),
|
||||
options,
|
||||
onInternalError,
|
||||
context,
|
||||
controller,
|
||||
});
|
||||
subprocess.all = makeAllStream(subprocess, options);
|
||||
addConvertedStreams(subprocess, options);
|
||||
addIpcMethods(subprocess, options);
|
||||
|
||||
const promise = handlePromise({
|
||||
subprocess,
|
||||
options,
|
||||
startTime,
|
||||
verboseInfo,
|
||||
fileDescriptors,
|
||||
originalStreams,
|
||||
command,
|
||||
escapedCommand,
|
||||
context,
|
||||
onInternalError,
|
||||
controller,
|
||||
});
|
||||
return {subprocess, promise};
|
||||
};
|
||||
|
||||
// Asynchronous logic, as opposed to the previous logic which can be run synchronously, i.e. can be returned to user right away
|
||||
const handlePromise = async ({subprocess, options, startTime, verboseInfo, fileDescriptors, originalStreams, command, escapedCommand, context, onInternalError, controller}) => {
|
||||
const [
|
||||
errorInfo,
|
||||
[exitCode, signal],
|
||||
stdioResults,
|
||||
allResult,
|
||||
ipcOutput,
|
||||
] = await waitForSubprocessResult({
|
||||
subprocess,
|
||||
options,
|
||||
context,
|
||||
verboseInfo,
|
||||
fileDescriptors,
|
||||
originalStreams,
|
||||
onInternalError,
|
||||
controller,
|
||||
});
|
||||
controller.abort();
|
||||
onInternalError.resolve();
|
||||
|
||||
const stdio = stdioResults.map((stdioResult, fdNumber) => stripNewline(stdioResult, options, fdNumber));
|
||||
const all = stripNewline(allResult, options, 'all');
|
||||
const result = getAsyncResult({
|
||||
errorInfo,
|
||||
exitCode,
|
||||
signal,
|
||||
stdio,
|
||||
all,
|
||||
ipcOutput,
|
||||
context,
|
||||
options,
|
||||
command,
|
||||
escapedCommand,
|
||||
startTime,
|
||||
});
|
||||
return handleResult(result, verboseInfo, options);
|
||||
};
|
||||
|
||||
const getAsyncResult = ({errorInfo, exitCode, signal, stdio, all, ipcOutput, context, options, command, escapedCommand, startTime}) => 'error' in errorInfo
|
||||
? makeError({
|
||||
error: errorInfo.error,
|
||||
command,
|
||||
escapedCommand,
|
||||
timedOut: context.terminationReason === 'timeout',
|
||||
isCanceled: context.terminationReason === 'cancel' || context.terminationReason === 'gracefulCancel',
|
||||
isGracefullyCanceled: context.terminationReason === 'gracefulCancel',
|
||||
isMaxBuffer: errorInfo.error instanceof MaxBufferError,
|
||||
isForcefullyTerminated: context.isForcefullyTerminated,
|
||||
exitCode,
|
||||
signal,
|
||||
stdio,
|
||||
all,
|
||||
ipcOutput,
|
||||
options,
|
||||
startTime,
|
||||
isSync: false,
|
||||
})
|
||||
: makeSuccessResult({
|
||||
command,
|
||||
escapedCommand,
|
||||
stdio,
|
||||
all,
|
||||
ipcOutput,
|
||||
options,
|
||||
startTime,
|
||||
});
|
||||
162
node_modules/execa/lib/methods/main-sync.js
generated
vendored
Normal file
162
node_modules/execa/lib/methods/main-sync.js
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
import {spawnSync} from 'node:child_process';
|
||||
import {handleCommand} from '../arguments/command.js';
|
||||
import {normalizeOptions} from '../arguments/options.js';
|
||||
import {makeError, makeEarlyError, makeSuccessResult} from '../return/result.js';
|
||||
import {handleResult} from '../return/reject.js';
|
||||
import {handleStdioSync} from '../stdio/handle-sync.js';
|
||||
import {stripNewline} from '../io/strip-newline.js';
|
||||
import {addInputOptionsSync} from '../io/input-sync.js';
|
||||
import {transformOutputSync} from '../io/output-sync.js';
|
||||
import {getMaxBufferSync} from '../io/max-buffer.js';
|
||||
import {getAllSync} from '../resolve/all-sync.js';
|
||||
import {getExitResultSync} from '../resolve/exit-sync.js';
|
||||
|
||||
// Main shared logic for all sync methods: `execaSync()`, `$.sync()`
|
||||
export const execaCoreSync = (rawFile, rawArguments, rawOptions) => {
|
||||
const {file, commandArguments, command, escapedCommand, startTime, verboseInfo, options, fileDescriptors} = handleSyncArguments(rawFile, rawArguments, rawOptions);
|
||||
const result = spawnSubprocessSync({
|
||||
file,
|
||||
commandArguments,
|
||||
options,
|
||||
command,
|
||||
escapedCommand,
|
||||
verboseInfo,
|
||||
fileDescriptors,
|
||||
startTime,
|
||||
});
|
||||
return handleResult(result, verboseInfo, options);
|
||||
};
|
||||
|
||||
// Compute arguments to pass to `child_process.spawnSync()`
|
||||
const handleSyncArguments = (rawFile, rawArguments, rawOptions) => {
|
||||
const {command, escapedCommand, startTime, verboseInfo} = handleCommand(rawFile, rawArguments, rawOptions);
|
||||
const syncOptions = normalizeSyncOptions(rawOptions);
|
||||
const {file, commandArguments, options} = normalizeOptions(rawFile, rawArguments, syncOptions);
|
||||
validateSyncOptions(options);
|
||||
const fileDescriptors = handleStdioSync(options, verboseInfo);
|
||||
return {
|
||||
file,
|
||||
commandArguments,
|
||||
command,
|
||||
escapedCommand,
|
||||
startTime,
|
||||
verboseInfo,
|
||||
options,
|
||||
fileDescriptors,
|
||||
};
|
||||
};
|
||||
|
||||
// Options normalization logic specific to sync methods
|
||||
const normalizeSyncOptions = options => options.node && !options.ipc ? {...options, ipc: false} : options;
|
||||
|
||||
// Options validation logic specific to sync methods
|
||||
const validateSyncOptions = ({ipc, ipcInput, detached, cancelSignal}) => {
|
||||
if (ipcInput) {
|
||||
throwInvalidSyncOption('ipcInput');
|
||||
}
|
||||
|
||||
if (ipc) {
|
||||
throwInvalidSyncOption('ipc: true');
|
||||
}
|
||||
|
||||
if (detached) {
|
||||
throwInvalidSyncOption('detached: true');
|
||||
}
|
||||
|
||||
if (cancelSignal) {
|
||||
throwInvalidSyncOption('cancelSignal');
|
||||
}
|
||||
};
|
||||
|
||||
const throwInvalidSyncOption = value => {
|
||||
throw new TypeError(`The "${value}" option cannot be used with synchronous methods.`);
|
||||
};
|
||||
|
||||
const spawnSubprocessSync = ({file, commandArguments, options, command, escapedCommand, verboseInfo, fileDescriptors, startTime}) => {
|
||||
const syncResult = runSubprocessSync({
|
||||
file,
|
||||
commandArguments,
|
||||
options,
|
||||
command,
|
||||
escapedCommand,
|
||||
fileDescriptors,
|
||||
startTime,
|
||||
});
|
||||
if (syncResult.failed) {
|
||||
return syncResult;
|
||||
}
|
||||
|
||||
const {resultError, exitCode, signal, timedOut, isMaxBuffer} = getExitResultSync(syncResult, options);
|
||||
const {output, error = resultError} = transformOutputSync({
|
||||
fileDescriptors,
|
||||
syncResult,
|
||||
options,
|
||||
isMaxBuffer,
|
||||
verboseInfo,
|
||||
});
|
||||
const stdio = output.map((stdioOutput, fdNumber) => stripNewline(stdioOutput, options, fdNumber));
|
||||
const all = stripNewline(getAllSync(output, options), options, 'all');
|
||||
return getSyncResult({
|
||||
error,
|
||||
exitCode,
|
||||
signal,
|
||||
timedOut,
|
||||
isMaxBuffer,
|
||||
stdio,
|
||||
all,
|
||||
options,
|
||||
command,
|
||||
escapedCommand,
|
||||
startTime,
|
||||
});
|
||||
};
|
||||
|
||||
const runSubprocessSync = ({file, commandArguments, options, command, escapedCommand, fileDescriptors, startTime}) => {
|
||||
try {
|
||||
addInputOptionsSync(fileDescriptors, options);
|
||||
const normalizedOptions = normalizeSpawnSyncOptions(options);
|
||||
return spawnSync(file, commandArguments, normalizedOptions);
|
||||
} catch (error) {
|
||||
return makeEarlyError({
|
||||
error,
|
||||
command,
|
||||
escapedCommand,
|
||||
fileDescriptors,
|
||||
options,
|
||||
startTime,
|
||||
isSync: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// The `encoding` option is handled by Execa, not by `child_process.spawnSync()`
|
||||
const normalizeSpawnSyncOptions = ({encoding, maxBuffer, ...options}) => ({...options, encoding: 'buffer', maxBuffer: getMaxBufferSync(maxBuffer)});
|
||||
|
||||
const getSyncResult = ({error, exitCode, signal, timedOut, isMaxBuffer, stdio, all, options, command, escapedCommand, startTime}) => error === undefined
|
||||
? makeSuccessResult({
|
||||
command,
|
||||
escapedCommand,
|
||||
stdio,
|
||||
all,
|
||||
ipcOutput: [],
|
||||
options,
|
||||
startTime,
|
||||
})
|
||||
: makeError({
|
||||
error,
|
||||
command,
|
||||
escapedCommand,
|
||||
timedOut,
|
||||
isCanceled: false,
|
||||
isGracefullyCanceled: false,
|
||||
isMaxBuffer,
|
||||
isForcefullyTerminated: false,
|
||||
exitCode,
|
||||
signal,
|
||||
stdio,
|
||||
all,
|
||||
ipcOutput: [],
|
||||
options,
|
||||
startTime,
|
||||
isSync: true,
|
||||
});
|
||||
51
node_modules/execa/lib/methods/node.js
generated
vendored
Normal file
51
node_modules/execa/lib/methods/node.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import {execPath, execArgv} from 'node:process';
|
||||
import path from 'node:path';
|
||||
import {safeNormalizeFileUrl} from '../arguments/file-url.js';
|
||||
|
||||
// `execaNode()` is a shortcut for `execa(..., {node: true})`
|
||||
export const mapNode = ({options}) => {
|
||||
if (options.node === false) {
|
||||
throw new TypeError('The "node" option cannot be false with `execaNode()`.');
|
||||
}
|
||||
|
||||
return {options: {...options, node: true}};
|
||||
};
|
||||
|
||||
// Applies the `node: true` option, and the related `nodePath`/`nodeOptions` options.
|
||||
// Modifies the file commands/arguments to ensure the same Node binary and flags are re-used.
|
||||
// Also adds `ipc: true` and `shell: false`.
|
||||
export const handleNodeOption = (file, commandArguments, {
|
||||
node: shouldHandleNode = false,
|
||||
nodePath = execPath,
|
||||
nodeOptions = execArgv.filter(nodeOption => !nodeOption.startsWith('--inspect')),
|
||||
cwd,
|
||||
execPath: formerNodePath,
|
||||
...options
|
||||
}) => {
|
||||
if (formerNodePath !== undefined) {
|
||||
throw new TypeError('The "execPath" option has been removed. Please use the "nodePath" option instead.');
|
||||
}
|
||||
|
||||
const normalizedNodePath = safeNormalizeFileUrl(nodePath, 'The "nodePath" option');
|
||||
const resolvedNodePath = path.resolve(cwd, normalizedNodePath);
|
||||
const newOptions = {
|
||||
...options,
|
||||
nodePath: resolvedNodePath,
|
||||
node: shouldHandleNode,
|
||||
cwd,
|
||||
};
|
||||
|
||||
if (!shouldHandleNode) {
|
||||
return [file, commandArguments, newOptions];
|
||||
}
|
||||
|
||||
if (path.basename(file, '.exe') === 'node') {
|
||||
throw new TypeError('When the "node" option is true, the first argument does not need to be "node".');
|
||||
}
|
||||
|
||||
return [
|
||||
resolvedNodePath,
|
||||
[...nodeOptions, file, ...commandArguments],
|
||||
{ipc: true, ...newOptions, shell: false},
|
||||
];
|
||||
};
|
||||
31
node_modules/execa/lib/methods/parameters.js
generated
vendored
Normal file
31
node_modules/execa/lib/methods/parameters.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import isPlainObject from 'is-plain-obj';
|
||||
import {safeNormalizeFileUrl} from '../arguments/file-url.js';
|
||||
|
||||
// The command `arguments` and `options` are both optional.
|
||||
// This also does basic validation on them and on the command file.
|
||||
export const normalizeParameters = (rawFile, rawArguments = [], rawOptions = {}) => {
|
||||
const filePath = safeNormalizeFileUrl(rawFile, 'First argument');
|
||||
const [commandArguments, options] = isPlainObject(rawArguments)
|
||||
? [[], rawArguments]
|
||||
: [rawArguments, rawOptions];
|
||||
|
||||
if (!Array.isArray(commandArguments)) {
|
||||
throw new TypeError(`Second argument must be either an array of arguments or an options object: ${commandArguments}`);
|
||||
}
|
||||
|
||||
if (commandArguments.some(commandArgument => typeof commandArgument === 'object' && commandArgument !== null)) {
|
||||
throw new TypeError(`Second argument must be an array of strings: ${commandArguments}`);
|
||||
}
|
||||
|
||||
const normalizedArguments = commandArguments.map(String);
|
||||
const nullByteArgument = normalizedArguments.find(normalizedArgument => normalizedArgument.includes('\0'));
|
||||
if (nullByteArgument !== undefined) {
|
||||
throw new TypeError(`Arguments cannot contain null bytes ("\\0"): ${nullByteArgument}`);
|
||||
}
|
||||
|
||||
if (!isPlainObject(options)) {
|
||||
throw new TypeError(`Last argument must be an options object: ${options}`);
|
||||
}
|
||||
|
||||
return [filePath, normalizedArguments, options];
|
||||
};
|
||||
15
node_modules/execa/lib/methods/promise.js
generated
vendored
Normal file
15
node_modules/execa/lib/methods/promise.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// The return value is a mixin of `subprocess` and `Promise`
|
||||
export const mergePromise = (subprocess, promise) => {
|
||||
for (const [property, descriptor] of descriptors) {
|
||||
const value = descriptor.value.bind(promise);
|
||||
Reflect.defineProperty(subprocess, property, {...descriptor, value});
|
||||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line unicorn/prefer-top-level-await
|
||||
const nativePromisePrototype = (async () => {})().constructor.prototype;
|
||||
|
||||
const descriptors = ['then', 'catch', 'finally'].map(property => [
|
||||
property,
|
||||
Reflect.getOwnPropertyDescriptor(nativePromisePrototype, property),
|
||||
]);
|
||||
22
node_modules/execa/lib/methods/script.js
generated
vendored
Normal file
22
node_modules/execa/lib/methods/script.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// Sets `$.sync` and `$.s`
|
||||
export const setScriptSync = (boundExeca, createNested, boundOptions) => {
|
||||
boundExeca.sync = createNested(mapScriptSync, boundOptions);
|
||||
boundExeca.s = boundExeca.sync;
|
||||
};
|
||||
|
||||
// Main logic for `$`
|
||||
export const mapScriptAsync = ({options}) => getScriptOptions(options);
|
||||
|
||||
// Main logic for `$.sync`
|
||||
const mapScriptSync = ({options}) => ({...getScriptOptions(options), isSync: true});
|
||||
|
||||
// `$` is like `execa` but with script-friendly options: `{stdin: 'inherit', preferLocal: true}`
|
||||
const getScriptOptions = options => ({options: {...getScriptStdinOption(options), ...options}});
|
||||
|
||||
const getScriptStdinOption = ({input, inputFile, stdio}) => input === undefined && inputFile === undefined && stdio === undefined
|
||||
? {stdin: 'inherit'}
|
||||
: {};
|
||||
|
||||
// When using $(...).pipe(...), most script-friendly options should apply to both commands.
|
||||
// However, some options (like `stdin: 'inherit'`) would create issues with piping, i.e. cannot be deep.
|
||||
export const deepScriptOptions = {preferLocal: true};
|
||||
153
node_modules/execa/lib/methods/template.js
generated
vendored
Normal file
153
node_modules/execa/lib/methods/template.js
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
import {ChildProcess} from 'node:child_process';
|
||||
import isPlainObject from 'is-plain-obj';
|
||||
import {isUint8Array, uint8ArrayToString} from '../utils/uint-array.js';
|
||||
|
||||
// Check whether the template string syntax is being used
|
||||
export const isTemplateString = templates => Array.isArray(templates) && Array.isArray(templates.raw);
|
||||
|
||||
// Convert execa`file ...commandArguments` to execa(file, commandArguments)
|
||||
export const parseTemplates = (templates, expressions) => {
|
||||
let tokens = [];
|
||||
|
||||
for (const [index, template] of templates.entries()) {
|
||||
tokens = parseTemplate({
|
||||
templates,
|
||||
expressions,
|
||||
tokens,
|
||||
index,
|
||||
template,
|
||||
});
|
||||
}
|
||||
|
||||
if (tokens.length === 0) {
|
||||
throw new TypeError('Template script must not be empty');
|
||||
}
|
||||
|
||||
const [file, ...commandArguments] = tokens;
|
||||
return [file, commandArguments, {}];
|
||||
};
|
||||
|
||||
const parseTemplate = ({templates, expressions, tokens, index, template}) => {
|
||||
if (template === undefined) {
|
||||
throw new TypeError(`Invalid backslash sequence: ${templates.raw[index]}`);
|
||||
}
|
||||
|
||||
const {nextTokens, leadingWhitespaces, trailingWhitespaces} = splitByWhitespaces(template, templates.raw[index]);
|
||||
const newTokens = concatTokens(tokens, nextTokens, leadingWhitespaces);
|
||||
|
||||
if (index === expressions.length) {
|
||||
return newTokens;
|
||||
}
|
||||
|
||||
const expression = expressions[index];
|
||||
const expressionTokens = Array.isArray(expression)
|
||||
? expression.map(expression => parseExpression(expression))
|
||||
: [parseExpression(expression)];
|
||||
return concatTokens(newTokens, expressionTokens, trailingWhitespaces);
|
||||
};
|
||||
|
||||
// Like `string.split(/[ \t\r\n]+/)` except newlines and tabs are:
|
||||
// - ignored when input as a backslash sequence like: `echo foo\n bar`
|
||||
// - not ignored when input directly
|
||||
// The only way to distinguish those in JavaScript is to use a tagged template and compare:
|
||||
// - the first array argument, which does not escape backslash sequences
|
||||
// - its `raw` property, which escapes them
|
||||
const splitByWhitespaces = (template, rawTemplate) => {
|
||||
if (rawTemplate.length === 0) {
|
||||
return {nextTokens: [], leadingWhitespaces: false, trailingWhitespaces: false};
|
||||
}
|
||||
|
||||
const nextTokens = [];
|
||||
let templateStart = 0;
|
||||
const leadingWhitespaces = DELIMITERS.has(rawTemplate[0]);
|
||||
|
||||
for (
|
||||
let templateIndex = 0, rawIndex = 0;
|
||||
templateIndex < template.length;
|
||||
templateIndex += 1, rawIndex += 1
|
||||
) {
|
||||
const rawCharacter = rawTemplate[rawIndex];
|
||||
if (DELIMITERS.has(rawCharacter)) {
|
||||
if (templateStart !== templateIndex) {
|
||||
nextTokens.push(template.slice(templateStart, templateIndex));
|
||||
}
|
||||
|
||||
templateStart = templateIndex + 1;
|
||||
} else if (rawCharacter === '\\') {
|
||||
const nextRawCharacter = rawTemplate[rawIndex + 1];
|
||||
if (nextRawCharacter === '\n') {
|
||||
// Handles escaped newlines in templates
|
||||
templateIndex -= 1;
|
||||
rawIndex += 1;
|
||||
} else if (nextRawCharacter === 'u' && rawTemplate[rawIndex + 2] === '{') {
|
||||
rawIndex = rawTemplate.indexOf('}', rawIndex + 3);
|
||||
} else {
|
||||
rawIndex += ESCAPE_LENGTH[nextRawCharacter] ?? 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const trailingWhitespaces = templateStart === template.length;
|
||||
if (!trailingWhitespaces) {
|
||||
nextTokens.push(template.slice(templateStart));
|
||||
}
|
||||
|
||||
return {nextTokens, leadingWhitespaces, trailingWhitespaces};
|
||||
};
|
||||
|
||||
const DELIMITERS = new Set([' ', '\t', '\r', '\n']);
|
||||
|
||||
// Number of characters in backslash escape sequences: \0 \xXX or \uXXXX
|
||||
// \cX is allowed in RegExps but not in strings
|
||||
// Octal sequences are not allowed in strict mode
|
||||
const ESCAPE_LENGTH = {x: 3, u: 5};
|
||||
|
||||
const concatTokens = (tokens, nextTokens, isSeparated) => isSeparated
|
||||
|| tokens.length === 0
|
||||
|| nextTokens.length === 0
|
||||
? [...tokens, ...nextTokens]
|
||||
: [
|
||||
...tokens.slice(0, -1),
|
||||
`${tokens.at(-1)}${nextTokens[0]}`,
|
||||
...nextTokens.slice(1),
|
||||
];
|
||||
|
||||
// Handle `${expression}` inside the template string syntax
|
||||
const parseExpression = expression => {
|
||||
const typeOfExpression = typeof expression;
|
||||
|
||||
if (typeOfExpression === 'string') {
|
||||
return expression;
|
||||
}
|
||||
|
||||
if (typeOfExpression === 'number') {
|
||||
return String(expression);
|
||||
}
|
||||
|
||||
if (isPlainObject(expression) && ('stdout' in expression || 'isMaxBuffer' in expression)) {
|
||||
return getSubprocessResult(expression);
|
||||
}
|
||||
|
||||
if (expression instanceof ChildProcess || Object.prototype.toString.call(expression) === '[object Promise]') {
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
throw new TypeError('Unexpected subprocess in template expression. Please use ${await subprocess} instead of ${subprocess}.');
|
||||
}
|
||||
|
||||
throw new TypeError(`Unexpected "${typeOfExpression}" in template expression`);
|
||||
};
|
||||
|
||||
const getSubprocessResult = ({stdout}) => {
|
||||
if (typeof stdout === 'string') {
|
||||
return stdout;
|
||||
}
|
||||
|
||||
if (isUint8Array(stdout)) {
|
||||
return uint8ArrayToString(stdout);
|
||||
}
|
||||
|
||||
if (stdout === undefined) {
|
||||
throw new TypeError('Missing result.stdout in template expression. This is probably due to the previous subprocess\' "stdout" option.');
|
||||
}
|
||||
|
||||
throw new TypeError(`Unexpected "${typeof stdout}" stdout in template expression`);
|
||||
};
|
||||
Reference in New Issue
Block a user