Skip to main content

aster/map/
layer_classifier.rs

1//! 架构层分类器
2//!
3//! 根据文件路径和内容自动分类模块所属的架构层
4
5use super::types::ModuleNode;
6use super::types_enhanced::ArchitectureLayer;
7
8/// 分类规则
9struct ClassificationRule {
10    patterns: Vec<&'static str>,
11    layer: ArchitectureLayer,
12    sub_layer: Option<&'static str>,
13    priority: u8,
14}
15
16/// 分类规则配置
17fn get_classification_rules() -> Vec<ClassificationRule> {
18    vec![
19        // 表现层 - UI 组件
20        ClassificationRule {
21            patterns: vec![
22                "/ui/",
23                "/components/",
24                "/pages/",
25                "/views/",
26                "/screens/",
27                ".tsx",
28            ],
29            layer: ArchitectureLayer::Presentation,
30            sub_layer: Some("components"),
31            priority: 10,
32        },
33        // 表现层 - 样式
34        ClassificationRule {
35            patterns: vec!["/styles/", "/css/", "/themes/", ".css", ".scss"],
36            layer: ArchitectureLayer::Presentation,
37            sub_layer: Some("styles"),
38            priority: 10,
39        },
40        // 业务层 - 核心逻辑
41        ClassificationRule {
42            patterns: vec![
43                "/core/",
44                "/domain/",
45                "/business/",
46                "/services/",
47                "/usecases/",
48            ],
49            layer: ArchitectureLayer::Business,
50            sub_layer: Some("core"),
51            priority: 20,
52        },
53        // 业务层 - 工具系统
54        ClassificationRule {
55            patterns: vec!["/tools/"],
56            layer: ArchitectureLayer::Business,
57            sub_layer: Some("tools"),
58            priority: 15,
59        },
60        // 数据层 - API
61        ClassificationRule {
62            patterns: vec!["/api/", "/client/", "/http/", "/fetch/"],
63            layer: ArchitectureLayer::Data,
64            sub_layer: Some("api"),
65            priority: 20,
66        },
67        // 数据层 - 存储
68        ClassificationRule {
69            patterns: vec![
70                "/db/",
71                "/database/",
72                "/repositories/",
73                "/storage/",
74                "/cache/",
75            ],
76            layer: ArchitectureLayer::Data,
77            sub_layer: Some("storage"),
78            priority: 20,
79        },
80        // 基础设施 - 配置
81        ClassificationRule {
82            patterns: vec!["/config/", "/settings/", "/env/"],
83            layer: ArchitectureLayer::Infrastructure,
84            sub_layer: Some("config"),
85            priority: 5,
86        },
87        // 基础设施 - 工具函数
88        ClassificationRule {
89            patterns: vec!["/utils/", "/helpers/", "/lib/", "/common/", "/shared/"],
90            layer: ArchitectureLayer::Infrastructure,
91            sub_layer: Some("utils"),
92            priority: 5,
93        },
94        // 基础设施 - 类型定义
95        ClassificationRule {
96            patterns: vec!["/types/", "/interfaces/", "/models/", ".d.ts"],
97            layer: ArchitectureLayer::Infrastructure,
98            sub_layer: Some("types"),
99            priority: 5,
100        },
101        // 横切关注点 - 钩子
102        ClassificationRule {
103            patterns: vec!["/hooks/"],
104            layer: ArchitectureLayer::CrossCutting,
105            sub_layer: Some("hooks"),
106            priority: 15,
107        },
108        // 横切关注点 - 中间件
109        ClassificationRule {
110            patterns: vec!["/middleware/", "/interceptors/"],
111            layer: ArchitectureLayer::CrossCutting,
112            sub_layer: Some("middleware"),
113            priority: 15,
114        },
115        // 横切关注点 - 日志
116        ClassificationRule {
117            patterns: vec!["/log/", "/logging/", "/monitor/", "/telemetry/"],
118            layer: ArchitectureLayer::CrossCutting,
119            sub_layer: Some("logging"),
120            priority: 15,
121        },
122        // 横切关注点 - 认证
123        ClassificationRule {
124            patterns: vec!["/auth/", "/permission/", "/security/", "/oauth/"],
125            layer: ArchitectureLayer::CrossCutting,
126            sub_layer: Some("auth"),
127            priority: 15,
128        },
129    ]
130}
131
132/// 分类结果
133#[derive(Debug, Clone)]
134pub struct ClassificationResult {
135    pub layer: ArchitectureLayer,
136    pub sub_layer: Option<String>,
137    pub confidence: f64,
138    pub matched_rules: Vec<String>,
139}
140
141/// 架构层分类器
142pub struct LayerClassifier {
143    rules: Vec<ClassificationRule>,
144}
145
146impl LayerClassifier {
147    pub fn new() -> Self {
148        Self {
149            rules: get_classification_rules(),
150        }
151    }
152
153    /// 对单个模块进行架构层分类
154    pub fn classify(&self, module: &ModuleNode) -> ClassificationResult {
155        let path = &module.id;
156        let path_lower = path.to_lowercase();
157        let mut matched: Vec<(&ClassificationRule, Vec<&str>)> = Vec::new();
158
159        for rule in &self.rules {
160            let matches: Vec<&str> = rule
161                .patterns
162                .iter()
163                .filter(|p| path_lower.contains(&p.to_lowercase()))
164                .copied()
165                .collect();
166            if !matches.is_empty() {
167                matched.push((rule, matches));
168            }
169        }
170
171        if !matched.is_empty() {
172            matched.sort_by(|a, b| {
173                b.0.priority
174                    .cmp(&a.0.priority)
175                    .then_with(|| b.1.len().cmp(&a.1.len()))
176            });
177
178            let best = &matched[0];
179            return ClassificationResult {
180                layer: best.0.layer,
181                sub_layer: best.0.sub_layer.map(String::from),
182                confidence: (0.5 + best.1.len() as f64 * 0.1).min(0.9),
183                matched_rules: best.1.iter().map(|s| s.to_string()).collect(),
184            };
185        }
186
187        // 基于内容特征分析
188        if let Some(result) = self.classify_by_content(module) {
189            return result;
190        }
191
192        // 默认分类
193        ClassificationResult {
194            layer: ArchitectureLayer::Infrastructure,
195            sub_layer: None,
196            confidence: 0.3,
197            matched_rules: vec!["default".to_string()],
198        }
199    }
200
201    fn classify_by_content(&self, module: &ModuleNode) -> Option<ClassificationResult> {
202        let mut has_react = false;
203        let mut has_db = false;
204        let mut has_api = false;
205
206        for imp in &module.imports {
207            let src = imp.source.to_lowercase();
208            if src.contains("react") || src.contains("ink") {
209                has_react = true;
210            }
211            if src.contains("mongo") || src.contains("mysql") || src.contains("postgres") {
212                has_db = true;
213            }
214            if src.contains("axios") || src.contains("fetch") || src.contains("http") {
215                has_api = true;
216            }
217        }
218
219        if has_react {
220            return Some(ClassificationResult {
221                layer: ArchitectureLayer::Presentation,
222                sub_layer: None,
223                confidence: 0.7,
224                matched_rules: vec!["content:react".to_string()],
225            });
226        }
227
228        if has_db {
229            return Some(ClassificationResult {
230                layer: ArchitectureLayer::Data,
231                sub_layer: Some("storage".to_string()),
232                confidence: 0.7,
233                matched_rules: vec!["content:database".to_string()],
234            });
235        }
236
237        if has_api {
238            return Some(ClassificationResult {
239                layer: ArchitectureLayer::Data,
240                sub_layer: Some("api".to_string()),
241                confidence: 0.6,
242                matched_rules: vec!["content:api".to_string()],
243            });
244        }
245
246        None
247    }
248
249    /// 批量分类
250    pub fn classify_all(
251        &self,
252        modules: &[ModuleNode],
253    ) -> std::collections::HashMap<String, ClassificationResult> {
254        modules
255            .iter()
256            .map(|m| (m.id.clone(), self.classify(m)))
257            .collect()
258    }
259
260    /// 获取层描述
261    pub fn get_layer_description(layer: ArchitectureLayer) -> &'static str {
262        match layer {
263            ArchitectureLayer::Presentation => "表现层:用户界面、组件、页面、视图渲染",
264            ArchitectureLayer::Business => "业务层:核心业务逻辑、领域模型、服务实现",
265            ArchitectureLayer::Data => "数据层:API 调用、数据库访问、存储管理",
266            ArchitectureLayer::Infrastructure => "基础设施层:工具函数、配置管理、类型定义",
267            ArchitectureLayer::CrossCutting => "横切关注点:认证、日志、中间件、插件系统",
268        }
269    }
270}
271
272impl Default for LayerClassifier {
273    fn default() -> Self {
274        Self::new()
275    }
276}
277
278/// 快速分类单个模块
279pub fn classify_module(module: &ModuleNode) -> ClassificationResult {
280    LayerClassifier::new().classify(module)
281}
282
283/// 批量分类模块
284pub fn classify_modules(
285    modules: &[ModuleNode],
286) -> std::collections::HashMap<String, ClassificationResult> {
287    LayerClassifier::new().classify_all(modules)
288}