Add support for $# comment lines in parser

This commit is contained in:
Chris Wanstrath 2026-03-12 16:12:38 -07:00
parent d3c9178958
commit 1ddee9ea9e
3 changed files with 55 additions and 3 deletions

View File

@ -127,6 +127,38 @@ describe("parse", () => {
expect(result.commands[0]!.expected).toEqual(["hi"])
})
test("$# comment line is skipped", () => {
const result = parse("test.shout", "$# start the server\n$ echo hi\nhi\n")
expect(result.commands).toHaveLength(1)
expect(result.commands[0]!.command).toBe("echo hi")
})
test("$# comment between commands", () => {
const result = parse("test.shout", "$ echo one\none\n$# now do two\n$ echo two\ntwo\n")
expect(result.commands).toHaveLength(2)
expect(result.commands[0]!.expected).toEqual(["one"])
expect(result.commands[1]!.expected).toEqual(["two"])
})
test("$# comment with space after hash", () => {
const result = parse("test.shout", "$ # server setup\n$ echo hi\nhi\n")
expect(result.commands).toHaveLength(1)
expect(result.commands[0]!.command).toBe("echo hi")
})
test("$# comment as last line", () => {
const result = parse("test.shout", "$ echo hi\nhi\n$# done\n")
expect(result.commands).toHaveLength(1)
expect(result.commands[0]!.expected).toEqual(["hi"])
})
test("output after $# comment is ignored", () => {
const result = parse("test.shout", "$ echo hi\nhi\n$# comment\nstray line\n$ echo bye\nbye\n")
expect(result.commands).toHaveLength(2)
expect(result.commands[0]!.expected).toEqual(["hi"])
expect(result.commands[1]!.expected).toEqual(["bye"])
})
test("no directives returns empty array", () => {
const result = parse("test.shout", "$ echo hi\nhi\n")
expect(result.directives).toEqual([])

View File

@ -32,6 +32,11 @@ function stripComment(line: string): string {
return line
}
/** A line like "$# ..." or "$ # ..." — a comment, not a real command */
export function isCommentLine(line: string): boolean {
return line.startsWith("$#") || (line.startsWith("$ ") && stripComment(line.slice(2)) === "")
}
function parseExitCode(lines: string[]): {
lines: string[]
exitCode: number | "*" | null
@ -134,7 +139,18 @@ export function parse(path: string, content: string): ShoutFile {
continue
}
if (line.startsWith("\\$ ") && current) {
if (isCommentLine(line)) {
// Comment line like "$# ..." or "$ # ..." — finalize current and skip
seenCommand = true
if (current) {
const trimmed = trimTrailingEmpty(current.expected)
const { lines: expectedLines, exitCode } = parseExitCode(trimmed)
current.expected = trimTrailingEmpty(expectedLines)
current.exitCode = exitCode
commands.push(current)
}
current = null
} else if (line.startsWith("\\$ ") && current) {
// Escaped dollar-space: literal expected output starting with "$ "
current.expected.push(line.slice(1))
} else if (line.startsWith("$ ")) {

View File

@ -1,6 +1,7 @@
import type { CommandResult } from "./run.ts"
import type { ShoutFile } from "./parse.ts"
import { matchOutput, matchLine } from "./match.ts"
import { isCommentLine } from "./parse.ts"
export function rewriteFile(
file: ShoutFile,
@ -15,7 +16,10 @@ export function rewriteFile(
for (let i = 0; i < lines.length; i++) {
const line = lines[i]!
if (line.startsWith("$ ") && !line.startsWith("\\$ ")) {
if (isCommentLine(line)) {
// Preserve comment lines as-is
output.push(line)
} else if (line.startsWith("$ ") && !line.startsWith("\\$ ")) {
// Emit the command line as-is
output.push(line)
@ -28,7 +32,7 @@ export function rewriteFile(
// Skip past old expected output lines in the original
let j = i + 1
while (j < lines.length && !(lines[j]!.startsWith("$ ") && !lines[j]!.startsWith("\\$ "))) {
while (j < lines.length && !isCommentLine(lines[j]!) && !(lines[j]!.startsWith("$ ") && !lines[j]!.startsWith("\\$ "))) {
j++
}
// Collect old expected lines (before trimming trailing blanks for separator)