Skip to main content

oxc_css_parser/parser/at_rule/
custom_selector.rs

1use super::Parser;
2use crate::{
3    Parse, arena_vec, ast::*, error::PResult, expect, peek, pos::Span, tokenizer::Token, util,
4};
5
6impl<'a> Parse<'a> for CustomSelector<'a> {
7    fn parse(input: &mut Parser<'a>) -> PResult<Self> {
8        let prefix_arg = if matches!(peek!(input).token, Token::DollarVar(..)) {
9            Some(input.parse::<CustomSelectorArg>()?)
10        } else {
11            None
12        };
13
14        let (_, colon_span) = expect!(input, Colon);
15        if let Some(prefix_arg) = &prefix_arg {
16            util::assert_no_ws_or_comment(&prefix_arg.span, &colon_span)?;
17        }
18        let name = input.parse::<Ident>()?;
19        util::assert_no_ws_or_comment(&colon_span, &name.span)?;
20
21        let args = if matches!(peek!(input).token, Token::LParen(..)) {
22            Some(input.parse::<CustomSelectorArgs>()?)
23        } else {
24            None
25        };
26
27        let span = Span {
28            start: prefix_arg
29                .as_ref()
30                .map(|prefix_arg| prefix_arg.span.start)
31                .unwrap_or(name.span.start),
32            end: args.as_ref().map(|args| args.span.end).unwrap_or(name.span.end),
33        };
34        Ok(CustomSelector { prefix_arg, name, args, span })
35    }
36}
37
38impl<'a> Parse<'a> for CustomSelectorArg<'a> {
39    fn parse(input: &mut Parser<'a>) -> PResult<Self> {
40        let (dollar_var, dollar_var_span) = expect!(input, DollarVar);
41        Ok(CustomSelectorArg {
42            name: input.ident(
43                dollar_var.ident,
44                Span { start: dollar_var_span.start + 1, end: dollar_var_span.end },
45            ),
46            span: dollar_var_span,
47        })
48    }
49}
50
51impl<'a> Parse<'a> for CustomSelectorArgs<'a> {
52    fn parse(input: &mut Parser<'a>) -> PResult<Self> {
53        let (_, Span { start, .. }) = expect!(input, LParen);
54
55        let mut args = arena_vec!(input);
56        let mut comma_spans = arena_vec!(input);
57        while !matches!(peek!(input).token, Token::RParen(..)) {
58            args.push(input.parse()?);
59            if !matches!(peek!(input).token, Token::RParen(..)) {
60                comma_spans.push(expect!(input, Comma).1);
61            }
62        }
63
64        let (_, Span { end, .. }) = expect!(input, RParen);
65        Ok(CustomSelectorArgs { args, comma_spans, span: Span { start, end } })
66    }
67}
68
69// https://drafts.csswg.org/css-extensions/#custom-selectors
70impl<'a> Parse<'a> for CustomSelectorPrelude<'a> {
71    fn parse(input: &mut Parser<'a>) -> PResult<Self> {
72        let custom_selector = input.parse::<CustomSelector>()?;
73        let selector = input.parse::<SelectorList>()?;
74        let span = Span { start: custom_selector.span.start, end: selector.span.end };
75        Ok(CustomSelectorPrelude { custom_selector, selector, span })
76    }
77}