fix(react): JSX at module scope, in a top-level const or in a test callback renders from where its calls are attributed (#2611)

JSX outside every function now renders from what a plain call there is
attributed to: a top-level value, or the file. Ownership is by line,
so no tag counts twice. Merged with main's destructuring rules (PRs
2676 and 2677): an owning parent takes a name as its local by its own
lines or by the file's top-level destructuring, and function parents
keep main's scope rules. The viewer's shared-chrome count no longer
counts a file as a render parent.

A/B: excalidraw +132 and bulletproof-react +38 render sites (tests to
the components they render, entries to their root apps, stories to
their components), none removed.

Fixes issue 2587.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Eric Minish
2026-10-20 17:08:28 +00:00
committed by GitHub
co-authored by Claude Opus 5.5
parent b95b316860
commit 63476df6a6
4 changed files with 340 additions and 29 deletions
+4 -1
View File
@@ -1621,7 +1621,10 @@ function renderParents(cg: CodeGraph, node: Node, memo: Map<string, number>): nu
const incoming = cg.getIncomingEdgesTo([node.id], ['calls']);
const sources = new Set<string>();
for (const e of incoming) {
if ((e.metadata as Record<string, unknown> | undefined)?.synthesizedBy === 'jsx-render') sources.add(e.source);
// A file renders at module scope — an entry's root, a test's subject
// (#2587) — and is no parent a screen shares chrome with.
if ((e.metadata as Record<string, unknown> | undefined)?.synthesizedBy === 'jsx-render' &&
cg.getNode(e.source)?.kind !== 'file') sources.add(e.source);
}
parents = sources.size;
memo.set(node.id, parents);