lib/scss_lint/linter/shorthand.rb in scss-lint-0.37.0 vs lib/scss_lint/linter/shorthand.rb in scss-lint-0.38.0

- old
+ new

@@ -1,11 +1,13 @@ +# rubocop:disable Metrics/CyclomaticComplexity module SCSSLint # Checks for the use of the shortest form for properties that can be written # in shorthand. class Linter::Shorthand < Linter include LinterRegistry + # @param node [Sass::Tree::Node] def visit_prop(node) property_name = node.name.join return unless SHORTHANDABLE_PROPERTIES.include?(property_name) case node.value @@ -25,14 +27,18 @@ border-width margin padding ] + # @param prop [String] + # @param list [Sass::Script::Tree::ListLiteral] def check_script_list(prop, list) check_shorthand(prop, list, list.children.map(&:to_sass)) end + # @param prop [String] + # @param literal [Sass::Script::Tree::Literal] def check_script_literal(prop, literal) value = literal.value # HACK: node_parent may not be initialized at this point, so we need to # set it ourselves @@ -47,17 +53,22 @@ (\S+\s+\S+(\s+\S+){0,2}) # Two to four values separated by spaces (\s+!\w+)? # Ignore `!important` priority overrides \z /x + # @param prop [String] + # @param script_string [Sass::Script::Value::String] def check_script_string(prop, script_string) return unless script_string.type == :identifier return unless values = script_string.value.strip[LIST_LITERAL_REGEX, 1] check_shorthand(prop, script_string, values.split) end + # @param prop [String] + # @param node [Sass::Script::Value::String] + # @param values [Array<String>] def check_shorthand(prop, node, values) return unless (2..4).member?(values.count) shortest_form = condensed_shorthand(*values) return if values == shortest_form @@ -65,30 +76,64 @@ add_lint(node, "Shorthand form for property `#{prop}` should be " \ "written more concisely as `#{shortest_form.join(' ')}` " \ "instead of `#{values.join(' ')}`") end + # @param top [String] + # @param right [String] + # @param bottom [String] + # @param left [String] + # @return [Array] def condensed_shorthand(top, right, bottom = nil, left = nil) - if can_condense_to_one_value(top, right, bottom, left) + if condense_to_one_value?(top, right, bottom, left) [top] - elsif can_condense_to_two_values(top, right, bottom, left) + elsif condense_to_two_values?(top, right, bottom, left) [top, right] - elsif right == left + elsif condense_to_three_values?(top, right, bottom, left) [top, right, bottom] else [top, right, bottom, left].compact end end - def can_condense_to_one_value(top, right, bottom, left) + # @param top [String] + # @param right [String] + # @param bottom [String] + # @param left [String] + # @return [Boolean] + def condense_to_one_value?(top, right, bottom, left) + return unless allowed?(1) return unless top == right top == bottom && (bottom == left || left.nil?) || bottom.nil? && left.nil? end - def can_condense_to_two_values(top, right, bottom, left) + # @param top [String] + # @param right [String] + # @param bottom [String] + # @param left [String] + # @return [Boolean] + def condense_to_two_values?(top, right, bottom, left) + return unless allowed?(2) + top == bottom && right == left || top == bottom && left.nil? && top != right + end + + # @param right [String] + # @param left [String] + # @return [Boolean] + def condense_to_three_values?(_, right, __, left) + return unless allowed?(3) + + right == left + end + + # @param size [Number] + # @return [Boolean] + def allowed?(size) + return false unless config['allowed_shorthands'] + config['allowed_shorthands'].map(&:to_i).include?(size) end end end