Skip to main content

the_code_graph_cli/commands/
stats.rs

1use domain::error::Result;
2use domain::model::{CloneConfig, FlowConfig, RiskConfig};
3use domain::use_cases::clones::CloneUseCase;
4use domain::use_cases::flow::FlowUseCase;
5use domain::use_cases::query::QueryUseCase;
6use domain::use_cases::risk::RiskUseCase;
7
8use crate::adapters::fs::RealFileSystem;
9use crate::commands::helpers::open_graph;
10use crate::output::{print, OutputFormat};
11
12pub fn run_stats(output_format: OutputFormat) -> Result<()> {
13    let (store, root) = open_graph()?;
14    let uc = QueryUseCase::new(store.clone(), store.clone());
15    let mut stats = uc.stats()?;
16
17    // On-demand flow analysis integration
18    let risk_store = store.clone();
19    let clone_store = store.clone();
20    let flow_uc = FlowUseCase::new(store);
21    let flow_config = FlowConfig::default();
22    let analysis = flow_uc.analyze(&flow_config)?;
23    stats.entry_point_count = Some(analysis.stats.total_entry_points);
24
25    // Only compute avg_criticality if <= 5000 symbols (Brandes' is O(V*E))
26    if stats.symbols <= 5000 {
27        let avg = if analysis.criticality.is_empty() {
28            0.0
29        } else {
30            analysis
31                .criticality
32                .iter()
33                .map(|c| c.betweenness)
34                .sum::<f64>()
35                / analysis.criticality.len() as f64
36        };
37        stats.avg_criticality = Some(avg);
38    }
39
40    // On-demand clone analysis integration
41    if stats.symbols <= 10_000 {
42        let clone_fs = RealFileSystem;
43        let clone_uc = CloneUseCase::new(clone_store, clone_fs, root);
44        let clone_config = CloneConfig::default();
45        if let Ok(clone_analysis) = clone_uc.analyze(&clone_config) {
46            stats.clone_clusters = Some(clone_analysis.clusters.len());
47            stats.duplication_pct = Some(clone_analysis.duplication_pct);
48            stats.most_duplicated = clone_analysis.most_duplicated;
49        }
50    }
51
52    // On-demand risk analysis integration
53    if stats.symbols <= 5000 {
54        let risk_uc = RiskUseCase::new(risk_store);
55        let risk_config = RiskConfig::default();
56        if let Ok(risk_analysis) = risk_uc.analyze(&risk_config) {
57            stats.avg_risk = Some(risk_analysis.stats.avg_risk);
58            stats.p90_risk = Some(risk_analysis.stats.p90_risk);
59        }
60    }
61
62    print(&stats, output_format);
63    Ok(())
64}