class SCSSLint::Linter::PropertySortOrder
Checks the declaration order of properties.
Public Instance Methods
check_order(node) { || ... }
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 16 def check_order(node) sortable_props = node.children.select do |child| child.is_a?(Sass::Tree::PropNode) && !ignore_property?(child) end if sortable_props.count >= config.fetch('min_properties', 2) sortable_prop_info = sortable_props.map do |child| name = child.name.join /^(?<vendor>-\w+(-osx)?-)?(?<property>.+)/ =~ name { name: name, vendor: vendor, property: "#{@nested_under}#{property}", node: child } end check_sort_order(sortable_prop_info) check_group_separation(sortable_prop_info) if @group end yield # Continue linting children end
visit_if(node, &block)
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 49 def visit_if(node, &block) check_order(node, &block) visit(node.else) if node.else end
visit_root(_node) { || ... }
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 6 def visit_root(_node) @preferred_order = extract_preferred_order_from_config if @preferred_order && config['separate_groups'] @group = assign_groups(@preferred_order) end yield # Continue linting children end
Private Instance Methods
assign_groups(order)
click to toggle source
When enforcing whether a blank line should separate “groups” of properties, we need to assign those properties to group numbers so we can quickly tell traversing from one property to the other that a blank line is required (since the group number would change).
# File lib/scss_lint/linter/property_sort_order.rb, line 60 def assign_groups(order) group_number = 0 last_was_empty = false order.each_with_object({}) do |property, group| # A gap indicates the start of the next group if property.nil? || property.strip.empty? group_number += 1 unless last_was_empty # Treat multiple gaps as single gap last_was_empty = true next end last_was_empty = false group[property] = group_number end end
check_group_separation(sortable_prop_info)
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 94 def check_group_separation(sortable_prop_info) # rubocop:disable AbcSize group_number = @group[sortable_prop_info.first[:property]] sortable_prop_info[0..-2].zip(sortable_prop_info[1..-1]).each do |first, second| next unless @group[second[:property]] != group_number # We're now in the next group group_number = @group[second[:property]] # The group number has changed, so ensure this property is separated # from the previous property by at least a line (could be a comment, # we don't care, but at least one line that isn't another property). next if first[:node].line < second[:node].line - 1 add_lint second[:node], "Property #{second[:name]} should be " 'separated from the previous group of ' "properties ending with #{first[:name]}" end end
check_sort_order(sortable_prop_info)
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 78 def check_sort_order(sortable_prop_info) sortable_prop_info = sortable_prop_info.uniq { |item| item[:name] } sorted_props = sortable_prop_info.sort { |a, b| compare_properties(a, b) } sorted_props.each_with_index do |prop, index| # Once we reach the portion of the list with unspecified properties, we # can stop checking since we don't care about order after that point break unless specified_property?(prop[:property]) next unless prop != sortable_prop_info[index] add_lint(sortable_prop_info[index][:node], lint_message(sorted_props)) break end end
compare_by_order(a, b, order)
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 150 def compare_by_order(a, b, order) (order.index(a[:property]) || Float::INFINITY) <=> (order.index(b[:property]) || Float::INFINITY) end
compare_by_vendor(a, b)
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 138 def compare_by_vendor(a, b) if a[:vendor] && b[:vendor] a[:vendor] <=> b[:vendor] elsif a[:vendor] -1 elsif b[:vendor] 1 else 0 end end
compare_properties(a, b)
click to toggle source
Compares two properties which can contain a vendor prefix. It allows for a sort order like:
p { border: ... -moz-border-radius: ... -o-border-radius: ... -webkit-border-radius: ... border-radius: ... color: ... }
…where vendor-prefixed properties come before the standard property, and are ordered amongst themselves by vendor prefix.
# File lib/scss_lint/linter/property_sort_order.rb, line 128 def compare_properties(a, b) if a[:property] == b[:property] compare_by_vendor(a, b) elsif @preferred_order compare_by_order(a, b, @preferred_order) else a[:property] <=> b[:property] end end
extract_preferred_order_from_config()
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 155 def extract_preferred_order_from_config case config['order'] when nil nil # No custom order specified when Array config['order'] when String begin file = File.open(File.join(SCSS_LINT_DATA, 'property-sort-orders', "#{config['order']}.txt")) file.read.split("\n").reject { |line| line =~ /^(#|\s*$)/ } rescue Errno::ENOENT raise SCSSLint::Exceptions::LinterError, "Preset property sort order '#{config['order']}' does not exist" end else raise SCSSLint::Exceptions::LinterError, 'Invalid property sort order specified -- must be the name of a ' 'preset or an array of strings' end end
ignore_property?(prop_node)
click to toggle source
Return whether to ignore a property in the sort order.
This includes:
-
properties containing interpolation
-
properties not explicitly defined in the sort order (if ignore_unspecified is set)
# File lib/scss_lint/linter/property_sort_order.rb, line 183 def ignore_property?(prop_node) return true if prop_node.name.any? { |part| !part.is_a?(String) } config['ignore_unspecified'] && @preferred_order && !@preferred_order.include?(prop_node.name.join) end
lint_message(sortable_prop_info)
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 199 def lint_message(sortable_prop_info) props = sortable_prop_info.map { |prop| prop[:name] }.join(', ') "Properties should be ordered #{props}" end
preset_order?()
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 195 def preset_order? config['order'].is_a?(String) end
specified_property?(prop_name)
click to toggle source
# File lib/scss_lint/linter/property_sort_order.rb, line 191 def specified_property?(prop_name) !@preferred_order || @preferred_order.include?(prop_name) end