Recursively find `function_call` nodes inside a given node and create unresolved Calls references.
(state: &mut ExtractionState, node: TsNode<'_>, fn_node_id: &str)
| 499 | |
| 500 | /// Recursively find `function_call` nodes inside a given node and create unresolved Calls references. |
| 501 | fn extract_call_sites(state: &mut ExtractionState, node: TsNode<'_>, fn_node_id: &str) { |
| 502 | let mut cursor = node.walk(); |
| 503 | if cursor.goto_first_child() { |
| 504 | loop { |
| 505 | let child = cursor.node(); |
| 506 | match child.kind() { |
| 507 | "function_call" => { |
| 508 | // Extract the callee name. |
| 509 | if let Some(name_node) = child.child_by_field_name("name") { |
| 510 | let callee_name = match name_node.kind() { |
| 511 | "dot_index_expression" => { |
| 512 | // e.g. string.format → "string.format" |
| 513 | state.node_text(name_node) |
| 514 | } |
| 515 | "method_index_expression" => { |
| 516 | // e.g. conn:connect → "conn:connect" |
| 517 | state.node_text(name_node) |
| 518 | } |
| 519 | _ => state.node_text(name_node), |
| 520 | }; |
| 521 | state.unresolved_refs.push(UnresolvedRef { |
| 522 | from_node_id: fn_node_id.to_string(), |
| 523 | reference_name: callee_name, |
| 524 | reference_kind: EdgeKind::Calls, |
| 525 | line: child.start_position().row as u32, |
| 526 | column: child.start_position().column as u32, |
| 527 | file_path: state.file_path.clone(), |
| 528 | }); |
| 529 | } |
| 530 | // Recurse into the call for nested calls. |
| 531 | Self::extract_call_sites(state, child, fn_node_id); |
| 532 | } |
| 533 | // Skip nested function declarations. |
| 534 | "function_declaration" => {} |
| 535 | _ => { |
| 536 | Self::extract_call_sites(state, child, fn_node_id); |
| 537 | } |
| 538 | } |
| 539 | if !cursor.goto_next_sibling() { |
| 540 | break; |
| 541 | } |
| 542 | } |
| 543 | } |
| 544 | } |
| 545 | |
| 546 | /// Build the final `ExtractionResult` from the accumulated state. |
| 547 | fn build_result(state: ExtractionState, start: Instant) -> ExtractionResult { |