MCPcopy Create free account
hub / github.com/Graphify-Labs/graphify / _dynamic_import_js

Function _dynamic_import_js

graphify/extract.py:1951–2015  ·  view source on GitHub ↗

Detect dynamic import() calls in JS/TS and emit imports_from edges. Handles patterns like: await import('./foo.js') import('./foo.js').then(...) const m = await import(`./foo`) Returns True if the node was a dynamic import (caller should skip normal call handling).

(node, source: bytes, caller_nid: str, str_path: str, edges: list,
                       seen_dyn_pairs: set)

Source from the content-addressed store, hash-verified

1949
1950
1951def _dynamic_import_js(node, source: bytes, caller_nid: str, str_path: str, edges: list,
1952 seen_dyn_pairs: set) -> bool:
1953 """Detect dynamic import() calls in JS/TS and emit imports_from edges.
1954
1955 Handles patterns like:
1956 await import('./foo.js')
1957 import('./foo.js').then(...)
1958 const m = await import(`./foo`)
1959
1960 Returns True if the node was a dynamic import (caller should skip normal call handling).
1961 """
1962 # Dynamic import is a call_expression whose function child is the keyword "import".
1963 # tree-sitter-typescript parses `import('...')` as call_expression with first child
1964 # being an "import" token (type="import").
1965 func_node = node.child_by_field_name("function")
1966 if func_node is None:
1967 # Fallback: check first child directly (some TS versions)
1968 if node.children and _read_text(node.children[0], source) == "import":
1969 func_node = node.children[0]
1970 else:
1971 return False
1972 if _read_text(func_node, source) != "import":
1973 return False
1974
1975 # Extract the module path from the arguments
1976 args = node.child_by_field_name("arguments")
1977 if args is None:
1978 return True # It's an import() but no args — skip
1979 for arg in args.children:
1980 if arg.type == "template_string":
1981 # Skip dynamic template literals — path can't be statically resolved
1982 if any(c.type == "template_substitution" for c in arg.children):
1983 break
1984 raw = _read_text(arg, source).strip("`")
1985 elif arg.type == "string":
1986 raw = _read_text(arg, source).strip("'\" ")
1987 else:
1988 continue
1989 if not raw:
1990 break
1991 # Resolve path using the same logic as static imports.
1992 resolved = _resolve_js_import_target(raw, str_path)
1993 if resolved is None:
1994 break
1995 tgt_nid, _ = resolved
1996 pair = (caller_nid, tgt_nid)
1997 if pair not in seen_dyn_pairs:
1998 seen_dyn_pairs.add(pair)
1999 edges.append({
2000 "source": caller_nid,
2001 "target": tgt_nid,
2002 # A deferred `import(...)` is a real dependency, so keep it as an
2003 # `imports_from` edge (visible in the graph) but mark it `deferred`
2004 # so find_import_cycles does not treat it as a static import and
2005 # report a phantom file cycle (#1241).
2006 "relation": "imports_from",
2007 "context": "import",
2008 "deferred": True,

Callers 1

walk_callsFunction · 0.85

Calls 2

_read_textFunction · 0.90

Tested by

no test coverage detected