You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Dart import edges are never resolved to file nodes. The edge is created, but its target is the import path as a string node with source_file: None, so nothing connects it to the file it names. Reverse traversal is therefore blind: affected returns "No affected nodes found" for a file whose importer is visible on line 5 of the source.
Measured on a real Flutter repo (76 source files, 636 nodes, 840 edges), graphify 0.9.30:
graphify/extractors/dart.py, section # 6. Imports and Exports:
forminre.finditer(r"""^\s*import\s+['"]([^'"]+)['"]""", src_clean, re.MULTILINE):
pkg=m.group(1)
tgt_nid=_make_id(pkg) # id from the raw stringadd_node(tgt_nid, pkg, source_file=None) # never linked to a fileadd_edge(file_nid, tgt_nid, "imports")
JS/TS goes through _resolve_js_import_target() in graphify/extractors/resolution.py, which returns _make_id(str(resolved_path)) — the same id the file node carries — so the edge lands on the real file. Dart has an extractor but no resolver counterpart.
Impact
Every question needing reverse traversal fails on Dart, while symbol-level relations work fine. On a 9-question battery over the same repo, the five questions requiring resolved import edges (who imports X, who instantiates Y, which file is most depended on) all failed; the three resting on inherits / implements / references all passed. Coverage itself is fine — 55/55 .dart files are in the graph.
This matters more in Flutter than the numbers suggest, because widget composition lives inside build(): "where is CellWidget constructed" is the ordinary question, and it is unanswerable without a cross-file edge to walk.
Not a criticism of either PR — just flagging that neither closes this, in case it is assumed:
feat(extract): tree-sitter-based Dart extraction with source_location line anchors #2114 (tree-sitter Dart extraction) keeps the same import handling; the new _handle_import_export() still does tgt_nid = _make_id(pkg) / add_node(..., source_file=None). The 1038-line diff contains no reference to resolution or _resolve_. The defect is orthogonal to the extraction backend.
fix: materialize internal import endpoints in monorepos #2174 (materialize internal import endpoints in monorepos) covers Python and JS/TS. Its "unresolved internal" endpoint classification would at least make these 139 edges visible as a diagnostic rather than silent, which seems worth having regardless.
Suggested shape
Mirroring _resolve_js_import_target, Dart needs noticeably less machinery than JS/TS — no extension inference (.dart is mandatory), no directory index convention, no path aliases:
raw.startswith(".") → relative to the importing file's directory, normalized.
package:<name>/<subpath> where <name> matches name: in the nearest pubspec.yaml → <pubspec_dir>/lib/<subpath>.
part / part of directives are a separate concern and could stay out of a first pass.
Happy to send a PR for this if it would be useful, or to leave it to whoever is already in dart.py — say which is easier, since #2114 touches the same function.
Summary
Dart import edges are never resolved to file nodes. The edge is created, but its target is the import path as a string node with
source_file: None, so nothing connects it to the file it names. Reverse traversal is therefore blind:affectedreturns "No affected nodes found" for a file whose importer is visible on line 5 of the source.Measured on a real Flutter repo (76 source files, 636 nodes, 840 edges), graphify 0.9.30:
imports_fromedges)Reproduce
Any Flutter/Dart project:
GRAPHIFY_FORCE=1 graphify . --code-onlyA concrete edge from the repo I measured, where
grid_screen.dartline 5 isimport '../cell/cell_widget.dart';:Cause
graphify/extractors/dart.py, section# 6. Imports and Exports:JS/TS goes through
_resolve_js_import_target()ingraphify/extractors/resolution.py, which returns_make_id(str(resolved_path))— the same id the file node carries — so the edge lands on the real file. Dart has an extractor but no resolver counterpart.Impact
Every question needing reverse traversal fails on Dart, while symbol-level relations work fine. On a 9-question battery over the same repo, the five questions requiring resolved import edges (who imports X, who instantiates Y, which file is most depended on) all failed; the three resting on
inherits/implements/referencesall passed. Coverage itself is fine — 55/55.dartfiles are in the graph.This matters more in Flutter than the numbers suggest, because widget composition lives inside
build(): "where isCellWidgetconstructed" is the ordinary question, and it is unanswerable without a cross-file edge to walk.Note on #2114 and #2174
Not a criticism of either PR — just flagging that neither closes this, in case it is assumed:
_handle_import_export()still doestgt_nid = _make_id(pkg)/add_node(..., source_file=None). The 1038-line diff contains no reference toresolutionor_resolve_. The defect is orthogonal to the extraction backend.Suggested shape
Mirroring
_resolve_js_import_target, Dart needs noticeably less machinery than JS/TS — no extension inference (.dartis mandatory), no directory index convention, no path aliases:raw.startswith(".")→ relative to the importing file's directory, normalized.package:<name>/<subpath>where<name>matchesname:in the nearestpubspec.yaml→<pubspec_dir>/lib/<subpath>.dart:*and otherpackage:*→ external; return the_make_id("ref", raw)namespaced id, as_resolve_js_import_targetalready does to avoid the Unresolved bare npm import gets aliased onto an unrelated same-named local file (cross-language phantom edge) #1638 collision.part/part ofdirectives are a separate concern and could stay out of a first pass.Happy to send a PR for this if it would be useful, or to leave it to whoever is already in
dart.py— say which is easier, since #2114 touches the same function.