1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use std::collections::HashSet;
use schemars::transform::{transform_subschemas, Transform};
use schemars::Schema;
use serde_json::Value;
pub struct OpenAiTransform;
impl Transform for OpenAiTransform {
fn transform(&mut self, schema: &mut Schema) {
if let Some(obj) = schema.as_object_mut() {
if obj.get("$ref").is_none() {
// Only add additionalProperties to object-type schemas
let is_object = obj
.get("type")
.and_then(|v| v.as_str())
.map(|t| t == "object")
.unwrap_or(false)
|| obj.contains_key("properties");
if is_object {
obj.insert("additionalProperties".to_string(), Value::Bool(false));
}
obj.remove("format");
obj.remove("minimum");
obj.remove("maximum");
// get all the items under "properties"
let properties = obj
.get("properties")
.and_then(|p| p.as_object())
.map(|obj| {
obj.keys()
.map(|k| Value::String(k.to_string()))
.collect::<Vec<_>>()
})
.unwrap_or_default()
.into_iter()
.collect::<HashSet<_>>();
// get the "required" array
let required = obj
.get("required")
.and_then(|r| r.as_array())
.cloned()
.unwrap_or_default()
.into_iter()
.collect::<HashSet<_>>();
if properties != required {
// add all the properties to the "required" array
let mut required_vec: Vec<Value> = properties.into_iter().collect();
// Sort for deterministic ordering
required_vec
.sort_by(|a, b| a.as_str().unwrap_or("").cmp(b.as_str().unwrap_or("")));
obj.insert("required".to_string(), Value::Array(required_vec));
} else {
// Even if properties == required, we need to ensure the array is sorted
if let Some(Value::Array(required_array)) = obj.get_mut("required") {
required_array
.sort_by(|a, b| a.as_str().unwrap_or("").cmp(b.as_str().unwrap_or("")));
}
}
}
// oneOf keys need to be replaced with anyOf
if let Some(one_of) = obj.get("oneOf") {
obj.insert("anyOf".to_string(), one_of.clone());
}
obj.remove("oneOf");
}
transform_subschemas(self, schema);
}
}