use alloc::vec::Vec;
use mf2_catalog::writer::{self, Options};
use mf2_catalog::{Catalog, Manifest, MsgId};
use mf2_locale_data::number::NumberNeeds;
use mf2_locale_data::{LocaleNeeds, direction, locale_entries};
use crate::error::CompileError;
#[derive(Debug)]
#[non_exhaustive]
pub struct Compiled {
pub catalog: Catalog,
#[doc(hidden)]
pub manifest: Manifest,
}
impl Compiled {
pub const ID: MsgId = MsgId::from_raw(0);
}
pub fn compile_str(source: &str, locale: &str) -> Result<Compiled, CompileError> {
compile(source, locale, false)
}
pub fn compile_str_stripped(source: &str, locale: &str) -> Result<Compiled, CompileError> {
compile(source, locale, true)
}
fn compile(source: &str, locale: &str, strip: bool) -> Result<Compiled, CompileError> {
let parsed = mf2_syntax::parse_model(source);
let model = match parsed.message {
Some(m) if parsed.diagnostics.is_empty() => m,
_ => return Err(CompileError::Invalid(parsed.diagnostics.into_vec())),
};
let analysis = mf2_syntax::analyze(&model);
let slots: Vec<&str> = analysis.externals.iter().map(|n| &*n.nfc).collect();
let mut options = Options::new(locale, direction(locale)?);
options.cldr_version = Some(mf2_locale_data::CLDR_VERSION);
let mut numbers = NumberNeeds::default();
numbers.add_message(&model);
numbers.symbols = true;
let mut needs = LocaleNeeds::default();
needs.cardinal = true;
needs.ordinal = true;
needs.numbers = numbers;
options.locale_entries = locale_entries(locale, &needs)?;
#[cfg(feature = "datetime-icu")]
{
use mf2_locale_data::icu_blob::{DateNeeds, IcuBlobSpec, icu_blob};
let mut dates = DateNeeds::default();
dates.add_message(&model);
if !dates.is_empty() {
options.locale_entries.push((
mf2_catalog::format::locale_key::ICU_BLOB,
icu_blob(locale, &IcuBlobSpec::every_variant(dates))?,
));
}
}
if strip {
options = options.stripped();
}
let (bytes, manifest) = writer::single(&model, &slots, &options)?;
let catalog = Catalog::new(bytes, manifest.hash())?;
Ok(Compiled { catalog, manifest })
}