Skip to main content

oxc_css_parser/parser/at_rule/
layer.rs

1use super::Parser;
2use crate::{
3    Parse,
4    ast::*,
5    error::{Error, PResult},
6    pos::Span,
7    tokenizer::{Token, TokenWithSpan},
8    util,
9};
10
11// https://drafts.csswg.org/css-cascade-5/#layering
12//
13// @layer <layer-name># ;                (statement form)
14// @layer <layer-name>? { <rule-list> }  (block form)
15impl<'a> Parse<'a> for LayerNames<'a> {
16    fn parse(input: &mut Parser<'a>) -> PResult<Self> {
17        let first = input.parse::<LayerName>()?;
18        let mut span = first.span.clone();
19
20        let mut names = input.vec1(first);
21        let mut comma_spans = input.vec();
22        while let Some((_, comma_span)) = input.cursor.eat_comma()? {
23            comma_spans.push(comma_span);
24            names.push(input.parse()?);
25        }
26
27        if let Some(last) = names.last() {
28            span.end = last.span.end;
29        }
30        Ok(LayerNames { names, comma_spans, span })
31    }
32}
33
34// https://drafts.csswg.org/css-cascade-5/#layer-names
35//
36// <layer-name> = <ident> [ '.' <ident> ]*
37impl<'a> Parse<'a> for LayerName<'a> {
38    fn parse(input: &mut Parser<'a>) -> PResult<Self> {
39        let first = input.parse::<InterpolableIdent>()?;
40        let start = first.span().start;
41        let mut end = first.span().end;
42
43        let mut idents = input.vec1(first);
44        while let TokenWithSpan { token: Token::Dot(..), span } = input.cursor.peek()? {
45            if span.start == end {
46                let span = input.cursor.bump()?.span;
47                let ident = input.parse::<InterpolableIdent>()?;
48                util::assert_no_ws_or_comment(&span, ident.span())?;
49                end = ident.span().end;
50                idents.push(ident);
51            } else {
52                break;
53            }
54        }
55
56        let invalid_ident = idents.iter().find(|ident| match &ident {
57            InterpolableIdent::Literal(ident) => util::is_css_wide_keyword(ident.name),
58            _ => false,
59        });
60        if let Some(invalid_ident) = invalid_ident {
61            input.recoverable_errors.push(Error {
62                kind: crate::error::ErrorKind::CSSWideKeywordDisallowed,
63                span: invalid_ident.span().clone(),
64            });
65        }
66
67        let span = Span { start, end };
68        Ok(LayerName { idents, span })
69    }
70}