MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / reactRenderEdges

Function reactRenderEdges

src/resolution/callback-synthesizer.ts:400–445  ·  view source on GitHub ↗

* Phase 4: React class-component re-render. `this.setState(...)` re-runs the * component's `render()`, but that hop is React-internal — no static edge — so a * flow like "mutation → setState → canvas repaint" dead-ends at setState even * though `render → getRenderableElements → …` is fully call-c

(queries: QueryBuilder, ctx: ResolutionContext, onYield: MaybeYield)

Source from the content-addressed store, hash-verified

398 * accepted — it's reachability-correct, like the callback channels.
399 */
400async function reactRenderEdges(queries: QueryBuilder, ctx: ResolutionContext, onYield: MaybeYield): Promise<Edge[]> {
401 let scanned255 = 0;
402 const edges: Edge[] = [];
403 const seen = new Set<string>();
404 // A class can only emit here if it CONTAINS a method named `render` — so one
405 // indexed name lookup bounds the candidate set up front, and the class scan
406 // below skips everything else before its per-class edge/node queries. On a
407 // repo with few/no render methods (any non-React codebase) this collapses
408 // the pass from every-class fan-out to ~zero DB work, with identical output:
409 // the skipped classes fail the same `render` check today, just after paying
410 // for their children. (Not a language gate: `render` + `this.setState(` in
411 // Java — e.g. Litho — legitimately matches today and still does.)
412 const renderOwners = new Set<string>();
413 for (const n of ctx.getNodesByName('render')) {
414 if (n.kind !== 'method') continue;
415 for (const e of queries.getIncomingEdges(n.id, ['contains'])) renderOwners.add(e.source);
416 }
417 if (renderOwners.size === 0) return edges;
418 for (const cls of queries.iterateNodesByKind('class')) {
419 if ((++scanned255 & 63) === 0) await onYield();
420 if (!renderOwners.has(cls.id)) continue;
421 const children = queries.getOutgoingEdges(cls.id, ['contains'])
422 .map((e) => queries.getNodeById(e.target))
423 .filter((n): n is Node => !!n && n.kind === 'method');
424 const render = children.find((n) => n.name === 'render');
425 if (!render) continue;
426 let added = 0;
427 for (const m of children) {
428 if (added >= MAX_CALLBACKS_PER_CHANNEL) break;
429 if (m.id === render.id) continue;
430 const content = ctx.readFile(m.filePath);
431 const src = content && sliceLines(content, m.startLine, m.endLine);
432 if (!src || !SETSTATE_RE.test(src)) continue;
433 const key = `${m.id}>${render.id}`;
434 if (seen.has(key)) continue;
435 seen.add(key);
436 edges.push({
437 source: m.id, target: render.id, kind: 'calls', line: m.startLine,
438 provenance: 'heuristic',
439 metadata: { synthesizedBy: 'react-render', via: 'setState', registeredAt: `${render.filePath}:${render.startLine}` },
440 });
441 added++;
442 }
443 }
444 return edges;
445}
446
447/**
448 * Phase 4b: Flutter setState → build (the Dart analog of react-render). In a

Callers 1

Calls 8

sliceLinesFunction · 0.85
hasMethod · 0.80
readFileMethod · 0.80
getNodesByNameMethod · 0.65
iterateNodesByKindMethod · 0.65
getNodeByIdMethod · 0.65
getIncomingEdgesMethod · 0.45
getOutgoingEdgesMethod · 0.45

Tested by

no test coverage detected