css_parse/traits/
style_sheet.rs

1use crate::{Kind, Parse, Parser, Result, T};
2use bumpalo::collections::Vec;
3
4/// This trait provides an implementation for parsing a [StyleSheet][1].
5///
6/// [1]: https://drafts.csswg.org/css-syntax-3/#parse-stylesheet
7///
8/// It does not implement [Parse], but provides `parse_stylesheet(&mut Parser<'a>) -> Result<...>`, which can make
9/// for a trivial [Parse] implementation. The type [StyleSheet::Rule] must be defined, and represents any Rule allowed
10/// in a style sheet, which is the only top level item of the stylesheet.
11///
12/// StyleSheets are special in that they must discard CdcOrCdo tokens.
13///
14/// The steps `parse_stylesheet` takes can be defined as:
15///
16/// ```md
17/// <style-sheet>
18///  │├─╮─╭─ <ws*> ─╮─╭╮─╭─ <cdcorcdo-token> ─╮─╭─ <rule> ──┤│
19///     │ ╰─────────╯ ││ ╰────────────────────╯ │
20///     ╰─────────────╯╰────────────────────────╯
21/// ```
22///
23pub trait StyleSheet<'a>: Sized + Parse<'a> {
24	type Rule: Parse<'a>;
25
26	fn parse_stylesheet(p: &mut Parser<'a>) -> Result<Vec<'a, Self::Rule>> {
27		let mut rules: Vec<'a, Self::Rule> = Vec::new_in(p.bump());
28		loop {
29			// While by default the parser will skip whitespace, the Rule type may be a whitespace sensitive
30			// node, for example `ComponentValues`. As such whitespace needs to be consumed here, before Declarations and
31			// Rules are parsed.
32			if p.parse_if_peek::<T![' ']>()?.is_some() || p.parse_if_peek::<T![CdcOrCdo]>()?.is_some() {
33				continue;
34			}
35
36			// need to peek as last tokens may be whitespace.
37			if p.at_end() || p.peek_next() == Kind::Eof {
38				return Ok(rules);
39			}
40			rules.push(p.parse::<Self::Rule>()?);
41		}
42	}
43}