vdev/commands/build/component_docs/
schema_core.rs1use super::{SchemaContext, get_schema_ref, nested_merge};
2use anyhow::{Result, anyhow};
3use serde_json::Value;
4
5impl SchemaContext {
6 pub fn get_json_schema_instance_type<'a>(&self, schema: &'a Value) -> Option<&'a str> {
7 let maybe_type = schema.get("type")?;
8
9 if maybe_type.is_null() || maybe_type.as_str() == Some("null") {
10 return None;
11 }
12
13 if let Value::Array(arr) = maybe_type {
14 let filtered: Vec<_> = arr.iter().filter(|v| v.as_str() != Some("null")).collect();
15 if filtered.len() == 1 {
16 return filtered[0].as_str();
17 }
18 } else if let Some(s) = maybe_type.as_str() {
19 return Some(s);
20 }
21
22 None
23 }
24
25 pub fn get_json_schema_type<'a>(&self, schema: &'a Value) -> Option<&'a str> {
26 if schema.get("allOf").is_some() {
27 Some("all-of")
28 } else if schema.get("oneOf").is_some() {
29 Some("one-of")
30 } else if schema.get("anyOf").is_some() {
31 Some("any-of")
32 } else if schema.get("type").is_some() {
33 self.get_json_schema_instance_type(schema)
34 } else if schema.get("const").is_some() {
35 Some("const")
36 } else if schema.get("enum").is_some() {
37 Some("enum")
38 } else {
39 None
40 }
41 }
42
43 pub fn get_schema_by_name(&self, schema_name: &str) -> Result<Value> {
44 let name = schema_name.replace("#/definitions/", "");
45 let def = self
46 .root_schema
47 .get("definitions")
48 .and_then(|defs| defs.get(&name))
49 .cloned();
50
51 if let Some(d) = def {
52 Ok(d)
53 } else {
54 Err(anyhow!(
55 "Could not find schema definition '{name}' in given schema."
56 ))
57 }
58 }
59
60 pub fn expand_schema_references(&mut self, unexpanded_schema: &Value) -> Result<Value> {
61 let mut schema = unexpanded_schema.clone();
62
63 let original_title = schema.get("title").cloned();
64 let original_description = schema.get("description").cloned();
65
66 let schema_ref = get_schema_ref(&schema).map(String::from);
67 if let Some(r) = schema_ref {
68 let expanded_ref = if let Some(cached) = self.expanded_schema_cache.get(&r) {
69 cached.clone()
70 } else {
71 debug!("Expanding top-level schema ref of '{}'...", r);
72 let unexpanded = self.get_schema_by_name(&r)?;
73 let expanded = self.expand_schema_references(&unexpanded)?;
74 self.expanded_schema_cache
75 .insert(r.clone(), expanded.clone());
76 expanded
77 };
78
79 let obj = schema.as_object_mut().unwrap();
80 obj.shift_remove("$ref");
81
82 let mut new_schema = expanded_ref.clone();
83 nested_merge(&mut new_schema, &Value::Object(obj.clone()));
84 schema = new_schema;
85 }
86
87 if let Some(items) = schema.get("items").cloned()
88 && items.get("$ref").is_some()
89 {
90 let expanded_items = self.expand_schema_references(&items)?;
91 let items_mut = schema.get_mut("items").unwrap().as_object_mut().unwrap();
92 items_mut.shift_remove("$ref");
93
94 let mut new_items = expanded_items;
95 nested_merge(&mut new_items, &Value::Object(items_mut.clone()));
96 *schema.get_mut("items").unwrap() = new_items;
97 }
98
99 if let Some(Value::Object(properties)) = schema.get_mut("properties") {
100 for (_, prop_schema) in properties.iter_mut() {
101 *prop_schema = self.expand_schema_references(&prop_schema.clone())?;
102 }
103 }
104
105 for key in &["allOf", "oneOf", "anyOf"] {
106 if let Some(Value::Array(arr)) = schema.get_mut(*key) {
107 let mut new_arr = Vec::new();
108 for subschema in arr.iter() {
109 new_arr.push(self.expand_schema_references(subschema)?);
110 }
111 *arr = new_arr;
112 }
113 }
114
115 if original_title.is_some() || original_description.is_some() {
116 let obj = schema.as_object_mut().unwrap();
117 if let Some(t) = original_title {
118 obj.insert("title".to_string(), t);
119 } else {
120 obj.shift_remove("title");
121 }
122 if let Some(d) = original_description {
123 obj.insert("description".to_string(), d);
124 } else {
125 obj.shift_remove("description");
126 }
127 }
128
129 Ok(schema)
130 }
131}