* Walk `command` and replace every top-level quoted region with a placeholder * token. Returns the masked string and the array of original quoted substrings * so callers can restore them later. * * Delegates all state-machine logic to `scanTopLevelQuotes`, ensuring * consistent quoting rules wi
(command: string)
| 406 | * a malformed command. |
| 407 | */ |
| 408 | function maskTopLevelQuotes(command: string): { masked: string; quotes: string[] } { |
| 409 | const { spans, unterminatedQuote } = scanTopLevelQuotes(command) |
| 410 | |
| 411 | // If the command has an unterminated quote, treat the unclosed region as a |
| 412 | // span running to the end of the string. This is safe because parseCommand |
| 413 | // already guards against unterminated quotes and returns the raw command as |
| 414 | // a single token before calling maskTopLevelQuotes -- but the fallback |
| 415 | // ensures maskTopLevelQuotes is robust even when called directly. |
| 416 | const effectiveSpans: QuoteSpan[] = |
| 417 | unterminatedQuote !== null |
| 418 | ? [ |
| 419 | ...spans, |
| 420 | { start: unterminatedQuote.openIndex, end: command.length, quoteType: unterminatedQuote.quoteType }, |
| 421 | ] |
| 422 | : spans |
| 423 | |
| 424 | const quotes: string[] = [] |
| 425 | let result = "" |
| 426 | let pos = 0 |
| 427 | |
| 428 | for (const span of effectiveSpans) { |
| 429 | // Copy the unquoted text between the previous span end and this span start. |
| 430 | result += command.slice(pos, span.start) |
| 431 | // Replace the quoted span with a placeholder. |
| 432 | quotes.push(command.slice(span.start, span.end)) |
| 433 | result += `__TOPLEVEL_QUOTE_${quotes.length - 1}__` |
| 434 | pos = span.end |
| 435 | } |
| 436 | |
| 437 | // Copy any remaining text after the last span (or the whole string if no spans). |
| 438 | result += command.slice(pos) |
| 439 | |
| 440 | return { masked: result, quotes } |
| 441 | } |
| 442 | |
| 443 | /** |
| 444 | * Split a command string into individual sub-commands by |
no test coverage detected