From 8a0367c505db0507fa7664ce6f70b412d7539757 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sun, 13 Sep 2026 18:25:31 +0530 Subject: [PATCH] Attribute calls in a module level anonymous closure to the file node Number 1740 fixed calls inside an anonymous callback by attributing them to the enclosing named function, but that only works when a named function actually encloses it. it("...", async () => { ... }) has no such enclosing function anywhere, and that shape hits test files hardest since it is the idiomatic way to write one. The original report already named the intended fallback, attribute to the module node when no named function encloses the call, but that half was never built. A topmost closure argument to a module level call statement now gets its own function_bodies entry keyed by the file node, mirroring the existing fix for this.X assignments found in the exact same statement shape, so the ordinary call walking machinery, including its own descent into further nested closures, picks it up from there. Toward #3124. Known gap left open, described in the new test module's own docstring: a callee that is both directly imported by the same file and only called from a module level anonymous closure still does not resolve, because the cross file resolution pass dedupes purely by source and target regardless of relation, so the file node's own import edge to that target pre-empts the calls edge. Fixing that dedup properly reaches far beyond this one case and is left for a separate change. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh --- graphify/extractors/engine.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/graphify/extractors/engine.py b/graphify/extractors/engine.py index aeec2574a..18c3a66ed 100644 --- a/graphify/extractors/engine.py +++ b/graphify/extractors/engine.py @@ -2397,6 +2397,22 @@ def _js_extra_walk(node, source: bytes, file_nid: str, stem: str, str_path: str, add_node_fn=add_node_fn, add_edge_fn=add_edge_fn, function_bodies=function_bodies, ) + # #3124: calls made directly inside this closure (not just + # `this.X = fn` member assignments) were dropped entirely, + # since walk_calls only ever runs on function_bodies + # entries and this closure has no named owner to seed one. + # `it("...", async () => { register(...) })` is exactly + # this shape: the nearest enclosing scope is anonymous, so + # #1740's "attribute to the enclosing function" fix never + # applies and nothing is emitted, not even to the file + # node #1740 itself named as the fallback. Attribute calls + # here to the file node instead, mirroring the member + # assignment attribution just above -- a nested member + # function's own body is appended with its own real id by + # `_js_scan_member_assignments`, so it lands in + # `_tracked_body_ids` and walk_calls' own boundary check + # skips re-descending into it from here. + function_bodies.append((file_nid, closure_body)) assign = next((c for c in node.children if c.type == "assignment_expression"), None) if assign is not None: