schemars.rs

 1use schemars::{JsonSchema, transform::transform_subschemas};
 2
 3const DEFS_PATH: &str = "#/$defs/";
 4
 5/// Replaces the JSON schema definition for some type if it is in use (in the definitions list), and
 6/// returns a reference to it.
 7///
 8/// This asserts that JsonSchema::schema_name() + "2" does not exist because this indicates that
 9/// there are multiple types that use this name, and unfortunately schemars APIs do not support
10/// resolving this ambiguity - see https://github.com/GREsau/schemars/issues/449
11///
12/// This takes a closure for `schema` because some settings types are not available on the remote
13/// server, and so will crash when attempting to access e.g. GlobalThemeRegistry.
14pub fn replace_subschema<T: JsonSchema>(
15    generator: &mut schemars::SchemaGenerator,
16    schema: impl Fn() -> schemars::Schema,
17) -> schemars::Schema {
18    // fallback on just using the schema name, which could collide.
19    let schema_name = T::schema_name();
20    let definitions = generator.definitions_mut();
21    assert!(!definitions.contains_key(&format!("{schema_name}2")));
22    if definitions.contains_key(schema_name.as_ref()) {
23        definitions.insert(schema_name.to_string(), schema().to_value());
24    }
25    schemars::Schema::new_ref(format!("{DEFS_PATH}{schema_name}"))
26}
27
28/// Adds a new JSON schema definition and returns a reference to it. **Panics** if the name is
29/// already in use.
30pub fn add_new_subschema(
31    generator: &mut schemars::SchemaGenerator,
32    name: &str,
33    schema: serde_json::Value,
34) -> schemars::Schema {
35    let old_definition = generator.definitions_mut().insert(name.to_string(), schema);
36    assert_eq!(old_definition, None);
37    schemars::Schema::new_ref(format!("{DEFS_PATH}{name}"))
38}
39
40/// Defaults `additionalProperties` to `true`, as if `#[schemars(deny_unknown_fields)]` was on every
41/// struct. Skips structs that have `additionalProperties` set (such as if #[serde(flatten)] is used
42/// on a map).
43#[derive(Clone)]
44pub struct DefaultDenyUnknownFields;
45
46impl schemars::transform::Transform for DefaultDenyUnknownFields {
47    fn transform(&mut self, schema: &mut schemars::Schema) {
48        if let Some(object) = schema.as_object_mut() {
49            if object.contains_key("properties")
50                && !object.contains_key("additionalProperties")
51                && !object.contains_key("unevaluatedProperties")
52            {
53                object.insert("additionalProperties".to_string(), false.into());
54            }
55        }
56        transform_subschemas(self, schema);
57    }
58}