@@ -1563,10 +1563,24 @@ def is_numerical_code(code_string: str, function_name: str | None = None) -> boo
15631563def get_opt_review_metrics (
15641564 source_code : str , file_path : Path , qualified_name : str , project_root : Path , tests_root : Path , language : Language
15651565) -> str :
1566- if language != Language .PYTHON :
1567- # TODO: {Claude} handle function refrences for other languages
1568- return ""
15691566 start_time = time .perf_counter ()
1567+
1568+ if language == Language .PYTHON :
1569+ calling_fns_details = _get_python_references (source_code , file_path , qualified_name , project_root , tests_root )
1570+ elif language in (Language .JAVASCRIPT , Language .TYPESCRIPT ):
1571+ calling_fns_details = _get_javascript_references (file_path , qualified_name , project_root , tests_root )
1572+ else :
1573+ calling_fns_details = ""
1574+
1575+ end_time = time .perf_counter ()
1576+ logger .debug (f"Got function references in { end_time - start_time :.2f} seconds" )
1577+ return calling_fns_details
1578+
1579+
1580+ def _get_python_references (
1581+ source_code : str , file_path : Path , qualified_name : str , project_root : Path , tests_root : Path
1582+ ) -> str :
1583+ """Get function references for Python code using jedi."""
15701584 try :
15711585 qualified_name_split = qualified_name .rsplit ("." , maxsplit = 1 )
15721586 if len (qualified_name_split ) == 1 :
@@ -1576,10 +1590,142 @@ def get_opt_review_metrics(
15761590 matches = get_fn_references_jedi (
15771591 source_code , file_path , project_root , target_function , target_class
15781592 ) # jedi is not perfect, it doesn't capture aliased references
1579- calling_fns_details = find_occurances (qualified_name , str (file_path ), matches , project_root , tests_root )
1593+ return find_occurances (qualified_name , str (file_path ), matches , project_root , tests_root )
15801594 except Exception as e :
1581- calling_fns_details = ""
1582- logger .debug (f"Investigate { e } " )
1583- end_time = time .perf_counter ()
1584- logger .debug (f"Got function references in { end_time - start_time :.2f} seconds" )
1585- return calling_fns_details
1595+ logger .debug (f"Error getting Python references: { e } " )
1596+ return ""
1597+
1598+
1599+ def _get_javascript_references (
1600+ file_path : Path , qualified_name : str , project_root : Path , tests_root : Path
1601+ ) -> str :
1602+ """Get function references for JavaScript/TypeScript code using tree-sitter.
1603+
1604+ This function finds all call sites of a JavaScript/TypeScript function
1605+ across the codebase and formats them for the optimizer's context.
1606+ """
1607+ try :
1608+ from codeflash .languages .javascript .find_references import ReferenceFinder
1609+ from codeflash .languages .treesitter_utils import get_analyzer_for_file
1610+
1611+ # Extract function name from qualified name
1612+ # Qualified name could be "functionName" or "ClassName.methodName"
1613+ function_name = qualified_name .rsplit ("." , maxsplit = 1 )[- 1 ]
1614+
1615+ finder = ReferenceFinder (project_root )
1616+ references = finder .find_references (function_name , file_path , max_files = 500 )
1617+
1618+ if not references :
1619+ return ""
1620+
1621+ # Format references similar to Python format
1622+ fn_call_context = ""
1623+ context_len = 0
1624+
1625+ # Group references by file
1626+ refs_by_file : dict [Path , list ] = {}
1627+ for ref in references :
1628+ # Exclude test files
1629+ try :
1630+ if ref .file_path .relative_to (tests_root ):
1631+ continue
1632+ except ValueError :
1633+ pass
1634+
1635+ # Exclude the source file's definition
1636+ if ref .file_path == file_path and ref .reference_type == "import" :
1637+ continue
1638+
1639+ if ref .file_path not in refs_by_file :
1640+ refs_by_file [ref .file_path ] = []
1641+ refs_by_file [ref .file_path ].append (ref )
1642+
1643+ for ref_file , file_refs in refs_by_file .items ():
1644+ if context_len > MAX_CONTEXT_LEN_REVIEW :
1645+ break
1646+
1647+ try :
1648+ path_relative = ref_file .relative_to (project_root )
1649+ except ValueError :
1650+ continue
1651+
1652+ # Get the file extension for syntax highlighting
1653+ ext = ref_file .suffix .lstrip ("." )
1654+ lang = "typescript" if ext in ("ts" , "tsx" ) else "javascript"
1655+
1656+ # Read the file to extract calling function context
1657+ try :
1658+ file_content = ref_file .read_text (encoding = "utf-8" )
1659+ lines = file_content .splitlines ()
1660+ except Exception :
1661+ continue
1662+
1663+ # Get unique caller functions from this file
1664+ callers_seen = set ()
1665+ caller_contexts = []
1666+
1667+ for ref in file_refs :
1668+ caller = ref .caller_function or "<module>"
1669+ if caller in callers_seen :
1670+ continue
1671+ callers_seen .add (caller )
1672+
1673+ # Extract context around the reference (the calling function or surrounding lines)
1674+ if ref .caller_function :
1675+ # Try to extract the full calling function
1676+ func_code = _extract_calling_function_js (file_content , ref .caller_function , ref .line )
1677+ if func_code :
1678+ caller_contexts .append (func_code )
1679+ context_len += len (func_code )
1680+ else :
1681+ # Module-level call - just show a few lines of context
1682+ start_line = max (0 , ref .line - 3 )
1683+ end_line = min (len (lines ), ref .line + 2 )
1684+ context_code = "\n " .join (lines [start_line :end_line ])
1685+ caller_contexts .append (context_code )
1686+ context_len += len (context_code )
1687+
1688+ if caller_contexts :
1689+ fn_call_context += f"```{ lang } :{ path_relative } \n "
1690+ fn_call_context += "\n " .join (caller_contexts )
1691+ fn_call_context += "\n ```\n "
1692+
1693+ return fn_call_context
1694+
1695+ except Exception as e :
1696+ logger .debug (f"Error getting JavaScript references: { e } " )
1697+ return ""
1698+
1699+
1700+ def _extract_calling_function_js (source_code : str , function_name : str , ref_line : int ) -> str | None :
1701+ """Extract the source code of a calling function in JavaScript/TypeScript.
1702+
1703+ Args:
1704+ source_code: Full source code of the file.
1705+ function_name: Name of the function to extract.
1706+ ref_line: Line number where the reference is (helps identify the right function).
1707+
1708+ Returns:
1709+ Source code of the function, or None if not found.
1710+ """
1711+ try :
1712+ from codeflash .languages .treesitter_utils import TreeSitterAnalyzer , TreeSitterLanguage
1713+
1714+ # Try TypeScript first, fall back to JavaScript
1715+ for lang in [TreeSitterLanguage .TYPESCRIPT , TreeSitterLanguage .TSX , TreeSitterLanguage .JAVASCRIPT ]:
1716+ try :
1717+ analyzer = TreeSitterAnalyzer (lang )
1718+ functions = analyzer .find_functions (source_code , include_methods = True )
1719+
1720+ for func in functions :
1721+ if func .name == function_name :
1722+ # Check if the reference line is within this function
1723+ if func .start_line <= ref_line <= func .end_line :
1724+ return func .source_text
1725+ break
1726+ except Exception :
1727+ continue
1728+
1729+ return None
1730+ except Exception :
1731+ return None
0 commit comments