Skip to main content

wowlab_engine/cli/validate/
mod.rs

1use std::collections::BTreeSet;
2
3use wowlab_common::output;
4use wowlab_engine_application::validate_rotation_for_spec;
5use wowlab_fs::{file, path::Path};
6use wowlab_types::{game::SpecId, sim::Rotation};
7
8use super::CliError;
9use crate::composition::EngineComposition;
10
11pub(crate) fn run(
12    rotation_path: &Path,
13    spec: Option<SpecId>,
14    composition: EngineComposition,
15) -> Result<(), CliError> {
16    let content = file::read_text(rotation_path)?;
17
18    let rotation: Rotation = serde_json::from_str(&content)?;
19
20    let name = if rotation.name.is_empty() {
21        "(unnamed)"
22    } else {
23        rotation.name.as_str()
24    };
25
26    let actions_count = rotation.lists.values().map(Vec::len).sum::<usize>();
27
28    output::success(&format!("Rotation '{name}' is valid"));
29    output::kv_fmt("Actions", actions_count);
30    output::kv_fmt("Variables", rotation.variables.len());
31    output::kv_fmt("Lists", rotation.lists.len());
32
33    let Some(spec_id) = spec else {
34        return Ok(());
35    };
36
37    let descriptor = composition.catalog().descriptor(spec_id)?;
38    let result = validate_rotation_for_spec(composition.catalog(), spec_id, &rotation)?;
39
40    if result.is_clean() {
41        output::success(&format!(
42            "All referenced names resolve against {}",
43            descriptor.display_name
44        ));
45
46        return Ok(());
47    }
48
49    report_missing("spell", &result.missing_spells);
50    report_missing("aura", &result.missing_auras);
51    report_missing("talent", &result.missing_talents);
52
53    Err(CliError::unresolved_names(
54        result.total_missing(),
55        descriptor.display_name.to_string(),
56    ))
57}
58
59fn report_missing(kind: &str, names: &BTreeSet<String>) {
60    // #t(block: rust_alloc_in_loop) error reporting only fires on the failure path
61    for n in names {
62        output::error(&format!("missing {kind}: {n}"));
63    }
64}