File size: 2,041 Bytes
d197cf3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | /** Shared argument splitter for service command lines rendered by platform adapters. */
type ArgSplitEscapeMode = "none" | "backslash" | "backslash-quote-only";
type ArgSplitQuoteChar = '"' | "'";
type ArgSplitQuoteStart = "anywhere" | "item-start";
/** Splits service command strings while preserving quoted arguments across platform parsers. */
export function splitArgsPreservingQuotes(
value: string,
options?: {
escapeMode?: ArgSplitEscapeMode;
quoteChars?: readonly ArgSplitQuoteChar[];
quoteStart?: ArgSplitQuoteStart;
},
): string[] {
const args: string[] = [];
let current = "";
let quoteChar: ArgSplitQuoteChar | null = null;
const escapeMode = options?.escapeMode ?? "none";
const quoteChars = new Set<ArgSplitQuoteChar>(options?.quoteChars ?? ['"']);
const quoteStart = options?.quoteStart ?? "anywhere";
for (let i = 0; i < value.length; i++) {
const char = value.charAt(i);
if (escapeMode === "backslash" && char === "\\") {
// POSIX-style service parsers consume any escaped next byte.
if (i + 1 < value.length) {
current += value[i + 1];
i++;
}
continue;
}
if (
escapeMode === "backslash-quote-only" &&
char === "\\" &&
i + 1 < value.length &&
value[i + 1] === '"'
) {
// Windows cmd scripts escape only renderer-inserted quotes here; paths keep
// their backslashes literal.
current += '"';
i++;
continue;
}
if (quoteChars.has(char as ArgSplitQuoteChar)) {
if (quoteChar === char) {
quoteChar = null;
continue;
}
const canOpenQuote = quoteStart === "anywhere" || current.length === 0;
if (!quoteChar && canOpenQuote) {
quoteChar = char as ArgSplitQuoteChar;
continue;
}
}
if (!quoteChar && /\s/.test(char)) {
if (current) {
args.push(current);
current = "";
}
continue;
}
current += char;
}
if (current) {
args.push(current);
}
return args;
}
|