Skip to main content

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	///
38	/// ```text,ignore
39	/// target-counter() = target-counter( [ <string> | <url> ] , <custom-ident> , <counter-style>? )
40	/// ```
41	TargetCounter(TargetCounterFunction<'a>),
42	/// <https://drafts.csswg.org/css-content-3/#target-counters>
43	///
44	/// ```text,ignore
45	/// target-counters() = target-counters( [ <string> | <url> ] , <custom-ident> , <string> , <counter-style>? )
46	/// ```
47	TargetCounters(TargetCountersFunction<'a>),
48	/// <https://drafts.csswg.org/css-content-3/#target-text>
49	///
50	/// ```text,ignore
51	/// target-text() = target-text( [ <string> | <url> ] , [ content | before | after | first-letter ]? )
52	/// ```
53	TargetText(TargetTextFunction),
54}
55
56#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
57#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
58#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
59#[derive(csskit_derives::NodeWithMetadata)]
60pub struct TargetCounterFunction<'a> {
61	#[atom(CssAtomSet::TargetCounter)]
62	pub name: T![Function],
63	pub params: TargetCounterParams<'a>,
64	pub close: T![')'],
65}
66
67#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
69pub struct TargetCounterParams<'a>(
70	TargetCounterKind,
71	Option<T![,]>,
72	T![Ident],
73	Option<T![,]>,
74	Option<CounterStyle<'a>>,
75);
76
77#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
78#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
79#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
80#[derive(csskit_derives::NodeWithMetadata)]
81pub struct TargetCountersFunction<'a> {
82	#[atom(CssAtomSet::TargetCounters)]
83	pub name: T![Function],
84	pub params: TargetCountersParams<'a>,
85	pub close: T![')'],
86}
87
88#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
90pub struct TargetCountersParams<'a>(
91	TargetCounterKind,
92	Option<T![,]>,
93	T![Ident],
94	Option<T![,]>,
95	T![String],
96	Option<T![,]>,
97	Option<CounterStyle<'a>>,
98);
99
100#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
101#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
102#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
103#[derive(csskit_derives::NodeWithMetadata)]
104pub struct TargetTextFunction {
105	#[atom(CssAtomSet::TargetText)]
106	pub name: T![Function],
107	pub params: TargetTextParams,
108	pub close: T![')'],
109}
110
111#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
112#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
113pub struct TargetTextParams(TargetCounterKind, Option<T![,]>, Option<TextFunctionContent>);
114
115#[cfg(test)]
116mod tests {
117	use super::*;
118	use crate::CssAtomSet;
119	use css_parse::{assert_parse, assert_parse_error};
120
121	#[test]
122	fn size_test() {
123		assert_eq!(std::mem::size_of::<Target>(), 184);
124	}
125
126	#[test]
127	fn test_writes() {
128		assert_parse!(CssAtomSet::ATOMS, Target, "target-counter('foo',bar,lower-roman)");
129		assert_parse!(CssAtomSet::ATOMS, Target, "target-counters('foo',bar,'baz',lower-roman)");
130		assert_parse!(CssAtomSet::ATOMS, Target, "target-text('foo')");
131		assert_parse!(CssAtomSet::ATOMS, Target, "target-text('foo',before)");
132	}
133
134	#[test]
135	fn test_errors() {
136		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counter()");
137		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counter('foo')");
138		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counters()");
139		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counters('foo')");
140		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counters('foo',bar)");
141		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-text()");
142		assert_parse_error!(CssAtomSet::ATOMS, Target, "target-text(123)");
143	}
144}