[ci] fix #690: bound the target-map brace scan and self-test the parser - #769
[ci] fix #690: bound the target-map brace scan and self-test the parser#769ritikpal1122 wants to merge 3 commits into
Conversation
…t the parser extractObjectValues() ended the object literal at the first downstream line trimming to "};". With TARGET_MAP's own closing brace deleted, that latched onto the "};" closing an arrow-function const 74 lines later, scraped 'travsr' and 'travsr-vscode-installer' out of the code between as if they were target triples, and blamed the release matrix for shipping no such artifact. The guard still failed closed, but it pointed at the wrong file. Replaced with quote-aware brace-depth counting plus an indentation bound. Depth counting alone is not enough: the rest of installer.ts re-balances, so the missing brace is absorbed and the scan latches onto the last "}" in the file instead (10 phantom triples rather than 7). The bound is what makes the failure detectable, since a map's entries are always indented under its declaration. Missing, unopened and malformed closers now each get their own message naming the object, the file and the line where the scan stopped. The script had no test harness, which is why this survived: on a clean tree a broken scan and a correct one print the same thing. Added --self-test, following .github/scripts/build-id.sh, and wired it into the existing target-maps CI job (job name unchanged, release.yml matches it by name). Its fixture is checked to defeat both a shape scan and a depth-only scan, so the regression cases cannot silently stop testing anything.
`atText` is a raw source line, so it routinely carries its own "(": the very
case this check explains renders as
still open at line 30 (export function resolveTargetTriple(), which is ...
which is visibly unbalanced. A guard whose whole purpose is a message the
reader can act on should not ship a message that reads as broken. Quoted now.
Three self-test regexes pinned the old rendering. The suite caught all three,
one per run, which is the harness doing its job on its first real edit.
raj-rkv
left a comment
There was a problem hiding this comment.
Reviewed against a worktree of origin/master, diffed at the merge base ef3eac1. I reproduced #690 on the real installer.ts rather than trusting the before/after in the description, and independently sabotage-checked the new suite.
The bug reproduces exactly as described. Deleting line 29 (the }; closing TARGET_MAP) from the real file and running master's parser:
OK: packages/travsr-vscode/src/installer.ts TARGET_MAP claims 7 target(s)
ERROR: ... TARGET_MAP claims 'travsr', but release.yml build matrix ships no such artifact
ERROR: ... TARGET_MAP claims 'travsr-vscode-installer', but ... ships no such artifact
Seven, with travsr and travsr-vscode-installer scraped out of code below the map, and the blame pointed at release.yml, which was fine. This branch on the same broken file:
ERROR: the closing brace of TARGET_MAP in packages/travsr-vscode/src/installer.ts
(declared on line 25) is missing: the object literal is still open at line 30,
which reads `export function resolveTargetTriple(`, ...
The claim that depth counting alone is worse is true, and the number is right. I removed the indentation bound and the terminator check to get a pure depth scan, against the same broken file:
OK: packages/travsr-vscode/src/installer.ts TARGET_MAP claims 10 target(s)
5 x "no such artifact"
Exactly the 10 the description names, up from 7. With the terminator check left in it instead runs to line 299, the last } in the file, and reports malformed. Either way the bound is what makes the failure locatable, so the reasoning for going past the fix suggested in the issue holds.
The suite is load-bearing. Patching the parser back to each rejected design:
shape scan -> 5 FAIL: the mandated case, its message assertion, single-line map,
non-object declaration, malformed closer
depth only -> 3 FAIL: the mandated case, its message assertion, non-object declaration
(the description says "the mandated case and 4 others" for both; that holds for the shape scan and is 2 others for depth-only, which does not change the conclusion.)
Also checked, since these are the things that would bite elsewhere:
--self-testreally does exit before touching any repo file, and it is cwd-independent: it passes run from/tmpagainst an absolute script path, so the CI step cannot depend on the working directory.- The job
name: release/installer target mapsis byte-identical and still on line 393, so #766's preflight required-check list is unaffected. Worth confirming given the two PRs are open together and both touchci.yml; they auto-merge with no conflict. - The fixture-property test is the right instinct. It means the
#690case cannot quietly stop testing anything if that regex line ininstaller.tsever changes shape.
Local: 12/12 self-test cases pass, the real check passes on a clean tree, ci.yml parses, auto-merges onto current master, no em-dashes added. 24 CI checks green.
One small finding in the inline comment. It does not block.
The unclosed message appended "which is back at the declaration's own indentation and so cannot be part of the literal" to every shape, but `where` has two, and the end of a file has no indentation. A map at the end of a file, or a truncated one, rendered a reason that cannot describe where it stopped. Same class as the parenthesis fix in this branch: both are the failure message this PR exists to make accurate. And the reason it survived is the reason Travsr-com#690 survived at all, one level up: all twelve cases end inside a file, so every one exercised the atLine branch and none could see the other. The justification now travels with the shape rather than being appended to it. A thirteenth case pins the end-of-file wording and asserts the indentation clause is absent, so the branch the suite could not see is the one it now watches. The unopened arm needed no change: "does not open an object literal before the end of the file" never explained the stopping point.
|
Fixed in The justification now travels with the shape instead of being appended to every one: const whyStopped = atLine
? `${where}, which is back at the declaration's own indentation and so cannot be part of the literal`
: `${where}, with no closing brace anywhere below the declaration`;Thirteenth case added, and it asserts both directions: that the end-of-file wording appears, and that Agreed the 13/13 self-test cases pass, the real check is still green on a clean tree, and this merges onto current master. |
Closes #690.
The bug
extractObjectValues()found the end of an object literal by scanning for the first line trimming to exactly};. With that line deleted it did not fail: it latched onto an unrelated later};and pulled everything between into the literal. The guard still failed closed, but the message named the wrong problem, sending the reader to fix a target map that was fine.Brace depth alone does not fix it
Worth flagging, because it contradicts the fix suggested in the issue. With pure depth counting the scan still does not stop: the rest of
installer.tsre-balances and absorbs the missing brace, so it latches onto the last}in the file and extracts 10 phantom triples instead of 7. That is worse than the original bug.So the scan combines quote-aware depth counting with an indentation bound: a map's entries are always indented under its declaration, so a non-blank line back at the declaration's own indentation means the literal should already have closed. Lines opening with
{/}are exempt so the literal's own};is not mistaken for the bound.Three distinct reasons now exist:
unclosed,unopened,malformed.Before / after
Test harness
The script had none, which is why this survived. No JS test convention exists for these scripts, so I followed the precedent of
.github/scripts/build-id.sh --self-test:node .github/scripts/check-target-maps.mjs --self-test, stdlib only, no deps, exits before reading any repo file. 12 cases.The fixture keeps the three properties that made #690 bite: a
};line for a shape scan to latch onto, quoted strings the value regex scrapes, and a brace count returning to zero for a depth-only scan to latch onto. One test asserts those fixture properties directly, so the regression cases cannot silently stop testing anything.Verified load-bearing by patching the parser back to (a) the old line-shape scan and (b) a depth-only scan: both fail the mandated case and 4 others.
Notes
target-mapsjob. Jobname: release/installer target mapsis unchanged, sorelease.yml's preflight required-check matching is unaffected.};closing an arrow function), not the});at 102.atTextis a source line carrying its own(. Three self-test regexes pinned the old rendering and the suite caught all three.