css_ast/functions/
target_functions.rs

1use super::prelude::*;
2use crate::{CssAtomSet, types::CounterStyle};
3
4#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
6#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(skip))]
7#[derive(csskit_derives::NodeWithMetadata)]
8pub enum TextFunctionContent {
9	#[atom(CssAtomSet::Content)]
10	Content(T![Ident]),
11	#[atom(CssAtomSet::Before)]
12	Before(T![Ident]),
13	#[atom(CssAtomSet::After)]
14	After(T![Ident]),
15	#[atom(CssAtomSet::FirstLetter)]
16	FirstLetter(T![Ident]),
17}
18
19#[derive(Parse, Peek, ToCursors, IntoCursor, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
21pub enum TargetCounterKind {
22	String(T![String]),
23	Url(T![Url]),
24}
25
26/// <https://drafts.csswg.org/css-content-3/#typedef-target>
27///
28/// ```text,ignore
29/// <target> = <target-counter()> | <target-counters()> | <target-text()>
30/// ```
31#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
33#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
34#[derive(csskit_derives::NodeWithMetadata)]
35pub enum Target<'a> {
36	// https://drafts.csswg.org/css-content-3/#target-counter
37	// target-counter() = target-counter( [ <string> | <url> ] , <custom-ident> , <counter-style>? )
38	TargetCounter(TargetCounterFunction<'a>),
39	// https://drafts.csswg.org/css-content-3/#target-counters
40	// target-counters() = target-counters( [ <string> | <url> ] , <custom-ident> , <string> , <counter-style>? )
41	TargetCounters(TargetCountersFunction<'a>),
42	// https://drafts.csswg.org/css-content-3/#target-text
43	// target-text() = target-text( [ <string> | <url> ] , [ content | before | after | first-letter ]? )
44	TargetText(TargetTextFunction),
45}
46
47#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
49#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
50#[derive(csskit_derives::NodeWithMetadata)]
51pub struct TargetCounterFunction<'a> {
52	#[atom(CssAtomSet::TargetCounter)]
53	pub name: T![Function],
54	pub params: TargetCounterParams<'a>,
55	pub close: T![')'],
56}
57
58#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
59#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
60pub struct TargetCounterParams<'a>(
61	TargetCounterKind,
62	Option<T![,]>,
63	T![Ident],
64	Option<T![,]>,
65	Option<CounterStyle<'a>>,
66);
67
68#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
70#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
71#[derive(csskit_derives::NodeWithMetadata)]
72pub struct TargetCountersFunction<'a> {
73	#[atom(CssAtomSet::TargetCounters)]
74	pub name: T![Function],
75	pub params: TargetCountersParams<'a>,
76	pub close: T![')'],
77}
78
79#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
80#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
81pub struct TargetCountersParams<'a>(
82	TargetCounterKind,
83	Option<T![,]>,
84	T![Ident],
85	Option<T![,]>,
86	T![String],
87	Option<T![,]>,
88	Option<CounterStyle<'a>>,
89);
90
91#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
92#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
93#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
94#[derive(csskit_derives::NodeWithMetadata)]
95pub struct TargetTextFunction {
96	#[atom(CssAtomSet::TargetText)]
97	pub name: T![Function],
98	pub params: TargetTextParams,
99	pub close: T![')'],
100}
101
102#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
104pub struct TargetTextParams(TargetCounterKind, Option<T![,]>, Option<TextFunctionContent>);
105
106#[cfg(test)]
107mod tests {
108	use super::*;
109	use crate::CssAtomSet;
110	use css_parse::{assert_parse, assert_parse_error};
111
112	#[test]
113	fn size_test() {
114		assert_eq!(std::mem::size_of::<Target>(), 184);
115	}
116
117	#[test]
118	fn test_writes() {
119		assert_parse!(CssAtomSet::ATOMS, Target, "target-counter('foo',bar,lower-roman)");
120		assert_parse!(CssAtomSet::ATOMS, Target, "target-counters('foo',bar,'baz',lower-roman)");
121		assert_parse!(CssAtomSet::ATOMS, Target, "target-text('foo')");
122		assert_parse!(CssAtomSet::ATOMS, Target, "target-text('foo',before)");
123	}
124
125	#[test]
126	fn test_errors() {
127		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counter()");
128		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counter('foo')");
129		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counters()");
130		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counters('foo')");
131		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counters('foo',bar)");
132		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-text()");
133		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-text(123)");
134	}
135}