feat(expo-router): add Expo Router support for screens and navigates
Introduce Expo Router integration: a new framework resolver, route-based screen nodes, and navigates edges, plus a /api/screens endpoint and a Screens UI view. Adds branch-guard-driven labeling of edges, resolution logic, and tests to cover extraction, resolution, and end-to-end flow. This enables CodeGraph UI to surface screens and transitions from Expo Router apps.
This commit is contained in:
@@ -193,8 +193,16 @@ export const FLOW_CALLABLE_KINDS: ReadonlySet<string> = new Set([
|
||||
'function',
|
||||
'component',
|
||||
'constructor',
|
||||
'route',
|
||||
]);
|
||||
|
||||
/**
|
||||
* Edge kinds a flow may ride. `navigates` is a screen transition (Expo Router
|
||||
* `router.push('/x')` → the route node) — a hop in the user's flow exactly as
|
||||
* a call is a hop in the program's.
|
||||
*/
|
||||
export const FLOW_EDGE_KINDS: ReadonlySet<string> = new Set(['calls', 'navigates']);
|
||||
|
||||
/**
|
||||
* Node kinds that can be an endpoint of a SYNTHESIZED edge without being
|
||||
* callable. An RTK thunk is `const X = createAsyncThunk(...)`, so a thunk →
|
||||
@@ -458,8 +466,10 @@ function walkCalls(
|
||||
if (id !== seed.id && named.has(id)) reached.push(id);
|
||||
if (depth >= maxHops - 1) continue;
|
||||
for (const c of cg.getCallees(id)) {
|
||||
if (c.edge.kind !== 'calls' || parent.has(c.node.id)) continue;
|
||||
const newStreak = named.has(c.node.id) ? 0 : streak + 1;
|
||||
if (!FLOW_EDGE_KINDS.has(c.edge.kind) || parent.has(c.node.id)) continue;
|
||||
// A route node is a connector, not a symbol the reader would have named:
|
||||
// crossing one costs no bridge budget.
|
||||
const newStreak = named.has(c.node.id) ? 0 : c.node.kind === 'route' ? streak : streak + 1;
|
||||
if (newStreak > maxBridge) continue;
|
||||
parent.set(c.node.id, { prev: id, edge: c.edge, node: c.node });
|
||||
queue.push({ id: c.node.id, depth: depth + 1, streak: newStreak });
|
||||
@@ -530,7 +540,7 @@ function walkBidirectional(
|
||||
const next: Node[] = [];
|
||||
for (const node of frontF) {
|
||||
for (const c of cg.getCallees(node.id)) {
|
||||
if (c.edge.kind !== 'calls' || forward.has(c.node.id)) continue;
|
||||
if (!FLOW_EDGE_KINDS.has(c.edge.kind) || forward.has(c.node.id)) continue;
|
||||
forward.set(c.node.id, { prev: node.id, edge: c.edge, node: c.node });
|
||||
next.push(c.node);
|
||||
}
|
||||
@@ -542,7 +552,7 @@ function walkBidirectional(
|
||||
const next: Node[] = [];
|
||||
for (const node of frontB) {
|
||||
for (const c of cg.getCallers(node.id)) {
|
||||
if (c.edge.kind !== 'calls' || backward.has(c.node.id)) continue;
|
||||
if (!FLOW_EDGE_KINDS.has(c.edge.kind) || backward.has(c.node.id)) continue;
|
||||
backward.set(c.node.id, { next: node.id, edge: c.edge });
|
||||
backNodes.set(c.node.id, c.node);
|
||||
next.push(c.node);
|
||||
|
||||
Reference in New Issue
Block a user