Skip to main content

code_repo_wiki/analysis/
mod.rs

1pub mod community;
2pub mod feature;
3pub mod graph;
4pub mod module;
5
6
7use anyhow::Result;
8
9use crate::ingest::parser::FileInsight;
10use crate::model::{KnowledgeGraph, ModuleCluster};
11
12/// 从 FileInsight 列表构建完整知识图谱
13pub fn build_graph(insights: &[FileInsight]) -> Result<KnowledgeGraph> {
14    graph::build(insights)
15}
16
17/// 检测模块边界(社区检测)
18pub fn detect_modules(graph: &KnowledgeGraph) -> Result<Vec<ModuleCluster>> {
19    let detector = module::ModuleDetector::new(graph);
20    Ok(detector.detect())
21}
22
23    #[cfg(test)]
24    mod tests {
25        use super::*;
26        use crate::ingest::parser::{Entity, FileInsight, ImportStmt};
27        use std::path::PathBuf;
28
29        #[test]
30        fn test_full_pipeline() {
31            let insights = vec![
32                FileInsight {
33                    path: PathBuf::from("src/main.rs"),
34                    language: "rust".into(),
35                    entities: vec![Entity {
36                        name: "main".into(),
37                        kind: "fn".into(),
38                        line_start: 1,
39                        line_end: 5,
40                        doc_comment: None,
41                        signature: Some("fn main()".into()),
42                        visibility: None,
43                    }],
44                    imports: vec![],
45                    doc_comments: vec![],
46                    source: String::new(),
47                },
48                FileInsight {
49                    path: PathBuf::from("src/lib.rs"),
50                    language: "rust".into(),
51                    entities: vec![Entity {
52                        name: "add".into(),
53                        kind: "fn".into(),
54                        line_start: 1,
55                        line_end: 3,
56                        doc_comment: None,
57                        signature: Some("fn add(a: i32, b: i32) -> i32".into()),
58                        visibility: None,
59                    }],
60                    imports: vec![ImportStmt {
61                        source: "crate::main".into(),
62                        alias: None,
63                        line: 1,
64                    }],
65                    doc_comments: vec![],
66                    source: String::new(),
67                },
68            ];
69
70        let graph = build_graph(&insights).expect("构建图失败");
71        assert!(graph.graph.node_count() > 0);
72        assert!(graph.graph.edge_count() > 0);
73        assert_eq!(graph.graph.node_count(), 6); // Project + Module(src) + 2 File + 2 Entity
74
75        let modules = detect_modules(&graph).expect("模块检测失败");
76        // 验证模块检测不 panic(当前测试图过小,可能返回空聚类)
77        assert!(modules.len() < graph.graph.node_count());
78    }
79
80    /// A1 接线回归:build_graph 返回的图必须已填充 modules(生成层
81    /// 以 graph.modules 为模块分组唯一来源,恒空会导致按模块生成
82    /// 静默退化为按文件分块)
83    #[test]
84    fn test_build_graph_fills_modules() {
85        let insights = vec![
86            FileInsight {
87                path: PathBuf::from("src/main.rs"),
88                language: "rust".into(),
89                entities: vec![Entity {
90                    name: "main".into(),
91                    kind: "fn".into(),
92                    line_start: 1,
93                    line_end: 5,
94                    doc_comment: None,
95                    signature: Some("fn main()".into()),
96                    visibility: None,
97                }],
98                imports: vec![],
99                doc_comments: vec![],
100                source: String::new(),
101            },
102            FileInsight {
103                path: PathBuf::from("src/lib.rs"),
104                language: "rust".into(),
105                entities: vec![Entity {
106                    name: "add".into(),
107                    kind: "fn".into(),
108                    line_start: 1,
109                    line_end: 3,
110                    doc_comment: None,
111                    signature: Some("fn add(a: i32, b: i32) -> i32".into()),
112                    visibility: None,
113                }],
114                imports: vec![ImportStmt {
115                    source: "crate::main".into(),
116                    alias: None,
117                    line: 1,
118                }],
119                doc_comments: vec![],
120                source: String::new(),
121            },
122        ];
123        let graph = build_graph(&insights).expect("构建图失败");
124        // build_graph 内部必须完成模块检测并写回 graph.modules
125        // (此前该字段恒空,是模块聚类未接线的根因)
126        assert_eq!(graph.modules, detect_modules(&graph).expect("模块检测失败"));
127    }
128}