Support escaped $ in expected output lines

This commit is contained in:
Chris Wanstrath 2026-03-12 15:22:38 -07:00
parent d927d79758
commit e829c67e88
3 changed files with 19 additions and 5 deletions

View File

@ -105,6 +105,13 @@ describe("parse", () => {
expect(result.commands[0]!.expected).toEqual(["@env PORT=3000"]) expect(result.commands[0]!.expected).toEqual(["@env PORT=3000"])
}) })
test("escaped dollar sign in expected output", () => {
const content = "$ echo '$ hello'\n\\$ hello\n"
const result = parse("test.shout", content)
expect(result.commands).toHaveLength(1)
expect(result.commands[0]!.expected).toEqual(["$ hello"])
})
test("no directives returns empty array", () => { test("no directives returns empty array", () => {
const result = parse("test.shout", "$ echo hi\nhi\n") const result = parse("test.shout", "$ echo hi\nhi\n")
expect(result.directives).toEqual([]) expect(result.directives).toEqual([])

View File

@ -134,7 +134,10 @@ export function parse(path: string, content: string): ShoutFile {
continue continue
} }
if (line.startsWith("$ ")) { if (line.startsWith("\\$ ") && current) {
// Escaped dollar-space: literal expected output starting with "$ "
current.expected.push(line.slice(1))
} else if (line.startsWith("$ ")) {
seenCommand = true seenCommand = true
if (current) { if (current) {
const trimmed = trimTrailingEmpty(current.expected) const trimmed = trimTrailingEmpty(current.expected)

View File

@ -15,7 +15,7 @@ export function rewriteFile(
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const line = lines[i]! const line = lines[i]!
if (line.startsWith("$ ")) { if (line.startsWith("$ ") && !line.startsWith("\\$ ")) {
// Emit the command line as-is // Emit the command line as-is
output.push(line) output.push(line)
@ -28,7 +28,7 @@ export function rewriteFile(
// Skip past old expected output lines in the original // Skip past old expected output lines in the original
let j = i + 1 let j = i + 1
while (j < lines.length && !lines[j]!.startsWith("$ ")) { while (j < lines.length && !(lines[j]!.startsWith("$ ") && !lines[j]!.startsWith("\\$ "))) {
j++ j++
} }
// Collect old expected lines (before trimming trailing blanks for separator) // Collect old expected lines (before trimming trailing blanks for separator)
@ -56,8 +56,8 @@ export function rewriteFile(
// Output original lines as-is // Output original lines as-is
for (const ol of oldExpectedRaw) output.push(ol) for (const ol of oldExpectedRaw) output.push(ol)
} else { } else {
// Replace with actual output // Replace with actual output (escape lines starting with "$ ")
for (const al of result.actual) output.push(al) for (const al of result.actual) output.push(escapeDollar(al))
// Re-add exit code marker if it existed // Re-add exit code marker if it existed
if (oldExitMarker) output.push(oldExitMarker) if (oldExitMarker) output.push(oldExitMarker)
// Preserve trailing blank lines as separators // Preserve trailing blank lines as separators
@ -76,6 +76,10 @@ export function rewriteFile(
return output.join("\n") return output.join("\n")
} }
function escapeDollar(line: string): string {
return line.startsWith("$ ") ? "\\" + line : line
}
function trimTrailingEmpty(lines: string[]): string[] { function trimTrailingEmpty(lines: string[]): string[] {
let end = lines.length let end = lines.length
while (end > 0 && lines[end - 1] === "") end-- while (end > 0 && lines[end - 1] === "") end--