use crate::template::{ComposeSection, PrimitivesManifest};
use anyhow::bail;
pub fn validate_compose_sections(
sections: &[ComposeSection],
manifest: &PrimitivesManifest,
) -> anyhow::Result<()> {
let known: Vec<&str> = manifest
.primitives
.iter()
.map(|p| p.name.as_str())
.collect();
for (idx, section) in sections.iter().enumerate() {
if !known.contains(§ion.primitive.as_str()) {
let suggestion = crate::discovery::find_closest(§ion.primitive, &known)
.map(|s| format!(". Did you mean '{}'?", s))
.unwrap_or_default();
bail!(
"section {}: primitive '{}' not found{}",
idx,
section.primitive,
suggestion
);
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::template::{PrimitiveInfo, PrimitivesManifest};
use serde_json::json;
use std::collections::BTreeMap;
fn manifest(names: &[&str]) -> PrimitivesManifest {
PrimitivesManifest {
version: "1.0".to_string(),
primitives: names
.iter()
.map(|n| PrimitiveInfo {
name: n.to_string(),
description: String::new(),
tags: vec![],
props: BTreeMap::new(),
})
.collect(),
}
}
fn section(primitive: &str) -> ComposeSection {
ComposeSection {
primitive: primitive.to_string(),
data: json!({}),
}
}
#[test]
fn test_valid_sections() {
let sections = vec![section("heading"), section("divider")];
let m = manifest(&["heading", "divider"]);
assert!(validate_compose_sections(§ions, &m).is_ok());
}
#[test]
fn test_unknown_primitive() {
let sections = vec![section("xyz")];
let m = manifest(&["heading"]);
assert!(validate_compose_sections(§ions, &m).is_err());
}
#[test]
fn test_suggestion_on_typo() {
let sections = vec![section("headig")];
let m = manifest(&["heading"]);
let err = validate_compose_sections(§ions, &m).unwrap_err();
assert!(err.to_string().contains("Did you mean"));
}
}