This commit is contained in:
2025-07-06 20:54:40 +08:00
parent f665eaab54
commit ced488a958
4076 changed files with 1108355 additions and 0 deletions

23
node_modules/execa/lib/methods/bind.js generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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`);
};