esp_extractor/
utils.rs

1use thiserror::Error;
2use std::path::Path;
3
4/// 自定义错误类型
5#[derive(Error, Debug)]
6pub enum EspError {
7    #[error("Invalid file format")]
8    InvalidFormat,
9    
10    #[error("Unsupported record type: {0}")]
11    UnsupportedRecordType(String),
12    
13    #[error("Compression error: {0}")]
14    CompressionError(String),
15    
16    #[error("IO error: {0}")]
17    IoError(#[from] std::io::Error),
18    
19    #[error("JSON error: {0}")]
20    JsonError(#[from] serde_json::Error),
21}
22
23/// 字符串验证配置
24struct StringValidationConfig {
25    blacklist: &'static [&'static str],
26    whitelist: &'static [&'static str],
27}
28
29impl StringValidationConfig {
30    const fn new() -> Self {
31        Self {
32            blacklist: &["<p>"],
33            whitelist: &["Orcax"],
34        }
35    }
36}
37
38/// 字符串验证函数
39pub fn is_valid_string(text: &str) -> bool {
40    let text = text.trim();
41    
42    if text.is_empty() {
43        return false;
44    }
45    
46    let config = StringValidationConfig::new();
47    
48    // 黑名单检查
49    if config.blacklist.contains(&text) {
50        return false;
51    }
52    
53    // 白名单检查
54    if is_whitelisted(text, &config) {
55        return true;
56    }
57    
58    // 检查是否为变量名格式
59    if is_variable_name(text) {
60        return false;
61    }
62    
63    // 检查字符有效性
64    text.chars().all(|c| !c.is_control() || c.is_whitespace())
65}
66
67/// 检查是否在白名单中
68fn is_whitelisted(text: &str, config: &StringValidationConfig) -> bool {
69    config.whitelist.iter().any(|&w| text.contains(w)) || text.contains("<Alias")
70}
71
72/// 检查是否为变量名格式(驼峰或下划线)
73fn is_variable_name(text: &str) -> bool {
74    is_camel_case(text) || is_snake_case(text)
75}
76
77/// 检查是否为驼峰命名
78fn is_camel_case(text: &str) -> bool {
79    if text.len() < 3 || !text.chars().all(|c| c.is_ascii_alphanumeric()) {
80        return false;
81    }
82    
83    let has_uppercase = text.chars().skip(2).any(|c| c.is_ascii_uppercase());
84    let not_all_uppercase = !text.chars().all(|c| c.is_ascii_uppercase());
85    
86    has_uppercase && not_all_uppercase
87}
88
89/// 检查是否为下划线命名
90fn is_snake_case(text: &str) -> bool {
91    !text.contains(' ') && text.contains('_')
92}
93
94/// 创建文件备份
95pub fn create_backup(file_path: &Path) -> Result<std::path::PathBuf, EspError> {
96    if !file_path.exists() {
97        return Err(EspError::IoError(std::io::Error::new(
98            std::io::ErrorKind::NotFound,
99            "原文件不存在"
100        )));
101    }
102    
103    let timestamp = chrono::Local::now().format("%Y-%m-%d-%H-%M-%S");
104    let backup_path = file_path.with_extension(format!("{}.bak", timestamp));
105    
106    std::fs::copy(file_path, &backup_path)
107        .map_err(EspError::IoError)?;
108    
109    Ok(backup_path)
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115    
116    #[test]
117    fn test_string_validation() {
118        // 有效字符串
119        assert!(is_valid_string("Iron Sword"));
120        assert!(is_valid_string("This is a valid description."));
121        assert!(is_valid_string("铁剑"));
122        assert!(is_valid_string("这是一个有效的描述。"));
123        assert!(is_valid_string("Mixed 中英文 text"));
124        
125        // 无效字符串
126        assert!(!is_valid_string("CamelCaseVariable"));
127        assert!(!is_valid_string("snake_case_var"));
128        assert!(!is_valid_string(""));
129        assert!(!is_valid_string("<p>"));
130    }
131    
132    #[test]
133    fn test_camel_case() {
134        assert!(is_camel_case("CamelCase"));
135        assert!(is_camel_case("myVariable"));
136        assert!(!is_camel_case("lowercase"));
137        assert!(!is_camel_case("UPPERCASE"));
138        assert!(!is_camel_case("my"));
139    }
140    
141    #[test]
142    fn test_snake_case() {
143        assert!(is_snake_case("snake_case"));
144        assert!(is_snake_case("my_variable"));
145        assert!(!is_snake_case("normal text"));
146        assert!(!is_snake_case("CamelCase"));
147    }
148}