MCPcopy
hub / github.com/colbymchenry/codegraph / captureFnRefCandidates

Function captureFnRefCandidates

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

Source from the content-addressed store, hash-verified

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