scss_lint 0.43.2 → 0.44.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.
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