1use okapi::openapi3::{Components, OpenApi, SchemaObject};
2use okapi::schemars::schema::{InstanceType, Schema, SingleOrVec};
3use serde_json::{json, Value};
4use std::collections::HashMap;
5
6pub const REF_OBJECT: &str = "\u{0}\u{0}\u{0}\u{0}";
7
8fn recurse_fix(mut v: &mut Value) {
9 match &mut v {
10 Value::Array(array) => {
11 for item in array {
12 recurse_fix(item);
13 }
14 }
15 Value::Object(obj) => {
16 for item in obj.iter_mut() {
17 recurse_fix(item.1);
18 }
19
20 if !obj.contains_key("examples") {
21 if let Some(ex) = obj.get("example").cloned() {
22 obj.insert("examples".to_string(), Value::Array(vec![ex]));
23 }
24 }
25 }
26
27 _ => {}
28 }
29}
30
31pub fn parse_schema_fix_example_issue(file_content: &str) -> OpenApi {
35 let mut root = serde_yaml::from_str::<Value>(file_content)
36 .expect("Failed to parse OpenAPI document as YAML document!");
37
38 if let Value::Object(root_obj) = &mut root {
39 if let Some(components) = root_obj.get_mut("components") {
40 recurse_fix(components);
41 }
42 }
43
44 parse_schema(&serde_yaml::to_string(&root).unwrap())
45}
46
47pub fn parse_schema(file_content: &str) -> OpenApi {
49 let schema = serde_yaml::from_str::<OpenApi>(file_content).expect("Failed to parse document");
50
51 if schema.components.is_none() {
52 log::error!("components is missing!");
53 panic!()
54 }
55
56 schema
57}
58
59fn expect_single<E>(e: &SingleOrVec<E>) -> &E {
60 match e {
61 SingleOrVec::Single(e) => e,
62 SingleOrVec::Vec(v) => &v[0],
63 }
64}
65
66fn expect_schema_object(s: &Schema) -> &SchemaObject {
67 match s {
68 Schema::Bool(_) => {
69 panic!("Got unexpected bool!");
70 }
71 Schema::Object(o) => o,
72 }
73}
74
75#[derive(Debug, Clone, serde::Serialize)]
77pub struct ObjectChild {
78 pub name: String,
80 pub node: TreeNode,
82}
83
84#[derive(Debug, Clone, serde::Serialize)]
86#[serde(tag = "type")]
87pub enum NodeType {
88 Null,
90 Boolean,
92 Array {
94 item: Box<TreeNode>,
96 },
97 Object {
99 required: Option<Vec<String>>,
101 children: Vec<ObjectChild>,
103 },
104 String,
106 Number,
108 Integer,
110}
111
112impl NodeType {
113 pub fn can_have_children(&self) -> bool {
115 matches!(self, NodeType::Object { .. } | NodeType::Array { .. })
116 }
117
118 pub fn symbol(&self) -> &'static str {
120 match self {
121 NodeType::Null => "NULL",
122 NodeType::Boolean => "Bool",
123 NodeType::Array { .. } => "[]",
124 NodeType::Object { .. } => "{}",
125 NodeType::String => "str",
126 NodeType::Number => "num",
127 NodeType::Integer => "int",
128 }
129 }
130}
131
132#[derive(Debug, Clone, serde::Serialize)]
134pub struct TreeNode {
135 pub name: String,
137 #[serde(flatten)]
139 pub r#type: NodeType,
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub description: Option<String>,
143 #[serde(skip_serializing_if = "Vec::is_empty")]
145 pub examples: Vec<String>,
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub r#enum: Option<Vec<String>>,
149}
150
151impl TreeNode {
152 pub fn print_name(&self) -> String {
155 format!("{} {}", self.name, self.r#type.symbol())
156 }
157
158 pub fn merge_with(self, other: Self) -> Self {
160 if !matches!(self.r#type, NodeType::String | NodeType::Object { .. }) {
161 panic!("Cannot merge!");
162 }
163
164 if !matches!(other.r#type, NodeType::String | NodeType::Object { .. }) {
165 panic!("Cannot merge other!");
166 }
167
168 let r#type = match (self.r#type, other.r#type) {
169 (NodeType::String, NodeType::String) => NodeType::String,
170 (NodeType::String, NodeType::Object { children, required })
171 | (NodeType::Object { children, required }, NodeType::String) => {
172 NodeType::Object { children, required }
173 }
174
175 (
176 NodeType::Object {
177 children: c1,
178 required: r1,
179 },
180 NodeType::Object {
181 children: mut c2,
182 required: r2,
183 },
184 ) => {
185 let mut children = c1;
186 children.append(&mut c2);
187
188 let mut required = r1.unwrap_or_default();
189 required.append(&mut r2.unwrap_or_default());
190
191 NodeType::Object {
192 children,
193 required: match required.is_empty() {
194 true => None,
195 false => Some(required),
196 },
197 }
198 }
199
200 (_, _) => unreachable!(),
201 };
202
203 TreeNode {
204 name: self.name.to_string(),
205 r#type,
206 description: other.description.or(self.description),
207 examples: match other.examples.is_empty() {
208 true => self.examples,
209 false => other.examples,
210 },
211 r#enum: other.r#enum.or(self.r#enum),
212 }
213 }
214
215 pub fn example_value(&self, max_recursion: usize) -> Value {
217 match &self.r#type {
218 NodeType::Null => Value::Null,
219 NodeType::Boolean => {
220 Value::Bool(self.examples.first().map(|e| e == "true").unwrap_or(false))
221 }
222
223 NodeType::Array { item } => Value::Array(vec![item.example_value(max_recursion)]),
224
225 NodeType::Object { children, .. } => {
226 if max_recursion == 0 {
227 return json!(HashMap::from([(REF_OBJECT.to_string(), &self.name)]));
228 }
229
230 json!(children
231 .iter()
232 .map(|c| (c.name.clone(), c.node.example_value(max_recursion - 1)))
233 .collect::<HashMap<String, serde_json::Value>>())
234 }
235
236 NodeType::String => Value::String(
237 self.examples
238 .first()
239 .map(|s| s.as_str().trim_matches('"'))
240 .unwrap_or("string")
241 .to_string(),
242 ),
243 NodeType::Number => serde_json::json!(self
244 .examples
245 .first()
246 .map(|s| s.parse::<f64>().expect("Failed to parse f64"))
247 .unwrap_or(1.)),
248 NodeType::Integer => serde_json::json!(self
249 .examples
250 .first()
251 .map(|s| s.parse::<u64>().expect("Failed to parse f64"))
252 .unwrap_or(0)),
253 }
254 }
255
256 pub fn json_schema(&self) -> Value {
258 valico::json_schema::builder::schema(|s| self.json_schema_inner(s)).into_json()
259 }
260
261 fn json_schema_inner(&self, builder: &mut valico::json_schema::builder::Builder) {
262 if let Some(description) = &self.description {
263 builder.desc(description);
264 }
265
266 match &self.r#type {
267 NodeType::Null => {
268 builder.null();
269 }
270 NodeType::Boolean => {
271 builder.boolean();
272 }
273
274 NodeType::Array { item } => {
275 builder.array();
276 builder.items_schema(|b| Self::json_schema_inner(item, b));
277 }
278
279 NodeType::Object { children, required } => {
280 if let Some(required) = required {
281 builder.required(required.clone());
282 }
283
284 builder.properties(|properties| {
285 for child in children {
286 properties.insert(&child.name, |child_prop| {
287 Self::json_schema_inner(&child.node, child_prop);
288 });
289 }
290 });
291 }
292
293 NodeType::String => {
294 builder.string();
295 }
296 NodeType::Number => {
297 builder.number();
298 }
299 NodeType::Integer => {
300 builder.integer();
301 }
302 }
303 }
304}
305
306pub fn build_tree(struct_name: &str, components: &Components) -> TreeNode {
308 let schema = components
309 .schemas
310 .get(struct_name)
311 .unwrap_or_else(|| panic!("Missing {struct_name}"));
312
313 build_tree_schema(schema, struct_name, components)
314}
315
316fn build_tree_schema(
318 schema: &SchemaObject,
319 struct_name: &str,
320 components: &Components,
321) -> TreeNode {
322 if let Some(name) = &schema.reference {
323 return build_tree(
324 name.strip_prefix("#/components/schemas/").unwrap(),
325 components,
326 );
327 }
328
329 if let Some(subschemas) = &schema.subschemas {
330 if let Some(all_of) = &subschemas.all_of {
331 assert!(!all_of.is_empty());
332 let mut tree =
333 build_tree_schema(expect_schema_object(&all_of[0]), struct_name, components);
334
335 for other in all_of.iter().skip(1) {
336 let other = build_tree_schema(expect_schema_object(other), struct_name, components);
337 tree = tree.merge_with(other);
338 }
339
340 tree.name = struct_name.to_string();
341 return tree;
342 } else {
343 panic!("Unsupported case!");
344 }
345 }
346
347 let schema_type = schema
348 .instance_type
349 .as_ref()
350 .map(expect_single)
351 .unwrap_or(&InstanceType::String);
352
353 let r#type = match schema_type {
354 InstanceType::Null => NodeType::Null,
355 InstanceType::Boolean => NodeType::Boolean,
356 InstanceType::Object => {
357 let object = schema.object.as_ref();
358 let children = object
359 .map(|s| s.properties.clone())
360 .unwrap_or_default()
361 .iter()
362 .map(|e| {
363 let o = expect_schema_object(e.1);
364 ObjectChild {
365 name: e.0.to_string(),
366 node: build_tree_schema(o, e.0, components),
367 }
368 })
369 .collect::<Vec<_>>();
370
371 let required = object
372 .as_ref()
373 .map(|o| &o.required)
374 .map(|r| r.iter().map(|s| s.to_string()).collect());
375
376 NodeType::Object { children, required }
377 }
378 InstanceType::Array => {
379 let item = expect_schema_object(expect_single(
380 schema.array.as_ref().unwrap().items.as_ref().unwrap(),
381 ));
382 NodeType::Array {
383 item: Box::new(build_tree_schema(
384 item,
385 &format!("{struct_name}[]"),
386 components,
387 )),
388 }
389 }
390 InstanceType::Number => NodeType::Number,
391 InstanceType::String => NodeType::String,
392 InstanceType::Integer => NodeType::Integer,
393 };
394
395 let metadata = schema.metadata.clone().unwrap_or_default();
396
397 TreeNode {
398 name: struct_name.to_string(),
399 r#type,
400 description: metadata.description,
401 examples: metadata
402 .examples
403 .iter()
404 .map(|v| v.to_string())
405 .collect::<Vec<_>>(),
406 r#enum: schema
407 .enum_values
408 .as_ref()
409 .map(|v| v.iter().map(|v| v.to_string()).collect()),
410 }
411}