Fix handling of attributes applied to unit variant types (#152)

This commit is contained in:
Adam Leventhal 2022-08-12 07:37:34 -07:00 committed by GitHub
parent 9464118c3a
commit 76427ef384
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 109 additions and 28 deletions

View file

@ -31,7 +31,8 @@ struct MyUnitStruct;
#[doc = " the enum's description."] #[doc = " the enum's description."]
enum MyEnum { enum MyEnum {
UndocumentedUnit, UndocumentedUnit,
/// This comment is not included in the generated schema :( UndocumentedUnit2,
/// This comment is included in the generated schema :)
DocumentedUnit, DocumentedUnit,
/// ## Complex variant /// ## Complex variant
/// This is a struct-like variant. /// This is a struct-like variant.

View file

@ -118,3 +118,21 @@ enum SimpleInternal {
fn enum_simple_internal_tag() -> TestResult { fn enum_simple_internal_tag() -> TestResult {
test_default_generated_schema::<SimpleInternal>("enum-simple-internal") test_default_generated_schema::<SimpleInternal>("enum-simple-internal")
} }
#[allow(dead_code)]
#[derive(JsonSchema)]
enum SoundOfMusic {
/// # A deer
///
/// A female deer
Do,
/// A drop of golden sun
Re,
/// A name I call myself
Mi,
}
#[test]
fn enum_unit_with_doc_comments() -> TestResult {
test_default_generated_schema::<SoundOfMusic>("enum-unit-doc")
}

View file

@ -6,7 +6,13 @@
{ {
"type": "string", "type": "string",
"enum": [ "enum": [
"Unit", "Unit"
]
},
{
"deprecated": true,
"type": "string",
"enum": [
"DeprecatedUnitVariant" "DeprecatedUnitVariant"
] ]
}, },

View file

@ -7,6 +7,13 @@
"type": "string", "type": "string",
"enum": [ "enum": [
"UndocumentedUnit", "UndocumentedUnit",
"UndocumentedUnit2"
]
},
{
"description": "This comment is included in the generated schema :)",
"type": "string",
"enum": [
"DocumentedUnit" "DocumentedUnit"
] ]
}, },

View file

@ -0,0 +1,28 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SoundOfMusic",
"oneOf": [
{
"title": "A deer",
"description": "A female deer",
"type": "string",
"enum": [
"Do"
]
},
{
"description": "A drop of golden sun",
"type": "string",
"enum": [
"Re"
]
},
{
"description": "A name I call myself",
"type": "string",
"enum": [
"Mi"
]
}
]
}

View file

@ -185,6 +185,21 @@ impl Attrs {
} }
self self
} }
pub fn is_default(&self) -> bool {
match self {
Self {
with: None,
title: None,
description: None,
deprecated: false,
examples,
repr: None,
crate_name: None,
} if examples.is_empty() => true,
_ => false,
}
}
} }
fn is_known_serde_or_validation_keyword(meta: &syn::Meta) -> bool { fn is_known_serde_or_validation_keyword(meta: &syn::Meta) -> bool {

View file

@ -149,8 +149,7 @@ fn expr_for_external_tagged_enum<'a>(
unique_names.insert(v.name()); unique_names.insert(v.name());
count += 1; count += 1;
}) })
.partition(|v| v.is_unit() && v.attrs.with.is_none()); .partition(|v| v.is_unit() && v.attrs.is_default());
let unit_names = unit_variants.iter().map(|v| v.name()); let unit_names = unit_variants.iter().map(|v| v.name());
let unit_schema = schema_object(quote! { let unit_schema = schema_object(quote! {
instance_type: Some(schemars::schema::InstanceType::String.into()), instance_type: Some(schemars::schema::InstanceType::String.into()),
@ -168,31 +167,38 @@ fn expr_for_external_tagged_enum<'a>(
schemas.extend(complex_variants.into_iter().map(|variant| { schemas.extend(complex_variants.into_iter().map(|variant| {
let name = variant.name(); let name = variant.name();
let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
let mut schema_expr = schema_object(quote! { let mut schema_expr = if variant.is_unit() && variant.attrs.with.is_none() {
instance_type: Some(schemars::schema::InstanceType::Object.into()), schema_object(quote! {
object: Some(Box::new(schemars::schema::ObjectValidation { instance_type: Some(schemars::schema::InstanceType::String.into()),
properties: { enum_values: Some(vec![#name.into()]),
let mut props = schemars::Map::new(); })
props.insert(#name.to_owned(), #sub_schema); } else {
props let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
}, schema_object(quote! {
required: { instance_type: Some(schemars::schema::InstanceType::Object.into()),
let mut required = schemars::Set::new(); object: Some(Box::new(schemars::schema::ObjectValidation {
required.insert(#name.to_owned()); properties: {
required let mut props = schemars::Map::new();
}, props.insert(#name.to_owned(), #sub_schema);
// Externally tagged variants must prohibit additional props
// properties irrespective of the disposition of },
// `deny_unknown_fields`. If additional properties were allowed required: {
// one could easily construct an object that validated against let mut required = schemars::Set::new();
// multiple variants since here it's the properties rather than required.insert(#name.to_owned());
// the values of a property that distingish between variants. required
additional_properties: Some(Box::new(false.into())), },
..Default::default() // Externally tagged variants must prohibit additional
})), // properties irrespective of the disposition of
}); // `deny_unknown_fields`. If additional properties were allowed
// one could easily construct an object that validated against
// multiple variants since here it's the properties rather than
// the values of a property that distingish between variants.
additional_properties: Some(Box::new(false.into())),
..Default::default()
})),
})
};
variant variant
.attrs .attrs