diff --git a/src/lib.rs b/src/lib.rs index d759da9..63772ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,8 +34,13 @@ fn expect_schema_object(s: &Schema) -> &SchemaObject { pub enum NodeType { Null, Boolean, - Array { item: Box }, - Object { children: Vec }, + Array { + item: Box, + }, + Object { + required: Option>, + children: Vec, + }, String, Number, Integer, @@ -46,11 +51,17 @@ pub struct TreeNode { pub name: String, #[serde(flatten)] pub r#type: NodeType, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub examples: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub r#enum: Option>, } impl TreeNode { /// Merge two TreeNode - pub fn merge_with(&self, other: &Self) -> Self { + pub fn merge_with(self, other: Self) -> Self { if !matches!(self.r#type, NodeType::String | NodeType::Object { .. }) { panic!("Cannot merge!"); } @@ -59,17 +70,36 @@ impl TreeNode { panic!("Cannot merge other!"); } - let r#type = match (&self.r#type, &other.r#type) { + let r#type = match (self.r#type, other.r#type) { (NodeType::String, NodeType::String) => NodeType::String, - (NodeType::String, NodeType::Object { children }) - | (NodeType::Object { children }, NodeType::String) => NodeType::Object { - children: children.clone(), - }, + (NodeType::String, NodeType::Object { children, required }) + | (NodeType::Object { children, required }, NodeType::String) => { + NodeType::Object { children, required } + } - (NodeType::Object { children: c1 }, NodeType::Object { children: c2 }) => { - let mut children = c1.clone(); - children.append(&mut c2.clone()); - NodeType::Object { children } + ( + NodeType::Object { + children: c1, + required: r1, + }, + NodeType::Object { + children: mut c2, + required: r2, + }, + ) => { + let mut children = c1; + children.append(&mut c2); + + let mut required = r1.unwrap_or_default(); + required.append(&mut r2.unwrap_or_default()); + + NodeType::Object { + children, + required: match required.is_empty() { + true => None, + false => Some(required), + }, + } } (_, _) => unreachable!(), @@ -78,6 +108,12 @@ impl TreeNode { TreeNode { name: self.name.to_string(), r#type, + description: other.description.or(self.description), + examples: match other.examples.is_empty() { + true => self.examples, + false => other.examples, + }, + r#enum: other.r#enum.or(self.r#enum), } } } @@ -113,7 +149,7 @@ fn build_tree_schema( for other in all_of.iter().skip(1) { let other = build_tree_schema(expect_schema_object(other), struct_name, components); - tree = tree.merge_with(&other); + tree = tree.merge_with(other); } return tree; @@ -132,9 +168,8 @@ fn build_tree_schema( InstanceType::Null => NodeType::Null, InstanceType::Boolean => NodeType::Boolean, InstanceType::Object => { - let children = schema - .object - .as_ref() + let object = schema.object.as_ref(); + let children = object .map(|s| s.properties.clone()) .unwrap_or_default() .iter() @@ -143,7 +178,13 @@ fn build_tree_schema( build_tree_schema(o, e.0, components) }) .collect::>(); - NodeType::Object { children } + + let required = object + .as_ref() + .map(|o| &o.required) + .map(|r| r.iter().map(|s| s.to_string()).collect()); + + NodeType::Object { children, required } } InstanceType::Array => { let item = expect_schema_object(expect_single( @@ -162,8 +203,20 @@ fn build_tree_schema( InstanceType::Integer => NodeType::Integer, }; + let metadata = schema.metadata.clone().unwrap_or_default(); + TreeNode { name: struct_name.to_string(), r#type, + description: metadata.description, + examples: metadata + .examples + .iter() + .map(|v| v.to_string()) + .collect::>(), + r#enum: schema + .enum_values + .as_ref() + .map(|v| v.iter().map(|v| v.to_string()).collect()), } }