use regex::Regex;
use std::sync::LazyLock;
fn git_hash_pattern() -> Regex {
let alts: Vec<String> = (0..7)
.map(|i| format!("[a-fA-F]{{{i}}}[0-9][0-9a-fA-F]{{{},{}}}", 6 - i, 39 - i))
.chain(std::iter::once(
"[a-fA-F]{7,39}[0-9][0-9a-fA-F]{0,32}".to_string(),
))
.collect();
Regex::new(&format!(r"\b(?:{})\b", alts.join("|"))).expect("Valid git hash regex")
}
static DEFAULT_SKIP_PATTERNS: LazyLock<Vec<Regex>> = LazyLock::new(|| {
vec![
Regex::new(r"https?://[^\s]+").expect("Valid URL regex"),
Regex::new(r"#[0-9a-fA-F]{3,8}").expect("Valid hex color regex"),
Regex::new(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}").expect("Valid email regex"),
Regex::new(r#"(?m)(?:^|[\s"'(\[=<,])\.{0,2}/[^\s]*"#).expect("Valid Unix path regex"),
Regex::new(r"[A-Za-z]:\\[^\s]*").expect("Valid Windows path regex"),
Regex::new(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}")
.expect("Valid UUID regex"),
Regex::new(r"[A-Za-z0-9+/]{20,}={1,2}").expect("Valid Base64 regex"),
git_hash_pattern(),
Regex::new(r"\[([^\]]+)\]\([^\s)]+\)").expect("Valid markdown link regex"),
Regex::new(r#""[^"\s]*/[^"\s]*"|'[^'\s]*/[^'\s]*'"#).expect("Valid quoted path regex"),
]
});
pub fn get_default_skip_patterns() -> &'static Vec<Regex> {
&DEFAULT_SKIP_PATTERNS
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_url_pattern() {
let patterns = get_default_skip_patterns();
let url_pattern = &patterns[0];
assert!(url_pattern.is_match("https://www.example.com"));
assert!(url_pattern.is_match("http://github.com/user/repo"));
assert!(!url_pattern.is_match("not a url"));
}
#[test]
fn test_hex_color_pattern() {
let patterns = get_default_skip_patterns();
let hex_pattern = &patterns[1];
assert!(hex_pattern.is_match("#deadbeef"));
assert!(hex_pattern.is_match("#fff"));
assert!(hex_pattern.is_match("#123456"));
assert!(!hex_pattern.is_match("deadbeef")); assert!(!hex_pattern.is_match("#gg")); }
#[test]
fn test_base64_pattern() {
let patterns = get_default_skip_patterns();
let base64_pattern = &patterns[6];
assert!(base64_pattern.is_match("dGVzdCBiYXNlNjQgZW5jb2Rpbmc=")); assert!(base64_pattern.is_match("SGVsbG8gV29ybGQhIFRoaXMgaXM=")); assert!(!base64_pattern.is_match("dGVzdCBiYXNlNjQgZW5jb2Rpbmc"));
assert!(!base64_pattern.is_match("administraton/dashboard"));
assert!(!base64_pattern.is_match("some/long/path/to/a/file"));
}
#[test]
fn test_email_pattern() {
let patterns = get_default_skip_patterns();
let email_pattern = &patterns[2];
assert!(email_pattern.is_match("user@example.com"));
assert!(email_pattern.is_match("test.email+tag@domain.co.uk"));
assert!(!email_pattern.is_match("not an email"));
}
#[test]
fn test_unix_path_pattern() {
let patterns = get_default_skip_patterns();
let path_pattern = &patterns[3];
assert!(path_pattern.is_match("/usr/local/bin"));
assert!(path_pattern.is_match("see /tmp/file.txt for details"));
assert!(path_pattern.is_match("path=\"/etc/hosts\""));
assert!(path_pattern.is_match("first line\n/var/log/syslog"));
assert!(path_pattern.is_match("import x from './modulle'"));
assert!(path_pattern.is_match("see ../docs/README"));
assert!(!path_pattern.is_match("and/or"));
assert!(!path_pattern.is_match("either/neither"));
}
#[test]
fn test_quoted_path_pattern() {
let patterns = get_default_skip_patterns();
let quoted_pattern = &patterns[9];
assert!(quoted_pattern.is_match("import 'package:flutter/material.dart';"));
assert!(quoted_pattern.is_match(r#"import "github.com/user/repo""#));
assert!(quoted_pattern.is_match("require('./lib/utils')"));
assert!(!quoted_pattern.is_match("'choose one and/or both'"));
assert!(!quoted_pattern.is_match("'hello'"));
assert!(!quoted_pattern.is_match("and/or"));
}
#[test]
fn test_git_hash_pattern() {
let patterns = get_default_skip_patterns();
let hash_pattern = &patterns[7];
assert!(hash_pattern.is_match("babc157"));
assert!(hash_pattern.is_match("abc1def")); assert!(hash_pattern.is_match("deadbeef0")); assert!(hash_pattern.is_match("1234567")); assert!(hash_pattern.is_match("d670460b4b4aece5915caf5c68d12f560a9fe3e4"));
assert!(!hash_pattern.is_match("acceded"));
assert!(!hash_pattern.is_match("defaced"));
assert!(!hash_pattern.is_match("accedded")); assert!(!hash_pattern.is_match("deadbeef"));
assert!(!hash_pattern.is_match("abc123"));
}
}