diff --git a/src/json_schema/mod.rs b/src/json_schema/mod.rs index bbedddcc..1516cf2d 100644 --- a/src/json_schema/mod.rs +++ b/src/json_schema/mod.rs @@ -569,11 +569,23 @@ mod tests { r#"(0|1)"#, vec!["0", "1"], vec!["a"], ), + // Enum array + ( + r#"{"title": "Foo", "enum": [[1,2],[3,4]], "type": "array"}"#, + format!(r#"(\[{0}1{0},{0}2{0}\]|\[{0}3{0},{0}4{0}\])"#, WHITESPACE).as_str(), + vec!["[1,2]", "[3,4]", "[1, 2 ]"], vec!["1", "[1,3]"], + ), + // Enum object + ( + r#"{"title": "Foo", "enum": [{"a":"b","c":"d"}, {"e":"f"}], "type": "object"}"#, + format!(r#"(\{{{0}"a"{0}:{0}"b"{0},{0}"c"{0}:{0}"d"{0}\}}|\{{{0}"e"{0}:{0}"f"{0}\}})"#, WHITESPACE).as_str(), + vec![r#"{"a":"b","c":"d"}"#, r#"{"e":"f"}"#, r#"{"a" : "b", "c": "d" }"#], vec!["a", r#"{"a":"b"}"#], + ), // Enum mix of types ( - r#"{"title": "Foo", "enum": [6, 5.3, "potato", true, null]}"#, - r#"(6|5\.3|"potato"|true|null)"#, - vec!["6", "5.3", r#""potato""#, "true", "null"], vec!["none", "53"], + r#"{"title": "Foo", "enum": [6, 5.3, "potato", true, null, [1,2], {"a":"b"}]}"#, + format!(r#"(6|5\.3|"potato"|true|null|\[{0}1{0},{0}2{0}\]|\{{{0}"a"{0}:{0}"b"{0}\}})"#, WHITESPACE).as_str(), + vec!["6", "5.3", r#""potato""#, "true", "null", "[1, 2]", r#"{"a": "b" }"#], vec!["none", "53"], ), // ========================================================== // UUID diff --git a/src/json_schema/parsing.rs b/src/json_schema/parsing.rs index d6ff8e9f..8eaa5bd6 100644 --- a/src/json_schema/parsing.rs +++ b/src/json_schema/parsing.rs @@ -237,13 +237,7 @@ impl<'a> Parser<'a> { Some(Value::Array(enum_values)) => { let choices: Result> = enum_values .iter() - .map(|choice| match choice { - Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => { - let json_string = serde_json::to_string(choice)?; - Ok(regex::escape(&json_string)) - } - _ => Err(Error::UnsupportedEnumDataType(Box::new(choice.clone()))), - }) + .map(|choice| self.parse_const_value(choice)) .collect(); let choices = choices?; @@ -254,17 +248,42 @@ impl<'a> Parser<'a> { } fn parse_const(&mut self, obj: &serde_json::Map) -> Result { - match obj.get("const") { - Some(const_value) => match const_value { - Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => { - let json_string = serde_json::to_string(const_value)?; - Ok(regex::escape(&json_string)) - } - _ => Err(Error::UnsupportedConstDataType(Box::new( - const_value.clone(), - ))), - }, - None => Err(Error::ConstKeyNotFound), + if let Some(const_value) = obj.get("const") { + self.parse_const_value(const_value) + } else { + Err(Error::ConstKeyNotFound) + } + } + + fn parse_const_value(&self, value: &Value) -> Result { + match value { + Value::Array(array_values) => { + let inner_regex = array_values + .iter() + .map(|value| self.parse_const_value(value)) + .collect::>>()? + .join(format!("{0},{0}", self.whitespace_pattern).as_str()); + Ok(format!(r"\[{0}{inner_regex}{0}\]", self.whitespace_pattern)) + } + Value::Object(obj) => { + let inner_regex = obj + .iter() + .map(|(key, value)| { + self.parse_const_value(value).map(|value_regex| { + format!(r#""{key}"{0}:{0}{value_regex}"#, self.whitespace_pattern) + }) + }) + .collect::>>()? + .join(format!("{0},{0}", self.whitespace_pattern).as_str()); + Ok(format!( + r"\{{{0}{inner_regex}{0}\}}", + self.whitespace_pattern + )) + } + _ => { + let json_string = serde_json::to_string(value)?; + Ok(regex::escape(&json_string)) + } } }