Skip to main content

css_ast/functions/
counter_functions.rs

1use super::prelude::*;
2use crate::types::CounterStyle;
3use css_parse::Box;
4
5/// <https://drafts.csswg.org/css-lists-3/#counter-functions>
6///
7/// ```text,ignore
8/// <counter()>  =  counter( <counter-name>, <counter-style>? )
9/// ```
10#[node]
11#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
13#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
14#[derive(csskit_derives::NodeWithMetadata)]
15pub struct CounterFunction<'a> {
16	#[atom(CssAtomSet::Counter)]
17	pub name: T![Function],
18	pub params: CounterFunctionParams<'a>,
19	#[semantic_eq(skip)]
20	pub close: T![')'],
21}
22
23#[node]
24#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
26#[derive(csskit_derives::NodeWithMetadata)]
27pub struct CounterFunctionParams<'a>(T![Ident], #[semantic_eq(skip)] Option<T![,]>, Option<CounterStyle<'a>>);
28
29/// <https://drafts.csswg.org/css-lists-3/#counter-functions>
30///
31/// ```text,ignore
32/// <counters()> = counters( <counter-name>, <string>, <counter-style>? )
33/// ```
34#[node]
35#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
37#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
38#[derive(csskit_derives::NodeWithMetadata)]
39pub struct CountersFunction<'a> {
40	#[atom(CssAtomSet::Counters)]
41	pub name: T![Function],
42	pub params: CountersFunctionParams<'a>,
43	#[semantic_eq(skip)]
44	pub close: T![')'],
45}
46
47#[node]
48#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
50#[derive(csskit_derives::NodeWithMetadata)]
51pub struct CountersFunctionParams<'a>(
52	T![Ident],
53	#[semantic_eq(skip)] Option<T![,]>,
54	T![String],
55	#[semantic_eq(skip)] Option<T![,]>,
56	Option<CounterStyle<'a>>,
57);
58
59/// <https://drafts.csswg.org/css-lists-3/#counter-functions>
60///
61/// ```text,ignore
62/// <counter> = <counter()> | <counters()>
63/// ```
64#[node]
65#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
67#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
68#[derive(csskit_derives::NodeWithMetadata)]
69pub enum Counter<'a> {
70	Counter(Box<'a, CounterFunction<'a>>),
71	Counters(Box<'a, CountersFunction<'a>>),
72}
73
74#[cfg(test)]
75mod tests {
76	use super::*;
77	use crate::CssAtomSet;
78	use css_parse::{assert_parse, assert_parse_error};
79
80	#[test]
81	fn test_writes() {
82		assert_parse!(CssAtomSet::ATOMS, Counter, "counter(foo)");
83		assert_parse!(CssAtomSet::ATOMS, Counter, "counter(foo,upper-latin)");
84		assert_parse!(CssAtomSet::ATOMS, Counter, "counters(foo,'bar')");
85		assert_parse!(CssAtomSet::ATOMS, Counter, "counters(foo,'bar',upper-latin)");
86	}
87
88	#[test]
89	fn test_errors() {
90		assert_parse_error!(CssAtomSet::ATOMS, Counter, "counter('bar')");
91		assert_parse_error!(CssAtomSet::ATOMS, Counter, "counters('bar')");
92	}
93}