pest_css_parser/stylesheet/
mod.rs

1use pest::{Parser, iterators::{Pairs, Pair}};
2
3use crate::{grammar::Grammar, Rule, Result};
4
5use self::constants::COLORS;
6pub use self::rule::*;
7
8mod rule;
9mod constants;
10
11#[derive(Debug, Default, Clone)]
12pub struct StyleSheet {
13    pub rules: Vec<CssRule>,
14    pub errors: Vec<String>,
15}
16
17impl StyleSheet {
18    pub fn parse(input: &str) -> Result<Self> {
19        let pairs = Grammar::parse(Rule::css, input).unwrap_or_else(|e| panic!("{}", e));
20
21        Self::build_stylesheet(pairs)
22    }
23
24    fn build_stylesheet(pairs: Pairs<Rule>) -> Result<Self> {
25        let mut stylesheet = StyleSheet::default();
26
27        for pair in pairs {
28            match pair.as_rule() {
29                Rule::rule_comment => {
30                    stylesheet
31                        .rules.push(CssRule::Comment(pair.into_inner().as_str().to_string()));
32                },
33                Rule::rule_normal => match Self::build_normal_rule(pair) {
34                    Ok(rule) => {
35                        let normal_rule = CssRule::Normal(rule);
36                        stylesheet.rules.push(normal_rule);
37                    }
38                    Err(error) => {
39                        stylesheet.errors.push(error.to_string());
40                    }
41                }
42                _ => {}
43            }
44        }
45
46        Ok(stylesheet)
47    }
48
49    fn build_normal_rule(pair: Pair<Rule>) -> Result<NormalRule> {
50        let mut normal_rule = NormalRule::default();
51        
52        for pair in pair.into_inner() {
53            match pair.as_rule() {
54                Rule::sel_normal => {
55                    normal_rule.selectors.push(Self::build_simple_selector(pair.into_inner())?);
56                }
57                Rule::declaration => {
58                    let del = Self::build_declaration(pair.into_inner())?;
59                    normal_rule.declarations.insert(del.0, del.1);
60                }
61                _ => {}
62            }
63        }
64
65        Ok(normal_rule)
66    }
67
68    fn build_simple_selector(pairs: Pairs<Rule>) -> Result<Selector> {
69        let mut selector = SimpleSelector::default();
70
71        for pair in pairs {
72            match pair.as_rule() {
73                Rule::sel_id_body => selector.id = Some(pair.as_str().to_string()),
74                Rule::sel_class_body => selector.class.push(pair.as_str().to_string()),
75                Rule::sel_type => selector.tag_name = Some(pair.as_str().to_string()),
76                _ => {}
77            }
78        }
79
80        Ok(Selector::Simple(selector))
81    }
82
83    fn build_declaration(pairs: Pairs<Rule>) -> Result<(String, Value)> {
84        let mut declaration = (String::default(), Value::StringLiteral(String::default()));
85
86        for pair in pairs {
87            match pair.as_rule() {
88                Rule::del_property => declaration.0 = pair.as_str().to_string(),
89                Rule::del_val_keyword => {
90                    let colors = COLORS.lock().unwrap();
91                    if let Some(color) = colors.get(pair.as_str()) {
92                        declaration.1 = Value::Color(*color)
93                    } else {
94                        declaration.1 = Value::Keyword(pair.as_str().to_string())
95                    }
96                },
97                Rule::del_val_length => {
98                    let mut inner_pairs = pair.into_inner();
99                    let len_value = inner_pairs.next().unwrap();
100                    let len_type = inner_pairs.next().unwrap();
101
102                    declaration.1 = Value::Length(
103                        len_value.as_str().parse().unwrap(),
104                        Unit::from(len_type.as_str())
105                    );
106                }
107                Rule::del_val_color => declaration.1 = Value::Color(Color::from_hex(pair.as_str())),
108                _ => {}
109            }
110        }
111
112        Ok(declaration)
113    }
114}