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