wowlab_engine/cli/validate/
mod.rs1use 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 for n in names {
62 output::error(&format!("missing {kind}: {n}"));
63 }
64}