lightningcss/rules/
layer.rs
1use super::{CssRuleList, Location, MinifyContext};
4use crate::error::{MinifyError, ParserError, PrinterError};
5use crate::parser::DefaultAtRule;
6use crate::printer::Printer;
7use crate::traits::{Parse, ToCss};
8use crate::values::string::CowArcStr;
9#[cfg(feature = "visitor")]
10use crate::visitor::Visit;
11use cssparser::*;
12use smallvec::SmallVec;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
21#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
22pub struct LayerName<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub SmallVec<[CowArcStr<'i>; 1]>);
23
24macro_rules! expect_non_whitespace {
25 ($parser: ident, $($branches: tt)+) => {{
26 let start_location = $parser.current_source_location();
27 match *$parser.next_including_whitespace()? {
28 $($branches)+
29 ref token => {
30 return Err(start_location.new_basic_unexpected_token_error(token.clone()))
31 }
32 }
33 }}
34}
35
36impl<'i> Parse<'i> for LayerName<'i> {
37 fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
38 let mut parts = SmallVec::new();
39 let ident = input.expect_ident()?;
40 parts.push(ident.into());
41
42 loop {
43 let name = input.try_parse(|input| {
44 expect_non_whitespace! {input,
45 Token::Delim('.') => Ok(()),
46 }?;
47
48 expect_non_whitespace! {input,
49 Token::Ident(ref id) => Ok(id.into()),
50 }
51 });
52
53 match name {
54 Ok(name) => parts.push(name),
55 Err(_) => break,
56 }
57 }
58
59 Ok(LayerName(parts))
60 }
61}
62
63impl<'i> ToCss for LayerName<'i> {
64 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
65 where
66 W: std::fmt::Write,
67 {
68 let mut first = true;
69 for name in &self.0 {
70 if first {
71 first = false;
72 } else {
73 dest.write_char('.')?;
74 }
75
76 serialize_identifier(name, dest)?;
77 }
78
79 Ok(())
80 }
81}
82
83#[derive(Debug, Clone, PartialEq)]
87#[cfg_attr(feature = "visitor", derive(Visit))]
88#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
89#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
90#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
91pub struct LayerStatementRule<'i> {
92 #[cfg_attr(feature = "serde", serde(borrow))]
94 #[cfg_attr(feature = "visitor", skip_visit)]
95 pub names: Vec<LayerName<'i>>,
96 #[cfg_attr(feature = "visitor", skip_visit)]
98 pub loc: Location,
99}
100
101impl<'i> ToCss for LayerStatementRule<'i> {
102 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
103 where
104 W: std::fmt::Write,
105 {
106 #[cfg(feature = "sourcemap")]
107 dest.add_mapping(self.loc);
108 dest.write_str("@layer ")?;
109 self.names.to_css(dest)?;
110 dest.write_char(';')
111 }
112}
113
114#[derive(Debug, Clone, PartialEq)]
116#[cfg_attr(feature = "visitor", derive(Visit))]
117#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
118#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
119#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
120pub struct LayerBlockRule<'i, R = DefaultAtRule> {
121 #[cfg_attr(feature = "serde", serde(borrow))]
123 #[cfg_attr(feature = "visitor", skip_visit)]
124 pub name: Option<LayerName<'i>>,
125 pub rules: CssRuleList<'i, R>,
127 #[cfg_attr(feature = "visitor", skip_visit)]
129 pub loc: Location,
130}
131
132impl<'i, T: Clone> LayerBlockRule<'i, T> {
133 pub(crate) fn minify(
134 &mut self,
135 context: &mut MinifyContext<'_, 'i>,
136 parent_is_unused: bool,
137 ) -> Result<bool, MinifyError> {
138 self.rules.minify(context, parent_is_unused)?;
139
140 Ok(self.rules.0.is_empty())
141 }
142}
143
144impl<'a, 'i, T: ToCss> ToCss for LayerBlockRule<'i, T> {
145 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
146 where
147 W: std::fmt::Write,
148 {
149 #[cfg(feature = "sourcemap")]
150 dest.add_mapping(self.loc);
151 dest.write_str("@layer")?;
152 if let Some(name) = &self.name {
153 dest.write_char(' ')?;
154 name.to_css(dest)?;
155 }
156
157 dest.whitespace()?;
158 dest.write_char('{')?;
159 dest.indent();
160 dest.newline()?;
161 self.rules.to_css(dest)?;
162 dest.dedent();
163 dest.newline()?;
164 dest.write_char('}')
165 }
166}