Skip to content

feat: full Dart language + Flutter ecosystem support#406

Open
dacianf wants to merge 2 commits intosafishamsi:v4from
dacianf:feat/dart-flutter-support
Open

feat: full Dart language + Flutter ecosystem support#406
dacianf wants to merge 2 commits intosafishamsi:v4from
dacianf:feat/dart-flutter-support

Conversation

@dacianf
Copy link
Copy Markdown

@dacianf dacianf commented Apr 16, 2026

Summary

Replaces the regex-based Dart extractor with a full tree-sitter AST implementation that brings Dart to parity with the mature Go/Rust/Elixir extractors and adds Flutter-specific structural analysis.

  • Pure Dart core — classes (sealed/final/base/abstract), mixins, extensions, enums, typedefs, functions, imports, inheritance graph, call-graph. Uses tree-sitter-dart-orchard for deterministic AST parsing. Works for server-side/CLI Dart projects with zero Flutter overhead.
  • Flutter layer (conditional on package:flutter imports) — widget classification (stateless/stateful/state/inherited), StatefulWidget↔State pairing, nested widget composition from build() methods, InheritedWidget dependency detection, Navigator API navigation edges.
  • Framework layer (conditional on framework imports) — Riverpod ref.watch/ref.readwatches_provider/reads_provider edges, BLoC on<Event>handles_event edges, GoRouter route definitions + context.go/context.pushnavigates_to edges. Follows the same pattern as the existing PHP/Laravel bound_to/listened_by edges.
  • Ecosystem file parserspubspec.yaml (package dependency graph), melos.yaml (monorepo workspaces), .arb (localization message keys).
  • Generated file exclusion.freezed.dart, .g.dart, .gr.dart, .gen.dart, .mocks.dart skipped at detect phase. .dart_tool/ added to skip dirs.

Architecture

Three-layer design where each layer is conditional and additive:

.dart file → extract.py orchestrator
                │
    ┌───────────┼───────────┐
    ▼           ▼           ▼
 Pure Dart   Flutter    Frameworks
 (always)    (if Flutter  (if framework
              imports)     imports)

Pure Dart server projects get full structural extraction (21 nodes, 40 edges on the test fixture) with zero Flutter overhead. The existing regex extractor produced 15 nodes and 14 edges with only 2 edge types (defines, imports) and no line numbers.

Changes

File What
graphify/extract_dart.py (new) Core Dart AST extractor
graphify/extract_flutter.py (new) Flutter widget/navigation layer
graphify/extract_dart_frameworks.py (new) Framework detection (Riverpod/BLoC/GoRouter)
graphify/extract_pubspec.py (new) pubspec.yaml parser
graphify/extract_melos.py (new) melos.yaml parser
graphify/extract_arb.py (new) .arb localization parser
graphify/extract.py Replace regex extractor with orchestrator, add filename dispatch
graphify/detect.py Generated Dart exclusion, .dart_tool skip
pyproject.toml Add tree-sitter-dart-orchard, pyyaml
7 test files, 8 fixtures 57 new tests

Test plan

  • 490/490 tests pass (57 new + 433 existing, zero regressions)
  • Pure Dart tests import from graphify.extract_dart (core only)
  • Flutter/framework tests import from graphify.extract (full orchestrated)
  • Pure Dart file produces identical result through core vs orchestrator (Flutter layer correctly skips)
  • Generated Dart files (.freezed.dart, .g.dart) excluded by detect.py
  • All edges include confidence_score field (v4 schema)

🤖 Generated with Claude Code

dacianf and others added 2 commits April 16, 2026 18:52
Replace the regex-based Dart extractor with a tree-sitter AST implementation
that brings Dart to parity with the mature Go/Rust/Elixir extractors and adds
Flutter-specific structural analysis.

Three-layer architecture (each layer is conditional):
1. Pure Dart core (extract_dart.py) — classes, mixins, extensions, enums,
   typedefs, functions, imports, inheritance, call-graph via tree-sitter
2. Flutter layer (extract_flutter.py) — widget classification, StatefulWidget/
   State pairing, nested composition from build(), InheritedWidget deps,
   Navigator API navigation edges. Only activates on package:flutter imports.
3. Framework layer (extract_dart_frameworks.py) — Riverpod watches_provider/
   reads_provider, BLoC handles_event/emits_state, GoRouter navigates_to.
   Only activates on framework imports.

Also adds:
- pubspec.yaml parser (package dependencies)
- melos.yaml parser (monorepo workspaces)
- .arb parser (localization message keys)
- Generated file exclusion (.freezed.dart, .g.dart, etc.)
- .dart_tool/ directory skip
- 57 new tests, 8 fixture files, 0 regressions (490/490 pass)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Correctness:
- Fix part_directive emitting wrong relation (part_of → has_part)
- Fix mixin `on` constraint target dart_kind (mixin → class)
- Fix createState regex matching any Word() instead of return value
- Fix context substring match → word boundary regex

Security:
- Add path traversal protection in extract_melos.py glob resolution

Performance:
- Move _CLASS_MODIFIERS to module-level frozenset (was rebuilt per class)
- Move _SKIP_DEPS/_SKIP_DEV_DEPS to module-level frozensets
- Compile _REF_WATCH/_REF_READ/_ON_EVENT/_EMIT_STATE regexes once at module level
- Remove redundant _EMIT_CALL guard before _EMIT_STATE.finditer()

Cleanness:
- Remove project-specific names from _KNOWN_WIDGETS set
- Remove unused class_label param from _walk_for_inherited
- Use word-boundary matching for framework import detection (prevents
  false positives like "dio" matching "studio", "hive" matching "archive")
- Create message key nodes in extract_arb.py (fixes dangling edges)
- Remove redundant `import yaml as _yaml` in extract_melos.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dacianf dacianf mentioned this pull request Apr 17, 2026
@dacianf
Copy link
Copy Markdown
Author

dacianf commented Apr 17, 2026

@safishamsi I oppend this PR to include a full flutter framework extraction. Let me know what you think about it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant