1pub mod cache;
2pub mod columns;
3pub mod discovery;
4pub mod jinja;
5pub mod manifest;
6pub mod manifest_cache;
7pub mod project;
8pub mod sql;
9#[allow(dead_code)]
10pub mod yaml_schema;
11
12use anyhow::Result;
13use serde::de::DeserializeOwned;
14
15pub fn yaml_from_str<T: DeserializeOwned>(content: &str, location: &str) -> Result<T> {
22 let value: serde_json::Value = match serde_saphyr::from_str(content) {
23 Ok(v) => v,
24 Err(e) => {
25 if is_duplicate_key_error(&e) {
26 let key = extract_duplicate_key(&e).unwrap_or("unknown");
27 crate::warn!(
28 "duplicate YAML key '{}' in {} (using last value)",
29 key,
30 location,
31 );
32 let options = serde_saphyr::options! {
33 duplicate_keys: serde_saphyr::options::DuplicateKeyPolicy::LastWins
34 };
35 serde_saphyr::from_str_with_options(content, options)?
36 } else {
37 return Err(e.into());
38 }
39 }
40 };
41 if value.is_null() {
42 return Ok(serde_json::from_value(serde_json::Value::Object(
44 Default::default(),
45 ))?);
46 }
47 Ok(serde_json::from_value(value)?)
48}
49
50fn is_duplicate_key_error(e: &serde_saphyr::Error) -> bool {
52 match e {
53 serde_saphyr::Error::DuplicateMappingKey { .. } => true,
54 serde_saphyr::Error::WithSnippet { error, .. } => is_duplicate_key_error(error),
55 _ => false,
56 }
57}
58
59fn extract_duplicate_key(e: &serde_saphyr::Error) -> Option<&str> {
61 match e {
62 serde_saphyr::Error::DuplicateMappingKey { key, .. } => key.as_deref(),
63 serde_saphyr::Error::WithSnippet { error, .. } => extract_duplicate_key(error),
64 _ => None,
65 }
66}