tailwind_rs_postcss/purger/
class_extractor.rs1use std::collections::HashSet;
4use regex::Regex;
5use super::types::*;
6
7pub struct ClassExtractor {
9 _class_patterns: Vec<String>,
10 css_rule_pattern: Regex,
11}
12
13impl ClassExtractor {
14 pub fn new() -> Self {
16 Self {
17 _class_patterns: Self::get_default_patterns(),
18 css_rule_pattern: Regex::new(r"([^{]+)\s*\{([^}]+)\}").unwrap(),
19 }
20 }
21
22 pub fn extract_classes(&self, css: &str) -> Result<HashSet<String>, PurgeError> {
24 let mut classes = HashSet::new();
25
26 for cap in self.css_rule_pattern.captures_iter(css) {
28 let selector = cap[1].trim();
29 let selector_classes = self.extract_classes_from_selector(selector);
30 classes.extend(selector_classes);
31 }
32
33 Ok(classes)
34 }
35
36 fn extract_classes_from_selector(&self, selector: &str) -> HashSet<String> {
38 let mut classes = HashSet::new();
39
40 let parts: Vec<&str> = selector.split(&[' ', '>', '+', '~', ','][..]).collect();
42
43 for part in parts {
44 let part = part.trim();
45 if part.starts_with('.') {
46 let class_name = part.strip_prefix('.').unwrap_or(part);
48 classes.insert(class_name.to_string());
49 }
50 }
51
52 classes
53 }
54
55 fn get_default_patterns() -> Vec<String> {
57 vec![
58 r"\.([a-zA-Z0-9_-]+)".to_string(),
59 "class\\s*=\\s*[\"']([^\"']+)[\"']".to_string(),
60 ]
61 }
62}