Skip to main content

espforge_lib/parse/
mod.rs

1use anyhow::{Context, Result};
2use espforge_common::EspforgeConfiguration;
3use serde_yaml_ng::Value;
4
5use crate::parse::{
6    processor::SectionProcessor,
7};
8
9pub mod components;
10pub mod devices;
11pub mod esp32;
12pub mod model;
13pub mod processor;
14pub mod project;
15
16
17pub struct ConfigParser {
18    processors: Vec<Box<dyn SectionProcessor>>,
19}
20
21impl ConfigParser {
22    /// Helper to start the building process
23    pub fn builder() -> ConfigParserBuilder {
24        ConfigParserBuilder::default()
25    }
26
27    /// Helper to get a parser with standard defaults immediately
28    pub fn new() -> Self {
29        ConfigParserBuilder::default_processors().build()
30    }
31
32    // The logic stays here, but the name implies action now.
33    pub fn parse(&self, yaml_text: &str) -> Result<EspforgeConfiguration> {
34        let raw_yaml: Value = serde_yaml_ng::from_str(yaml_text)?;
35        let root_map = raw_yaml
36            .as_mapping()
37            .ok_or_else(|| anyhow::anyhow!("Config must be a map"))?;
38
39        let mut model = EspforgeConfiguration::default();
40
41        for processor in &self.processors {
42            let key = processor.section_key();
43            if let Some(section_content) = root_map.get(Value::String(key.to_string())) {
44                processor
45                    .process(section_content, &mut model)
46                    .with_context(|| format!("Error processing configuration section '{}'", key))?;
47            }
48        }
49
50        if model.chip.is_empty() {
51            return Err(anyhow::anyhow!(
52                "Project configuration missing required 'espforge.chip' or 'espforge.platform'"
53            ));
54        }
55
56        Ok(model)
57    }
58}
59
60
61pub struct ConfigParserBuilder {
62    processors: Vec<Box<dyn SectionProcessor>>,
63}
64
65impl Default for ConfigParserBuilder {
66    fn default() -> Self {
67        Self::new()
68    }
69}
70
71impl ConfigParserBuilder {
72    pub fn new() -> Self {
73        Self {
74            processors: Vec::new(),
75        }
76    }
77
78    pub fn default_processors() -> Self {
79        Self::new()
80            .with_processor(Box::new(project::ProjectInfoProvisioner))
81            .with_processor(Box::new(esp32::PlatformProvisioner))
82            .with_processor(Box::new(components::ComponentProvisioner))
83            .with_processor(Box::new(devices::DeviceProvisioner))
84    }
85
86    pub fn with_processor(mut self, processor: Box<dyn SectionProcessor>) -> Self {
87        self.processors.push(processor);
88        self
89    }
90
91    // Returns the Parser, not another Builder
92    pub fn build(mut self) -> ConfigParser {
93        self.processors.sort_by_key(|p| std::cmp::Reverse(p.priority()));
94
95        ConfigParser {
96            processors: self.processors,
97        }
98    }
99}