init: archlens — architecture diagram generator
Some checks failed
CI / Check / Test (push) Failing after 1m24s
Some checks failed
CI / Check / Test (push) Failing after 1m24s
Hex arch + DDD, tree-sitter parsing, Mermaid/ASCII output. Supports Rust + Python. 92 tests. CI, diff, --check for staleness detection.
This commit is contained in:
51
docs/adr/0001-hexagonal-architecture-with-ddd.md
Normal file
51
docs/adr/0001-hexagonal-architecture-with-ddd.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# 0001 — Hexagonal Architecture with DDD
|
||||
|
||||
**Status:** Accepted
|
||||
**Date:** 2026-06-16
|
||||
|
||||
## Context
|
||||
|
||||
Archlens is a language-agnostic architecture diagram generator. It needs to support multiple input languages (Rust, C#, Python), multiple output formats (Mermaid, ASCII, future: D2, interactive web), and multiple IO strategies (file, stdout). The tool must be extensible without modifying core logic.
|
||||
|
||||
## Decision
|
||||
|
||||
Use hexagonal architecture (ports and adapters) with DDD structuring. Workspace layout:
|
||||
|
||||
```
|
||||
crates/
|
||||
domain/ — zero external deps (no tracing, no rayon, nothing)
|
||||
application/ — depends on domain only + rayon, tracing (pragmatic utility exceptions)
|
||||
adapters/
|
||||
tree-sitter/ — SourceAnalyzer (internal modules per language)
|
||||
walkdir/ — FileDiscovery
|
||||
mermaid/ — DiagramRenderer
|
||||
ascii/ — DiagramRenderer
|
||||
file-writer/ — OutputWriter
|
||||
stdout-writer/ — OutputWriter
|
||||
toml-config/ — ConfigLoader
|
||||
presentation/ — CLI (clap), composition root, tracing-subscriber setup
|
||||
```
|
||||
|
||||
**Dependency rules:**
|
||||
- Domain depends on nothing
|
||||
- Application depends on domain
|
||||
- Adapters depend on domain (not application)
|
||||
- Presentation depends on application + adapters (composition root)
|
||||
|
||||
**Use cases** are generic over port traits (static dispatch), not trait objects.
|
||||
|
||||
**Pragmatic exceptions:** `rayon` and `tracing` in application crate. These are general-purpose utilities, not external system adapters. Documented explicitly to avoid precedent creep.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
- **Trait objects for DI:** Simpler type signatures but runtime dispatch overhead and less compile-time safety. Rejected — generics align better with Rust idioms and zero-cost goals.
|
||||
- **DI container (shaku):** Unnecessary ceremony for Rust. Manual wiring in presentation is explicit and sufficient.
|
||||
- **Domain with tracing dependency:** Rejected to keep domain fully pure. Application wraps domain calls in spans.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Adding a new language = new module in tree-sitter adapter (or new adapter crate)
|
||||
- Adding a new output format = new adapter crate implementing DiagramRenderer
|
||||
- Adding a new output destination = new adapter crate implementing OutputWriter
|
||||
- Use case type signatures carry multiple generic parameters (accepted tradeoff)
|
||||
- Domain crate is testable with zero setup — no mocks for infrastructure needed
|
||||
31
docs/adr/0002-tree-sitter-for-parsing.md
Normal file
31
docs/adr/0002-tree-sitter-for-parsing.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# 0002 — Tree-sitter for Source Code Parsing
|
||||
|
||||
**Status:** Accepted
|
||||
**Date:** 2026-06-16
|
||||
|
||||
## Context
|
||||
|
||||
Archlens needs to extract type-level information (classes, structs, traits, interfaces, enums, fields, inheritance) from Rust, C#, and Python source code. The tool must be language-agnostic in design, fast enough for CI, and memory-efficient for large codebases.
|
||||
|
||||
## Decision
|
||||
|
||||
Use tree-sitter as the primary parsing backend. One `tree-sitter` adapter crate with internal modules per language. Each language module defines tree-sitter S-expression queries to extract CodeElements and Relationships.
|
||||
|
||||
**Tradeoff accepted:** Tree-sitter provides syntactic analysis only — no cross-file type resolution, no generics resolution, no resolved imports. This is sufficient for architecture diagrams where we care about structural relationships visible in the source text.
|
||||
|
||||
Semantic resolution is a future concern, handled by a separate adapter (e.g., `roslyn-adapter` for C#) implementing the same `SourceAnalyzer` port.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
- **Custom parsers/lexers per language:** Full control but enormous implementation and maintenance effort. Rejected.
|
||||
- **LSP servers:** Rich semantic info but heavy to run, hard to orchestrate in CI, each language needs its own server process. Rejected for CI use case.
|
||||
- **Native AST APIs (Roslyn, rustc_ast, Python ast):** Very accurate but each is a completely different API and ecosystem. Can't run Roslyn from Rust easily. Rejected as primary approach — viable as future specialized adapters.
|
||||
- **Regex/heuristic:** Breaks on edge cases. Not serious for a real tool.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Single unified parsing approach across all languages
|
||||
- Adding a new language = writing tree-sitter queries (hours, not weeks)
|
||||
- No semantic type resolution — `use Foo` doesn't tell us which `Foo` across modules
|
||||
- Memory-efficient: parse trees are per-file and dropped after extraction
|
||||
- Fast: tree-sitter is incremental and optimized for performance
|
||||
Reference in New Issue
Block a user