use crate::parse_result::{ErrorCollector, ParserConfig};
pub trait Validate {
fn validate(&self, path: &str, config: &ParserConfig, collector: &mut ErrorCollector);
}
pub mod helpers {
use crate::error::ValidationError;
use crate::parse_result::{ErrorCollector, ParserConfig};
use regex::Regex;
pub fn validate_length(
value: &str,
field_name: &str,
min: Option<usize>,
max: Option<usize>,
path: &str,
config: &ParserConfig,
collector: &mut ErrorCollector,
) -> bool {
let mut valid = true;
if let Some(min_len) = min
&& value.chars().count() < min_len
{
let error = ValidationError::new(
1001,
format!("{field_name} is shorter than the minimum length of {min_len}"),
)
.with_field(field_name.to_string())
.with_path(path.to_string());
if config.fail_fast {
collector.add_critical_error(error);
return false;
} else {
collector.add_error(error);
valid = false;
}
}
if let Some(max_len) = max
&& value.chars().count() > max_len
{
let error = ValidationError::new(
1002,
format!("{field_name} exceeds the maximum length of {max_len}"),
)
.with_field(field_name.to_string())
.with_path(path.to_string());
if config.fail_fast {
collector.add_critical_error(error);
return false;
} else {
collector.add_error(error);
valid = false;
}
}
valid
}
pub fn validate_pattern(
value: &str,
field_name: &str,
pattern: &str,
path: &str,
config: &ParserConfig,
collector: &mut ErrorCollector,
) -> bool {
let trimmed_value = value.trim();
let regex = match Regex::new(pattern) {
Ok(r) => r,
Err(_) => {
collector.add_critical_error(
ValidationError::new(
9999,
format!("Invalid regex pattern for {field_name}: {pattern}"),
)
.with_field(field_name.to_string())
.with_path(path.to_string()),
);
return false;
}
};
if !regex.is_match(trimmed_value) {
let error = ValidationError::new(
1005,
format!("{field_name} does not match the required pattern (value: '{value}')"),
)
.with_field(field_name.to_string())
.with_path(path.to_string());
if config.fail_fast {
collector.add_critical_error(error);
return false;
} else {
collector.add_error(error);
return false;
}
}
true
}
pub fn validate_required<T>(
value: &Option<T>,
field_name: &str,
path: &str,
_config: &ParserConfig,
collector: &mut ErrorCollector,
) -> bool {
if value.is_none() {
let error = ValidationError::new(1003, format!("{field_name} is required"))
.with_field(field_name.to_string())
.with_path(path.to_string());
collector.add_critical_error(error);
return false;
}
true
}
pub fn child_path(parent: &str, field: &str) -> String {
if parent.is_empty() {
field.to_string()
} else {
format!("{parent}.{field}")
}
}
}