feat: implement all P1/P2/P3/P4 improvements from issue backlog
Some checks failed
CI / Check / Test (push) Failing after 1m33s
Architecture Docs / Generate diagrams (push) Successful in 3m21s

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:
2026-06-17 09:50:50 +02:00
parent 27197062eb
commit fdd85011a4
42 changed files with 2767 additions and 92 deletions

View File

@@ -136,3 +136,74 @@ fn extracts_composition_from_class_level_annotations() {
assert_eq!(composition[0].source(), "Definition");
assert_eq!(composition[0].target(), "Gad");
}
#[test]
fn extracts_python_class_methods() {
let source = "class OrderService:\n def process(self):\n pass\n def cancel(self):\n pass\n";
let result = analyze_python(source, "service.py");
let element = result
.elements()
.iter()
.find(|e| e.name() == "OrderService")
.unwrap();
assert!(
element.methods().iter().any(|m| m.contains("process")),
"expected 'process' method, got: {:?}",
element.methods()
);
assert!(
element.methods().iter().any(|m| m.contains("cancel")),
"expected 'cancel' method, got: {:?}",
element.methods()
);
}
#[test]
fn extracts_python_method_typed_params() {
let source = "class OrderService:\n def process(self, order: Order, count: int) -> None:\n pass\n";
let result = analyze_python(source, "service.py");
let element = result
.elements()
.iter()
.find(|e| e.name() == "OrderService")
.unwrap();
let method = element
.methods()
.iter()
.find(|m| m.contains("process"))
.unwrap();
assert!(
method.contains("order: Order"),
"missing typed param: {method}"
);
assert!(
method.contains("count: int"),
"missing typed param: {method}"
);
}
#[test]
fn extracts_python_method_return_annotation() {
let source = "class OrderService:\n def get(self) -> Order:\n pass\n";
let result = analyze_python(source, "service.py");
let element = result
.elements()
.iter()
.find(|e| e.name() == "OrderService")
.unwrap();
let method = element
.methods()
.iter()
.find(|m| m.contains("get"))
.unwrap();
assert!(
method.contains("-> Order"),
"expected return type, got: {method}"
);
}