properly parse plain css functions

This commit is contained in:
ConnorSkees 2020-04-06 15:35:46 -04:00
parent 9faaabebfa
commit ce346077f9
3 changed files with 69 additions and 30 deletions

View File

@ -40,7 +40,7 @@ enum CallArg {
impl CallArg { impl CallArg {
pub fn position(&self) -> SassResult<usize> { pub fn position(&self) -> SassResult<usize> {
match self { match self {
Self::Named(..) => todo!(), Self::Named(..) => Err("found named".into()),
Self::Positional(p) => Ok(*p), Self::Positional(p) => Ok(*p),
} }
} }
@ -58,6 +58,24 @@ impl CallArgs {
CallArgs(HashMap::new()) CallArgs(HashMap::new())
} }
pub fn to_css_string(self, scope: &Scope, super_selector: &Selector) -> SassResult<String> {
let mut string = String::with_capacity(2 + self.len() * 10);
string.push('(');
let args = match self.get_variadic(scope, super_selector) {
Ok(v) => v,
Err(..) => return Err("Plain CSS functions don't support keyword arguments.".into()),
};
string.push_str(
&args
.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<String>>()
.join(", "),
);
string.push(')');
Ok(string)
}
/// Get argument by name /// Get argument by name
/// ///
/// Removes the argument /// Removes the argument

View File

@ -16,7 +16,7 @@ use crate::selector::Selector;
use crate::unit::Unit; use crate::unit::Unit;
use crate::utils::{ use crate::utils::{
devour_whitespace, eat_comment, eat_ident, eat_ident_no_interpolation, eat_number, devour_whitespace, eat_comment, eat_ident, eat_ident_no_interpolation, eat_number,
parse_interpolation, parse_quoted_string, read_until_char, read_until_closing_paren, parse_quoted_string, read_until_char, read_until_closing_paren,
read_until_closing_square_brace, read_until_newline, IsWhitespace, read_until_closing_square_brace, read_until_newline, IsWhitespace,
}; };
use crate::value::Value; use crate::value::Value;
@ -374,34 +374,10 @@ impl Value {
)?)) )?))
} }
None => { None => {
s.push('('); s.push_str(
let mut unclosed_parens = 0; &eat_call_args(toks, scope, super_selector)?
while let Some(t) = toks.next() { .to_css_string(scope, super_selector)?,
match &t.kind { );
'(' => {
unclosed_parens += 1;
}
'#' if toks.next().unwrap().kind == '{' => s.push_str(
&parse_interpolation(toks, scope, super_selector)?
.to_string(),
),
'$' => s.push_str(
&scope
.get_var(&eat_ident(toks, scope, super_selector)?)?
.to_string(),
),
')' => {
if unclosed_parens <= 1 {
s.push(')');
break;
} else {
unclosed_parens -= 1;
}
}
_ => {}
}
s.push_str(&t.kind.to_string());
}
return Ok(IntermediateValue::Value(Value::Ident(s, QuoteKind::None))); return Ok(IntermediateValue::Value(Value::Ident(s, QuoteKind::None)));
} }
}, },

45
tests/plain-css-fn.rs Normal file
View File

@ -0,0 +1,45 @@
#![cfg(test)]
#[macro_use]
mod macros;
test!(
type_is_string,
"a {\n color: type-of(foo(1+1));\n}\n",
"a {\n color: string;\n}\n"
);
test!(
evaluates_arguments,
"a {\n color: foo(1+1);\n}\n",
"a {\n color: foo(2);\n}\n"
);
test!(
arguments_are_comma_separated,
"a {\n color: foo(1+1, 2+3, 4+5);\n}\n",
"a {\n color: foo(2, 5, 9);\n}\n"
);
test!(
converts_sql_quotes,
"a {\n color: foo('hi');\n}\n",
"a {\n color: foo(\"hi\");\n}\n"
);
test!(
super_selector,
"a {\n color: foo(&);\n}\n",
"a {\n color: foo(a);\n}\n"
);
test!(
nested_plain_css_fn,
"a {\n color: foo(foo(foo(foo(1+1))));\n}\n",
"a {\n color: foo(foo(foo(foo(2))));\n}\n"
);
error!(
disallows_named_arguments,
"a {\n color: foo($a: 1+1);\n}\n",
"Error: Plain CSS functions don't support keyword arguments."
);
test!(
evalutes_variables,
"a {\n $primary: #f2ece4;\n $accent: #e1d7d2;\n color: radial-gradient($primary, $accent);\n}\n",
"a {\n color: radial-gradient(#f2ece4, #e1d7d2);\n}\n"
);