css_ast/rules/
document.rs

1use css_parse::{
2	AtRule, CommaSeparated, Parse, Parser, Result as ParserResult, RuleList, T, atkeyword_set, function_set,
3};
4use csskit_derives::{Parse, Peek, ToCursors, ToSpan, Visitable};
5
6use crate::stylesheet::Rule;
7
8atkeyword_set!(pub struct AtDocumentKeyword "document");
9
10// https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#at-document
11#[derive(Parse, Peek, ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
13#[visit]
14pub struct DocumentRule<'a>(pub AtRule<AtDocumentKeyword, DocumentMatcherList<'a>, DocumentRuleBlock<'a>>);
15
16#[derive(Parse, Peek, ToCursors, ToSpan, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
18pub struct DocumentMatcherList<'a>(pub CommaSeparated<'a, DocumentMatcher>);
19
20function_set!(
21	pub enum DocumentMatcherFunctionKeyword {
22		Url: "url",
23		UrlPrefix: "url-prefix",
24		Domain: "domain",
25		MediaDocument: "media-document",
26		Regexp: "regexp",
27	}
28);
29
30#[derive(Peek, ToCursors, ToSpan, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
32#[visit(self)]
33pub enum DocumentMatcher {
34	Url(T![Url]),
35	UrlFunction(T![Function], T![String], T![')']),
36	UrlPrefix(T![Function], T![String], T![')']),
37	Domain(T![Function], T![String], T![')']),
38	MediaDocument(T![Function], T![String], T![')']),
39	Regexp(T![Function], T![String], T![')']),
40}
41
42impl<'a> Parse<'a> for DocumentMatcher {
43	fn parse(p: &mut Parser<'a>) -> ParserResult<Self> {
44		if p.peek::<T![Url]>() {
45			Ok(Self::Url(p.parse::<T![Url]>()?))
46		} else {
47			match p.parse::<DocumentMatcherFunctionKeyword>()? {
48				DocumentMatcherFunctionKeyword::Url(function) => {
49					let string = p.parse::<T![String]>()?;
50					let close = p.parse::<T![')']>()?;
51					Ok(Self::UrlFunction(function, string, close))
52				}
53				DocumentMatcherFunctionKeyword::UrlPrefix(function) => {
54					let string = p.parse::<T![String]>()?;
55					let close = p.parse::<T![')']>()?;
56					Ok(Self::UrlPrefix(function, string, close))
57				}
58				DocumentMatcherFunctionKeyword::Domain(function) => {
59					let string = p.parse::<T![String]>()?;
60					let close = p.parse::<T![')']>()?;
61					Ok(Self::UrlPrefix(function, string, close))
62				}
63				DocumentMatcherFunctionKeyword::MediaDocument(function) => {
64					let string = p.parse::<T![String]>()?;
65					let close = p.parse::<T![')']>()?;
66					Ok(Self::UrlPrefix(function, string, close))
67				}
68				DocumentMatcherFunctionKeyword::Regexp(function) => {
69					let string = p.parse::<T![String]>()?;
70					let close = p.parse::<T![')']>()?;
71					Ok(Self::UrlPrefix(function, string, close))
72				}
73			}
74		}
75	}
76}
77
78#[derive(Parse, Peek, ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
80pub struct DocumentRuleBlock<'a>(RuleList<'a, Rule<'a>>);
81
82#[cfg(test)]
83mod tests {
84	use super::*;
85	use css_parse::assert_parse;
86
87	#[test]
88	fn size_test() {
89		assert_eq!(std::mem::size_of::<DocumentRule>(), 128);
90		assert_eq!(std::mem::size_of::<DocumentMatcher>(), 40);
91		assert_eq!(std::mem::size_of::<DocumentRuleBlock>(), 64);
92	}
93
94	#[test]
95	fn test_writes() {
96		assert_parse!(DocumentRule, r#"@document url("http://www.w3.org"){}"#);
97		assert_parse!(DocumentRule, r#"@document domain("mozilla.org"){}"#);
98		assert_parse!(DocumentRule, r#"@document url-prefix("http://www.w3.org/Style/"){}"#);
99		assert_parse!(DocumentRule, r#"@document media-document("video"){}"#);
100		assert_parse!(DocumentRule, r#"@document regexp("https:.*"){}"#);
101		assert_parse!(
102			DocumentRule,
103			r#"@document url(http://www.w3.org),url-prefix("http://www.w3.org/Style/"),domain("mozilla.org"){}"#
104		);
105		assert_parse!(
106			DocumentRule,
107			r#"@document url(http://www.w3.org),url-prefix("http://www.w3.org/Style/"),domain("mozilla.org"){body{color:black}}"#
108		);
109	}
110}