diff --git a/docs/architecture/module.mmd b/docs/architecture/module.mmd index 56368a7..49f99e2 100644 --- a/docs/architecture/module.mmd +++ b/docs/architecture/module.mmd @@ -3,8 +3,8 @@ graph TD Presentation[Presentation] Adapters[Adapters] Application[Application] - Adapters -->|24 deps| Domain - Presentation -->|1 dep| Application - Application -->|2 deps| Domain Presentation -->|11 deps| Adapters - Presentation -->|1 dep| Domain \ No newline at end of file + Presentation -->|1 dep| Domain + Presentation -->|1 dep| Application + Application -->|4 deps| Domain + Adapters -->|25 deps| Domain \ No newline at end of file diff --git a/docs/architecture/project.mmd b/docs/architecture/project.mmd index 1d1b97e..e750e68 100644 --- a/docs/architecture/project.mmd +++ b/docs/architecture/project.mmd @@ -16,19 +16,19 @@ graph TD archlens_html[archlens-html] end archlens_application --> archlens_domain - archlens --> archlens_cargo_workspace - archlens --> archlens_application - archlens --> archlens_walkdir + archlens --> archlens_toml_config archlens --> archlens_file_writer + archlens --> archlens_d2 + archlens --> archlens_python_project + archlens --> archlens_application + archlens --> archlens_mermaid + archlens --> archlens_cargo_workspace + archlens --> archlens_domain + archlens --> archlens_tree_sitter archlens --> archlens_html archlens --> archlens_stdout_writer - archlens --> archlens_python_project - archlens --> archlens_d2 + archlens --> archlens_walkdir archlens --> archlens_ascii - archlens --> archlens_tree_sitter - archlens --> archlens_domain - archlens --> archlens_toml_config - archlens --> archlens_mermaid archlens_tree_sitter --> archlens_domain archlens_walkdir --> archlens_domain archlens_mermaid --> archlens_domain diff --git a/docs/architecture/type/adapters.mmd b/docs/architecture/type/adapters.mmd index 6d019be..9e58598 100644 --- a/docs/architecture/type/adapters.mmd +++ b/docs/architecture/type/adapters.mmd @@ -8,6 +8,7 @@ classDiagram class ToolSection class PyprojectToml class WalkdirDiscovery + class ExtractionContext class TreeSitterAnalyzer class LanguageExtractor class RustExtractor @@ -61,6 +62,17 @@ classDiagram WalkdirDiscovery : +new() -] Self WalkdirDiscovery : -detect_language(path Path) -] Option[Language] WalkdirDiscovery : -is_excluded(path Path, root Path, excludes [String]) -] bool + ExtractionContext : elements Vec + ExtractionContext : relationships Vec + ExtractionContext : warnings Vec + ExtractionContext : local_types HashSet + ExtractionContext : file_path FilePath + ExtractionContext : +new(file_path FilePath) -] Self + ExtractionContext : +add_element(element CodeElement) + ExtractionContext : +add_relationship(rel Relationship) + ExtractionContext : +add_warning(file_path FilePath, line usize, message str) + ExtractionContext : +file_path() -] FilePath + ExtractionContext : +into_result() -] Result[AnalysisResult, DomainError] TreeSitterAnalyzer : rust RustExtractor TreeSitterAnalyzer : python PythonExtractor TreeSitterAnalyzer : +new() -] Self @@ -133,4 +145,4 @@ classDiagram class domain_module["Domain"] { <> } - adapters_module --> domain_module : 13 deps \ No newline at end of file + adapters_module --> domain_module : 14 deps \ No newline at end of file diff --git a/docs/architecture/type/application.mmd b/docs/architecture/type/application.mmd index cb503f6..1d2f110 100644 --- a/docs/architecture/type/application.mmd +++ b/docs/architecture/type/application.mmd @@ -2,19 +2,46 @@ classDiagram namespace Application { class AnalyzeCodebase class AnalyzeCodebaseResult + class DiffResult + class DiffDiagram + class CheckFreshness + class GenerateDiagramResult + class GenerateDiagram } AnalyzeCodebase : file_discovery F AnalyzeCodebase : source_analyzer S AnalyzeCodebase : +new(file_discovery F, source_analyzer S) -] Self AnalyzeCodebase : +execute(root Path, config AnalysisConfig) -] Result[AnalyzeCodebaseResult, DomainError] - AnalyzeCodebaseResult : graph CodeGraph + AnalyzeCodebaseResult : graph NormalizedGraph AnalyzeCodebaseResult : warnings Vec - AnalyzeCodebaseResult : +graph() -] CodeGraph + AnalyzeCodebaseResult : +graph() -] NormalizedGraph AnalyzeCodebaseResult : +warnings() -] [AnalysisWarning] + DiffResult : added Vec + DiffResult : removed Vec + DiffResult : +is_empty() -] bool + DiffDiagram : graph a NormalizedGraph + DiffDiagram : renderer a dyn DiagramRenderer + DiffDiagram : existing_path a std path Path + DiffDiagram : +execute() -] Result[DiffResult, DomainError] + CheckFreshness : graph a NormalizedGraph + CheckFreshness : renderer a dyn DiagramRenderer + CheckFreshness : existing_path a std path Path + CheckFreshness : +execute() -] Result[bool, DomainError] + GenerateDiagramResult : violations Vec + GenerateDiagramResult : output RenderOutput + GenerateDiagram : graph NormalizedGraph + GenerateDiagram : renderer Box + GenerateDiagram : allow_rules Vec + GenerateDiagram : deny_rules Vec + GenerateDiagram : split_by_module bool + GenerateDiagram : format_ext String + GenerateDiagram : output_dir Option + GenerateDiagram : +execute() -] Result[(), DomainError] + GenerateDiagram : +check_violations_only() -] Vec[String] class application_module["Application"] { <> } class domain_module["Domain"] { <> } - application_module --> domain_module : 1 dep \ No newline at end of file + application_module --> domain_module : 3 deps \ No newline at end of file diff --git a/docs/architecture/type/domain.mmd b/docs/architecture/type/domain.mmd index ca88540..84d836b 100644 --- a/docs/architecture/type/domain.mmd +++ b/docs/architecture/type/domain.mmd @@ -6,6 +6,7 @@ classDiagram class RenderedFile class SourceFile class ModuleName + class ModuleAssignment class Language class FilePath class RelationshipKind @@ -25,6 +26,7 @@ classDiagram class OutputWriter class DiagramRenderer class SourceAnalyzer + class NormalizedGraph class CodeGraph class DomainError } @@ -49,10 +51,14 @@ classDiagram SourceFile : +path() -] FilePath SourceFile : +language() -] Language ModuleName : +new(value str) -] Result[Self, DomainError] + ModuleName : +assign(file_path str, root Path, module_mappings HashMap[String, String]) -] ModuleAssignment ModuleName : +from_path(file_path str, root Path, module_mappings HashMap[String, String]) -] Option[Self] ModuleName : +from_directory_group(member_path str) -] Option[Self] ModuleName : +capitalize(s str) -] String ModuleName : +as_str() -] str + ModuleAssignment : +module_name() -] Option[ModuleName] + ModuleAssignment : +into_module_name() -] Option[ModuleName] + ModuleAssignment : +reason() -] Option[static str] Language : +name() -] static str Language : +is_test_file(path Path) -] bool FilePath : +new(value str) -] Result[Self, DomainError] @@ -145,6 +151,17 @@ classDiagram CodeElement : +with_methods(methods Vec[String]) -] Self CodeElement : +fields() -] [String] CodeElement : +methods() -] [String] + NormalizedGraph : +from_analyzed(graph CodeGraph, known_dirs HashSet[String]) -] Result[Self, DomainError] + NormalizedGraph : +from_project(graph CodeGraph) -] Self + NormalizedGraph : +elements() -] [CodeElement] + NormalizedGraph : +relationships() -] [Relationship] + NormalizedGraph : +modules() -] Vec[ModuleName] + NormalizedGraph : +elements_by_module() -] (HashMap[String, Vec[CodeElement]], Vec[CodeElement]) + NormalizedGraph : +module_edges() -] HashMap[(String, String), usize] + NormalizedGraph : +subgraph_by_module(module ModuleName) -] CodeGraph + NormalizedGraph : +cross_module_deps_for(module ModuleName) -] Vec[(ModuleName, usize)] + NormalizedGraph : +merge_project_edges(project_graph CodeGraph) + NormalizedGraph : +as_graph() -] CodeGraph CodeGraph : elements Vec CodeGraph : relationships Vec CodeGraph : +new() -] Self diff --git a/docs/architecture/type/overview.mmd b/docs/architecture/type/overview.mmd index 47a688d..869fa13 100644 --- a/docs/architecture/type/overview.mmd +++ b/docs/architecture/type/overview.mmd @@ -1,4 +1,35 @@ classDiagram + namespace Domain { + class OutputConfig + class DiagramLevel + class RenderOutput + class RenderedFile + class SourceFile + class ModuleName + class ModuleAssignment + class Language + class FilePath + class RelationshipKind + class Visibility + class CodeElementKind + class RuleKind + class RuleViolation + class BoundaryRule + class AnalysisConfig + class AnalysisResult + class AnalysisWarning + class Relationship + class CodeElement + class FileDiscovery + class ConfigLoader + class ProjectAnalyzer + class OutputWriter + class DiagramRenderer + class SourceAnalyzer + class NormalizedGraph + class CodeGraph + class DomainError + } namespace Adapters { class MermaidRenderer class AsciiRenderer @@ -8,6 +39,7 @@ classDiagram class ToolSection class PyprojectToml class WalkdirDiscovery + class ExtractionContext class TreeSitterAnalyzer class LanguageExtractor class RustExtractor @@ -31,35 +63,6 @@ classDiagram class MemberToml class PackageSection } - namespace Domain { - class OutputConfig - class DiagramLevel - class RenderOutput - class RenderedFile - class SourceFile - class ModuleName - class Language - class FilePath - class RelationshipKind - class Visibility - class CodeElementKind - class RuleKind - class RuleViolation - class BoundaryRule - class AnalysisConfig - class AnalysisResult - class AnalysisWarning - class Relationship - class CodeElement - class FileDiscovery - class ConfigLoader - class ProjectAnalyzer - class OutputWriter - class DiagramRenderer - class SourceAnalyzer - class CodeGraph - class DomainError - } namespace Presentation { class Cli class Command @@ -67,92 +70,12 @@ classDiagram namespace Application { class AnalyzeCodebase class AnalyzeCodebaseResult + class DiffResult + class DiffDiagram + class CheckFreshness + class GenerateDiagramResult + class GenerateDiagram } - MermaidRenderer : level DiagramLevel - MermaidRenderer : show_weights bool - MermaidRenderer : +new() -] Self - MermaidRenderer : +with_level(level DiagramLevel) -] Self - MermaidRenderer : +with_weights(show bool) -] Self - MermaidRenderer : -display_name(qualified str) -] str - MermaidRenderer : -format_element_name(element CodeElement) -] String - MermaidRenderer : -format_visibility(visibility Visibility) -] static str - MermaidRenderer : -render_class_diagram(graph CodeGraph) -] String - MermaidRenderer : -push_class_lines(lines mut Vec[String], deferred mut Vec[String], element CodeElement, indent str, in_namespace bool) - MermaidRenderer : -render_module_flowchart(graph CodeGraph) -] String - MermaidRenderer : -render_project_flowchart(graph CodeGraph) -] String - MermaidRenderer : -sanitize_id(name str) -] String - AsciiRenderer : +new() -] Self - AsciiRenderer : -format_kind(element CodeElement) -] static str - PythonProjectAnalyzer : +new() -] Self - <> ProjectSection - ProjectSection : name Option - ProjectSection : dependencies Vec - <> PoetrySection - PoetrySection : name Option - PoetrySection : dependencies HashMap - <> ToolSection - ToolSection : poetry PoetrySection - <> PyprojectToml - PyprojectToml : project Option - PyprojectToml : tool ToolSection - WalkdirDiscovery : +new() -] Self - WalkdirDiscovery : -detect_language(path Path) -] Option[Language] - WalkdirDiscovery : -is_excluded(path Path, root Path, excludes [String]) -] bool - TreeSitterAnalyzer : rust RustExtractor - TreeSitterAnalyzer : python PythonExtractor - TreeSitterAnalyzer : +new() -] Self - TreeSitterAnalyzer : -extractor_for(language Language) -] Option[dyn LanguageExtractor] - FileOutputWriter : output_path OutputPath - FileOutputWriter : +new(output_dir PathBuf) -] Self - FileOutputWriter : +single_file(path PathBuf) -] Self - <> OutputPath - StdoutOutputWriter : +new() -] Self - <> RawRules - RawRules : allow Vec - RawRules : deny Vec - <> RawConfig - RawConfig : analysis RawAnalysis - RawConfig : output RawOutput - RawConfig : modules HashMap - RawConfig : rules RawRules - <> RawAnalysis - RawAnalysis : exclude Vec - RawAnalysis : level Option - <> RawOutput - RawOutput : format Option - RawOutput : path Option - RawOutput : split_by_module bool - TomlConfigLoader : raw RawConfig - TomlConfigLoader : +from_path(path Path) -] Result[Self, DomainError] - TomlConfigLoader : -parse_level(level Option[String]) -] DiagramLevel - D2Renderer : level DiagramLevel - D2Renderer : +new() -] Self - D2Renderer : +with_level(level DiagramLevel) -] Self - HtmlRenderer : +new() -] Self - <> GraphData - GraphData : nodes Vec - GraphData : edges Vec - <> NodeData - NodeData : id String - NodeData : label String - NodeData : module String - NodeData : kind String - NodeData : fields Vec - NodeData : methods Vec - <> EdgeData - EdgeData : source String - EdgeData : target String - EdgeData : kind String - CargoWorkspaceAnalyzer : +new() -] Self - <> WorkspaceToml - WorkspaceToml : workspace Option - <> WorkspaceSection - WorkspaceSection : members Vec - <> MemberToml - MemberToml : package Option - MemberToml : dependencies HashMap - <> PackageSection - PackageSection : name String OutputConfig : split_by_module bool OutputConfig : output_path Option OutputConfig : +with_split_by_module(split bool) -] Self @@ -174,10 +97,14 @@ classDiagram SourceFile : +path() -] FilePath SourceFile : +language() -] Language ModuleName : +new(value str) -] Result[Self, DomainError] + ModuleName : +assign(file_path str, root Path, module_mappings HashMap[String, String]) -] ModuleAssignment ModuleName : +from_path(file_path str, root Path, module_mappings HashMap[String, String]) -] Option[Self] ModuleName : +from_directory_group(member_path str) -] Option[Self] ModuleName : +capitalize(s str) -] String ModuleName : +as_str() -] str + ModuleAssignment : +module_name() -] Option[ModuleName] + ModuleAssignment : +into_module_name() -] Option[ModuleName] + ModuleAssignment : +reason() -] Option[static str] Language : +name() -] static str Language : +is_test_file(path Path) -] bool FilePath : +new(value str) -] Result[Self, DomainError] @@ -270,6 +197,17 @@ classDiagram CodeElement : +with_methods(methods Vec[String]) -] Self CodeElement : +fields() -] [String] CodeElement : +methods() -] [String] + NormalizedGraph : +from_analyzed(graph CodeGraph, known_dirs HashSet[String]) -] Result[Self, DomainError] + NormalizedGraph : +from_project(graph CodeGraph) -] Self + NormalizedGraph : +elements() -] [CodeElement] + NormalizedGraph : +relationships() -] [Relationship] + NormalizedGraph : +modules() -] Vec[ModuleName] + NormalizedGraph : +elements_by_module() -] (HashMap[String, Vec[CodeElement]], Vec[CodeElement]) + NormalizedGraph : +module_edges() -] HashMap[(String, String), usize] + NormalizedGraph : +subgraph_by_module(module ModuleName) -] CodeGraph + NormalizedGraph : +cross_module_deps_for(module ModuleName) -] Vec[(ModuleName, usize)] + NormalizedGraph : +merge_project_edges(project_graph CodeGraph) + NormalizedGraph : +as_graph() -] CodeGraph CodeGraph : elements Vec CodeGraph : relationships Vec CodeGraph : +new() -] Self @@ -286,6 +224,102 @@ classDiagram CodeGraph : +subgraph_by_module(module ModuleName) -] CodeGraph CodeGraph : +merge_project_edges(project_graph CodeGraph) CodeGraph : +module_edges() -] HashMap[(String, String), usize] + MermaidRenderer : level DiagramLevel + MermaidRenderer : show_weights bool + MermaidRenderer : +new() -] Self + MermaidRenderer : +with_level(level DiagramLevel) -] Self + MermaidRenderer : +with_weights(show bool) -] Self + MermaidRenderer : -display_name(qualified str) -] str + MermaidRenderer : -format_element_name(element CodeElement) -] String + MermaidRenderer : -format_visibility(visibility Visibility) -] static str + MermaidRenderer : -render_class_diagram(graph CodeGraph) -] String + MermaidRenderer : -push_class_lines(lines mut Vec[String], deferred mut Vec[String], element CodeElement, indent str, in_namespace bool) + MermaidRenderer : -render_module_flowchart(graph CodeGraph) -] String + MermaidRenderer : -render_project_flowchart(graph CodeGraph) -] String + MermaidRenderer : -sanitize_id(name str) -] String + AsciiRenderer : +new() -] Self + AsciiRenderer : -format_kind(element CodeElement) -] static str + PythonProjectAnalyzer : +new() -] Self + <> ProjectSection + ProjectSection : name Option + ProjectSection : dependencies Vec + <> PoetrySection + PoetrySection : name Option + PoetrySection : dependencies HashMap + <> ToolSection + ToolSection : poetry PoetrySection + <> PyprojectToml + PyprojectToml : project Option + PyprojectToml : tool ToolSection + WalkdirDiscovery : +new() -] Self + WalkdirDiscovery : -detect_language(path Path) -] Option[Language] + WalkdirDiscovery : -is_excluded(path Path, root Path, excludes [String]) -] bool + ExtractionContext : elements Vec + ExtractionContext : relationships Vec + ExtractionContext : warnings Vec + ExtractionContext : local_types HashSet + ExtractionContext : file_path FilePath + ExtractionContext : +new(file_path FilePath) -] Self + ExtractionContext : +add_element(element CodeElement) + ExtractionContext : +add_relationship(rel Relationship) + ExtractionContext : +add_warning(file_path FilePath, line usize, message str) + ExtractionContext : +file_path() -] FilePath + ExtractionContext : +into_result() -] Result[AnalysisResult, DomainError] + TreeSitterAnalyzer : rust RustExtractor + TreeSitterAnalyzer : python PythonExtractor + TreeSitterAnalyzer : +new() -] Self + TreeSitterAnalyzer : -extractor_for(language Language) -] Option[dyn LanguageExtractor] + FileOutputWriter : output_path OutputPath + FileOutputWriter : +new(output_dir PathBuf) -] Self + FileOutputWriter : +single_file(path PathBuf) -] Self + <> OutputPath + StdoutOutputWriter : +new() -] Self + <> RawRules + RawRules : allow Vec + RawRules : deny Vec + <> RawConfig + RawConfig : analysis RawAnalysis + RawConfig : output RawOutput + RawConfig : modules HashMap + RawConfig : rules RawRules + <> RawAnalysis + RawAnalysis : exclude Vec + RawAnalysis : level Option + <> RawOutput + RawOutput : format Option + RawOutput : path Option + RawOutput : split_by_module bool + TomlConfigLoader : raw RawConfig + TomlConfigLoader : +from_path(path Path) -] Result[Self, DomainError] + TomlConfigLoader : -parse_level(level Option[String]) -] DiagramLevel + D2Renderer : level DiagramLevel + D2Renderer : +new() -] Self + D2Renderer : +with_level(level DiagramLevel) -] Self + HtmlRenderer : +new() -] Self + <> GraphData + GraphData : nodes Vec + GraphData : edges Vec + <> NodeData + NodeData : id String + NodeData : label String + NodeData : module String + NodeData : kind String + NodeData : fields Vec + NodeData : methods Vec + <> EdgeData + EdgeData : source String + EdgeData : target String + EdgeData : kind String + CargoWorkspaceAnalyzer : +new() -] Self + <> WorkspaceToml + WorkspaceToml : workspace Option + <> WorkspaceSection + WorkspaceSection : members Vec + <> MemberToml + MemberToml : package Option + MemberToml : dependencies HashMap + <> PackageSection + PackageSection : name String Cli : command Option Cli : path PathBuf Cli : level String @@ -306,10 +340,32 @@ classDiagram AnalyzeCodebase : source_analyzer S AnalyzeCodebase : +new(file_discovery F, source_analyzer S) -] Self AnalyzeCodebase : +execute(root Path, config AnalysisConfig) -] Result[AnalyzeCodebaseResult, DomainError] - AnalyzeCodebaseResult : graph CodeGraph + AnalyzeCodebaseResult : graph NormalizedGraph AnalyzeCodebaseResult : warnings Vec - AnalyzeCodebaseResult : +graph() -] CodeGraph + AnalyzeCodebaseResult : +graph() -] NormalizedGraph AnalyzeCodebaseResult : +warnings() -] [AnalysisWarning] + DiffResult : added Vec + DiffResult : removed Vec + DiffResult : +is_empty() -] bool + DiffDiagram : graph a NormalizedGraph + DiffDiagram : renderer a dyn DiagramRenderer + DiffDiagram : existing_path a std path Path + DiffDiagram : +execute() -] Result[DiffResult, DomainError] + CheckFreshness : graph a NormalizedGraph + CheckFreshness : renderer a dyn DiagramRenderer + CheckFreshness : existing_path a std path Path + CheckFreshness : +execute() -] Result[bool, DomainError] + GenerateDiagramResult : violations Vec + GenerateDiagramResult : output RenderOutput + GenerateDiagram : graph NormalizedGraph + GenerateDiagram : renderer Box + GenerateDiagram : allow_rules Vec + GenerateDiagram : deny_rules Vec + GenerateDiagram : split_by_module bool + GenerateDiagram : format_ext String + GenerateDiagram : output_dir Option + GenerateDiagram : +execute() -] Result[(), DomainError] + GenerateDiagram : +check_violations_only() -] Vec[String] SourceFile --> FilePath SourceFile --> Language RuleViolation --> RuleKind @@ -326,6 +382,7 @@ classDiagram PyprojectToml --> ToolSection PythonProjectAnalyzer <|-- ProjectAnalyzer WalkdirDiscovery <|-- FileDiscovery + ExtractionContext --> FilePath TreeSitterAnalyzer --> RustExtractor TreeSitterAnalyzer --> PythonExtractor TreeSitterAnalyzer <|-- SourceAnalyzer @@ -343,4 +400,6 @@ classDiagram D2Renderer <|-- DiagramRenderer HtmlRenderer <|-- DiagramRenderer CargoWorkspaceAnalyzer <|-- ProjectAnalyzer - AnalyzeCodebaseResult --> CodeGraph \ No newline at end of file + AnalyzeCodebaseResult --> NormalizedGraph + GenerateDiagramResult --> RenderOutput + GenerateDiagram --> NormalizedGraph \ No newline at end of file