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