lib/scss_lint/linter.rb in scss_lint-0.42.2 vs lib/scss_lint/linter.rb in scss_lint-0.43.0
- old
+ new
@@ -1,11 +1,27 @@
module SCSSLint
# Defines common functionality available to all linters.
- class Linter < Sass::Tree::Visitors::Base
+ class Linter < Sass::Tree::Visitors::Base # rubocop:disable ClassLength
include SelectorVisitor
include Utils
+ class << self
+ attr_accessor :simple_name
+
+ # When defining a Linter class, define its simple name as well. This
+ # assumes that the module hierarchy of every linter starts with
+ # `SCSSLint::Linter::`, and removes this part of the class name.
+ #
+ # `SCSSLint::Linter::Foo.simple_name` #=> "Foo"
+ # `SCSSLint::Linter::Compass::Bar.simple_name` #=> "Compass::Bar"
+ def inherited(linter)
+ name_parts = linter.name.split('::')
+ name = name_parts.length < 3 ? '' : name_parts[2..-1].join('::')
+ linter.simple_name = name
+ end
+ end
+
attr_reader :config, :engine, :lints
# Create a linter.
def initialize
@lints = []
@@ -27,11 +43,11 @@
end
# Return the human-friendly name of this linter as specified in the
# configuration file and in lint descriptions.
def name
- self.class.name.split('::')[2..-1].join('::')
+ self.class.simple_name
end
protected
# Helper for creating lint from a parse tree node
@@ -59,20 +75,10 @@
end
Location.new(range.start_pos.line, range.start_pos.offset, length)
end
- # @param source_position [Sass::Source::Position]
- # @param offset [Integer]
- # @return [String] the character at the given [Sass::Source::Position]
- def character_at(source_position, offset = 0)
- actual_line = source_position.line - 1
- actual_offset = source_position.offset + offset - 1
-
- engine.lines.size > actual_line && engine.lines[actual_line][actual_offset]
- end
-
# Extracts the original source code given a range.
#
# @param source_range [Sass::Source::Range]
# @return [String] the original source code
def source_from_range(source_range) # rubocop:disable Metrics/AbcSize
@@ -143,10 +149,20 @@
end
end
private
+ def visit_comment(_node)
+ # Don't lint children of comments by default, as the Sass parser contains
+ # many bugs related to the source ranges reported within code in /*...*/
+ # comments.
+ #
+ # Instead of defining this empty method on every linter, we assume every
+ # linter ignores comments by default. Individual linters can override at
+ # their discretion.
+ end
+
def extract_location(node_or_line_or_location)
if node_or_line_or_location.is_a?(Location)
node_or_line_or_location
elsif node_or_line_or_location.respond_to?(:source_range) &&
node_or_line_or_location.source_range
@@ -154,8 +170,36 @@
elsif node_or_line_or_location.respond_to?(:line)
Location.new(node_or_line_or_location.line)
else
Location.new(node_or_line_or_location)
end
+ end
+
+ # @param source_position [Sass::Source::Position]
+ # @param offset [Integer]
+ # @return [String] the character at the given [Sass::Source::Position]
+ def character_at(source_position, offset = 0)
+ actual_line = source_position.line - 1
+ actual_offset = source_position.offset + offset - 1
+
+ engine.lines.size > actual_line && engine.lines[actual_line][actual_offset]
+ end
+
+ # Starting at source_position (plus offset), search for pattern and return
+ # the offset from the source_position.
+ #
+ # @param source_position [Sass::Source::Position]
+ # @param pattern [String, RegExp] the pattern to search for
+ # @param offset [Integer]
+ # @return [Integer] the offset at which [pattern] was found.
+ def offset_to(source_position, pattern, offset = 0)
+ actual_line = source_position.line - 1
+ actual_offset = source_position.offset + offset - 1
+
+ return nil if actual_line >= engine.lines.size
+
+ actual_index = engine.lines[actual_line].index(pattern, actual_offset)
+
+ actual_index && actual_index + 1 - source_position.offset
end
end
end