1use css_parse::{Function, T, function_set, keyword_set};
2use csskit_derives::{IntoCursor, Parse, Peek, ToCursors, ToSpan, Visitable};
3
4use crate::types::CounterStyle;
5
6keyword_set!(
7 pub enum TextFunctionContent {
8 Content: "content",
9 Before: "before",
10 After: "after",
11 FirstLetter: "first-letter"
12 }
13);
14
15#[derive(Parse, Peek, ToCursors, IntoCursor, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
17pub enum TargetCounterKind {
18 String(T![String]),
19 Url(T![Url]),
20}
21
22#[derive(Parse, Peek, ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
29#[visit]
30pub enum Target<'a> {
31 TargetCounter(TargetCounterFunction<'a>),
34 TargetCounters(TargetCountersFunction<'a>),
37 TargetText(TargetTextFunction),
40}
41
42function_set!(pub struct TargetCounterFunctionName "target-counter");
43
44#[derive(Parse, Peek, ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
46#[visit(self)]
47pub struct TargetCounterFunction<'a>(Function<TargetCounterFunctionName, TargetCounterParams<'a>>);
48
49#[derive(Parse, Peek, ToSpan, ToCursors, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
50#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
51pub struct TargetCounterParams<'a>(
52 TargetCounterKind,
53 Option<T![,]>,
54 T![Ident],
55 Option<T![,]>,
56 Option<CounterStyle<'a>>,
57);
58
59function_set!(pub struct TargetCountersFunctionName "target-counters");
60
61#[derive(Parse, Peek, ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
62#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
63#[visit(self)]
64pub struct TargetCountersFunction<'a>(Function<TargetCountersFunctionName, TargetCountersParams<'a>>);
65
66#[derive(Parse, Peek, ToSpan, ToCursors, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
67#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
68pub struct TargetCountersParams<'a>(
69 TargetCounterKind,
70 Option<T![,]>,
71 T![Ident],
72 Option<T![,]>,
73 T![String],
74 Option<T![,]>,
75 Option<CounterStyle<'a>>,
76);
77
78function_set!(pub struct TargetTextFunctionName "target-text");
79
80#[derive(Parse, Peek, ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
82#[visit(self)]
83pub struct TargetTextFunction(Function<TargetTextFunctionName, TargetTextParams>);
84
85#[derive(Parse, Peek, ToSpan, ToCursors, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
86#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
87pub struct TargetTextParams(TargetCounterKind, Option<T![,]>, Option<TextFunctionContent>);
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use css_parse::{assert_parse, assert_parse_error};
93
94 #[test]
95 fn size_test() {
96 assert_eq!(std::mem::size_of::<Target>(), 200);
97 }
98
99 #[test]
100 fn test_writes() {
101 assert_parse!(Target, "target-counter('foo',bar,lower-roman)");
102 assert_parse!(Target, "target-counters('foo',bar,'baz',lower-roman)");
103 assert_parse!(Target, "target-text('foo')");
104 assert_parse!(Target, "target-text('foo',before)");
105 }
106
107 #[test]
108 fn test_errors() {
109 assert_parse_error!(Target, "target-counter()");
110 assert_parse_error!(Target, "target-counter('foo')");
111 assert_parse_error!(Target, "target-counters()");
112 assert_parse_error!(Target, "target-counters('foo')");
113 assert_parse_error!(Target, "target-counters('foo',bar)");
114 assert_parse_error!(Target, "target-text()");
115 assert_parse_error!(Target, "target-text(123)");
116 }
117}