fix(codex): backslash parity in the TOML closing-quote scan

Round 2's escape check rejected a quote whenever a single backslash
preceded it, so an escaped backslash before a real closing quote (e.g.
path = "path\\" # c) was misread as an escaped quote and the field was
dropped. Now counts the run of backslashes and only treats an ODD run as
escaping the quote. Folded the old two-branch quote handling into one
scan (it already finds the terminator correctly with or without a
trailing comment) and decode \\ -> \ in the extracted value, since the
scan already knows which backslash run is real.
This commit is contained in:
2026-09-08 16:57:02 +07:00
parent 236e94760f
commit b0788eea80
2 changed files with 23 additions and 12 deletions
+10
View File
@@ -98,6 +98,16 @@ describe("codex-discovery", () => {
assert.equal(meta.description, 'say \\"hi\\"');
});
it("recognises a quote preceded by an escaped backslash as a real terminator", () => {
const meta = cx.readTomlMeta('path = "path\\\\" # c\n');
assert.equal(meta.path, "path\\");
});
it("keeps counting backslash pairs correctly with four of them before the terminator", () => {
const meta = cx.readTomlMeta('key = "a\\\\\\\\" # c\n');
assert.equal(meta.key, "a\\\\");
});
it("reads a rule file's preview", () => {
write(
path.join(TMP, "rules", "no-force-push.rules"),
+13 -12
View File
@@ -119,25 +119,26 @@ function readTomlMeta(text) {
if (!value.slice(3).includes('"""')) inTripleQuote = true;
continue;
}
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
} else if (value.startsWith('"') || value.startsWith("'")) {
// A quoted value with a trailing `# comment` outside the string —
// e.g. model = "gpt-5.4" # default. Find the real closing quote
// (skipping a `\"` escaped one) and strip everything after it.
if (value.startsWith('"') || value.startsWith("'")) {
// Find the real closing quote — one not preceded by an ODD run of
// backslashes (an even run, including zero, means it isn't escaped) —
// so a trailing `# comment` outside the string is stripped without
// being fooled by an escaped quote or an escaped backslash inside it.
const quote = value[0];
let closeIdx = -1;
for (let i = 1; i < value.length; i++) {
if (value[i] === quote && value[i - 1] !== "\\") {
if (value[i] !== quote) continue;
let backslashes = 0;
while (value[i - 1 - backslashes] === "\\") backslashes++;
if (backslashes % 2 === 0) {
closeIdx = i;
break;
}
}
if (closeIdx > 0) value = value.slice(1, closeIdx);
else continue;
if (closeIdx < 0) continue;
// \\ decodes to one backslash; other escapes (e.g. \") are left
// literal — this is a best-effort reader, not a full TOML unescaper.
value = value.slice(1, closeIdx).replace(/\\\\/g, "\\");
} else if (/^(true|false|-?\d+(\.\d+)?)\s*(#.*)?$/.test(value)) {
value = value.replace(/\s*#.*$/, "");
value = value === "true" ? true : value === "false" ? false : Number(value);