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

Function normalizeValue

src/extraction/function-ref.ts:525–597  ·  view source on GitHub ↗

* Normalize one value expression to zero or more function names. Recursion is * bounded (wrapper layers only); anything that isn't a recognized * function-value shape yields [].

(
  node: SyntaxNode,
  spec: FnRefSpec,
  source: string,
  depth: number
)

Source from the content-addressed store, hash-verified

523 * function-value shape yields [].
524 */
525function normalizeValue(
526 node: SyntaxNode,
527 spec: FnRefSpec,
528 source: string,
529 depth: number
530): NormalizedRef[] {
531 if (depth > 4) return [];
532 const type = node.type;
533
534 // Bare identifier
535 if (spec.idTypes.has(type)) {
536 return [{ name: getNodeText(node, source), node }];
537 }
538
539 // Transparent layers (argument, value_argument, literal_element,
540 // expression_list, block_argument). expression_list fans out (Go `a, b = f, g`).
541 const layerField = spec.layers?.get(type);
542 if (spec.layers?.has(type)) {
543 // Labeled-argument param-forward skip (Swift/Kotlin): `value: value` /
544 // `delay: delay` — when the label EQUALS the value identifier, the value
545 // is a forwarded local/parameter, not a function reference (Alamofire
546 // A/B finding; same rationale as the `this.x = x` assignment skip).
547 if (type === 'value_argument') {
548 const label = getChildByField(node, 'name');
549 const value = getChildByField(node, 'value') ?? node.namedChild(node.namedChildCount - 1);
550 if (
551 label &&
552 value &&
553 getNodeText(label, source).trim() === getNodeText(value, source).trim()
554 ) {
555 return [];
556 }
557 }
558 if (layerField) {
559 const inner = getChildByField(node, layerField);
560 return inner ? normalizeValue(inner, spec, source, depth + 1) : [];
561 }
562 const results: NormalizedRef[] = [];
563 for (let i = 0; i < node.namedChildCount; i++) {
564 const child = node.namedChild(i);
565 if (child) results.push(...normalizeValue(child, spec, source, depth + 1));
566 }
567 return results;
568 }
569
570 // Unary wrappers: &fn / @Fn / `fn _`
571 const unwrapField = spec.unwrap?.get(type);
572 if (spec.unwrap?.has(type)) {
573 // C-family `pointer_expression` covers BOTH `&x` (address-of — a function
574 // value) and `*x` (dereference — a data read, never a function value).
575 // Only `&` qualifies; without this, fmt's `*begin` reads resolved to its
576 // free `begin()` functions.
577 if (type === 'pointer_expression' && node.child(0)?.type !== '&') return [];
578 const inner = unwrapField ? getChildByField(node, unwrapField) : node.namedChild(0);
579 if (!inner) return [];
580 // C++ `&Widget::on_click` — keep the QUALIFIED name. Resolution scopes the
581 // method to that class (more precise than a bare-name match, and exempt
582 // from the cpp bare-ids-are-free-functions rule since `&Cls::m` is an

Callers 1

captureFnRefCandidatesFunction · 0.85

Calls 5

getNodeTextFunction · 0.90
getChildByFieldFunction · 0.90
normalizeSpecialFunction · 0.85
hasMethod · 0.80
getMethod · 0.65

Tested by

no test coverage detected