Use const instead of single-valued enum (#291)

This commit is contained in:
Graham Esau 2024-05-13 21:30:51 +01:00 committed by GitHub
parent 8c2c32bce0
commit 18300c67bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 61 additions and 131 deletions

View file

@ -53,17 +53,16 @@ impl<T: Serialize> MaybeSerializeWrapper<T> {
} }
} }
/// Create a schema for a unit enum /// Create a schema for a unit enum variant
pub fn new_unit_enum(variant: &str) -> Schema { pub fn new_unit_enum_variant(variant: &str) -> Schema {
// TODO switch from single-valued "enum" to "const"
json_schema!({ json_schema!({
"type": "string", "type": "string",
"enum": [variant], "const": variant,
}) })
} }
/// Create a schema for an externally tagged enum /// Create a schema for an externally tagged enum variant
pub fn new_externally_tagged_enum(variant: &str, sub_schema: Schema) -> Schema { pub fn new_externally_tagged_enum_variant(variant: &str, sub_schema: Schema) -> Schema {
json_schema!({ json_schema!({
"type": "object", "type": "object",
"properties": { "properties": {
@ -74,7 +73,8 @@ pub fn new_externally_tagged_enum(variant: &str, sub_schema: Schema) -> Schema {
}) })
} }
pub fn apply_internal_enum_tag( /// Update a schema for an internally tagged enum variant
pub fn apply_internal_enum_variant_tag(
schema: &mut Schema, schema: &mut Schema,
tag_name: &str, tag_name: &str,
variant: &str, variant: &str,
@ -94,8 +94,7 @@ pub fn apply_internal_enum_tag(
tag_name.to_string(), tag_name.to_string(),
json!({ json!({
"type": "string", "type": "string",
// TODO switch from single-valued "enum" to "const" "const": variant
"enum": [variant]
}), }),
); );
} }
@ -113,34 +112,6 @@ pub fn apply_internal_enum_tag(
} }
} }
/// Create a schema for an internally tagged enum
pub fn new_internally_tagged_enum(
tag_name: &str,
variant: &str,
deny_unknown_fields: bool,
) -> Schema {
// TODO switch from single-valued "enum" to "const"
let mut schema = json_schema!({
"type": "object",
"properties": {
tag_name: {
"type": "string",
"enum": [variant],
}
},
"required": [tag_name],
});
if deny_unknown_fields {
schema
.as_object_mut()
.unwrap()
.insert("additionalProperties".into(), false.into());
}
schema
}
pub fn insert_object_property<T: ?Sized + JsonSchema>( pub fn insert_object_property<T: ?Sized + JsonSchema>(
schema: &mut Schema, schema: &mut Schema,
key: &str, key: &str,

View file

@ -97,6 +97,7 @@ impl SchemaSettings {
skip_additional_properties: true, skip_additional_properties: true,
}), }),
Box::new(SetSingleExample), Box::new(SetSingleExample),
Box::new(ReplaceConstValue),
], ],
inline_subschemas: false, inline_subschemas: false,
} }

View file

@ -169,3 +169,21 @@ impl Visitor for SetSingleExample {
} }
} }
} }
/// This visitor will replace the `const` schema property with a single-valued `enum` property.
///
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `const` property.
#[derive(Debug, Clone)]
pub struct ReplaceConstValue;
impl Visitor for ReplaceConstValue {
fn visit_schema(&mut self, schema: &mut Schema) {
visit_schema(self, schema);
if let Some(obj) = schema.as_object_mut() {
if let Some(value) = obj.remove("const") {
obj.insert("enum".into(), Value::Array(vec![value]));
}
}
}
}

View file

@ -11,10 +11,8 @@
}, },
{ {
"type": "string", "type": "string",
"deprecated": true, "const": "DeprecatedUnitVariant",
"enum": [ "deprecated": true
"DeprecatedUnitVariant"
]
}, },
{ {
"type": "object", "type": "object",

View file

@ -13,9 +13,7 @@
{ {
"description": "This comment is included in the generated schema :)", "description": "This comment is included in the generated schema :)",
"type": "string", "type": "string",
"enum": [ "const": "DocumentedUnit"
"DocumentedUnit"
]
}, },
{ {
"title": "Complex variant", "title": "Complex variant",

View file

@ -7,9 +7,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "UnitOne"
"UnitOne"
]
} }
}, },
"additionalProperties": false, "additionalProperties": false,
@ -22,9 +20,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "StringMap"
"StringMap"
]
} }
}, },
"additionalProperties": { "additionalProperties": {
@ -39,9 +35,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "UnitStructNewType"
"UnitStructNewType"
]
} }
}, },
"additionalProperties": false, "additionalProperties": false,
@ -61,9 +55,7 @@
}, },
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "StructNewType"
"StructNewType"
]
} }
}, },
"required": [ "required": [
@ -84,9 +76,7 @@
}, },
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "Struct"
"Struct"
]
} }
}, },
"additionalProperties": false, "additionalProperties": false,
@ -101,9 +91,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "UnitTwo"
"UnitTwo"
]
} }
}, },
"additionalProperties": false, "additionalProperties": false,
@ -117,9 +105,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "WithInt"
"WithInt"
]
} }
}, },
"required": [ "required": [

View file

@ -7,9 +7,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "UnitOne"
"UnitOne"
]
} }
}, },
"required": [ "required": [
@ -21,9 +19,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "StringMap"
"StringMap"
]
} }
}, },
"additionalProperties": { "additionalProperties": {
@ -38,9 +34,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "UnitStructNewType"
"UnitStructNewType"
]
} }
}, },
"required": [ "required": [
@ -59,9 +53,7 @@
}, },
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "StructNewType"
"StructNewType"
]
} }
}, },
"required": [ "required": [
@ -82,9 +74,7 @@
}, },
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "Struct"
"Struct"
]
} }
}, },
"required": [ "required": [
@ -98,9 +88,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "UnitTwo"
"UnitTwo"
]
} }
}, },
"required": [ "required": [
@ -113,9 +101,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "WithInt"
"WithInt"
]
} }
}, },
"required": [ "required": [

View file

@ -7,9 +7,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "A"
"A"
]
} }
}, },
"additionalProperties": false, "additionalProperties": false,
@ -22,9 +20,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "B"
"B"
]
} }
}, },
"additionalProperties": false, "additionalProperties": false,
@ -37,9 +33,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "C"
"C"
]
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View file

@ -7,9 +7,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "A"
"A"
]
} }
}, },
"required": [ "required": [
@ -21,9 +19,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "B"
"B"
]
} }
}, },
"required": [ "required": [
@ -35,9 +31,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "C"
"C"
]
} }
}, },
"required": [ "required": [

View file

@ -6,23 +6,17 @@
"title": "A deer", "title": "A deer",
"description": "A female deer", "description": "A female deer",
"type": "string", "type": "string",
"enum": [ "const": "Do"
"Do"
]
}, },
{ {
"description": "A drop of golden sun", "description": "A drop of golden sun",
"type": "string", "type": "string",
"enum": [ "const": "Re"
"Re"
]
}, },
{ {
"description": "A name I call myself", "description": "A name I call myself",
"type": "string", "type": "string",
"enum": [ "const": "Mi"
"Mi"
]
} }
] ]
} }

View file

@ -45,9 +45,7 @@
{ {
"description": "This is a documented unit variant", "description": "This is a documented unit variant",
"type": "string", "type": "string",
"enum": [ "const": "DocumentedUnit"
"DocumentedUnit"
]
}, },
{ {
"type": "object", "type": "object",

View file

@ -45,9 +45,7 @@
{ {
"description": "This is a documented unit variant", "description": "This is a documented unit variant",
"type": "string", "type": "string",
"enum": [ "const": "DocumentedUnit"
"DocumentedUnit"
]
}, },
{ {
"type": "object", "type": "object",

View file

@ -10,9 +10,7 @@
}, },
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "Struct"
"Struct"
]
} }
}, },
"required": [ "required": [
@ -25,9 +23,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "NewType"
"NewType"
]
} }
}, },
"required": [ "required": [
@ -39,9 +35,7 @@
"properties": { "properties": {
"typeProperty": { "typeProperty": {
"type": "string", "type": "string",
"enum": [ "const": "Unit"
"Unit"
]
} }
}, },
"required": [ "required": [

View file

@ -197,12 +197,12 @@ fn expr_for_external_tagged_enum<'a>(
let mut schema_expr = if variant.is_unit() && variant.attrs.with.is_none() { let mut schema_expr = if variant.is_unit() && variant.attrs.with.is_none() {
quote! { quote! {
schemars::_private::new_unit_enum(#name) schemars::_private::new_unit_enum_variant(#name)
} }
} else { } else {
let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields); let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
quote! { quote! {
schemars::_private::new_externally_tagged_enum(#name, #sub_schema) schemars::_private::new_externally_tagged_enum_variant(#name, #sub_schema)
} }
}; };
@ -236,7 +236,7 @@ fn expr_for_internal_tagged_enum<'a>(
quote!({ quote!({
let mut schema = #schema_expr; let mut schema = #schema_expr;
schemars::_private::apply_internal_enum_tag(&mut schema, #tag_name, #name, #deny_unknown_fields); schemars::_private::apply_internal_enum_variant_tag(&mut schema, #tag_name, #name, #deny_unknown_fields);
schema schema
}) })
}) })