Skip to main content

css_inline/
parser.rs

1use cssparser::ParserState;
2
3pub(crate) struct CSSRuleListParser<'d, 'i>(&'d mut Vec<Declaration<'i>>);
4
5impl<'d, 'i> CSSRuleListParser<'d, 'i> {
6    #[inline]
7    pub(crate) fn new(declarations: &'d mut Vec<Declaration<'i>>) -> CSSRuleListParser<'d, 'i> {
8        CSSRuleListParser(declarations)
9    }
10}
11
12pub(crate) struct CSSDeclarationListParser;
13
14pub(crate) type Name<'i> = cssparser::CowRcStr<'i>;
15pub(crate) type Declaration<'i> = (Name<'i>, &'i str);
16pub(crate) type QualifiedRule<'i> = (&'i str, (usize, usize));
17
18fn exhaust<'i>(input: &mut cssparser::Parser<'i, '_>) -> &'i str {
19    let start = input.position();
20    while input.next().is_ok() {}
21    input.slice_from(start)
22}
23
24/// Parser for qualified rules - a prelude + a simple {} block.
25///
26/// Usually these rules are a selector + list of declarations: `p { color: blue; font-size: 2px }`
27impl<'i> cssparser::QualifiedRuleParser<'i> for CSSRuleListParser<'_, 'i> {
28    type Prelude = &'i str;
29    type QualifiedRule = QualifiedRule<'i>;
30    type Error = ();
31
32    fn parse_prelude<'t>(
33        &mut self,
34        input: &mut cssparser::Parser<'i, 't>,
35    ) -> Result<Self::Prelude, cssparser::ParseError<'i, Self::Error>> {
36        // Proceed with parsing until the end of the prelude.
37        Ok(exhaust(input))
38    }
39
40    fn parse_block<'t>(
41        &mut self,
42        prelude: Self::Prelude,
43        _: &ParserState,
44        input: &mut cssparser::Parser<'i, 't>,
45    ) -> Result<Self::QualifiedRule, cssparser::ParseError<'i, Self::Error>> {
46        Ok((prelude, parse_declarations_into(input, self.0)))
47    }
48}
49
50/// Parse a declaration within {} block: `color: blue`
51impl<'i> cssparser::DeclarationParser<'i> for CSSDeclarationListParser {
52    type Declaration = Declaration<'i>;
53    type Error = ();
54
55    fn parse_value<'t>(
56        &mut self,
57        name: Name<'i>,
58        input: &mut cssparser::Parser<'i, 't>,
59        _declaration_start: &ParserState,
60    ) -> Result<Self::Declaration, cssparser::ParseError<'i, Self::Error>> {
61        Ok((name, exhaust(input)))
62    }
63}
64
65impl<'i> cssparser::AtRuleParser<'i> for CSSRuleListParser<'_, 'i> {
66    type Prelude = &'i str;
67    type AtRule = QualifiedRule<'i>;
68    type Error = ();
69}
70
71/// Parsing for at-rules, e.g: `@charset "utf-8";`
72/// Since they are can not be inlined we use the default implementation, that rejects all at-rules.
73impl<'i> cssparser::AtRuleParser<'i> for CSSDeclarationListParser {
74    type Prelude = String;
75    type AtRule = Declaration<'i>;
76    type Error = ();
77}
78
79impl<'i> cssparser::RuleBodyItemParser<'i, Declaration<'i>, ()> for CSSDeclarationListParser {
80    fn parse_declarations(&self) -> bool {
81        true
82    }
83
84    fn parse_qualified(&self) -> bool {
85        true
86    }
87}
88
89impl<'i> cssparser::QualifiedRuleParser<'i> for CSSDeclarationListParser {
90    type Prelude = String;
91    type QualifiedRule = Declaration<'i>;
92    type Error = ();
93}
94
95pub(crate) struct AtRuleFilteringParser<'d, 'i, 'o> {
96    declarations: &'d mut Vec<Declaration<'i>>,
97    at_rules: &'o mut String,
98}
99
100impl<'d, 'i, 'o> AtRuleFilteringParser<'d, 'i, 'o> {
101    #[inline]
102    pub(crate) fn new(
103        declarations: &'d mut Vec<Declaration<'i>>,
104        at_rules: &'o mut String,
105    ) -> AtRuleFilteringParser<'d, 'i, 'o> {
106        AtRuleFilteringParser {
107            declarations,
108            at_rules,
109        }
110    }
111}
112
113impl<'i> cssparser::QualifiedRuleParser<'i> for AtRuleFilteringParser<'_, 'i, '_> {
114    type Prelude = &'i str;
115    type QualifiedRule = QualifiedRule<'i>;
116    type Error = ();
117
118    fn parse_prelude<'t>(
119        &mut self,
120        input: &mut cssparser::Parser<'i, 't>,
121    ) -> Result<Self::Prelude, cssparser::ParseError<'i, Self::Error>> {
122        Ok(exhaust(input))
123    }
124
125    fn parse_block<'t>(
126        &mut self,
127        prelude: Self::Prelude,
128        _: &ParserState,
129        input: &mut cssparser::Parser<'i, 't>,
130    ) -> Result<Self::QualifiedRule, cssparser::ParseError<'i, Self::Error>> {
131        Ok((prelude, parse_declarations_into(input, self.declarations)))
132    }
133}
134
135impl<'i> cssparser::AtRuleParser<'i> for AtRuleFilteringParser<'_, 'i, '_> {
136    type Prelude = &'i str;
137    type AtRule = QualifiedRule<'i>;
138    type Error = ();
139
140    fn parse_prelude<'t>(
141        &mut self,
142        name: cssparser::CowRcStr<'i>,
143        input: &mut cssparser::Parser<'i, 't>,
144    ) -> Result<Self::Prelude, cssparser::ParseError<'i, Self::Error>> {
145        self.at_rules.push('@');
146        self.at_rules.push_str(&name);
147        Ok(exhaust(input))
148    }
149
150    fn parse_block<'t>(
151        &mut self,
152        prelude: Self::Prelude,
153        _start: &ParserState,
154        input: &mut cssparser::Parser<'i, 't>,
155    ) -> Result<Self::AtRule, cssparser::ParseError<'i, Self::Error>> {
156        let start = self.at_rules.len();
157        self.at_rules.push_str(prelude);
158        self.at_rules.push('{');
159        self.at_rules.push_str(exhaust(input));
160        self.at_rules.push('}');
161        self.at_rules.push(' ');
162        Ok((prelude, (start, self.at_rules.len())))
163    }
164}
165
166fn parse_declarations_into<'i>(
167    input: &mut cssparser::Parser<'i, '_>,
168    declarations: &mut Vec<Declaration<'i>>,
169) -> (usize, usize) {
170    let mut parser = CSSDeclarationListParser;
171    let parser = cssparser::RuleBodyParser::new(input, &mut parser);
172    let start = declarations.len();
173    for item in parser.flatten() {
174        declarations.push(item);
175    }
176    (start, declarations.len())
177}