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
|
@ -30,6 +30,9 @@ pub struct Struct4(
|
||||||
regex(path = "baz"),
|
regex(path = "baz"),
|
||||||
regex(pattern = "baz"),
|
regex(pattern = "baz"),
|
||||||
phone,
|
phone,
|
||||||
|
email(code = "code_str", message = "message"),
|
||||||
|
email = "foo",
|
||||||
|
email,
|
||||||
email,
|
email,
|
||||||
url
|
url
|
||||||
)]
|
)]
|
||||||
|
|
|
@ -82,10 +82,28 @@ error: `schemars(regex(...))` attribute requires `pattern = ...`
|
||||||
30 | regex(path = "baz"),
|
30 | regex(path = "baz"),
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: schemars attribute cannot contain both `url` and `email`
|
error: unexpected value of schemars email attribute item
|
||||||
--> tests/ui/invalid_validation_attrs.rs:34:9
|
--> tests/ui/invalid_validation_attrs.rs:33:14
|
||||||
|
|
|
|
||||||
34 | url
|
33 | email(code = "code_str", message = "message"),
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unexpected value of schemars email attribute item
|
||||||
|
--> tests/ui/invalid_validation_attrs.rs:34:15
|
||||||
|
|
|
||||||
|
34 | email = "foo",
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: duplicate schemars attribute item `email`
|
||||||
|
--> tests/ui/invalid_validation_attrs.rs:36:9
|
||||||
|
|
|
||||||
|
36 | email,
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: schemars attribute cannot contain both `url` and `email`
|
||||||
|
--> tests/ui/invalid_validation_attrs.rs:37:9
|
||||||
|
|
|
||||||
|
37 | url
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: unknown schemars attribute `phone`
|
error: unknown schemars attribute `phone`
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub struct Struct {
|
||||||
contains_str2: String,
|
contains_str2: String,
|
||||||
#[validate(email)]
|
#[validate(email)]
|
||||||
email_address: String,
|
email_address: String,
|
||||||
#[validate(url)]
|
#[validate(url(code = "code_str", message = "message"))]
|
||||||
homepage: String,
|
homepage: String,
|
||||||
#[validate(length(min = 1, max = 100))]
|
#[validate(length(min = 1, max = 100))]
|
||||||
non_empty_str: String,
|
non_empty_str: String,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use proc_macro2::{TokenStream, TokenTree};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream, Parser},
|
parse::{Parse, ParseStream, Parser},
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
Expr, ExprLit, Lit, LitStr, Meta, MetaNameValue,
|
Expr, ExprLit, Lit, LitStr, Meta, MetaList, MetaNameValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{path_str, AttrCtxt};
|
use super::{path_str, AttrCtxt};
|
||||||
|
@ -10,10 +10,27 @@ use super::{path_str, AttrCtxt};
|
||||||
pub fn require_path_only(meta: Meta, cx: &AttrCtxt) -> Result<(), ()> {
|
pub fn require_path_only(meta: Meta, cx: &AttrCtxt) -> Result<(), ()> {
|
||||||
match meta {
|
match meta {
|
||||||
Meta::Path(_) => Ok(()),
|
Meta::Path(_) => Ok(()),
|
||||||
_ => {
|
Meta::List(MetaList {
|
||||||
let name = path_str(meta.path());
|
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(
|
cx.error_spanned_by(
|
||||||
meta,
|
quote!(#eq_token #value),
|
||||||
format_args!(
|
format_args!(
|
||||||
"unexpected value of {} {} attribute item",
|
"unexpected value of {} {} attribute item",
|
||||||
cx.attr_type, name
|
cx.attr_type, name
|
||||||
|
|
|
@ -32,14 +32,12 @@ impl Format {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_attr_str(s: &str) -> Self {
|
fn from_attr_str(s: &str) -> Option<Self> {
|
||||||
match s {
|
Some(match s {
|
||||||
"email" => Format::Email,
|
"email" => Format::Email,
|
||||||
"url" => Format::Uri,
|
"url" => Format::Uri,
|
||||||
_ => {
|
_ => return None,
|
||||||
panic!("Invalid format attr string `{s}`. This is a bug in schemars, please raise an issue!")
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +130,10 @@ impl ValidationAttrs {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_meta(&mut self, meta: Meta, meta_name: &str, cx: &AttrCtxt) -> Option<Meta> {
|
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 {
|
match meta_name {
|
||||||
"length" => match self.length {
|
"length" => match self.length {
|
||||||
Some(_) => cx.duplicate_error(&meta),
|
Some(_) => cx.duplicate_error(&meta),
|
||||||
|
@ -143,8 +145,6 @@ impl ValidationAttrs {
|
||||||
None => self.range = parse_length_or_range(meta, cx).ok(),
|
None => self.range = parse_length_or_range(meta, cx).ok(),
|
||||||
},
|
},
|
||||||
|
|
||||||
"email" | "url" => self.handle_format(meta, meta_name, cx),
|
|
||||||
|
|
||||||
"required" => {
|
"required" => {
|
||||||
if self.required {
|
if self.required {
|
||||||
cx.duplicate_error(&meta);
|
cx.duplicate_error(&meta);
|
||||||
|
@ -159,7 +159,7 @@ impl ValidationAttrs {
|
||||||
(None, None, "schemars") => self.regex = parse_schemars_regex(meta, cx).ok(),
|
(None, None, "schemars") => self.regex = parse_schemars_regex(meta, cx).ok(),
|
||||||
(None, None, "validate") => self.regex = parse_validate_regex(meta, cx).ok(),
|
(None, None, "validate") => self.regex = parse_validate_regex(meta, cx).ok(),
|
||||||
(None, None, wat) => {
|
(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) {
|
"contains" => match (&self.regex, &self.contains) {
|
||||||
|
@ -184,14 +184,15 @@ impl ValidationAttrs {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_format(&mut self, meta: Meta, meta_name: &str, cx: &AttrCtxt) {
|
fn handle_format(&mut self, meta: Meta, format: Format, cx: &AttrCtxt) {
|
||||||
match &self.format {
|
match self.format {
|
||||||
Some(f) if f.attr_str() == meta_name => cx.duplicate_error(&meta),
|
Some(current) if current == format => cx.duplicate_error(&meta),
|
||||||
Some(f) => cx.mutual_exclusive_error(&meta, f.attr_str()),
|
Some(current) => cx.mutual_exclusive_error(&meta, current.attr_str()),
|
||||||
None => {
|
None => {
|
||||||
// FIXME this is too strict - it may be a MetaList in validator attr (e.g. with message/code items)
|
// Allow a MetaList in validator attr (e.g. with message/code items),
|
||||||
if require_path_only(meta, cx).is_ok() {
|
// but restrict it to path only in schemars attr.
|
||||||
self.format = Some(Format::from_attr_str(meta_name))
|
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