diff --git a/schemars/tests/docs.rs b/schemars/tests/docs.rs index 2f27771..788140d 100644 --- a/schemars/tests/docs.rs +++ b/schemars/tests/docs.rs @@ -31,7 +31,8 @@ struct MyUnitStruct; #[doc = " the enum's description."] enum MyEnum { UndocumentedUnit, - /// This comment is not included in the generated schema :( + UndocumentedUnit2, + /// This comment is included in the generated schema :) DocumentedUnit, /// ## Complex variant /// This is a struct-like variant. diff --git a/schemars/tests/enum.rs b/schemars/tests/enum.rs index 2bafefd..3f60e84 100644 --- a/schemars/tests/enum.rs +++ b/schemars/tests/enum.rs @@ -118,3 +118,21 @@ enum SimpleInternal { fn enum_simple_internal_tag() -> TestResult { test_default_generated_schema::("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::("enum-unit-doc") +} diff --git a/schemars/tests/expected/deprecated-enum.json b/schemars/tests/expected/deprecated-enum.json index 074310f..825ae50 100644 --- a/schemars/tests/expected/deprecated-enum.json +++ b/schemars/tests/expected/deprecated-enum.json @@ -6,7 +6,13 @@ { "type": "string", "enum": [ - "Unit", + "Unit" + ] + }, + { + "deprecated": true, + "type": "string", + "enum": [ "DeprecatedUnitVariant" ] }, diff --git a/schemars/tests/expected/doc_comments_enum.json b/schemars/tests/expected/doc_comments_enum.json index 0adc380..53aaa86 100644 --- a/schemars/tests/expected/doc_comments_enum.json +++ b/schemars/tests/expected/doc_comments_enum.json @@ -7,6 +7,13 @@ "type": "string", "enum": [ "UndocumentedUnit", + "UndocumentedUnit2" + ] + }, + { + "description": "This comment is included in the generated schema :)", + "type": "string", + "enum": [ "DocumentedUnit" ] }, diff --git a/schemars/tests/expected/enum-unit-doc.json b/schemars/tests/expected/enum-unit-doc.json new file mode 100644 index 0000000..11a5c2a --- /dev/null +++ b/schemars/tests/expected/enum-unit-doc.json @@ -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" + ] + } + ] +} \ No newline at end of file diff --git a/schemars_derive/src/attr/mod.rs b/schemars_derive/src/attr/mod.rs index b1b9f04..3fad9e4 100644 --- a/schemars_derive/src/attr/mod.rs +++ b/schemars_derive/src/attr/mod.rs @@ -185,6 +185,21 @@ impl Attrs { } 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 { diff --git a/schemars_derive/src/schema_exprs.rs b/schemars_derive/src/schema_exprs.rs index c5b1672..1f55084 100644 --- a/schemars_derive/src/schema_exprs.rs +++ b/schemars_derive/src/schema_exprs.rs @@ -149,8 +149,7 @@ fn expr_for_external_tagged_enum<'a>( unique_names.insert(v.name()); 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_schema = schema_object(quote! { 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| { let name = variant.name(); - let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields); - let mut schema_expr = schema_object(quote! { - instance_type: Some(schemars::schema::InstanceType::Object.into()), - object: Some(Box::new(schemars::schema::ObjectValidation { - properties: { - let mut props = schemars::Map::new(); - props.insert(#name.to_owned(), #sub_schema); - props - }, - required: { - let mut required = schemars::Set::new(); - required.insert(#name.to_owned()); - required - }, - // 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() - })), - }); + let mut schema_expr = if variant.is_unit() && variant.attrs.with.is_none() { + schema_object(quote! { + instance_type: Some(schemars::schema::InstanceType::String.into()), + enum_values: Some(vec![#name.into()]), + }) + } else { + let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields); + schema_object(quote! { + instance_type: Some(schemars::schema::InstanceType::Object.into()), + object: Some(Box::new(schemars::schema::ObjectValidation { + properties: { + let mut props = schemars::Map::new(); + props.insert(#name.to_owned(), #sub_schema); + props + }, + required: { + let mut required = schemars::Set::new(); + required.insert(#name.to_owned()); + required + }, + // 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 .attrs