Repository navigation
fix(jsx): a .jsx component links to the file-scope values it reads, as in .js and .tsx - #2561
Merged
Merged
Conversation
…s in .js and .tsx 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>
…w-50bd8b # Conflicts: # __tests__/kernel-tsjs-parity.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A
.jsxfile got no same-file value-reference edges: thereferencesedges (metadatavalueRef: true) from a reader to the file-scopeconst/varit reads, whichcodegraph impactand the impact trail incodegraph_explore/codegraph_nodefollow.TreeSitterExtractor.VALUE_REF_LANGSlistedtypescript,javascriptandtsx, but notjsx, and the kernel mirrored the gap. So a component in a.jsxfile had no edge to the lazy page it renders (<LoginPage />underconst LoginPage = Loadable(lazy(…))), the route table it builds or the config it maps over, while the same code in.jsor.tsxhad all of them.Probe: the same React source through
extractFromSourceas.jsx,.tsxand.js:.jsx.tsx.jsWas leaving out
jsxdeliberate?No sign of it.
git log -G VALUE_REF_LANGS: the set was introduced in ec90ddf (2026-06-13) as['typescript', 'javascript', 'tsx'], and #897 and #1186 (ArkTS) extended it. None of them mentionsjsx. The design doc's coverage table says "TypeScript, JavaScript, tsx … the original languages" and never namesjsx. Every other JS-family gate in the extractor includesjsx: declarators, import bindings, re-exports, store detection and the fn-ref spec. The kernel'sVariant::value_refs()existed only to copy the TS set bug-for-bug, with the comment "VALUE_REF_LANGS includes typescript/tsx/javascript but NOT jsx"..jsxuses the same JavaScript grammar as.js, so nothing about it needs different handling.Change
src/extraction/tree-sitter.ts: add'jsx'toVALUE_REF_LANGS.codegraph-kernel/src/tsjs/mod.rs: dropVariant::value_refs()and its two early returns, so every TS/JS variant runs value refs, as on the wasm path.jsx(and the playbook's list also gainsarkts, already in the set).Tests
value-reference-edges.test.ts: a.jsxfile indexed end to end:AuthRoutes → LoginPage(a lazy page rendered as a tag) andNav → NAV_ITEMS(a table mapped inside JSX).kernel-tsjs-parity.test.ts: the same source astsx,jsandjsxthrough the kernel and the wasm path, asserting parity and the exact four value-ref edges.jsxcases fail and thetsx/jsones pass. With the fixed TypeScript but main's kernel (CODEGRAPH_KERNEL_PATH), the parity case fails (kernel 8 edges, wasm 12), so a fix on one side only can't pass.Validation
Before/after full indexes of the same repos, kernel-routed as users run them, dumped with
scripts/dump-graph.mjsand diffed by natural keys. The pair was rebuilt and rerun on each main this branch merged:d8a7f868,ed199e60,e47cb258, and finallyd0bb9be5, which includes #2420. Every run added the same edge set, line for line..jsxfiles.tsxnow)bigbluebutton-html5.jsx)Every added edge was checked against the source with a parse (the grammar the extractor uses for
.jsx). Each one:referencesedge with{"valueRef":true}, with both ends in the same.jsxfile,const/let/var,const/let/vardeclarators, so a same-named parameter would get past it. That gap predates this PR and shows in.jsand.tsxwith a syntheticfunction F({ headCells }). An audit of all 2,201 JS/TS value-ref edges in these repos, including the ones.js/.tsxfiles already had, found no real case. A default value like{ error = defaultError }is a read, so its edge is correct.All 400 pass. By what the target is:
defineMessages)intlMessages, read byrenderand handlersDEBOUNCE_TIME,ANIMATION_NONEsxstyle objectavatarSX, matxinitialAuthStateheadCells, chart data likemonthlyLabelsLoadable(lazy(() => import(…))))materialRoutes → AppButton, berryMainRoutes → DashboardDefaultcreateContext)ConfigProvider → ConfigContext(<ConfigContext.Provider>)letassigned laterlet EmojiPicker, Emoji;, set inonShowDropdown, rendered inrenderYupschema,new DOMParser())In 201 of the 400, the reader uses the value inside JSX, as a tag (
<LoginPage />) or in an expression ({rows.map(…)}). In the other 199 it's plain code, such as a handler reading a message table.What a user sees (
codegraph impact, before → after):AppButton(const AppButton = Loadable(lazy(() => import("./buttons/AppButton")))): 1 → 3 affected. ThematerialRoutestable that renders<AppButton />is now affected, and so isroutes.jsx, which imports that table.headCells(a column table): 1 → 3 affected.OrderTableHead, which maps over it, is now affected, and so isOrderTable, which renders<OrderTableHead>.scripts/kernel-parity.mjs --lang jsx,javascript,tsx,typescriptover the five.jsxrepos with the fixed build: 0 files with diffs. 2,556 files are byte-identical and 37 defer to wasm on parse errors, the same 37 as with the unmodified build. Nodes and refs are unchanged; only edge totals grow.Test suite. On the final branch (main
d0bb9be5+ this change), with the kernel staged andCODEGRAPH_KERNEL_EXPECT=1:tscis clean.An earlier full run, on a box saturated by other sessions, had 5 failures in daemon/MCP/process tests (
mcp-daemon,mcp-status-freshness,mcp-writer-lock,daemon-pid-reuse, andfunction-ref's 60 s #1820 case). None of those tests indexes a.jsxfile. Each failure reproduced on main under the same load in interleaved runs, or passed on rerun.Overlap
d0bb9be5) routes every PascalCase reference from a.tsx/.jsxfile throughdeclaredComponentin the React resolver's Pattern 1. Value refs never reach it: they are finished edges emitted during extraction, not references for a resolver. Accordingly, every A/B above leaves refs unchanged, including the one ond0bb9be5, andjsx-child-disambiguation.test.ts(fix(react): a component a file declares itself as a value is what its JSX renders #2420's cases) passes 20/20 on this branch.jsx-rendersynthesizer. Those are synthesized edges, and the synthesis merge dedupes them only among themselves, so the two changes don't interact. They share only CHANGELOG.md.export defaultdeclares, not the first exported function #2432, fix(react-router): a lazy route links the page a barrel module forwards #2436, fix(sync): a route rendering a same-file lazy value follows its module, and a new component gets its JSX edges #2452, fix(react,vue): a tag imported from a package renders no project namesake #2475, fix(react): a tag that passes type arguments renders its generic component #2476, fix(react-router): a lazy route links the page its loader picks #2480, fix(react-router): a lazy route follows a barrel that re-exports an import #2558) is resolution or synthesis. fix(react): a typed styled component is a component, not a constant #2429 is extraction: it makes styled componentscomponentnodes, so in every JS dialect they are neither value-ref targets nor readers. All of it is included in the final A/B.🤖 Generated with Claude Code