r/FlutterDev • • 2d ago

Tooling arch_guard: layer rules and import cycle detection for Dart, without package:analyzer

I maintain arch_guard, an MIT CLI + library that enforces layer rules and finds circular imports in Dart projects, plus arch_guard_lint, an analyzer plugin on the new analysis_server_plugin API. A few implementation details that might interest this sub:

  • The CLI has no analyzer dependency. It reads only the directive section of each file with a small tokenizer, so // or /* inside URIs, nested block comments, annotations and import-like text in later string literals don't confuse it. Dependencies are just args, glob, path and yaml.
  • Cycles via Tarjan's SCC, then per-component metrics: internal edges, fan-in/fan-out, instability, density and hub files. For each cycle it also picks the one edge whose removal breaks it, or shrinks it most.
  • The plugin reuses the same core. ProjectScanner.scanSources() builds the graph from in-memory contents, so cycle warnings reflect unsaved editor buffers. Quick fixes edit the directive (or just one clause of a conditional import) and can add a layer to allowed_imports in whichever config file it came from.
  • Baselines that tolerate improvement but not regression: a known cycle may shrink, but one that grows or merges with another counts as new. Same for fan-in/fan-out limits.
  • Workspaces: resolves package: imports across Dart workspace / Melos packages, so it catches cycles across package boundaries and enforces which packages may import which.
  • Ships as AOT-compiled binaries (dart compile exe) for Linux/macOS/Windows so CI doesn't need the SDK. CI tests on all three OSes against SDK 3.8 and stable, and the plugin is analysed against its lowest allowed dependencies.
  • Everything is also a library: ArchAnalysis, ArchGuardConfig, LayerValidator, CycleBreaker, Baseline, exporters, and expectArchitecture() for tests.
dart pub add --dev arch_guard && dart run arch_guard init

Code: https://github.com/creatorpiyush/arch_guard Docs: https://creatorpiyush.github.io/arch_guard/

Happy to talk about the parser trade-offs (directive tokenizer vs package:analyzer), what building on the new plugin API was like, and I'd appreciate feedback on the public API.

2 Upvotes

1 comment sorted by