scss_lint 0.43.2 → 0.44.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/bin/scss-lint +2 -1
  3. data/config/default.yml +3 -0
  4. data/data/properties.txt +35 -0
  5. data/data/property-sort-orders/smacss.txt +9 -0
  6. data/data/pseudo-elements.txt +5 -0
  7. data/lib/scss_lint.rb +1 -0
  8. data/lib/scss_lint/cli.rb +50 -30
  9. data/lib/scss_lint/config.rb +28 -3
  10. data/lib/scss_lint/constants.rb +6 -4
  11. data/lib/scss_lint/control_comment_processor.rb +8 -7
  12. data/lib/scss_lint/engine.rb +1 -1
  13. data/lib/scss_lint/file_finder.rb +1 -1
  14. data/lib/scss_lint/linter.rb +8 -7
  15. data/lib/scss_lint/linter/bang_format.rb +2 -2
  16. data/lib/scss_lint/linter/border_zero.rb +2 -2
  17. data/lib/scss_lint/linter/color_variable.rb +1 -1
  18. data/lib/scss_lint/linter/declaration_order.rb +10 -8
  19. data/lib/scss_lint/linter/duplicate_property.rb +2 -2
  20. data/lib/scss_lint/linter/empty_line_between_blocks.rb +3 -1
  21. data/lib/scss_lint/linter/final_newline.rb +3 -3
  22. data/lib/scss_lint/linter/indentation.rb +20 -20
  23. data/lib/scss_lint/linter/leading_zero.rb +2 -2
  24. data/lib/scss_lint/linter/mergeable_selector.rb +3 -4
  25. data/lib/scss_lint/linter/name_format.rb +2 -1
  26. data/lib/scss_lint/linter/nesting_depth.rb +1 -1
  27. data/lib/scss_lint/linter/property_sort_order.rb +11 -13
  28. data/lib/scss_lint/linter/selector_depth.rb +9 -8
  29. data/lib/scss_lint/linter/selector_format.rb +1 -1
  30. data/lib/scss_lint/linter/shorthand.rb +1 -1
  31. data/lib/scss_lint/linter/single_line_per_selector.rb +3 -1
  32. data/lib/scss_lint/linter/space_around_operator.rb +4 -2
  33. data/lib/scss_lint/linter/space_before_brace.rb +8 -8
  34. data/lib/scss_lint/linter/space_between_parens.rb +11 -11
  35. data/lib/scss_lint/linter/string_quotes.rb +9 -10
  36. data/lib/scss_lint/linter/trailing_zero.rb +1 -1
  37. data/lib/scss_lint/linter/transition_all.rb +1 -1
  38. data/lib/scss_lint/linter/unnecessary_mantissa.rb +3 -1
  39. data/lib/scss_lint/linter/unnecessary_parent_reference.rb +9 -2
  40. data/lib/scss_lint/linter/url_quotes.rb +4 -2
  41. data/lib/scss_lint/linter/variable_for_property.rb +1 -1
  42. data/lib/scss_lint/linter/vendor_prefix.rb +3 -3
  43. data/lib/scss_lint/linter/zero_unit.rb +3 -1
  44. data/lib/scss_lint/location.rb +1 -1
  45. data/lib/scss_lint/logger.rb +149 -0
  46. data/lib/scss_lint/options.rb +5 -1
  47. data/lib/scss_lint/rake_task.rb +10 -3
  48. data/lib/scss_lint/reporter.rb +4 -2
  49. data/lib/scss_lint/reporter/default_reporter.rb +3 -3
  50. data/lib/scss_lint/version.rb +3 -1
  51. data/spec/scss_lint/cli_spec.rb +66 -14
  52. data/spec/scss_lint/config_spec.rb +25 -5
  53. data/spec/scss_lint/linter/name_format_spec.rb +10 -0
  54. data/spec/scss_lint/linter/property_sort_order_spec.rb +28 -0
  55. data/spec/scss_lint/linter/unnecessary_parent_reference_spec.rb +10 -0
  56. data/spec/scss_lint/linter/variable_for_property_spec.rb +10 -0
  57. data/spec/scss_lint/logger_spec.rb +27 -0
  58. data/spec/scss_lint/options_spec.rb +18 -0
  59. data/spec/scss_lint/plugins/linter_dir_spec.rb +1 -1
  60. data/spec/scss_lint/reporter/clean_files_reporter_spec.rb +1 -1
  61. data/spec/scss_lint/reporter/config_reporter_spec.rb +1 -1
  62. data/spec/scss_lint/reporter/default_reporter_spec.rb +2 -1
  63. data/spec/scss_lint/reporter/files_reporter_spec.rb +1 -1
  64. data/spec/scss_lint/reporter/json_reporter_spec.rb +5 -5
  65. metadata +10 -7
@@ -12,15 +12,15 @@ module SCSSLint
12
12
  private
13
13
 
14
14
  def location(lint)
15
- "#{lint.filename.color(:cyan)}:#{lint.location.line.to_s.color(:magenta)}"
15
+ "#{log.cyan(lint.filename)}:#{log.magenta(lint.location.line.to_s)}"
16
16
  end
17
17
 
18
18
  def type(lint)
19
- lint.error? ? '[E]'.color(:red) : '[W]'.color(:yellow)
19
+ lint.error? ? log.red('[E]') : log.yellow('[W]')
20
20
  end
21
21
 
22
22
  def message(lint)
23
- linter_name = "#{lint.linter.name}: ".color(:green) if lint.linter
23
+ linter_name = log.green("#{lint.linter.name}: ") if lint.linter
24
24
  "#{linter_name}#{lint.description}"
25
25
  end
26
26
  end
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Defines the gem version.
2
4
  module SCSSLint
3
- VERSION = '0.43.2'
5
+ VERSION = '0.44.0'.freeze
4
6
  end
@@ -19,10 +19,6 @@ describe SCSSLint::CLI do
19
19
  class SCSSLint::Linter::FakeTestLinter2 < SCSSLint::Linter; end
20
20
 
21
21
  before do
22
- # Silence console output
23
- @output = ''
24
- STDOUT.stub(:write) { |*args| @output.<<(*args) }
25
-
26
22
  SCSSLint::Config.stub(:load)
27
23
  .with(SCSSLint::Config::DEFAULT_FILE, merge_with_default: false)
28
24
  .and_return(config)
@@ -32,9 +28,12 @@ describe SCSSLint::CLI do
32
28
  end
33
29
 
34
30
  describe '#run' do
35
- let(:files) { ['file1.scss', 'file2.scss'] }
36
- let(:flags) { [] }
37
- subject { SCSSLint::CLI.new }
31
+ let(:files) { ['file1.scss', 'file2.scss'] }
32
+ let(:flags) { [] }
33
+ let(:io) { StringIO.new }
34
+ let(:output) { io.string }
35
+ let(:logger) { SCSSLint::Logger.new(io) }
36
+ subject { SCSSLint::CLI.new(logger) }
38
37
 
39
38
  before do
40
39
  SCSSLint::FileFinder.any_instance.stub(:find).and_return(files)
@@ -47,6 +46,59 @@ describe SCSSLint::CLI do
47
46
  # Keep running tests
48
47
  end
49
48
 
49
+ context 'when passed the --color flag' do
50
+ let(:flags) { ['--color'] }
51
+
52
+ it 'sets the logger to output in color' do
53
+ safe_run
54
+ logger.color_enabled.should == true
55
+ end
56
+
57
+ context 'and the output stream is not a TTY' do
58
+ before do
59
+ io.stub(:tty?).and_return(false)
60
+ end
61
+
62
+ it 'sets the logger to output in color' do
63
+ safe_run
64
+ logger.color_enabled.should == true
65
+ end
66
+ end
67
+ end
68
+
69
+ context 'when passed the --no-color flag' do
70
+ let(:flags) { ['--no-color'] }
71
+
72
+ it 'sets the logger to not output in color' do
73
+ safe_run
74
+ logger.color_enabled.should == false
75
+ end
76
+ end
77
+
78
+ context 'when --[no-]color flag is not specified' do
79
+ before do
80
+ io.stub(:tty?).and_return(tty)
81
+ end
82
+
83
+ context 'and the output stream is a TTY' do
84
+ let(:tty) { true }
85
+
86
+ it 'sets the logger to output in color' do
87
+ safe_run
88
+ logger.color_enabled.should == true
89
+ end
90
+ end
91
+
92
+ context 'and the output stream is not a TTY' do
93
+ let(:tty) { false }
94
+
95
+ it 'sets the logger to not output in color' do
96
+ safe_run
97
+ logger.color_enabled.should == false
98
+ end
99
+ end
100
+ end
101
+
50
102
  context 'when there are no lints' do
51
103
  before do
52
104
  SCSSLint::Runner.any_instance.stub(:lints).and_return([])
@@ -58,7 +110,7 @@ describe SCSSLint::CLI do
58
110
 
59
111
  it 'outputs nothing' do
60
112
  safe_run
61
- @output.should be_empty
113
+ output.should be_empty
62
114
  end
63
115
  end
64
116
 
@@ -81,7 +133,7 @@ describe SCSSLint::CLI do
81
133
 
82
134
  it 'outputs the warnings' do
83
135
  safe_run
84
- @output.should include 'Some description'
136
+ output.should include 'Some description'
85
137
  end
86
138
  end
87
139
 
@@ -104,7 +156,7 @@ describe SCSSLint::CLI do
104
156
 
105
157
  it 'outputs the errors' do
106
158
  safe_run
107
- @output.should include 'Some description'
159
+ output.should include 'Some description'
108
160
  end
109
161
  end
110
162
 
@@ -125,17 +177,17 @@ describe SCSSLint::CLI do
125
177
 
126
178
  it 'outputs the error message' do
127
179
  safe_run
128
- @output.should include message
180
+ output.should include message
129
181
  end
130
182
 
131
183
  it 'outputs the backtrace' do
132
184
  safe_run
133
- @output.should include backtrace.join("\n")
185
+ output.should include backtrace.join("\n")
134
186
  end
135
187
 
136
188
  it 'outputs a link to the issue tracker' do
137
189
  safe_run
138
- @output.should include SCSSLint::BUG_REPORT_URL
190
+ output.should include SCSSLint::BUG_REPORT_URL
139
191
  end
140
192
  end
141
193
 
@@ -171,7 +223,7 @@ describe SCSSLint::CLI do
171
223
  context 'when specified SCSS file globs match no files' do
172
224
  before do
173
225
  SCSSLint::FileFinder.any_instance.stub(:find)
174
- .and_raise(SCSSLint::Exceptions::NoFilesError)
226
+ .and_raise(SCSSLint::Exceptions::NoFilesError)
175
227
  end
176
228
 
177
229
  it 'exits with an appropriate status code' do
@@ -132,15 +132,15 @@ describe SCSSLint::Config do
132
132
 
133
133
  before do
134
134
  SCSSLint::LinterRegistry.stub(:linters)
135
- .and_return([SCSSLint::Linter::SomeNamespace::FakeLinter1,
136
- SCSSLint::Linter::SomeNamespace::FakeLinter2])
135
+ .and_return([SCSSLint::Linter::SomeNamespace::FakeLinter1,
136
+ SCSSLint::Linter::SomeNamespace::FakeLinter2])
137
137
  end
138
138
 
139
139
  it 'returns the same options for all linters under that namespace' do
140
140
  subject.linter_options(SCSSLint::Linter::SomeNamespace::FakeLinter1)
141
- .should eq('enabled' => true)
141
+ .should include 'enabled' => true
142
142
  subject.linter_options(SCSSLint::Linter::SomeNamespace::FakeLinter2)
143
- .should eq('enabled' => true)
143
+ .should include 'enabled' => true
144
144
  end
145
145
  end
146
146
 
@@ -229,7 +229,27 @@ describe SCSSLint::Config do
229
229
 
230
230
  it 'returns the options for the specified linter' do
231
231
  config.linter_options(SCSSLint::Linter::FakeConfigLinter.new)
232
- .should == linter_options
232
+ .should include linter_options
233
+ end
234
+
235
+ context 'when global severity is specified' do
236
+ let(:options) { super().merge('severity' => 'some-severity') }
237
+
238
+ context 'and linter severity is not specified' do
239
+ it 'returns the global severity' do
240
+ config.linter_options(SCSSLint::Linter::FakeConfigLinter.new)
241
+ .should include 'severity' => 'some-severity'
242
+ end
243
+ end
244
+
245
+ context 'and linter severity is specified' do
246
+ let(:linter_options) { super().merge('severity' => 'custom-severity') }
247
+
248
+ it 'returns the custom linter severity' do
249
+ config.linter_options(SCSSLint::Linter::FakeConfigLinter.new)
250
+ .should include 'severity' => 'custom-severity'
251
+ end
252
+ end
233
253
  end
234
254
  end
235
255
 
@@ -48,6 +48,16 @@ describe SCSSLint::Linter::NameFormat do
48
48
  it { should report_lint line: 1 }
49
49
  end
50
50
 
51
+ context 'when a function contains variables with capital letters' do
52
+ let(:scss) { <<-SCSS }
53
+ p {
54
+ content: good-function($badVariable);
55
+ }
56
+ SCSS
57
+
58
+ it { should report_lint line: 2 }
59
+ end
60
+
51
61
  context 'when a mixin is declared with a capital letter' do
52
62
  let(:scss) { <<-SCSS }
53
63
  @mixin badMixin() {
@@ -364,6 +364,20 @@ describe SCSSLint::Linter::PropertySortOrder do
364
364
  SCSS
365
365
 
366
366
  it { should_not report_lint }
367
+
368
+ context 'and there are duplicate properties' do
369
+ let(:scss) { <<-SCSS }
370
+ p {
371
+ position: absolute;
372
+ top: 0;
373
+ transition: -webkit-transform .33s;
374
+ transition: transform .33s;
375
+ background-color: #eee;
376
+ }
377
+ SCSS
378
+
379
+ it { should_not report_lint }
380
+ end
367
381
  end
368
382
 
369
383
  context 'and the properties do not match the order' do
@@ -377,6 +391,20 @@ describe SCSSLint::Linter::PropertySortOrder do
377
391
  SCSS
378
392
 
379
393
  it { should report_lint }
394
+
395
+ context 'and there are duplicate properties' do
396
+ let(:scss) { <<-SCSS }
397
+ p {
398
+ position: absolute;
399
+ transition: -webkit-transform .33s;
400
+ transition: transform .33s;
401
+ top: 0;
402
+ background-color: #eee;
403
+ }
404
+ SCSS
405
+
406
+ it { should report_lint line: 3 }
407
+ end
380
408
  end
381
409
  end
382
410
 
@@ -95,4 +95,14 @@ describe SCSSLint::Linter::UnnecessaryParentReference do
95
95
 
96
96
  it { should_not report_lint }
97
97
  end
98
+
99
+ context 'when an ampersand is used in concatentation following an ampersand' do
100
+ let(:scss) { <<-SCSS }
101
+ .icon {
102
+ & &-small {}
103
+ }
104
+ SCSS
105
+
106
+ it { should_not report_lint }
107
+ end
98
108
  end
@@ -118,6 +118,16 @@ describe SCSSLint::Linter::VariableForProperty do
118
118
  it { should_not report_lint }
119
119
  end
120
120
 
121
+ context 'when property specifies `initial`' do
122
+ let(:scss) { <<-SCSS }
123
+ p {
124
+ color: initial;
125
+ }
126
+ SCSS
127
+
128
+ it { should_not report_lint }
129
+ end
130
+
121
131
  context 'when property specifies `transparent`' do
122
132
  let(:scss) { <<-SCSS }
123
133
  p {
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Logger do
4
+ let(:io) { StringIO.new }
5
+ let(:logger) { described_class.new(io) }
6
+
7
+ describe '#color_enabled' do
8
+ subject { io.string }
9
+
10
+ before do
11
+ logger.color_enabled = enabled
12
+ logger.success('Success!')
13
+ end
14
+
15
+ context 'when color is enabled' do
16
+ let(:enabled) { true }
17
+
18
+ it { should include '32' }
19
+ end
20
+
21
+ context 'when color is disabled' do
22
+ let(:enabled) { false }
23
+
24
+ it { should_not include '32' }
25
+ end
26
+ end
27
+ end
@@ -30,5 +30,23 @@ describe SCSSLint::Options do
30
30
  expect { subject }.to raise_error SCSSLint::Exceptions::InvalidCLIOption
31
31
  end
32
32
  end
33
+
34
+ context 'color' do
35
+ describe 'manually on' do
36
+ let(:args) { ['--color'] }
37
+
38
+ it 'sets the `color` option to true' do
39
+ subject.should include color: true
40
+ end
41
+ end
42
+
43
+ describe 'manually off' do
44
+ let(:args) { ['--no-color'] }
45
+
46
+ it 'sets the `color option to false' do
47
+ subject.should include color: false
48
+ end
49
+ end
50
+ end
33
51
  end
34
52
  end
@@ -13,7 +13,7 @@ describe SCSSLint::Plugins::LinterDir do
13
13
  describe '#load' do
14
14
  it 'requires each file in the plugin directory' do
15
15
  subject.should_receive(:require)
16
- .with(File.join(plugin_directory, 'linter_plugin.rb')).once
16
+ .with(File.join(plugin_directory, 'linter_plugin.rb')).once
17
17
 
18
18
  subject.load
19
19
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SCSSLint::Reporter::CleanFilesReporter do
4
- subject { described_class.new(lints, files) }
4
+ subject { described_class.new(lints, files, nil) }
5
5
 
6
6
  describe '#report_lints' do
7
7
  context 'when there are no lints and no files' do
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe SCSSLint::Reporter::ConfigReporter do
4
4
  subject { YAML.load(result) }
5
- let(:result) { described_class.new(lints, []).report_lints }
5
+ let(:result) { described_class.new(lints, [], nil).report_lints }
6
6
 
7
7
  describe '#report_lints' do
8
8
  context 'when there are no lints' do
@@ -1,7 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SCSSLint::Reporter::DefaultReporter do
4
- subject { SCSSLint::Reporter::DefaultReporter.new(lints, []) }
4
+ let(:logger) { SCSSLint::Logger.new($stdout) }
5
+ subject { SCSSLint::Reporter::DefaultReporter.new(lints, [], logger) }
5
6
 
6
7
  describe '#report_lints' do
7
8
  context 'when there are no lints' do
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SCSSLint::Reporter::FilesReporter do
4
- subject { described_class.new(lints, []) }
4
+ subject { described_class.new(lints, [], nil) }
5
5
 
6
6
  describe '#report_lints' do
7
7
  context 'when there are no lints' do
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SCSSLint::Reporter::JSONReporter do
4
- subject { SCSSLint::Reporter::JSONReporter.new(lints, []) }
4
+ subject { SCSSLint::Reporter::JSONReporter.new(lints, [], nil) }
5
5
 
6
6
  describe '#report_lints' do
7
7
  let(:json) { JSON.parse(subject.report_lints) }
@@ -56,22 +56,22 @@ describe SCSSLint::Reporter::JSONReporter do
56
56
 
57
57
  it 'marks each issue with a line number' do
58
58
  json.values.flat_map { |issues| issues.map { |issue| issue['line'] } }
59
- .should =~ locations.map(&:line)
59
+ .should =~ locations.map(&:line)
60
60
  end
61
61
 
62
62
  it 'marks each issue with a column number' do
63
63
  json.values.flat_map { |issues| issues.map { |issue| issue['column'] } }
64
- .should =~ locations.map(&:column)
64
+ .should =~ locations.map(&:column)
65
65
  end
66
66
 
67
67
  it 'marks each issue with a length' do
68
68
  json.values.flat_map { |issues| issues.map { |issue| issue['length'] } }
69
- .should =~ locations.map(&:length)
69
+ .should =~ locations.map(&:length)
70
70
  end
71
71
 
72
72
  it 'marks each issue with a reason containing the lint description' do
73
73
  json.values.flat_map { |issues| issues.map { |issue| issue['reason'] } }
74
- .should =~ descriptions
74
+ .should =~ descriptions
75
75
  end
76
76
 
77
77
  context 'when lints are warnings' do