1use super::prelude::*;
2use crate::Computed;
3#[cfg(feature = "visitable")]
4use crate::visit::{NodeId, QueryableNode};
5
6#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
9#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit, queryable(skip))]
10#[cfg_attr(feature = "css_feature_data", derive(::csskit_derives::ToCSSFeature), css_feature("css.at-rules.property"))]
11#[derive(csskit_derives::NodeWithMetadata)]
12#[metadata(node_kinds = AtRule, used_at_rules = Property, property_kinds = Name)]
13pub struct PropertyRule<'a> {
14 #[cfg_attr(feature = "visitable", visit(skip))]
15 #[atom(CssAtomSet::Property)]
16 pub name: T![AtKeyword],
17 pub prelude: PropertyPrelude,
18 #[metadata(delegate)]
19 pub block: PropertyRuleBlock<'a>,
20}
21
22#[cfg(feature = "visitable")]
23impl<'a> QueryableNode for PropertyRule<'a> {
24 const NODE_ID: NodeId = NodeId::PropertyRule;
25
26 fn get_property(&self, kind: PropertyKind) -> Option<Cursor> {
27 match kind {
28 PropertyKind::Name => Some(self.prelude.ident()),
29 _ => None,
30 }
31 }
32}
33
34#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
36#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
37#[derive(csskit_derives::NodeWithMetadata)]
38pub struct PropertyPrelude(T![DashedIdent]);
39
40impl PropertyPrelude {
41 pub fn ident(&self) -> Cursor {
43 self.0.into()
44 }
45}
46
47#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
49#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
50#[derive(csskit_derives::NodeWithMetadata)]
51pub struct PropertyRuleBlock<'a>(#[metadata(delegate)] DeclarationList<'a, PropertyRuleStyleValue<'a>, CssMetadata>);
52
53#[derive(ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
55#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
56pub enum PropertyRuleStyleValue<'a> {
57 InitialValue(ComponentValues<'a>),
58 Syntax(SyntaxValue),
59 Inherits(InheritsValue),
60 Unknown(ComponentValues<'a>),
61}
62
63#[derive(Parse, Peek, IntoCursor, ToCursors, Debug, Copy, 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 enum InheritsValue {
68 #[atom(CssAtomSet::True)]
69 True(T![Ident]),
70 #[atom(CssAtomSet::False)]
71 False(T![Ident]),
72}
73
74#[derive(Parse, Peek, ToCursors, IntoCursor, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
75#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
76#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
77#[derive(csskit_derives::NodeWithMetadata)]
78pub struct SyntaxValue(T![String]);
79
80impl<'a, M: NodeMetadata> DeclarationValue<'a, M> for PropertyRuleStyleValue<'a> {
81 type ComputedValue = Computed<'a>;
82
83 fn valid_declaration_name<I>(p: &Parser<'a, I>, c: Cursor) -> bool
84 where
85 I: Iterator<Item = Cursor> + Clone,
86 {
87 matches!(p.to_atom::<CssAtomSet>(c), CssAtomSet::InitialValue | CssAtomSet::Inherits | CssAtomSet::Syntax)
88 }
89
90 fn is_unknown(&self) -> bool {
91 matches!(self, Self::Unknown(_))
92 }
93
94 fn is_initial(&self) -> bool {
95 false
96 }
97
98 fn is_inherit(&self) -> bool {
99 false
100 }
101
102 fn is_unset(&self) -> bool {
103 false
104 }
105
106 fn is_revert(&self) -> bool {
107 false
108 }
109
110 fn is_revert_layer(&self) -> bool {
111 false
112 }
113
114 fn needs_computing(&self) -> bool {
115 matches!(self, Self::Unknown(_))
116 }
117
118 fn parse_declaration_value<I>(p: &mut Parser<'a, I>, c: Cursor) -> ParserResult<Self>
119 where
120 I: Iterator<Item = Cursor> + Clone,
121 {
122 Ok(match p.to_atom::<CssAtomSet>(c) {
123 CssAtomSet::InitialValue => Self::InitialValue(p.parse::<ComponentValues<'a>>()?),
124 CssAtomSet::Inherits => Self::Inherits(p.parse::<InheritsValue>()?),
125 CssAtomSet::Syntax => Self::Syntax(p.parse::<SyntaxValue>()?),
126 _ => Self::Unknown(p.parse::<ComponentValues<'a>>()?),
127 })
128 }
129}
130
131impl<'a, M: NodeMetadata> NodeWithMetadata<M> for PropertyRuleStyleValue<'a> {
132 fn metadata(&self) -> M {
133 M::default()
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140 use crate::CssAtomSet;
141 use css_parse::assert_parse;
142
143 #[test]
144 fn size_test() {
145 assert_eq!(std::mem::size_of::<PropertyRule>(), 128);
146 }
147
148 #[test]
149 fn test_writes() {
150 assert_parse!(
151 CssAtomSet::ATOMS,
152 PropertyRule,
153 r#"@property --foo{initial-value:0;inherits:false;syntax:"<length>"}"#
154 );
155 }
156}