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}