allow @keyframes
to have vendor prefixes and decimal selectors
This commit is contained in:
parent
627bd62bb9
commit
e0cecb4e5c
@ -2,6 +2,10 @@ use crate::parse::Stmt;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Keyframes {
|
||||
/// `@keyframes` can contain a browser prefix,
|
||||
/// e.g. `@-webkit-keyframes { ... }`, and therefore
|
||||
/// we cannot be certain of the name of the at-rule
|
||||
pub rule: String,
|
||||
pub name: String,
|
||||
pub body: Vec<Stmt>,
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use std::convert::TryFrom;
|
||||
|
||||
use codemap::Spanned;
|
||||
|
||||
use crate::error::SassError;
|
||||
use crate::{common::unvendor, error::SassError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AtRuleKind {
|
||||
@ -72,31 +72,35 @@ pub enum AtRuleKind {
|
||||
impl TryFrom<&Spanned<String>> for AtRuleKind {
|
||||
type Error = Box<SassError>;
|
||||
fn try_from(c: &Spanned<String>) -> Result<Self, Box<SassError>> {
|
||||
Ok(match c.node.as_str() {
|
||||
"use" => Self::Use,
|
||||
"forward" => Self::Forward,
|
||||
"import" => Self::Import,
|
||||
"mixin" => Self::Mixin,
|
||||
"include" => Self::Include,
|
||||
"function" => Self::Function,
|
||||
"return" => Self::Return,
|
||||
"extend" => Self::Extend,
|
||||
"at-root" => Self::AtRoot,
|
||||
"error" => Self::Error,
|
||||
"warn" => Self::Warn,
|
||||
"debug" => Self::Debug,
|
||||
"if" => Self::If,
|
||||
"each" => Self::Each,
|
||||
"for" => Self::For,
|
||||
"while" => Self::While,
|
||||
"charset" => Self::Charset,
|
||||
"supports" => Self::Supports,
|
||||
"keyframes" => Self::Keyframes,
|
||||
"content" => Self::Content,
|
||||
"media" => Self::Media,
|
||||
match c.node.as_str() {
|
||||
"use" => return Ok(Self::Use),
|
||||
"forward" => return Ok(Self::Forward),
|
||||
"import" => return Ok(Self::Import),
|
||||
"mixin" => return Ok(Self::Mixin),
|
||||
"include" => return Ok(Self::Include),
|
||||
"function" => return Ok(Self::Function),
|
||||
"return" => return Ok(Self::Return),
|
||||
"extend" => return Ok(Self::Extend),
|
||||
"at-root" => return Ok(Self::AtRoot),
|
||||
"error" => return Ok(Self::Error),
|
||||
"warn" => return Ok(Self::Warn),
|
||||
"debug" => return Ok(Self::Debug),
|
||||
"if" => return Ok(Self::If),
|
||||
"each" => return Ok(Self::Each),
|
||||
"for" => return Ok(Self::For),
|
||||
"while" => return Ok(Self::While),
|
||||
"charset" => return Ok(Self::Charset),
|
||||
"supports" => return Ok(Self::Supports),
|
||||
"content" => return Ok(Self::Content),
|
||||
"media" => return Ok(Self::Media),
|
||||
"else" => return Err(("This at-rule is not allowed here.", c.span).into()),
|
||||
"" => return Err(("Expected identifier.", c.span).into()),
|
||||
s => Self::Unknown(s.to_owned()),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(match unvendor(&c.node) {
|
||||
"keyframes" => Self::Keyframes,
|
||||
_ => Self::Unknown(c.node.to_owned()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -157,8 +157,12 @@ impl Css {
|
||||
})?
|
||||
}
|
||||
Stmt::Keyframes(k) => {
|
||||
let Keyframes { name, body } = *k;
|
||||
vals.push(Toplevel::Keyframes(Box::new(Keyframes { name, body })))
|
||||
let Keyframes { rule, name, body } = *k;
|
||||
vals.push(Toplevel::Keyframes(Box::new(Keyframes {
|
||||
rule,
|
||||
name,
|
||||
body,
|
||||
})))
|
||||
}
|
||||
k @ Stmt::KeyframesRuleSet(..) => {
|
||||
unreachable!("@keyframes ruleset {:?}", k)
|
||||
@ -324,13 +328,13 @@ impl Css {
|
||||
writeln!(buf, "{}}}", padding)?;
|
||||
}
|
||||
Toplevel::Keyframes(k) => {
|
||||
let Keyframes { name, body } = *k;
|
||||
let Keyframes { rule, name, body } = *k;
|
||||
if should_emit_newline {
|
||||
should_emit_newline = false;
|
||||
writeln!(buf)?;
|
||||
}
|
||||
|
||||
write!(buf, "{}@keyframes", padding)?;
|
||||
write!(buf, "{}@{}", padding, rule)?;
|
||||
|
||||
if !name.is_empty() {
|
||||
write!(buf, " {}", name)?;
|
||||
|
@ -55,7 +55,14 @@ impl<'a, 'b> KeyframesSelectorParser<'a, 'b> {
|
||||
}
|
||||
}
|
||||
'0'..='9' => {
|
||||
let num = eat_whole_number(self.parser.toks);
|
||||
let mut num = eat_whole_number(self.parser.toks);
|
||||
|
||||
if let Some(Token { kind: '.', .. }) = self.parser.toks.peek() {
|
||||
self.parser.toks.next();
|
||||
num.push('.');
|
||||
num.push_str(&eat_whole_number(self.parser.toks));
|
||||
}
|
||||
|
||||
if !matches!(self.parser.toks.next(), Some(Token { kind: '%', .. })) {
|
||||
return Err(("expected \"%\".", tok.pos).into());
|
||||
}
|
||||
@ -177,7 +184,7 @@ impl<'a> Parser<'a> {
|
||||
Err(("expected \"{\".", span).into())
|
||||
}
|
||||
|
||||
pub(super) fn parse_keyframes(&mut self) -> SassResult<Stmt> {
|
||||
pub(super) fn parse_keyframes(&mut self, rule: String) -> SassResult<Stmt> {
|
||||
let name = self.parse_keyframes_name()?;
|
||||
|
||||
self.whitespace();
|
||||
@ -200,6 +207,6 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
.parse_stmt()?;
|
||||
|
||||
Ok(Stmt::Keyframes(Box::new(Keyframes { name, body })))
|
||||
Ok(Stmt::Keyframes(Box::new(Keyframes { rule, name, body })))
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +200,9 @@ impl<'a> Parser<'a> {
|
||||
AtRuleKind::Forward => todo!("@forward not yet implemented"),
|
||||
AtRuleKind::Extend => self.parse_extend()?,
|
||||
AtRuleKind::Supports => stmts.push(self.parse_supports()?),
|
||||
AtRuleKind::Keyframes => stmts.push(self.parse_keyframes()?),
|
||||
AtRuleKind::Keyframes => {
|
||||
stmts.push(self.parse_keyframes(kind_string.node)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
'$' => self.parse_variable_declaration()?,
|
||||
|
@ -121,3 +121,21 @@ test!(
|
||||
}",
|
||||
"@keyframes {\n to {\n color: red;\n }\n from {\n color: green;\n }\n}\n"
|
||||
);
|
||||
test!(
|
||||
keyframes_vendor_prefix,
|
||||
"@-webkit-keyframes foo {
|
||||
0% {
|
||||
color: red;
|
||||
}
|
||||
}",
|
||||
"@-webkit-keyframes foo {\n 0% {\n color: red;\n }\n}\n"
|
||||
);
|
||||
test!(
|
||||
keyframes_allow_decimal_selector,
|
||||
"@keyframes foo {
|
||||
12.5% {
|
||||
color: red;
|
||||
}
|
||||
}",
|
||||
"@-webkit-keyframes foo {\n 0% {\n color: red;\n }\n}\n"
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user