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/values/ident.rs
Line
Count
Source
1
//! CSS identifiers.
2
3
use crate::error::{ParserError, PrinterError};
4
use crate::printer::Printer;
5
use crate::properties::css_modules::Specifier;
6
use crate::traits::{Parse, ParseWithOptions, ToCss};
7
use crate::values::string::CowArcStr;
8
#[cfg(feature = "visitor")]
9
use crate::visitor::Visit;
10
use cssparser::*;
11
use smallvec::SmallVec;
12
use std::borrow::Borrow;
13
use std::ops::Deref;
14
15
use super::string::impl_string_type;
16
17
/// A CSS [`<custom-ident>`](https://www.w3.org/TR/css-values-4/#custom-idents).
18
///
19
/// Custom idents are author defined, and allow any valid identifier except the
20
/// [CSS-wide keywords](https://www.w3.org/TR/css-values-4/#css-wide-keywords).
21
/// They may be renamed to include a hash when compiled as part of a CSS module.
22
#[derive(Debug, Clone, Eq, Hash)]
23
0
#[cfg_attr(feature = "visitor", derive(Visit))]
Unexecuted instantiation: <lightningcss::values::ident::CustomIdent as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::ValueCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::CustomIdent as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::FirstRgbColorCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::CustomIdent as lightningcss::visitor::Visit<_, _>>::visit_children
24
#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
25
#[cfg_attr(feature = "visitor", visit(visit_custom_ident, CUSTOM_IDENTS))]
26
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
27
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
28
pub struct CustomIdent<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub CowArcStr<'i>);
29
30
impl<'i> Parse<'i> for CustomIdent<'i> {
31
138k
  fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
32
138k
    let location = input.current_source_location();
33
138k
    let ident = input.expect_ident()?;
34
97.9k
    let valid = match_ignore_ascii_case! { &ident,
35
97.9k
      "initial" | "inherit" | "unset" | "default" | "revert" | "revert-layer" => false,
36
97.9k
      _ => true
37
    };
38
39
97.9k
    if !valid {
40
18
      return Err(location.new_unexpected_token_error(Token::Ident(ident.clone())));
41
97.9k
    }
42
43
97.9k
    Ok(CustomIdent(ident.into()))
44
138k
  }
45
}
46
47
impl<'i> ToCss for CustomIdent<'i> {
48
0
  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
49
0
  where
50
0
    W: std::fmt::Write,
51
  {
52
0
    self.to_css_with_options(dest, true)
53
0
  }
54
}
55
56
impl<'i> CustomIdent<'i> {
57
  /// Write the custom ident to CSS.
58
0
  pub(crate) fn to_css_with_options<W>(
59
0
    &self,
60
0
    dest: &mut Printer<W>,
61
0
    enabled_css_modules: bool,
62
0
  ) -> Result<(), PrinterError>
63
0
  where
64
0
    W: std::fmt::Write,
65
  {
66
0
    let css_module_custom_idents_enabled = enabled_css_modules
67
0
      && dest
68
0
        .css_module
69
0
        .as_mut()
70
0
        .map_or(false, |css_module| css_module.config.custom_idents);
71
0
    dest.write_ident(&self.0, css_module_custom_idents_enabled)
72
0
  }
73
}
74
75
/// A list of CSS [`<custom-ident>`](https://www.w3.org/TR/css-values-4/#custom-idents) values.
76
pub type CustomIdentList<'i> = SmallVec<[CustomIdent<'i>; 1]>;
77
78
/// The `none` keyword, or a space-separated list of custom idents.
79
#[derive(Debug, Clone, PartialEq, Default)]
80
0
#[cfg_attr(feature = "visitor", derive(Visit))]
Unexecuted instantiation: <lightningcss::values::ident::NoneOrCustomIdentList as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::ValueCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::NoneOrCustomIdentList as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::FirstRgbColorCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::NoneOrCustomIdentList as lightningcss::visitor::Visit<_, _>>::visit_children
81
#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
82
#[cfg_attr(
83
  feature = "serde",
84
  derive(serde::Serialize, serde::Deserialize),
85
  serde(rename_all = "kebab-case")
86
)]
87
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
88
pub enum NoneOrCustomIdentList<'i> {
89
  /// None.
90
  #[default]
91
  None,
92
  /// A list of idents.
93
  #[cfg_attr(feature = "serde", serde(borrow, untagged))]
94
  Idents(SmallVec<[CustomIdent<'i>; 1]>),
95
}
96
97
impl<'i> Parse<'i> for NoneOrCustomIdentList<'i> {
98
14
  fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
99
14
    let mut types = SmallVec::new();
100
    loop {
101
29
      if let Ok(ident) = input.try_parse(CustomIdent::parse) {
102
15
        if ident == "none" {
103
0
          if types.is_empty() {
104
0
            return Ok(NoneOrCustomIdentList::None);
105
          } else {
106
0
            return Err(input.new_custom_error(ParserError::InvalidValue));
107
          }
108
15
        }
109
110
15
        types.push(ident);
111
      } else {
112
14
        return Ok(NoneOrCustomIdentList::Idents(types));
113
      }
114
    }
115
14
  }
116
}
117
118
impl<'i> ToCss for NoneOrCustomIdentList<'i> {
119
0
  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
120
0
  where
121
0
    W: std::fmt::Write,
122
  {
123
0
    match self {
124
0
      NoneOrCustomIdentList::None => dest.write_str("none"),
125
0
      NoneOrCustomIdentList::Idents(types) => {
126
0
        let mut first = true;
127
0
        for ident in types {
128
0
          if !first {
129
0
            dest.write_char(' ')?;
130
0
          } else {
131
0
            first = false;
132
0
          }
133
0
          ident.to_css(dest)?;
134
        }
135
0
        Ok(())
136
      }
137
    }
138
0
  }
139
}
140
141
/// A CSS [`<dashed-ident>`](https://www.w3.org/TR/css-values-4/#dashed-idents) declaration.
142
///
143
/// Dashed idents are used in cases where an identifier can be either author defined _or_ CSS-defined.
144
/// Author defined idents must start with two dash characters ("--") or parsing will fail.
145
#[derive(Debug, Clone, Eq, Hash)]
146
0
#[cfg_attr(feature = "visitor", derive(Visit))]
Unexecuted instantiation: <lightningcss::values::ident::DashedIdent as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::ValueCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::DashedIdent as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::FirstRgbColorCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::DashedIdent as lightningcss::visitor::Visit<_, _>>::visit_children
147
#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
148
#[cfg_attr(feature = "visitor", visit(visit_dashed_ident, DASHED_IDENTS))]
149
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(transparent))]
150
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
151
pub struct DashedIdent<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub CowArcStr<'i>);
152
153
impl<'i> Parse<'i> for DashedIdent<'i> {
154
82.8k
  fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
155
82.8k
    let location = input.current_source_location();
156
82.8k
    let ident = input.expect_ident()?;
157
27.6k
    if !ident.starts_with("--") {
158
18.5k
      return Err(location.new_unexpected_token_error(Token::Ident(ident.clone())));
159
9.06k
    }
160
161
9.06k
    Ok(DashedIdent(ident.into()))
162
82.8k
  }
163
}
164
165
impl<'i> ToCss for DashedIdent<'i> {
166
0
  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
167
0
  where
168
0
    W: std::fmt::Write,
169
  {
170
0
    dest.write_dashed_ident(&self.0, true)
171
0
  }
172
}
173
174
#[cfg(feature = "serde")]
175
impl<'i, 'de: 'i> serde::Deserialize<'de> for DashedIdent<'i> {
176
  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
177
  where
178
    D: serde::Deserializer<'de>,
179
  {
180
    let ident = CowArcStr::deserialize(deserializer)?;
181
    if !ident.starts_with("--") {
182
      return Err(serde::de::Error::custom("Dashed idents must start with --"));
183
    }
184
185
    Ok(DashedIdent(ident))
186
  }
187
}
188
189
/// A CSS [`<dashed-ident>`](https://www.w3.org/TR/css-values-4/#dashed-idents) reference.
190
///
191
/// Dashed idents are used in cases where an identifier can be either author defined _or_ CSS-defined.
192
/// Author defined idents must start with two dash characters ("--") or parsing will fail.
193
///
194
/// In CSS modules, when the `dashed_idents` option is enabled, the identifier may be followed by the
195
/// `from` keyword and an argument indicating where the referenced identifier is declared (e.g. a filename).
196
#[derive(Debug, Clone, PartialEq)]
197
0
#[cfg_attr(feature = "visitor", derive(Visit))]
Unexecuted instantiation: <lightningcss::values::ident::DashedIdentReference as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::ValueCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::DashedIdentReference as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::FirstRgbColorCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::DashedIdentReference as lightningcss::visitor::Visit<_, _>>::visit_children
198
#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
199
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
200
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
201
pub struct DashedIdentReference<'i> {
202
  /// The referenced identifier.
203
  #[cfg_attr(feature = "serde", serde(borrow))]
204
  pub ident: DashedIdent<'i>,
205
  /// CSS modules extension: the filename where the variable is defined.
206
  /// Only enabled when the CSS modules `dashed_idents` option is turned on.
207
  pub from: Option<Specifier<'i>>,
208
}
209
210
impl<'i> ParseWithOptions<'i> for DashedIdentReference<'i> {
211
29.4k
  fn parse_with_options<'t>(
212
29.4k
    input: &mut Parser<'i, 't>,
213
29.4k
    options: &crate::stylesheet::ParserOptions,
214
29.4k
  ) -> Result<Self, ParseError<'i, ParserError<'i>>> {
215
29.4k
    let ident = DashedIdent::parse(input)?;
216
217
9.06k
    let from = match &options.css_modules {
218
8.61k
      Some(config) if config.dashed_idents => {
219
0
        if input.try_parse(|input| input.expect_ident_matching("from")).is_ok() {
220
0
          Some(Specifier::parse(input)?)
221
        } else {
222
0
          None
223
        }
224
      }
225
9.06k
      _ => None,
226
    };
227
228
9.06k
    Ok(DashedIdentReference { ident, from })
229
29.4k
  }
230
}
231
232
impl<'i> ToCss for DashedIdentReference<'i> {
233
0
  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
234
0
  where
235
0
    W: std::fmt::Write,
236
  {
237
0
    match &mut dest.css_module {
238
0
      Some(css_module) if css_module.config.dashed_idents => {
239
0
        if let Some(name) = css_module.reference_dashed(&self.ident.0, &self.from, dest.loc.source_index) {
240
0
          dest.write_str("--")?;
241
0
          serialize_name(&name, dest)?;
242
0
          return Ok(());
243
0
        }
244
      }
245
0
      _ => {}
246
    }
247
248
0
    dest.write_dashed_ident(&self.ident.0, false)
249
0
  }
250
}
251
252
/// A CSS [`<ident>`](https://www.w3.org/TR/css-values-4/#css-css-identifier).
253
#[derive(Debug, Clone, Eq, Hash, Default)]
254
0
#[cfg_attr(feature = "visitor", derive(Visit))]
Unexecuted instantiation: <lightningcss::values::ident::Ident as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::ValueCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::Ident as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::FirstRgbColorCollector>>::visit_children
Unexecuted instantiation: <lightningcss::values::ident::Ident as lightningcss::visitor::Visit<_, _>>::visit_children
255
#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
256
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
257
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
258
pub struct Ident<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub CowArcStr<'i>);
259
260
impl<'i> Parse<'i> for Ident<'i> {
261
15.1k
  fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
262
15.1k
    let ident = input.expect_ident()?;
263
7.87k
    Ok(Ident(ident.into()))
264
15.1k
  }
265
}
266
267
impl<'i> ToCss for Ident<'i> {
268
0
  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
269
0
  where
270
0
    W: std::fmt::Write,
271
  {
272
0
    serialize_identifier(&self.0, dest)?;
273
0
    Ok(())
274
0
  }
275
}
276
277
impl<'i> cssparser::ToCss for Ident<'i> {
278
0
  fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result
279
0
  where
280
0
    W: std::fmt::Write,
281
  {
282
0
    serialize_identifier(&self.0, dest)
283
0
  }
284
}
285
286
impl_string_type!(Ident);
287
impl_string_type!(CustomIdent);
288
impl_string_type!(DashedIdent);