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

Function reduxThunkEdges

src/resolution/callback-synthesizer.ts:2099–2150  ·  view source on GitHub ↗
(queries: QueryBuilder, ctx: ResolutionContext, onYield: MaybeYield)

Source from the content-addressed store, hash-verified

2097const THUNK_FANOUT_CAP = 24;
2098
2099async function reduxThunkEdges(queries: QueryBuilder, ctx: ResolutionContext, onYield: MaybeYield): Promise<Edge[]> {
2100 let scanned255 = 0;
2101 const edges: Edge[] = [];
2102 const seen = new Set<string>();
2103 for (const node of queries.iterateNodesByKind('constant')) {
2104 if ((++scanned255 & 63) === 0) await onYield();
2105 // Cheap gate: the initializer (captured in `signature`) must be a create(Async)Thunk call —
2106 // avoids reading every constant's body on a large repo.
2107 if (!node.signature || !THUNK_DECL_RE.test(node.signature)) continue;
2108 const content = ctx.readFile(node.filePath);
2109 const src = content && sliceLines(content, node.startLine, node.endLine);
2110 if (!src) continue;
2111 // Thunks are TS/JS-family (same // and /* */ comment syntax); map to a CommentLang.
2112 const safe = stripCommentsForRegex(src, node.language === 'javascript' || node.language === 'jsx' ? 'javascript' : 'typescript');
2113 THUNK_DISPATCH_RE.lastIndex = 0;
2114 let m: RegExpExecArray | null;
2115 let added = 0;
2116 while ((m = THUNK_DISPATCH_RE.exec(safe)) && added < THUNK_FANOUT_CAP) {
2117 const name = m[1]!;
2118 if (name === node.name) continue; // self-dispatch (recursive thunk) — skip
2119 // Resolve the dispatched name, PREFERRING the thunk/action-creator over a same-named
2120 // service function. `dispatch(X(...))` dispatches a thunk or an action-creator (both
2121 // `constant`s) — never an unrelated helper that merely shares the name. On octo-call,
2122 // `leaveCall` is BOTH a `createAsyncThunk` const AND a service function, and the bare
2123 // `.find()` picked the function (wrong). Order: thunk const > other const > same-file
2124 // callable > first match. A single candidate (no collision) is unaffected.
2125 const cands = ctx
2126 .getNodesByName(name)
2127 .filter((n) => n.kind === 'constant' || n.kind === 'function' || n.kind === 'method');
2128 const target =
2129 cands.find((n) => !!n.signature && THUNK_DECL_RE.test(n.signature)) ??
2130 cands.find((n) => n.kind === 'constant') ??
2131 cands.find((n) => n.filePath === node.filePath) ??
2132 cands[0];
2133 if (!target || target.id === node.id) continue;
2134 const key = `${node.id}>${target.id}`;
2135 if (seen.has(key)) continue;
2136 seen.add(key);
2137 const line = node.startLine + safe.slice(0, m.index).split('\n').length - 1;
2138 edges.push({
2139 source: node.id,
2140 target: target.id,
2141 kind: 'calls',
2142 line,
2143 provenance: 'heuristic',
2144 metadata: { synthesizedBy: 'redux-thunk', via: name, registeredAt: `${node.filePath}:${line}` },
2145 });
2146 added++;
2147 }
2148 }
2149 return edges;
2150}
2151
2152// ── Object-literal registry dispatch ─────────────────────────────────────────
2153// A command/handler registry maps string keys → handler class/function symbols in an

Callers 1

Calls 7

stripCommentsForRegexFunction · 0.90
sliceLinesFunction · 0.85
readFileMethod · 0.80
hasMethod · 0.80
iterateNodesByKindMethod · 0.65
execMethod · 0.65
getNodesByNameMethod · 0.65

Tested by

no test coverage detected