From d56ad3c3146b112a1b8a0cac3f805780c47ca4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E4=B8=9D?= Date: Sat, 17 Sep 2022 22:33:42 +0800 Subject: [PATCH 1/2] fix: avoid parsing `animation: "none"` to `animation: "none" none`. In the `animation` property, special handling is required when the values of both `animation-name` and `animation-fill-mode` are `none`. --- src/lib.rs | 53 ++++++++++++++++++++++++++++++++++++- src/properties/animation.rs | 6 ++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5a517da5..7cf07fc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8195,10 +8195,38 @@ mod tests { minify_test(".foo { animation-name: test }", ".foo{animation-name:test}"); minify_test(".foo { animation-name: \"test\" }", ".foo{animation-name:test}"); minify_test(".foo { animation-name: foo, bar }", ".foo{animation-name:foo,bar}"); - minify_test(".foo { animation-name: \"revert\" }", ".foo{animation-name:\"revert\"}"); minify_test(".foo { animation-name: \"none\" }", ".foo{animation-name:\"none\"}"); + minify_test(".foo { animation-name: \"none\", foo }", ".foo{animation-name:\"none\",foo}"); let name = crate::properties::animation::AnimationName::parse_string("default"); assert!(matches!(name, Err(..))); + + minify_test(".foo { animation-name: none }", ".foo{animation-name:none}"); + minify_test(".foo { animation-name: none, none }", ".foo{animation-name:none,none}"); + + // Test CSS-wide keywords + minify_test(".foo { animation-name: unset }", ".foo{animation-name:unset}"); + minify_test(".foo { animation-name: \"unset\" }", ".foo{animation-name:\"unset\"}"); + minify_test(".foo { animation-name: \"revert\" }", ".foo{animation-name:\"revert\"}"); + minify_test( + ".foo { animation-name: \"unset\", \"revert\"}", + ".foo{animation-name:\"unset\",\"revert\"}", + ); + minify_test( + ".foo { animation-name: foo, \"revert\"}", + ".foo{animation-name:foo,\"revert\"}", + ); + minify_test( + ".foo { animation-name: \"string\", \"revert\"}", + ".foo{animation-name:string,\"revert\"}", + ); + minify_test( + ".foo { animation-name: \"string\", foo, \"revert\"}", + ".foo{animation-name:string,foo,\"revert\"}", + ); + minify_test( + ".foo { animation-name: \"default\" }", + ".foo{animation-name:\"default\"}", + ); minify_test(".foo { animation-duration: 100ms }", ".foo{animation-duration:.1s}"); minify_test( ".foo { animation-duration: 100ms, 2000ms }", @@ -8265,6 +8293,29 @@ mod tests { ".foo { animation-fill-mode: Backwards,forwards }", ".foo{animation-fill-mode:backwards,forwards}", ); + minify_test(".foo { animation: \"none\" }", ".foo{animation:\"none\"}"); + minify_test(".foo { animation: \"None\" }", ".foo{animation:\"None\"}"); + minify_test(".foo { animation: \"none\", none }", ".foo{animation:\"none\",none}"); + + // Test animation-name + animation-fill-mode + minify_test(".foo { animation: \"none\" 2s both}", ".foo{animation:\"none\" 2s both}"); + minify_test(".foo { animation: both \"none\" 2s}", ".foo{animation:\"none\" 2s both}"); + minify_test(".foo { animation: none \"none\" 2s}", ".foo{animation:\"none\" 2s}"); + minify_test(".foo { animation: none, \"none\" 2s forwards}", ".foo{animation:none,\"none\" 2s forwards}"); + + + minify_test(".foo { animation: \"unset\" }", ".foo{animation:\"unset\"}"); + minify_test(".foo { animation: \"string\" .5s }", ".foo{animation:string .5s}"); + minify_test(".foo { animation: \"unset\" .5s }", ".foo{animation:\"unset\" .5s}"); + minify_test( + ".foo { animation: none, \"unset\" .5s}", + ".foo{animation:none,\"unset\" .5s}", + ); + minify_test( + ".foo { animation: \"unset\" 0s 3s infinite, none }", + ".foo{animation:\"unset\" 0s 3s infinite,none}", + ); + minify_test( ".foo { animation: 3s ease-in 1s infinite reverse both running slidein }", ".foo{animation:slidein 3s ease-in 1s infinite reverse both}", diff --git a/src/properties/animation.rs b/src/properties/animation.rs index 35fa0406..20d05ef3 100644 --- a/src/properties/animation.rs +++ b/src/properties/animation.rs @@ -267,7 +267,11 @@ impl<'i> ToCss for Animation<'i> { self.direction.to_css(dest)?; } - if self.fill_mode != AnimationFillMode::None || AnimationFillMode::parse_string(&name).is_ok() { + // Avoid parsing `animation: "none"` to `animation: "none" none`. + let animation_name_is_none = AnimationName::parse_string(&name).as_ref().map(|n| n == &AnimationName::None).unwrap_or(true); + if self.fill_mode == AnimationFillMode::None && animation_name_is_none { + return Ok(()); + } else if self.fill_mode != AnimationFillMode::None || AnimationFillMode::parse_string(&name).is_ok() { dest.write_char(' ')?; self.fill_mode.to_css(dest)?; } From c0cb7369a6733e10c59dc1b1604f05c2daf9bdea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E4=B8=9D?= Date: Sat, 17 Sep 2022 22:45:30 +0800 Subject: [PATCH 2/2] chore: add more animation test --- src/lib.rs | 27 +++++++++++++++++++++------ src/properties/animation.rs | 5 ++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7cf07fc0..c0dc3ad4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8196,7 +8196,10 @@ mod tests { minify_test(".foo { animation-name: \"test\" }", ".foo{animation-name:test}"); minify_test(".foo { animation-name: foo, bar }", ".foo{animation-name:foo,bar}"); minify_test(".foo { animation-name: \"none\" }", ".foo{animation-name:\"none\"}"); - minify_test(".foo { animation-name: \"none\", foo }", ".foo{animation-name:\"none\",foo}"); + minify_test( + ".foo { animation-name: \"none\", foo }", + ".foo{animation-name:\"none\",foo}", + ); let name = crate::properties::animation::AnimationName::parse_string("default"); assert!(matches!(name, Err(..))); @@ -8293,16 +8296,29 @@ mod tests { ".foo { animation-fill-mode: Backwards,forwards }", ".foo{animation-fill-mode:backwards,forwards}", ); + minify_test(".foo { animation: none }", ".foo{animation:none}"); minify_test(".foo { animation: \"none\" }", ".foo{animation:\"none\"}"); minify_test(".foo { animation: \"None\" }", ".foo{animation:\"None\"}"); minify_test(".foo { animation: \"none\", none }", ".foo{animation:\"none\",none}"); + minify_test(".foo { animation: none, none }", ".foo{animation:none,none}"); + minify_test(".foo { animation: \"none\" none }", ".foo{animation:\"none\"}"); + minify_test(".foo { animation: none none }", ".foo{animation:none}"); // Test animation-name + animation-fill-mode - minify_test(".foo { animation: \"none\" 2s both}", ".foo{animation:\"none\" 2s both}"); - minify_test(".foo { animation: both \"none\" 2s}", ".foo{animation:\"none\" 2s both}"); + minify_test( + ".foo { animation: \"none\" 2s both}", + ".foo{animation:\"none\" 2s both}", + ); + minify_test( + ".foo { animation: both \"none\" 2s}", + ".foo{animation:\"none\" 2s both}", + ); + minify_test(".foo { animation: \"none\" 2s none}", ".foo{animation:\"none\" 2s}"); minify_test(".foo { animation: none \"none\" 2s}", ".foo{animation:\"none\" 2s}"); - minify_test(".foo { animation: none, \"none\" 2s forwards}", ".foo{animation:none,\"none\" 2s forwards}"); - + minify_test( + ".foo { animation: none, \"none\" 2s forwards}", + ".foo{animation:none,\"none\" 2s forwards}", + ); minify_test(".foo { animation: \"unset\" }", ".foo{animation:\"unset\"}"); minify_test(".foo { animation: \"string\" .5s }", ".foo{animation:string .5s}"); @@ -8333,7 +8349,6 @@ mod tests { ".foo { animation: foo 0s 3s infinite }", ".foo{animation:foo 0s 3s infinite}", ); - minify_test(".foo { animation: none }", ".foo{animation:none}"); test( r#" .foo { diff --git a/src/properties/animation.rs b/src/properties/animation.rs index 20d05ef3..5e4602df 100644 --- a/src/properties/animation.rs +++ b/src/properties/animation.rs @@ -268,7 +268,10 @@ impl<'i> ToCss for Animation<'i> { } // Avoid parsing `animation: "none"` to `animation: "none" none`. - let animation_name_is_none = AnimationName::parse_string(&name).as_ref().map(|n| n == &AnimationName::None).unwrap_or(true); + let animation_name_is_none = AnimationName::parse_string(&name) + .as_ref() + .map(|n| n == &AnimationName::None) + .unwrap_or(true); if self.fill_mode == AnimationFillMode::None && animation_name_is_none { return Ok(()); } else if self.fill_mode != AnimationFillMode::None || AnimationFillMode::parse_string(&name).is_ok() {