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)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct Keyframes {
|
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 name: String,
|
||||||
pub body: Vec<Stmt>,
|
pub body: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::convert::TryFrom;
|
|||||||
|
|
||||||
use codemap::Spanned;
|
use codemap::Spanned;
|
||||||
|
|
||||||
use crate::error::SassError;
|
use crate::{common::unvendor, error::SassError};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AtRuleKind {
|
pub enum AtRuleKind {
|
||||||
@ -72,31 +72,35 @@ pub enum AtRuleKind {
|
|||||||
impl TryFrom<&Spanned<String>> for AtRuleKind {
|
impl TryFrom<&Spanned<String>> for AtRuleKind {
|
||||||
type Error = Box<SassError>;
|
type Error = Box<SassError>;
|
||||||
fn try_from(c: &Spanned<String>) -> Result<Self, Box<SassError>> {
|
fn try_from(c: &Spanned<String>) -> Result<Self, Box<SassError>> {
|
||||||
Ok(match c.node.as_str() {
|
match c.node.as_str() {
|
||||||
"use" => Self::Use,
|
"use" => return Ok(Self::Use),
|
||||||
"forward" => Self::Forward,
|
"forward" => return Ok(Self::Forward),
|
||||||
"import" => Self::Import,
|
"import" => return Ok(Self::Import),
|
||||||
"mixin" => Self::Mixin,
|
"mixin" => return Ok(Self::Mixin),
|
||||||
"include" => Self::Include,
|
"include" => return Ok(Self::Include),
|
||||||
"function" => Self::Function,
|
"function" => return Ok(Self::Function),
|
||||||
"return" => Self::Return,
|
"return" => return Ok(Self::Return),
|
||||||
"extend" => Self::Extend,
|
"extend" => return Ok(Self::Extend),
|
||||||
"at-root" => Self::AtRoot,
|
"at-root" => return Ok(Self::AtRoot),
|
||||||
"error" => Self::Error,
|
"error" => return Ok(Self::Error),
|
||||||
"warn" => Self::Warn,
|
"warn" => return Ok(Self::Warn),
|
||||||
"debug" => Self::Debug,
|
"debug" => return Ok(Self::Debug),
|
||||||
"if" => Self::If,
|
"if" => return Ok(Self::If),
|
||||||
"each" => Self::Each,
|
"each" => return Ok(Self::Each),
|
||||||
"for" => Self::For,
|
"for" => return Ok(Self::For),
|
||||||
"while" => Self::While,
|
"while" => return Ok(Self::While),
|
||||||
"charset" => Self::Charset,
|
"charset" => return Ok(Self::Charset),
|
||||||
"supports" => Self::Supports,
|
"supports" => return Ok(Self::Supports),
|
||||||
"keyframes" => Self::Keyframes,
|
"content" => return Ok(Self::Content),
|
||||||
"content" => Self::Content,
|
"media" => return Ok(Self::Media),
|
||||||
"media" => Self::Media,
|
|
||||||
"else" => return Err(("This at-rule is not allowed here.", c.span).into()),
|
"else" => return Err(("This at-rule is not allowed here.", c.span).into()),
|
||||||
"" => return Err(("Expected identifier.", 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) => {
|
Stmt::Keyframes(k) => {
|
||||||
let Keyframes { name, body } = *k;
|
let Keyframes { rule, name, body } = *k;
|
||||||
vals.push(Toplevel::Keyframes(Box::new(Keyframes { name, body })))
|
vals.push(Toplevel::Keyframes(Box::new(Keyframes {
|
||||||
|
rule,
|
||||||
|
name,
|
||||||
|
body,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
k @ Stmt::KeyframesRuleSet(..) => {
|
k @ Stmt::KeyframesRuleSet(..) => {
|
||||||
unreachable!("@keyframes ruleset {:?}", k)
|
unreachable!("@keyframes ruleset {:?}", k)
|
||||||
@ -324,13 +328,13 @@ impl Css {
|
|||||||
writeln!(buf, "{}}}", padding)?;
|
writeln!(buf, "{}}}", padding)?;
|
||||||
}
|
}
|
||||||
Toplevel::Keyframes(k) => {
|
Toplevel::Keyframes(k) => {
|
||||||
let Keyframes { name, body } = *k;
|
let Keyframes { rule, name, body } = *k;
|
||||||
if should_emit_newline {
|
if should_emit_newline {
|
||||||
should_emit_newline = false;
|
should_emit_newline = false;
|
||||||
writeln!(buf)?;
|
writeln!(buf)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(buf, "{}@keyframes", padding)?;
|
write!(buf, "{}@{}", padding, rule)?;
|
||||||
|
|
||||||
if !name.is_empty() {
|
if !name.is_empty() {
|
||||||
write!(buf, " {}", name)?;
|
write!(buf, " {}", name)?;
|
||||||
|
@ -55,7 +55,14 @@ impl<'a, 'b> KeyframesSelectorParser<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
'0'..='9' => {
|
'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: '%', .. })) {
|
if !matches!(self.parser.toks.next(), Some(Token { kind: '%', .. })) {
|
||||||
return Err(("expected \"%\".", tok.pos).into());
|
return Err(("expected \"%\".", tok.pos).into());
|
||||||
}
|
}
|
||||||
@ -177,7 +184,7 @@ impl<'a> Parser<'a> {
|
|||||||
Err(("expected \"{\".", span).into())
|
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()?;
|
let name = self.parse_keyframes_name()?;
|
||||||
|
|
||||||
self.whitespace();
|
self.whitespace();
|
||||||
@ -200,6 +207,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
.parse_stmt()?;
|
.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::Forward => todo!("@forward not yet implemented"),
|
||||||
AtRuleKind::Extend => self.parse_extend()?,
|
AtRuleKind::Extend => self.parse_extend()?,
|
||||||
AtRuleKind::Supports => stmts.push(self.parse_supports()?),
|
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()?,
|
'$' => self.parse_variable_declaration()?,
|
||||||
|
@ -121,3 +121,21 @@ test!(
|
|||||||
}",
|
}",
|
||||||
"@keyframes {\n to {\n color: red;\n }\n from {\n color: green;\n }\n}\n"
|
"@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