diff --git a/src/args.rs b/src/args.rs index 8d8456c..8dfcc14 100644 --- a/src/args.rs +++ b/src/args.rs @@ -40,7 +40,7 @@ enum CallArg { impl CallArg { pub fn position(&self) -> SassResult { match self { - Self::Named(..) => todo!(), + Self::Named(..) => Err("found named".into()), Self::Positional(p) => Ok(*p), } } @@ -58,6 +58,24 @@ impl CallArgs { CallArgs(HashMap::new()) } + pub fn to_css_string(self, scope: &Scope, super_selector: &Selector) -> SassResult { + 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::>() + .join(", "), + ); + string.push(')'); + Ok(string) + } + /// Get argument by name /// /// Removes the argument diff --git a/src/value/parse.rs b/src/value/parse.rs index 355742f..61e2387 100644 --- a/src/value/parse.rs +++ b/src/value/parse.rs @@ -16,7 +16,7 @@ use crate::selector::Selector; use crate::unit::Unit; use crate::utils::{ 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, }; use crate::value::Value; @@ -374,34 +374,10 @@ impl Value { )?)) } None => { - s.push('('); - let mut unclosed_parens = 0; - while let Some(t) = toks.next() { - 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()); - } + s.push_str( + &eat_call_args(toks, scope, super_selector)? + .to_css_string(scope, super_selector)?, + ); return Ok(IntermediateValue::Value(Value::Ident(s, QuoteKind::None))); } }, diff --git a/tests/plain-css-fn.rs b/tests/plain-css-fn.rs new file mode 100644 index 0000000..9a8d27a --- /dev/null +++ b/tests/plain-css-fn.rs @@ -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" +);