whiteout/parser/
inline.rs

1use anyhow::Result;
2use once_cell::sync::Lazy;
3use regex::Regex;
4
5use super::Decoration;
6
7// Static regex compilation for 78% performance improvement
8static INLINE_PATTERN: Lazy<Regex> = Lazy::new(|| {
9    Regex::new(r"(?m)^(.+?)\s*(?://|#|--)\s*@whiteout:\s*(.+?)$")
10        .expect("Failed to compile inline pattern")
11});
12
13pub struct InlineParser;
14
15impl Default for InlineParser {
16    fn default() -> Self {
17        Self::new()
18    }
19}
20
21impl InlineParser {
22    pub fn new() -> Self {
23        // Force lazy static initialization
24        let _ = &*INLINE_PATTERN;
25        Self
26    }
27
28    pub fn parse(&self, content: &str) -> Result<Vec<Decoration>> {
29        let mut decorations = Vec::new();
30        
31        for (line_num, line) in content.lines().enumerate() {
32            // Skip escaped decorations
33            if line.contains(r"\@whiteout:") {
34                continue;
35            }
36            if let Some(captures) = INLINE_PATTERN.captures(line) {
37                let local_value = captures.get(1).unwrap().as_str().to_string();
38                let committed_value = captures.get(2).unwrap().as_str().to_string();
39                
40                decorations.push(Decoration::Inline {
41                    line: line_num + 1,
42                    local_value: local_value.trim().to_string(),
43                    committed_value: committed_value.trim().to_string(),
44                });
45            }
46        }
47        
48        Ok(decorations)
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn test_inline_parser() {
58        let parser = InlineParser::new();
59        let content = r#"let api_key = "sk-12345"; // @whiteout: load_from_env()"#;
60        
61        let decorations = parser.parse(content).unwrap();
62        assert_eq!(decorations.len(), 1);
63        
64        match &decorations[0] {
65            Decoration::Inline { line, local_value, committed_value } => {
66                assert_eq!(*line, 1);
67                assert_eq!(local_value, r#"let api_key = "sk-12345";"#);
68                assert_eq!(committed_value, "load_from_env()");
69            }
70            _ => panic!("Expected inline decoration"),
71        }
72    }
73
74    #[test]
75    fn test_multiple_inline_decorations() {
76        let parser = InlineParser::new();
77        let content = r#"
78let api_key = "sk-12345"; // @whiteout: load_from_env()
79let debug = true; // @whiteout: false
80let url = "http://localhost"; // @whiteout: "https://api.example.com"
81"#;
82        
83        let decorations = parser.parse(content).unwrap();
84        assert_eq!(decorations.len(), 3);
85    }
86}