Skip to main content

drft/analyses/
mod.rs

1pub mod betweenness;
2pub mod bridges;
3pub mod change_propagation;
4pub mod connected_components;
5pub mod degree;
6pub mod depth;
7pub mod graph_stats;
8pub mod impact_radius;
9pub mod pagerank;
10pub mod scc;
11pub mod transitive_reduction;
12
13use crate::config::Config;
14use crate::graph::Graph;
15use crate::lockfile::Lockfile;
16use std::path::Path;
17
18/// Context passed to every analysis, providing access to the graph,
19/// filesystem root, config, and optional lockfile.
20pub struct AnalysisContext<'a> {
21    pub graph: &'a Graph,
22    pub root: &'a Path,
23    pub config: &'a Config,
24    pub lockfile: Option<&'a Lockfile>,
25}
26
27/// All known analysis names, sorted alphabetically.
28pub fn all_analysis_names() -> &'static [&'static str] {
29    &[
30        "betweenness",
31        "bridges",
32        "change-propagation",
33        "connected-components",
34        "degree",
35        "depth",
36        "graph-stats",
37        "impact-radius",
38        "pagerank",
39        "scc",
40        "transitive-reduction",
41    ]
42}
43
44/// An analysis computes structured data about the graph.
45/// Rules consume analysis results and map them to diagnostics.
46/// Metrics extract scalar values from analysis results.
47/// See [`docs/analyses`](../../docs/analyses/README.md) for conceptual documentation on each analysis.
48pub trait Analysis {
49    type Output: serde::Serialize;
50
51    fn name(&self) -> &str;
52
53    fn run(&self, ctx: &AnalysisContext) -> Self::Output;
54}
55
56/// The complete, enriched graph. Built once, enriched once.
57/// Carries the graph plus all structural analyses unconditionally.
58pub struct EnrichedGraph {
59    pub graph: Graph,
60    pub betweenness: betweenness::BetweennessResult,
61    pub bridges: bridges::BridgesResult,
62    pub change_propagation: change_propagation::ChangePropagationResult,
63    pub connected_components: connected_components::ConnectedComponentsResult,
64    pub degree: degree::DegreeResult,
65    pub depth: depth::DepthResult,
66    pub graph_stats: graph_stats::GraphStatsResult,
67    pub impact_radius: impact_radius::ImpactRadiusResult,
68    pub pagerank: pagerank::PageRankResult,
69    pub scc: scc::SccResult,
70    pub transitive_reduction: transitive_reduction::TransitiveReductionResult,
71}
72
73/// Build an enriched graph: construct the graph, then run all analyses unconditionally.
74pub fn enrich(
75    root: &Path,
76    config: &Config,
77    lockfile: Option<&Lockfile>,
78) -> anyhow::Result<EnrichedGraph> {
79    let graph = crate::graph::build_graph(root, config)?;
80    Ok(enrich_graph(graph, root, config, lockfile))
81}
82
83/// Enrich a pre-built graph with all analyses.
84pub fn enrich_graph(
85    graph: Graph,
86    root: &Path,
87    config: &Config,
88    lockfile: Option<&Lockfile>,
89) -> EnrichedGraph {
90    let ctx = AnalysisContext {
91        graph: &graph,
92        root,
93        config,
94        lockfile,
95    };
96
97    let betweenness = betweenness::Betweenness.run(&ctx);
98    let bridges = bridges::Bridges.run(&ctx);
99    let change_propagation = change_propagation::ChangePropagation.run(&ctx);
100    let connected_components = connected_components::ConnectedComponents.run(&ctx);
101    let degree = degree::Degree.run(&ctx);
102    let depth = depth::Depth.run(&ctx);
103    let graph_stats = graph_stats::GraphStats.run(&ctx);
104    let impact_radius = impact_radius::ImpactRadius.run(&ctx);
105    let pagerank = pagerank::PageRank.run(&ctx);
106    let scc = scc::StronglyConnectedComponents.run(&ctx);
107    let transitive_reduction = transitive_reduction::TransitiveReduction.run(&ctx);
108
109    EnrichedGraph {
110        graph,
111        betweenness,
112        bridges,
113        change_propagation,
114        connected_components,
115        degree,
116        depth,
117        graph_stats,
118        impact_radius,
119        pagerank,
120        scc,
121        transitive_reduction,
122    }
123}