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