Skip to content

Commit ba3c208

Browse files
yujinakayamaShane da Silva
authored and
Shane da Silva
committed
Add column and length information to Lint
As noted in id_with_extraneous_selector.rb, Sass::Selector::SimpleSequence#source_range sometimes lies about its line. So for now the linter reports the line number with SimpleSequence#line and discards column and length information. Change-Id: Ibc71b5662a0797046230287a4ff40b61fffb01a0 Reviewed-on: http://gerrit.causes.com/37222 Tested-by: jenkins <[email protected]> Reviewed-by: Shane da Silva <[email protected]>
1 parent 740e7c9 commit ba3c208

16 files changed

+129
-21
lines changed

Rakefile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require 'bundler/gem_tasks'

lib/scss_lint.rb

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require 'scss_lint/config'
33
require 'scss_lint/cli'
44
require 'scss_lint/engine'
5+
require 'scss_lint/location'
56
require 'scss_lint/lint'
67
require 'scss_lint/linter_registry'
78
require 'scss_lint/runner'

lib/scss_lint/cli.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def scssish_file?(file)
181181

182182
# @param lints [Array<Lint>]
183183
def report_lints(lints)
184-
sorted_lints = lints.sort_by { |l| [l.filename, l.line] }
184+
sorted_lints = lints.sort_by { |l| [l.filename, l.location] }
185185
reporter = @options.fetch(:reporter, Reporter::DefaultReporter)
186186
.new(sorted_lints)
187187
output = reporter.report_lints

lib/scss_lint/lint.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
module SCSSLint
22
# Stores information about a single problem that was detected by a [Linter].
33
class Lint
4-
attr_reader :filename, :line, :description, :severity
4+
attr_reader :filename, :location, :description, :severity
55

66
# @param filename [String]
7-
# @param line [Integer]
7+
# @param location [SCSSLint::Location]
88
# @param description [String]
99
# @param severity [Symbol]
10-
def initialize(filename, line, description, severity = :warning)
10+
def initialize(filename, location, description, severity = :warning)
1111
@filename = filename
12-
@line = line
12+
@location = location
1313
@description = description
1414
@severity = severity
1515
end

lib/scss_lint/linter.rb

+23-2
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,34 @@ def run(engine, config)
2323
# @param node_or_line [Sass::Script::Tree::Node, Sass::Engine::Line]
2424
# @param message [String]
2525
def add_lint(node_or_line, message)
26-
line = node_or_line.respond_to?(:line) ? node_or_line.line : node_or_line
26+
location = if node_or_line.respond_to?(:source_range) && node_or_line.source_range
27+
location_from_range(node_or_line.source_range)
28+
elsif node_or_line.respond_to?(:line)
29+
Location.new(node_or_line.line)
30+
else
31+
Location.new(node_or_line)
32+
end
2733

2834
@lints << Lint.new(engine.filename,
29-
line,
35+
location,
3036
message)
3137
end
3238

39+
# Helper for creating location from a source range
40+
#
41+
# @param range [Sass::Source::Range]
42+
# @return [SCSSLint::Location]
43+
def location_from_range(range)
44+
length = if range.start_pos.line == range.end_pos.line
45+
range.end_pos.offset - range.start_pos.offset
46+
else
47+
line_source = engine.lines[range.start_pos.line]
48+
line_source.length - range.start_pos.offset + 1
49+
end
50+
51+
Location.new(range.start_pos.line, range.start_pos.offset, length)
52+
end
53+
3354
# @param source_position [Sass::Source::Position]
3455
# @param offset [Integer]
3556
# @return [String] the character at the given [Sass::Source::Position]

lib/scss_lint/linter/id_with_extraneous_selector.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ def visit_simple_sequence(seq)
1313
end
1414

1515
if can_be_simplified
16-
add_lint(seq, "Selector `#{seq}` can be simplified to `#{id_sel}`, " \
17-
'since IDs should be uniquely identifying')
16+
# TODO: Sass::Selector::SimpleSequence#source_range sometimes lies about
17+
# its line, so reference `#line` directly
18+
add_lint(seq.line, "Selector `#{seq}` can be simplified to `#{id_sel}`, " <<
19+
'since IDs should be uniquely identifying')
1820
end
1921
end
2022
end

lib/scss_lint/linter/space_between_parens.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ def check(str, index, engine)
2626
spaces = str.count ' '
2727

2828
if spaces != @spaces
29-
@lints << Lint.new(engine.filename, index + 1, "Expected #{pluralize(@spaces, 'space')} " \
30-
"between parentheses instead of #{spaces}")
29+
location = Location.new(index + 1)
30+
message = "Expected #{pluralize(@spaces, 'space')}" <<
31+
" between parentheses instead of #{spaces}"
32+
@lints << Lint.new(engine.filename, location, message)
3133
end
3234
end
3335
end

lib/scss_lint/location.rb

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module SCSSLint
2+
# Stores a location of [Lint] in a source.
3+
class Location
4+
include Comparable
5+
6+
attr_reader :line, :column, :length
7+
8+
# @param line [Integer] An one-based index
9+
# @param column [Integer] An one-based index
10+
# @param length [Integer] A length in the line
11+
def initialize(line = 1, column = 1, length = 1)
12+
raise ArgumentError, "Line must be more than 0, passed #{line}" if line < 1
13+
raise ArgumentError, "Column must be more than 0, passed #{column}" if column < 1
14+
raise ArgumentError, "Length must be more than 0, passed #{length}" if length < 1
15+
16+
@line = line
17+
@column = column
18+
@length = length
19+
end
20+
21+
def ==(other)
22+
[:line, :column, :length].all? do |attr|
23+
send(attr) == other.send(attr)
24+
end
25+
end
26+
27+
alias_method :eql?, :==
28+
29+
def <=>(other)
30+
[:line, :column, :length].each do |attr|
31+
result = send(attr) <=> other.send(attr)
32+
return result unless result == 0
33+
end
34+
35+
0
36+
end
37+
end
38+
end

lib/scss_lint/reporter/default_reporter.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ def report_lints
55
if lints.any?
66
lints.map do |lint|
77
type = lint.error? ? '[E]'.color(:red) : '[W]'.color(:yellow)
8-
"#{lint.filename.color(:cyan)}:" << "#{lint.line}".color(:magenta) <<
8+
"#{lint.filename.color(:cyan)}:" << "#{lint.location.line}".color(:magenta) <<
99
" #{type} #{lint.description}"
1010
end.join("\n") + "\n"
1111
end

lib/scss_lint/reporter/xml_reporter.rb

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ def report_lints
88
lints.group_by(&:filename).each do |filename, file_lints|
99
output << "<file name=#{filename.encode(:xml => :attr)}>"
1010

11-
1211
file_lints.each do |lint|
13-
output << "<issue line=\"#{lint.line}\" " <<
12+
output << "<issue line=\"#{lint.location.line}\" " <<
1413
"severity=\"#{lint.severity}\" " <<
1514
"reason=#{lint.description.encode(:xml => :attr)} />"
1615
end

lib/scss_lint/runner.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ def find_lints(file)
4949
end
5050
end
5151
rescue Sass::SyntaxError => ex
52-
@lints << Lint.new(ex.sass_filename, ex.sass_line, ex.to_s, :error)
52+
@lints << Lint.new(ex.sass_filename, Location.new(ex.sass_line), ex.to_s, :error)
5353
rescue FileEncodingError => ex
54-
@lints << Lint.new(file, 1, ex.to_s, :error)
54+
@lints << Lint.new(file, Location.new, ex.to_s, :error)
5555
end
5656
end
5757
end

spec/scss_lint/location_spec.rb

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
require 'spec_helper'
2+
3+
describe SCSSLint::Location do
4+
let(:engine) { described_class.new(css) }
5+
6+
describe '#<=>' do
7+
let(:locations) do
8+
[
9+
SCSSLint::Location.new(2, 2, 2),
10+
SCSSLint::Location.new(2, 2, 1),
11+
SCSSLint::Location.new(2, 1, 2),
12+
SCSSLint::Location.new(2, 1, 1),
13+
SCSSLint::Location.new(1, 2, 2),
14+
SCSSLint::Location.new(1, 2, 1),
15+
SCSSLint::Location.new(1, 1, 2),
16+
SCSSLint::Location.new(1, 1, 1)
17+
]
18+
end
19+
20+
it 'enables to sort locations' do
21+
locations.sort.should == [
22+
SCSSLint::Location.new(1, 1, 1),
23+
SCSSLint::Location.new(1, 1, 2),
24+
SCSSLint::Location.new(1, 2, 1),
25+
SCSSLint::Location.new(1, 2, 2),
26+
SCSSLint::Location.new(2, 1, 1),
27+
SCSSLint::Location.new(2, 1, 2),
28+
SCSSLint::Location.new(2, 2, 1),
29+
SCSSLint::Location.new(2, 2, 2)
30+
]
31+
end
32+
33+
context 'when the same location is passed' do
34+
let(:location) { SCSSLint::Location.new(1, 1, 1) }
35+
let(:other_location) { SCSSLint::Location.new(1, 1, 1) }
36+
37+
it 'returns 0' do
38+
(location <=> other_location).should == 0
39+
end
40+
end
41+
end
42+
end

spec/scss_lint/reporter/default_reporter_spec.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
let(:severities) { [:warning] * 2 }
2020
let(:lints) do
2121
filenames.each_with_index.map do |filename, index|
22-
SCSSLint::Lint.new(filename, lines[index], descriptions[index], severities[index])
22+
location = SCSSLint::Location.new(lines[index])
23+
SCSSLint::Lint.new(filename, location, descriptions[index], severities[index])
2324
end
2425
end
2526

spec/scss_lint/reporter/files_reporter_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
let(:filenames) { ['some-filename.scss', 'some-filename.scss', 'other-filename.scss'] }
1717
let(:lints) do
1818
filenames.each_with_index.map do |filename, index|
19-
SCSSLint::Lint.new(filename, 0, '', :warning)
19+
SCSSLint::Lint.new(filename, SCSSLint::Location.new, '', :warning)
2020
end
2121
end
2222

spec/scss_lint/reporter/xml_reporter_spec.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
let(:severities) { [:warning] * 3 }
3636
let(:lints) do
3737
filenames.each_with_index.map do |filename, index|
38-
SCSSLint::Lint.new(filename, lines[index], descriptions[index], severities[index])
38+
location = SCSSLint::Location.new(lines[index])
39+
SCSSLint::Lint.new(filename, location, descriptions[index], severities[index])
3940
end
4041
end
4142

spec/support/matchers/report_lint.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
when 0
1515
''
1616
when 1
17-
", but was on line #{linter.lints.first.line}"
17+
", but was on line #{linter.lints.first.location.line}"
1818
else
1919
lines = lint_lines(linter)
2020
", but lints were reported on lines #{lines[0...-1].join(', ')} and #{lines.last}"
@@ -43,6 +43,6 @@ def has_lints?(linter, expected_line, count)
4343
end
4444

4545
def lint_lines(linter)
46-
linter.lints.map(&:line)
46+
linter.lints.map { |lint| lint.location.line }
4747
end
4848
end

0 commit comments

Comments
 (0)