workshop-rs 1.7.0

Canonical multi-locale Overwatch Workshop semantic core: catalog, parser, WIR, validation, emitter.
Documentation
use crate::catalog::{Catalog, Kind};
use crate::core::error::{Result, WorkshopError};
use crate::wir;

pub(crate) fn validate_event(
    event: &wir::Event,
    span: Option<crate::core::source::Span>,
    catalog: &Catalog,
) -> Result<()> {
    let (id, filters) = match event {
        wir::Event::Global => ("global", None),
        wir::Event::EachPlayer => ("eachPlayer", None),
        wir::Event::EachPlayerWithFilters { team, target } => ("eachPlayer", Some((*team, target))),
        wir::Event::Player { kind, team, target } => (kind.catalog_id(), Some((*team, target))),
        wir::Event::Subroutine { .. } => ("subroutine", None),
    };
    if catalog.entry(Kind::Event, id).is_none() {
        return Err(WorkshopError::unknown(
            "event",
            id.to_string(),
            crate::catalog::Locale::new("en-US"),
            span,
        )
        .with_candidates(crate::core::suggest::nearest(
            id,
            catalog.canonical_spellings(Kind::Event, catalog.primary_locale()),
            crate::core::suggest::CANDIDATE_LIMIT,
        )));
    }
    let Some((team, target)) = filters else {
        return Ok(());
    };
    let en = crate::catalog::Locale::new("en-US");
    let team_member = match team {
        wir::EventTeam::All => "ALL",
        wir::EventTeam::Team1 => "TEAM_1",
        wir::EventTeam::Team2 => "TEAM_2",
    };
    if catalog
        .enum_spelling("EventTeam", &en, team_member)
        .is_none()
    {
        return Err(WorkshopError::unknown(
            "event team",
            team_member.to_string(),
            en.clone(),
            span,
        )
        .with_candidates(crate::core::suggest::nearest(
            team_member,
            catalog.canonical_member_spellings("EventTeam", catalog.primary_locale()),
            crate::core::suggest::CANDIDATE_LIMIT,
        )));
    }
    let target_member = match target {
        wir::EventTarget::All => Some("ALL".to_string()),
        wir::EventTarget::Slot(slot) => Some(format!("SLOT_{slot}")),
        wir::EventTarget::Hero(hero) => {
            if catalog.enum_spelling("Hero", &en, hero).is_none() {
                return Err(
                    WorkshopError::unknown("event player", hero.clone(), en.clone(), span)
                        .with_candidates(crate::core::suggest::nearest(
                            hero,
                            catalog
                                .canonical_member_spellings("EventPlayer", catalog.primary_locale())
                                .chain(
                                    catalog.canonical_member_spellings(
                                        "Hero",
                                        catalog.primary_locale(),
                                    ),
                                ),
                            crate::core::suggest::CANDIDATE_LIMIT,
                        )),
                );
            }
            None
        }
    };
    if let Some(target_member) = target_member {
        if catalog
            .enum_spelling("EventPlayer", &en, &target_member)
            .is_none()
        {
            return Err(
                WorkshopError::unknown("event player", target_member.clone(), en, span)
                    .with_candidates(crate::core::suggest::nearest(
                        &target_member,
                        catalog
                            .canonical_member_spellings("EventPlayer", catalog.primary_locale())
                            .chain(
                                catalog
                                    .canonical_member_spellings("Hero", catalog.primary_locale()),
                            ),
                        crate::core::suggest::CANDIDATE_LIMIT,
                    )),
            );
        }
    }
    Ok(())
}