Skip to main content

aster/map/
view_builder.rs

1//! 视图构建器
2//!
3//! 构建目录树视图和架构分层视图
4
5use std::collections::HashMap;
6
7use super::layer_classifier::LayerClassifier;
8use super::types::ModuleNode;
9use super::types_enhanced::*;
10
11/// 视图构建器
12pub struct ViewBuilder {
13    classifier: LayerClassifier,
14}
15
16impl ViewBuilder {
17    pub fn new() -> Self {
18        Self {
19            classifier: LayerClassifier::new(),
20        }
21    }
22
23    /// 构建所有视图
24    pub fn build_views(&self, modules: &[ModuleNode]) -> Views {
25        Views {
26            directory_tree: self.build_directory_tree(modules),
27            architecture_layers: self.build_architecture_layers(modules),
28        }
29    }
30
31    /// 构建目录树视图
32    pub fn build_directory_tree(&self, modules: &[ModuleNode]) -> DirectoryNode {
33        let mut root = DirectoryNode {
34            name: "src".to_string(),
35            path: "src".to_string(),
36            node_type: DirectoryNodeType::Directory,
37            description: None,
38            purpose: None,
39            module_id: None,
40            children: Some(Vec::new()),
41        };
42
43        let mut sorted_modules: Vec<_> = modules.iter().collect();
44        sorted_modules.sort_by(|a, b| a.id.cmp(&b.id));
45
46        let mut dir_cache: HashMap<String, usize> = HashMap::new();
47
48        for module in sorted_modules {
49            let path = &module.id;
50            if !path.starts_with("src/") && !path.starts_with("src\\") {
51                continue;
52            }
53
54            let parts: Vec<&str> = path.split(&['/', '\\'][..]).collect();
55            self.insert_module_node(&mut root, &parts, 1, module, &mut dir_cache);
56        }
57
58        self.sort_directory_children(&mut root);
59        root
60    }
61
62    fn insert_module_node(
63        &self,
64        parent: &mut DirectoryNode,
65        parts: &[&str],
66        index: usize,
67        module: &ModuleNode,
68        _dir_cache: &mut HashMap<String, usize>,
69    ) {
70        if index >= parts.len() {
71            return;
72        }
73
74        let part = parts[index];
75        let is_last = index == parts.len() - 1;
76        let current_path = parts[..=index].join("/");
77
78        let children = parent.children.get_or_insert_with(Vec::new);
79
80        if is_last {
81            children.push(DirectoryNode {
82                name: part.to_string(),
83                path: current_path,
84                node_type: DirectoryNodeType::File,
85                description: None,
86                purpose: None,
87                module_id: Some(module.id.clone()),
88                children: None,
89            });
90        } else {
91            let dir_idx = children
92                .iter()
93                .position(|c| c.name == part && c.node_type == DirectoryNodeType::Directory);
94
95            if let Some(idx) = dir_idx {
96                self.insert_module_node(&mut children[idx], parts, index + 1, module, _dir_cache);
97            } else {
98                let mut new_dir = DirectoryNode {
99                    name: part.to_string(),
100                    path: current_path,
101                    node_type: DirectoryNodeType::Directory,
102                    description: None,
103                    purpose: None,
104                    module_id: None,
105                    children: Some(Vec::new()),
106                };
107                self.insert_module_node(&mut new_dir, parts, index + 1, module, _dir_cache);
108                children.push(new_dir);
109            }
110        }
111    }
112
113    fn sort_directory_children(&self, node: &mut DirectoryNode) {
114        if let Some(ref mut children) = node.children {
115            children.sort_by(|a, b| match (&a.node_type, &b.node_type) {
116                (DirectoryNodeType::Directory, DirectoryNodeType::File) => std::cmp::Ordering::Less,
117                (DirectoryNodeType::File, DirectoryNodeType::Directory) => {
118                    std::cmp::Ordering::Greater
119                }
120                _ => a.name.cmp(&b.name),
121            });
122
123            for child in children.iter_mut() {
124                if child.node_type == DirectoryNodeType::Directory {
125                    self.sort_directory_children(child);
126                }
127            }
128        }
129    }
130
131    /// 构建架构分层视图
132    pub fn build_architecture_layers(&self, modules: &[ModuleNode]) -> ArchitectureLayers {
133        let mut layers = ArchitectureLayers::default();
134
135        for module in modules {
136            let result = self.classifier.classify(module);
137
138            let layer_info = match result.layer {
139                ArchitectureLayer::Presentation => &mut layers.presentation,
140                ArchitectureLayer::Business => &mut layers.business,
141                ArchitectureLayer::Data => &mut layers.data,
142                ArchitectureLayer::Infrastructure => &mut layers.infrastructure,
143                ArchitectureLayer::CrossCutting => &mut layers.cross_cutting,
144            };
145
146            layer_info.modules.push(module.id.clone());
147
148            if let Some(sub) = result.sub_layer {
149                let sub_layers = layer_info.sub_layers.get_or_insert_with(HashMap::new);
150                sub_layers.entry(sub).or_default().push(module.id.clone());
151            }
152        }
153
154        // 排序
155        layers.presentation.modules.sort();
156        layers.business.modules.sort();
157        layers.data.modules.sort();
158        layers.infrastructure.modules.sort();
159        layers.cross_cutting.modules.sort();
160
161        layers
162    }
163}
164
165impl Default for ViewBuilder {
166    fn default() -> Self {
167        Self::new()
168    }
169}
170
171/// 统计目录树节点数量
172pub fn count_tree_nodes(node: &DirectoryNode) -> (usize, usize) {
173    let mut dirs = 0;
174    let mut files = 0;
175
176    fn count(n: &DirectoryNode, dirs: &mut usize, files: &mut usize) {
177        match n.node_type {
178            DirectoryNodeType::Directory => *dirs += 1,
179            DirectoryNodeType::File => *files += 1,
180        }
181        if let Some(ref children) = n.children {
182            for child in children {
183                count(child, dirs, files);
184            }
185        }
186    }
187
188    count(node, &mut dirs, &mut files);
189    (dirs, files)
190}
191
192/// 获取目录树最大深度
193pub fn get_tree_depth(node: &DirectoryNode) -> usize {
194    fn depth(n: &DirectoryNode, current: usize) -> usize {
195        if let Some(ref children) = n.children {
196            children
197                .iter()
198                .map(|c| depth(c, current + 1))
199                .max()
200                .unwrap_or(current)
201        } else {
202            current
203        }
204    }
205    depth(node, 0)
206}
207
208/// 快速构建视图
209pub fn build_views(modules: &[ModuleNode]) -> Views {
210    ViewBuilder::new().build_views(modules)
211}
212
213/// 快速构建目录树
214pub fn build_directory_tree(modules: &[ModuleNode]) -> DirectoryNode {
215    ViewBuilder::new().build_directory_tree(modules)
216}
217
218/// 快速构建架构分层
219pub fn build_architecture_layers(modules: &[ModuleNode]) -> ArchitectureLayers {
220    ViewBuilder::new().build_architecture_layers(modules)
221}