Skip to main content

css_ast/rules/
property.rs

1use super::prelude::*;
2use crate::Computed;
3#[cfg(feature = "visitable")]
4use crate::visit::{NodeId, QueryableNode};
5
6/// <https://drafts.css-houdini.org/css-properties-values-api/#at-property-rule>
7#[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	/// Returns a cursor to the dashed identifier (e.g., `--my-color`).
42	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(
64	Parse, Peek, IntoCursor, ToSpan, SemanticEq, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
65)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
67#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
68#[derive(csskit_derives::NodeWithMetadata)]
69pub enum InheritsValue {
70	#[atom(CssAtomSet::True)]
71	True(T![Ident]),
72	#[atom(CssAtomSet::False)]
73	False(T![Ident]),
74}
75
76#[derive(
77	Parse, Peek, ToCursors, IntoCursor, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
78)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
80#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
81#[derive(csskit_derives::NodeWithMetadata)]
82pub struct SyntaxValue(T![String]);
83
84impl<'a, M: NodeMetadata> DeclarationValue<'a, M> for PropertyRuleStyleValue<'a> {
85	type ComputedValue = Computed<'a>;
86
87	fn valid_declaration_name<I>(p: &Parser<'a, I>, c: Cursor) -> bool
88	where
89		I: Iterator<Item = Cursor> + Clone,
90	{
91		matches!(p.to_atom::<CssAtomSet>(c), CssAtomSet::InitialValue | CssAtomSet::Inherits | CssAtomSet::Syntax)
92	}
93
94	fn is_unknown(&self) -> bool {
95		matches!(self, Self::Unknown(_))
96	}
97
98	fn is_initial(&self) -> bool {
99		false
100	}
101
102	fn is_inherit(&self) -> bool {
103		false
104	}
105
106	fn is_unset(&self) -> bool {
107		false
108	}
109
110	fn is_revert(&self) -> bool {
111		false
112	}
113
114	fn is_revert_layer(&self) -> bool {
115		false
116	}
117
118	fn needs_computing(&self) -> bool {
119		matches!(self, Self::Unknown(_))
120	}
121
122	fn parse_declaration_value<I>(p: &mut Parser<'a, I>, c: Cursor) -> ParserResult<Self>
123	where
124		I: Iterator<Item = Cursor> + Clone,
125	{
126		Ok(match p.to_atom::<CssAtomSet>(c) {
127			CssAtomSet::InitialValue => Self::InitialValue(p.parse::<ComponentValues<'a>>()?),
128			CssAtomSet::Inherits => Self::Inherits(p.parse::<InheritsValue>()?),
129			CssAtomSet::Syntax => Self::Syntax(p.parse::<SyntaxValue>()?),
130			_ => Self::Unknown(p.parse::<ComponentValues<'a>>()?),
131		})
132	}
133}
134
135impl<'a, M: NodeMetadata> NodeWithMetadata<M> for PropertyRuleStyleValue<'a> {
136	fn metadata(&self) -> M {
137		M::default()
138	}
139}
140
141#[cfg(test)]
142mod tests {
143	use super::*;
144	use crate::CssAtomSet;
145	use css_parse::assert_parse;
146
147	#[test]
148	fn size_test() {
149		assert_eq!(std::mem::size_of::<PropertyRule>(), 128);
150	}
151
152	#[test]
153	fn test_writes() {
154		assert_parse!(
155			CssAtomSet::ATOMS,
156			PropertyRule,
157			r#"@property --foo{initial-value:0;inherits:false;syntax:"<length>"}"#
158		);
159	}
160}