ffaee04613
Adds support for the indented syntax, plain CSS imports, `@forward`, and many other previously missing features.
414 lines
8.1 KiB
Rust
414 lines
8.1 KiB
Rust
#[macro_use]
|
|
mod macros;
|
|
|
|
test!(
|
|
return_num,
|
|
"@function a() {\n @return 1;\n}\n\nb {\ncolor: a();\n}\n",
|
|
"b {\n color: 1;\n}\n"
|
|
);
|
|
test!(
|
|
return_spaced_list,
|
|
"@function a() {\n @return a b;\n}\n\nb {\ncolor: a();\n}\n",
|
|
"b {\n color: a b;\n}\n"
|
|
);
|
|
test!(
|
|
single_arg,
|
|
"@function a($c) {\n @return $c;\n}\n\nb {\ncolor: a(1);\n}\n",
|
|
"b {\n color: 1;\n}\n"
|
|
);
|
|
test!(
|
|
return_variable,
|
|
"@function a($a) {\n @return $a;\n}\n\nb {\ncolor: a(1);\n}\n",
|
|
"b {\n color: 1;\n}\n"
|
|
);
|
|
test!(
|
|
function_call_as_arg,
|
|
"@function a($a) {\n @return $a;\n}\n\nb {\ncolor: a(a(2));\n}\n",
|
|
"b {\n color: 2;\n}\n"
|
|
);
|
|
test!(
|
|
function_named_arg_value_variable,
|
|
"$x: red;\n\n@function a($a) {\n @return $a;\n}\n\nb {\ncolor: a($a: $x);\n}\n",
|
|
"b {\n color: red;\n}\n"
|
|
);
|
|
test!(
|
|
function_trailing_comma,
|
|
"@function a($a) {\n @return $a;\n}\n\nb {\ncolor: a(red,);\n}\n",
|
|
"b {\n color: red;\n}\n"
|
|
);
|
|
test!(
|
|
return_no_semicolon,
|
|
"@function a() {\n @return 1\n}\n\nb {\ncolor: a();\n}\n",
|
|
"b {\n color: 1;\n}\n"
|
|
);
|
|
test!(
|
|
two_returns,
|
|
"@function a() {\n @return 1; @return 2;\n}\n\nb {\ncolor: a();\n}\n",
|
|
"b {\n color: 1;\n}\n"
|
|
);
|
|
test!(
|
|
value_after_variable,
|
|
"$x: 0;\na {\n color: if($x != 0, a, b);\n}\n",
|
|
"a {\n color: b;\n}\n"
|
|
);
|
|
test!(
|
|
function_decl_in_ruleset,
|
|
"a {\n @function foo() {\n @return 3;\n }\n color: foo();\n}\n",
|
|
"a {\n color: 3;\n}\n"
|
|
);
|
|
test!(
|
|
function_decl_in_foreign_ruleset,
|
|
"a {\n @function foo() {\n @return 3;\n }\n}\nb {\n color: foo();\n}\n",
|
|
"b {\n color: foo();\n}\n"
|
|
);
|
|
test!(
|
|
global_function_in_scope,
|
|
"@function f() {\n @return g();\n}\n@function g() {\n @return false;\n}\na {\n color: f();\n color: g();\n}\n",
|
|
"a {\n color: false;\n color: false;\n}\n"
|
|
);
|
|
test!(
|
|
square_bracket_comma_separated,
|
|
"@function foo($a) {\n @return $a;\n}\n\na {\n color: foo([a, b]);\n}\n",
|
|
"a {\n color: [a, b];\n}\n"
|
|
);
|
|
test!(
|
|
eats_quoted_content,
|
|
"a {\n color: unquote(\"a, b, c, d\");\n}\n",
|
|
"a {\n color: a, b, c, d;\n}\n"
|
|
);
|
|
test!(
|
|
variable_declaration,
|
|
"@function str-replace($string, $search, $replace: \"\") {\n $index: $string;\n @return $index;\n}\n\na {\n color: str-replace(\"a#b#c\", \"#\", \":\");\n}",
|
|
"a {\n color: \"a#b#c\";\n}\n"
|
|
);
|
|
error!(
|
|
missing_name,
|
|
"@function() {}", "Error: Expected identifier."
|
|
);
|
|
error!(
|
|
args_do_not_start_with_var,
|
|
"@function foo(FOO) {}", "Error: expected \")\"."
|
|
);
|
|
error!(
|
|
double_comma_args,
|
|
"@function foo($a,$b,,) {}", "Error: expected \")\"."
|
|
);
|
|
error!(
|
|
body_missing_closing_curly_brace,
|
|
"@function foo() {", "Error: expected \"}\"."
|
|
);
|
|
test!(
|
|
does_not_modify_local_variables,
|
|
"@function bar($color-name) {
|
|
@if $color-name==bar {
|
|
@error bar;
|
|
}
|
|
|
|
$color: bar;
|
|
@return null;
|
|
}
|
|
|
|
@function foo($a, $b) {
|
|
@return \"success!\";
|
|
}
|
|
|
|
a {
|
|
$color: foo;
|
|
|
|
color: foo(bar($color), bar($color));
|
|
}",
|
|
"a {\n color: \"success!\";\n}\n"
|
|
);
|
|
error!(
|
|
denies_function_declaration_in_control_flow,
|
|
"@if true {\n @function foo() {}\n}\n",
|
|
"Error: Functions may not be declared in control directives."
|
|
);
|
|
error!(
|
|
denies_function_declaration_with_reserved_name,
|
|
"@function url() {}", "Error: Invalid function name."
|
|
);
|
|
test!(
|
|
function_finds_outer_local_variable,
|
|
"a {
|
|
$a: red;
|
|
|
|
@function foo() {
|
|
@return $a;
|
|
}
|
|
|
|
color: foo();
|
|
}",
|
|
"a {\n color: red;\n}\n"
|
|
);
|
|
test!(
|
|
function_ignores_the_scope_with_which_it_was_defined,
|
|
"a {
|
|
$a: red;
|
|
@function foo() {
|
|
@return $a;
|
|
}
|
|
$a: green;
|
|
color: foo();
|
|
}",
|
|
"a {\n color: green;\n}\n"
|
|
);
|
|
test!(
|
|
function_defined_and_called_at_toplevel_can_recognize_inner_variables,
|
|
"@function foo($level) {
|
|
$level: abs($level);
|
|
|
|
@return $level;
|
|
}
|
|
|
|
@mixin bar($a) {
|
|
a {
|
|
color: $a;
|
|
}
|
|
}
|
|
|
|
@include bar(foo(-9));",
|
|
"a {\n color: 9;\n}\n"
|
|
);
|
|
test!(
|
|
redeclaration_in_inner_scope,
|
|
"@function foo() {
|
|
@return foo;
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
|
|
@function foo() {
|
|
@return bar;
|
|
}
|
|
|
|
a {
|
|
@function foo() {
|
|
@return baz;
|
|
}
|
|
}
|
|
|
|
color: foo();
|
|
}",
|
|
"a {\n color: foo;\n color: bar;\n}\n"
|
|
);
|
|
error!(
|
|
disallows_unknown_at_rule,
|
|
"@function foo() {
|
|
@foo;
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_media_query,
|
|
"@function foo() {
|
|
@media screen {};
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_at_root,
|
|
"@function foo() {
|
|
@at-root {};
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_charset,
|
|
"@function foo() {
|
|
@charset 'utf-8';
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_extend,
|
|
"@function foo() {
|
|
@extend a;
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_keyframes,
|
|
"@function foo() {
|
|
@keyframes foo {}
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_supports,
|
|
"@function foo() {
|
|
@supports foo {}
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_import,
|
|
"@function foo() {
|
|
@import \"foo.css\";
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_inner_function_declaration,
|
|
"@function foo() {
|
|
@function bar() {}
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_include,
|
|
"@function foo() {
|
|
@include bar;
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"Error: This at-rule is not allowed here."
|
|
);
|
|
error!(
|
|
disallows_selectors,
|
|
"@function foo($a) {
|
|
functiona {
|
|
@return $a;
|
|
}
|
|
}
|
|
|
|
a {
|
|
color: foo(nul);
|
|
}",
|
|
"Error: expected \".\"."
|
|
);
|
|
error!(
|
|
pass_one_arg_to_fn_that_accepts_zero,
|
|
"@function foo() {
|
|
@return red;
|
|
}
|
|
|
|
a {
|
|
color: foo(1);
|
|
}",
|
|
"Error: Only 0 arguments allowed, but 1 was passed."
|
|
);
|
|
error!(
|
|
pass_two_args_to_fn_that_accepts_one,
|
|
"@function foo($a) {
|
|
@return red;
|
|
}
|
|
|
|
a {
|
|
color: foo(1, 2);
|
|
}",
|
|
"Error: Only 1 argument allowed, but 2 were passed."
|
|
);
|
|
error!(
|
|
declaration_inside_function,
|
|
"@function foo() {
|
|
opacity: 1;
|
|
@return 2;
|
|
}",
|
|
"Error: @function rules may not contain declarations."
|
|
);
|
|
error!(
|
|
style_rule_inside_function,
|
|
"@function foo() {
|
|
a {}
|
|
@return 2;
|
|
}",
|
|
"Error: @function rules may not contain style rules."
|
|
);
|
|
test!(
|
|
allows_multiline_comment,
|
|
"@function foo($a) {
|
|
/* foo */
|
|
@return $a;
|
|
}
|
|
|
|
a {
|
|
color: foo(nul);
|
|
}",
|
|
"a {\n color: nul;\n}\n"
|
|
);
|
|
test!(
|
|
allows_multiline_comment_between_args,
|
|
"@function foo /**/ () /**/ {
|
|
@return red;
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"a {\n color: red;\n}\n"
|
|
);
|
|
test!(
|
|
return_inside_each,
|
|
"@function foo() {
|
|
@each $i in 0 {
|
|
@return $i;
|
|
}
|
|
}
|
|
|
|
a {
|
|
color: foo();
|
|
}",
|
|
"a {\n color: 0;\n}\n"
|
|
);
|
|
test!(
|
|
recursive_function_cannot_modify_scope_of_calling_function,
|
|
"@function with-local-variable($recurse) {
|
|
$var: before;
|
|
|
|
@if ($recurse) {
|
|
$a: with-local-variable($recurse: false);
|
|
}
|
|
|
|
$ret: $var;
|
|
$var: after;
|
|
@return $ret;
|
|
}
|
|
|
|
a {
|
|
color: with-local-variable($recurse: true);
|
|
}",
|
|
"a {\n color: before;\n}\n"
|
|
);
|
|
|
|
// todo: return inside if, return inside while, return inside for
|