tg-bot-reminder/node_modules/execa/lib/command.js
2023-08-13 16:48:04 +03:00

121 lines
3.0 KiB
JavaScript

import {Buffer} from 'node:buffer';
import {ChildProcess} from 'node:child_process';
const normalizeArgs = (file, args = []) => {
if (!Array.isArray(args)) {
return [file];
}
return [file, ...args];
};
const NO_ESCAPE_REGEXP = /^[\w.-]+$/;
const DOUBLE_QUOTES_REGEXP = /"/g;
const escapeArg = arg => {
if (typeof arg !== 'string' || NO_ESCAPE_REGEXP.test(arg)) {
return arg;
}
return `"${arg.replace(DOUBLE_QUOTES_REGEXP, '\\"')}"`;
};
export const joinCommand = (file, args) => normalizeArgs(file, args).join(' ');
export const getEscapedCommand = (file, args) => normalizeArgs(file, args).map(arg => escapeArg(arg)).join(' ');
const SPACES_REGEXP = / +/g;
// Handle `execaCommand()`
export const parseCommand = command => {
const tokens = [];
for (const token of command.trim().split(SPACES_REGEXP)) {
// Allow spaces to be escaped by a backslash if not meant as a delimiter
const previousToken = tokens[tokens.length - 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 parseExpression = expression => {
const typeOfExpression = typeof expression;
if (typeOfExpression === 'string') {
return expression;
}
if (typeOfExpression === 'number') {
return String(expression);
}
if (
typeOfExpression === 'object'
&& expression !== null
&& !(expression instanceof ChildProcess)
&& 'stdout' in expression
) {
const typeOfStdout = typeof expression.stdout;
if (typeOfStdout === 'string') {
return expression.stdout;
}
if (Buffer.isBuffer(expression.stdout)) {
return expression.stdout.toString();
}
throw new TypeError(`Unexpected "${typeOfStdout}" stdout in template expression`);
}
throw new TypeError(`Unexpected "${typeOfExpression}" in template expression`);
};
const concatTokens = (tokens, nextTokens, isNew) => isNew || tokens.length === 0 || nextTokens.length === 0
? [...tokens, ...nextTokens]
: [
...tokens.slice(0, -1),
`${tokens[tokens.length - 1]}${nextTokens[0]}`,
...nextTokens.slice(1),
];
const parseTemplate = ({templates, expressions, tokens, index, template}) => {
const templateString = template ?? templates.raw[index];
const templateTokens = templateString.split(SPACES_REGEXP).filter(Boolean);
const newTokens = concatTokens(
tokens,
templateTokens,
templateString.startsWith(' '),
);
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,
templateString.endsWith(' '),
);
};
export const parseTemplates = (templates, expressions) => {
let tokens = [];
for (const [index, template] of templates.entries()) {
tokens = parseTemplate({templates, expressions, tokens, index, template});
}
return tokens;
};