json_schema.rs

 1use schemars::schema::{
 2    ArrayValidation, InstanceType, RootSchema, Schema, SchemaObject, SingleOrVec,
 3};
 4use serde_json::Value;
 5
 6pub struct SettingsJsonSchemaParams<'a> {
 7    pub language_names: &'a [String],
 8    pub font_names: &'a [String],
 9}
10
11impl SettingsJsonSchemaParams<'_> {
12    pub fn font_family_schema(&self) -> Schema {
13        let available_fonts: Vec<_> = self.font_names.iter().cloned().map(Value::String).collect();
14
15        SchemaObject {
16            instance_type: Some(InstanceType::String.into()),
17            enum_values: Some(available_fonts),
18            ..Default::default()
19        }
20        .into()
21    }
22
23    pub fn font_fallback_schema(&self) -> Schema {
24        SchemaObject {
25            instance_type: Some(SingleOrVec::Vec(vec![
26                InstanceType::Array,
27                InstanceType::Null,
28            ])),
29            array: Some(Box::new(ArrayValidation {
30                items: Some(schemars::schema::SingleOrVec::Single(Box::new(
31                    self.font_family_schema(),
32                ))),
33                unique_items: Some(true),
34                ..Default::default()
35            })),
36            ..Default::default()
37        }
38        .into()
39    }
40}
41
42type PropertyName<'a> = &'a str;
43type ReferencePath<'a> = &'a str;
44
45/// Modifies the provided [`RootSchema`] by adding references to all of the specified properties.
46///
47/// # Examples
48///
49/// ```
50/// # let root_schema = RootSchema::default();
51/// add_references_to_properties(&mut root_schema, &[
52///     ("property_a", "#/definitions/DefinitionA"),
53///     ("property_b", "#/definitions/DefinitionB"),
54/// ])
55/// ```
56pub fn add_references_to_properties(
57    root_schema: &mut RootSchema,
58    properties_with_references: &[(PropertyName, ReferencePath)],
59) {
60    for (property, definition) in properties_with_references {
61        let Some(schema) = root_schema.schema.object().properties.get_mut(*property) else {
62            log::warn!("property '{property}' not found in JSON schema");
63            continue;
64        };
65
66        match schema {
67            Schema::Object(schema) => {
68                schema.reference = Some(definition.to_string());
69            }
70            Schema::Bool(_) => {
71                // Boolean schemas can't have references.
72            }
73        }
74    }
75}