fix: handle escaped backslash sequences in quote parsing

Fixed the escape detection logic in joinQuotedLines() to properly count
consecutive backslashes. A quote is only escaped if preceded by an odd
number of backslashes:
- \\" = escaped backslash + closing quote (string ends)
- \\\" = escaped backslash + escaped quote (string continues)

Added test cases to verify the fix.
This commit is contained in:
Roo Code 2025-12-22 22:40:55 +00:00
parent 35c8d13a2b
commit 62d74cbdbd
2 changed files with 26 additions and 2 deletions

View file

@ -77,6 +77,20 @@ describe("joinQuotedLines", () => {
const input = 'bd create "desc\nmore" && npm install\necho done'
expect(joinQuotedLines(input)).toEqual(['bd create "desc\nmore" && npm install', "echo done"])
})
it('should handle escaped backslash before closing quote (\\\\" sequence)', () => {
// \\" means escaped backslash (\\) followed by closing quote (")
// The string should end at the quote, not continue
const input = 'echo "hello\\\\"\necho done'
expect(joinQuotedLines(input)).toEqual(['echo "hello\\\\"', "echo done"])
})
it('should handle escaped backslash followed by escaped quote (\\\\\\" sequence)', () => {
// \\\" means escaped backslash (\\) followed by escaped quote (\")
// The string should continue past the quote
const input = 'echo "hello\\\\\\"world"\necho done'
expect(joinQuotedLines(input)).toEqual(['echo "hello\\\\\\"world"', "echo done"])
})
})
describe("parseCommand", () => {

View file

@ -31,10 +31,20 @@ export function joinQuotedLines(command: string): string[] {
while (i < command.length) {
const char = command[i]
const prevChar = i > 0 ? command[i - 1] : ""
// Handle escape sequences (only in double quotes, single quotes are literal)
const isEscaped = prevChar === "\\" && inDoubleQuote
// Count consecutive backslashes before the current character
// If odd count, the current character is escaped; if even, it's not
// e.g., \" = escaped quote, \\" = escaped backslash + closing quote
let backslashCount = 0
if (inDoubleQuote) {
let j = i - 1
while (j >= 0 && command[j] === "\\") {
backslashCount++
j--
}
}
const isEscaped = backslashCount % 2 === 1
// Handle quote state changes
if (char === '"' && !inSingleQuote && !isEscaped) {