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

Function captureFnRefCandidates

src/extraction/function-ref.ts:414–517  ·  view source on GitHub ↗
(
  container: SyntaxNode,
  rule: CaptureRule,
  spec: FnRefSpec,
  source: string
)

Source from the content-addressed store, hash-verified

412 * (name, position) pairs of every function-value-shaped expression found.
413 */
414export function captureFnRefCandidates(
415 container: SyntaxNode,
416 rule: CaptureRule,
417 spec: FnRefSpec,
418 source: string
419): FnRefCandidate[] {
420 const valueNodes: SyntaxNode[] = [];
421
422 switch (rule.mode) {
423 case 'args':
424 case 'list': {
425 for (let i = 0; i < container.namedChildCount; i++) {
426 const child = container.namedChild(i);
427 if (child) valueNodes.push(child);
428 }
429 break;
430 }
431 case 'rhs': {
432 const rhs = rule.field
433 ? getChildByField(container, rule.field)
434 : container.namedChild(container.namedChildCount - 1);
435 if (rhs) {
436 // Param-storage skip: `this.status = status` / `o->cb = cb` — when
437 // the assigned member's name EQUALS the RHS identifier, the RHS is a
438 // local/parameter being stored, and the function it holds (if any)
439 // is unknowable statically. A same-named function elsewhere would
440 // resolve to the WRONG target (excalidraw A/B finding), so skip.
441 const lhs =
442 getChildByField(container, 'left') ??
443 getChildByField(container, 'lhs') ??
444 getChildByField(container, 'target') ??
445 (container.namedChildCount >= 2 ? container.namedChild(0) : null);
446 const lhsText = lhs ? getNodeText(lhs, source) : '';
447 const lhsLastName = lhsText.match(/([A-Za-z_$][A-Za-z0-9_$]*)\s*$/)?.[1];
448 const rhsText = getNodeText(rhs, source).trim();
449 if (lhsLastName && lhsLastName === rhsText) break;
450 valueNodes.push(rhs);
451 }
452 break;
453 }
454 case 'value': {
455 let value = rule.field ? getChildByField(container, rule.field) : null;
456 // Keyed containers without a value field (Go keyed_element): the value
457 // is the LAST named child (the first is the key).
458 if (!value && container.namedChildCount > 0) {
459 value = container.namedChild(container.namedChildCount - 1);
460 }
461 if (value) valueNodes.push(value);
462 break;
463 }
464 case 'varinit': {
465 // Destructuring (`const { center } = ellipse`) extracts DATA from the
466 // RHS — never a function alias. Without this skip, a parameter that
467 // shadows a same-named imported function produced a wrong edge.
468 const nameNode =
469 getChildByField(container, 'name') ?? getChildByField(container, 'pattern');
470 if (nameNode && (nameNode.type === 'object_pattern' || nameNode.type === 'array_pattern' ||
471 nameNode.type === 'tuple_pattern' || nameNode.type === 'struct_pattern')) {

Callers 1

maybeCaptureFnRefsMethod · 0.90

Calls 4

getChildByFieldFunction · 0.90
getNodeTextFunction · 0.90
normalizeValueFunction · 0.85
hasMethod · 0.80

Tested by

no test coverage detected