refactor: deepen modules, consolidate inference, delete dead code
- Extract build_graph/load_config/create_renderer in presentation (393→~250 lines) - Move module inference into ModuleName::from_path(), delete 3 scattered copies - Move resolve_relationships/filter_external_imports into CodeGraph - Add LanguageExtractor trait in tree-sitter adapter - Add CodeGraph::elements_by_module(), replace 6 identical grouping loops - Delete dead RenderDiagrams query
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use archlens_domain::{
|
||||
CodeElement, CodeGraph, DomainError, RelationshipKind, RenderOutput, RenderedFile,
|
||||
ports::DiagramRenderer,
|
||||
@@ -55,19 +53,7 @@ impl DiagramRenderer for AsciiRenderer {
|
||||
return Ok(RenderOutput::single(file));
|
||||
}
|
||||
|
||||
let mut grouped: HashMap<String, Vec<&CodeElement>> = HashMap::new();
|
||||
let mut ungrouped: Vec<&CodeElement> = Vec::new();
|
||||
|
||||
for element in graph.elements() {
|
||||
if let Some(module) = element.module() {
|
||||
grouped
|
||||
.entry(module.as_str().to_string())
|
||||
.or_default()
|
||||
.push(element);
|
||||
} else {
|
||||
ungrouped.push(element);
|
||||
}
|
||||
}
|
||||
let (grouped, ungrouped) = graph.elements_by_module();
|
||||
|
||||
if !ungrouped.is_empty() {
|
||||
lines.push(String::new());
|
||||
|
||||
@@ -82,7 +82,7 @@ impl ProjectAnalyzer for CargoWorkspaceAnalyzer {
|
||||
let mut element =
|
||||
CodeElement::new(package_name, CodeElementKind::Project, file_path, 1)?;
|
||||
|
||||
if let Some(module) = infer_group(member_path) {
|
||||
if let Some(module) = ModuleName::from_directory_group(member_path) {
|
||||
element = element.with_module(module);
|
||||
}
|
||||
|
||||
@@ -110,14 +110,3 @@ impl ProjectAnalyzer for CargoWorkspaceAnalyzer {
|
||||
Ok(graph)
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_group(member_path: &str) -> Option<ModuleName> {
|
||||
let parts: Vec<&str> = member_path.split('/').collect();
|
||||
if parts.len() < 3 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let group = parts[parts.len() - 2];
|
||||
let capitalized = format!("{}{}", group[..1].to_uppercase(), &group[1..]);
|
||||
ModuleName::new(&capitalized).ok()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use archlens_domain::{
|
||||
CodeElement, CodeGraph, DiagramLevel, DomainError, RelationshipKind, RenderOutput,
|
||||
CodeElement, CodeGraph, DiagramLevel, DomainError, ModuleName, RelationshipKind, RenderOutput,
|
||||
RenderedFile, Visibility, ports::DiagramRenderer,
|
||||
};
|
||||
|
||||
@@ -46,20 +46,7 @@ impl MermaidRenderer {
|
||||
fn render_class_diagram(&self, graph: &CodeGraph) -> String {
|
||||
let mut lines = vec!["classDiagram".to_string()];
|
||||
|
||||
let mut grouped: HashMap<String, Vec<&CodeElement>> = HashMap::new();
|
||||
let mut ungrouped: Vec<&CodeElement> = Vec::new();
|
||||
|
||||
for element in graph.elements() {
|
||||
if let Some(module) = element.module() {
|
||||
grouped
|
||||
.entry(module.as_str().to_string())
|
||||
.or_default()
|
||||
.push(element);
|
||||
} else {
|
||||
ungrouped.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
let (grouped, ungrouped) = graph.elements_by_module();
|
||||
let has_namespaces = !grouped.is_empty();
|
||||
|
||||
let mut seen: HashSet<String> = HashSet::new();
|
||||
@@ -157,7 +144,7 @@ impl MermaidRenderer {
|
||||
RelationshipKind::Import => {
|
||||
let source_mod = file_to_module.get(rel.source());
|
||||
let target_top = rel.target().split('.').next().unwrap_or("");
|
||||
let target_mod = Self::capitalize(target_top);
|
||||
let target_mod = ModuleName::capitalize(target_top);
|
||||
|
||||
if let Some(src) = source_mod
|
||||
&& modules.contains(&target_mod)
|
||||
@@ -201,29 +188,10 @@ impl MermaidRenderer {
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
fn capitalize(s: &str) -> String {
|
||||
if s.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
format!("{}{}", s[..1].to_uppercase(), &s[1..])
|
||||
}
|
||||
|
||||
fn render_project_flowchart(&self, graph: &CodeGraph) -> String {
|
||||
let mut lines = vec!["graph TD".to_string()];
|
||||
|
||||
let mut grouped: HashMap<String, Vec<&CodeElement>> = HashMap::new();
|
||||
let mut ungrouped: Vec<&CodeElement> = Vec::new();
|
||||
|
||||
for element in graph.elements() {
|
||||
if let Some(module) = element.module() {
|
||||
grouped
|
||||
.entry(module.as_str().to_string())
|
||||
.or_default()
|
||||
.push(element);
|
||||
} else {
|
||||
ungrouped.push(element);
|
||||
}
|
||||
}
|
||||
let (grouped, ungrouped) = graph.elements_by_module();
|
||||
|
||||
for element in &ungrouped {
|
||||
let id = Self::sanitize_id(element.name());
|
||||
|
||||
5
crates/adapters/tree-sitter/src/language_extractor.rs
Normal file
5
crates/adapters/tree-sitter/src/language_extractor.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
use archlens_domain::{AnalysisResult, DomainError, FilePath};
|
||||
|
||||
pub trait LanguageExtractor {
|
||||
fn analyze(&self, source: &str, file_path: &FilePath) -> Result<AnalysisResult, DomainError>;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
mod language_extractor;
|
||||
mod python;
|
||||
mod rust;
|
||||
mod tree_sitter_analyzer;
|
||||
|
||||
@@ -7,6 +7,16 @@ use archlens_domain::{
|
||||
Relationship, RelationshipKind,
|
||||
};
|
||||
|
||||
use crate::language_extractor::LanguageExtractor;
|
||||
|
||||
pub struct PythonExtractor;
|
||||
|
||||
impl LanguageExtractor for PythonExtractor {
|
||||
fn analyze(&self, source: &str, file_path: &FilePath) -> Result<AnalysisResult, DomainError> {
|
||||
analyze(source, file_path)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze(source: &str, file_path: &FilePath) -> Result<AnalysisResult, DomainError> {
|
||||
let mut parser = Parser::new();
|
||||
parser
|
||||
|
||||
@@ -42,6 +42,16 @@ use archlens_domain::{
|
||||
Relationship, RelationshipKind, Visibility,
|
||||
};
|
||||
|
||||
use crate::language_extractor::LanguageExtractor;
|
||||
|
||||
pub struct RustExtractor;
|
||||
|
||||
impl LanguageExtractor for RustExtractor {
|
||||
fn analyze(&self, source: &str, file_path: &FilePath) -> Result<AnalysisResult, DomainError> {
|
||||
analyze(source, file_path)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze(source: &str, file_path: &FilePath) -> Result<AnalysisResult, DomainError> {
|
||||
let mut parser = Parser::new();
|
||||
parser
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
use archlens_domain::{AnalysisResult, DomainError, Language, SourceFile, ports::SourceAnalyzer};
|
||||
|
||||
use crate::{python, rust};
|
||||
use crate::language_extractor::LanguageExtractor;
|
||||
use crate::python::PythonExtractor;
|
||||
use crate::rust::RustExtractor;
|
||||
|
||||
pub struct TreeSitterAnalyzer;
|
||||
pub struct TreeSitterAnalyzer {
|
||||
rust: RustExtractor,
|
||||
python: PythonExtractor,
|
||||
}
|
||||
|
||||
impl Default for TreeSitterAnalyzer {
|
||||
fn default() -> Self {
|
||||
@@ -12,7 +17,18 @@ impl Default for TreeSitterAnalyzer {
|
||||
|
||||
impl TreeSitterAnalyzer {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
Self {
|
||||
rust: RustExtractor,
|
||||
python: PythonExtractor,
|
||||
}
|
||||
}
|
||||
|
||||
fn extractor_for(&self, language: Language) -> Option<&dyn LanguageExtractor> {
|
||||
match language {
|
||||
Language::Rust => Some(&self.rust),
|
||||
Language::Python => Some(&self.python),
|
||||
Language::CSharp => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +37,9 @@ impl SourceAnalyzer for TreeSitterAnalyzer {
|
||||
let source = std::fs::read_to_string(file.path().as_str())
|
||||
.map_err(|e| DomainError::IoError(e.to_string()))?;
|
||||
|
||||
match file.language() {
|
||||
Language::Rust => rust::analyze(&source, file.path()),
|
||||
Language::Python => python::analyze(&source, file.path()),
|
||||
Language::CSharp => Ok(AnalysisResult::empty()),
|
||||
match self.extractor_for(file.language()) {
|
||||
Some(extractor) => extractor.analyze(&source, file.path()),
|
||||
None => Ok(AnalysisResult::empty()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user