use schemars::generate::SchemaSettings;
use schemars::transform::RecursiveTransform;
use schemars::{JsonSchema, Schema};
use serde_json::Value;
pub fn args_schema<A: JsonSchema>() -> Value {
let mut settings = SchemaSettings::draft2020_12().with_transform(RecursiveTransform(plain));
settings.inline_subschemas = true;
settings.meta_schema = None;
let mut schema = settings.into_generator().into_root_schema_for::<A>();
if let Some(root) = schema.as_object_mut() {
root.shift_remove("description");
}
schema.to_value()
}
fn plain(schema: &mut Schema) {
let Some(schema) = schema.as_object_mut() else {
return;
};
if let Some(Value::Array(alternatives)) = schema.get_mut("anyOf") {
let null = serde_json::json!({"type": "null"});
let before = alternatives.len();
alternatives.retain(|alternative| *alternative != null);
if let [Value::Object(only)] = alternatives.as_slice()
&& before > 1
{
let only = only.clone();
schema.shift_remove("anyOf");
for (key, value) in only {
schema.entry(key).or_insert(value);
}
}
}
if let Some(Value::String(text)) = schema.get_mut("description") {
let paragraphs: Vec<String> = text.split("\n\n").map(|p| p.replace('\n', " ")).collect();
*text = paragraphs.join("\n\n");
}
for key in ["title", "default", "format"] {
schema.shift_remove(key);
}
if schema.contains_key("properties") && !schema.contains_key("additionalProperties") {
schema.insert("additionalProperties".to_owned(), Value::Bool(false));
}
if let Some(Value::Array(types)) = schema.get_mut("type")
&& types.iter().any(|kind| kind == "null")
{
types.retain(|kind| kind != "null");
if let [kind] = types.as_slice() {
let kind = kind.clone();
schema.insert("type".to_owned(), kind);
}
if let Some(Value::Array(values)) = schema.get_mut("enum") {
values.retain(|value| !value.is_null());
}
}
}