fix(jsx): a .jsx component links to the file-scope values it reads, as in .js and .tsx (#2561)

Value-reference edges (a reader symbol -> the file-scope const/var it
reads, which impact follows) ran for typescript, tsx and javascript but
not jsx. A .jsx file is its own language, parsed with the JavaScript
grammar, so the same component had no edge to the lazy page it renders
(`<LoginPage />` under `const LoginPage = Loadable(lazy(...))`), the route
table or the config it maps over as .jsx, and all of them as .js or .tsx.
Every other JS-family gate in the extractor lists jsx, and nothing in the
history says this one was left out on purpose: the kernel mirrored the gap
with an explicit "NOT jsx" check for parity.

Add jsx to VALUE_REF_LANGS and drop the kernel's jsx exclusion.

On mantis, matx, berry, mastodon and bigbluebutton-html5 the index only
gains edges (35, 56, 15, 28 and 266): no node, ref or file changes and no
edge removed. Every added edge is a same-file read of a file-scope value
that is the only binding of its name in the file. A repo with no .jsx
files indexes byte-identically, and kernel-parity.mjs shows 0 diffs over
those repos with the same deferrals as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-10-14 23:23:21 +00:00
committed by GitHub
parent 8206c8c271
commit 3f714bcc48
7 changed files with 69 additions and 13 deletions
+1 -8
View File
@@ -46,10 +46,6 @@ impl Variant {
fn is_ts(self) -> bool {
matches!(self, Variant::Typescript | Variant::Tsx)
}
/// VALUE_REF_LANGS includes typescript/tsx/javascript but NOT jsx.
fn value_refs(self) -> bool {
!matches!(self, Variant::Jsx)
}
}
/// typescriptExtractor.methodTypes / javascriptExtractor.methodTypes.
@@ -478,9 +474,6 @@ impl<'t> Walker<'t> {
// --- value references (captureValueRefScope / flushValueRefs) --------------
fn capture_value_ref_scope(&mut self, kind: &'static str, name: &str, row: u32, node: Node<'t>, value_target: bool) {
if !self.variant.value_refs() {
return;
}
let target_kind_ok = kind == "constant" || kind == "variable";
if value_target
&& target_kind_ok
@@ -506,7 +499,7 @@ impl<'t> Walker<'t> {
let scopes = std::mem::take(&mut self.value_scopes);
let mut targets = std::mem::take(&mut self.fs_values);
let counts = std::mem::take(&mut self.fs_value_counts);
if !self.variant.value_refs() || std::env::var("CODEGRAPH_VALUE_REFS").as_deref() == Ok("0") {
if std::env::var("CODEGRAPH_VALUE_REFS").as_deref() == Ok("0") {
return;
}
if targets.is_empty() || scopes.is_empty() || util::is_generated_file(self.file_path) {