Skip to main content

css_ast/rules/
property.rs

1use super::prelude::*;
2#[cfg(feature = "visitable")]
3use crate::visit::{NodeId, QueryableNode};
4
5/// <https://drafts.css-houdini.org/css-properties-values-api/#at-property-rule>
6#[node]
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(block)]
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#[node]
35#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
37#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
38#[derive(csskit_derives::NodeWithMetadata)]
39pub struct PropertyPrelude(T![DashedIdent]);
40
41impl PropertyPrelude {
42	/// Returns a cursor to the dashed identifier (e.g., `--my-color`).
43	pub fn ident(&self) -> Cursor {
44		self.0.into()
45	}
46}
47
48#[node]
49#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
50#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
51#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
52#[derive(csskit_derives::NodeWithMetadata)]
53pub struct PropertyRuleBlock<'a>(DeclarationList<'a, PropertyRuleStyleValue<'a>, CssMetadata>);
54
55#[node]
56#[derive(ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
57#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
58#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
59pub enum PropertyRuleStyleValue<'a> {
60	InitialValue(ComponentValues<'a>),
61	Syntax(SyntaxValue),
62	Inherits(InheritsValue),
63	Unknown(ComponentValues<'a>),
64}
65
66#[node]
67#[derive(
68	Parse, Peek, IntoCursor, ToSpan, SemanticEq, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
69)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
71#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
72#[derive(csskit_derives::NodeWithMetadata)]
73pub enum InheritsValue {
74	#[atom(CssAtomSet::True)]
75	True(T![Ident]),
76	#[atom(CssAtomSet::False)]
77	False(T![Ident]),
78}
79
80#[node]
81#[derive(
82	Parse, Peek, ToCursors, IntoCursor, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
83)]
84#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
85#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
86#[derive(csskit_derives::NodeWithMetadata)]
87pub struct SyntaxValue(T![String]);
88
89impl<'a, M: NodeMetadata> DeclarationValue<'a, M> for PropertyRuleStyleValue<'a> {
90	fn valid_declaration_name<I>(p: &Parser<'a, I>, c: Cursor) -> bool
91	where
92		I: Iterator<Item = Cursor> + Clone,
93	{
94		matches!(p.to_atom::<CssAtomSet>(c), CssAtomSet::InitialValue | CssAtomSet::Inherits | CssAtomSet::Syntax)
95	}
96
97	fn is_unknown(&self) -> bool {
98		matches!(self, Self::Unknown(_))
99	}
100
101	fn needs_computing(&self) -> bool {
102		matches!(self, Self::Unknown(_))
103	}
104
105	fn parse_declaration_value<I>(p: &mut Parser<'a, I>, c: Cursor) -> ParserResult<Self>
106	where
107		I: Iterator<Item = Cursor> + Clone,
108	{
109		Ok(match p.to_atom::<CssAtomSet>(c) {
110			CssAtomSet::InitialValue => Self::InitialValue(p.parse::<ComponentValues<'a>>()?),
111			CssAtomSet::Inherits => Self::Inherits(p.parse::<InheritsValue>()?),
112			CssAtomSet::Syntax => Self::Syntax(p.parse::<SyntaxValue>()?),
113			_ => Self::Unknown(p.parse::<ComponentValues<'a>>()?),
114		})
115	}
116}
117
118impl<'a, M: NodeMetadata> NodeWithMetadata<M> for PropertyRuleStyleValue<'a> {
119	fn metadata(&self) -> M {
120		M::default()
121	}
122}
123
124#[cfg(test)]
125mod tests {
126	use super::*;
127	use crate::CssAtomSet;
128	use css_parse::assert_parse;
129
130	#[test]
131	fn test_writes() {
132		assert_parse!(
133			CssAtomSet::ATOMS,
134			PropertyRule,
135			r#"@property --foo{initial-value:0;inherits:false;syntax:"<length>"}"#
136		);
137	}
138}