From 3dba6e3757aaf7df9ec8d462cd8dc7f3354f38c9 Mon Sep 17 00:00:00 2001 From: Mog Nesbitt Date: Sat, 8 Mar 2025 13:19:51 +1300 Subject: [PATCH] Prefer !important rules over non-!important rules in the same ruleset Previously, the css rule "color: black !important; color: red;" would be collapsed to "color: red;" as the processor did not take whether the !important flag was set inside the same rule. This commit makes the Declaration Value initializer take notice of the !important flag and correctly handle it. --- CHANGELOG.md | 1 + lib/css_parser/rule_set.rb | 9 ++++++--- test/test_merging.rb | 12 ++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87c2a87..23470e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Unreleased +* Prefer `!important` rules over non-`!important` rules in the same ruleset * Minor performance improvements ### Version v1.21.0 diff --git a/lib/css_parser/rule_set.rb b/lib/css_parser/rule_set.rb index 5c06a92..467f2b5 100644 --- a/lib/css_parser/rule_set.rb +++ b/lib/css_parser/rule_set.rb @@ -89,17 +89,20 @@ def initialize(declarations = {}) # puts declarations['margin'] # => # # - # If the property already exists its value will be over-written. + # If the property already exists its value will be over-written unless it was !important and the new value + # is not !important. # If the value is empty - property will be deleted def []=(property, value) property = normalize_property(property) + currently_important = declarations[property]&.important - if value.is_a?(Value) + if value.is_a?(Value) && (!currently_important || value.important) declarations[property] = value elsif value.to_s.strip.empty? delete property else - declarations[property] = Value.new(value) + value = Value.new(value) + declarations[property] = value if !currently_important || value.important end rescue ArgumentError => e raise e.exception, "#{property} #{e.message}" diff --git a/test/test_merging.rb b/test/test_merging.rb index 360f2ae..83f8e41 100644 --- a/test/test_merging.rb +++ b/test/test_merging.rb @@ -109,6 +109,18 @@ def test_merging_important assert_equal 'black !important;', merged['color'] end + def test_prioritising_important_over_non_important_in_the_same_block + rs1 = RuleSet.new(block: 'color: black !important; color: red;') + merged = CssParser.merge(rs1) + assert_equal 'black !important;', merged['color'] + end + + def test_prioritising_two_important_declarations_in_the_same_block + rs1 = RuleSet.new(block: 'color: black !important; color: red !important;') + merged = CssParser.merge(rs1) + assert_equal 'red !important;', merged['color'] + end + def test_merging_multiple_important rs1 = RuleSet.new(block: 'color: black !important;', specificity: 1000) rs2 = RuleSet.new(block: 'color: red !important;', specificity: 1)