feat: implement all P1/P2/P3/P4 improvements from issue backlog
P1 correctness: - filter test files by default (--include-tests to opt in) - per-module diagrams show cross-module dependency arrows - qualified type names (Module::TypeName) fix false edges from duplicate names P2 output richness: - method parameter types and return types in class diagrams (Rust + Python) - Python pyproject.toml project analyzer (--level project for monorepos) P3 unique value: - boundary rules in archlens.toml ([rules] allow/deny, --strict enforcement) P4 nice to have: - dependency weight labels on module arrows (--no-weights to disable) - --watch mode with 500ms debounce - D2 renderer adapter (--format d2) - interactive self-contained HTML viewer (--format html) - git-aware incremental analysis (--since <ref>)
This commit is contained in:
@@ -156,7 +156,7 @@ fn renders_module_level_flowchart() {
|
||||
assert!(content.contains("graph TD"));
|
||||
assert!(content.contains("Orders"));
|
||||
assert!(content.contains("Billing"));
|
||||
assert!(content.contains("Orders --> Billing"));
|
||||
assert!(content.contains("Orders --") && content.contains("Billing"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -320,9 +320,99 @@ fn module_level_aggregates_cross_module_deps_into_single_arrow() {
|
||||
let output = renderer.render(&graph).unwrap();
|
||||
let content = output.files()[0].content();
|
||||
|
||||
let arrow_count = content.matches("Orders --> Infra").count();
|
||||
let arrow_count =
|
||||
content.matches("Orders --> Infra").count() + content.matches("Orders --|").count();
|
||||
assert_eq!(
|
||||
arrow_count, 1,
|
||||
"should have exactly one aggregated arrow, got:\n{content}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_level_shows_dep_count_as_edge_label() {
|
||||
let mut graph = CodeGraph::new();
|
||||
graph.add_element(
|
||||
CodeElement::new(
|
||||
"ServiceA",
|
||||
CodeElementKind::Class,
|
||||
FilePath::new("src/app/a.rs").unwrap(),
|
||||
1,
|
||||
)
|
||||
.unwrap()
|
||||
.with_module(ModuleName::new("App").unwrap()),
|
||||
);
|
||||
graph.add_element(
|
||||
CodeElement::new(
|
||||
"ServiceB",
|
||||
CodeElementKind::Class,
|
||||
FilePath::new("src/app/b.rs").unwrap(),
|
||||
1,
|
||||
)
|
||||
.unwrap()
|
||||
.with_module(ModuleName::new("App").unwrap()),
|
||||
);
|
||||
graph.add_element(
|
||||
CodeElement::new(
|
||||
"Order",
|
||||
CodeElementKind::Class,
|
||||
FilePath::new("src/domain/order.rs").unwrap(),
|
||||
1,
|
||||
)
|
||||
.unwrap()
|
||||
.with_module(ModuleName::new("Domain").unwrap()),
|
||||
);
|
||||
graph.add_relationship(
|
||||
Relationship::new("ServiceA", "Order", RelationshipKind::Composition).unwrap(),
|
||||
);
|
||||
graph.add_relationship(
|
||||
Relationship::new("ServiceB", "Order", RelationshipKind::Composition).unwrap(),
|
||||
);
|
||||
let graph = graph.qualify();
|
||||
|
||||
let renderer = MermaidRenderer::with_level(DiagramLevel::Module);
|
||||
let output = renderer.render(&graph).unwrap();
|
||||
let content = output.files()[0].content();
|
||||
|
||||
assert!(
|
||||
content.contains(r#"|"2 deps"|"#),
|
||||
"expected dep count label in: {content}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_level_single_dep_uses_singular_label() {
|
||||
let mut graph = CodeGraph::new();
|
||||
graph.add_element(
|
||||
CodeElement::new(
|
||||
"Service",
|
||||
CodeElementKind::Class,
|
||||
FilePath::new("src/app/s.rs").unwrap(),
|
||||
1,
|
||||
)
|
||||
.unwrap()
|
||||
.with_module(ModuleName::new("App").unwrap()),
|
||||
);
|
||||
graph.add_element(
|
||||
CodeElement::new(
|
||||
"Order",
|
||||
CodeElementKind::Class,
|
||||
FilePath::new("src/domain/o.rs").unwrap(),
|
||||
1,
|
||||
)
|
||||
.unwrap()
|
||||
.with_module(ModuleName::new("Domain").unwrap()),
|
||||
);
|
||||
graph.add_relationship(
|
||||
Relationship::new("Service", "Order", RelationshipKind::Composition).unwrap(),
|
||||
);
|
||||
let graph = graph.qualify();
|
||||
|
||||
let renderer = MermaidRenderer::with_level(DiagramLevel::Module);
|
||||
let output = renderer.render(&graph).unwrap();
|
||||
let content = output.files()[0].content();
|
||||
|
||||
assert!(
|
||||
content.contains(r#"|"1 dep"|"#),
|
||||
"expected singular dep label in: {content}"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user