swc_css_parser/parser/
util.rs

1use std::ops::{Deref, DerefMut};
2
3use swc_common::{Span, Spanned, DUMMY_SP};
4use swc_css_ast::*;
5
6use super::{
7    input::{Input, InputType, ParserInput},
8    Ctx, Error, PResult, Parse, Parser,
9};
10use crate::{error::ErrorKind, parser::BlockContentsGrammar};
11
12impl<I> Parser<I>
13where
14    I: ParserInput,
15{
16    /// Original context is restored when returned guard is dropped.
17    #[inline]
18    pub(super) fn with_ctx(&mut self, ctx: Ctx) -> WithCtx<I> {
19        let orig_ctx = self.ctx;
20
21        self.ctx = ctx;
22
23        WithCtx {
24            orig_ctx,
25            inner: self,
26        }
27    }
28
29    #[inline]
30    pub(super) fn parse_as<T>(&mut self) -> PResult<T>
31    where
32        Self: Parse<T>,
33    {
34        self.parse()
35    }
36
37    pub(super) fn try_parse<Ret>(
38        &mut self,
39        op: impl FnOnce(&mut Parser<I>) -> PResult<Ret>,
40    ) -> Option<Ret> {
41        let mut parser = self.clone();
42
43        match op(&mut parser) {
44            Ok(v) => {
45                *self = parser;
46                Some(v)
47            }
48            Err(..) => None,
49        }
50    }
51
52    pub(super) fn create_locv(&self, children: Vec<ComponentValue>) -> ListOfComponentValues {
53        let span = match (children.first(), children.last()) {
54            (Some(first), Some(last)) => Span::new(first.span_lo(), last.span_hi()),
55            _ => DUMMY_SP,
56        };
57
58        ListOfComponentValues { span, children }
59    }
60
61    pub(super) fn parse_according_to_grammar<T>(
62        &mut self,
63        list_of_component_values: &ListOfComponentValues,
64        op: impl FnOnce(&mut Parser<Input>) -> PResult<T>,
65    ) -> PResult<T> {
66        let lexer = Input::new(InputType::ListOfComponentValues(list_of_component_values));
67        let mut parser = Parser::new(lexer, self.config);
68        let res = op(&mut parser.with_ctx(self.ctx));
69
70        self.errors.extend(parser.take_errors());
71
72        res
73    }
74
75    pub(super) fn canonicalize_at_rule_prelude(&mut self, mut at_rule: AtRule) -> PResult<AtRule> {
76        let normalized_at_rule_name = match &at_rule.name {
77            AtRuleName::Ident(Ident { value, .. }) => value.to_ascii_lowercase(),
78            AtRuleName::DashedIdent(_) => return Ok(at_rule),
79        };
80
81        let list_of_component_values = match at_rule.prelude {
82            Some(at_rule_prelude) => match *at_rule_prelude {
83                AtRulePrelude::ListOfComponentValues(list_of_component_values) => {
84                    list_of_component_values
85                }
86                _ => {
87                    unreachable!();
88                }
89            },
90            _ => {
91                unreachable!();
92            }
93        };
94
95        at_rule.prelude = match self
96            .parse_according_to_grammar(&list_of_component_values, |parser| {
97                parser.parse_at_rule_prelude(&normalized_at_rule_name)
98            }) {
99            Ok(at_rule_prelude) => match at_rule_prelude {
100                Some(AtRulePrelude::LayerPrelude(LayerPrelude::NameList(name_list)))
101                    if name_list.name_list.len() > 1 && at_rule.block.is_some() =>
102                {
103                    self.errors.push(Error::new(
104                        name_list.span,
105                        ErrorKind::Expected("only one name"),
106                    ));
107
108                    Some(Box::new(AtRulePrelude::ListOfComponentValues(
109                        list_of_component_values,
110                    )))
111                }
112                None if normalized_at_rule_name == "layer" && at_rule.block.is_none() => {
113                    self.errors.push(Error::new(
114                        at_rule.span,
115                        ErrorKind::Expected("at least one name"),
116                    ));
117
118                    Some(Box::new(AtRulePrelude::ListOfComponentValues(
119                        list_of_component_values,
120                    )))
121                }
122                _ => at_rule_prelude.map(Box::new),
123            },
124            Err(err) => {
125                if *err.kind() != ErrorKind::Ignore {
126                    self.errors.push(err);
127                }
128
129                if !list_of_component_values.children.is_empty() {
130                    Some(Box::new(AtRulePrelude::ListOfComponentValues(
131                        list_of_component_values,
132                    )))
133                } else {
134                    None
135                }
136            }
137        };
138
139        Ok(at_rule)
140    }
141
142    pub(super) fn canonicalize_at_rule_block(&mut self, mut at_rule: AtRule) -> PResult<AtRule> {
143        let normalized_at_rule_name = match &at_rule.name {
144            AtRuleName::Ident(Ident { value, .. }) => value.to_ascii_lowercase(),
145            AtRuleName::DashedIdent(_) => return Ok(at_rule),
146        };
147
148        let mut block = match at_rule.block {
149            Some(simple_block) => simple_block,
150            _ => {
151                unreachable!();
152            }
153        };
154
155        let list_of_component_values = self.create_locv(block.value);
156
157        block.value = match self.parse_according_to_grammar(&list_of_component_values, |parser| {
158            parser.parse_at_rule_block(&normalized_at_rule_name)
159        }) {
160            Ok(block_contents) => block_contents,
161            Err(err) => {
162                if *err.kind() != ErrorKind::Ignore {
163                    self.errors.push(err);
164                }
165
166                list_of_component_values.children
167            }
168        };
169
170        at_rule.block = Some(block);
171
172        Ok(at_rule)
173    }
174
175    pub(super) fn canonicalize_qualified_rule_prelude(
176        &mut self,
177        mut qualified_rule: QualifiedRule,
178    ) -> PResult<QualifiedRule> {
179        let list_of_component_values = match qualified_rule.prelude {
180            QualifiedRulePrelude::ListOfComponentValues(list_of_component_values) => {
181                list_of_component_values
182            }
183            _ => {
184                unreachable!();
185            }
186        };
187
188        qualified_rule.prelude = if self.ctx.in_keyframes_at_rule {
189            QualifiedRulePrelude::ListOfComponentValues(list_of_component_values)
190        } else if self.ctx.mixed_with_declarations {
191            match self.parse_according_to_grammar::<RelativeSelectorList>(
192                &list_of_component_values,
193                |parser| parser.parse(),
194            ) {
195                Ok(relative_selector_list) => {
196                    QualifiedRulePrelude::RelativeSelectorList(relative_selector_list)
197                }
198                Err(err) => {
199                    self.errors.push(err);
200
201                    QualifiedRulePrelude::ListOfComponentValues(list_of_component_values)
202                }
203            }
204        } else {
205            match self
206                .parse_according_to_grammar::<SelectorList>(&list_of_component_values, |parser| {
207                    parser.parse()
208                }) {
209                Ok(selector_list) => QualifiedRulePrelude::SelectorList(selector_list),
210                Err(err) => {
211                    self.errors.push(err);
212
213                    QualifiedRulePrelude::ListOfComponentValues(list_of_component_values)
214                }
215            }
216        };
217
218        Ok(qualified_rule)
219    }
220
221    pub(super) fn canonicalize_qualified_rule_block(
222        &mut self,
223        mut qualified_rule: QualifiedRule,
224    ) -> PResult<QualifiedRule> {
225        qualified_rule.block.value = match self.ctx.block_contents_grammar {
226            BlockContentsGrammar::RuleList if self.ctx.in_keyframes_at_rule => self
227                .parse_according_to_grammar(
228                    &self.create_locv(qualified_rule.block.value),
229                    |parser| {
230                        parser
231                            .with_ctx(Ctx {
232                                block_contents_grammar: BlockContentsGrammar::DeclarationList,
233                                ..parser.ctx
234                            })
235                            .parse_as::<Vec<DeclarationOrAtRule>>()
236                    },
237                )?
238                .into_iter()
239                .map(ComponentValue::from)
240                .collect(),
241            _ => self
242                .parse_according_to_grammar(
243                    &self.create_locv(qualified_rule.block.value),
244                    |parser| {
245                        parser
246                            .with_ctx(Ctx {
247                                block_contents_grammar: BlockContentsGrammar::StyleBlock,
248                                ..parser.ctx
249                            })
250                            .parse_as::<Vec<StyleBlock>>()
251                    },
252                )?
253                .into_iter()
254                .map(ComponentValue::from)
255                .collect(),
256        };
257
258        Ok(qualified_rule)
259    }
260
261    pub(super) fn canonicalize_function_value(
262        &mut self,
263        mut function: Function,
264    ) -> PResult<Function> {
265        let locv = self.create_locv(function.value);
266
267        function.value = match self.parse_according_to_grammar(&locv, |parser| {
268            parser.parse_function_values(&function.name)
269        }) {
270            Ok(values) => values,
271            Err(err) => {
272                if *err.kind() != ErrorKind::Ignore {
273                    self.errors.push(err);
274                }
275
276                locv.children
277            }
278        };
279
280        Ok(function)
281    }
282
283    pub(super) fn canonicalize_declaration_value(
284        &mut self,
285        mut declaration: Declaration,
286    ) -> PResult<Declaration> {
287        let locv = self.create_locv(declaration.value);
288
289        let value = self.parse_according_to_grammar(&locv, |parser| {
290            let mut values = Vec::new();
291
292            loop {
293                if is!(parser, EOF) {
294                    break;
295                }
296
297                values.push(parser.parse_generic_value()?);
298            }
299
300            Ok(values)
301        });
302        declaration.value = match value {
303            Ok(values) => values,
304            Err(err) => {
305                if *err.kind() != ErrorKind::Ignore {
306                    self.errors.push(err);
307                }
308
309                locv.children
310            }
311        };
312
313        Ok(declaration)
314    }
315
316    pub(super) fn try_to_parse_legacy_nesting(&mut self) -> Option<QualifiedRule> {
317        let state = self.input.state();
318        let qualified_rule = self
319            .with_ctx(Ctx {
320                block_contents_grammar: BlockContentsGrammar::StyleBlock,
321                mixed_with_declarations: true,
322                ..self.ctx
323            })
324            .parse_as::<QualifiedRule>();
325
326        match qualified_rule {
327            Ok(qualified_rule) => Some(qualified_rule),
328            _ => {
329                self.input.reset(&state);
330
331                None
332            }
333        }
334    }
335
336    pub(super) fn try_to_parse_declaration_in_parens(&mut self) -> Option<Declaration> {
337        let mut temporary_list = ListOfComponentValues {
338            span: Default::default(),
339            children: Vec::new(),
340        };
341
342        while !is_one_of!(self, ")", EOF) {
343            let component_value = match self.parse_as::<ComponentValue>() {
344                Ok(component_value) => component_value,
345                Err(_) => return None,
346            };
347
348            temporary_list.children.push(component_value);
349        }
350
351        self.parse_according_to_grammar::<Declaration>(&temporary_list, |parser| parser.parse_as())
352            .ok()
353    }
354
355    pub(super) fn parse_declaration_from_temporary_list(
356        &mut self,
357        temporary_list: &ListOfComponentValues,
358    ) -> PResult<Declaration> {
359        self.parse_according_to_grammar::<Declaration>(temporary_list, |parser| parser.parse_as())
360    }
361
362    // The <declaration-value> production matches any sequence of one or more
363    // tokens, so long as the sequence does not contain <bad-string-token>,
364    // <bad-url-token>, unmatched <)-token>, <]-token>, or <}-token>, or top-level
365    // <semicolon-token> tokens or <delim-token> tokens with a value of "!". It
366    // represents the entirety of what a valid declaration can have as its value.
367    pub(super) fn validate_declaration_value(
368        &mut self,
369        component_value: &ComponentValue,
370    ) -> PResult<()> {
371        let ComponentValue::PreservedToken(preserved_token) = component_value else {
372            return Ok(());
373        };
374
375        let kind = match preserved_token.token {
376            Token::BadString { .. } => ErrorKind::Unexpected("bad string in declaration value"),
377            Token::BadUrl { .. } => ErrorKind::Unexpected("bad url in declaration value"),
378            Token::RParen => ErrorKind::Unexpected("')' in declaration value"),
379            Token::RBracket => ErrorKind::Unexpected("']' in declaration value"),
380            Token::RBrace => ErrorKind::Unexpected("'}' in declaration value"),
381            Token::Semi => ErrorKind::Unexpected("';' in declaration value"),
382            Token::Delim { value: '!' } => ErrorKind::Unexpected("'!' in declaration value"),
383            _ => return Ok(()),
384        };
385
386        Err(Error::new(preserved_token.span, kind))
387    }
388}
389
390pub(super) struct WithCtx<'w, I: 'w + ParserInput> {
391    inner: &'w mut Parser<I>,
392    orig_ctx: Ctx,
393}
394
395impl<I: ParserInput> Deref for WithCtx<'_, I> {
396    type Target = Parser<I>;
397
398    fn deref(&self) -> &Parser<I> {
399        self.inner
400    }
401}
402impl<I: ParserInput> DerefMut for WithCtx<'_, I> {
403    fn deref_mut(&mut self) -> &mut Parser<I> {
404        self.inner
405    }
406}
407
408impl<I: ParserInput> Drop for WithCtx<'_, I> {
409    fn drop(&mut self) {
410        self.inner.ctx = self.orig_ctx;
411    }
412}