Skip to main content

wowlab_engine/cli/audit/
mod.rs

1mod output;
2
3use wowlab_common::output as out;
4use wowlab_engine_application::{SpecAudit, audit_manifest_repository};
5use wowlab_engine_ports::DynDataResolver;
6use wowlab_fs::{
7    directory::{self, EntryKind},
8    path::{Path, PathBuf},
9};
10use wowlab_manifest_schema::ManifestRepository;
11
12use super::CliError;
13
14pub(crate) async fn run(manifests: Option<PathBuf>, workspace_root: &Path) -> Result<(), CliError> {
15    let manifests_dir = match manifests {
16        Some(path) => path,
17        None => find_manifests_dir(workspace_root)?.ok_or_else(|| {
18            CliError::audit(
19                "could not auto-detect manifests directory. Set ENGINE_ROOT or pass --manifests <path>"
20                    .to_string(),
21            )
22        })?,
23    };
24
25    let handle = super::resolver::create(workspace_root)?;
26
27    run_audit(&manifests_dir, &handle.resolver).await
28}
29
30async fn run_audit(manifests_dir: &Path, resolver: &DynDataResolver<'_>) -> Result<(), CliError> {
31    let repository = ManifestRepository::new(manifests_dir);
32    let spec_count = repository.spec_paths()?.len();
33
34    out::banner("Manifest Audit", &format!("{spec_count} specs"));
35    out::blank();
36
37    let audits = audit_manifest_repository(&repository, resolver).await?;
38
39    let (total_errors, total_warnings, specs_with_errors) = print_audits(&audits);
40
41    output::print_summary(
42        total_errors,
43        total_warnings,
44        specs_with_errors,
45        audits.len(),
46    );
47
48    if total_errors > 0 {
49        Err(CliError::audit(format!(
50            "{total_errors} audit errors found"
51        )))
52    } else {
53        Ok(())
54    }
55}
56
57fn print_audits(audits: &[SpecAudit]) -> (usize, usize, usize) {
58    let mut total_errors = 0;
59    let mut total_warnings = 0;
60    let mut specs_with_errors = 0;
61
62    for audit in audits {
63        specs_with_errors += usize::from(!audit.errors.is_empty());
64        total_errors += audit.errors.len();
65        total_warnings += audit.warnings.len();
66        output::print_spec(audit);
67    }
68
69    (total_errors, total_warnings, specs_with_errors)
70}
71
72fn find_manifests_dir(workspace_root: &Path) -> Result<Option<PathBuf>, CliError> {
73    let path = workspace_root
74        .join("crates")
75        .join("engine")
76        .join("manifests");
77    let entry = directory::inspect(&path)?;
78
79    Ok(entry
80        .is_some_and(|entry| entry.kind() == EntryKind::Directory)
81        .then_some(path))
82}