scss-lint 0.30.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/scss-lint +1 -4
- data/config/default.yml +5 -4
- data/data/property-sort-orders/recess.txt +149 -0
- data/data/property-sort-orders/smacss.txt +138 -0
- data/lib/scss_lint.rb +1 -0
- data/lib/scss_lint/cli.rb +93 -153
- data/lib/scss_lint/config.rb +16 -13
- data/lib/scss_lint/control_comment_processor.rb +83 -0
- data/lib/scss_lint/engine.rb +21 -5
- data/lib/scss_lint/exceptions.rb +6 -0
- data/lib/scss_lint/linter.rb +6 -2
- data/lib/scss_lint/linter/bang_format.rb +20 -9
- data/lib/scss_lint/linter/duplicate_property.rb +35 -30
- data/lib/scss_lint/linter/empty_line_between_blocks.rb +1 -1
- data/lib/scss_lint/linter/id_selector.rb +10 -0
- data/lib/scss_lint/linter/indentation.rb +2 -1
- data/lib/scss_lint/linter/leading_zero.rb +6 -6
- data/lib/scss_lint/linter/name_format.rb +11 -0
- data/lib/scss_lint/linter/selector_format.rb +0 -4
- data/lib/scss_lint/linter/single_line_per_property.rb +13 -7
- data/lib/scss_lint/linter/single_line_per_selector.rb +19 -11
- data/lib/scss_lint/linter/trailing_semicolon.rb +5 -3
- data/lib/scss_lint/linter/trailing_zero.rb +4 -4
- data/lib/scss_lint/options.rb +113 -0
- data/lib/scss_lint/reporter/default_reporter.rb +15 -7
- data/lib/scss_lint/reporter/json_reporter.rb +15 -8
- data/lib/scss_lint/reporter/xml_reporter.rb +12 -6
- data/lib/scss_lint/runner.rb +4 -5
- data/lib/scss_lint/version.rb +1 -1
- data/spec/scss_lint/cli_spec.rb +9 -229
- data/spec/scss_lint/linter/bang_format_spec.rb +20 -0
- data/spec/scss_lint/linter/duplicate_property_spec.rb +13 -0
- data/spec/scss_lint/linter/empty_line_between_blocks_spec.rb +12 -11
- data/spec/scss_lint/linter/id_selector_spec.rb +62 -0
- data/spec/scss_lint/linter/indentation_spec.rb +11 -0
- data/spec/scss_lint/linter/name_format_spec.rb +147 -117
- data/spec/scss_lint/linter/selector_format_spec.rb +3 -66
- data/spec/scss_lint/linter/trailing_semicolon_spec.rb +20 -0
- data/spec/scss_lint/linter_spec.rb +248 -0
- data/spec/scss_lint/options_spec.rb +42 -0
- data/spec/spec_helper.rb +1 -1
- metadata +177 -183
- data/lib/scss_lint/linter/id_with_extraneous_selector.rb +0 -20
- data/spec/scss_lint/linter/id_with_extraneous_selector_spec.rb +0 -139
@@ -29,10 +29,6 @@ module SCSSLint
|
|
29
29
|
check(placeholder, 'placeholder') unless @ignored_types.include?('placeholder')
|
30
30
|
end
|
31
31
|
|
32
|
-
def visit_pseudo(pseudo)
|
33
|
-
check(pseudo, 'pseudo') unless @ignored_types.include?('pseudo-selector')
|
34
|
-
end
|
35
|
-
|
36
32
|
private
|
37
33
|
|
38
34
|
def check(node, type)
|
@@ -18,13 +18,7 @@ module SCSSLint
|
|
18
18
|
'on separate line from selector')
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
# the same line
|
23
|
-
properties[0..-2].zip(properties[1..-1]).each do |first, second|
|
24
|
-
next unless first.line == second.line
|
25
|
-
|
26
|
-
add_lint(second, "Property '#{second.name.join}' should be placed on own line")
|
27
|
-
end
|
21
|
+
check_adjacent_properties(properties)
|
28
22
|
end
|
29
23
|
|
30
24
|
private
|
@@ -49,5 +43,17 @@ module SCSSLint
|
|
49
43
|
def first_property_not_on_own_line?(rule, properties)
|
50
44
|
properties.any? && properties.first.line == rule.line
|
51
45
|
end
|
46
|
+
|
47
|
+
# Compare each property against the next property to see if they are on
|
48
|
+
# the same line.
|
49
|
+
#
|
50
|
+
# @param properties [Array<Sass::Tree::PropNode>]
|
51
|
+
def check_adjacent_properties(properties)
|
52
|
+
properties[0..-2].zip(properties[1..-1]).each do |first, second|
|
53
|
+
next unless first.line == second.line
|
54
|
+
|
55
|
+
add_lint(second, "Property '#{second.name.join}' should be placed on own line")
|
56
|
+
end
|
57
|
+
end
|
52
58
|
end
|
53
59
|
end
|
@@ -8,19 +8,27 @@ module SCSSLint
|
|
8
8
|
def visit_comma_sequence(node)
|
9
9
|
return unless node.members.count > 1
|
10
10
|
|
11
|
-
|
12
|
-
# Comma is on its own line
|
13
|
-
add_lint(node, MESSAGE)
|
14
|
-
end
|
11
|
+
check_comma_on_own_line(node)
|
15
12
|
|
16
13
|
node.members[1..-1].each_with_index do |sequence, index|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
check_sequence_commas(node, sequence, index)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def check_comma_on_own_line(node)
|
21
|
+
return unless node.members[0].members[1] == "\n"
|
22
|
+
add_lint(node, MESSAGE)
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_sequence_commas(node, sequence, index)
|
26
|
+
if sequence.members[0] != "\n"
|
27
|
+
# Next sequence doesn't reside on its own line
|
28
|
+
add_lint(node.line + index, MESSAGE)
|
29
|
+
elsif sequence.members[1] == "\n"
|
30
|
+
# Comma is on its own line
|
31
|
+
add_lint(node.line + index, MESSAGE)
|
24
32
|
end
|
25
33
|
end
|
26
34
|
end
|
@@ -28,6 +28,8 @@ module SCSSLint
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def visit_import(node)
|
31
|
+
# Ignore all but the last import for comma-separated @imports
|
32
|
+
return if source_from_range(node.source_range) =~ /,\s*$/
|
31
33
|
check_semicolon(node)
|
32
34
|
end
|
33
35
|
|
@@ -35,13 +37,13 @@ module SCSSLint
|
|
35
37
|
|
36
38
|
def check_semicolon(node)
|
37
39
|
if has_space_before_semicolon?(node)
|
38
|
-
line = node.source_range.start_pos.line
|
39
|
-
add_lint line, 'Declaration should be terminated by a semicolon'
|
40
|
-
elsif !ends_with_semicolon?(node)
|
41
40
|
line = node.source_range.start_pos.line
|
42
41
|
add_lint line,
|
43
42
|
'Declaration should not have a space before ' \
|
44
43
|
'the terminating semicolon'
|
44
|
+
elsif !ends_with_semicolon?(node)
|
45
|
+
line = node.source_range.start_pos.line
|
46
|
+
add_lint line, 'Declaration should be terminated by a semicolon'
|
45
47
|
elsif ends_with_multiple_semicolons?(node)
|
46
48
|
line = node.source_range.start_pos.line
|
47
49
|
add_lint line, 'Declaration should be terminated by a single semicolon'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module SCSSLint
|
2
|
-
# Checks for unnecessary
|
2
|
+
# Checks for unnecessary trailing zeros in numeric values with decimal points.
|
3
3
|
class Linter::TrailingZero < Linter
|
4
4
|
include LinterRegistry
|
5
5
|
|
@@ -9,7 +9,7 @@ module SCSSLint
|
|
9
9
|
non_string_values = remove_quoted_strings(node.value).split
|
10
10
|
non_string_values.each do |value|
|
11
11
|
next unless number = value[FRACTIONAL_DIGIT_REGEX, 1]
|
12
|
-
|
12
|
+
check_for_trailing_zeros(node, number)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -17,14 +17,14 @@ module SCSSLint
|
|
17
17
|
return unless number =
|
18
18
|
source_from_range(node.source_range)[FRACTIONAL_DIGIT_REGEX, 1]
|
19
19
|
|
20
|
-
|
20
|
+
check_for_trailing_zeros(node, number)
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
24
24
|
|
25
25
|
FRACTIONAL_DIGIT_REGEX = /^-?(\d*\.\d+)/
|
26
26
|
|
27
|
-
def
|
27
|
+
def check_for_trailing_zeros(node, original_number)
|
28
28
|
return unless match = /^(\d*\.\d*)0+$/.match(original_number)
|
29
29
|
|
30
30
|
fixed_number = match[1]
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module SCSSLint
|
4
|
+
# Handles option parsing for the command line application.
|
5
|
+
class Options
|
6
|
+
DEFAULT_REPORTER = [SCSSLint::Reporter::DefaultReporter, :stdout]
|
7
|
+
|
8
|
+
# Parses command line options into an options hash.
|
9
|
+
#
|
10
|
+
# @param args [Array<String>] arguments passed via the command line
|
11
|
+
# @return [Hash] parsed options
|
12
|
+
def parse(args)
|
13
|
+
@options = {
|
14
|
+
reporters: [DEFAULT_REPORTER],
|
15
|
+
}
|
16
|
+
|
17
|
+
OptionParser.new do |parser|
|
18
|
+
parser.banner = "Usage: #{parser.program_name} [options] [scss-files]"
|
19
|
+
|
20
|
+
add_display_options parser
|
21
|
+
add_linter_options parser
|
22
|
+
add_file_options parser
|
23
|
+
add_info_options parser
|
24
|
+
end.parse!(args)
|
25
|
+
|
26
|
+
# Any remaining arguments are assumed to be files
|
27
|
+
@options[:files] = args
|
28
|
+
|
29
|
+
@options
|
30
|
+
rescue OptionParser::InvalidOption => ex
|
31
|
+
raise SCSSLint::Exceptions::InvalidCLIOption,
|
32
|
+
ex.message,
|
33
|
+
ex.backtrace
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def add_display_options(parser)
|
39
|
+
parser.on('-f', '--format Formatter', 'Specify how to display lints', String) do |format|
|
40
|
+
define_output_format(format)
|
41
|
+
end
|
42
|
+
|
43
|
+
parser.on('-r', '--require path', 'Require Ruby file', String) do |path|
|
44
|
+
@options[:required_paths] ||= []
|
45
|
+
@options[:required_paths] << path
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param format [String]
|
50
|
+
def define_output_format(format)
|
51
|
+
unless @options[:reporters] == [DEFAULT_REPORTER] && format == 'Default'
|
52
|
+
@options[:reporters].reject! { |i| i == DEFAULT_REPORTER }
|
53
|
+
reporter = SCSSLint::Reporter.const_get(format + 'Reporter')
|
54
|
+
@options[:reporters] << [reporter, :stdout]
|
55
|
+
end
|
56
|
+
rescue NameError
|
57
|
+
raise SCSSLint::Exceptions::InvalidCLIOption,
|
58
|
+
"Invalid output format specified: #{format}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_linter_options(parser)
|
62
|
+
parser.on('-i', '--include-linter linter,...', Array,
|
63
|
+
'Specify which linters you want to run') do |linters|
|
64
|
+
@options[:included_linters] = linters
|
65
|
+
end
|
66
|
+
|
67
|
+
parser.on('-x', '--exclude-linter linter,...', Array,
|
68
|
+
"Specify which linters you don't want to run") do |linters|
|
69
|
+
@options[:excluded_linters] = linters
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_file_options(parser)
|
74
|
+
parser.on('-c', '--config config-file', String,
|
75
|
+
'Specify which configuration file you want to use') do |conf_file|
|
76
|
+
@options[:config_file] = conf_file
|
77
|
+
end
|
78
|
+
|
79
|
+
parser.on('-e', '--exclude file,...', Array,
|
80
|
+
'List of file names to exclude') do |files|
|
81
|
+
@options[:excluded_files] = files
|
82
|
+
end
|
83
|
+
|
84
|
+
parser.on('-o', '--out path', 'Write output to a file instead of STDOUT', String) do |path|
|
85
|
+
define_output_path(path)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# @param path [String]
|
90
|
+
def define_output_path(path)
|
91
|
+
last_reporter, _output = @options[:reporters].pop
|
92
|
+
@options[:reporters] << [last_reporter, path]
|
93
|
+
end
|
94
|
+
|
95
|
+
def add_info_options(parser)
|
96
|
+
parser.on_tail('--show-formatters', 'Shows available formatters') do
|
97
|
+
@options[:show_formatters] = true
|
98
|
+
end
|
99
|
+
|
100
|
+
parser.on_tail('--show-linters', 'Display available linters') do
|
101
|
+
@options[:show_linters] = true
|
102
|
+
end
|
103
|
+
|
104
|
+
parser.on_tail('-h', '--help', 'Display help documentation') do
|
105
|
+
@options[:help] = parser.help
|
106
|
+
end
|
107
|
+
|
108
|
+
parser.on_tail('-v', '--version', 'Display version') do
|
109
|
+
@options[:version] = true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -5,15 +5,23 @@ module SCSSLint
|
|
5
5
|
return unless lints.any?
|
6
6
|
|
7
7
|
lints.map do |lint|
|
8
|
-
|
8
|
+
"#{location(lint)} #{type(lint)} #{message(lint)}"
|
9
|
+
end.join("\n") + "\n"
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
message = "#{linter_name}#{lint.description}"
|
12
|
+
private
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def location(lint)
|
15
|
+
"#{lint.filename.color(:cyan)}:#{lint.location.line.to_s.color(:magenta)}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def type(lint)
|
19
|
+
lint.error? ? '[E]'.color(:red) : '[W]'.color(:yellow)
|
20
|
+
end
|
21
|
+
|
22
|
+
def message(lint)
|
23
|
+
linter_name = "#{lint.linter.name}: ".color(:green) if lint.linter
|
24
|
+
"#{linter_name}#{lint.description}"
|
17
25
|
end
|
18
26
|
end
|
19
27
|
end
|
@@ -7,17 +7,24 @@ module SCSSLint
|
|
7
7
|
output = {}
|
8
8
|
lints.group_by(&:filename).each do |filename, file_lints|
|
9
9
|
output[filename] = file_lints.map do |lint|
|
10
|
-
|
11
|
-
issue['linter'] = lint.linter.name if lint.linter
|
12
|
-
issue['line'] = lint.location.line
|
13
|
-
issue['column'] = lint.location.column
|
14
|
-
issue['length'] = lint.location.length
|
15
|
-
issue['severity'] = lint.severity
|
16
|
-
issue['reason'] = lint.description
|
17
|
-
issue
|
10
|
+
issue_hash(lint)
|
18
11
|
end
|
19
12
|
end
|
20
13
|
JSON.pretty_generate(output)
|
21
14
|
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def issue_hash(lint)
|
19
|
+
{
|
20
|
+
'line' => lint.location.line,
|
21
|
+
'column' => lint.location.column,
|
22
|
+
'length' => lint.location.length,
|
23
|
+
'severity' => lint.severity,
|
24
|
+
'reason' => lint.description,
|
25
|
+
}.tap do |hash|
|
26
|
+
hash['linter'] = lint.linter.name if lint.linter
|
27
|
+
end
|
28
|
+
end
|
22
29
|
end
|
23
30
|
end
|
@@ -9,12 +9,7 @@ module SCSSLint
|
|
9
9
|
output << "<file name=#{filename.encode(xml: :attr)}>"
|
10
10
|
|
11
11
|
file_lints.each do |lint|
|
12
|
-
output <<
|
13
|
-
"line=\"#{lint.location.line}\" " \
|
14
|
-
"column=\"#{lint.location.column}\" " \
|
15
|
-
"length=\"#{lint.location.length}\" " \
|
16
|
-
"severity=\"#{lint.severity}\" " \
|
17
|
-
"reason=#{lint.description.encode(xml: :attr)} />"
|
12
|
+
output << issue_tag(lint)
|
18
13
|
end
|
19
14
|
|
20
15
|
output << '</file>'
|
@@ -23,5 +18,16 @@ module SCSSLint
|
|
23
18
|
|
24
19
|
output
|
25
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def issue_tag(lint)
|
25
|
+
"<issue linter=\"#{lint.linter.name if lint.linter}\" " \
|
26
|
+
"line=\"#{lint.location.line}\" " \
|
27
|
+
"column=\"#{lint.location.column}\" " \
|
28
|
+
"length=\"#{lint.location.length}\" " \
|
29
|
+
"severity=\"#{lint.severity}\" " \
|
30
|
+
"reason=#{lint.description.encode(xml: :attr)} />"
|
31
|
+
end
|
26
32
|
end
|
27
33
|
end
|
data/lib/scss_lint/runner.rb
CHANGED
@@ -35,11 +35,8 @@ module SCSSLint
|
|
35
35
|
config ||= @config
|
36
36
|
|
37
37
|
@linters.each do |linter|
|
38
|
-
next unless config.linter_enabled?(linter)
|
39
|
-
next if config.excluded_file_for_linter?(file, linter)
|
40
|
-
|
41
38
|
begin
|
42
|
-
run_linter(linter, engine, config)
|
39
|
+
run_linter(linter, engine, config, file)
|
43
40
|
rescue => error
|
44
41
|
raise SCSSLint::Exceptions::LinterError,
|
45
42
|
"#{linter.class} raised unexpected error linting file #{file}: " \
|
@@ -55,7 +52,9 @@ module SCSSLint
|
|
55
52
|
end
|
56
53
|
|
57
54
|
# For stubbing in tests.
|
58
|
-
def run_linter(linter, engine, config)
|
55
|
+
def run_linter(linter, engine, config, file)
|
56
|
+
return unless config.linter_enabled?(linter)
|
57
|
+
return if config.excluded_file_for_linter?(file, linter)
|
59
58
|
linter.run(engine, config.linter_options(linter))
|
60
59
|
end
|
61
60
|
end
|
data/lib/scss_lint/version.rb
CHANGED
data/spec/scss_lint/cli_spec.rb
CHANGED
@@ -27,246 +27,28 @@ describe SCSSLint::CLI do
|
|
27
27
|
SCSSLint::Linter::FakeTestLinter2])
|
28
28
|
end
|
29
29
|
|
30
|
-
describe '#parse_arguments' do
|
31
|
-
let(:files) { ['file1.scss', 'file2.scss'] }
|
32
|
-
let(:flags) { [] }
|
33
|
-
subject { SCSSLint::CLI.new(flags + files) }
|
34
|
-
|
35
|
-
def safe_parse
|
36
|
-
subject.parse_arguments
|
37
|
-
rescue SystemExit
|
38
|
-
# Keep running tests
|
39
|
-
end
|
40
|
-
|
41
|
-
context 'when the config_file flag is set' do
|
42
|
-
let(:config_file) { 'my-config-file.yml' }
|
43
|
-
let(:flags) { ['-c', config_file] }
|
44
|
-
|
45
|
-
it 'loads that config file' do
|
46
|
-
SCSSLint::Config.should_receive(:load).with(config_file)
|
47
|
-
safe_parse
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'and the config file is invalid' do
|
51
|
-
before do
|
52
|
-
SCSSLint::Config.should_receive(:load)
|
53
|
-
.with(config_file)
|
54
|
-
.and_raise(SCSSLint::InvalidConfiguration)
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'halts with a configuration error code' do
|
58
|
-
subject.should_receive(:halt).with(:config)
|
59
|
-
safe_parse
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
context 'when the excluded files flag is set' do
|
65
|
-
let(:flags) { ['-e', 'file1.scss,file3.scss'] }
|
66
|
-
|
67
|
-
it 'sets the :excluded_files option' do
|
68
|
-
safe_parse
|
69
|
-
subject.options[:excluded_files].should =~ ['file1.scss', 'file3.scss']
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
context 'when the include linters flag is set' do
|
74
|
-
let(:flags) { %w[-i FakeTestLinter2] }
|
75
|
-
|
76
|
-
it 'enables only the included linters' do
|
77
|
-
safe_parse
|
78
|
-
subject.config.enabled_linters.should == [SCSSLint::Linter::FakeTestLinter2]
|
79
|
-
end
|
80
|
-
|
81
|
-
context 'and the included linter does not exist' do
|
82
|
-
let(:flags) { %w[-i NonExistentLinter] }
|
83
|
-
|
84
|
-
it 'halts with a configuration error code' do
|
85
|
-
subject.should_receive(:halt).with(:config)
|
86
|
-
safe_parse
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
context 'when the exclude linters flag is set' do
|
92
|
-
let(:flags) { %w[-x FakeTestLinter1] }
|
93
|
-
|
94
|
-
it 'includes all linters except the excluded one' do
|
95
|
-
safe_parse
|
96
|
-
subject.config.enabled_linters.should == \
|
97
|
-
[SCSSLint::Linter::FakeTestLinter2]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
context 'when the require flag is set' do
|
102
|
-
let(:flags) { %w[--require uri] }
|
103
|
-
|
104
|
-
it 'requires the specified file and constants are accessible' do
|
105
|
-
safe_parse
|
106
|
-
expect { subject.instance_eval %{ URI } }.to_not raise_error
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
context 'when neither format nor out flag is set' do
|
111
|
-
let(:flags) { %w[] }
|
112
|
-
|
113
|
-
it 'sets the default reporter to output to stdout' do
|
114
|
-
safe_parse
|
115
|
-
subject.options[:reporters].should \
|
116
|
-
include([SCSSLint::Reporter::DefaultReporter, :stdout])
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
context 'when the out flag is set' do
|
121
|
-
context 'and the path is valid' do
|
122
|
-
let(:flags) { %w[--out foo.txt] }
|
123
|
-
|
124
|
-
it 'sets the default :output to the given path' do
|
125
|
-
safe_parse
|
126
|
-
subject.options[:reporters].should \
|
127
|
-
include([SCSSLint::Reporter::DefaultReporter, 'foo.txt'])
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
context 'when the format flag is set' do
|
133
|
-
context 'and the format is valid' do
|
134
|
-
let(:flags) { %w[--format XML] }
|
135
|
-
|
136
|
-
it 'sets the :reporter option to the correct reporter' do
|
137
|
-
safe_parse
|
138
|
-
subject.options[:reporters].should \
|
139
|
-
include([SCSSLint::Reporter::XMLReporter, :stdout])
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
context 'and an out path is specified' do
|
144
|
-
let(:flags) { %w[--format XML --out foo.txt] }
|
145
|
-
|
146
|
-
it 'sets the specified reporter :output to the given path' do
|
147
|
-
safe_parse
|
148
|
-
subject.options[:reporters].should \
|
149
|
-
include([SCSSLint::Reporter::XMLReporter, 'foo.txt'])
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
context 'and the format is invalid' do
|
154
|
-
let(:flags) { %w[--format InvalidFormat] }
|
155
|
-
|
156
|
-
it 'sets the :reporter option to the correct reporter' do
|
157
|
-
subject.should_receive(:halt).with(:config)
|
158
|
-
safe_parse
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
context 'when the show formatters flag is set' do
|
164
|
-
let(:flags) { ['--show-formatters'] }
|
165
|
-
|
166
|
-
it 'prints the formatters' do
|
167
|
-
subject.should_receive(:print_formatters)
|
168
|
-
safe_parse
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
context 'when the show linters flag is set' do
|
173
|
-
let(:flags) { ['--show-linters'] }
|
174
|
-
|
175
|
-
it 'prints the linters' do
|
176
|
-
subject.should_receive(:print_linters)
|
177
|
-
safe_parse
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
context 'when the help flag is set' do
|
182
|
-
let(:flags) { ['-h'] }
|
183
|
-
|
184
|
-
it 'prints a help message' do
|
185
|
-
subject.should_receive(:print_help)
|
186
|
-
safe_parse
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
context 'when the version flag is set' do
|
191
|
-
let(:flags) { ['-v'] }
|
192
|
-
|
193
|
-
it 'prints the program version' do
|
194
|
-
subject.should_receive(:print_version)
|
195
|
-
safe_parse
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
context 'when an invalid option is specified' do
|
200
|
-
let(:flags) { ['--non-existant-option'] }
|
201
|
-
|
202
|
-
it 'prints a help message' do
|
203
|
-
subject.should_receive(:print_help)
|
204
|
-
safe_parse
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
context 'when no files are specified' do
|
209
|
-
let(:files) { [] }
|
210
|
-
|
211
|
-
it 'sets :files option to the empty list' do
|
212
|
-
safe_parse
|
213
|
-
subject.options[:files].should be_empty
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
context 'when files are specified' do
|
218
|
-
it 'sets :files option to the list of files' do
|
219
|
-
safe_parse
|
220
|
-
subject.options[:files].should =~ files
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
30
|
describe '#run' do
|
226
|
-
let(:files)
|
227
|
-
let(:
|
228
|
-
subject
|
31
|
+
let(:files) { ['file1.scss', 'file2.scss'] }
|
32
|
+
let(:flags) { [] }
|
33
|
+
subject { SCSSLint::CLI.new }
|
229
34
|
|
230
35
|
before do
|
231
36
|
subject.stub(:extract_files_from).and_return(files)
|
232
37
|
end
|
233
38
|
|
234
39
|
def safe_run
|
235
|
-
subject.run
|
40
|
+
subject.run(flags + files)
|
236
41
|
rescue SystemExit
|
237
42
|
# Keep running tests
|
238
43
|
end
|
239
44
|
|
240
|
-
context 'when no files are specified' do
|
241
|
-
let(:files) { [] }
|
242
|
-
|
243
|
-
it 'exits with a no-input status code' do
|
244
|
-
subject.should_receive(:halt).with(:no_input)
|
245
|
-
safe_run
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
context 'when files are specified' do
|
250
|
-
it 'passes the set of files to the runner' do
|
251
|
-
SCSSLint::Runner.any_instance.should_receive(:run).with(files)
|
252
|
-
safe_run
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'uses the default reporter' do
|
256
|
-
SCSSLint::Reporter::DefaultReporter.any_instance
|
257
|
-
.should_receive(:report_lints)
|
258
|
-
safe_run
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
45
|
context 'when there are no lints' do
|
263
46
|
before do
|
264
47
|
SCSSLint::Runner.any_instance.stub(:lints).and_return([])
|
265
48
|
end
|
266
49
|
|
267
|
-
it '
|
268
|
-
|
269
|
-
safe_run
|
50
|
+
it 'returns a successful exit code' do
|
51
|
+
safe_run.should == 0
|
270
52
|
end
|
271
53
|
|
272
54
|
it 'outputs nothing' do
|
@@ -288,9 +70,8 @@ describe SCSSLint::CLI do
|
|
288
70
|
])
|
289
71
|
end
|
290
72
|
|
291
|
-
it '
|
292
|
-
|
293
|
-
safe_run
|
73
|
+
it 'returns a exit code indicating only warnings were reported' do
|
74
|
+
safe_run.should == 1
|
294
75
|
end
|
295
76
|
|
296
77
|
it 'outputs the warnings' do
|
@@ -313,8 +94,7 @@ describe SCSSLint::CLI do
|
|
313
94
|
end
|
314
95
|
|
315
96
|
it 'exits with an error status code' do
|
316
|
-
|
317
|
-
safe_run
|
97
|
+
safe_run.should == 2
|
318
98
|
end
|
319
99
|
|
320
100
|
it 'outputs the errors' do
|