NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #4035 most downloaded on pub.dev
ArchUnit-inspired architecture testing for Dart & Flutter. Enforce layer boundaries, slice isolation, cycles, coupling metrics, and violation baselines — all in plain Dart tests.
Last release 7 months ago
12 Mar 2026
Too new to tell
only 1 release windows
Nearly every release is documented
notes for 5 of 5 stable releases
Nothing withdrawn
no release was ever pulled
7 months old
5 releases · first in 2026
One column per month.
Cycle detection performance — Collector.cycles now uses a done set (DFS memoisation) to avoid re-exploring already-completed subtrees, reducing worst-
Bug fixes / performance:
Collector.cycles now uses a done set (DFS memoisation) to avoid re-exploring already-completed subtrees, reducing worst-case complexity from O(n!) to O(n + e)._globMatch refactor — assertions.dart now delegates to the shared matchesGlob helper in pattern.dart, removing duplicated glob logic.Variadic `union()` — now accepts 2–5 selectors instead of exactly 2, eliminating the need for deep nesting: `dart // Before (0.2.x) union(a, union(b,
New features:
Variadic union() — now accepts 2–5 selectors instead of exactly 2, eliminating the need for deep nesting:
// Before (0.2.x)
union(a, union(b, union(c, d)))
// Now
union(a, b, c, d)
difference(a, b) — new top-level set operation returning libraries in a but not in b:
// All feature files except generated code
difference(filesMatching('features/**'), filesMatching('features/**/*.g.dart'))
except: parameter on all assertion functions — exclude a subset of subjects from a rule without splitting it into two tests:
shouldNotDependOn(
filesMatching('shared/**'),
filesMatching('features/**'),
graph,
except: filesMatching('shared/guards/**'), // guards are a bridge by design
);
shouldNotTransitivelyDependOn(subject, object, graph, except: filesMatching('...'));
shouldOnlyDependOn(subject, allowed, graph, except: filesMatching('...'));
shouldNotBeCalledBy(object, callers, graph, except: filesMatching('...'));
shouldOnlyBeCalledBy(object, allowed, graph, except: filesMatching('...'));
Content-based selectors (extending, implementing, withAnnotation) — select libraries by what their classes declare, not just by file path:
// Every ChangeNotifier subclass must live in a providers/ folder
shouldHaveUriMatching(extending('ChangeNotifier'), '**/providers/**', graph);
// UnreadCountSource implementations must stay in shared/
shouldNotDependOn(implementing('UnreadCountSource'), filesMatching('features/**'), graph);
// @immutable models must not import services
shouldNotTransitivelyDependOn(withAnnotation('immutable'), filesMatching('**/services/**'), graph);
Root path is inferred from the nearest pubspec.yaml walking up from CWD, or overridden via the DART_ARCH_TEST_ROOT environment variable.
Exports: difference, extending, implementing, withAnnotation are now exported from package:dart_arch_test/dart_arch_test.dart.
Fixed Collector.buildGraph crashing under flutter test with PathNotFoundException on artifacts/engine/version and lib/_internal/libraries.dart. Under
Bug fix:
Collector.buildGraph crashing under flutter test with
PathNotFoundException on artifacts/engine/version and
lib/_internal/libraries.dart. Under flutter test,
Platform.resolvedExecutable is flutter_tester (not dart), so the
analyzer package's getSdkPath() resolved to the wrong directory.
Collector now walks up the directory tree to find the real Dart SDK
(bin/cache/dart-sdk/) before falling back to the previous behaviour.…in 7.x, removed in 9.x) to result.element (deprecated in 7.x, stable in 9.x). The // ignore: deprecated_member_use suppression keeps the code clean on…
Bug fix:
Collector.buildGraph now compiles against analyzer ≥9.0.0: switched from
result.element2 (experimental in 7.x, removed in 9.x) to result.element
(deprecated in 7.x, stable in 9.x). The // ignore: deprecated_member_use
suppression keeps the code clean on both analyzer ranges.`Metrics` — Robert C. Martin coupling metrics from the import graph:
New features:
Metrics — Robert C. Martin coupling metrics from the import graph:
Metrics.coupling(uri, graph) — afferent coupling (Ca), efferent coupling (Ce), instability, abstractness, distance for a single libraryMetrics.instability(uri, graph) — convenience shorthand for Ce / (Ca + Ce)Metrics.martin(pattern, graph) — bulk report for all libraries matching a glob patternCouplingMetrics — immutable data class holding all five metric fieldsFreeze — violation baseline / snapshot support:
freeze(ruleId, () { ... }) — top-level convenience function; passes if violations match the baseline, fails with FreezeFailure on new violationsFreeze.freeze(ruleId, assertion, {storeDir}) — class-based API with optional custom store directoryFreeze.updateFreeze() — returns true when DART_ARCH_TEST_UPDATE_FREEZE=1 is setFreeze.storePath() — returns the baseline directory (env DART_ARCH_TEST_FREEZE_STORE or test/arch_test_violations/)FreezeFailure — exception type thrown when new violations are detectedSlices additions:
allLibrariesCoveredBy(scope, graph, {except}) — asserts every library in scope belongs to at least one declared slice; except accepts glob patterns to skipsliceCycles(graph) — returns all dependency cycles at the slice levelshouldBeFreeOfSliceCycles(graph) — throws ArchTestFailure if any slice-level cycle existsExports: CouplingMetrics, Metrics, Freeze, FreezeFailure, freeze are now exported from package:dart_arch_test/dart_arch_test.dart.
Your coding agent can read these notes before it upgrades. Set up the MCP server →