1use super::prelude::*;
2use crate::{CssAtomSet, types::CounterStyle};
3use css_parse::Box;
4
5#[node]
6#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
8#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(skip))]
9#[derive(csskit_derives::NodeWithMetadata)]
10pub enum TextFunctionContent {
11 #[atom(CssAtomSet::Content)]
12 Content(T![Ident]),
13 #[atom(CssAtomSet::Before)]
14 Before(T![Ident]),
15 #[atom(CssAtomSet::After)]
16 After(T![Ident]),
17 #[atom(CssAtomSet::FirstLetter)]
18 FirstLetter(T![Ident]),
19}
20
21#[derive(
22 Parse, Peek, ToCursors, IntoCursor, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
23)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
25#[derive(csskit_derives::NodeWithMetadata)]
26pub enum TargetCounterKind {
27 String(T![String]),
28 Url(T![Url]),
29}
30
31#[node]
37#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
39#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
40#[derive(csskit_derives::NodeWithMetadata)]
41pub enum Target<'a> {
42 TargetCounter(Box<'a, TargetCounterFunction<'a>>),
48 TargetCounters(Box<'a, TargetCountersFunction<'a>>),
54 TargetText(TargetTextFunction),
60}
61
62#[node]
63#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
64#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
65#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
66#[derive(csskit_derives::NodeWithMetadata)]
67pub struct TargetCounterFunction<'a> {
68 #[atom(CssAtomSet::TargetCounter)]
69 pub name: T![Function],
70 pub params: TargetCounterParams<'a>,
71 #[semantic_eq(skip)]
72 pub close: T![')'],
73}
74
75#[node]
76#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
77#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
78#[derive(csskit_derives::NodeWithMetadata)]
79pub struct TargetCounterParams<'a>(
80 TargetCounterKind,
81 #[semantic_eq(skip)] Option<T![,]>,
82 T![Ident],
83 #[semantic_eq(skip)] Option<T![,]>,
84 Option<CounterStyle<'a>>,
85);
86
87#[node]
88#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
90#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
91#[derive(csskit_derives::NodeWithMetadata)]
92pub struct TargetCountersFunction<'a> {
93 #[atom(CssAtomSet::TargetCounters)]
94 pub name: T![Function],
95 pub params: TargetCountersParams<'a>,
96 #[semantic_eq(skip)]
97 pub close: T![')'],
98}
99
100#[node]
101#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
103#[derive(csskit_derives::NodeWithMetadata)]
104pub struct TargetCountersParams<'a>(
105 TargetCounterKind,
106 #[semantic_eq(skip)] Option<T![,]>,
107 T![Ident],
108 #[semantic_eq(skip)] Option<T![,]>,
109 T![String],
110 #[semantic_eq(skip)] Option<T![,]>,
111 Option<CounterStyle<'a>>,
112);
113
114#[node]
115#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
116#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
117#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
118#[derive(csskit_derives::NodeWithMetadata)]
119pub struct TargetTextFunction {
120 #[atom(CssAtomSet::TargetText)]
121 pub name: T![Function],
122 pub params: TargetTextParams,
123 #[semantic_eq(skip)]
124 pub close: T![')'],
125}
126
127#[node]
128#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
129#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
130#[derive(csskit_derives::NodeWithMetadata)]
131pub struct TargetTextParams(TargetCounterKind, #[semantic_eq(skip)] Option<T![,]>, Option<TextFunctionContent>);
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use crate::CssAtomSet;
137 use css_parse::{assert_parse, assert_parse_error};
138
139 #[test]
140 fn test_writes() {
141 assert_parse!(CssAtomSet::ATOMS, Target, "target-counter('foo',bar,lower-roman)");
142 assert_parse!(CssAtomSet::ATOMS, Target, "target-counters('foo',bar,'baz',lower-roman)");
143 assert_parse!(CssAtomSet::ATOMS, Target, "target-text('foo')");
144 assert_parse!(CssAtomSet::ATOMS, Target, "target-text('foo',before)");
145 }
146
147 #[test]
148 fn test_errors() {
149 assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counter()");
150 assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counter('foo')");
151 assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counters()");
152 assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counters('foo')");
153 assert_parse_error!(CssAtomSet::ATOMS, Target, "target-counters('foo',bar)");
154 assert_parse_error!(CssAtomSet::ATOMS, Target, "target-text()");
155 assert_parse_error!(CssAtomSet::ATOMS, Target, "target-text(123)");
156 }
157}