Refactoring
This commit is contained in:
parent
4be21bd811
commit
5f841f2e5c
4 changed files with 117 additions and 101 deletions
|
@ -5,6 +5,7 @@ mod validation;
|
||||||
pub use schemars_to_serde::process_serde_attrs;
|
pub use schemars_to_serde::process_serde_attrs;
|
||||||
pub use validation::ValidationAttrs;
|
pub use validation::ValidationAttrs;
|
||||||
|
|
||||||
|
use crate::metadata::SchemaMetadata;
|
||||||
use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use serde_derive_internals::Ctxt;
|
use serde_derive_internals::Ctxt;
|
||||||
|
@ -53,6 +54,27 @@ impl Attrs {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_metadata(&self) -> SchemaMetadata<'_> {
|
||||||
|
#[allow(clippy::ptr_arg)]
|
||||||
|
fn none_if_empty(s: &String) -> Option<&str> {
|
||||||
|
if s.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SchemaMetadata {
|
||||||
|
title: self.title.as_ref().and_then(none_if_empty),
|
||||||
|
description: self.description.as_ref().and_then(none_if_empty),
|
||||||
|
deprecated: self.deprecated,
|
||||||
|
examples: &self.examples,
|
||||||
|
read_only: false,
|
||||||
|
write_only: false,
|
||||||
|
default: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn populate(
|
fn populate(
|
||||||
mut self,
|
mut self,
|
||||||
attrs: &[syn::Attribute],
|
attrs: &[syn::Attribute],
|
||||||
|
|
|
@ -120,7 +120,7 @@ impl ValidationAttrs {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_to_schema(&self, schema_expr: TokenStream) -> TokenStream {
|
pub fn apply_to_schema(&self, schema_expr: &mut TokenStream) {
|
||||||
let mut array_validation = Vec::new();
|
let mut array_validation = Vec::new();
|
||||||
let mut number_validation = Vec::new();
|
let mut number_validation = Vec::new();
|
||||||
let mut object_validation = Vec::new();
|
let mut object_validation = Vec::new();
|
||||||
|
@ -200,7 +200,7 @@ impl ValidationAttrs {
|
||||||
|| string_validation.is_some()
|
|| string_validation.is_some()
|
||||||
|| format.is_some()
|
|| format.is_some()
|
||||||
{
|
{
|
||||||
quote! {
|
*schema_expr = quote! {
|
||||||
{
|
{
|
||||||
let mut schema = #schema_expr;
|
let mut schema = #schema_expr;
|
||||||
if let schemars::schema::Schema::Object(schema_object) = &mut schema
|
if let schemars::schema::Schema::Object(schema_object) = &mut schema
|
||||||
|
@ -214,8 +214,6 @@ impl ValidationAttrs {
|
||||||
schema
|
schema
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
schema_expr
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use crate::attr;
|
|
||||||
use attr::Attrs;
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -14,24 +12,10 @@ pub struct SchemaMetadata<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SchemaMetadata<'a> {
|
impl<'a> SchemaMetadata<'a> {
|
||||||
pub fn from_attrs(attrs: &'a Attrs) -> Self {
|
pub fn apply_to_schema(&self, schema_expr: &mut TokenStream) {
|
||||||
SchemaMetadata {
|
|
||||||
title: attrs.title.as_ref().and_then(none_if_empty),
|
|
||||||
description: attrs.description.as_ref().and_then(none_if_empty),
|
|
||||||
deprecated: attrs.deprecated,
|
|
||||||
examples: &attrs.examples,
|
|
||||||
read_only: false,
|
|
||||||
write_only: false,
|
|
||||||
default: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply_to_schema(&self, schema_expr: TokenStream) -> TokenStream {
|
|
||||||
let setters = self.make_setters();
|
let setters = self.make_setters();
|
||||||
if setters.is_empty() {
|
if !setters.is_empty() {
|
||||||
schema_expr
|
*schema_expr = quote! {
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
schemars::_private::apply_metadata(#schema_expr, schemars::schema::Metadata {
|
schemars::_private::apply_metadata(#schema_expr, schemars::schema::Metadata {
|
||||||
#(#setters)*
|
#(#setters)*
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -91,12 +75,3 @@ impl<'a> SchemaMetadata<'a> {
|
||||||
setters
|
setters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::ptr_arg)]
|
|
||||||
fn none_if_empty(s: &String) -> Option<&str> {
|
|
||||||
if s.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use serde_derive_internals::attr::{self as serde_attr, Default as SerdeDefault,
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
|
|
||||||
pub fn expr_for_container(cont: &Container) -> TokenStream {
|
pub fn expr_for_container(cont: &Container) -> TokenStream {
|
||||||
let schema_expr = match &cont.data {
|
let mut schema_expr = match &cont.data {
|
||||||
Data::Struct(Style::Unit, _) => expr_for_unit_struct(),
|
Data::Struct(Style::Unit, _) => expr_for_unit_struct(),
|
||||||
Data::Struct(Style::Newtype, fields) => expr_for_newtype_struct(&fields[0]),
|
Data::Struct(Style::Newtype, fields) => expr_for_newtype_struct(&fields[0]),
|
||||||
Data::Struct(Style::Tuple, fields) => expr_for_tuple_struct(fields),
|
Data::Struct(Style::Tuple, fields) => expr_for_tuple_struct(fields),
|
||||||
|
@ -17,8 +17,8 @@ pub fn expr_for_container(cont: &Container) -> TokenStream {
|
||||||
Data::Enum(variants) => expr_for_enum(variants, &cont.serde_attrs),
|
Data::Enum(variants) => expr_for_enum(variants, &cont.serde_attrs),
|
||||||
};
|
};
|
||||||
|
|
||||||
let doc_metadata = SchemaMetadata::from_attrs(&cont.attrs);
|
cont.attrs.as_metadata().apply_to_schema(&mut schema_expr);
|
||||||
doc_metadata.apply_to_schema(schema_expr)
|
schema_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_for_repr(cont: &Container) -> Result<TokenStream, syn::Error> {
|
pub fn expr_for_repr(cont: &Container) -> Result<TokenStream, syn::Error> {
|
||||||
|
@ -47,13 +47,13 @@ pub fn expr_for_repr(cont: &Container) -> Result<TokenStream, syn::Error> {
|
||||||
let enum_ident = &cont.ident;
|
let enum_ident = &cont.ident;
|
||||||
let variant_idents = variants.iter().map(|v| &v.ident);
|
let variant_idents = variants.iter().map(|v| &v.ident);
|
||||||
|
|
||||||
let schema_expr = schema_object(quote! {
|
let mut schema_expr = schema_object(quote! {
|
||||||
instance_type: Some(schemars::schema::InstanceType::Integer.into()),
|
instance_type: Some(schemars::schema::InstanceType::Integer.into()),
|
||||||
enum_values: Some(vec![#((#enum_ident::#variant_idents as #repr_type).into()),*]),
|
enum_values: Some(vec![#((#enum_ident::#variant_idents as #repr_type).into()),*]),
|
||||||
});
|
});
|
||||||
|
|
||||||
let doc_metadata = SchemaMetadata::from_attrs(&cont.attrs);
|
cont.attrs.as_metadata().apply_to_schema(&mut schema_expr);
|
||||||
Ok(doc_metadata.apply_to_schema(schema_expr))
|
Ok(schema_expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream {
|
fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream {
|
||||||
|
@ -61,29 +61,24 @@ fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream {
|
||||||
let span = field.original.span();
|
let span = field.original.span();
|
||||||
let gen = quote!(gen);
|
let gen = quote!(gen);
|
||||||
|
|
||||||
let schema_expr = if field.validation_attrs.required {
|
let mut schema_expr = if field.validation_attrs.required {
|
||||||
quote_spanned! {span=>
|
quote_spanned! {span=>
|
||||||
{
|
|
||||||
#type_def
|
|
||||||
<#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#gen)
|
<#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#gen)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if allow_ref {
|
} else if allow_ref {
|
||||||
quote_spanned! {span=>
|
quote_spanned! {span=>
|
||||||
{
|
|
||||||
#type_def
|
|
||||||
#gen.subschema_for::<#ty>()
|
#gen.subschema_for::<#ty>()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
quote_spanned! {span=>
|
quote_spanned! {span=>
|
||||||
{
|
|
||||||
#type_def
|
|
||||||
<#ty as schemars::JsonSchema>::json_schema(#gen)
|
<#ty as schemars::JsonSchema>::json_schema(#gen)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
field.validation_attrs.apply_to_schema(schema_expr)
|
|
||||||
|
prepend_type_def(type_def, &mut schema_expr);
|
||||||
|
field.validation_attrs.apply_to_schema(&mut schema_expr);
|
||||||
|
|
||||||
|
schema_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_for_field_schema(field: &Field) -> (syn::Type, Option<TokenStream>) {
|
pub fn type_for_field_schema(field: &Field) -> (syn::Type, Option<TokenStream>) {
|
||||||
|
@ -167,7 +162,7 @@ fn expr_for_external_tagged_enum<'a>(
|
||||||
let name = variant.name();
|
let name = variant.name();
|
||||||
let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
|
let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
|
||||||
|
|
||||||
let schema_expr = schema_object(quote! {
|
let mut schema_expr = schema_object(quote! {
|
||||||
instance_type: Some(schemars::schema::InstanceType::Object.into()),
|
instance_type: Some(schemars::schema::InstanceType::Object.into()),
|
||||||
object: Some(Box::new(schemars::schema::ObjectValidation {
|
object: Some(Box::new(schemars::schema::ObjectValidation {
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -184,8 +179,13 @@ fn expr_for_external_tagged_enum<'a>(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
let doc_metadata = SchemaMetadata::from_attrs(&variant.attrs);
|
|
||||||
doc_metadata.apply_to_schema(schema_expr)
|
variant
|
||||||
|
.attrs
|
||||||
|
.as_metadata()
|
||||||
|
.apply_to_schema(&mut schema_expr);
|
||||||
|
|
||||||
|
schema_expr
|
||||||
}));
|
}));
|
||||||
|
|
||||||
schema_object(quote! {
|
schema_object(quote! {
|
||||||
|
@ -208,7 +208,7 @@ fn expr_for_internal_tagged_enum<'a>(
|
||||||
enum_values: Some(vec![#name.into()]),
|
enum_values: Some(vec![#name.into()]),
|
||||||
});
|
});
|
||||||
|
|
||||||
let tag_schema = schema_object(quote! {
|
let mut tag_schema = schema_object(quote! {
|
||||||
instance_type: Some(schemars::schema::InstanceType::Object.into()),
|
instance_type: Some(schemars::schema::InstanceType::Object.into()),
|
||||||
object: Some(Box::new(schemars::schema::ObjectValidation {
|
object: Some(Box::new(schemars::schema::ObjectValidation {
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -224,15 +224,16 @@ fn expr_for_internal_tagged_enum<'a>(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
let doc_metadata = SchemaMetadata::from_attrs(&variant.attrs);
|
|
||||||
let tag_schema = doc_metadata.apply_to_schema(tag_schema);
|
|
||||||
|
|
||||||
match expr_for_untagged_enum_variant_for_flatten(&variant, deny_unknown_fields) {
|
variant.attrs.as_metadata().apply_to_schema(&mut tag_schema);
|
||||||
Some(variant_schema) => quote! {
|
|
||||||
#tag_schema.flatten(#variant_schema)
|
if let Some(variant_schema) =
|
||||||
},
|
expr_for_untagged_enum_variant_for_flatten(&variant, deny_unknown_fields)
|
||||||
None => tag_schema,
|
{
|
||||||
|
tag_schema.extend(quote!(.flatten(#variant_schema)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tag_schema
|
||||||
});
|
});
|
||||||
|
|
||||||
schema_object(quote! {
|
schema_object(quote! {
|
||||||
|
@ -248,9 +249,14 @@ fn expr_for_untagged_enum<'a>(
|
||||||
deny_unknown_fields: bool,
|
deny_unknown_fields: bool,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let schemas = variants.map(|variant| {
|
let schemas = variants.map(|variant| {
|
||||||
let schema_expr = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
|
let mut schema_expr = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
|
||||||
let doc_metadata = SchemaMetadata::from_attrs(&variant.attrs);
|
|
||||||
doc_metadata.apply_to_schema(schema_expr)
|
variant
|
||||||
|
.attrs
|
||||||
|
.as_metadata()
|
||||||
|
.apply_to_schema(&mut schema_expr);
|
||||||
|
|
||||||
|
schema_expr
|
||||||
});
|
});
|
||||||
|
|
||||||
schema_object(quote! {
|
schema_object(quote! {
|
||||||
|
@ -297,7 +303,7 @@ fn expr_for_adjacent_tagged_enum<'a>(
|
||||||
TokenStream::new()
|
TokenStream::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let outer_schema = schema_object(quote! {
|
let mut outer_schema = schema_object(quote! {
|
||||||
instance_type: Some(schemars::schema::InstanceType::Object.into()),
|
instance_type: Some(schemars::schema::InstanceType::Object.into()),
|
||||||
object: Some(Box::new(schemars::schema::ObjectValidation {
|
object: Some(Box::new(schemars::schema::ObjectValidation {
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -317,8 +323,12 @@ fn expr_for_adjacent_tagged_enum<'a>(
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
let doc_metadata = SchemaMetadata::from_attrs(&variant.attrs);
|
variant
|
||||||
doc_metadata.apply_to_schema(outer_schema)
|
.attrs
|
||||||
|
.as_metadata()
|
||||||
|
.apply_to_schema(&mut outer_schema);
|
||||||
|
|
||||||
|
outer_schema
|
||||||
});
|
});
|
||||||
|
|
||||||
schema_object(quote! {
|
schema_object(quote! {
|
||||||
|
@ -333,12 +343,12 @@ fn expr_for_untagged_enum_variant(variant: &Variant, deny_unknown_fields: bool)
|
||||||
if let Some(with_attr) = &variant.attrs.with {
|
if let Some(with_attr) = &variant.attrs.with {
|
||||||
let (ty, type_def) = type_for_schema(with_attr);
|
let (ty, type_def) = type_for_schema(with_attr);
|
||||||
let gen = quote!(gen);
|
let gen = quote!(gen);
|
||||||
return quote_spanned! {variant.original.span()=>
|
let mut schema_expr = quote_spanned! {variant.original.span()=>
|
||||||
{
|
|
||||||
#type_def
|
|
||||||
#gen.subschema_for::<#ty>()
|
#gen.subschema_for::<#ty>()
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
prepend_type_def(type_def, &mut schema_expr);
|
||||||
|
return schema_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
match variant.style {
|
match variant.style {
|
||||||
|
@ -356,12 +366,12 @@ fn expr_for_untagged_enum_variant_for_flatten(
|
||||||
if let Some(with_attr) = &variant.attrs.with {
|
if let Some(with_attr) = &variant.attrs.with {
|
||||||
let (ty, type_def) = type_for_schema(with_attr);
|
let (ty, type_def) = type_for_schema(with_attr);
|
||||||
let gen = quote!(gen);
|
let gen = quote!(gen);
|
||||||
return Some(quote_spanned! {variant.original.span()=>
|
let mut schema_expr = quote_spanned! {variant.original.span()=>
|
||||||
{
|
|
||||||
#type_def
|
|
||||||
<#ty as schemars::JsonSchema>::json_schema(#gen)
|
<#ty as schemars::JsonSchema>::json_schema(#gen)
|
||||||
}
|
};
|
||||||
});
|
|
||||||
|
prepend_type_def(type_def, &mut schema_expr);
|
||||||
|
return Some(schema_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(match variant.style {
|
Some(match variant.style {
|
||||||
|
@ -429,17 +439,6 @@ fn expr_for_struct(
|
||||||
|
|
||||||
let (ty, type_def) = type_for_field_schema(field);
|
let (ty, type_def) = type_for_field_schema(field);
|
||||||
|
|
||||||
let gen = quote!(gen);
|
|
||||||
let schema_expr = if field.validation_attrs.required {
|
|
||||||
quote_spanned! {ty.span()=>
|
|
||||||
<#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#gen)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote_spanned! {ty.span()=>
|
|
||||||
#gen.subschema_for::<#ty>()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let maybe_insert_required = match (&default, field.validation_attrs.required) {
|
let maybe_insert_required = match (&default, field.validation_attrs.required) {
|
||||||
(Some(_), _) => TokenStream::new(),
|
(Some(_), _) => TokenStream::new(),
|
||||||
(None, false) => {
|
(None, false) => {
|
||||||
|
@ -458,11 +457,22 @@ fn expr_for_struct(
|
||||||
read_only: field.serde_attrs.skip_deserializing(),
|
read_only: field.serde_attrs.skip_deserializing(),
|
||||||
write_only: field.serde_attrs.skip_serializing(),
|
write_only: field.serde_attrs.skip_serializing(),
|
||||||
default,
|
default,
|
||||||
..SchemaMetadata::from_attrs(&field.attrs)
|
..field.attrs.as_metadata()
|
||||||
};
|
};
|
||||||
|
|
||||||
let schema_expr = metadata.apply_to_schema(schema_expr);
|
let gen = quote!(gen);
|
||||||
let schema_expr = field.validation_attrs.apply_to_schema(schema_expr);
|
let mut schema_expr = if field.validation_attrs.required {
|
||||||
|
quote_spanned! {ty.span()=>
|
||||||
|
<#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#gen)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote_spanned! {ty.span()=>
|
||||||
|
#gen.subschema_for::<#ty>()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
metadata.apply_to_schema(&mut schema_expr);
|
||||||
|
field.validation_attrs.apply_to_schema(&mut schema_expr);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
{
|
{
|
||||||
|
@ -486,12 +496,12 @@ fn expr_for_struct(
|
||||||
};
|
};
|
||||||
|
|
||||||
let args = quote!(gen, #required);
|
let args = quote!(gen, #required);
|
||||||
quote_spanned! {ty.span()=>
|
let mut schema_expr = quote_spanned! {ty.span()=>
|
||||||
.flatten({
|
|
||||||
#type_def
|
|
||||||
schemars::_private::json_schema_for_flatten::<#ty>(#args)
|
schemars::_private::json_schema_for_flatten::<#ty>(#args)
|
||||||
})
|
};
|
||||||
}
|
|
||||||
|
prepend_type_def(type_def, &mut schema_expr);
|
||||||
|
schema_expr
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -513,7 +523,7 @@ fn expr_for_struct(
|
||||||
#set_additional_properties
|
#set_additional_properties
|
||||||
#(#properties)*
|
#(#properties)*
|
||||||
schemars::schema::Schema::Object(schema_object)
|
schemars::schema::Schema::Object(schema_object)
|
||||||
#(#flattens)*
|
#(.flatten(#flattens))*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -582,3 +592,14 @@ fn schema_object(properties: TokenStream) -> TokenStream {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepend_type_def(type_def: Option<TokenStream>, schema_expr: &mut TokenStream) {
|
||||||
|
if let Some(type_def) = type_def {
|
||||||
|
*schema_expr = quote! {
|
||||||
|
{
|
||||||
|
#type_def
|
||||||
|
#schema_expr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue