Exclude skipped fields/variants from json schema

This commit is contained in:
Graham Esau 2019-09-12 19:07:25 +01:00
parent 709ba7b62e
commit 5de6bcfdef
5 changed files with 137 additions and 11 deletions

View file

@ -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"
]
}
]
}

View file

@ -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"
]
}

View file

@ -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
}

58
schemars/tests/skip.rs Normal file
View file

@ -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::<MyStruct>("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::<TupleStruct>("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::<MyEnum>("skip_enum_variants")
}

View file

@ -104,6 +104,7 @@ fn is_unit_variant(v: &Variant) -> bool {
} }
fn schema_for_enum(variants: &[Variant], cattrs: &attr::Container) -> TokenStream { fn schema_for_enum(variants: &[Variant], cattrs: &attr::Container) -> TokenStream {
let variants = variants.iter().filter(|v| !v.attrs.skip_deserializing());
match cattrs.tag() { match cattrs.tag() {
EnumTag::External => schema_for_external_tagged_enum(variants, cattrs), EnumTag::External => schema_for_external_tagged_enum(variants, cattrs),
EnumTag::None => schema_for_untagged_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<Item = &'a Variant<'a>>,
cattrs: &attr::Container,
) -> TokenStream {
let (unit_variants, complex_variants): (Vec<_>, Vec<_>) = 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_count = unit_variants.len();
let unit_names = unit_variants 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( fn schema_for_internal_tagged_enum<'a>(
variants: &[Variant], variants: impl Iterator<Item = &'a Variant<'a>>,
cattrs: &attr::Container, cattrs: &attr::Container,
tag_name: &str, tag_name: &str,
) -> TokenStream { ) -> TokenStream {
let schemas = variants.iter().map(|variant| { let schemas = variants.map(|variant| {
let name = variant.attrs.name().deserialize_name(); let name = variant.attrs.name().deserialize_name();
let type_schema = wrap_schema_fields(quote! { let type_schema = wrap_schema_fields(quote! {
instance_type: Some(schemars::schema::InstanceType::String.into()), 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 { fn schema_for_untagged_enum<'a>(
let schemas = variants variants: impl Iterator<Item = &'a Variant<'a>>,
.iter() cattrs: &attr::Container,
.map(|v| schema_for_untagged_enum_variant(v, cattrs)); ) -> TokenStream {
let schemas = variants.map(|v| schema_for_untagged_enum_variant(v, cattrs));
wrap_schema_fields(quote! { wrap_schema_fields(quote! {
any_of: Some(vec![#(#schemas),*]), 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 { 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! { quote! {
gen.subschema_for::<(#(#types),*)>()? gen.subschema_for::<(#(#types),*)>()?
} }
} }
fn schema_for_struct(fields: &[Field], cattrs: &attr::Container) -> TokenStream { 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 container_has_default = has_default(cattrs.default());
let mut required = Vec::new(); let mut required = Vec::new();
let recurse = nested.iter().map(|field| { let recurse = nested.iter().map(|field| {