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

Method boundaryCandidates

src/mcp/tools.ts:2373–2430  ·  view source on GitHub ↗

* Shortlist candidate runtime targets for a dispatch key surfaced by * buildDynamicBoundaries. Exact conventional names first (`save` → * `onSave`/`handleSave`; `CreateCmd` → `CreateCmdHandler`), then FTS, with a * normalized-containment post-filter (FTS camel-splitting is fuzzier t

(cg: CodeGraph, key: string, keyIsType: boolean, named: Map<string, Node>, selfId: string)

Source from the content-addressed store, hash-verified

2371 * are marked — that's the "you were right, here's the wiring" case.
2372 */
2373 private boundaryCandidates(cg: CodeGraph, key: string, keyIsType: boolean, named: Map<string, Node>, selfId: string): string {
2374 const CALLABLE = new Set(['method', 'function', 'component', 'constructor', 'class']);
2375 const norm = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, '');
2376 const keyNorm = norm(key);
2377 if (keyNorm.length < 3) return '';
2378 const cands = new Map<string, Node>();
2379 const consider = (n: Node | undefined | null) => {
2380 if (!n || n.id === selfId || !CALLABLE.has(n.kind) || cands.has(n.id)) return;
2381 const nameNorm = norm(n.name || '');
2382 if (nameNorm.length < 3) return;
2383 if (!nameNorm.includes(keyNorm) && !keyNorm.includes(nameNorm)) return;
2384 cands.set(n.id, n);
2385 };
2386 const cap = key.charAt(0).toUpperCase() + key.slice(1);
2387 const probes = keyIsType
2388 ? [`${key}Handler`, key]
2389 : [key, `on${cap}`, `handle${cap}`, `${key}Handler`, `handle_${key}`];
2390 for (const p of probes) {
2391 try { for (const n of cg.getNodesByName(p)) consider(n); } catch { /* exact probe miss is fine */ }
2392 }
2393 let raw = 0;
2394 try {
2395 const results = cg.searchNodes(key, { limit: 12 });
2396 raw = results.length;
2397 for (const r of results) consider(r.node);
2398 } catch { /* FTS syntax edge — exact probes already ran */ }
2399 if (cands.size === 0) {
2400 return raw >= 12 && key.length < 5 ? `key \`${key}\` is too generic to shortlist (${raw}+ matches)` : '';
2401 }
2402 // A constructor candidate duplicates its class: extractors emit ctors as
2403 // METHOD nodes named like the class (C#/Java `Foo::Foo`) — keep the class.
2404 const all = [...cands.values()];
2405 const classKey = new Set(all.filter((n) => n.kind === 'class').map((n) => `${n.name}|${n.filePath}`));
2406 const namedNames = new Set([...named.values()].map((n) => n.name));
2407 const isNamed = (n: Node) => named.has(n.id) || namedNames.has(n.name); // the flow's named set holds callables only — transfer the mark to the class
2408 const list = all
2409 .filter((n) => !(n.kind !== 'class' && classKey.has(`${n.name}|${n.filePath}`)))
2410 .sort((a, b) => (isNamed(b) ? 1 : 0) - (isNamed(a) ? 1 : 0))
2411 .slice(0, 4)
2412 .map((n) => {
2413 // Typed-bus convention: the runtime target is the candidate class's
2414 // Handle/Execute/Consume method — name the exact node, not just the class.
2415 let display = n.qualifiedName || n.name;
2416 let at = `${n.filePath}:${n.startLine}`;
2417 if (keyIsType && n.kind === 'class') {
2418 try {
2419 const HANDLER_METHODS = /^(handle|handleAsync|execute|executeAsync|consume|consumeAsync|run|__invoke)$/i;
2420 const method = cg.getOutgoingEdges(n.id)
2421 .filter((e) => e.kind === 'contains')
2422 .map((e) => { try { return cg.getNode(e.target); } catch { return null; } })
2423 .find((c): c is Node => !!c && c.kind === 'method' && HANDLER_METHODS.test(c.name));
2424 if (method) { display = `${n.name}.${method.name}`; at = `${method.filePath}:${method.startLine}`; }
2425 } catch { /* class without resolvable members — show the class itself */ }
2426 }
2427 return `\`${display}\` (${at})${isNamed(n) ? ' ← you named this' : ''}`;
2428 });
2429 return `candidates for key \`${key}\`: ${list.join(', ')}`;
2430 }

Callers 1

Calls 8

considerFunction · 0.85
hasMethod · 0.80
getNodeMethod · 0.80
getNodesByNameMethod · 0.65
normFunction · 0.50
searchNodesMethod · 0.45
getOutgoingEdgesMethod · 0.45
joinMethod · 0.45

Tested by

no test coverage detected