test(release): treat escaped shell separators as literal text

The scanner honoured backslash escapes inside double quotes but not
outside them, so an escaped separator such as find's -exec ... \; still
broke a line into a bare command position.

Consume an unquoted backslash and the character after it before the
comment and separator checks.
This commit is contained in:
sudacode
2026-08-23 04:31:52 -07:00
parent 107c6d1b06
commit db96659b14
2 changed files with 16 additions and 0 deletions
+8
View File
@@ -38,6 +38,14 @@ test('stepRunsCommand ignores separators inside quotes and inline comments', ()
assert.equal(stepRunsCommand({ run: 'gh release view "$V" 2>&1 | tee log' }, /^tee\b/), true);
});
test('stepRunsCommand treats backslash-escaped separators as literal text', () => {
assert.equal(runs(String.raw`echo foo \; bun run verify --flag "$VALUE"`), false);
assert.equal(runs(String.raw`echo foo \| bun run verify --flag "$VALUE"`), false);
assert.equal(runs(String.raw`find . -exec bun run verify --flag "$VALUE" \;`), false);
// An escape does not swallow a following real separator.
assert.equal(runs(String.raw`echo a\b; bun run verify --flag "$VALUE"`), true);
});
test('commandPositions splits on separators and strips control-flow prefixes', () => {
assert.deepEqual(
commandPositions({ run: 'if gh release view "$V"; then\ngh release edit "$V"\nfi' }),
+8
View File
@@ -75,6 +75,14 @@ function splitCommandSeparators(line: string): string[] {
continue;
}
// An unquoted backslash escapes the next character, so `\;` is literal text
// rather than a separator. Checked before comments and separators.
if (char === '\\' && index + 1 < line.length) {
current += char + line[index + 1]!;
index += 1;
continue;
}
if (char === "'" || char === '"') {
quote = char;
current += char;