pest_css_parser/stylesheet/
mod.rs1use 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}