lib/scss_lint/linter/indentation.rb in scss_lint-0.42.2 vs lib/scss_lint/linter/indentation.rb in scss_lint-0.43.0
- old
+ new
@@ -4,11 +4,20 @@
include LinterRegistry
def visit_root(_node)
@indent_width = config['width'].to_i
@indent_character = config['character'] || 'space'
+ if @indent_character == 'tab'
+ @other_character = ' '
+ @other_character_name = 'space'
+ else
+ @other_character = "\t"
+ @other_character_name = 'tab'
+ end
+ @allow_non_nested_indentation = config['allow_non_nested_indentation']
@indent = 0
+ @indentations = {}
yield
end
def check_and_visit_children(node)
# Don't continue checking children as the moment a parent's indentation is
@@ -26,44 +35,36 @@
# Ignore the case where the node is on the same line as its previous
# sibling or its parent, as indentation isn't possible
return if nodes_on_same_line?(previous_node(node), node)
- if @indent_character == 'tab'
- other_character = ' '
- other_character_name = 'space'
- else
- other_character = "\t"
- other_character_name = 'tab'
- end
-
- check_indent_width(node, other_character, @indent_character, other_character_name)
+ check_indent_width(node)
end
- def check_indent_width(node, other_character, character_name, other_character_name)
+ def check_indent_width(node)
actual_indent = node_indent(node)
- if actual_indent.include?(other_character)
+ if actual_indent.include?(@other_character)
add_lint(node.line,
- "Line should be indented with #{character_name}s, " \
- "not #{other_character_name}s")
+ "Line should be indented with #{@indent_character}s, " \
+ "not #{@other_character_name}s")
return true
end
- if config['allow_non_nested_indentation']
- check_arbitrary_indent(node, actual_indent.length, character_name)
+ if @allow_non_nested_indentation
+ check_arbitrary_indent(node, actual_indent.length)
else
- check_regular_indent(node, actual_indent.length, character_name)
+ check_regular_indent(node, actual_indent.length)
end
end
# Deal with `else` statements, which require special care since they are
# considered children of `if` statements.
def visit_if(node)
check_indentation(node)
- if config['allow_non_nested_indentation']
+ if @allow_non_nested_indentation
yield # Continue linting else statement
else
visit(node.else) if node.else
end
end
@@ -137,57 +138,45 @@
return unless first_child_source = node.children.first.source_range
same_position?(node.source_range.end_pos, first_child_source.start_pos)
end
- def check_regular_indent(node, actual_indent, character_name)
+ def check_regular_indent(node, actual_indent)
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")
+ add_lint(node.line, lint_message(@indent, actual_indent))
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)
+ def check_arbitrary_indent(node, actual_indent)
+ return if check_root_ruleset_indent(node, actual_indent)
+
+ # Allow any root-level node (i.e. one that would normally have an indent
+ # of zero) to have an arbitrary amount of indent
+ return if @indent == 0
+
+ return if one_shift_greater_than_parent?(node, actual_indent)
+ parent_indent = node_indent(node_indent_parent(node)).length
+ expected_indent = parent_indent + @indent_width
+ add_lint(node.line, lint_message(expected_indent, actual_indent))
+ true
+ end
+
+ # Allow rulesets to be indented any amount when the indent is zero, as long
+ # as it's a multiple of the indent width
+ def check_root_ruleset_indent(node, actual_indent)
+ # Whether node is a ruleset not nested within any other ruleset.
+ if @indent == 0 && node.is_a?(Sass::Tree::RuleNode)
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")
+ add_lint(node.line, lint_message("a multiple of #{@indent_width}", actual_indent))
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_indent_parent(node)).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
+ false
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]
@@ -200,11 +189,11 @@
# Return indentation of a node.
#
# @param node [Sass::Tree::Node]
# @return [Integer]
def node_indent(node)
- engine.lines[node.line - 1][/^(\s*)/, 1]
+ @indentations[node] ||= engine.lines[node.line - 1][/^(\s*)/]
end
def node_indent_parent(node)
if else_node?(node)
while node.node_parent.is_a?(Sass::Tree::IfNode) &&
@@ -212,8 +201,13 @@
node = node.node_parent
end
end
node.node_parent
+ end
+
+ def lint_message(expected, actual)
+ "Line should be indented #{expected} #{@indent_character}s, but was " \
+ "indented #{actual} #{@indent_character}s"
end
end
end