scss_lint 0.45.0 → 0.46.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: 3c80256e0f694ade8ef5c0651dfc3cd95d1ed76a
4
- data.tar.gz: ea61d9083a223c299df36c0bc827e92716b941e5
3
+ metadata.gz: 9c199f69c02fbbb36ce36e564adaa78528fd5b49
4
+ data.tar.gz: 7372af4e048f1935dc730dfffacf89bcc4a1faed
5
5
  SHA512:
6
- metadata.gz: bdd1c5afb4507f544ec533ee8387506edcf1ad30e8466b0d01a0faaec2db376c4413fbd7b822fac687ba6c7ffd9672ad8103fdf2796a8521c6ae08815511269d
7
- data.tar.gz: 22a40913e53ebf7e82b181aca67af574a26d5a00ce10b7b090c77f7ba1756e084b038d634b0ff4dc244bd0561922a02f2a780b0f073aa4419e93a7638fea54b9
6
+ metadata.gz: dad57b1b932447052533abef8b58f2bd0288badf398b2eb946ed7bcfa8dc225e2615e7b90fce017092d5647c1057600b1e7edde12f5fd50781c358530b84e88e
7
+ data.tar.gz: 3581b2b0fb3d039346241eec26c889083fca38b0d3f1021052e94107bc0b766e636dd370af2c0e9c92fad70a9df7a5e3494c6f50f4d00005427ceb3b22fab54d
data/config/default.yml CHANGED
@@ -116,6 +116,10 @@ linters:
116
116
  PlaceholderInExtend:
117
117
  enabled: true
118
118
 
119
+ PrivateNamingConvention:
120
+ enabled: false
121
+ prefix: _
122
+
119
123
  PropertyCount:
120
124
  enabled: false
121
125
  include_nested: false
@@ -3,13 +3,22 @@ module SCSSLint
3
3
  class Linter::DuplicateProperty < Linter
4
4
  include LinterRegistry
5
5
 
6
+ def visit_root(_node)
7
+ @ignore_consecutive = config['ignore_consecutive']
8
+ yield
9
+ end
10
+
6
11
  def check_properties(node)
7
12
  static_properties(node).each_with_object({}) do |prop, prop_names|
8
13
  prop_key = property_key(prop)
9
14
 
10
15
  if existing_prop = prop_names[prop_key]
11
- add_lint(prop, "Property `#{existing_prop.name.join}` already "\
12
- "defined on line #{existing_prop.line}")
16
+ if existing_prop.line < prop.line - 1 || !ignore_consecutive_of?(prop)
17
+ add_lint(prop, "Property `#{existing_prop.name.join}` already "\
18
+ "defined on line #{existing_prop.line}")
19
+ else
20
+ prop_names[prop_key] = prop
21
+ end
13
22
  else
14
23
  prop_names[prop_key] = prop
15
24
  end
@@ -54,5 +63,21 @@ module SCSSLint
54
63
  prop.value.to_s
55
64
  end
56
65
  end
66
+
67
+ def ignore_consecutive_of?(prop)
68
+ case @ignore_consecutive
69
+ when true
70
+ return true
71
+ when false
72
+ return false
73
+ when nil
74
+ return false
75
+ when Array
76
+ return @ignore_consecutive.include?(prop.name.join)
77
+ else
78
+ raise SCSSLint::Exceptions::LinterError,
79
+ "#{@ignore_consecutive.inspect} is not a valid value for ignore_consecutive."
80
+ end
81
+ end
57
82
  end
58
83
  end
@@ -0,0 +1,157 @@
1
+ module SCSSLint
2
+ # Verifies that variables, functions, and mixins that follow the private
3
+ # naming convention are defined and used within the same file.
4
+ class Linter::PrivateNamingConvention < Linter # rubocop:disable ClassLength
5
+ include LinterRegistry
6
+
7
+ DEFINITIONS = {
8
+ Sass::Tree::FunctionNode => {
9
+ defines: Sass::Script::Tree::Funcall,
10
+ human_name: 'function',
11
+ },
12
+ Sass::Tree::MixinDefNode => {
13
+ defines: Sass::Tree::MixinNode,
14
+ human_name: 'mixin',
15
+ },
16
+ Sass::Tree::VariableNode => {
17
+ defines: Sass::Script::Tree::Variable,
18
+ human_name: 'variable',
19
+ },
20
+ }.freeze
21
+
22
+ HUMAN_NODE_NAMES = Hash[DEFINITIONS.map { |k, v| [k, v[:human_name]] }].freeze
23
+ DEFINED_BYS = Hash[DEFINITIONS.map { |k, v| [v[:defines], k] }].freeze
24
+
25
+ def visit_root(node)
26
+ # Register all top-level function, mixin, and variable definitions.
27
+ node.children.each_with_object([]) do |child_node|
28
+ if DEFINITIONS.key?(child_node.class)
29
+ register_node child_node
30
+ else
31
+ yield
32
+ end
33
+ end
34
+
35
+ # After we have visited everything, we want to see if any private things
36
+ # were defined but not used.
37
+ after_visit_all
38
+ end
39
+
40
+ def visit_script_funcall(node)
41
+ check_privacy(node)
42
+ yield # Continue linting any arguments of this function call
43
+ end
44
+
45
+ def visit_mixin(node)
46
+ check_privacy(node)
47
+ yield # Continue into content block of this mixin's block
48
+ end
49
+
50
+ def visit_script_variable(node)
51
+ check_privacy(node)
52
+ end
53
+
54
+ private
55
+
56
+ def register_node(node, node_text = node.name)
57
+ return unless private?(node)
58
+
59
+ @private_definitions ||= {}
60
+ @private_definitions[node.class] ||= {}
61
+
62
+ @private_definitions[node.class][node_text] = {
63
+ node: node,
64
+ times_used: 0,
65
+ }
66
+ end
67
+
68
+ def check_privacy(node, node_text = node.name)
69
+ return unless private?(node)
70
+
71
+ defined_by_class = defined_by(node)
72
+
73
+ # Look at top-level private definitions
74
+ if @private_definitions &&
75
+ @private_definitions[defined_by_class] &&
76
+ @private_definitions[defined_by_class][node_text]
77
+ @private_definitions[defined_by_class][node_text][:times_used] += 1
78
+ return
79
+ end
80
+
81
+ # We did not find a top-level private definition, so let's traverse up the
82
+ # tree, looking for private definitions of this node that are scoped.
83
+ looking_for = {
84
+ node: node,
85
+ defined_by: defined_by_class,
86
+ location: location_from_range(node.source_range),
87
+ }
88
+ return if node_defined_earlier_in_branch?(node.node_parent, looking_for)
89
+
90
+ node_type = humanize_node_class(node)
91
+ add_lint(
92
+ node,
93
+ "Private #{node_type} #{node_text} must be defined in the same file it is used"
94
+ )
95
+ end
96
+
97
+ def node_defined_earlier_in_branch?(node_to_look_in, looking_for)
98
+ # Look at all of the children of this node and return true if we find a
99
+ # defining node that matches in name and type.
100
+ node_to_look_in.children.each_with_object([]) do |child_node|
101
+ break unless before?(child_node, looking_for[:location])
102
+ next unless child_node.class == looking_for[:defined_by]
103
+ next unless child_node.name == looking_for[:node].name
104
+
105
+ return true # We found a match, so we are done
106
+ end
107
+
108
+ # We are at the top of the branch and don't want to check the root branch,
109
+ # since that is handled elsewhere, which means that we did not find a
110
+ # match.
111
+ return false unless node_to_look_in.node_parent.node_parent
112
+
113
+ # We did not find a match yet, and haven't reached the top of the branch,
114
+ # so recurse.
115
+ if node_to_look_in.node_parent
116
+ node_defined_earlier_in_branch?(node_to_look_in.node_parent, looking_for)
117
+ end
118
+ end
119
+
120
+ def private?(node)
121
+ node.name.start_with?(config['prefix'])
122
+ end
123
+
124
+ def before?(node, before_location)
125
+ location = location_from_range(node.source_range)
126
+ return true if location.line < before_location.line
127
+ if location.line == before_location.line &&
128
+ location.column < before_location.column
129
+ return true
130
+ end
131
+ false
132
+ end
133
+
134
+ def after_visit_all
135
+ return unless @private_definitions
136
+
137
+ @private_definitions.each do |_, nodes|
138
+ nodes.each do |node_text, node_info|
139
+ next if node_info[:times_used] > 0
140
+ node_type = humanize_node_class(node_info[:node])
141
+ add_lint(
142
+ node_info[:node],
143
+ "Private #{node_type} #{node_text} must be used in the same file it is defined"
144
+ )
145
+ end
146
+ end
147
+ end
148
+
149
+ def humanize_node_class(node)
150
+ HUMAN_NODE_NAMES[node.class]
151
+ end
152
+
153
+ def defined_by(node)
154
+ DEFINED_BYS[node.class]
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,123 @@
1
+ module SCSSLint
2
+ # Reports in TAP format.
3
+ # http://testanything.org/
4
+ class Reporter::TAPReporter < Reporter
5
+ TAP_VERSION = 'TAP version 13'.freeze
6
+
7
+ def report_lints
8
+ output = [TAP_VERSION, format_plan(files, lints)]
9
+ return format_output(output) unless files.any?
10
+
11
+ output.concat(format_files(files, lints))
12
+ format_output(output)
13
+ end
14
+
15
+ private
16
+
17
+ # @param files [Array<String>]
18
+ # @param lints [Array<SCSSLint::Lint>]
19
+ # @return [String]
20
+ def format_plan(files, lints)
21
+ files_with_lints = lints.map(&:filename).uniq
22
+ extra_lines = lints.count - files_with_lints.count
23
+ comment = files.count == 0 ? ' # No files to lint' : ''
24
+ "1..#{files.count + extra_lines}#{comment}"
25
+ end
26
+
27
+ # @param files [Array<String>]
28
+ # @param lints [Array<SCSSLint::Lint>]
29
+ # @return [Array<String>] one item per ok file or not ok lint
30
+ def format_files(files, lints)
31
+ unless lints.any?
32
+ # There are no lints, so we can take a shortcut and just output an ok
33
+ # test line for every file.
34
+ return files.map.with_index do |filename, index|
35
+ format_ok(filename, index + 1)
36
+ end
37
+ end
38
+
39
+ # There are lints, so we need to go through each file, find the lints
40
+ # for the file, and add them to the output.
41
+
42
+ # Since we'll be looking up lints by filename for each filename, we want
43
+ # to make a first pass to group all of the lints by filename to make
44
+ # lookup fast.
45
+ grouped_lints = group_lints_by_filename(lints)
46
+
47
+ test_number = 1
48
+ files.map do |filename|
49
+ if grouped_lints.key?(filename)
50
+ # This file has lints, so we want to generate a "not ok" test line for
51
+ # each failing lint.
52
+ grouped_lints[filename].map do |lint|
53
+ formatted = format_not_ok(lint, test_number)
54
+ test_number += 1
55
+ formatted
56
+ end
57
+ else
58
+ formatted = format_ok(filename, test_number)
59
+ test_number += 1
60
+ [formatted]
61
+ end
62
+ end.flatten
63
+ end
64
+
65
+ # @param lints [Array<SCSSLint::Lint>]
66
+ # @return [Hash] keyed by filename, values are arrays of lints
67
+ def group_lints_by_filename(lints)
68
+ grouped_lints = {}
69
+ lints.each do |lint|
70
+ grouped_lints[lint.filename] ||= []
71
+ grouped_lints[lint.filename] << lint
72
+ end
73
+ grouped_lints
74
+ end
75
+
76
+ # @param filename [String]
77
+ # @param test_number [Number]
78
+ # @return [String]
79
+ def format_ok(filename, test_number)
80
+ "ok #{test_number} - #{filename}"
81
+ end
82
+
83
+ # @param lint [SCSSLint::Lint]
84
+ # @param test_number [Number]
85
+ # @return [String]
86
+ def format_not_ok(lint, test_number)
87
+ location = lint.location
88
+ test_line_description = "#{lint.filename}:#{location.line}:#{location.column}"
89
+ test_line_description += " #{lint.linter.name}" if lint.linter
90
+
91
+ <<-EOS.strip
92
+ not ok #{test_number} - #{test_line_description}
93
+ ---
94
+ message: #{lint.description}
95
+ severity: #{lint.severity}
96
+ data:
97
+ file: #{lint.filename}
98
+ line: #{lint.location.line}
99
+ column: #{lint.location.column}
100
+ ---
101
+ EOS
102
+ end
103
+
104
+ # @param output [Array<String>]
105
+ # @return [String]
106
+ def format_output(output)
107
+ output.join("\n") + "\n"
108
+ end
109
+
110
+ def location(lint)
111
+ "#{log.cyan(lint.filename)}:#{log.magenta(lint.location.line.to_s)}"
112
+ end
113
+
114
+ def type(lint)
115
+ lint.error? ? log.red('[E]') : log.yellow('[W]')
116
+ end
117
+
118
+ def message(lint)
119
+ linter_name = log.green("#{lint.linter.name}: ") if lint.linter
120
+ "#{linter_name}#{lint.description}"
121
+ end
122
+ end
123
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Defines the gem version.
4
4
  module SCSSLint
5
- VERSION = '0.45.0'.freeze
5
+ VERSION = '0.46.0'.freeze
6
6
  end
@@ -186,4 +186,59 @@ describe SCSSLint::Linter::DuplicateProperty do
186
186
 
187
187
  it { should report_lint line: 4 }
188
188
  end
189
+
190
+ context 'when consecutive duplicate properties are allowed' do
191
+ let(:linter_config) { { 'ignore_consecutive' => true } }
192
+
193
+ context 'when rule set contains consecutive duplicates' do
194
+ let(:scss) { <<-SCSS }
195
+ p {
196
+ background-color: #fff;
197
+ background-color: rgba(255, 255, 255, 0.7);
198
+ background-color: a-third-thing;
199
+ }
200
+ SCSS
201
+
202
+ it { should_not report_lint }
203
+ end
204
+
205
+ context 'when rule set contains non-consecutive duplicates' do
206
+ let(:scss) { <<-SCSS }
207
+ p {
208
+ margin: 0;
209
+ padding: 0;
210
+ margin: 1em;
211
+ }
212
+ SCSS
213
+
214
+ it { should report_lint line: 4 }
215
+ end
216
+ end
217
+
218
+ context 'when specific consecutive duplicate properties are allowed' do
219
+ let(:linter_config) { { 'ignore_consecutive' => ['background-color', 'transition'] } }
220
+
221
+ context 'when rule set contains consecutive duplicates in whitelist' do
222
+ let(:scss) { <<-SCSS }
223
+ p {
224
+ background-color: #fff;
225
+ background-color: rgba(255, 255, 255, 0.7);
226
+ background-color: a-third-thing;
227
+ }
228
+ SCSS
229
+
230
+ it { should_not report_lint }
231
+ end
232
+
233
+ context 'when rule set contains consecutive duplicates not in whitelist' do
234
+ let(:scss) { <<-SCSS }
235
+ p {
236
+ margin: 0;
237
+ margin: 5px;
238
+ }
239
+ SCSS
240
+
241
+ it { should report_lint line: 3 }
242
+ end
243
+ end
189
244
  end
@@ -0,0 +1,445 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Linter::PrivateNamingConvention do
4
+ context 'when a private variable' do
5
+ context 'is not used in the same file it is defined' do
6
+ let(:scss) { <<-SCSS }
7
+ $_foo: red;
8
+ SCSS
9
+
10
+ it { should report_lint line: 1 }
11
+ end
12
+
13
+ context 'is used but not defined in the same file' do
14
+ let(:scss) { <<-SCSS }
15
+ p {
16
+ color: $_foo;
17
+ background: rgba($_foo, 0);
18
+ }
19
+ SCSS
20
+
21
+ it { should report_lint line: 2 }
22
+ it { should report_lint line: 3 }
23
+ end
24
+
25
+ context 'is used but has not been defined quite yet' do
26
+ let(:scss) { <<-SCSS }
27
+ p {
28
+ color: $_foo;
29
+ background: rgba($_foo, 0);
30
+ }
31
+
32
+ $_foo: red;
33
+ SCSS
34
+
35
+ it { should report_lint line: 2 }
36
+ it { should report_lint line: 3 }
37
+ end
38
+
39
+ context 'is defined and used in the same file' do
40
+ let(:scss) { <<-SCSS }
41
+ $_foo: red;
42
+
43
+ p {
44
+ color: $_foo;
45
+ }
46
+ SCSS
47
+
48
+ it { should_not report_lint }
49
+ end
50
+
51
+ context 'is defined and used in the same file in a function' do
52
+ let(:scss) { <<-SCSS }
53
+ $_foo: red;
54
+
55
+ p {
56
+ color: rgba($_foo, 0);
57
+ }
58
+ SCSS
59
+
60
+ it { should_not report_lint }
61
+ end
62
+
63
+ context 'is defined within a selector and not used' do
64
+ let(:scss) { <<-SCSS }
65
+ p {
66
+ $_foo: red;
67
+ }
68
+ SCSS
69
+
70
+ it { should_not report_lint }
71
+ end
72
+
73
+ context 'is defined within a selector and used' do
74
+ let(:scss) { <<-SCSS }
75
+ p {
76
+ $_foo: red;
77
+ color: $_foo;
78
+ }
79
+ SCSS
80
+
81
+ it { should_not report_lint }
82
+ end
83
+
84
+ context 'is defined within a selector and used in a nested selector' do
85
+ let(:scss) { <<-SCSS }
86
+ p {
87
+ $_foo: red;
88
+
89
+ a {
90
+ color: $_foo;
91
+ }
92
+ }
93
+ SCSS
94
+
95
+ it { should_not report_lint }
96
+ end
97
+
98
+ context 'is defined within a selector but too late' do
99
+ let(:scss) { <<-SCSS }
100
+ p {
101
+ color: $_foo;
102
+ $_foo: red;
103
+ }
104
+ SCSS
105
+
106
+ it { should report_lint line: 2 }
107
+ end
108
+
109
+ context 'is defined within a selector but after the nested selector it is used in' do
110
+ let(:scss) { <<-SCSS }
111
+ p {
112
+ a {
113
+ color: $_foo;
114
+ }
115
+
116
+ $_foo: red;
117
+ }
118
+ SCSS
119
+
120
+ it { should report_lint line: 3 }
121
+ end
122
+
123
+ context 'is defined in a different selector than it is used in' do
124
+ let(:scss) { <<-SCSS }
125
+ p {
126
+ $_foo: red;
127
+ }
128
+
129
+ a {
130
+ color: $_foo;
131
+ }
132
+ SCSS
133
+
134
+ it { should report_lint line: 6 }
135
+ end
136
+ end
137
+
138
+ context 'when a public variable' do
139
+ context 'is used but not defined' do
140
+ let(:scss) { <<-SCSS }
141
+ p {
142
+ color: $foo;
143
+ }
144
+ SCSS
145
+
146
+ it { should_not report_lint }
147
+ end
148
+
149
+ context 'is defined but not used' do
150
+ let(:scss) { <<-SCSS }
151
+ $foo: red;
152
+ SCSS
153
+
154
+ it { should_not report_lint }
155
+ end
156
+ end
157
+
158
+ context 'when a private mixin' do
159
+ context 'is not used in the same file it is defined' do
160
+ let(:scss) { <<-SCSS }
161
+ @mixin _foo {
162
+ color: red;
163
+ }
164
+ SCSS
165
+
166
+ it { should report_lint line: 1 }
167
+ end
168
+
169
+ context 'is used but not defined in the same file' do
170
+ let(:scss) { <<-SCSS }
171
+ p {
172
+ @include _foo;
173
+ }
174
+ SCSS
175
+
176
+ it { should report_lint line: 2 }
177
+ end
178
+
179
+ context 'is used but has not been defined quite yet' do
180
+ let(:scss) { <<-SCSS }
181
+ p {
182
+ @include _foo;
183
+ }
184
+
185
+ @mixin _foo {
186
+ color: red;
187
+ }
188
+ SCSS
189
+
190
+ it { should report_lint line: 2 }
191
+ end
192
+
193
+ context 'is defined within a selector and not used' do
194
+ let(:scss) { <<-SCSS }
195
+ p {
196
+ @mixin _foo {
197
+ color: red;
198
+ }
199
+ }
200
+ SCSS
201
+
202
+ it { should_not report_lint }
203
+ end
204
+
205
+ context 'is defined within a selector and used within that selector' do
206
+ let(:scss) { <<-SCSS }
207
+ p {
208
+ @mixin _foo {
209
+ color: red;
210
+ }
211
+
212
+ @include _foo;
213
+ }
214
+ SCSS
215
+
216
+ it { should_not report_lint }
217
+ end
218
+
219
+ context 'is defined within a selector and used within a nested selector' do
220
+ let(:scss) { <<-SCSS }
221
+ p {
222
+ @mixin _foo {
223
+ color: red;
224
+ }
225
+
226
+ a {
227
+ @include _foo;
228
+ }
229
+ }
230
+ SCSS
231
+
232
+ it { should_not report_lint }
233
+ end
234
+
235
+ context 'is defined within a selector and used within that selector too early' do
236
+ let(:scss) { <<-SCSS }
237
+ p {
238
+ @include _foo;
239
+
240
+ @mixin _foo {
241
+ color: red;
242
+ }
243
+ }
244
+ SCSS
245
+
246
+ it { should report_lint line: 2 }
247
+ end
248
+
249
+ context 'is defined within a selector and used within a nested selector too early' do
250
+ let(:scss) { <<-SCSS }
251
+ p {
252
+ a {
253
+ @include _foo;
254
+ }
255
+
256
+ @mixin _foo {
257
+ color: red;
258
+ }
259
+ }
260
+ SCSS
261
+
262
+ it { should report_lint line: 3 }
263
+ end
264
+
265
+ context 'is defined and used in the same file' do
266
+ let(:scss) { <<-SCSS }
267
+ @mixin _foo {
268
+ color: red;
269
+ }
270
+
271
+ p {
272
+ @include _foo;
273
+ }
274
+ SCSS
275
+
276
+ it { should_not report_lint }
277
+ end
278
+ end
279
+
280
+ context 'when a public mixin' do
281
+ context 'is used but not defined' do
282
+ let(:scss) { <<-SCSS }
283
+ p {
284
+ @include foo;
285
+ }
286
+ SCSS
287
+
288
+ it { should_not report_lint }
289
+ end
290
+
291
+ context 'is defined but not used' do
292
+ let(:scss) { <<-SCSS }
293
+ @mixin foo {
294
+ color: red;
295
+ }
296
+ SCSS
297
+
298
+ it { should_not report_lint }
299
+ end
300
+ end
301
+
302
+ describe 'when a private function' do
303
+ context 'is not used in the same file it is defined' do
304
+ let(:scss) { <<-SCSS }
305
+ @function _foo() {
306
+ @return red;
307
+ }
308
+ SCSS
309
+
310
+ it { should report_lint line: 1 }
311
+ end
312
+
313
+ context 'is used but not defined in the same file' do
314
+ let(:scss) { <<-SCSS }
315
+ p {
316
+ color: _foo();
317
+ }
318
+ SCSS
319
+
320
+ it { should report_lint line: 2 }
321
+ end
322
+
323
+ context 'is used but has not been defined quite yet' do
324
+ let(:scss) { <<-SCSS }
325
+ p {
326
+ color: _foo();
327
+ }
328
+
329
+ @function _foo() {
330
+ @return red;
331
+ }
332
+ SCSS
333
+
334
+ it { should report_lint line: 2 }
335
+ end
336
+
337
+ context 'is defined within a selector and not used' do
338
+ let(:scss) { <<-SCSS }
339
+ p {
340
+ @function _foo() {
341
+ @return red;
342
+ }
343
+ }
344
+ SCSS
345
+
346
+ it { should_not report_lint }
347
+ end
348
+
349
+ context 'is defined within a selector and used within the same selector' do
350
+ let(:scss) { <<-SCSS }
351
+ p {
352
+ @function _foo() {
353
+ @return red;
354
+ }
355
+
356
+ color: _foo();
357
+ }
358
+ SCSS
359
+
360
+ it { should_not report_lint }
361
+ end
362
+
363
+ context 'is defined within a selector and used within a nested selector' do
364
+ let(:scss) { <<-SCSS }
365
+ p {
366
+ @function _foo() {
367
+ @return red;
368
+ }
369
+
370
+ a {
371
+ color: _foo();
372
+ }
373
+ }
374
+ SCSS
375
+
376
+ it { should_not report_lint }
377
+ end
378
+
379
+ context 'is defined within a selector and used within the same selector too early' do
380
+ let(:scss) { <<-SCSS }
381
+ p {
382
+ color: _foo();
383
+
384
+ @function _foo() {
385
+ @return red;
386
+ }
387
+ }
388
+ SCSS
389
+
390
+ it { should report_lint line: 2 }
391
+ end
392
+
393
+ context 'is defined within a selector and used within a nested too early' do
394
+ let(:scss) { <<-SCSS }
395
+ p {
396
+ a {
397
+ color: _foo();
398
+ }
399
+
400
+ @function _foo() {
401
+ @return red;
402
+ }
403
+ }
404
+ SCSS
405
+
406
+ it { should report_lint line: 3 }
407
+ end
408
+
409
+ context 'is defined and used in the same file' do
410
+ let(:scss) { <<-SCSS }
411
+ @function _foo() {
412
+ @return red;
413
+ }
414
+
415
+ p {
416
+ color: _foo();
417
+ }
418
+ SCSS
419
+
420
+ it { should_not report_lint }
421
+ end
422
+ end
423
+
424
+ context 'when a public function' do
425
+ context 'is used but not defined' do
426
+ let(:scss) { <<-SCSS }
427
+ p {
428
+ color: foo();
429
+ }
430
+ SCSS
431
+
432
+ it { should_not report_lint }
433
+ end
434
+
435
+ context 'is defined but not used' do
436
+ let(:scss) { <<-SCSS }
437
+ @function foo() {
438
+ @return red;
439
+ }
440
+ SCSS
441
+
442
+ it { should_not report_lint }
443
+ end
444
+ end
445
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Reporter::TAPReporter do
4
+ let(:logger) { SCSSLint::Logger.new($stdout) }
5
+ subject { described_class.new(lints, filenames, logger) }
6
+
7
+ describe '#report_lints' do
8
+ context 'when there are no files' do
9
+ let(:filenames) { [] }
10
+ let(:lints) { [] }
11
+
12
+ it 'returns the TAP version, plan, and explanation' do
13
+ subject.report_lints.should == "TAP version 13\n1..0 # No files to lint\n"
14
+ end
15
+ end
16
+
17
+ context 'when there are files but no lints' do
18
+ let(:filenames) { ['file.scss', 'another-file.scss'] }
19
+ let(:lints) { [] }
20
+
21
+ it 'returns the TAP version, plan, and ok test lines' do
22
+ subject.report_lints.should eq(<<-EOS)
23
+ TAP version 13
24
+ 1..2
25
+ ok 1 - file.scss
26
+ ok 2 - another-file.scss
27
+ EOS
28
+ end
29
+ end
30
+
31
+ context 'when there are some lints' do
32
+ let(:filenames) { %w[ok1.scss not-ok1.scss not-ok2.scss ok2.scss] }
33
+
34
+ let(:lints) do
35
+ [
36
+ SCSSLint::Lint.new(
37
+ SCSSLint::Linter::PrivateNamingConvention,
38
+ filenames[1],
39
+ SCSSLint::Location.new(123, 10, 8),
40
+ 'Description of lint 1',
41
+ :warning
42
+ ),
43
+ SCSSLint::Lint.new(
44
+ SCSSLint::Linter::PrivateNamingConvention,
45
+ filenames[2],
46
+ SCSSLint::Location.new(20, 2, 6),
47
+ 'Description of lint 2',
48
+ :error
49
+ ),
50
+ SCSSLint::Lint.new(
51
+ SCSSLint::Linter::PrivateNamingConvention,
52
+ filenames[2],
53
+ SCSSLint::Location.new(21, 3, 4),
54
+ 'Description of lint 3',
55
+ :warning
56
+ ),
57
+ ]
58
+ end
59
+
60
+ it 'returns the TAP version, plan, and correct test lines' do
61
+ subject.report_lints.should eq(<<-EOS)
62
+ TAP version 13
63
+ 1..5
64
+ ok 1 - ok1.scss
65
+ not ok 2 - not-ok1.scss:123:10 SCSSLint::Linter::PrivateNamingConvention
66
+ ---
67
+ message: Description of lint 1
68
+ severity: warning
69
+ data:
70
+ file: not-ok1.scss
71
+ line: 123
72
+ column: 10
73
+ ---
74
+ not ok 3 - not-ok2.scss:20:2 SCSSLint::Linter::PrivateNamingConvention
75
+ ---
76
+ message: Description of lint 2
77
+ severity: error
78
+ data:
79
+ file: not-ok2.scss
80
+ line: 20
81
+ column: 2
82
+ ---
83
+ not ok 4 - not-ok2.scss:21:3 SCSSLint::Linter::PrivateNamingConvention
84
+ ---
85
+ message: Description of lint 3
86
+ severity: warning
87
+ data:
88
+ file: not-ok2.scss
89
+ line: 21
90
+ column: 3
91
+ ---
92
+ ok 5 - ok2.scss
93
+ EOS
94
+ end
95
+ end
96
+ end
97
+ 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.45.0
4
+ version: 0.46.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-02-17 00:00:00.000000000 Z
12
+ date: 2016-02-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -118,6 +118,7 @@ files:
118
118
  - lib/scss_lint/linter/name_format.rb
119
119
  - lib/scss_lint/linter/nesting_depth.rb
120
120
  - lib/scss_lint/linter/placeholder_in_extend.rb
121
+ - lib/scss_lint/linter/private_naming_convention.rb
121
122
  - lib/scss_lint/linter/property_count.rb
122
123
  - lib/scss_lint/linter/property_sort_order.rb
123
124
  - lib/scss_lint/linter/property_spelling.rb
@@ -163,6 +164,7 @@ files:
163
164
  - lib/scss_lint/reporter/default_reporter.rb
164
165
  - lib/scss_lint/reporter/files_reporter.rb
165
166
  - lib/scss_lint/reporter/json_reporter.rb
167
+ - lib/scss_lint/reporter/tap_reporter.rb
166
168
  - lib/scss_lint/runner.rb
167
169
  - lib/scss_lint/sass/script.rb
168
170
  - lib/scss_lint/sass/tree.rb
@@ -203,6 +205,7 @@ files:
203
205
  - spec/scss_lint/linter/name_format_spec.rb
204
206
  - spec/scss_lint/linter/nesting_depth_spec.rb
205
207
  - spec/scss_lint/linter/placeholder_in_extend_spec.rb
208
+ - spec/scss_lint/linter/private_naming_convention_spec.rb
206
209
  - spec/scss_lint/linter/property_count_spec.rb
207
210
  - spec/scss_lint/linter/property_sort_order_spec.rb
208
211
  - spec/scss_lint/linter/property_spelling_spec.rb
@@ -249,6 +252,7 @@ files:
249
252
  - spec/scss_lint/reporter/default_reporter_spec.rb
250
253
  - spec/scss_lint/reporter/files_reporter_spec.rb
251
254
  - spec/scss_lint/reporter/json_reporter_spec.rb
255
+ - spec/scss_lint/reporter/tap_reporter_spec.rb
252
256
  - spec/scss_lint/reporter_spec.rb
253
257
  - spec/scss_lint/runner_spec.rb
254
258
  - spec/scss_lint/selector_visitor_spec.rb
@@ -314,6 +318,7 @@ test_files:
314
318
  - spec/scss_lint/linter/name_format_spec.rb
315
319
  - spec/scss_lint/linter/nesting_depth_spec.rb
316
320
  - spec/scss_lint/linter/placeholder_in_extend_spec.rb
321
+ - spec/scss_lint/linter/private_naming_convention_spec.rb
317
322
  - spec/scss_lint/linter/property_count_spec.rb
318
323
  - spec/scss_lint/linter/property_sort_order_spec.rb
319
324
  - spec/scss_lint/linter/property_spelling_spec.rb
@@ -360,6 +365,7 @@ test_files:
360
365
  - spec/scss_lint/reporter/default_reporter_spec.rb
361
366
  - spec/scss_lint/reporter/files_reporter_spec.rb
362
367
  - spec/scss_lint/reporter/json_reporter_spec.rb
368
+ - spec/scss_lint/reporter/tap_reporter_spec.rb
363
369
  - spec/scss_lint/reporter_spec.rb
364
370
  - spec/scss_lint/runner_spec.rb
365
371
  - spec/scss_lint/selector_visitor_spec.rb