From 720eb34682bb776694cb2ba4abb88aec8ecc0d62 Mon Sep 17 00:00:00 2001 From: J Smith Date: Fri, 16 Apr 2021 14:36:29 -0300 Subject: [PATCH 1/2] Allow CSS functions to be used when expanding dimensions shorthand --- CHANGELOG.md | 2 +- lib/css_parser/regexps.rb | 16 ++++++++ lib/css_parser/rule_set.rb | 8 +++- test/test_rule_set_expanding_shorthand.rb | 48 +++++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de60100..be37493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Unreleased - * Put diff here + * Allow CSS functions to be used in CssParser::RuleSet#expand_dimensions_shorthand! [#126](https://github.com/premailer/css_parser/pull/126) ### Version 1.9.0 diff --git a/lib/css_parser/regexps.rb b/lib/css_parser/regexps.rb index 9b3bcf6..a76ffda 100644 --- a/lib/css_parser/regexps.rb +++ b/lib/css_parser/regexps.rb @@ -58,6 +58,22 @@ def self.regex_possible_values(*values) RE_BORDER_STYLE = /(\s*^)?(none|hidden|dotted|dashed|solid|double|dot-dash|dot-dot-dash|wave|groove|ridge|inset|outset)(\s*$)?/imx.freeze RE_BORDER_UNITS = Regexp.union(BOX_MODEL_UNITS_RX, /(thin|medium|thick)/i) + # Functions like calc, var, clamp, etc. + RE_FUNCTIONS = / + ( + [a-z0-9-]+ # function name + ) + (?> + \( # opening parenthesis + (?: + ([^()]+) + | # recursion via subexpression + \g<0> + )* + \) # closing parenthesis + ) + /imx.freeze + # Patterns for specificity calculations NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX_NC = / (?:\.\w+) # classes diff --git a/lib/css_parser/rule_set.rb b/lib/css_parser/rule_set.rb index 793e80f..82cbc87 100644 --- a/lib/css_parser/rule_set.rb +++ b/lib/css_parser/rule_set.rb @@ -24,6 +24,8 @@ class RuleSet ['border-width', %w[border-top-width border-right-width border-bottom-width border-left-width]] ].freeze + WHITESPACE_REPLACEMENT = '___SPACE___' + class Declarations class Value attr_reader :value @@ -357,6 +359,7 @@ def expand_dimensions_shorthand! # :nodoc: # # TODO: rgba, hsl, hsla value.gsub!(RE_COLOUR) { |c| c.gsub(/(\s*,\s*)/, ',') } + value.gsub!(RE_FUNCTIONS) { |c| c.gsub(/\s+/, WHITESPACE_REPLACEMENT) } matches = value.strip.split(/\s+/) @@ -375,7 +378,10 @@ def expand_dimensions_shorthand! # :nodoc: end t, r, b, l = values - replacement = {top => t, right => r, bottom => b, left => l} + + replacement = {top => t, right => r, bottom => b, left => l}.transform_values do |replacement_value| + replacement_value.gsub(WHITESPACE_REPLACEMENT, ' ') + end declarations.replace_declaration!(property, replacement, preserve_importance: true) end diff --git a/test/test_rule_set_expanding_shorthand.rb b/test/test_rule_set_expanding_shorthand.rb index 2d41018..792285e 100644 --- a/test/test_rule_set_expanding_shorthand.rb +++ b/test/test_rule_set_expanding_shorthand.rb @@ -296,6 +296,54 @@ def test_expanding_important_shorthand_with_replaced_properties assert_equal expected_declarations, declarations end + def test_functions_with_many_spaces + shorthand = 'margin: calc(1em / 4 * var(--foo));' + declarations = expand_declarations(shorthand) + expected_declarations = { + 'margin-top' => 'calc(1em / 4 * var(--foo))', + 'margin-bottom' => 'calc(1em / 4 * var(--foo))', + 'margin-left' => 'calc(1em / 4 * var(--foo))', + 'margin-right' => 'calc(1em / 4 * var(--foo))' + } + assert_equal expected_declarations, declarations + end + + def test_functions_with_no_spaces + shorthand = 'margin: calc(1em/4*4);' + declarations = expand_declarations(shorthand) + expected_declarations = { + 'margin-top' => 'calc(1em/4*4)', + 'margin-bottom' => 'calc(1em/4*4)', + 'margin-left' => 'calc(1em/4*4)', + 'margin-right' => 'calc(1em/4*4)' + } + assert_equal expected_declarations, declarations + end + + def test_functions_with_one_space + shorthand = 'margin: calc(1em /4);' + declarations = expand_declarations(shorthand) + expected_declarations = { + 'margin-top' => 'calc(1em /4)', + 'margin-bottom' => 'calc(1em /4)', + 'margin-left' => 'calc(1em /4)', + 'margin-right' => 'calc(1em /4)' + } + assert_equal expected_declarations, declarations + end + + def test_functions_with_commas + shorthand = 'margin: clamp(1rem, 2.5vw, 2rem)' + declarations = expand_declarations(shorthand) + expected_declarations = { + 'margin-top' => 'clamp(1rem, 2.5vw, 2rem)', + 'margin-bottom' => 'clamp(1rem, 2.5vw, 2rem)', + 'margin-left' => 'clamp(1rem, 2.5vw, 2rem)', + 'margin-right' => 'clamp(1rem, 2.5vw, 2rem)' + } + assert_equal expected_declarations, declarations + end + protected def expand_declarations(declarations) From 2b656393ce6c9702f3c98cf6041e232457cf5e63 Mon Sep 17 00:00:00 2001 From: J Smith Date: Mon, 26 Jul 2021 12:18:41 -0300 Subject: [PATCH 2/2] Move whitespace preserving split to `RuleSet#split_value_preserving_whitespace` --- lib/css_parser/rule_set.rb | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/css_parser/rule_set.rb b/lib/css_parser/rule_set.rb index 82cbc87..bd880a8 100644 --- a/lib/css_parser/rule_set.rb +++ b/lib/css_parser/rule_set.rb @@ -359,9 +359,8 @@ def expand_dimensions_shorthand! # :nodoc: # # TODO: rgba, hsl, hsla value.gsub!(RE_COLOUR) { |c| c.gsub(/(\s*,\s*)/, ',') } - value.gsub!(RE_FUNCTIONS) { |c| c.gsub(/\s+/, WHITESPACE_REPLACEMENT) } - matches = value.strip.split(/\s+/) + matches = split_value_preserving_function_whitespace(value) case matches.length when 1 @@ -377,11 +376,7 @@ def expand_dimensions_shorthand! # :nodoc: raise ArgumentError, "Cannot parse #{value}" end - t, r, b, l = values - - replacement = {top => t, right => r, bottom => b, left => l}.transform_values do |replacement_value| - replacement_value.gsub(WHITESPACE_REPLACEMENT, ' ') - end + replacement = [top, right, bottom, left].zip(values).to_h declarations.replace_declaration!(property, replacement, preserve_importance: true) end @@ -640,6 +635,19 @@ def parse_selectors!(selectors) # :nodoc: s end end + + def split_value_preserving_function_whitespace(value) + split_value = value.gsub(RE_FUNCTIONS) do |c| + c.gsub!(/\s+/, WHITESPACE_REPLACEMENT) + c + end + + matches = split_value.strip.split(/\s+/) + + matches.each do |c| + c.gsub!(WHITESPACE_REPLACEMENT, ' ') + end + end end class OffsetAwareRuleSet < RuleSet