1use crate::json_utils::remove_preserving_order;
22use schemars::generate::SchemaSettings;
23use schemars::transform::RecursiveTransform;
24use schemars::{JsonSchema, Schema};
25use serde_json::Value;
26
27pub fn args_schema<A: JsonSchema>() -> Value {
35 let mut settings = SchemaSettings::draft2020_12().with_transform(RecursiveTransform(plain));
36 settings.inline_subschemas = true;
37 settings.meta_schema = None;
38 let mut schema = settings.into_generator().into_root_schema_for::<A>();
39 if let Some(root) = schema.as_object_mut() {
40 remove_preserving_order(root, "description");
41 }
42 schema.to_value()
43}
44
45fn plain(schema: &mut Schema) {
51 let Some(schema) = schema.as_object_mut() else {
52 return;
53 };
54 if let Some(Value::Array(alternatives)) = schema.get_mut("anyOf") {
55 let null = serde_json::json!({"type": "null"});
56 let before = alternatives.len();
57 alternatives.retain(|alternative| *alternative != null);
58 if let [Value::Object(only)] = alternatives.as_slice()
59 && before > 1
60 {
61 let only = only.clone();
62 remove_preserving_order(schema, "anyOf");
63 for (key, value) in only {
64 schema.entry(key).or_insert(value);
65 }
66 }
67 }
68 if let Some(Value::String(text)) = schema.get_mut("description") {
69 let paragraphs: Vec<String> = text.split("\n\n").map(|p| p.replace('\n', " ")).collect();
70 *text = paragraphs.join("\n\n");
71 }
72 for key in ["title", "default", "format"] {
73 remove_preserving_order(schema, key);
74 }
75 if schema.contains_key("properties") && !schema.contains_key("additionalProperties") {
76 schema.insert("additionalProperties".to_owned(), Value::Bool(false));
77 }
78 if let Some(Value::Array(types)) = schema.get_mut("type")
79 && types.iter().any(|kind| kind == "null")
80 {
81 types.retain(|kind| kind != "null");
82 if let [kind] = types.as_slice() {
83 let kind = kind.clone();
84 schema.insert("type".to_owned(), kind);
85 }
86 if let Some(Value::Array(values)) = schema.get_mut("enum") {
87 values.retain(|value| !value.is_null());
88 }
89 }
90}