Coverage Report

Created: 2026-10-28 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lightningcss-1.0.0-alpha.72/src/rules/property.rs
Line
Count
Source
1
//! The `@property` rule.
2
3
use super::Location;
4
#[cfg(feature = "visitor")]
5
use crate::visitor::Visit;
6
use crate::{
7
  error::{ParserError, PrinterError},
8
  printer::Printer,
9
  properties::custom::TokenList,
10
  traits::{Parse, ToCss},
11
  values::{
12
    ident::DashedIdent,
13
    syntax::{ParsedComponent, SyntaxString},
14
  },
15
};
16
use cssparser::*;
17
18
/// A [@property](https://drafts.css-houdini.org/css-properties-values-api/#at-property-rule) rule.
19
#[derive(Debug, PartialEq, Clone)]
20
0
#[cfg_attr(feature = "visitor", derive(Visit))]
Unexecuted instantiation: <lightningcss::rules::property::PropertyRule as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::ValueCollector>>::visit_children
Unexecuted instantiation: <lightningcss::rules::property::PropertyRule as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::FirstRgbColorCollector>>::visit_children
Unexecuted instantiation: <lightningcss::rules::property::PropertyRule as lightningcss::visitor::Visit<_, _>>::visit_children
21
#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
22
#[cfg_attr(
23
  feature = "serde",
24
  derive(serde::Serialize, serde::Deserialize),
25
  serde(rename_all = "camelCase")
26
)]
27
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
28
pub struct PropertyRule<'i> {
29
  /// The name of the custom property to declare.
30
  #[cfg_attr(feature = "serde", serde(borrow))]
31
  pub name: DashedIdent<'i>,
32
  /// A syntax string to specify the grammar for the custom property.
33
  #[cfg_attr(feature = "visitor", skip_visit)]
34
  pub syntax: SyntaxString,
35
  /// Whether the custom property is inherited.
36
  #[cfg_attr(feature = "visitor", skip_visit)]
37
  pub inherits: bool,
38
  /// An optional initial value for the custom property.
39
  #[cfg_attr(feature = "visitor", skip_visit)]
40
  pub initial_value: Option<ParsedComponent<'i>>,
41
  /// The location of the rule in the source file.
42
  #[cfg_attr(feature = "visitor", skip_visit)]
43
  pub loc: Location,
44
}
45
46
impl<'i> PropertyRule<'i> {
47
0
  pub(crate) fn parse<'t>(
48
0
    name: DashedIdent<'i>,
49
0
    input: &mut Parser<'i, 't>,
50
0
    loc: Location,
51
0
  ) -> Result<Self, ParseError<'i, ParserError<'i>>> {
52
0
    let mut parser = PropertyRuleDeclarationParser {
53
0
      syntax: None,
54
0
      inherits: None,
55
0
      initial_value: None,
56
0
    };
57
58
0
    let mut decl_parser = RuleBodyParser::new(input, &mut parser);
59
0
    while let Some(decl) = decl_parser.next() {
60
0
      match decl {
61
0
        Ok(()) => {}
62
0
        Err((e, _)) => return Err(e),
63
      }
64
    }
65
66
    // `syntax` and `inherits` are always required.
67
0
    let parser = decl_parser.parser;
68
0
    let syntax = parser
69
0
      .syntax
70
0
      .clone()
71
0
      .ok_or(decl_parser.input.new_custom_error(ParserError::AtRuleBodyInvalid))?;
72
0
    let inherits = parser
73
0
      .inherits
74
0
      .clone()
75
0
      .ok_or(decl_parser.input.new_custom_error(ParserError::AtRuleBodyInvalid))?;
76
77
    // `initial-value` is required unless the syntax is a universal definition.
78
0
    let initial_value = match syntax {
79
0
      SyntaxString::Universal => match parser.initial_value {
80
0
        None => None,
81
0
        Some(val) => {
82
0
          let mut input = ParserInput::new(val);
83
0
          let mut parser = Parser::new(&mut input);
84
85
0
          if parser.is_exhausted() {
86
0
            Some(ParsedComponent::TokenList(TokenList(vec![])))
87
          } else {
88
0
            Some(syntax.parse_value(&mut parser)?)
89
          }
90
        }
91
      },
92
      _ => {
93
0
        let val = parser
94
0
          .initial_value
95
0
          .ok_or(input.new_custom_error(ParserError::AtRuleBodyInvalid))?;
96
0
        let mut input = ParserInput::new(val);
97
0
        let mut parser = Parser::new(&mut input);
98
0
        Some(syntax.parse_value(&mut parser)?)
99
      }
100
    };
101
102
0
    return Ok(PropertyRule {
103
0
      name,
104
0
      syntax,
105
0
      inherits,
106
0
      initial_value,
107
0
      loc,
108
0
    });
109
0
  }
110
}
111
112
impl<'i> ToCss for PropertyRule<'i> {
113
0
  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
114
0
  where
115
0
    W: std::fmt::Write,
116
  {
117
    #[cfg(feature = "sourcemap")]
118
    dest.add_mapping(self.loc);
119
0
    dest.write_str("@property ")?;
120
0
    self.name.to_css(dest)?;
121
0
    dest.whitespace()?;
122
0
    dest.write_char('{')?;
123
0
    dest.indent();
124
0
    dest.newline()?;
125
126
0
    dest.write_str("syntax:")?;
127
0
    dest.whitespace()?;
128
0
    self.syntax.to_css(dest)?;
129
0
    dest.write_char(';')?;
130
0
    dest.newline()?;
131
132
0
    dest.write_str("inherits:")?;
133
0
    dest.whitespace()?;
134
0
    match self.inherits {
135
0
      true => dest.write_str("true")?,
136
0
      false => dest.write_str("false")?,
137
    }
138
139
0
    if let Some(initial_value) = &self.initial_value {
140
0
      dest.write_char(';')?;
141
0
      dest.newline()?;
142
143
0
      dest.write_str("initial-value:")?;
144
0
      dest.whitespace()?;
145
0
      initial_value.to_css(dest)?;
146
147
0
      if !dest.minify {
148
0
        dest.write_char(';')?;
149
0
      }
150
0
    }
151
152
0
    dest.dedent();
153
0
    dest.newline()?;
154
0
    dest.write_char('}')
155
0
  }
156
}
157
158
pub(crate) struct PropertyRuleDeclarationParser<'i> {
159
  syntax: Option<SyntaxString>,
160
  inherits: Option<bool>,
161
  initial_value: Option<&'i str>,
162
}
163
164
impl<'i> cssparser::DeclarationParser<'i> for PropertyRuleDeclarationParser<'i> {
165
  type Declaration = ();
166
  type Error = ParserError<'i>;
167
168
0
  fn parse_value<'t>(
169
0
    &mut self,
170
0
    name: CowRcStr<'i>,
171
0
    input: &mut cssparser::Parser<'i, 't>,
172
0
    _declaration_start: &ParserState,
173
0
  ) -> Result<Self::Declaration, cssparser::ParseError<'i, Self::Error>> {
174
0
    match_ignore_ascii_case! { &name,
175
0
      "syntax" => {
176
0
        let syntax = SyntaxString::parse(input)?;
177
0
        self.syntax = Some(syntax);
178
      },
179
0
      "inherits" => {
180
0
        let location = input.current_source_location();
181
0
        let ident = input.expect_ident()?;
182
0
        let inherits = match_ignore_ascii_case! {&*ident,
183
0
          "true" => true,
184
0
          "false" => false,
185
0
          _ => return Err(location.new_unexpected_token_error(
186
0
            cssparser::Token::Ident(ident.clone())
187
0
          ))
188
        };
189
0
        self.inherits = Some(inherits);
190
      },
191
0
      "initial-value" => {
192
        // Buffer the value into a string. We will parse it later.
193
0
        let start = input.position();
194
0
        while input.next().is_ok() {}
195
0
        let initial_value = input.slice_from(start);
196
0
        self.initial_value = Some(initial_value);
197
      },
198
0
      _ => return Err(input.new_custom_error(ParserError::InvalidDeclaration))
199
    }
200
201
0
    return Ok(());
202
0
  }
203
}
204
205
/// Default methods reject all at rules.
206
impl<'i> AtRuleParser<'i> for PropertyRuleDeclarationParser<'i> {
207
  type Prelude = ();
208
  type AtRule = ();
209
  type Error = ParserError<'i>;
210
}
211
212
impl<'i> QualifiedRuleParser<'i> for PropertyRuleDeclarationParser<'i> {
213
  type Prelude = ();
214
  type QualifiedRule = ();
215
  type Error = ParserError<'i>;
216
}
217
218
impl<'i> RuleBodyItemParser<'i, (), ParserError<'i>> for PropertyRuleDeclarationParser<'i> {
219
0
  fn parse_qualified(&self) -> bool {
220
0
    false
221
0
  }
222
223
0
  fn parse_declarations(&self) -> bool {
224
0
    true
225
0
  }
226
}