Skip to main content

schematic/config/formats/
yaml.rs

1use super::create_span;
2use crate::config::error::ConfigError;
3use crate::config::parser::ParserError;
4use crate::config::source::*;
5use miette::NamedSource;
6use serde::de::{DeserializeOwned, IntoDeserializer};
7use serde_norway::{Deserializer, Error, Value};
8use std::path::Path;
9
10#[derive(Default)]
11pub struct YamlFormat {}
12
13impl<T: DeserializeOwned> SourceFormat<T> for YamlFormat {
14    fn should_parse(&self, source: &Source) -> bool {
15        source
16            .get_file_ext()
17            .is_some_and(|ext| ext == "yml" || ext == "yaml")
18    }
19
20    fn parse(
21        &self,
22        source: &Source,
23        content: &str,
24        _cache_path: Option<&Path>,
25    ) -> Result<T, ConfigError> {
26        let name = source.get_file_name();
27
28        fn create_parser_error(
29            name: &str,
30            content: &str,
31            path: String,
32            error: Error,
33        ) -> ParserError {
34            ParserError {
35                content: NamedSource::new(name, content.to_owned()),
36                path,
37                span: error
38                    .location()
39                    .map(|s| create_span(content, s.line(), s.column())),
40                message: error.to_string(),
41            }
42        }
43
44        // First pass, convert string to value
45        let de = Deserializer::from_str(content);
46
47        let mut result: Value = serde_path_to_error::deserialize(de).map_err(|error| {
48            create_parser_error(name, content, error.path().to_string(), error.into_inner())
49        })?;
50
51        // Applies anchors/aliases/references
52        result
53            .apply_merge()
54            .map_err(|error| create_parser_error(name, content, String::new(), error))?;
55
56        // Second pass, convert value to struct
57        let de = result.into_deserializer();
58
59        let result: T = serde_path_to_error::deserialize(de).map_err(|error| {
60            create_parser_error(name, content, error.path().to_string(), error.into_inner())
61        })?;
62
63        Ok(result)
64    }
65}