use crate::functions::metadata::{ArgumentMetadata, FunctionMetadata, SyntaxVariants};
use crate::is_functions::IsFunction;
use minijinja::value::Kwargs;
use minijinja::{Environment, Error, Value};
use regex::Regex;
const STRING_ARG: ArgumentMetadata = ArgumentMetadata {
name: "string",
arg_type: "string",
required: true,
default: None,
description: "The string to validate",
};
pub struct Email;
impl Email {
const EMAIL_PATTERN: &'static str = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
pub fn validate(s: &str) -> bool {
let re = Regex::new(Self::EMAIL_PATTERN).unwrap();
re.is_match(s)
}
}
impl IsFunction for Email {
const FUNCTION_NAME: &'static str = "is_email";
const IS_NAME: &'static str = "email";
const METADATA: FunctionMetadata = FunctionMetadata {
name: "is_email",
category: "validation",
description: "Validate email address format",
arguments: &[STRING_ARG],
return_type: "boolean",
examples: &[
"{{ is_email(string=\"user@example.com\") }}",
"{% if email_var is email %}valid{% endif %}",
],
syntax: SyntaxVariants::FUNCTION_AND_TEST,
};
fn call_as_function(kwargs: Kwargs) -> Result<Value, Error> {
let string: String = kwargs.get("string")?;
Ok(Value::from(Self::validate(&string)))
}
fn call_as_is(value: &Value) -> bool {
value.as_str().map(Self::validate).unwrap_or(false)
}
}
pub struct Url;
impl Url {
const URL_PATTERN: &'static str =
r"^(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]*[-A-Za-z0-9+&@#/%=~_|]$";
pub fn validate(s: &str) -> bool {
let re = Regex::new(Self::URL_PATTERN).unwrap();
re.is_match(s)
}
}
impl IsFunction for Url {
const FUNCTION_NAME: &'static str = "is_url";
const IS_NAME: &'static str = "url";
const METADATA: FunctionMetadata = FunctionMetadata {
name: "is_url",
category: "validation",
description: "Validate URL format (supports http, https, ftp, file schemes)",
arguments: &[STRING_ARG],
return_type: "boolean",
examples: &[
"{{ is_url(string=\"https://example.com\") }}",
"{% if url_var is url %}valid{% endif %}",
],
syntax: SyntaxVariants::FUNCTION_AND_TEST,
};
fn call_as_function(kwargs: Kwargs) -> Result<Value, Error> {
let string: String = kwargs.get("string")?;
Ok(Value::from(Self::validate(&string)))
}
fn call_as_is(value: &Value) -> bool {
value.as_str().map(Self::validate).unwrap_or(false)
}
}
pub struct Ip;
impl Ip {
pub fn validate(s: &str) -> bool {
s.parse::<std::net::IpAddr>().is_ok()
}
}
impl IsFunction for Ip {
const FUNCTION_NAME: &'static str = "is_ip";
const IS_NAME: &'static str = "ip";
const METADATA: FunctionMetadata = FunctionMetadata {
name: "is_ip",
category: "validation",
description: "Validate IP address format (IPv4 or IPv6)",
arguments: &[STRING_ARG],
return_type: "boolean",
examples: &[
"{{ is_ip(string=\"192.168.1.1\") }}",
"{% if ip_var is ip %}valid{% endif %}",
],
syntax: SyntaxVariants::FUNCTION_AND_TEST,
};
fn call_as_function(kwargs: Kwargs) -> Result<Value, Error> {
let string: String = kwargs.get("string")?;
Ok(Value::from(Self::validate(&string)))
}
fn call_as_is(value: &Value) -> bool {
value.as_str().map(Self::validate).unwrap_or(false)
}
}
pub struct Uuid;
impl Uuid {
const UUID_PATTERN: &'static str =
r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$";
pub fn validate(s: &str) -> bool {
let re = Regex::new(Self::UUID_PATTERN).unwrap();
re.is_match(s)
}
}
impl IsFunction for Uuid {
const FUNCTION_NAME: &'static str = "is_uuid";
const IS_NAME: &'static str = "uuid";
const METADATA: FunctionMetadata = FunctionMetadata {
name: "is_uuid",
category: "validation",
description: "Validate UUID format (all versions)",
arguments: &[STRING_ARG],
return_type: "boolean",
examples: &[
"{{ is_uuid(string=\"550e8400-e29b-41d4-a716-446655440000\") }}",
"{% if uuid_var is uuid %}valid{% endif %}",
],
syntax: SyntaxVariants::FUNCTION_AND_TEST,
};
fn call_as_function(kwargs: Kwargs) -> Result<Value, Error> {
let string: String = kwargs.get("string")?;
Ok(Value::from(Self::validate(&string)))
}
fn call_as_is(value: &Value) -> bool {
value.as_str().map(Self::validate).unwrap_or(false)
}
}
pub fn register_all(env: &mut Environment) {
Email::register(env);
Url::register(env);
Ip::register(env);
Uuid::register(env);
}