From 5de6bcfdeffcf2e87fcffcade6d83950ee96e026 Mon Sep 17 00:00:00 2001 From: Graham Esau Date: Thu, 12 Sep 2019 19:07:25 +0100 Subject: [PATCH] Exclude skipped fields/variants from json schema --- .../tests/expected/skip_enum_variants.json | 23 ++++++++ .../tests/expected/skip_struct_fields.json | 18 ++++++ .../tests/expected/skip_tuple_fields.json | 16 +++++ schemars/tests/skip.rs | 58 +++++++++++++++++++ schemars_derive/src/lib.rs | 33 +++++++---- 5 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 schemars/tests/expected/skip_enum_variants.json create mode 100644 schemars/tests/expected/skip_struct_fields.json create mode 100644 schemars/tests/expected/skip_tuple_fields.json create mode 100644 schemars/tests/skip.rs diff --git a/schemars/tests/expected/skip_enum_variants.json b/schemars/tests/expected/skip_enum_variants.json new file mode 100644 index 0000000..f15342f --- /dev/null +++ b/schemars/tests/expected/skip_enum_variants.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MyEnum", + "anyOf": [ + { + "enum": [ + "Included2" + ] + }, + { + "type": "object", + "properties": { + "Included1": { + "type": "number", + "format": "float" + } + }, + "required": [ + "Included1" + ] + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/skip_struct_fields.json b/schemars/tests/expected/skip_struct_fields.json new file mode 100644 index 0000000..c03f4e9 --- /dev/null +++ b/schemars/tests/expected/skip_struct_fields.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MyStruct", + "type": "object", + "properties": { + "included1": { + "type": "number", + "format": "float" + }, + "included2": { + "type": "null" + } + }, + "required": [ + "included1", + "included2" + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/skip_tuple_fields.json b/schemars/tests/expected/skip_tuple_fields.json new file mode 100644 index 0000000..9e5745b --- /dev/null +++ b/schemars/tests/expected/skip_tuple_fields.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "TupleStruct", + "type": "array", + "items": [ + { + "type": "number", + "format": "float" + }, + { + "type": "null" + } + ], + "maxItems": 2, + "minItems": 2 +} \ No newline at end of file diff --git a/schemars/tests/skip.rs b/schemars/tests/skip.rs new file mode 100644 index 0000000..19890b1 --- /dev/null +++ b/schemars/tests/skip.rs @@ -0,0 +1,58 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +#[derive(Debug, JsonSchema)] +struct MyStruct { + #[schemars(skip)] + skipped1: i32, + #[serde(skip)] + skipped2: bool, + #[serde(skip_deserializing)] + skipped3: String, + #[serde(skip_serializing)] + included1: f32, + included2: (), +} + +#[test] +fn skip_struct_fields() -> TestResult { + test_default_generated_schema::("skip_struct_fields") +} + +#[derive(Debug, JsonSchema)] +struct TupleStruct ( + #[schemars(skip)] + i32, + #[serde(skip)] + bool, + #[serde(skip_deserializing)] + String, + #[serde(skip_serializing)] + f32, + (), +); + +#[test] +fn skip_tuple_fields() -> TestResult { + test_default_generated_schema::("skip_tuple_fields") +} + +#[derive(Debug, JsonSchema)] +pub enum MyEnum { + #[schemars(skip)] + Skipped1(i32), + #[serde(skip)] + Skipped2, + #[serde(skip_deserializing)] + Skipped3, + #[serde(skip_serializing)] + Included1(f32), + Included2, +} + +#[test] +fn skip_enum_variants() -> TestResult { + test_default_generated_schema::("skip_enum_variants") +} + diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs index 00a3acf..7ef1e26 100644 --- a/schemars_derive/src/lib.rs +++ b/schemars_derive/src/lib.rs @@ -104,6 +104,7 @@ fn is_unit_variant(v: &Variant) -> bool { } fn schema_for_enum(variants: &[Variant], cattrs: &attr::Container) -> TokenStream { + let variants = variants.iter().filter(|v| !v.attrs.skip_deserializing()); match cattrs.tag() { EnumTag::External => schema_for_external_tagged_enum(variants, cattrs), EnumTag::None => schema_for_untagged_enum(variants, cattrs), @@ -112,9 +113,12 @@ fn schema_for_enum(variants: &[Variant], cattrs: &attr::Container) -> TokenStrea } } -fn schema_for_external_tagged_enum(variants: &[Variant], cattrs: &attr::Container) -> TokenStream { +fn schema_for_external_tagged_enum<'a>( + variants: impl Iterator>, + cattrs: &attr::Container, +) -> TokenStream { let (unit_variants, complex_variants): (Vec<_>, Vec<_>) = - variants.iter().partition(|v| is_unit_variant(v)); + variants.partition(|v| is_unit_variant(v)); let unit_count = unit_variants.len(); let unit_names = unit_variants @@ -156,12 +160,12 @@ fn schema_for_external_tagged_enum(variants: &[Variant], cattrs: &attr::Containe }) } -fn schema_for_internal_tagged_enum( - variants: &[Variant], +fn schema_for_internal_tagged_enum<'a>( + variants: impl Iterator>, cattrs: &attr::Container, tag_name: &str, ) -> TokenStream { - let schemas = variants.iter().map(|variant| { + let schemas = variants.map(|variant| { let name = variant.attrs.name().deserialize_name(); let type_schema = wrap_schema_fields(quote! { instance_type: Some(schemars::schema::InstanceType::String.into()), @@ -195,10 +199,11 @@ fn schema_for_internal_tagged_enum( }) } -fn schema_for_untagged_enum(variants: &[Variant], cattrs: &attr::Container) -> TokenStream { - let schemas = variants - .iter() - .map(|v| schema_for_untagged_enum_variant(v, cattrs)); +fn schema_for_untagged_enum<'a>( + variants: impl Iterator>, + cattrs: &attr::Container, +) -> TokenStream { + let schemas = variants.map(|v| schema_for_untagged_enum_variant(v, cattrs)); wrap_schema_fields(quote! { any_of: Some(vec![#(#schemas),*]), @@ -228,14 +233,20 @@ fn schema_for_newtype_struct(field: &Field) -> TokenStream { } fn schema_for_tuple_struct(fields: &[Field]) -> TokenStream { - let types = fields.iter().map(get_json_schema_type); + let types = fields + .iter() + .filter(|f| !f.attrs.skip_deserializing()) + .map(get_json_schema_type); quote! { gen.subschema_for::<(#(#types),*)>()? } } fn schema_for_struct(fields: &[Field], cattrs: &attr::Container) -> TokenStream { - let (nested, flat): (Vec<_>, Vec<_>) = fields.iter().partition(|f| !f.attrs.flatten()); + let (flat, nested): (Vec<_>, Vec<_>) = fields + .iter() + .filter(|f| !f.attrs.skip_deserializing()) + .partition(|f| f.attrs.flatten()); let container_has_default = has_default(cattrs.default()); let mut required = Vec::new(); let recurse = nested.iter().map(|field| {