diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bb4d22..12c8f80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [0.8.4] - **In-dev** +### Added: +- `#[schemars(schema_with = "...")]` attribute can now be set on enum variants. + ## [0.8.3] - 2021-04-05 ### Added: - Support for `#[schemars(crate = "...")]` attribute to allow deriving JsonSchema when the schemars crate is aliased to a different name (https://github.com/GREsau/schemars/pull/55 / https://github.com/GREsau/schemars/pull/80) diff --git a/schemars/tests/enum_deny_unknown_fields.rs b/schemars/tests/enum_deny_unknown_fields.rs index 4fcb4bf..bf0f400 100644 --- a/schemars/tests/enum_deny_unknown_fields.rs +++ b/schemars/tests/enum_deny_unknown_fields.rs @@ -14,8 +14,8 @@ pub struct Struct { bar: bool, } -// Outer container should always have additionalPropreties: false -// `Struct` variant should have additionalPropreties: false +// Outer container should always have additionalProperties: false +// `Struct` variant should have additionalProperties: false #[derive(Debug, JsonSchema)] #[schemars(rename_all = "camelCase", deny_unknown_fields)] pub enum External { @@ -38,7 +38,7 @@ fn enum_external_tag() -> TestResult { test_default_generated_schema::("enum-external-duf") } -// Only `Struct` variant should have additionalPropreties: false +// Only `Struct` variant should have additionalProperties: false #[derive(Debug, JsonSchema)] #[schemars(tag = "typeProperty", deny_unknown_fields)] pub enum Internal { @@ -60,7 +60,7 @@ fn enum_internal_tag() -> TestResult { test_default_generated_schema::("enum-internal-duf") } -// Only `Struct` variant should have additionalPropreties: false +// Only `Struct` variant should have additionalProperties: false #[derive(Debug, JsonSchema)] #[schemars(untagged, deny_unknown_fields)] pub enum Untagged { @@ -82,7 +82,7 @@ fn enum_untagged() -> TestResult { test_default_generated_schema::("enum-untagged-duf") } -// Outer container and `Struct` variant should have additionalPropreties: false +// Outer container and `Struct` variant should have additionalProperties: false #[derive(Debug, JsonSchema)] #[schemars(tag = "t", content = "c", deny_unknown_fields)] pub enum Adjacent { diff --git a/schemars/tests/expected/schema_with-enum-adjacent-tagged.json b/schemars/tests/expected/schema_with-enum-adjacent-tagged.json index 1258d30..f464511 100644 --- a/schemars/tests/expected/schema_with-enum-adjacent-tagged.json +++ b/schemars/tests/expected/schema_with-enum-adjacent-tagged.json @@ -74,6 +74,24 @@ "minItems": 2 } } + }, + { + "type": "object", + "required": [ + "c", + "t" + ], + "properties": { + "t": { + "type": "string", + "enum": [ + "Unit" + ] + }, + "c": { + "type": "boolean" + } + } } ] } \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-enum-external.json b/schemars/tests/expected/schema_with-enum-external.json index 364b5f3..92fb5a6 100644 --- a/schemars/tests/expected/schema_with-enum-external.json +++ b/schemars/tests/expected/schema_with-enum-external.json @@ -56,6 +56,18 @@ } }, "additionalProperties": false + }, + { + "type": "object", + "required": [ + "unit" + ], + "properties": { + "unit": { + "type": "boolean" + } + }, + "additionalProperties": false } ] } \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-enum-internal.json b/schemars/tests/expected/schema_with-enum-internal.json index ae6ce94..ea39afe 100644 --- a/schemars/tests/expected/schema_with-enum-internal.json +++ b/schemars/tests/expected/schema_with-enum-internal.json @@ -36,6 +36,23 @@ ] } } + }, + { + "type": [ + "boolean", + "object" + ], + "required": [ + "typeProperty" + ], + "properties": { + "typeProperty": { + "type": "string", + "enum": [ + "Unit" + ] + } + } } ] } \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-enum-untagged.json b/schemars/tests/expected/schema_with-enum-untagged.json index d22f5a3..55147de 100644 --- a/schemars/tests/expected/schema_with-enum-untagged.json +++ b/schemars/tests/expected/schema_with-enum-untagged.json @@ -29,6 +29,9 @@ ], "maxItems": 2, "minItems": 2 + }, + { + "type": "boolean" } ] } \ No newline at end of file diff --git a/schemars/tests/schema_with_enum.rs b/schemars/tests/schema_with_enum.rs index 38cef03..c204644 100644 --- a/schemars/tests/schema_with_enum.rs +++ b/schemars/tests/schema_with_enum.rs @@ -2,8 +2,6 @@ mod util; use schemars::JsonSchema; use util::*; -// FIXME determine whether schema_with should be allowed on unit variants - fn schema_fn(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { ::json_schema(gen) } @@ -23,8 +21,8 @@ pub enum External { #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, i32, ), - // #[schemars(schema_with = "schema_fn")] - // Unit, + #[schemars(schema_with = "schema_fn")] + Unit, } #[test] @@ -40,8 +38,8 @@ pub enum Internal { foo: DoesntImplementJsonSchema, }, NewType(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema), - // #[schemars(schema_with = "schema_fn")] - // Unit, + #[schemars(schema_with = "schema_fn")] + Unit, } #[test] @@ -61,8 +59,8 @@ pub enum Untagged { #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, i32, ), - // #[schemars(schema_with = "schema_fn")] - // Unit, + #[schemars(schema_with = "schema_fn")] + Unit, } #[test] @@ -82,8 +80,8 @@ pub enum Adjacent { #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, i32, ), - // #[schemars(schema_with = "schema_fn")] - // Unit, + #[schemars(schema_with = "schema_fn")] + Unit, } #[test] diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs index 7b140a5..11e026f 100644 --- a/schemars_derive/src/lib.rs +++ b/schemars_derive/src/lib.rs @@ -50,7 +50,7 @@ fn derive_json_schema( let (impl_generics, ty_generics, where_clause) = cont.generics.split_for_impl(); if let Some(transparent_field) = cont.transparent_field() { - let (ty, type_def) = schema_exprs::type_for_schema(transparent_field, 0); + let (ty, type_def) = schema_exprs::type_for_field_schema(transparent_field, 0); return Ok(quote! { const _: () = { #crate_alias diff --git a/schemars_derive/src/schema_exprs.rs b/schemars_derive/src/schema_exprs.rs index a9e4deb..c5e83f2 100644 --- a/schemars_derive/src/schema_exprs.rs +++ b/schemars_derive/src/schema_exprs.rs @@ -57,7 +57,7 @@ pub fn expr_for_repr(cont: &Container) -> Result { } fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream { - let (ty, type_def) = type_for_schema(field, 0); + let (ty, type_def) = type_for_field_schema(field, 0); let span = field.original.span(); let gen = quote!(gen); @@ -78,11 +78,17 @@ fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream { } } -pub fn type_for_schema(field: &Field, local_id: usize) -> (syn::Type, Option) { +pub fn type_for_field_schema(field: &Field, local_id: usize) -> (syn::Type, Option) { match &field.attrs.with { None => (field.ty.to_owned(), None), - Some(WithAttr::Type(ty)) => (ty.to_owned(), None), - Some(WithAttr::Function(fun)) => { + Some(with_attr) => type_for_schema(with_attr, local_id), + } +} + +fn type_for_schema(with_attr: &WithAttr, local_id: usize) -> (syn::Type, Option) { + match with_attr { + WithAttr::Type(ty) => (ty.to_owned(), None), + WithAttr::Function(fun) => { let ty_name = format_ident!("_SchemarsSchemaWithFunction{}", local_id); let fn_name = fun.segments.last().unwrap().ident.to_string(); @@ -316,10 +322,14 @@ fn expr_for_adjacent_tagged_enum<'a>( } fn expr_for_untagged_enum_variant(variant: &Variant, deny_unknown_fields: bool) -> TokenStream { - if let Some(WithAttr::Type(with)) = &variant.attrs.with { + if let Some(with_attr) = &variant.attrs.with { + let (ty, type_def) = type_for_schema(with_attr, 0); let gen = quote!(gen); return quote_spanned! {variant.original.span()=> - #gen.subschema_for::<#with>() + { + #type_def + #gen.subschema_for::<#ty>() + } }; } @@ -335,10 +345,14 @@ fn expr_for_untagged_enum_variant_for_flatten( variant: &Variant, deny_unknown_fields: bool, ) -> Option { - if let Some(WithAttr::Type(with)) = &variant.attrs.with { + if let Some(with_attr) = &variant.attrs.with { + let (ty, type_def) = type_for_schema(with_attr, 0); let gen = quote!(gen); return Some(quote_spanned! {variant.original.span()=> - <#with as schemars::JsonSchema>::json_schema(#gen) + { + #type_def + <#ty as schemars::JsonSchema>::json_schema(#gen) + } }); } @@ -365,7 +379,7 @@ fn expr_for_tuple_struct(fields: &[Field]) -> TokenStream { .iter() .filter(|f| !f.serde_attrs.skip_deserializing()) .enumerate() - .map(|(i, f)| type_for_schema(f, i)) + .map(|(i, f)| type_for_field_schema(f, i)) .unzip(); quote! { { @@ -411,7 +425,7 @@ fn expr_for_struct( ..SchemaMetadata::from_attrs(&field.attrs) }; - let (ty, type_def) = type_for_schema(field, type_defs.len()); + let (ty, type_def) = type_for_field_schema(field, type_defs.len()); if let Some(type_def) = type_def { type_defs.push(type_def); } @@ -427,7 +441,7 @@ fn expr_for_struct( let flattens: Vec<_> = flattened_fields .into_iter() .map(|field| { - let (ty, type_def) = type_for_schema(field, type_defs.len()); + let (ty, type_def) = type_for_field_schema(field, type_defs.len()); if let Some(type_def) = type_def { type_defs.push(type_def); }