Skip to main content

camel_component_validator/
config.rs

1use std::path::{Path, PathBuf};
2
3use camel_component_api::CamelError;
4
5#[derive(Debug, Clone, PartialEq)]
6pub enum SchemaType {
7    Xml,
8    Json,
9    Yaml,
10    RelaxNg,
11    Schematron,
12}
13
14#[derive(Debug, Clone)]
15pub struct ValidatorConfig {
16    pub schema_path: PathBuf,
17    pub schema_type: SchemaType,
18}
19
20impl ValidatorConfig {
21    pub fn from_uri(uri: &str) -> Result<Self, CamelError> {
22        let without_scheme = uri.strip_prefix("validator:").ok_or_else(|| {
23            CamelError::EndpointCreationFailed(format!(
24                "invalid validator URI: must start with 'validator:' — got '{uri}'"
25            ))
26        })?;
27
28        let (path_str, query) = match without_scheme.find('?') {
29            Some(idx) => (&without_scheme[..idx], Some(&without_scheme[idx + 1..])),
30            None => (without_scheme, None),
31        };
32
33        if path_str.is_empty() {
34            return Err(CamelError::EndpointCreationFailed(
35                "validator URI must specify a schema path".to_string(),
36            ));
37        }
38
39        let schema_path = PathBuf::from(path_str);
40
41        let schema_type = if let Some(q) = query {
42            let type_val = q.split('&').find_map(|kv| kv.strip_prefix("type="));
43            match type_val {
44                Some("xml") | Some("xml-schema") | Some("xsd") => SchemaType::Xml,
45                Some("json") | Some("json-schema") => SchemaType::Json,
46                Some("yaml") | Some("yaml-schema") => SchemaType::Yaml,
47                Some("rng") | Some("relaxng") => SchemaType::RelaxNg,
48                Some("sch") | Some("schematron") => SchemaType::Schematron,
49                Some(other) => {
50                    return Err(CamelError::EndpointCreationFailed(format!(
51                        "unknown schema type '{other}'; expected xml, json, yaml, rng, or schematron"
52                    )));
53                }
54                None => detect_type_from_extension(&schema_path)?,
55            }
56        } else {
57            detect_type_from_extension(&schema_path)?
58        };
59
60        Ok(ValidatorConfig {
61            schema_path,
62            schema_type,
63        })
64    }
65}
66
67fn detect_type_from_extension(path: &Path) -> Result<SchemaType, CamelError> {
68    match path.extension().and_then(|e| e.to_str()) {
69        Some("xsd") => Ok(SchemaType::Xml),
70        Some("json") => Ok(SchemaType::Json),
71        Some("yaml") | Some("yml") => Ok(SchemaType::Yaml),
72        Some("rng") | Some("rnc") => Ok(SchemaType::RelaxNg),
73        Some("sch") => Ok(SchemaType::Schematron),
74        ext => Err(CamelError::EndpointCreationFailed(format!(
75            "cannot infer schema type from extension {ext:?}; use ?type=xml|json|yaml|rng|schematron"
76        ))),
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn detects_xml_from_xsd_extension() {
86        let cfg = ValidatorConfig::from_uri("validator:schemas/order.xsd").unwrap();
87        assert_eq!(cfg.schema_path, PathBuf::from("schemas/order.xsd"));
88        assert_eq!(cfg.schema_type, SchemaType::Xml);
89    }
90
91    #[test]
92    fn detects_json_from_json_extension() {
93        let cfg = ValidatorConfig::from_uri("validator:schemas/order.json").unwrap();
94        assert_eq!(cfg.schema_type, SchemaType::Json);
95    }
96
97    #[test]
98    fn detects_yaml_from_yaml_extension() {
99        let cfg = ValidatorConfig::from_uri("validator:schemas/order.yaml").unwrap();
100        assert_eq!(cfg.schema_type, SchemaType::Yaml);
101    }
102
103    #[test]
104    fn detects_yaml_from_yml_extension() {
105        let cfg = ValidatorConfig::from_uri("validator:schemas/order.yml").unwrap();
106        assert_eq!(cfg.schema_type, SchemaType::Yaml);
107    }
108
109    #[test]
110    fn type_param_overrides_extension() {
111        let cfg = ValidatorConfig::from_uri("validator:schemas/order.xsd?type=json").unwrap();
112        assert_eq!(cfg.schema_type, SchemaType::Json);
113    }
114
115    #[test]
116    fn wrong_scheme_errors() {
117        assert!(ValidatorConfig::from_uri("timer:tick").is_err());
118    }
119
120    #[test]
121    fn empty_path_errors() {
122        assert!(ValidatorConfig::from_uri("validator:").is_err());
123    }
124
125    #[test]
126    fn unknown_type_param_errors() {
127        assert!(ValidatorConfig::from_uri("validator:schema.xsd?type=csv").is_err());
128    }
129
130    #[test]
131    fn no_extension_no_type_param_errors() {
132        assert!(ValidatorConfig::from_uri("validator:schema").is_err());
133    }
134}