oxc_css_parser/parser/at_rule/
keyframes.rs1use super::Parser;
2use crate::{
3 Parse, arena_vec,
4 ast::*,
5 eat,
6 error::{Error, ErrorKind, PResult},
7 parser::state::ParserState,
8 peek,
9 pos::{Span, Spanned},
10 tokenizer::Token,
11 util,
12};
13
14impl<'a> Parse<'a> for KeyframeBlock<'a> {
16 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
17 let first_selector = input.parse::<KeyframeSelector>()?;
18 let start = first_selector.span().start;
19
20 let mut selectors = input.vec_with_capacity(2);
21 selectors.push(first_selector);
22 let mut comma_spans = arena_vec!(input);
23 while let Some((_, comma_span)) = eat!(input, Comma) {
24 comma_spans.push(comma_span);
25 selectors.push(input.parse()?);
26 }
27 debug_assert_eq!(comma_spans.len() + 1, selectors.len());
28
29 let block = input
30 .with_state(ParserState { in_keyframes_at_rule: false, ..input.state.clone() })
31 .parse::<SimpleBlock>()?;
32
33 let span = Span { start, end: block.span.end };
34 Ok(KeyframeBlock { selectors, comma_spans, block, span })
35 }
36}
37
38impl<'a> Parse<'a> for KeyframeSelector<'a> {
39 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
40 match &peek!(input).token {
41 Token::Percentage(..) => Ok(KeyframeSelector::Percentage(input.parse()?)),
42 _ => {
43 let ident = input.parse()?;
44 match &ident {
45 InterpolableIdent::Literal(ident)
46 if !ident.name.eq_ignore_ascii_case("from")
47 && !ident.name.eq_ignore_ascii_case("to") =>
48 {
49 input.recoverable_errors.push(Error {
50 kind: ErrorKind::UnknownKeyframeSelectorIdent,
51 span: ident.span.clone(),
52 });
53 }
54 _ => {}
55 }
56 Ok(KeyframeSelector::Ident(ident))
57 }
58 }
59 }
60}
61
62impl<'a> Parse<'a> for KeyframesName<'a> {
64 fn parse(input: &mut Parser<'a>) -> PResult<Self> {
65 match &peek!(input).token {
66 Token::Ident(..) | Token::HashLBrace(..) | Token::AtLBraceVar(..) => {
67 let ident = input.parse()?;
68 match &ident {
69 InterpolableIdent::Literal(ident)
70 if util::is_css_wide_keyword(ident.name)
71 || ident.name.eq_ignore_ascii_case("default") =>
72 {
73 input.recoverable_errors.push(Error {
74 kind: ErrorKind::CSSWideKeywordDisallowed,
75 span: ident.span.clone(),
76 });
77 }
78 _ => {}
79 }
80 Ok(KeyframesName::Ident(ident))
81 }
82 Token::AtKeyword(..) => input.parse().map(KeyframesName::LessVariable),
83 Token::Tilde(..) => input.parse().map(KeyframesName::LessEscapedStr),
84 _ => input.parse().map(KeyframesName::Str),
85 }
86 }
87}