lib/scss_lint/linter/indentation.rb in scss-lint-0.34.0 vs lib/scss_lint/linter/indentation.rb in scss-lint-0.35.0
- old
+ new
@@ -1,8 +1,8 @@
module SCSSLint
# Checks for consistent indentation of nested declarations and rule sets.
- class Linter::Indentation < Linter
+ class Linter::Indentation < Linter # rubocop:disable ClassLength
include LinterRegistry
def visit_root(_node)
@indent_width = config['width'].to_i
@indent_character = config['character'] || 'space'
@@ -38,27 +38,24 @@
check_indent_width(node, other_character, @indent_character, other_character_name)
end
def check_indent_width(node, other_character, character_name, other_character_name)
- actual_indent = engine.lines[node.line - 1][/^(\s*)/, 1]
+ actual_indent = node_indent(node)
if actual_indent.include?(other_character)
add_lint(node.line,
"Line should be indented with #{character_name}s, " \
"not #{other_character_name}s")
return true
end
- unless allow_arbitrary_indent?(node) || actual_indent.length == @indent
- add_lint(node.line,
- "Line should be indented #{@indent} #{character_name}s, " \
- "but was indented #{actual_indent.length} #{character_name}s")
- return true
+ if config['allow_non_nested_indentation']
+ check_arbitrary_indent(node, actual_indent.length, character_name)
+ else
+ check_regular_indent(node, actual_indent.length, character_name)
end
-
- false
end
# Deal with `else` statements
def visit_if(node, &block)
check_and_visit_children(node, &block)
@@ -129,12 +126,72 @@
return unless first_child_source = node.children.first.source_range
same_position?(node.source_range.end_pos, first_child_source.start_pos)
end
- def allow_arbitrary_indent?(node)
- @indent == 0 &&
- config['allow_non_nested_indentation'] &&
- node.is_a?(Sass::Tree::RuleNode)
+ def check_regular_indent(node, actual_indent, character_name)
+ return if actual_indent == @indent
+
+ add_lint(node.line,
+ "Line should be indented #{@indent} #{character_name}s, " \
+ "but was indented #{actual_indent} #{character_name}s")
+ true
+ end
+
+ def check_arbitrary_indent(node, actual_indent, character_name) # rubocop:disable CyclomaticComplexity, MethodLength, LineLength
+ # Allow rulesets to be indented any amount when the indent is zero, as
+ # long as it's a multiple of the indent width
+ if ruleset_under_root_node?(node)
+ unless actual_indent % @indent_width == 0
+ add_lint(node.line,
+ "Line must be indented a multiple of #{@indent_width} " \
+ "#{character_name}s, but was indented #{actual_indent} #{character_name}s")
+ return true
+ end
+ end
+
+ if @indent == 0
+ unless node.is_a?(Sass::Tree::RuleNode) || actual_indent == 0
+ add_lint(node.line,
+ "Line should be indented 0 #{character_name}s, " \
+ "but was indented #{actual_indent} #{character_name}s")
+ return true
+ end
+ elsif !one_shift_greater_than_parent?(node, actual_indent)
+ parent_indent = node_indent(node.node_parent).length
+ expected_indent = parent_indent + @indent_width
+
+ add_lint(node.line,
+ "Line should be indented #{expected_indent} #{character_name}s, " \
+ "but was indented #{actual_indent} #{character_name}s")
+ return true
+ end
+ end
+
+ # Returns whether node is a ruleset not nested within any other ruleset.
+ #
+ # @param node [Sass::Tree::Node]
+ # @return [true,false]
+ def ruleset_under_root_node?(node)
+ @indent == 0 && node.is_a?(Sass::Tree::RuleNode)
+ end
+
+ # Returns whether node is indented exactly one indent width greater than its
+ # parent.
+ #
+ # @param node [Sass::Tree::Node]
+ # @return [true,false]
+ def one_shift_greater_than_parent?(node, actual_indent)
+ parent_indent = node_indent(node.node_parent).length
+ expected_indent = parent_indent + @indent_width
+ expected_indent == actual_indent
+ end
+
+ # Return indentation of a node.
+ #
+ # @param node [Sass::Tree::Node]
+ # @return [Integer]
+ def node_indent(node)
+ engine.lines[node.line - 1][/^(\s*)/, 1]
end
end
end