class SCSSLint::Linter::Shorthand

Checks for the use of the shortest form for properties that can be written in shorthand.

Constants

LIST_LITERAL_REGEX
SHORTHANDABLE_PROPERTIES

Public Instance Methods

visit_prop(node) click to toggle source

@param node [Sass::Tree::Node]

# File lib/scss_lint/linter/shorthand.rb, line 9
def visit_prop(node)
  property_name = node.name.join
  return unless SHORTHANDABLE_PROPERTIES.include?(property_name)

  case node.value
  when Sass::Script::Tree::Literal
    check_script_literal(property_name, node.value)
  when Sass::Script::Tree::ListLiteral
    check_script_list(property_name, node.value)
  end
end

Private Instance Methods

allowed?(size) click to toggle source

@param size [Number] @return [Boolean]

# File lib/scss_lint/linter/shorthand.rb, line 134
def allowed?(size)
  return false unless config['allowed_shorthands']
  config['allowed_shorthands'].map(&:to_i).include?(size)
end
check_script_list(prop, list) click to toggle source

@param prop [String] @param list [Sass::Script::Tree::ListLiteral]

# File lib/scss_lint/linter/shorthand.rb, line 34
def check_script_list(prop, list)
  check_shorthand(prop, list, list.children.map(&:to_sass))
end
check_script_literal(prop, literal) click to toggle source

@param prop [String] @param literal [Sass::Script::Tree::Literal]

# File lib/scss_lint/linter/shorthand.rb, line 40
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
  value.node_parent = literal
  return unless value.is_a?(Sass::Script::Value::String)

  check_script_string(prop, value)
end
check_script_string(prop, script_string) click to toggle source

@param prop [String] @param script_string [Sass::Script::Value::String]

# File lib/scss_lint/linter/shorthand.rb, line 60
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
check_shorthand(prop, node, values) click to toggle source

@param prop [String] @param node [Sass::Script::Value::String] @param values [Array<String>]

# File lib/scss_lint/linter/shorthand.rb, line 70
def check_shorthand(prop, node, values)
  return unless (2..4).member?(values.count)

  shortest_form = condensed_shorthand(*values)
  return if values == shortest_form

  add_lint(node, "Shorthand form for property `#{prop}` should be "                       "written more concisely as `#{shortest_form.join(' ')}` "                       "instead of `#{values.join(' ')}`")
end
condense_to_one_value?(top, right, bottom, left) click to toggle source

@param top [String] @param right [String] @param bottom [String] @param left [String] @return [Boolean]

# File lib/scss_lint/linter/shorthand.rb, line 103
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
condense_to_three_values?(_, right, __, left) click to toggle source

@param right [String] @param left [String] @return [Boolean]

# File lib/scss_lint/linter/shorthand.rb, line 126
def condense_to_three_values?(_, right, __, left)
  return unless allowed?(3)

  right == left
end
condense_to_two_values?(top, right, bottom, left) click to toggle source

@param top [String] @param right [String] @param bottom [String] @param left [String] @return [Boolean]

# File lib/scss_lint/linter/shorthand.rb, line 116
def condense_to_two_values?(top, right, bottom, left)
  return unless allowed?(2)

  top == bottom && right == left ||
    top == bottom && left.nil? && top != right
end
condensed_shorthand(top, right, bottom = nil, left = nil) click to toggle source

@param top [String] @param right [String] @param bottom [String] @param left [String] @return [Array]

# File lib/scss_lint/linter/shorthand.rb, line 86
def condensed_shorthand(top, right, bottom = nil, left = nil)
  if condense_to_one_value?(top, right, bottom, left)
    [top]
  elsif condense_to_two_values?(top, right, bottom, left)
    [top, right]
  elsif condense_to_three_values?(top, right, bottom, left)
    [top, right, bottom]
  else
    [top, right, bottom, left].compact
  end
end