Pre-scan top-level AST to collect import mappings and defined names. Returns: (import_map, defined_names) where import_map maps imported names to their source module/path, and defined_names is the set of function/class names defined at file scope.
(
self, root, language: str, source: bytes,
)
| 5229 | return False |
| 5230 | |
| 5231 | def _collect_file_scope( |
| 5232 | self, root, language: str, source: bytes, |
| 5233 | ) -> tuple[dict[str, str], set[str]]: |
| 5234 | """Pre-scan top-level AST to collect import mappings and defined names. |
| 5235 | |
| 5236 | Returns: |
| 5237 | (import_map, defined_names) where import_map maps imported names |
| 5238 | to their source module/path, and defined_names is the set of |
| 5239 | function/class names defined at file scope. |
| 5240 | """ |
| 5241 | import_map: dict[str, str] = {} |
| 5242 | defined_names: set[str] = set() |
| 5243 | |
| 5244 | class_types = set(self._class_types.get(language, [])) |
| 5245 | func_types = set(self._function_types.get(language, [])) |
| 5246 | import_types = set(self._import_types.get(language, [])) |
| 5247 | |
| 5248 | # Node types that wrap a class/function with decorators/annotations |
| 5249 | decorator_wrappers = {"decorated_definition", "decorator"} |
| 5250 | |
| 5251 | for child in root.children: |
| 5252 | node_type = child.type |
| 5253 | |
| 5254 | # Unwrap decorator wrappers to reach the inner definition |
| 5255 | target = child |
| 5256 | if node_type in decorator_wrappers: |
| 5257 | for inner in child.children: |
| 5258 | if inner.type in func_types or inner.type in class_types: |
| 5259 | target = inner |
| 5260 | break |
| 5261 | elif ( |
| 5262 | language in ("javascript", "typescript", "tsx") |
| 5263 | and node_type == "export_statement" |
| 5264 | ): |
| 5265 | for inner in child.children: |
| 5266 | if inner.type in func_types or inner.type in class_types: |
| 5267 | target = inner |
| 5268 | break |
| 5269 | |
| 5270 | target_type = target.type |
| 5271 | |
| 5272 | # R: function names live on the left side of binary_operator |
| 5273 | if language == "r" and target_type == "binary_operator": |
| 5274 | r_children = target.children |
| 5275 | if ( |
| 5276 | len(r_children) >= 3 |
| 5277 | and r_children[0].type == "identifier" |
| 5278 | and r_children[2].type == "function_definition" |
| 5279 | ): |
| 5280 | name = r_children[0].text.decode("utf-8", errors="replace") |
| 5281 | defined_names.add(name) |
| 5282 | continue |
| 5283 | |
| 5284 | # Collect defined function/class names |
| 5285 | if target_type in func_types or target_type in class_types: |
| 5286 | name = self._get_name(target, language, |
| 5287 | "class" if target_type in class_types else "function") |
| 5288 | if name: |
no test coverage detected