Skip to main content

ferrous_forge/safety/checks/
doc.rs

1//! Documentation checking - placeholder for now, using standards module
2
3use crate::Result;
4use std::path::Path;
5use std::time::Instant;
6
7use super::SafetyCheck;
8use crate::safety::{CheckType, report::CheckResult};
9
10/// Doc check implementation
11pub struct DocCheck;
12
13impl SafetyCheck for DocCheck {
14    async fn run(project_path: &Path) -> Result<CheckResult> {
15        run(project_path).await
16    }
17
18    fn name() -> &'static str {
19        "doc"
20    }
21
22    fn description() -> &'static str {
23        "Builds project documentation"
24    }
25}
26
27/// Run documentation build check
28///
29/// # Errors
30///
31/// Returns an error if the check result cannot be constructed.
32pub async fn run(project_path: &Path) -> Result<CheckResult> {
33    let start = Instant::now();
34    let mut result = CheckResult::new(CheckType::Doc);
35
36    match tokio::process::Command::new("cargo")
37        .args(["doc", "--no-deps"])
38        .current_dir(project_path)
39        .output()
40        .await
41    {
42        Ok(output) => {
43            if !output.status.success() {
44                let stderr = String::from_utf8_lossy(&output.stderr);
45                result.add_error(&format!("cargo doc failed: {stderr}"));
46                result.fail();
47            } else {
48                result.add_context("Documentation built successfully");
49            }
50        }
51        Err(e) => {
52            result.add_error(&format!("Failed to execute cargo doc: {e}"));
53            result.fail();
54        }
55    }
56
57    result.set_duration(start.elapsed());
58    Ok(result)
59}
60
61/// Check documentation coverage
62///
63/// # Errors
64///
65/// Returns an error if the documentation coverage check fails to run.
66pub async fn coverage_check(project_path: &Path) -> Result<CheckResult> {
67    let start = Instant::now();
68    let mut result = CheckResult::new(CheckType::DocCoverage);
69
70    let coverage = crate::doc_coverage::check_documentation_coverage(project_path).await?;
71    let threshold = 50.0;
72
73    if !coverage.meets_threshold(threshold) {
74        result.add_error(&format!(
75            "Documentation coverage {:.1}% is below the {:.0}% threshold",
76            coverage.coverage_percent, threshold
77        ));
78        result.fail();
79    }
80
81    result.add_context(&format!(
82        "Documentation coverage: {:.1}% ({}/{} items documented)",
83        coverage.coverage_percent, coverage.documented_items, coverage.total_items
84    ));
85
86    result.set_duration(start.elapsed());
87    Ok(result)
88}