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:
@@ -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"),
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user