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