@@ -454,23 +454,46 @@ def find_imports(self, source: str) -> list[ImportInfo]:
454454
455455 return imports
456456
457- def _walk_tree_for_imports (self , node : Node , source_bytes : bytes , imports : list [ImportInfo ]) -> None :
458- """Recursively walk the tree to find import statements."""
457+ def _walk_tree_for_imports (
458+ self , node : Node , source_bytes : bytes , imports : list [ImportInfo ], in_function : bool = False
459+ ) -> None :
460+ """Recursively walk the tree to find import statements.
461+
462+ Args:
463+ node: Current node to check.
464+ source_bytes: Source code bytes.
465+ imports: List to append found imports to.
466+ in_function: Whether we're currently inside a function/method body.
467+ """
468+ # Track when we enter function/method bodies
469+ # These node types contain function/method bodies where require() should not be treated as imports
470+ function_body_types = {
471+ "function_declaration" ,
472+ "method_definition" ,
473+ "arrow_function" ,
474+ "function_expression" ,
475+ "function" , # Generic function in some grammars
476+ }
477+
459478 if node .type == "import_statement" :
460479 import_info = self ._extract_import_info (node , source_bytes )
461480 if import_info :
462481 imports .append (import_info )
463482
464- # Also handle require() calls for CommonJS
465- if node .type == "call_expression" :
483+ # Also handle require() calls for CommonJS, but only at module level
484+ # require() inside functions is a dynamic import, not a module import
485+ if node .type == "call_expression" and not in_function :
466486 func_node = node .child_by_field_name ("function" )
467487 if func_node and self .get_node_text (func_node , source_bytes ) == "require" :
468488 import_info = self ._extract_require_info (node , source_bytes )
469489 if import_info :
470490 imports .append (import_info )
471491
492+ # Update in_function flag for children
493+ child_in_function = in_function or node .type in function_body_types
494+
472495 for child in node .children :
473- self ._walk_tree_for_imports (child , source_bytes , imports )
496+ self ._walk_tree_for_imports (child , source_bytes , imports , child_in_function )
474497
475498 def _extract_import_info (self , node : Node , source_bytes : bytes ) -> ImportInfo | None :
476499 """Extract import information from an import statement node."""
@@ -841,20 +864,27 @@ def _extract_commonjs_export(self, node: Node, source_bytes: bytes) -> ExportInf
841864 end_line = node .end_point [0 ] + 1 ,
842865 )
843866
844- def is_function_exported (self , source : str , function_name : str ) -> tuple [bool , str | None ]:
867+ def is_function_exported (
868+ self , source : str , function_name : str , class_name : str | None = None
869+ ) -> tuple [bool , str | None ]:
845870 """Check if a function is exported and get its export name.
846871
872+ For class methods, also checks if the containing class is exported.
873+
847874 Args:
848875 source: The source code to analyze.
849876 function_name: The name of the function to check.
877+ class_name: For class methods, the name of the containing class.
850878
851879 Returns:
852880 Tuple of (is_exported, export_name). export_name may differ from
853- function_name if exported with an alias.
881+ function_name if exported with an alias. For class methods,
882+ returns the class export name.
854883
855884 """
856885 exports = self .find_exports (source )
857886
887+ # First, check if the function itself is directly exported
858888 for export in exports :
859889 # Check default export
860890 if export .default_export == function_name :
@@ -865,6 +895,18 @@ def is_function_exported(self, source: str, function_name: str) -> tuple[bool, s
865895 if name == function_name :
866896 return (True , alias if alias else name )
867897
898+ # For class methods, check if the containing class is exported
899+ if class_name :
900+ for export in exports :
901+ # Check if class is default export
902+ if export .default_export == class_name :
903+ return (True , class_name )
904+
905+ # Check if class is in named exports
906+ for name , alias in export .exported_names :
907+ if name == class_name :
908+ return (True , alias if alias else name )
909+
868910 return (False , None )
869911
870912 def find_function_calls (self , source : str , within_function : FunctionNode ) -> list [str ]:
0 commit comments