#![allow(clippy::redundant_pub_crate)]
use plumb_core::Config;
#[derive(Debug, Clone)]
pub(crate) struct ValidationIssue {
pub(crate) path_segments: Vec<String>,
pub(crate) message: String,
}
pub(crate) fn validate(cfg: &Config) -> Option<ValidationIssue> {
for (token, value) in &cfg.color.tokens {
if !is_valid_hex_color(value) {
return Some(ValidationIssue {
path_segments: vec!["color".to_owned(), "tokens".to_owned(), token.clone()],
message: format!(
"`{value}` is not a valid hex color (expected `#rgb`, `#rgba`, `#rrggbb`, or `#rrggbbaa`)"
),
});
}
}
None
}
pub(crate) fn is_valid_hex_color(value: &str) -> bool {
let Some(body) = value.strip_prefix('#') else {
return false;
};
let len = body.len();
if !(len == 3 || len == 4 || len == 6 || len == 8) {
return false;
}
body.bytes().all(|b| b.is_ascii_hexdigit())
}
#[cfg(test)]
mod tests {
use super::is_valid_hex_color;
#[test]
fn accepts_canonical_six_digit_hex() {
assert!(is_valid_hex_color("#0b7285"));
assert!(is_valid_hex_color("#FFFFFF"));
}
#[test]
fn accepts_short_and_alpha_forms() {
assert!(is_valid_hex_color("#fff"));
assert!(is_valid_hex_color("#fffe"));
assert!(is_valid_hex_color("#0b728580"));
}
#[test]
fn rejects_missing_hash_or_bad_chars() {
assert!(!is_valid_hex_color("0b7285"));
assert!(!is_valid_hex_color("#0b72g5"));
assert!(!is_valid_hex_color("#12345"));
assert!(!is_valid_hex_color("not-a-hex"));
assert!(!is_valid_hex_color(""));
assert!(!is_valid_hex_color("#"));
}
}