ffaee04613
Adds support for the indented syntax, plain CSS imports, `@forward`, and many other previously missing features.
573 lines
12 KiB
Rust
573 lines
12 KiB
Rust
#[macro_use]
|
|
mod macros;
|
|
|
|
test!(
|
|
basic_toplevel,
|
|
"@media foo {\n a {\n color: red;\n }\n}\n",
|
|
"@media foo {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
error!(
|
|
no_params,
|
|
"@media {\n a {\n color: red;\n }\n}\n", "Error: Expected identifier."
|
|
);
|
|
test!(
|
|
basic_nested,
|
|
"a {\n @media foo {\n color: red;\n }\n}\n",
|
|
"@media foo {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(empty_body, "@media (min-width: 2px) {}", "");
|
|
test!(
|
|
newlines_are_not_emitted_for_child_styles,
|
|
"a {
|
|
@media screen {
|
|
b {
|
|
color: red;
|
|
}
|
|
c {
|
|
color: green;
|
|
}
|
|
}
|
|
}",
|
|
"@media screen {\n a b {\n color: red;\n }\n a c {\n color: green;\n }\n}\n"
|
|
);
|
|
test!(
|
|
multiple_identifiers_in_query,
|
|
"@media not screen {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media not screen {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
multiple_identifiers_in_query_second_is_and,
|
|
"@media print and (foo: 1 2 3) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media print and (foo: 1 2 3) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
single_identifier_inside_parens,
|
|
"@media (color) {a {color: red;}}",
|
|
"@media (color) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
quoted_colon_in_parens,
|
|
"@media screen and (\":\") {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media screen and (:) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
multiline_comments_everywhere,
|
|
"@media/**/foo/**/and/**/(/**/bar/**/)/**/{
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media foo and (bar) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
comparison_in_query,
|
|
"@media (100px < 400px) {
|
|
a {
|
|
interpolation: in-parens
|
|
}
|
|
}",
|
|
"@media (100px < 400px) {\n a {\n interpolation: in-parens;\n }\n}\n"
|
|
);
|
|
test!(
|
|
interpolated_comparison_in_query,
|
|
"@media (#{100px < 400px}) {
|
|
a {
|
|
interpolation: in-parens
|
|
}
|
|
}",
|
|
"@media (true) {\n a {\n interpolation: in-parens;\n }\n}\n"
|
|
);
|
|
test!(
|
|
single_eq_in_query,
|
|
"@media (height=600px) {
|
|
a {
|
|
b: c
|
|
}
|
|
}
|
|
",
|
|
"@media (height = 600px) {\n a {\n b: c;\n }\n}\n"
|
|
);
|
|
test!(
|
|
double_eq_in_query,
|
|
"@media (height==600px) {
|
|
a {
|
|
b: c
|
|
}
|
|
}
|
|
",
|
|
"@media (false) {\n a {\n b: c;\n }\n}\n"
|
|
);
|
|
test!(
|
|
newline_emitted_for_different_toplevel_rulesets,
|
|
"@media print {
|
|
a {
|
|
color: red;
|
|
}
|
|
|
|
b {
|
|
color: green;
|
|
}
|
|
}",
|
|
"@media print {\n a {\n color: red;\n }\n b {\n color: green;\n }\n}\n"
|
|
);
|
|
test!(
|
|
removes_media_if_all_children_are_blank,
|
|
"@media foo {
|
|
a {}
|
|
}",
|
|
""
|
|
);
|
|
test!(
|
|
correct_order_of_children_when_merging,
|
|
"@media (foo) {
|
|
@media (bar) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}
|
|
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (foo) and (bar) {\n a {\n color: red;\n }\n}\n@media (foo) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
newline_emitted_before_media_when_following_ruleset,
|
|
"a {
|
|
color: red;
|
|
}
|
|
@media print {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"a {\n color: red;\n}\n\n@media print {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
no_newline_emitted_between_two_media_rules,
|
|
"@media print {
|
|
a {
|
|
color: red;
|
|
}
|
|
}
|
|
@media print {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media print {\n a {\n color: red;\n }\n}\n@media print {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
no_newline_emitted_between_two_media_rules_when_in_same_ruleset,
|
|
"a {
|
|
@media foo {
|
|
color: red;
|
|
}
|
|
|
|
@media bar {
|
|
color: green;
|
|
}
|
|
}",
|
|
"@media foo {\n a {\n color: red;\n }\n}\n@media bar {\n a {\n color: green;\n }\n}\n"
|
|
);
|
|
test!(
|
|
allows_interpolated_at_rule,
|
|
"@#{media} (true) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (true) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
no_newline_between_two_media_following_ruleset,
|
|
"a {
|
|
color: red;
|
|
}
|
|
|
|
@media (min-width: 0px) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 0px) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"a {\n color: red;\n}\n\n@media (min-width: 0px) {\n a {\n color: red;\n }\n}\n@media (min-width: 0px) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
no_newline_after_media_after_ruleset,
|
|
"a {
|
|
color: red;
|
|
}
|
|
|
|
@media (min-width: 0px) {
|
|
b {
|
|
color: red;
|
|
}
|
|
}
|
|
|
|
d {
|
|
color: red;
|
|
}",
|
|
"a {\n color: red;\n}\n\n@media (min-width: 0px) {\n b {\n color: red;\n }\n}\nd {\n color: red;\n}\n"
|
|
);
|
|
test!(
|
|
no_newline_after_media_when_outer,
|
|
"@media (min-width: 0px) {
|
|
b {
|
|
color: red;
|
|
}
|
|
}
|
|
|
|
d {
|
|
color: red;
|
|
}",
|
|
"@media (min-width: 0px) {\n b {\n color: red;\n }\n}\nd {\n color: red;\n}\n"
|
|
);
|
|
test!(
|
|
newline_after_media_when_inner,
|
|
"a {
|
|
@media (max-width: 0px) {
|
|
color: red;
|
|
}
|
|
}
|
|
|
|
a {
|
|
color: red;
|
|
}",
|
|
"@media (max-width: 0px) {\n a {\n color: red;\n }\n}\n\na {\n color: red;\n}\n"
|
|
);
|
|
test!(
|
|
nested_media_with_compatible_queries,
|
|
"@media (foo) {
|
|
@media (bar) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}
|
|
}",
|
|
"@media (foo) and (bar) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
nested_media_with_incompatible_queries,
|
|
"@media foo {
|
|
@media bar {
|
|
a {
|
|
color: red;
|
|
}
|
|
}
|
|
}",
|
|
""
|
|
);
|
|
test!(
|
|
removes_media_if_all_children_are_placeholder,
|
|
"@media foo {
|
|
%a {
|
|
color: red;
|
|
}
|
|
}",
|
|
""
|
|
);
|
|
test!(
|
|
plain_import_inside_media_is_not_moved_to_top,
|
|
r#"@media foo {
|
|
a {
|
|
color: red;
|
|
}
|
|
|
|
@import "foo.css";
|
|
}"#,
|
|
"@media foo {\n a {\n color: red;\n }\n @import \"foo.css\";\n}\n"
|
|
);
|
|
error!(
|
|
media_feature_missing_closing_paren,
|
|
"@media foo and (bar:a", "Error: expected \")\"."
|
|
);
|
|
error!(
|
|
media_feature_missing_curly_brace_after_hash,
|
|
"@media foo and # {}", "Error: expected \"{\"."
|
|
);
|
|
error!(
|
|
// note: dart-sass gives error "Expected expression"
|
|
nothing_after_not_in_parens,
|
|
"@media (not", "Error: Expected whitespace."
|
|
);
|
|
error!(
|
|
nothing_after_and,
|
|
"@media foo and", "Error: Expected whitespace."
|
|
);
|
|
error!(nothing_after_or, "@media foo or", r#"Error: expected "{"."#);
|
|
error!(
|
|
no_parens_after_and,
|
|
"@media foo and bar {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"Error: expected media condition in parentheses."
|
|
);
|
|
test!(
|
|
query_starts_with_interpolation,
|
|
"@media #{foo} {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media foo {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
query_is_parens_with_comma,
|
|
"@media (foo, bar) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (foo, bar) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
query_is_parens_with_space_before_comma,
|
|
"@media (foo , bar) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (foo, bar) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
query_and_first_has_no_parens,
|
|
"@media foo and (bar) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media foo and (bar) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
query_comma_separated_list_both_parens,
|
|
"@media (foo), (bar) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (foo), (bar) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
query_comma_separated_list_both_parens_space_before_paren,
|
|
"@media (foo) , (bar) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (foo), (bar) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
query_comma_separated_list_loud_comments,
|
|
"@media /**/foo/**/,/**/bar/**/ {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media foo, bar {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
query_not_paren,
|
|
"@media not (color) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media not (color) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
many_parens,
|
|
"@media (((color))) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (((color))) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
many_parens_around_and,
|
|
"@media ((screen and (color))) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media ((color)) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
newline_between_media_rules_declared_at_root_inside_each,
|
|
"@each $a in 1 2 3 {
|
|
a {
|
|
@media foo {
|
|
b {
|
|
color: $a;
|
|
}
|
|
}
|
|
|
|
color: foo;
|
|
}
|
|
}",
|
|
"a {\n color: foo;\n}\n@media foo {\n a b {\n color: 1;\n }\n}\n\na {\n color: foo;\n}\n@media foo {\n a b {\n color: 2;\n }\n}\n\na {\n color: foo;\n}\n@media foo {\n a b {\n color: 3;\n }\n}\n"
|
|
);
|
|
test!(
|
|
newline_between_media_rules_declared_at_root_inside_each_with_preceding_style_rule,
|
|
"@each $a in 1 2 {
|
|
a {
|
|
color: red;
|
|
}
|
|
|
|
@media foo {
|
|
a {
|
|
color: $a;
|
|
}
|
|
}
|
|
}",
|
|
"a {\n color: red;\n}\n\n@media foo {\n a {\n color: 1;\n }\n}\na {\n color: red;\n}\n\n@media foo {\n a {\n color: 2;\n }\n}\n"
|
|
);
|
|
test!(
|
|
no_newline_between_media_rules_when_invisble_rule_between,
|
|
"a {}
|
|
|
|
@media (min-width: 5px) {
|
|
a {
|
|
color: 1;
|
|
}
|
|
}
|
|
|
|
a {}
|
|
|
|
@media (min-width: 5px) {
|
|
a {
|
|
color: 1;
|
|
}
|
|
}",
|
|
"@media (min-width: 5px) {\n a {\n color: 1;\n }\n}\n@media (min-width: 5px) {\n a {\n color: 1;\n }\n}\n"
|
|
);
|
|
test!(
|
|
two_media_rules_in_content_block,
|
|
"@mixin foo() {
|
|
@content;
|
|
}
|
|
|
|
@include foo {
|
|
@media foo {
|
|
a {
|
|
color: red;
|
|
}
|
|
}
|
|
@media foo {
|
|
b {
|
|
color: red;
|
|
}
|
|
}
|
|
}",
|
|
"@media foo {\n a {\n color: red;\n }\n}\n@media foo {\n b {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
splits_child_nodes_when_preceding_media,
|
|
"@media (foo) {
|
|
@media (prefers-reduced-motion: reduce) {
|
|
a {
|
|
transition: none;
|
|
}
|
|
}
|
|
|
|
a {
|
|
color: red;
|
|
}
|
|
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (foo) and (prefers-reduced-motion: reduce) {\n a {\n transition: none;\n }\n}\n@media (foo) {\n a {\n color: red;\n }\n}\n@media (foo) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
doesnt_split_child_nodes_when_trailing_media,
|
|
"@media (foo) {
|
|
a {
|
|
color: red;
|
|
}
|
|
|
|
a {
|
|
color: red;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
a {
|
|
transition: none;
|
|
}
|
|
}
|
|
}",
|
|
"@media (foo) {\n a {\n color: red;\n }\n a {\n color: red;\n }\n}\n@media (foo) and (prefers-reduced-motion: reduce) {\n a {\n transition: none;\n }\n}\n"
|
|
);
|
|
test!(
|
|
#[ignore = "our is_invisible_check inside css tree is flawed here"]
|
|
doesnt_split_child_nodes_when_leading_but_invisible_media,
|
|
"@media (foo) {
|
|
@media (prefers-reduced-motion: reduce) {}
|
|
|
|
a {
|
|
color: red;
|
|
}
|
|
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (foo) {\n a {\n color: red;\n }\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
media_has_url_in_parens,
|
|
"@media (url) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}",
|
|
"@media (url) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
test!(
|
|
#[ignore = "our is_invisible_check inside css tree is flawed here"]
|
|
media_does_not_split_when_child_rule_has_invisible_media,
|
|
"@media (min-width: 1px) {
|
|
.first {
|
|
font-weight: 100;
|
|
|
|
@media (min-width: 2px) {}
|
|
}
|
|
|
|
.second {
|
|
font-weight: 200;
|
|
}
|
|
}",
|
|
"@media (url) {\n a {\n color: red;\n }\n}\n"
|
|
);
|
|
error!(
|
|
media_query_has_quoted_closing_paren,
|
|
r#"@media ('a)'w) {
|
|
a {
|
|
color: red;
|
|
}
|
|
}"#,
|
|
"Error: expected no more input."
|
|
);
|