Skip to main content

archidoc_engine/
check.rs

1use std::fs;
2use std::path::Path;
3
4use archidoc_types::{DriftReport, DriftedFile, ModuleDoc};
5
6/// Check for documentation drift against a single ARCHITECTURE.md file.
7///
8/// Generates the expected content in memory and compares it to the
9/// existing file on disk. Returns a report of differences.
10pub fn check_drift(docs: &[ModuleDoc], architecture_file: &Path, root: &Path) -> DriftReport {
11    let expected = crate::architecture::generate(docs, root);
12
13    let mut report = DriftReport::default();
14
15    if !architecture_file.exists() {
16        report
17            .missing_files
18            .push("ARCHITECTURE.md".to_string());
19        return report;
20    }
21
22    let actual = fs::read_to_string(architecture_file).unwrap_or_default();
23
24    if expected != actual {
25        report.drifted_files.push(DriftedFile {
26            path: "ARCHITECTURE.md".to_string(),
27            expected_lines: expected.lines().count(),
28            actual_lines: actual.lines().count(),
29        });
30    }
31
32    report
33}
34
35/// Format a drift report as human-readable text.
36pub fn format_drift_report(report: &DriftReport) -> String {
37    let mut out = String::new();
38
39    if !report.has_drift() {
40        out.push_str("Documentation is up to date.\n");
41        return out;
42    }
43
44    out.push_str("Documentation drift detected!\n\n");
45
46    if !report.drifted_files.is_empty() {
47        out.push_str(&format!(
48            "Changed files ({}):\n",
49            report.drifted_files.len()
50        ));
51        for file in &report.drifted_files {
52            out.push_str(&format!("  {} (expected {} lines, got {})\n",
53                file.path, file.expected_lines, file.actual_lines));
54        }
55    }
56
57    if !report.missing_files.is_empty() {
58        out.push_str(&format!(
59            "Missing files ({}):\n",
60            report.missing_files.len()
61        ));
62        for file in &report.missing_files {
63            out.push_str(&format!("  {}\n", file));
64        }
65    }
66
67    if !report.extra_files.is_empty() {
68        out.push_str(&format!(
69            "Extra files ({}):\n",
70            report.extra_files.len()
71        ));
72        for file in &report.extra_files {
73            out.push_str(&format!("  {}\n", file));
74        }
75    }
76
77    out.push_str("\nRun `archidoc` to regenerate.\n");
78    out
79}