Skip to content

Commit af57c0e

Browse files
theCodeDriftclaude
andcommitted
test(cli): pin the language-field failures beside the recipe that claims them
A comment here pointed at a `the language field` suite that did not exist on this branch — it was added one PR up the stack, so a maintainer following the pointer found nothing and might have assumed the C#-abort and wrong-parser behaviours were covered. Reported in review, and correct. Moved down rather than the comment softened. `route.txt` makes both claims on this branch, and the house rule is that an engine claim in a recipe is quoted from a pinned binary rather than described, so the claim and its pin belong in the same change. Adds a third case while here, pinning the fact this branch's own history got wrong: `C++` and `cpp` are ACCEPTED aliases resolving to Cpp, so an off-list spelling is not reliably an error. Without it the suite reads as "off-list spellings fail", which is the claim that had to be corrected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cyga14bww8rmazH2XrF8ms
1 parent 32ac3ab commit af57c0e

1 file changed

Lines changed: 63 additions & 0 deletions

File tree

‎packages/cli/test/ast-grep-vendor-contract.test.ts‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ const test = (cwd: string, ruleId: string) =>
153153
/** One eval call, at line 0 column 10 of `src/a.ts`. */
154154
const evalSource = { "src/a.ts": 'const x = eval("1");\n' };
155155

156+
/** `rule("no-eval")` with its `language:` swapped for another spelling. */
157+
const atLanguage = (language: string) =>
158+
rule("no-eval").replace("language: TypeScript", `language: ${language}`);
159+
156160
/** Exit status of scanning one finding declared at `severity`. */
157161
const statusAt = (severity: string) =>
158162
scan(
@@ -484,6 +488,65 @@ withSg("ast-grep vendor contract", () => {
484488
});
485489
});
486490

491+
/**
492+
* How a wrong `language:` fails — the two shapes `route.txt` warns about.
493+
*
494+
* Nothing of ours catches either one first: the vendored
495+
* `src/generated/ast-grep-rule-schema.json` types `$defs.Language` as a bare
496+
* string with no enum, and `verify` never reads the field. So the binary's
497+
* response IS the contract, and a recipe telling an author what to expect is
498+
* quoting it. These live beside the recipe that makes the claim, so the claim
499+
* and its pin land in the same change.
500+
*/
501+
describe("the language field", () => {
502+
it("fails the whole scan on a spelling it does not recognize", () => {
503+
// `C#` is the plausible wrong spelling of `CSharp`, and getting it wrong
504+
// is not a rule that quietly matches nothing: ast-grep cannot parse the
505+
// config, so every OTHER rule in the project goes unreported too. The
506+
// error names the enum, which is what an author sees.
507+
const result = scan(
508+
project({ rules: { "no-eval": atLanguage("C#") }, sources: evalSource })
509+
);
510+
expect(result.status).toBeGreaterThan(1);
511+
expect(result.stderr).toContain("SgLang");
512+
});
513+
514+
it("accepts off-list aliases, so an off-list spelling is not an error", () => {
515+
// The half that corrects an earlier claim in this branch's own history:
516+
// `C++` and `cpp` are NOT rejected, they resolve to Cpp. The recipe tells
517+
// authors to copy from the canonical list for the other two reasons, not
518+
// because every off-list spelling fails.
519+
const sources = {
520+
"src/a.cpp": "int main(){int simply=1;return simply;}\n",
521+
};
522+
for (const spelling of ["Cpp", "C++", "cpp"]) {
523+
const result = scan(
524+
project({ rules: { "no-eval": atLanguage(spelling) }, sources })
525+
);
526+
expect(result.status, `${spelling} was rejected`).not.toBeGreaterThan(
527+
1
528+
);
529+
}
530+
});
531+
532+
it("treats Tsx and TypeScript as different parsers, not aliases", () => {
533+
// The quiet half of the same field, and the reason the recipe names this
534+
// pair specifically. `TypeScript` over a `.tsx` tree exits clean with no
535+
// findings, which is indistinguishable from a codebase with nothing to
536+
// flag — the rule looks written and proves nothing.
537+
const sources = { "src/a.tsx": "const el = <div>{eval(x)}</div>;\n" };
538+
const asTypeScript = scan(
539+
project({ rules: { "no-eval": atLanguage("TypeScript") }, sources })
540+
);
541+
expect(asTypeScript.status).toBe(0);
542+
expect(asTypeScript.stdout.trim()).toBe("");
543+
expect(
544+
scan(project({ rules: { "no-eval": atLanguage("Tsx") }, sources }))
545+
.stdout
546+
).toContain("eval(x)");
547+
});
548+
});
549+
487550
/**
488551
* Relocated from `engine-layout.test.ts`, which existed only for these two.
489552
*

0 commit comments

Comments
 (0)