Skip to content

Commit

Permalink
Merge pull request #22 from yassun7010/refactor_validation_hint
Browse files Browse the repository at this point in the history
Refactor: validation and custom message hint.
  • Loading branch information
yassun7010 authored Jan 6, 2024
2 parents 1aea7b9 + de78c46 commit 92373a5
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 213 deletions.
76 changes: 64 additions & 12 deletions serde_valid_derive/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::validate::{MetaListValidation, MetaNameValueValidation, MetaPathValidation};
use crate::validate::{
MetaListValidation, MetaNameValueCustomMessage, MetaNameValueValidation, MetaPathCustomMessage,
MetaPathValidation,
};
use proc_macro2::TokenStream;
use quote::quote;
use syn::spanned::Spanned;

use crate::types::CommaSeparatedNestedMetas;
#[cfg(feature = "fluent")]
use crate::validate::MetaListMessage;
use crate::validate::MetaListCustomMessage;

pub fn object_errors_tokens() -> TokenStream {
quote!(::serde_valid::validation::Errors::Object(
Expand Down Expand Up @@ -213,27 +215,57 @@ impl Error {
)
}

pub fn validate_meta_name_value_need_value(path: &syn::Path, validation_type: &str) -> Self {
pub fn meta_path_validation_need_value(path: &syn::Path, validation_type: &str) -> Self {
Self::new(
path.span(),
format!("#[validate({validation_type} = ???)] needs validation value."),
format!("#[validate({validation_type}(???))] needs validation path."),
)
}

pub fn validate_meta_path_need_value(path: &syn::Path, validation_type: &str) -> Self {
pub fn meta_path_custom_message_need_value(
path: &syn::Path,
custom_message_type: &str,
) -> Self {
Self::new(
path.span(),
format!("#[validate({validation_type}(???))] needs validation path."),
format!("#[validate(..., {custom_message_type}(???))] needs custom message path."),
)
}

pub fn validate_meta_list_need_value(path: &syn::Path, validation_type: &str) -> Self {
pub fn meta_list_validation_need_value(path: &syn::Path, validation_type: &str) -> Self {
Self::new(
path.span(),
format!("#[validate({validation_type}(???, ...))] needs validation list."),
)
}

pub fn meta_list_custom_message_need_value(
path: &syn::Path,
custom_message_type: &str,
) -> Self {
Self::new(
path.span(),
format!("#[validate(..., {custom_message_type}(???, ...))] needs custom message list."),
)
}

pub fn meta_name_value_validation_need_value(path: &syn::Path, validation_type: &str) -> Self {
Self::new(
path.span(),
format!("#[validate({validation_type} = ???)] needs validation value."),
)
}

pub fn meta_name_value_custom_message_need_value(
path: &syn::Path,
validation_type: &str,
) -> Self {
Self::new(
path.span(),
format!("#[validate(..., {validation_type} = ???)] needs custom message value."),
)
}

pub fn validate_attribute_parse_error(attribute: &syn::Attribute, error: &syn::Error) -> Self {
Self::new(
attribute.span(),
Expand All @@ -253,7 +285,12 @@ impl Error {
)
}

pub fn validate_unknown_type(path: &syn::Path, unknown: &str, candidates: &[&str]) -> Self {
pub fn unknown_validation_type(path: &syn::Path, unknown: &str) -> Self {
let candidates = &(MetaPathValidation::iter().map(|x| x.name()))
.chain(MetaListValidation::iter().map(|x| x.name()))
.chain(MetaNameValueValidation::iter().map(|x| x.name()))
.collect::<Vec<_>>();

let filterd_candidates =
did_you_mean(unknown, candidates).unwrap_or_else(|| candidates.to_vec());

Expand All @@ -263,6 +300,21 @@ impl Error {
)
}

pub fn unknown_custom_message_type(path: &syn::Path, unknown: &str) -> Self {
let candidates = &(MetaPathCustomMessage::iter().map(|x| x.name()))
.chain(MetaListCustomMessage::iter().map(|x| x.name()))
.chain(MetaNameValueCustomMessage::iter().map(|x| x.name()))
.collect::<Vec<_>>();

let filterd_candidates =
did_you_mean(unknown, candidates).unwrap_or_else(|| candidates.to_vec());

Self::new(
path.span(),
format!("Unknown: `{unknown}` error message type. Is it one of the following?\n{filterd_candidates:#?}"),
)
}

pub fn validate_enumerate_parse_error(path: &syn::Path, error: &syn::Error) -> Self {
Self::new(
path.span(),
Expand Down Expand Up @@ -294,7 +346,7 @@ impl Error {
}

#[cfg(feature = "fluent")]
pub fn fluent_need_item(message_type: &MetaListMessage, path: &syn::Path) -> Self {
pub fn fluent_need_item(message_type: &MetaListCustomMessage, path: &syn::Path) -> Self {
Self::new(
path.span(),
format!("`{}` need items.", message_type.name()),
Expand All @@ -303,7 +355,7 @@ impl Error {

#[cfg(feature = "fluent")]
pub fn fluent_allow_key(
message_type: &MetaListMessage,
message_type: &MetaListCustomMessage,
nested_meta: &crate::types::NestedMeta,
) -> Self {
Self::new(
Expand All @@ -324,7 +376,7 @@ impl Error {

#[cfg(feature = "fluent")]
pub fn fluent_allow_args(
message_type: &MetaListMessage,
message_type: &MetaListCustomMessage,
nested_meta: &crate::types::NestedMeta,
) -> Self {
Self::new(
Expand Down
8 changes: 4 additions & 4 deletions serde_valid_derive/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ mod numeric;
mod object;
mod string;

pub use common::{MetaListValidation, MetaNameValueValidation, MetaPathValidation};
pub use common::{
MetaListCustomMessage, MetaListValidation, MetaNameValueCustomMessage, MetaNameValueValidation,
MetaPathCustomMessage, MetaPathValidation,
};

pub use field::{FieldValidators, Validator};
pub use meta::extract_meta_validator;

#[cfg(feature = "fluent")]
pub use common::MetaListMessage;
20 changes: 10 additions & 10 deletions serde_valid_derive/src/validate/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ macro_rules! enum_str {
};
}

enum_str! {
pub enum MetaPathValidation {
UniqueItems = "unique_items",
}
}

enum_str! {
pub enum MetaListValidation {
Enumerate = "enumerate",
Expand All @@ -92,34 +98,28 @@ enum_str! {
}

enum_str! {
pub enum MetaPathValidation {
UniqueItems = "unique_items",
pub enum MetaPathCustomMessage {
}
}

#[cfg(not(feature = "fluent"))]
enum_str! {
pub enum MetaListMessage {
pub enum MetaListCustomMessage {
MessageFn = "message_fn",
}
}

#[cfg(feature = "fluent")]
enum_str! {
pub enum MetaListMessage {
pub enum MetaListCustomMessage {
MessageFn = "message_fn",
I18n = "i18n",
Fluent = "fluent",
}
}

enum_str! {
pub enum MetaNameValueMessage {
pub enum MetaNameValueCustomMessage {
Message = "message",
}
}

enum_str! {
pub enum MetaPathMessage {
}
}
128 changes: 51 additions & 77 deletions serde_valid_derive/src/validate/common/custom_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use proc_macro2::TokenStream;
use quote::quote;
use std::str::FromStr;

use super::{get_str, MetaListMessage, MetaNameValueMessage, MetaPathMessage};
use super::{get_str, MetaListCustomMessage, MetaNameValueCustomMessage, MetaPathCustomMessage};

#[derive(Debug, Default)]
pub struct CustomMessageToken {
Expand Down Expand Up @@ -51,108 +51,82 @@ impl CustomMessageToken {
pub fn extract_custom_message_tokens(
meta: &syn::Meta,
) -> Result<CustomMessageToken, crate::Errors> {
match meta {
syn::Meta::List(message_fn_list) => {
extract_custom_message_tokens_from_meta_list(message_fn_list)
let custom_message_path = match meta {
syn::Meta::Path(path) => path,
syn::Meta::List(list) => &list.path,
syn::Meta::NameValue(name_value) => &name_value.path,
};
let custom_message_name = SingleIdentPath::new(custom_message_path)
.ident()
.to_string();

match (
MetaPathCustomMessage::from_str(&custom_message_name),
MetaListCustomMessage::from_str(&custom_message_name),
MetaNameValueCustomMessage::from_str(&custom_message_name),
meta,
) {
(Ok(_), _, _, syn::Meta::Path(_)) => {
unreachable!()
}
syn::Meta::NameValue(name_value) => {
extract_custom_message_tokens_from_name_value(name_value)
(_, Ok(custom_message_type), _, syn::Meta::List(custom_message)) => {
extract_custom_message_tokens_from_meta_list(&custom_message_type, custom_message)
}
syn::Meta::Path(path) => {
let path_label = SingleIdentPath::new(path).ident().to_string();
if MetaNameValueMessage::from_str(&path_label).is_ok() {
Err(crate::Error::validate_meta_name_value_need_value(
path,
&path_label,
))
} else if MetaListMessage::from_str(&path_label).is_ok() {
Err(crate::Error::validate_meta_list_need_value(
path,
&path_label,
))
} else {
Err(crate::Error::validate_unknown_type(
path,
&path_label,
&(MetaNameValueMessage::iter().map(|x| x.name()))
.chain(MetaListMessage::iter().map(|x| x.name()))
.chain(MetaPathMessage::iter().map(|x| x.name()))
.collect::<Vec<_>>(),
))
}
(_, _, Ok(custom_message_type), syn::Meta::NameValue(custom_message)) => {
extract_custom_message_tokens_from_name_value(&custom_message_type, custom_message)
}
.map_err(|error| vec![error]),
(Ok(_), _, _, _) => Err(vec![crate::Error::meta_path_custom_message_need_value(
custom_message_path,
&custom_message_name,
)]),
(_, Ok(_), _, _) => Err(vec![crate::Error::meta_list_custom_message_need_value(
custom_message_path,
&custom_message_name,
)]),
(_, _, Ok(_), _) => Err(vec![
crate::Error::meta_name_value_custom_message_need_value(
custom_message_path,
&custom_message_name,
),
]),
_ => Err(vec![crate::Error::unknown_custom_message_type(
custom_message_path,
&custom_message_name,
)]),
}
}

fn extract_custom_message_tokens_from_meta_list(
custom_message_type: &MetaListCustomMessage,
meta_list: &syn::MetaList,
) -> Result<CustomMessageToken, crate::Errors> {
let path = &meta_list.path;
let path_ident = SingleIdentPath::new(path).ident();
let path_label = path_ident.to_string();
let message_fn_define = meta_list
.parse_args_with(CommaSeparatedNestedMetas::parse_terminated)
.map_err(|error| vec![crate::Error::message_fn_parse_error(path_ident, &error)])?;

match MetaListMessage::from_str(&path_label) {
Ok(MetaListMessage::MessageFn) => get_message_fn_from_nested_meta(path, &message_fn_define)
.map(CustomMessageToken::new_message_fn),
match custom_message_type {
MetaListCustomMessage::MessageFn => {
get_message_fn_from_nested_meta(path, &message_fn_define)
.map(CustomMessageToken::new_message_fn)
}
#[cfg(feature = "fluent")]
Ok(ref message_type @ (MetaListMessage::I18n | MetaListMessage::Fluent)) => {
message_type @ (MetaListCustomMessage::I18n | MetaListCustomMessage::Fluent) => {
get_fluent_message_from_nested_meta(message_type, path, &message_fn_define)
.map(CustomMessageToken::new_fluent_message)
}
Err(unknown) => {
let error = if MetaNameValueMessage::from_str(&path_label).is_ok() {
crate::Error::validate_meta_list_need_value(path, &path_label)
} else if MetaPathMessage::from_str(&path_label).is_ok() {
crate::Error::validate_meta_path_need_value(path, &path_label)
} else {
crate::Error::validate_unknown_type(
path,
&unknown,
&MetaListMessage::iter()
.map(|x| x.name())
.collect::<Vec<_>>(),
)
};
Err(vec![error])
}
}
}

fn extract_custom_message_tokens_from_name_value(
custom_message_type: &MetaNameValueCustomMessage,
name_value: &syn::MetaNameValue,
) -> Result<CustomMessageToken, crate::Errors> {
let path = &name_value.path;
let path_ident = SingleIdentPath::new(path).ident();
let path_label = path_ident.to_string();

match MetaNameValueMessage::from_str(&path_label) {
Ok(MetaNameValueMessage::Message) => {
match custom_message_type {
MetaNameValueCustomMessage::Message => {
get_message_from_expr(&name_value.value).map(CustomMessageToken::new_message_fn)
}
Err(unknown) => if MetaListMessage::from_str(&path_label).is_ok() {
Err(crate::Error::validate_meta_list_need_value(
path,
&path_label,
))
} else if MetaPathMessage::from_str(&path_label).is_ok() {
Err(crate::Error::validate_meta_path_need_value(
path,
&path_label,
))
} else {
Err(crate::Error::validate_unknown_type(
path,
&unknown,
&MetaNameValueMessage::iter()
.map(|x| x.name())
.collect::<Vec<_>>(),
))
}
.map_err(|error| vec![error]),
}
}

Expand Down Expand Up @@ -190,7 +164,7 @@ fn get_message_from_lit(lit: &syn::Lit) -> Result<TokenStream, crate::Errors> {

#[cfg(feature = "fluent")]
fn get_fluent_message_from_nested_meta(
message_type: &MetaListMessage,
message_type: &MetaListCustomMessage,
path: &syn::Path,
fn_define: &CommaSeparatedNestedMetas,
) -> Result<TokenStream, crate::Errors> {
Expand Down
Loading

0 comments on commit 92373a5

Please sign in to comment.