mirror of
https://github.com/safishamsi/graphify.git
synced 2026-08-28 09:17:02 +00:00
test(js): cover dynamic-require skip and no-double-count for lazy requires (#2700)
Adds the two invariants the deep-dive flagged: require(variable) must not fabricate an edge, and a module-scope require still yields exactly one imports_from edge (guards the module-vs-body pass partition against future double-counting). Also adds the CHANGELOG entry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
259bb6acfb
commit
e5d662eb63
@@ -4,6 +4,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu
|
||||
|
||||
## 0.9.44 (unreleased)
|
||||
|
||||
- Fix: a lazy CommonJS `require(...)` inside a function body (the idiom for breaking circular dependencies) now emits the same `imports_from`/`imports` dependency edges as a top-level require, attributed to the enclosing function, instead of being silently dropped; a dynamic `require(variable)` is still skipped (#2700, thanks @rajanpanth).
|
||||
- Fix: a JS/TS identifier bound by an import whose target resolves outside the scanned corpus (e.g. a `lucide-react` icon) is now shadowed, so using it as a value no longer fabricates an INFERRED `indirect_call` onto an unrelated same-named callable elsewhere in the corpus; a relative/in-corpus import still resolves to its real target (#2757, thanks @phudayyy).
|
||||
- Fix: an OCaml qualified call `M.f` to an external module (one not defined in the same file, e.g. Hardcaml's `Reg_spec.create`) no longer binds to a same-named local `let f` — which produced a false `calls` edge and, when the caller was that local `f`, a `f -> f` self-loop. External qualified calls are kept as a distinct target labelled by the full path; unqualified calls and calls into a locally-defined module still resolve locally, and cross-file `Geo.area` still collapses onto another file's `area`.
|
||||
|
||||
|
||||
@@ -801,6 +801,38 @@ def test_extract_js_function_scoped_require_emits_import_edge(tmp_path):
|
||||
assert lazy_edges[0]["confidence"] == "EXTRACTED"
|
||||
|
||||
|
||||
def test_extract_js_dynamic_require_variable_is_not_fabricated(tmp_path):
|
||||
"""A lazy `require(someVar)` has no static string target, so the body pass
|
||||
must skip it rather than fabricate an edge to a guessed path (#2700)."""
|
||||
caller = tmp_path / "dyn.js"
|
||||
caller.write_text(
|
||||
"function load(name) {\n"
|
||||
" const mod = require(name);\n"
|
||||
" return mod;\n"
|
||||
"}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
result = extract([caller], cache_root=tmp_path, root=tmp_path, parallel=False)
|
||||
assert not [e for e in result["edges"] if e["relation"] in ("imports_from", "imports")]
|
||||
|
||||
|
||||
def test_extract_js_module_scope_require_still_single_edge(tmp_path):
|
||||
"""No-double-count regression: the module-level and body require passes must
|
||||
never both emit for the same require — a top-level require stays exactly one
|
||||
imports_from edge (#2700)."""
|
||||
target = tmp_path / "target.js"
|
||||
target.write_text("exports.helper = () => 42;\n", encoding="utf-8")
|
||||
caller = tmp_path / "top.js"
|
||||
caller.write_text("const { helper } = require('./target');\n", encoding="utf-8")
|
||||
|
||||
result = extract([caller, target], cache_root=tmp_path, root=tmp_path, parallel=False)
|
||||
lazy_edges = [
|
||||
e for e in result["edges"]
|
||||
if e["relation"] == "imports_from" and "target" in e["target"]
|
||||
]
|
||||
assert len(lazy_edges) == 1
|
||||
|
||||
|
||||
def test_extract_js_arrow_function_still_extracted():
|
||||
"""Regression: arrow functions in lexical_declaration must still produce nodes."""
|
||||
from graphify.extract import extract_js
|
||||
|
||||
Reference in New Issue
Block a user