espforge_lib/parse/
mod.rs

1use anyhow::{Context, Result};
2use serde_yaml_ng::Value;
3
4use crate::parse::{
5    model::EspforgeConfiguration,
6    processor::{ProcessorRegistration, SectionProcessor},
7};
8
9pub mod components;
10pub mod devices;
11pub mod esp32;
12pub mod model;
13pub mod processor;
14pub mod project;
15
16pub struct ConfigurationOrchestrator;
17
18impl Default for ConfigurationOrchestrator {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl ConfigurationOrchestrator {
25    pub fn new() -> Self {
26        Self {}
27    }
28
29    pub fn compile(&self, yaml_text: &str) -> Result<EspforgeConfiguration> {
30        let raw_yaml: Value = serde_yaml_ng::from_str(yaml_text)?;
31        let root_map = raw_yaml
32            .as_mapping()
33            .ok_or_else(|| anyhow::anyhow!("Config must be a map"))?;
34
35        let mut model = EspforgeConfiguration::default();
36
37        let mut processors: Vec<Box<dyn SectionProcessor>> =
38            inventory::iter::<ProcessorRegistration>
39                .into_iter()
40                .map(|reg| (reg.factory)())
41                .collect();
42
43        processors.sort_by_key(|b| std::cmp::Reverse(b.priority()));
44        for processor in processors {
45            let key = processor.section_key();
46            if let Some(section_content) = root_map.get(Value::String(key.to_string())) {
47                processor
48                    .process(section_content, &mut model)
49                    .with_context(|| format!("Error processing configuration section '{}'", key))?;
50            }
51        }
52
53        if model.chip.is_empty() {
54            return Err(anyhow::anyhow!(
55                "Project configuration missing required 'espforge.chip' or 'espforge.platform' definition"
56            ));
57        }
58
59        Ok(model)
60    }
61}