Version: 0.9.9 (linux x64, node:sqlite backend)
Language: TypeScript/TSX (Turborepo monorepo, ~490 indexed files)
Summary
Components declared as const X = React.forwardRef(...) are indexed as
constant nodes, and no render/call edges are created for their JSX
usages (<X ...>). As a result codegraph_callers / codegraph_impact
return "No callers found" for any shadcn/ui-style component, even when
dozens of files render it.
Function-declared components are fine: for export function ThemeProvider()
the JSX render edges exist and callers are reported correctly. The problem
is specific to the declaration style.
Repro
// packages/ui/src/button.tsx
import * as React from "react";
export const Button = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>((props, ref) => <button ref={ref} {...props} />);
Button.displayName = "Button";
// apps/web/page.tsx
import { Button } from "../../packages/ui/src/button";
export function Page() {
return <Button>Click</Button>;
}
codegraph init -i
codegraph callers Button
Expected: Page (function) — apps/web/page.tsx
Actual: No callers found for "Button"
Also observed:
codegraph_search with kind: "component" does not return Button at all (it only exists as a constant node).
The import { Button } ... edges ARE indexed, so the data loss is only in the render/call edge extraction, not in import tracking.
Real-world impact
In our monorepo is rendered in 81 files across 3 apps
(verified with grep), yet codegraph_callers Button and
codegraph_impact Button report nothing. This is a dangerous silent false
negative: "no callers" reads as "safe to change" right before a refactor of
a design-system component. Every shadcn/ui component uses the
const X = React.forwardRef(...) pattern, so for typical React design
systems the entire UI layer is invisible to impact analysis.
Likely related (untested): React.memo(...), styled(...) and other
HOC-wrapped const components.
Suggested fix
Treat const X = React.forwardRef(...) / React.memo(...) initializers as
component declarations in the tree-sitter extraction queries (kind:
component), and emit the same JSX render edges that function-declared
components get.
For comparison: function-declared components in the same codebase resolve
correctly through barrel re-exports and workspace aliases (@repo/ui), so
the resolution layer itself looks solid — it's only the component
recognition for wrapped declarations that's missing.
Version: 0.9.9 (linux x64, node:sqlite backend)
Language: TypeScript/TSX (Turborepo monorepo, ~490 indexed files)
Summary
Components declared as
const X = React.forwardRef(...)are indexed asconstantnodes, and no render/call edges are created for their JSXusages (
<X ...>). As a resultcodegraph_callers/codegraph_impactreturn "No callers found" for any shadcn/ui-style component, even when
dozens of files render it.
Function-declared components are fine: for
export function ThemeProvider()the JSX render edges exist and callers are reported correctly. The problem
is specific to the declaration style.
Repro
Also observed:
codegraph_search with kind: "component" does not return Button at all (it only exists as a constant node).
The import { Button } ... edges ARE indexed, so the data loss is only in the render/call edge extraction, not in import tracking.
Real-world impact
In our monorepo is rendered in 81 files across 3 apps
(verified with grep), yet codegraph_callers Button and
codegraph_impact Button report nothing. This is a dangerous silent false
negative: "no callers" reads as "safe to change" right before a refactor of
a design-system component. Every shadcn/ui component uses the
const X = React.forwardRef(...) pattern, so for typical React design
systems the entire UI layer is invisible to impact analysis.
Likely related (untested): React.memo(...), styled(...) and other
HOC-wrapped const components.
Suggested fix
Treat const X = React.forwardRef(...) / React.memo(...) initializers as
component declarations in the tree-sitter extraction queries (kind:
component), and emit the same JSX render edges that function-declared
components get.
For comparison: function-declared components in the same codebase resolve
correctly through barrel re-exports and workspace aliases (@repo/ui), so
the resolution layer itself looks solid — it's only the component
recognition for wrapped declarations that's missing.