Archaven
Archaven is a Rust library for checking dependency rules inside Rust projects.
It scans Rust source files, extracts dependencies between module paths, runs your rules against those dependencies, and returns a printable list of violations. The primary use case is an architecture test that fails when code crosses a boundary it should not cross.
use ;
What Archaven Checks
Archaven works with Rust module paths such as:
app::sales::orders::domain::order
app::sales::orders::infrastructure::adapter::billing_client
app::billing::invoices::application::command::issue_invoice
For each dependency found in the source tree, Archaven asks:
source path -> target path
Then every configured Rule decides whether that dependency is allowed. A rule
can describe boundaries between scopes, dependencies inside one scope, or a
global source-to-target policy.
Installation
Add Archaven as a dev dependency:
[]
= "0.2"
Core Concepts
Archaven
Archaven is the checker. Add one or more rules, call check, and assert that
the returned Violations collection is empty.
let violations = new
.rule
.check
.unwrap;
violations.assert_empty;
check returns Result<Violations, ArchavenError>:
Err(...)means scanning, parsing, or rule compilation failed.Ok(violations)means analysis completed and the returned list contains all architectural violations.
Rule::between
Rule::between(pattern) checks dependencies between different instances matched
by the same scope pattern.
between
With paths like app::sales::... and app::billing::..., this checks
cross-context dependencies from sales to billing and from billing to
sales. Dependencies inside app::sales are ignored by this rule.
Example:
between
.named
.deny_all
.allow
The from and to patterns are relative to the matched source and target
scopes. For a dependency from app::sales to app::billing, the rule above
allows:
app::sales::*::infrastructure::adapter::**
->
app::billing::*::application::command::**
app::billing::*::application::query::**
Rule::within
Rule::within(pattern) checks dependencies inside the same matched scope.
within
With a scope like app::sales::orders, this checks dependencies from one path
under orders to another path under orders. Dependencies from orders to
invoices are ignored by this rule.
Example:
within
.named
.deny_all
.allow
.allow
.allow
.allow
If a file assembles a module and should not be evaluated by that rule, ignore it with a file glob:
within
.named
.deny_all
.ignore_files
.allow
ignore_files is per-rule. Dependencies discovered in matching source files are
skipped for that rule before deny, deny_all, and allow are evaluated.
This can model layered, hexagonal, vertical-slice, plugin, or custom dependency styles without adding architecture-specific types to the public API.
Rule::new
Rule::new() checks absolute source and target patterns.
new
.named
.deny
Use this when a rule is not scoped by between or within.
Path Patterns
Archaven matches module paths by :: segments.
* = exactly one segment
** = one or more segments
Examples:
app::*::anything matches app::orders::anything
app::*::anything does not match app::orders::nested::anything
app::**::anything matches app::orders::nested::anything
app::**::anything does not match app::anything
app::** matches app::orders and app::orders::domain
app::** does not match app
Patterns are intentionally segment-based. app::*::domain is different from
app::**::domain, and ** never means "zero segments".
Modular Monolith Example
Given this source layout:
src/app/sales/orders/domain/order.rs
src/app/sales/orders/application/command/create_order.rs
src/app/sales/orders/infrastructure/adapter/billing_client.rs
src/app/sales/orders/ui/http_controller.rs
src/app/billing/invoices/application/command/issue_invoice.rs
src/app/billing/invoices/application/query/get_invoice.rs
Check cross-context communication:
use ;
Check dependencies inside each module:
use ;
Violation Output
Violations implements Display, so it can be used directly in assertions:
assert!;
For test assertions, assert_empty panics with the formatted violation list and
reports the panic at the assertion call site:
violations.assert_empty;
You can also format violations yourself:
for violation in &violations
A violation contains:
- rule name
- reason
- source module path
- target module path
- file path
- line and column when available
How Scanning Works
Archaven derives source module paths from Rust file paths under the directory
passed to check.
For example:
src/app/sales/orders/domain/order.rs
becomes:
app::sales::orders::domain::order
The scanner parses Rust files with syn and records dependencies from:
use crate::...crate::...self::...super::...- local root paths such as
app::...
Use Rule::ignore_files(["**/mod.rs"]) when module composition root files
intentionally wire internals that the rule should not evaluate.
This keeps Archaven fast and usable from regular tests. It also means the first version is a source-level checker, not a full Rust compiler front-end. Macro generated paths, complex re-exports, trait dispatch, and every possible aliasing pattern may require explicit paths in code or future scanner improvements.
Custom Rule Sets
The built-in Rule type is enough for many projects, but Archaven also exposes
RuleSet for custom policies.
use ;
;
License
Licensed under either of:
- Apache License, Version 2.0
- MIT license
at your option.