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