Allow validate
(but not schemars
) attributes to have extra values where necessary
This commit is contained in:
parent
a85f0fc7bc
commit
56cdd45c5a
5 changed files with 63 additions and 24 deletions
|
@ -2,7 +2,7 @@ use proc_macro2::{TokenStream, TokenTree};
|
|||
use syn::{
|
||||
parse::{Parse, ParseStream, Parser},
|
||||
punctuated::Punctuated,
|
||||
Expr, ExprLit, Lit, LitStr, Meta, MetaNameValue,
|
||||
Expr, ExprLit, Lit, LitStr, Meta, MetaList, MetaNameValue,
|
||||
};
|
||||
|
||||
use super::{path_str, AttrCtxt};
|
||||
|
@ -10,10 +10,27 @@ use super::{path_str, AttrCtxt};
|
|||
pub fn require_path_only(meta: Meta, cx: &AttrCtxt) -> Result<(), ()> {
|
||||
match meta {
|
||||
Meta::Path(_) => Ok(()),
|
||||
_ => {
|
||||
let name = path_str(meta.path());
|
||||
Meta::List(MetaList {
|
||||
path, delimiter, ..
|
||||
}) => {
|
||||
let name = path_str(&path);
|
||||
cx.syn_error(syn::Error::new(
|
||||
delimiter.span().join(),
|
||||
format_args!(
|
||||
"unexpected value of {} {} attribute item",
|
||||
cx.attr_type, name
|
||||
),
|
||||
));
|
||||
Err(())
|
||||
}
|
||||
Meta::NameValue(MetaNameValue {
|
||||
path,
|
||||
eq_token,
|
||||
value,
|
||||
}) => {
|
||||
let name = path_str(&path);
|
||||
cx.error_spanned_by(
|
||||
meta,
|
||||
quote!(#eq_token #value),
|
||||
format_args!(
|
||||
"unexpected value of {} {} attribute item",
|
||||
cx.attr_type, name
|
||||
|
|
|
@ -32,14 +32,12 @@ impl Format {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_attr_str(s: &str) -> Self {
|
||||
match s {
|
||||
fn from_attr_str(s: &str) -> Option<Self> {
|
||||
Some(match s {
|
||||
"email" => Format::Email,
|
||||
"url" => Format::Uri,
|
||||
_ => {
|
||||
panic!("Invalid format attr string `{s}`. This is a bug in schemars, please raise an issue!")
|
||||
}
|
||||
}
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +130,10 @@ impl ValidationAttrs {
|
|||
}
|
||||
|
||||
fn process_meta(&mut self, meta: Meta, meta_name: &str, cx: &AttrCtxt) -> Option<Meta> {
|
||||
if let Some(format) = Format::from_attr_str(meta_name) {
|
||||
self.handle_format(meta, format, cx);
|
||||
return None;
|
||||
}
|
||||
match meta_name {
|
||||
"length" => match self.length {
|
||||
Some(_) => cx.duplicate_error(&meta),
|
||||
|
@ -143,8 +145,6 @@ impl ValidationAttrs {
|
|||
None => self.range = parse_length_or_range(meta, cx).ok(),
|
||||
},
|
||||
|
||||
"email" | "url" => self.handle_format(meta, meta_name, cx),
|
||||
|
||||
"required" => {
|
||||
if self.required {
|
||||
cx.duplicate_error(&meta);
|
||||
|
@ -159,7 +159,7 @@ impl ValidationAttrs {
|
|||
(None, None, "schemars") => self.regex = parse_schemars_regex(meta, cx).ok(),
|
||||
(None, None, "validate") => self.regex = parse_validate_regex(meta, cx).ok(),
|
||||
(None, None, wat) => {
|
||||
panic!("Unexpected attr type `{wat}` for regex item. This is a bug in schemars, please raise an issue!")
|
||||
unreachable!("Unexpected attr type `{wat}` for regex item. This is a bug in schemars, please raise an issue!")
|
||||
}
|
||||
},
|
||||
"contains" => match (&self.regex, &self.contains) {
|
||||
|
@ -184,14 +184,15 @@ impl ValidationAttrs {
|
|||
None
|
||||
}
|
||||
|
||||
fn handle_format(&mut self, meta: Meta, meta_name: &str, cx: &AttrCtxt) {
|
||||
match &self.format {
|
||||
Some(f) if f.attr_str() == meta_name => cx.duplicate_error(&meta),
|
||||
Some(f) => cx.mutual_exclusive_error(&meta, f.attr_str()),
|
||||
fn handle_format(&mut self, meta: Meta, format: Format, cx: &AttrCtxt) {
|
||||
match self.format {
|
||||
Some(current) if current == format => cx.duplicate_error(&meta),
|
||||
Some(current) => cx.mutual_exclusive_error(&meta, current.attr_str()),
|
||||
None => {
|
||||
// FIXME this is too strict - it may be a MetaList in validator attr (e.g. with message/code items)
|
||||
if require_path_only(meta, cx).is_ok() {
|
||||
self.format = Some(Format::from_attr_str(meta_name))
|
||||
// Allow a MetaList in validator attr (e.g. with message/code items),
|
||||
// but restrict it to path only in schemars attr.
|
||||
if cx.attr_type == "validate" || require_path_only(meta, cx).is_ok() {
|
||||
self.format = Some(format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue