Skip to content

Commit

Permalink
Merge pull request #68 from yassun7010/support_warnings
Browse files Browse the repository at this point in the history
Support warnings
  • Loading branch information
yassun7010 authored Jun 15, 2024
2 parents c192c36 + 574b49e commit e9d73e2
Show file tree
Hide file tree
Showing 23 changed files with 602 additions and 66 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ regex = "^1.6"
paste = "^1.0"
serde_json = "^1.0"
serde = "^1.0"
itertools = "0.13.0"
8 changes: 4 additions & 4 deletions serde_valid/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ version.workspace = true
[dependencies]
fluent = { package = "fluent", version = "^0.16.0", optional = true }
indexmap = { version = "^2.0", features = ["serde"] }
itertools = "^0.13"
itertools.workspace = true
num-traits = "^0.2"
once_cell = "^1.7"
paste = { workspace = true }
regex = { workspace = true }
paste.workspace = true
regex.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde_json.workspace = true
serde_toml = { package = "toml", version = "^0.8", optional = true }
serde_valid_derive = { path = "../serde_valid_derive" }
serde_valid_literal = { path = "../serde_valid_literal" }
Expand Down
4 changes: 2 additions & 2 deletions serde_valid/tests/array_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use serde_valid::Validate;

#[test]
fn items_err_message() {
fn rule_sample(_a: &i32) -> Result<(), serde_valid::validation::Error> {
fn rule_sample(_a: i32) -> Result<(), serde_valid::validation::Error> {
Err(serde_valid::validation::Error::Custom(
"Rule error.".to_owned(),
))
Expand All @@ -18,7 +18,7 @@ fn items_err_message() {
}

#[derive(Validate)]
#[rule(rule_sample(val))]
#[validate(custom(|s| rule_sample(s.val)))]
struct TestChildStruct {
#[validate(minimum = 1)]
#[validate(maximum = 10)]
Expand Down
4 changes: 2 additions & 2 deletions serde_valid/tests/complex_test.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use serde_valid::Validate;

fn sample_rule(_val: &i32) -> Result<(), serde_valid::validation::Error> {
fn sample_rule(_val: i32) -> Result<(), serde_valid::validation::Error> {
Ok(())
}

#[derive(Debug, Validate)]
#[rule(sample_rule(int_value))]
#[validate(custom(|s| sample_rule(s.int_value)))]
struct TestStruct<'a> {
// Generic validator
#[validate(enumerate(5, 10, 15))]
Expand Down
12 changes: 6 additions & 6 deletions serde_valid/tests/enum_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ use serde_json::json;
use serde_valid::Validate;

#[test]
fn enum_named_variant_validation_is_ok() {
fn ok_rule(_a: &TestStruct, _b: &TestStruct) -> Result<(), serde_valid::validation::Error> {
fn enum_named_enum_validation_is_ok() {
fn ok_enum(_value: &TestEnum) -> Result<(), serde_valid::validation::Error> {
Ok(())
}
#[derive(Validate)]
#[validate(custom(ok_enum))]
enum TestEnum {
#[rule(ok_rule(a, b))]
Named {
#[validate]
a: TestStruct,
Expand Down Expand Up @@ -70,16 +70,16 @@ fn enum_newtype_variant_validation_is_ok() {
}

#[test]
fn enum_named_variant_validation_is_err() {
fn err_rule(_a: &TestStruct, _b: &TestStruct) -> Result<(), serde_valid::validation::Error> {
fn enum_named_enum_validation_is_err() {
fn err_rule(_data: &TestEnum) -> Result<(), serde_valid::validation::Error> {
Err(serde_valid::validation::Error::Custom(
"Rule error.".to_owned(),
))
}

#[derive(Validate)]
#[validate(custom(err_rule))]
enum TestEnum {
#[rule(err_rule(a, b))]
Named {
#[validate]
a: TestStruct,
Expand Down
4 changes: 2 additions & 2 deletions serde_valid/tests/specific_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use serde_valid::Validate;
#[test]
fn test_raw_type_field() {
#[derive(Validate)]
#[rule(sample_rule(r#type))]
#[validate(custom(|s| sample_rule(s.r#type)))]
struct MyStruct {
#[validate(maximum = 10)]
pub r#type: i32,
}

fn sample_rule(_type: &i32) -> Result<(), serde_valid::validation::Error> {
fn sample_rule(_type: i32) -> Result<(), serde_valid::validation::Error> {
Ok(())
}

Expand Down
3 changes: 2 additions & 1 deletion serde_valid_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ version.workspace = true
proc-macro = true

[dependencies]
paste = { workspace = true }
itertools.workspace = true
paste.workspace = true
proc-macro-error = "^1.0"
proc-macro2 = "^1.0"
quote = "^1.0"
Expand Down
1 change: 1 addition & 0 deletions serde_valid_derive/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod common;
pub mod field_validate;
pub mod rule;
pub mod struct_validate;
pub mod variant_validate;

pub type Validator = TokenStream;

Expand Down
24 changes: 21 additions & 3 deletions serde_valid_derive/src/attribute/rule/named_struct_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,29 @@ use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::spanned::Spanned;

use crate::types::{CommaSeparatedNestedMetas, CommaSeparatedTokenStreams};
use crate::{
output_stream::OutputStream,
types::{CommaSeparatedNestedMetas, CommaSeparatedTokenStreams},
warning::Warning,
};

pub fn collect_rules_from_named_struct(
ident: &syn::Ident,
attributes: &[syn::Attribute],
) -> Result<(HashSet<syn::Ident>, TokenStream), crate::Errors> {
) -> Result<(HashSet<syn::Ident>, OutputStream), crate::Errors> {
let mut errors = vec![];

let mut rule_fields = HashSet::new();
let mut warnings = vec![];
let rules = attributes
.iter()
.filter(|attribute| attribute.path().is_ident("rule"))
.inspect(|attribute| {
warnings.push(Warning::new_rule_deprecated(
ident,
attribute.bracket_token.span.span(),
));
})
.filter_map(|attribute| match &attribute.meta {
syn::Meta::List(list) => match collect_rule(list) {
Ok((field_ident, stream)) => {
Expand All @@ -36,7 +48,13 @@ pub fn collect_rules_from_named_struct(
.collect::<Vec<_>>();

if errors.is_empty() {
Ok((rule_fields, TokenStream::from_iter(rules)))
Ok((
rule_fields,
OutputStream {
output: TokenStream::from_iter(rules),
warnings,
},
))
} else {
Err(errors)
}
Expand Down
24 changes: 21 additions & 3 deletions serde_valid_derive/src/attribute/rule/unnamed_struct_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,29 @@ use proc_macro2::TokenStream;
use quote::quote;
use syn::spanned::Spanned;

use crate::types::{CommaSeparatedNestedMetas, CommaSeparatedTokenStreams, NestedMeta};
use crate::{
output_stream::OutputStream,
types::{CommaSeparatedNestedMetas, CommaSeparatedTokenStreams, NestedMeta},
warning::Warning,
};

pub fn collect_rules_from_unnamed_struct(
ident: &syn::Ident,
attributes: &[syn::Attribute],
) -> Result<(HashSet<syn::Ident>, TokenStream), crate::Errors> {
) -> Result<(HashSet<syn::Ident>, OutputStream), crate::Errors> {
let mut errors = vec![];

let mut rule_fields = HashSet::new();
let mut warnings = vec![];
let rules = attributes
.iter()
.filter(|attribute| attribute.path().is_ident("rule"))
.inspect(|attribute| {
warnings.push(Warning::new_rule_deprecated(
ident,
attribute.bracket_token.span.span(),
));
})
.filter_map(|attribute| match &attribute.meta {
syn::Meta::List(list) => match collect_rule(list) {
Ok((field_ident, stream)) => {
Expand All @@ -36,7 +48,13 @@ pub fn collect_rules_from_unnamed_struct(
.collect::<Vec<_>>();

if errors.is_empty() {
Ok((rule_fields, TokenStream::from_iter(rules)))
Ok((
rule_fields,
OutputStream {
output: TokenStream::from_iter(rules),
warnings,
},
))
} else {
Err(errors)
}
Expand Down
35 changes: 35 additions & 0 deletions serde_valid_derive/src/attribute/variant_validate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
mod generic;
mod meta;

use crate::attribute::Validator;

use self::meta::extract_variant_validator;

pub fn collect_variant_custom_from_named_variant(
attributes: &[syn::Attribute],
) -> Result<Validator, crate::Errors> {
let mut errors = vec![];

let validations = attributes
.iter()
.filter_map(|attribute| {
if attribute.path().is_ident("validate") {
match extract_variant_validator(attribute) {
Ok(validator) => Some(validator),
Err(validator_error) => {
errors.extend(validator_error);
None
}
}
} else {
None
}
})
.collect::<Vec<_>>();

if errors.is_empty() {
Ok(Validator::from_iter(validations))
} else {
Err(errors)
}
}
3 changes: 3 additions & 0 deletions serde_valid_derive/src/attribute/variant_validate/generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod custom;

pub use custom::extract_generic_variant_custom_validator;
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use crate::attribute::common::message_format::MessageFormat;
use crate::attribute::Validator;
use crate::types::CommaSeparatedNestedMetas;
use quote::quote;

pub fn extract_generic_variant_custom_validator(
meta_list: &syn::MetaList,
_message_format: MessageFormat,
) -> Result<Validator, crate::Errors> {
let mut errors = vec![];

let nested = meta_list
.parse_args_with(CommaSeparatedNestedMetas::parse_terminated)
.map_err(|error| vec![crate::Error::rule_args_parse_error(meta_list, &error)])?;

match nested.len() {
0 => Err(vec![
crate::Error::validate_custom_need_function_or_closure(meta_list),
])?,
2.. => nested
.iter()
.skip(1)
.for_each(|error| errors.push(crate::Error::rule_allow_single_function(error))),
_ => {}
}

let rule = match &nested[0] {
crate::types::NestedMeta::Meta(syn::Meta::Path(path)) => {
extract_variant_custom_from_meta_path(path)
}
crate::types::NestedMeta::Meta(syn::Meta::List(list)) => {
extract_variant_custom_from_meta_list(list)
}
crate::types::NestedMeta::Closure(closure) => extract_variant_custom_from_closure(closure),
_ => Err(vec![
crate::Error::validate_custom_need_function_or_closure(&nested[0]),
]),
};

match rule {
Ok(_) => {
if errors.is_empty() {
rule
} else {
Err(errors)
}
}
Err(rule_errors) => Err(errors.into_iter().chain(rule_errors).collect()),
}
}

fn extract_variant_custom_from_meta_path(
meta_path: &syn::Path,
) -> Result<Validator, crate::Errors> {
let rule_fn_name = &meta_path;

Ok(quote!(
if let Err(__error) = #rule_fn_name(self) {
__rule_vec_errors.push(__error);
};
))
}

fn extract_variant_custom_from_meta_list(
meta_list: &syn::MetaList,
) -> Result<Validator, crate::Errors> {
Ok(quote!(
if let Err(__error) = serde_valid::helpers::wrap_closure_validation(self, #meta_list) {
__rule_vec_errors.push(__error);
};
))
}

fn extract_variant_custom_from_closure(
closure: &syn::ExprClosure,
) -> Result<Validator, crate::Errors> {
Ok(quote!(
if let Err(__error) = serde_valid::helpers::wrap_closure_validation(self, #closure) {
__rule_vec_errors.push(__error);
};
))
}
Loading

0 comments on commit e9d73e2

Please sign in to comment.