scss_lint 0.48.0 → 0.49.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 836d64855e532ba7edb008a354400fdb3a752b40
4
- data.tar.gz: 9712c133bc9cf2ff5b9bc5081fc27ab2a258263b
3
+ metadata.gz: 881e2595ce6e859e53e9148db36e2f3d11bcb429
4
+ data.tar.gz: e28e168aa7ec435017b415278fe3fc68c8b911ca
5
5
  SHA512:
6
- metadata.gz: 8da6137c2915033192ede52347dd8ed2384a134afb192f8f053957da5d6043ea24b100d93f8acf6391bbef92e88d36aa6d97e258413056996b4aef0538de090e
7
- data.tar.gz: e043ed88d75c13b5343f18c2cab961853016bfce1533a721ed8cc7f323fe2bd37d24d50cb90ba5b76931f4fb94a3be67f9b009183c28d8967e9a5b6e27663846
6
+ metadata.gz: f27ed9d01d9a7920c3d88d0d9345b8ba107978fd536d90618d406af9cc8209221cc220054d1f118320af98927fce38b91144c4af1c4686d2a09b7dda2394aaaa
7
+ data.tar.gz: c6cfb9ba3bf3a0957cbd756b7e0cf9b4702432a94275214b97c98fd2884e63bc225adaec713148d41fae2b0078e070ed6e77ded6d3c4c4139b0cb8e4aaa0b3ec
data/config/default.yml CHANGED
@@ -168,7 +168,7 @@ linters:
168
168
 
169
169
  Shorthand:
170
170
  enabled: true
171
- allowed_shorthands: [1, 2, 3]
171
+ allowed_shorthands: [1, 2, 3, 4]
172
172
 
173
173
  SingleLinePerProperty:
174
174
  enabled: true
@@ -45,6 +45,7 @@ padding-left
45
45
 
46
46
  float
47
47
  clear
48
+ clip
48
49
 
49
50
  columns
50
51
  column-gap
@@ -106,6 +107,7 @@ outline-width
106
107
 
107
108
  background
108
109
  background-attachment
110
+ background-clip
109
111
  background-color
110
112
  background-image
111
113
  background-repeat
@@ -4,7 +4,7 @@ module SCSSLint
4
4
  include LinterRegistry
5
5
 
6
6
  def visit_debug(node)
7
- add_lint(node, 'Remove @debug line')
7
+ add_lint(node, 'Remove `@debug` line')
8
8
  end
9
9
  end
10
10
  end
@@ -36,10 +36,10 @@ module SCSSLint
36
36
  if same_line_preferred?
37
37
  unless curly_on_same_line
38
38
  add_lint(else_node,
39
- '@else should be placed on same line as previous curly brace')
39
+ '`@else` should be placed on same line as previous curly brace')
40
40
  end
41
41
  elsif curly_on_same_line
42
- add_lint(else_node, '@else should be placed on its own line')
42
+ add_lint(else_node, '`@else` should be placed on its own line')
43
43
  end
44
44
  end
45
45
 
@@ -4,7 +4,7 @@ module SCSSLint
4
4
  include LinterRegistry
5
5
 
6
6
  def visit_extend(node)
7
- add_lint(node, 'Do not use the @extend directive (@include a @mixin ' \
7
+ add_lint(node, 'Do not use the `@extend` directive (`@include` a `@mixin` ' \
8
8
  'instead)')
9
9
  end
10
10
  end
@@ -0,0 +1,107 @@
1
+ module SCSSLint
2
+ # Ensures length literals are used only in variable declarations.
3
+ class Linter::LengthVariable < Linter
4
+ include LinterRegistry
5
+
6
+ LENGTH_UNITS = [
7
+ 'ch', 'em', 'ex', 'rem', # Font-relative lengths
8
+ 'cm', 'in', 'mm', 'pc', 'pt', 'px', 'q', # Absolute lengths
9
+ 'vh', 'vw', 'vmin', 'vmax' # Viewport-percentage lengths
10
+ ].freeze
11
+
12
+ LENGTH_RE = %r{
13
+ (?:^|[\s+\-/*()]) # math or space separated, or beginning of string
14
+ ( # capture whole length
15
+ 0 # unitless zero
16
+ |
17
+ [-+]? # optional sign
18
+ (?:
19
+ \.\d+ # with leading decimal, e.g. .5
20
+ |
21
+ \d+(\.\d+)? # whole or maybe with trailing decimal
22
+ )
23
+ (?:#{LENGTH_UNITS.join('|')}) # unit!
24
+ )
25
+ (?:$|[\s+\-/*()]) # math or space separated, or end of string
26
+ }x
27
+
28
+ def visit_prop(node)
29
+ return if allowed_prop?(node)
30
+ lint_lengths(node)
31
+ end
32
+
33
+ def visit_mixindef(node)
34
+ lint_lengths(node)
35
+ end
36
+
37
+ def visit_media(node)
38
+ lint_lengths(node)
39
+ end
40
+
41
+ def visit_mixin(node)
42
+ lint_lengths(node)
43
+ end
44
+
45
+ private
46
+
47
+ def lint_lengths(node)
48
+ lengths = extract_lengths(node)
49
+ lengths = [lengths].flatten.compact.uniq
50
+ lengths -= config['allowed_lengths'] if config['allowed_lengths']
51
+ lengths.each do |length|
52
+ record_lint(node, length) unless lengths.empty?
53
+ end
54
+ end
55
+
56
+ def record_lint(node, length)
57
+ add_lint node, "Length literals like `#{length}` should only be used in " \
58
+ 'variable declarations; they should be referred to via ' \
59
+ 'variables everywhere else.'
60
+ end
61
+
62
+ def allowed_prop?(node)
63
+ config['allowed_properties'] && config['allowed_properties'].include?(node.name.first.to_s)
64
+ end
65
+
66
+ # Though long, This method is clear enough in a boring, dispatch kind of way.
67
+ # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
68
+ def extract_lengths(node)
69
+ case node
70
+ when Sass::Tree::PropNode
71
+ extract_lengths(node.value)
72
+ when Sass::Script::Tree::Literal
73
+ extract_lengths_from_string(node.value)
74
+ when String
75
+ extract_lengths_from_string(node)
76
+ when Sass::Script::Tree::Funcall,
77
+ Sass::Tree::MixinNode,
78
+ Sass::Tree::MixinDefNode
79
+ extract_lengths_from_list(*node.args)
80
+ when Sass::Script::Tree::ListLiteral
81
+ extract_lengths_from_list(*node.elements)
82
+ when Sass::Tree::MediaNode
83
+ extract_lengths_from_list(*node.query)
84
+ when Array
85
+ extract_lengths_from_list(*node)
86
+ when Sass::Script::Tree::Interpolation
87
+ extract_lengths_from_list(node.before, node.mid, node.after)
88
+ when Sass::Script::Tree::Operation
89
+ extract_lengths_from_list(node.operand1, node.operand2)
90
+ when Sass::Script::Tree::UnaryOperation
91
+ extract_lengths(node.operand)
92
+ when Sass::Script::Tree::Variable
93
+ nil
94
+ end
95
+ end
96
+ # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
97
+
98
+ def extract_lengths_from_string(string)
99
+ matchdata = string.to_s.match(LENGTH_RE)
100
+ matchdata && matchdata.captures
101
+ end
102
+
103
+ def extract_lengths_from_list(*values)
104
+ values.map { |v| extract_lengths(v) }
105
+ end
106
+ end
107
+ end
@@ -3,13 +3,34 @@ module SCSSLint
3
3
  class Linter::NameFormat < Linter
4
4
  include LinterRegistry
5
5
 
6
+ CSS_FUNCTION_WHITELIST = %w[
7
+ rotateX rotateY rotateZ
8
+ scaleX scaleY scaleZ
9
+ skewX skewY
10
+ translateX translateY translateZ
11
+ linear-gradient repeating-linear-gradient
12
+ radial-gradient repeating-radial-gradient
13
+ ].to_set.freeze
14
+
15
+ SCSS_FUNCTION_WHITELIST = %w[
16
+ adjust-hue adjust-color scale-color change-color ie-hex-str
17
+ str-length str-insert str-index str-slice to-upper-case to-lower-case
18
+ list-separator
19
+ map-get map-merge map-remove map-keys map-values map-has-key
20
+ selector-nest selector-append selector-extend selector-replace
21
+ selector-unify is-superselector simple-selectors selector-parse
22
+ feature-exists variable-exists global-variable-exists function-exists
23
+ mixin-exists type-of
24
+ unique-id
25
+ ].to_set.freeze
26
+
6
27
  def visit_function(node)
7
28
  check_name(node, 'function')
8
29
  yield # Continue into content block of this function definition
9
30
  end
10
31
 
11
32
  def visit_mixin(node)
12
- check_name(node, 'mixin') unless FUNCTION_WHITELIST.include?(node.name)
33
+ check_name(node, 'mixin') unless whitelist?(node.name)
13
34
  yield # Continue into content block of this mixin's block
14
35
  end
15
36
 
@@ -19,7 +40,7 @@ module SCSSLint
19
40
  end
20
41
 
21
42
  def visit_script_funcall(node)
22
- check_name(node, 'function') unless FUNCTION_WHITELIST.include?(node.name)
43
+ check_name(node, 'function') unless whitelist?(node.name)
23
44
  yield # Continue linting any arguments of this function call
24
45
  end
25
46
 
@@ -34,13 +55,10 @@ module SCSSLint
34
55
 
35
56
  private
36
57
 
37
- FUNCTION_WHITELIST = %w[
38
- rotateX rotateY rotateZ
39
- scaleX scaleY scaleZ
40
- skewX skewY
41
- translateX translateY translateZ
42
- linear-gradient
43
- ].to_set
58
+ def whitelist?(name)
59
+ CSS_FUNCTION_WHITELIST.include?(name) ||
60
+ SCSS_FUNCTION_WHITELIST.include?(name)
61
+ end
44
62
 
45
63
  def check_name(node, node_type, node_text = node.name)
46
64
  node_text = trim_underscore_prefix(node_text)
@@ -105,9 +105,9 @@ module SCSSLint
105
105
  # we don't care, but at least one line that isn't another property).
106
106
  next if first[:node].line < second[:node].line - 1
107
107
 
108
- add_lint second[:node], "Property #{second[:name]} should be " \
109
- 'separated from the previous group of ' \
110
- "properties ending with #{first[:name]}"
108
+ add_lint second[:node], "Property `#{second[:name]}` should have an " \
109
+ 'empty line separating it from the previous ' \
110
+ "group of properties ending with `#{first[:name]}`"
111
111
  end
112
112
  end
113
113
 
@@ -163,7 +163,7 @@ module SCSSLint
163
163
  file = File.open(File.join(SCSS_LINT_DATA,
164
164
  'property-sort-orders',
165
165
  "#{config['order']}.txt"))
166
- file.read.split("\n").reject { |line| line =~ /^(#|\s*$)/ }
166
+ file.read.split("\n").reject { |line| line =~ /^\s*#/ }
167
167
  rescue Errno::ENOENT
168
168
  raise SCSSLint::Exceptions::LinterError,
169
169
  "Preset property sort order '#{config['order']}' does not exist"
@@ -68,6 +68,9 @@ module SCSSLint
68
68
  # @param node [Sass::Script::Value::String]
69
69
  # @param values [Array<String>]
70
70
  def check_shorthand(prop, node, values)
71
+ add_lint(node, "Shorthands of length `#{values.count}` are not allowed. " \
72
+ "Value was `#{values.join(' ')}`") unless allowed?(values.count)
73
+
71
74
  return unless (2..4).member?(values.count)
72
75
 
73
76
  shortest_form = condensed_shorthand(*values)
@@ -94,8 +94,7 @@ module SCSSLint
94
94
  end
95
95
 
96
96
  def adjust_for_interpolation
97
- @source = normalize_source(
98
- @linter.source_fm_range(slide_to_the_left(@node.source_range)))
97
+ @source = normalize_source(@linter.source_fm_range(slide_to_the_left(@node.source_range)))
99
98
  @left_range = slide_to_the_left(@node.operand1.source_range)
100
99
  @right_range = slide_to_the_left(@node.operand2.source_range)
101
100
  end
@@ -25,7 +25,7 @@ module SCSSLint
25
25
  FRACTIONAL_DIGIT_REGEX = /^-?(\d*\.\d+)/
26
26
 
27
27
  def check_for_trailing_zeros(node, original_number)
28
- return unless match = /^(\d*\.\d*)0+$/.match(original_number)
28
+ return unless match = /^(\d*\.(?:[0-9]*[1-9]|[1-9])*)0+$/.match(original_number)
29
29
 
30
30
  fixed_number = match[1]
31
31
 
@@ -12,7 +12,11 @@ module SCSSLint
12
12
  private
13
13
 
14
14
  def location(lint)
15
- "#{log.cyan(lint.filename)}:#{log.magenta(lint.location.line.to_s)}"
15
+ [
16
+ log.cyan(lint.filename),
17
+ log.magenta(lint.location.line.to_s),
18
+ log.magenta(lint.location.column.to_s),
19
+ ].join(':')
16
20
  end
17
21
 
18
22
  def type(lint)
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Defines the gem version.
4
4
  module SCSSLint
5
- VERSION = '0.48.0'.freeze
5
+ VERSION = '0.49.0'.freeze
6
6
  end
@@ -274,7 +274,8 @@ describe SCSSLint::Linter::Indentation do
274
274
 
275
275
  context 'when indentation in non-nested code is allowed' do
276
276
  let(:linter_config) do
277
- { 'allow_non_nested_indentation' => true,
277
+ {
278
+ 'allow_non_nested_indentation' => true,
278
279
  'character' => 'space',
279
280
  'width' => 2,
280
281
  }
@@ -0,0 +1,388 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Linter::LengthVariable do
4
+ context 'when a length literal is used in a variable declaration' do
5
+ let(:scss) { <<-SCSS }
6
+ $my-length: 10px;
7
+ SCSS
8
+
9
+ it { should_not report_lint }
10
+ end
11
+
12
+ context 'when a length calculation containing literals is used in a variable declaration' do
13
+ let(:scss) { <<-SCSS }
14
+ $my-length: 10px / 2;
15
+ SCSS
16
+
17
+ it { should_not report_lint }
18
+ end
19
+
20
+ context 'when a length literal is used in a property' do
21
+ let(:scss) { <<-SCSS }
22
+ p {
23
+ width: 10px;
24
+ }
25
+ SCSS
26
+
27
+ it { should report_lint line: 2 }
28
+ end
29
+
30
+ context 'when a negative length literal is used in a property' do
31
+ let(:scss) { <<-SCSS }
32
+ p {
33
+ margin: -10px;
34
+ }
35
+ SCSS
36
+
37
+ it { should report_lint line: 2 }
38
+ end
39
+
40
+ context 'when a length literal is used in a function call' do
41
+ let(:scss) { <<-SCSS }
42
+ p {
43
+ width: my-func(10px);
44
+ }
45
+ SCSS
46
+
47
+ it { should report_lint line: 2 }
48
+ end
49
+
50
+ context 'when a length literal is used in a mixin' do
51
+ let(:scss) { <<-SCSS }
52
+ p {
53
+ @include my-mixin(10px);
54
+ }
55
+ SCSS
56
+
57
+ it { should report_lint line: 2 }
58
+ end
59
+
60
+ context 'when a length literal is used in a shorthand property' do
61
+ let(:scss) { <<-SCSS }
62
+ p {
63
+ text-shadow: 10px 10px black;
64
+ }
65
+ SCSS
66
+
67
+ it { should report_lint line: 2 }
68
+ end
69
+
70
+ context 'when a length literal is used as a mixin default argument' do
71
+ let(:scss) { <<-SCSS }
72
+ @mixin checkbox ($length: 10px) {
73
+ width: $length;
74
+ }
75
+ SCSS
76
+
77
+ it { should report_lint line: 1 }
78
+ end
79
+
80
+ context 'when a number is used in a property' do
81
+ let(:scss) { <<-SCSS }
82
+ p {
83
+ z-index: 9000;
84
+ transition-duration: 250ms;
85
+ line-height: 1;
86
+ }
87
+ SCSS
88
+
89
+ it { should_not report_lint }
90
+ end
91
+
92
+ context 'when a non-length keyword is used in a property' do
93
+ let(:scss) { <<-SCSS }
94
+ p {
95
+ width: auto;
96
+ }
97
+ SCSS
98
+
99
+ it { should_not report_lint }
100
+ end
101
+
102
+ context 'when a variable is used in a property' do
103
+ let(:scss) { <<-SCSS }
104
+ p {
105
+ width: $my-length;
106
+ }
107
+ SCSS
108
+
109
+ it { should_not report_lint }
110
+ end
111
+
112
+ context 'when a variable is used in a function call' do
113
+ let(:scss) { <<-SCSS }
114
+ p {
115
+ width: my-func($my-length);
116
+ }
117
+ SCSS
118
+
119
+ it { should_not report_lint }
120
+ end
121
+
122
+ context 'when a variable operated with a literal' do
123
+ let(:scss) { <<-SCSS }
124
+ p {
125
+ width: $my-length + 10px;
126
+ height: $my-length - 10px;
127
+ top: $my-length * 10px;
128
+ bottom: $my-length - 10px;
129
+ }
130
+ SCSS
131
+
132
+ it { should report_lint line: 2 }
133
+ it { should report_lint line: 3 }
134
+ it { should report_lint line: 4 }
135
+ it { should report_lint line: 5 }
136
+ end
137
+
138
+ context 'when a variable unary operation' do
139
+ let(:scss) { <<-SCSS }
140
+ p {
141
+ top: -$my-length;
142
+ bottom: +$my-length;
143
+ }
144
+ SCSS
145
+
146
+ it { should_not report_lint line: 2 }
147
+ it { should_not report_lint line: 3 }
148
+ end
149
+
150
+ context 'when a variable is used in a shorthand property' do
151
+ let(:scss) { <<-SCSS }
152
+ p {
153
+ border: $my-length solid black;
154
+ }
155
+ SCSS
156
+
157
+ it { should_not report_lint }
158
+ end
159
+
160
+ context 'when a property contains "auto"' do
161
+ let(:scss) { <<-SCSS }
162
+ p {
163
+ margin: auto;
164
+ }
165
+ SCSS
166
+
167
+ it { should_not report_lint }
168
+ end
169
+
170
+ context 'when a length literal is used in a map declaration' do
171
+ let(:scss) { <<-SCSS }
172
+ $margins: (
173
+ small: 4px,
174
+ medium: 8px,
175
+ large: 16px
176
+ );
177
+ SCSS
178
+
179
+ it { should_not report_lint }
180
+ end
181
+
182
+ context 'when a string with a length is used in a function call' do
183
+ let(:scss) { <<-SCSS }
184
+ p {
185
+ width: my-func('10px');
186
+ }
187
+ SCSS
188
+
189
+ it { should_not report_lint }
190
+ end
191
+
192
+ context 'when a variable is interpolated in a multiline comment' do
193
+ let(:scss) { <<-SCSS }
194
+ $a: 0;
195
+
196
+ /*!
197
+ * test \#{a}
198
+ */
199
+ SCSS
200
+
201
+ it { should_not report_lint }
202
+ end
203
+
204
+ context 'when using calc' do
205
+ let(:scss) { <<-SCSS }
206
+ p {
207
+ width: calc(100em + 5px);
208
+ }
209
+ SCSS
210
+
211
+ it { should report_lint line: 2 }
212
+ end
213
+
214
+ context 'when using calc with no spacing' do
215
+ let(:scss) { <<-SCSS }
216
+ p {
217
+ width: calc(100em+5px);
218
+ }
219
+ SCSS
220
+
221
+ it { should report_lint line: 2 }
222
+ end
223
+
224
+ context 'when using calc with all interpolations' do
225
+ let(:scss) { <<-SCSS }
226
+ p {
227
+ width: calc(\#{$my-width} + \#{$my-spacing});
228
+ }
229
+ SCSS
230
+
231
+ it { should_not report_lint }
232
+ end
233
+
234
+ context 'when a variable is interpolated' do
235
+ let(:scss) { <<-SCSS }
236
+ p {
237
+ width: calc(\#{$my-length} + 5px)
238
+ }
239
+ SCSS
240
+
241
+ it { should report_lint line: 2 }
242
+ end
243
+
244
+ context 'when a literal is interpolated' do
245
+ let(:scss) { <<-SCSS }
246
+ p {
247
+ width: calc(\#{10px} + $my-length)
248
+ }
249
+ SCSS
250
+
251
+ it { should report_lint line: 2 }
252
+ end
253
+
254
+ context 'when a string is interpolated' do ## analogous to the ColorVariable linter
255
+ let(:scss) { <<-SCSS }
256
+ p {
257
+ width: calc(\#{'10px'} + $my-length)
258
+ }
259
+ SCSS
260
+
261
+ it { should_not report_lint }
262
+ end
263
+
264
+ context 'when disambiguating with brackets' do
265
+ let(:scss) { <<-SCSS }
266
+ p {
267
+ margin: (-10px) (-10px);
268
+ }
269
+ SCSS
270
+
271
+ it { should report_lint line: 2 }
272
+ end
273
+
274
+ context 'in the awkward looking font shorthand' do
275
+ let(:scss) { <<-SCSS }
276
+ strong { font: bold 10px/14px sans-serif; }
277
+ em { font: bold $my-font-size/14px sans-serif; }
278
+ blockquote { font: bold 10px/$my-line-height sans-serif; }
279
+ p { font: bold $my-font-size/1 sans-serif; }
280
+ SCSS
281
+
282
+ it { should report_lint line: 1 }
283
+ it { should report_lint line: 2 }
284
+ it { should report_lint line: 3 }
285
+ it { should_not report_lint line: 4 }
286
+ end
287
+
288
+ context 'when a length is used in a media query' do
289
+ let(:scss) { <<-SCSS }
290
+ @media (min-width:100px) {
291
+ p { color: red; }
292
+ }
293
+ @media (max-width: 100px ) {
294
+ p { color: blue; }
295
+ }
296
+ @media (max-width: 100px*5) {
297
+ p { color: orange; }
298
+ }
299
+ @media (min-device-pixel-ratio: 2) {
300
+ p { color: green; }
301
+ }
302
+ SCSS
303
+
304
+ it { should report_lint line: 1 }
305
+ it { should report_lint line: 4 }
306
+ it { should report_lint line: 7 }
307
+ it { should_not report_lint line: 10 }
308
+ end
309
+
310
+ context 'when length is allowed' do
311
+ let(:linter_config) { { 'allowed_lengths' => %w[100px 0 5px] } }
312
+ context 'when using an allowed length' do
313
+ let(:scss) { <<-SCSS }
314
+ p {
315
+ width: 100px;
316
+ border-width: 0;
317
+ }
318
+ SCSS
319
+
320
+ it { should_not report_lint }
321
+ end
322
+
323
+ context 'when using an allowed length in a calculation' do
324
+ let(:scss) { <<-SCSS }
325
+ p {
326
+ margin: -(5px);
327
+ border-width: $my-variable + 5px;
328
+ width: calc(100px + \#{$my-margin});
329
+ }
330
+ SCSS
331
+
332
+ it { should_not report_lint }
333
+ end
334
+
335
+ context 'when using a similar disallowed length' do
336
+ let(:scss) { <<-SCSS }
337
+ p {
338
+ width: 101px;
339
+ margin: 100em;
340
+ border-width: 0;
341
+ }
342
+ SCSS
343
+
344
+ it { should report_lint line: 2 }
345
+ it { should report_lint line: 3 }
346
+ it { should_not report_lint line: 4 }
347
+ end
348
+ end
349
+
350
+ context 'when using a length with an allowed property' do
351
+ let(:linter_config) { { 'allowed_properties' => ['text-shadow', 'box-shadow'] } }
352
+ let(:scss) { <<-SCSS }
353
+ p {
354
+ text-shadow: 10px 10px 5px blue;
355
+ box-shadow: 10px 10px 5px red;
356
+ width: $my-variable;
357
+ }
358
+ SCSS
359
+
360
+ it { should_not report_lint }
361
+ end
362
+
363
+ context 'when a length calculation containing literals is used in a property' do
364
+ let(:scss) { <<-SCSS }
365
+ p {
366
+ width: 10px + 10px;
367
+ }
368
+ a {
369
+ width: 10px - 10px;
370
+ }
371
+ i {
372
+ width: 10px / 4;
373
+ }
374
+ span {
375
+ width: 10px * 2;
376
+ }
377
+ .class {
378
+ width: -10px + 11;
379
+ }
380
+ SCSS
381
+
382
+ it { should report_lint line: 2 }
383
+ it { should report_lint line: 5 }
384
+ it { should report_lint line: 8 }
385
+ it { should report_lint line: 11 }
386
+ it { should report_lint line: 14 }
387
+ end
388
+ end
@@ -405,6 +405,33 @@ describe SCSSLint::Linter::PropertySortOrder do
405
405
 
406
406
  it { should report_lint line: 3 }
407
407
  end
408
+
409
+ context 'and `separate_groups` is enabled' do
410
+ let(:linter_config) { super().merge('separate_groups' => true) }
411
+
412
+ context 'and the properties are not separated' do
413
+ let(:scss) { <<-SCSS }
414
+ p {
415
+ visibility: hidden;
416
+ margin: 0;
417
+ }
418
+ SCSS
419
+
420
+ it { should report_lint }
421
+ end
422
+
423
+ context 'and the properties are separated' do
424
+ let(:scss) { <<-SCSS }
425
+ p {
426
+ visibility: hidden;
427
+
428
+ margin: 0;
429
+ }
430
+ SCSS
431
+
432
+ it { should_not report_lint }
433
+ end
434
+ end
408
435
  end
409
436
  end
410
437
 
@@ -194,5 +194,16 @@ describe SCSSLint::Linter::Shorthand do
194
194
 
195
195
  it { should_not report_lint }
196
196
  end
197
+
198
+ context 'is fine but length is not allowed' do
199
+ let(:allowed) { [1, 2, 3] }
200
+ let(:scss) { <<-SCSS }
201
+ p {
202
+ margin: 1px 2px 3px 4px;
203
+ }
204
+ SCSS
205
+
206
+ it { should report_lint }
207
+ end
197
208
  end
198
209
  end
@@ -47,6 +47,16 @@ describe SCSSLint::Linter::TrailingZero do
47
47
  it { should_not report_lint }
48
48
  end
49
49
 
50
+ context 'when a unitless fractional value with multiple trailing zero exists' do
51
+ let(:scss) { <<-SCSS }
52
+ p {
53
+ line-height: .600;
54
+ }
55
+ SCSS
56
+
57
+ it { should report_lint }
58
+ end
59
+
50
60
  context 'when a negative unitless fractional value with no trailing zero exists' do
51
61
  let(:scss) { <<-SCSS }
52
62
  p {
@@ -15,12 +15,13 @@ describe SCSSLint::Reporter::DefaultReporter do
15
15
 
16
16
  context 'when there are lints' do
17
17
  let(:filenames) { ['some-filename.scss', 'other-filename.scss'] }
18
- let(:lines) { [502, 724] }
18
+ let(:locations) { [[502, 3], [724, 6]] }
19
19
  let(:descriptions) { ['Description of lint 1', 'Description of lint 2'] }
20
20
  let(:severities) { [:warning] * 2 }
21
21
  let(:lints) do
22
22
  filenames.each_with_index.map do |filename, index|
23
- location = SCSSLint::Location.new(lines[index])
23
+ line, column = locations[index]
24
+ location = SCSSLint::Location.new(line, column, 10)
24
25
  SCSSLint::Lint.new(nil, filename, location, descriptions[index],
25
26
  severities[index])
26
27
  end
@@ -41,8 +42,14 @@ describe SCSSLint::Reporter::DefaultReporter do
41
42
  end
42
43
 
43
44
  it 'prints the line number for each lint' do
44
- lines.each do |line|
45
- subject.report_lints.scan(line.to_s).count.should == 1
45
+ locations.each do |location|
46
+ subject.report_lints.scan(location[0].to_s).count.should == 1
47
+ end
48
+ end
49
+
50
+ it 'prints the column number for each lint' do
51
+ locations.each do |location|
52
+ subject.report_lints.scan(location[1].to_s).count.should == 1
46
53
  end
47
54
  end
48
55
 
@@ -44,7 +44,7 @@ describe SCSSLint::Reporter::StatsReporter do
44
44
  end
45
45
 
46
46
  it 'prints the total lints and total lines' do
47
- subject.report_lints.should match /2 total +\(across 1/
47
+ subject.report_lints.should match(/2 total +\(across 1/)
48
48
  end
49
49
  end
50
50
 
@@ -74,7 +74,7 @@ describe SCSSLint::Reporter::StatsReporter do
74
74
  end
75
75
 
76
76
  it 'prints the total lints and total lines' do
77
- subject.report_lints.should match /3 total +\(across 1/
77
+ subject.report_lints.should match(/3 total +\(across 1/)
78
78
  end
79
79
  end
80
80
 
@@ -108,7 +108,7 @@ describe SCSSLint::Reporter::StatsReporter do
108
108
  end
109
109
 
110
110
  it 'prints the total lints and total lines' do
111
- subject.report_lints.should match /6 total +\(across 3/
111
+ subject.report_lints.should match(/6 total +\(across 3/)
112
112
  end
113
113
  end
114
114
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scss_lint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.48.0
4
+ version: 0.49.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brigade Engineering
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-04-16 00:00:00.000000000 Z
12
+ date: 2016-07-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -37,14 +37,14 @@ dependencies:
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 3.4.15
40
+ version: 3.4.20
41
41
  type: :runtime
42
42
  prerelease: false
43
43
  version_requirements: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 3.4.15
47
+ version: 3.4.20
48
48
  description: Configurable tool for writing clean and consistent SCSS
49
49
  email:
50
50
  - eng@brigade.com
@@ -100,6 +100,7 @@ files:
100
100
  - lib/scss_lint/linter/important_rule.rb
101
101
  - lib/scss_lint/linter/indentation.rb
102
102
  - lib/scss_lint/linter/leading_zero.rb
103
+ - lib/scss_lint/linter/length_variable.rb
103
104
  - lib/scss_lint/linter/mergeable_selector.rb
104
105
  - lib/scss_lint/linter/name_format.rb
105
106
  - lib/scss_lint/linter/nesting_depth.rb
@@ -188,6 +189,7 @@ files:
188
189
  - spec/scss_lint/linter/important_rule_spec.rb
189
190
  - spec/scss_lint/linter/indentation_spec.rb
190
191
  - spec/scss_lint/linter/leading_zero_spec.rb
192
+ - spec/scss_lint/linter/length_variable_spec.rb
191
193
  - spec/scss_lint/linter/mergeable_selector_spec.rb
192
194
  - spec/scss_lint/linter/name_format_spec.rb
193
195
  - spec/scss_lint/linter/nesting_depth_spec.rb
@@ -268,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
270
  version: '0'
269
271
  requirements: []
270
272
  rubyforge_project:
271
- rubygems_version: 2.4.5.1
273
+ rubygems_version: 2.5.1
272
274
  signing_key:
273
275
  specification_version: 4
274
276
  summary: SCSS lint tool
@@ -303,6 +305,7 @@ test_files:
303
305
  - spec/scss_lint/linter/important_rule_spec.rb
304
306
  - spec/scss_lint/linter/indentation_spec.rb
305
307
  - spec/scss_lint/linter/leading_zero_spec.rb
308
+ - spec/scss_lint/linter/length_variable_spec.rb
306
309
  - spec/scss_lint/linter/mergeable_selector_spec.rb
307
310
  - spec/scss_lint/linter/name_format_spec.rb
308
311
  - spec/scss_lint/linter/nesting_depth_spec.rb
@@ -363,3 +366,4 @@ test_files:
363
366
  - spec/spec_helper.rb
364
367
  - spec/support/isolated_environment.rb
365
368
  - spec/support/matchers/report_lint.rb
369
+ has_rdoc: