scss-lint 0.28.0 → 0.29.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/config/default.yml +7 -3
- data/data/properties.txt +14 -6
- data/lib/scss_lint/cli.rb +1 -1
- data/lib/scss_lint/config.rb +1 -1
- data/lib/scss_lint/linter/declaration_order.rb +1 -1
- data/lib/scss_lint/linter/empty_line_between_blocks.rb +11 -2
- data/lib/scss_lint/linter/id_with_extraneous_selector.rb +0 -2
- data/lib/scss_lint/linter/leading_zero.rb +2 -4
- data/lib/scss_lint/linter/property_sort_order.rb +2 -1
- data/lib/scss_lint/linter/selector_format.rb +79 -0
- data/lib/scss_lint/linter/trailing_semicolon.rb +8 -0
- data/lib/scss_lint/linter/trailing_zero.rb +41 -0
- data/lib/scss_lint/linter/unnecessary_parent_reference.rb +7 -2
- data/lib/scss_lint/linter/url_quotes.rb +2 -0
- data/lib/scss_lint/reporter/json_reporter.rb +23 -0
- data/lib/scss_lint/sass/script.rb +1 -1
- data/lib/scss_lint/version.rb +1 -1
- data/spec/scss_lint/linter/empty_line_between_blocks_spec.rb +12 -0
- data/spec/scss_lint/linter/property_sort_order_spec.rb +11 -0
- data/spec/scss_lint/linter/selector_format_spec.rb +272 -0
- data/spec/scss_lint/linter/trailing_semicolon_spec.rb +10 -0
- data/spec/scss_lint/linter/trailing_zero_spec.rb +176 -0
- data/spec/scss_lint/linter/unnecessary_parent_reference_spec.rb +10 -0
- data/spec/scss_lint/linter/url_quotes_spec.rb +10 -0
- data/spec/scss_lint/reporter/json_reporter_spec.rb +96 -0
- metadata +13 -7
- data/lib/scss_lint/linter/capitalization_in_selector.rb +0 -49
- data/spec/scss_lint/linter/capitalization_in_selector_spec.rb +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe908b2051342dce6151d04897242d18a3f9bf0b
|
4
|
+
data.tar.gz: 785752360ba0475386ecc1c8f8d202268293f428
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd5a9205186a67350c31d52d0cbd8677510fa5ae270ca0b25fc99dd87768c8b02393ebbbf2d068cc66f19ddf89ff7fb19b467d74a99ea3702fe7ff134352ef0a
|
7
|
+
data.tar.gz: 8063dfc1815c2d3b4a3edb76540635282484e0e56a1ce7b71bf2a60ec493ad5b3948b17b4fae56db6e1df226aa6704802946530aaf6304bd3a5952875b6d1409
|
data/config/default.yml
CHANGED
@@ -3,9 +3,6 @@ linters:
|
|
3
3
|
BorderZero:
|
4
4
|
enabled: true
|
5
5
|
|
6
|
-
CapitalizationInSelector:
|
7
|
-
enabled: true
|
8
|
-
|
9
6
|
ColorKeyword:
|
10
7
|
enabled: true
|
11
8
|
|
@@ -82,6 +79,10 @@ linters:
|
|
82
79
|
enabled: true
|
83
80
|
max_depth: 3
|
84
81
|
|
82
|
+
SelectorFormat:
|
83
|
+
enabled: true
|
84
|
+
convention: hyphenated_lowercase # or 'snake_case', or 'camel_case', or a regex pattern
|
85
|
+
|
85
86
|
Shorthand:
|
86
87
|
enabled: true
|
87
88
|
|
@@ -117,6 +118,9 @@ linters:
|
|
117
118
|
TrailingSemicolon:
|
118
119
|
enabled: true
|
119
120
|
|
121
|
+
TrailingZero:
|
122
|
+
enabled: false
|
123
|
+
|
120
124
|
UnnecessaryMantissa:
|
121
125
|
enabled: true
|
122
126
|
|
data/data/properties.txt
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
@keyframes
|
1
2
|
align-content
|
2
3
|
align-items
|
4
|
+
align-self
|
3
5
|
alignment-adjust
|
4
6
|
alignment-baseline
|
5
|
-
|
7
|
+
all
|
6
8
|
animation
|
7
9
|
animation-delay
|
8
10
|
animation-direction
|
@@ -12,8 +14,8 @@ animation-iteration-count
|
|
12
14
|
animation-name
|
13
15
|
animation-play-state
|
14
16
|
animation-timing-function
|
15
|
-
appearance
|
16
17
|
app-region
|
18
|
+
appearance
|
17
19
|
aspect-ratio
|
18
20
|
backface-visibility
|
19
21
|
background
|
@@ -123,9 +125,9 @@ column-rule
|
|
123
125
|
column-rule-color
|
124
126
|
column-rule-style
|
125
127
|
column-rule-width
|
126
|
-
columns
|
127
128
|
column-span
|
128
129
|
column-width
|
130
|
+
columns
|
129
131
|
content
|
130
132
|
counter-increment
|
131
133
|
counter-reset
|
@@ -176,7 +178,9 @@ font-variant-ligatures
|
|
176
178
|
font-weight
|
177
179
|
glyph-orientation-horizontal
|
178
180
|
glyph-orientation-vertical
|
181
|
+
grid
|
179
182
|
grid-after
|
183
|
+
grid-area
|
180
184
|
grid-auto-columns
|
181
185
|
grid-auto-flow
|
182
186
|
grid-auto-rows
|
@@ -188,6 +192,7 @@ grid-row
|
|
188
192
|
grid-rows
|
189
193
|
grid-start
|
190
194
|
grid-template
|
195
|
+
grid-template-areas
|
191
196
|
hanging-punctuation
|
192
197
|
height
|
193
198
|
highlight
|
@@ -207,8 +212,8 @@ image-resolution
|
|
207
212
|
inline-box-align
|
208
213
|
isolation
|
209
214
|
justify-content
|
215
|
+
justify-self
|
210
216
|
kerning
|
211
|
-
@keyframes
|
212
217
|
left
|
213
218
|
letter-spacing
|
214
219
|
lighting-color
|
@@ -354,6 +359,7 @@ ruby-align
|
|
354
359
|
ruby-overhang
|
355
360
|
ruby-position
|
356
361
|
ruby-span
|
362
|
+
scroll-behavior
|
357
363
|
shape-image-threshold
|
358
364
|
shape-inside
|
359
365
|
shape-margin
|
@@ -375,8 +381,8 @@ stroke-miterlimit
|
|
375
381
|
stroke-opacity
|
376
382
|
stroke-width
|
377
383
|
svg-shadow
|
378
|
-
table-layout
|
379
384
|
tab-size
|
385
|
+
table-layout
|
380
386
|
tap-highlight-color
|
381
387
|
target
|
382
388
|
target-name
|
@@ -389,8 +395,8 @@ text-combine
|
|
389
395
|
text-decoration
|
390
396
|
text-decoration-color
|
391
397
|
text-decoration-line
|
392
|
-
text-decorations-in-effect
|
393
398
|
text-decoration-style
|
399
|
+
text-decorations-in-effect
|
394
400
|
text-emphasis
|
395
401
|
text-emphasis-color
|
396
402
|
text-emphasis-position
|
@@ -425,6 +431,7 @@ text-underline-width
|
|
425
431
|
text-wrap
|
426
432
|
top
|
427
433
|
touch-action
|
434
|
+
touch-action-delay
|
428
435
|
transform
|
429
436
|
transform-origin
|
430
437
|
transform-origin-x
|
@@ -455,6 +462,7 @@ voice-volume
|
|
455
462
|
white-space
|
456
463
|
widows
|
457
464
|
width
|
465
|
+
will-change
|
458
466
|
word-break
|
459
467
|
word-spacing
|
460
468
|
word-wrap
|
data/lib/scss_lint/cli.rb
CHANGED
data/lib/scss_lint/config.rb
CHANGED
@@ -36,7 +36,7 @@ module SCSSLint
|
|
36
36
|
@dir_to_config ||= {}
|
37
37
|
@dir_to_config[directory] ||=
|
38
38
|
begin
|
39
|
-
config_file = possible_config_files(directory).find
|
39
|
+
config_file = possible_config_files(directory).find(&:file?)
|
40
40
|
Config.load(config_file.to_s) if config_file
|
41
41
|
end
|
42
42
|
end
|
@@ -36,8 +36,17 @@ module SCSSLint
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def check_following_node(node, type)
|
39
|
-
return unless (following_node = next_node(node)) &&
|
40
|
-
|
39
|
+
return unless (following_node = next_node(node)) &&
|
40
|
+
(next_start_line = following_node.line)
|
41
|
+
|
42
|
+
# Special case: ignore comments immediately after a closing brace
|
43
|
+
line = engine.lines[next_start_line - 1].strip
|
44
|
+
return if following_node.is_a?(Sass::Tree::CommentNode) &&
|
45
|
+
line =~ %r{\s*\}\s*/(/|\*)}
|
46
|
+
|
47
|
+
# Otherwise check if line before the next node's starting line is blank
|
48
|
+
line = engine.lines[next_start_line - 2].strip
|
49
|
+
return if line.empty?
|
41
50
|
|
42
51
|
add_lint(next_start_line - 1, MESSAGE_FORMAT % [type, 'followed'])
|
43
52
|
end
|
@@ -13,8 +13,6 @@ module SCSSLint
|
|
13
13
|
end
|
14
14
|
return unless can_be_simplified
|
15
15
|
|
16
|
-
# TODO: Sass::Selector::SimpleSequence#source_range sometimes lies about
|
17
|
-
# its line, so reference `#line` directly
|
18
16
|
add_lint(seq.line, "Selector `#{seq}` can be simplified to `#{id_sel}`, " \
|
19
17
|
'since IDs should be uniquely identifying')
|
20
18
|
end
|
@@ -14,10 +14,8 @@ module SCSSLint
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def visit_script_number(node)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
return unless number = source[FRACTIONAL_DIGIT_REGEX, 1]
|
17
|
+
return unless number =
|
18
|
+
source_from_range(node.source_range)[FRACTIONAL_DIGIT_REGEX, 1]
|
21
19
|
|
22
20
|
check_number(node, number)
|
23
21
|
end
|
@@ -33,8 +33,9 @@ module SCSSLint
|
|
33
33
|
yield # Continue linting children
|
34
34
|
end
|
35
35
|
|
36
|
-
alias_method :
|
36
|
+
alias_method :visit_media, :check_sort_order
|
37
37
|
alias_method :visit_mixin, :check_sort_order
|
38
|
+
alias_method :visit_rule, :check_sort_order
|
38
39
|
|
39
40
|
def visit_if(node, &block)
|
40
41
|
check_sort_order(node, &block)
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module SCSSLint
|
2
|
+
# Checks that selector names use a specified convention
|
3
|
+
class Linter::SelectorFormat < Linter
|
4
|
+
include LinterRegistry
|
5
|
+
|
6
|
+
def visit_root(_node)
|
7
|
+
@ignored_names = Array(config['ignored_names']).to_set
|
8
|
+
@ignored_types = Array(config['ignored_types']).to_set
|
9
|
+
yield
|
10
|
+
end
|
11
|
+
|
12
|
+
def visit_attribute(attribute)
|
13
|
+
check(attribute) unless @ignored_types.include?('attribute')
|
14
|
+
end
|
15
|
+
|
16
|
+
def visit_class(klass)
|
17
|
+
check(klass) unless @ignored_types.include?('class')
|
18
|
+
end
|
19
|
+
|
20
|
+
def visit_element(element)
|
21
|
+
check(element) unless @ignored_types.include?('element')
|
22
|
+
end
|
23
|
+
|
24
|
+
def visit_id(id)
|
25
|
+
check(id) unless @ignored_types.include?('id')
|
26
|
+
end
|
27
|
+
|
28
|
+
def visit_placeholder(placeholder)
|
29
|
+
check(placeholder) unless @ignored_types.include?('placeholder')
|
30
|
+
end
|
31
|
+
|
32
|
+
def visit_pseudo(pseudo)
|
33
|
+
check(pseudo) unless @ignored_types.include?('pseudo-selector')
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def check(node)
|
39
|
+
name = node.name
|
40
|
+
|
41
|
+
return if @ignored_names.include?(name)
|
42
|
+
return unless violation = violated_convention(name)
|
43
|
+
|
44
|
+
add_lint(node, "Selector `#{name}` should be " \
|
45
|
+
"written #{violation[:explanation]}")
|
46
|
+
end
|
47
|
+
|
48
|
+
CONVENTIONS = {
|
49
|
+
'hyphenated_lowercase' => {
|
50
|
+
explanation: 'in lowercase with hyphens',
|
51
|
+
validator: ->(name) { name !~ /[^\-a-z0-9]/ },
|
52
|
+
},
|
53
|
+
'snake_case' => {
|
54
|
+
explanation: 'in lowercase with underscores',
|
55
|
+
validator: ->(name) { name !~ /[^_a-z0-9]/ },
|
56
|
+
},
|
57
|
+
'camel_case' => {
|
58
|
+
explanation: 'has no spaces with capitalized words except first',
|
59
|
+
validator: ->(name) { name =~ /^[a-z][a-zA-Z0-9]*$/ },
|
60
|
+
},
|
61
|
+
'BEM' => {
|
62
|
+
explanation: 'in BEM (Block Element Modifier) format',
|
63
|
+
validator: ->(name) { name !~ /[A-Z]|-{3}|_{3}|[^_]_[^_]/ },
|
64
|
+
},
|
65
|
+
}
|
66
|
+
|
67
|
+
# Checks the given name and returns the violated convention if it failed.
|
68
|
+
def violated_convention(name_string)
|
69
|
+
convention_name = config['convention'] || 'hyphenated_lowercase'
|
70
|
+
|
71
|
+
convention = CONVENTIONS[convention_name] || {
|
72
|
+
explanation: "must match regex /#{convention_name}/",
|
73
|
+
validator: ->(name) { name =~ /#{convention_name}/ }
|
74
|
+
}
|
75
|
+
|
76
|
+
convention unless convention[:validator].call(name_string)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -38,6 +38,9 @@ module SCSSLint
|
|
38
38
|
add_lint line,
|
39
39
|
'Declaration should not have a space before ' \
|
40
40
|
'the terminating semicolon'
|
41
|
+
elsif ends_with_multiple_semicolons?(node)
|
42
|
+
line = node.source_range.start_pos.line
|
43
|
+
add_lint line, 'Declaration should be terminated by a single semicolon'
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
@@ -46,6 +49,11 @@ module SCSSLint
|
|
46
49
|
source_from_range(node.source_range) =~ /;$/
|
47
50
|
end
|
48
51
|
|
52
|
+
def ends_with_multiple_semicolons?(node)
|
53
|
+
# Look one character past the end to see if there's another semicolon
|
54
|
+
character_at(node.source_range.end_pos, 1) == ';'
|
55
|
+
end
|
56
|
+
|
49
57
|
def has_space_before_semicolon?(node)
|
50
58
|
source_from_range(node.source_range) =~ /\s;$/
|
51
59
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SCSSLint
|
2
|
+
# Checks for unnecessary leading zeros in numeric values with decimal points.
|
3
|
+
class Linter::TrailingZero < Linter
|
4
|
+
include LinterRegistry
|
5
|
+
|
6
|
+
def visit_script_string(node)
|
7
|
+
return unless node.type == :identifier
|
8
|
+
|
9
|
+
non_string_values = remove_quoted_strings(node.value).split
|
10
|
+
non_string_values.each do |value|
|
11
|
+
next unless number = value[FRACTIONAL_DIGIT_REGEX, 1]
|
12
|
+
check_number(node, number)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def visit_script_number(node)
|
17
|
+
return unless number =
|
18
|
+
source_from_range(node.source_range)[FRACTIONAL_DIGIT_REGEX, 1]
|
19
|
+
|
20
|
+
check_number(node, number)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
FRACTIONAL_DIGIT_REGEX = /^-?(\d*\.\d+)/
|
26
|
+
|
27
|
+
def check_number(node, original_number)
|
28
|
+
return unless match = /^(\d*\.\d*)0+$/.match(original_number)
|
29
|
+
|
30
|
+
fixed_number = match[1]
|
31
|
+
|
32
|
+
# Handle special case of 0 being the only trailing digit
|
33
|
+
fixed_number = fixed_number[0..-2] if fixed_number.end_with?('.')
|
34
|
+
fixed_number = 0 if fixed_number.empty? # Handle ".0" -> "0"
|
35
|
+
|
36
|
+
add_lint(node,
|
37
|
+
"`#{original_number}` should be written without a trailing " \
|
38
|
+
"zero as `#{fixed_number}`")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -12,6 +12,12 @@ module SCSSLint
|
|
12
12
|
def visit_sequence(sequence)
|
13
13
|
return unless sequence_starts_with_parent?(sequence.members.first)
|
14
14
|
|
15
|
+
# Allow concatentation, e.g.
|
16
|
+
# element {
|
17
|
+
# &.foo {}
|
18
|
+
# }
|
19
|
+
return if sequence.members.first.members.size > 1
|
20
|
+
|
15
21
|
# Allow sequences that contain multiple parent references, e.g.
|
16
22
|
# element {
|
17
23
|
# & + & { ... }
|
@@ -36,8 +42,7 @@ module SCSSLint
|
|
36
42
|
def sequence_starts_with_parent?(simple_sequence)
|
37
43
|
return unless simple_sequence.is_a?(Sass::Selector::SimpleSequence)
|
38
44
|
first = simple_sequence.members.first
|
39
|
-
|
40
|
-
first.is_a?(Sass::Selector::Parent) &&
|
45
|
+
first.is_a?(Sass::Selector::Parent) &&
|
41
46
|
first.suffix.nil? # Ignore concatenated selectors, like `&-something`
|
42
47
|
end
|
43
48
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module SCSSLint
|
4
|
+
# Reports lints in a JSON format.
|
5
|
+
class Reporter::JSONReporter < Reporter
|
6
|
+
def report_lints
|
7
|
+
output = {}
|
8
|
+
lints.group_by(&:filename).each do |filename, file_lints|
|
9
|
+
output[filename] = file_lints.map do |lint|
|
10
|
+
issue = {}
|
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
|
18
|
+
end
|
19
|
+
end
|
20
|
+
JSON.pretty_generate(output)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -15,7 +15,7 @@ module Sass::Script
|
|
15
15
|
{
|
16
16
|
'Value' => %w[ArgList Bool Color List Map Null Number String],
|
17
17
|
'Tree' => %w[Funcall Interpolation ListLiteral Literal MapLiteral
|
18
|
-
Operation StringInterpolation UnaryOperation Variable],
|
18
|
+
Operation Selector StringInterpolation UnaryOperation Variable],
|
19
19
|
}.each do |namespace, types|
|
20
20
|
types.each do |type|
|
21
21
|
node_name = type.downcase
|
data/lib/scss_lint/version.rb
CHANGED
@@ -204,6 +204,18 @@ describe SCSSLint::Linter::EmptyLineBetweenBlocks do
|
|
204
204
|
it { should_not report_lint }
|
205
205
|
end
|
206
206
|
|
207
|
+
context 'when a rule set is immediately followed by a comment' do
|
208
|
+
let(:css) { <<-CSS }
|
209
|
+
a {
|
210
|
+
} // A comment
|
211
|
+
|
212
|
+
a {
|
213
|
+
} /* Another comment */
|
214
|
+
CSS
|
215
|
+
|
216
|
+
it { should_not report_lint }
|
217
|
+
end
|
218
|
+
|
207
219
|
context 'when there are multiple placeholder rule sets' do
|
208
220
|
context 'with blank lines between them' do
|
209
221
|
let(:css) { <<-CSS }
|
@@ -185,6 +185,17 @@ describe SCSSLint::Linter::PropertySortOrder do
|
|
185
185
|
it { should report_lint line: 3 }
|
186
186
|
end
|
187
187
|
|
188
|
+
context 'when @media block contains properties not in sorted order' do
|
189
|
+
let(:css) { <<-CSS }
|
190
|
+
@media screen and (min-width: 500px) {
|
191
|
+
margin: 5px;
|
192
|
+
display: none;
|
193
|
+
}
|
194
|
+
CSS
|
195
|
+
|
196
|
+
it { should report_lint line: 2 }
|
197
|
+
end
|
198
|
+
|
188
199
|
context 'when if block contains properties in sorted order' do
|
189
200
|
let(:css) { <<-CSS }
|
190
201
|
@if $var {
|
@@ -0,0 +1,272 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SCSSLint::Linter::SelectorFormat do
|
4
|
+
context 'when class has alphanumeric chars and is separated by hyphens' do
|
5
|
+
let(:css) { <<-CSS }
|
6
|
+
.foo-bar-77 {
|
7
|
+
}
|
8
|
+
CSS
|
9
|
+
|
10
|
+
it { should_not report_lint }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when id has alphanumeric chars and is separated by hyphens' do
|
14
|
+
let(:css) { <<-CSS }
|
15
|
+
#foo-bar-77 {
|
16
|
+
}
|
17
|
+
CSS
|
18
|
+
|
19
|
+
it { should_not report_lint }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when element has alphanumeric chars and is separated by hyphens' do
|
23
|
+
let(:css) { <<-CSS }
|
24
|
+
foo-bar-77 {
|
25
|
+
}
|
26
|
+
CSS
|
27
|
+
|
28
|
+
it { should_not report_lint }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when placeholder has alphanumeric chars and is separated by hyphens' do
|
32
|
+
let(:css) { <<-CSS }
|
33
|
+
%foo-bar-77 {
|
34
|
+
}
|
35
|
+
CSS
|
36
|
+
|
37
|
+
it { should_not report_lint }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when pseudo-selector has alphanumeric chars and is separated by hyphens' do
|
41
|
+
let(:css) { <<-CSS }
|
42
|
+
[foo-bar-77=text] {
|
43
|
+
}
|
44
|
+
CSS
|
45
|
+
|
46
|
+
it { should_not report_lint }
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when selector has alphanumeric chars and is separated by underscores' do
|
50
|
+
let(:css) { <<-CSS }
|
51
|
+
.foo_bar {
|
52
|
+
}
|
53
|
+
CSS
|
54
|
+
|
55
|
+
it { should report_lint line: 1 }
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when selector has is in camelCase' do
|
59
|
+
let(:css) { <<-CSS }
|
60
|
+
fooBar77 {
|
61
|
+
}
|
62
|
+
CSS
|
63
|
+
|
64
|
+
it { should report_lint line: 1 }
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when placeholder has alphanumeric chars and is separated by underscores' do
|
68
|
+
let(:css) { <<-CSS }
|
69
|
+
%foo_bar {
|
70
|
+
}
|
71
|
+
CSS
|
72
|
+
|
73
|
+
it { should report_lint line: 1 }
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'psuedo-selector has alphanumeric chars and is separated by underscores' do
|
77
|
+
let(:css) { <<-CSS }
|
78
|
+
:foo_bar {
|
79
|
+
}
|
80
|
+
CSS
|
81
|
+
|
82
|
+
it { should report_lint line: 1 }
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when attribute has alphanumeric chars and is separated by underscores' do
|
86
|
+
let(:css) { <<-CSS }
|
87
|
+
[data_text] {
|
88
|
+
}
|
89
|
+
CSS
|
90
|
+
|
91
|
+
it { should report_lint line: 1 }
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when attribute selector has alphanumeric chars and is separated by underscores' do
|
95
|
+
let(:css) { <<-CSS }
|
96
|
+
[data-text=some_text] {
|
97
|
+
}
|
98
|
+
CSS
|
99
|
+
|
100
|
+
it { should_not report_lint }
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'when convention is set to snake_case' do
|
104
|
+
let(:linter_config) { { 'convention' => 'snake_case' } }
|
105
|
+
|
106
|
+
context 'when selector has alphanumeric chars and is separated by underscores' do
|
107
|
+
let(:css) { <<-CSS }
|
108
|
+
.foo_bar_77 {
|
109
|
+
}
|
110
|
+
CSS
|
111
|
+
|
112
|
+
it { should_not report_lint }
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when selector has alphanumeric chars and is separated by hyphens' do
|
116
|
+
let(:css) { <<-CSS }
|
117
|
+
.foo-bar-77 {
|
118
|
+
}
|
119
|
+
CSS
|
120
|
+
|
121
|
+
it { should report_lint line: 1 }
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when selector has is in camelCase' do
|
125
|
+
let(:css) { <<-CSS }
|
126
|
+
.fooBar77 {
|
127
|
+
}
|
128
|
+
CSS
|
129
|
+
|
130
|
+
it { should report_lint line: 1 }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'when convention is set to camel_case' do
|
135
|
+
let(:linter_config) { { 'convention' => 'camel_case' } }
|
136
|
+
|
137
|
+
context 'when selector has is in camelCase' do
|
138
|
+
let(:css) { <<-CSS }
|
139
|
+
.fooBar77 {
|
140
|
+
}
|
141
|
+
CSS
|
142
|
+
|
143
|
+
it { should_not report_lint }
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'when selector capitalizes first word' do
|
147
|
+
let(:css) { <<-CSS }
|
148
|
+
.FooBar77 {
|
149
|
+
}
|
150
|
+
CSS
|
151
|
+
|
152
|
+
it { should report_lint line: 1 }
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when selector has alphanumeric chars and is separated by underscores' do
|
156
|
+
let(:css) { <<-CSS }
|
157
|
+
.foo_bar_77 {
|
158
|
+
}
|
159
|
+
CSS
|
160
|
+
|
161
|
+
it { should report_lint line: 1 }
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'when selector has alphanumeric chars and is separated by hyphens' do
|
165
|
+
let(:css) { <<-CSS }
|
166
|
+
.foo-bar-77 {
|
167
|
+
}
|
168
|
+
CSS
|
169
|
+
|
170
|
+
it { should report_lint line: 1 }
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'when convention is set to use a regex' do
|
175
|
+
let(:linter_config) { { 'convention' => /^[0-9]*$/ } }
|
176
|
+
|
177
|
+
context 'when selector uses regex properly' do
|
178
|
+
let(:css) { <<-CSS }
|
179
|
+
.1337 {
|
180
|
+
}
|
181
|
+
CSS
|
182
|
+
|
183
|
+
it { should_not report_lint }
|
184
|
+
end
|
185
|
+
|
186
|
+
context 'when selector does not use regex properly' do
|
187
|
+
let(:css) { <<-CSS }
|
188
|
+
.leet {
|
189
|
+
}
|
190
|
+
CSS
|
191
|
+
|
192
|
+
it { should report_lint line: 1 }
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'when ignored names are set' do
|
197
|
+
let(:linter_config) { { 'ignored_names' => ['fooBar'] } }
|
198
|
+
|
199
|
+
context 'it ignores exact string matches' do
|
200
|
+
let(:css) { <<-CSS }
|
201
|
+
fooBar {
|
202
|
+
}
|
203
|
+
CSS
|
204
|
+
|
205
|
+
it { should_not report_lint }
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'when ignored types is set to class' do
|
210
|
+
let(:linter_config) { { 'ignored_types' => ['class'] } }
|
211
|
+
|
212
|
+
context 'it ignores all invalid classes' do
|
213
|
+
let(:css) { <<-CSS }
|
214
|
+
.fooBar {
|
215
|
+
}
|
216
|
+
CSS
|
217
|
+
|
218
|
+
it { should_not report_lint }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context 'when ignored types is set to id, element, placeholder, pseudo-selector' do
|
223
|
+
let(:linter_config) do
|
224
|
+
{ 'ignored_types' => %w[id attribute element placeholder pseudo-selector] }
|
225
|
+
end
|
226
|
+
|
227
|
+
context 'it ignores all invalid ids' do
|
228
|
+
let(:css) { <<-CSS }
|
229
|
+
#fooBar {
|
230
|
+
}
|
231
|
+
CSS
|
232
|
+
|
233
|
+
it { should_not report_lint }
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'it ignores all invalid elements' do
|
237
|
+
let(:css) { <<-CSS }
|
238
|
+
fooBar {
|
239
|
+
}
|
240
|
+
CSS
|
241
|
+
|
242
|
+
it { should_not report_lint }
|
243
|
+
end
|
244
|
+
|
245
|
+
context 'it ignores all invalid placeholders' do
|
246
|
+
let(:css) { <<-CSS }
|
247
|
+
%fooBar {
|
248
|
+
}
|
249
|
+
CSS
|
250
|
+
|
251
|
+
it { should_not report_lint }
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'it ignores all invalid attributes' do
|
255
|
+
let(:css) { <<-CSS }
|
256
|
+
[fooBar=fooBar] {
|
257
|
+
}
|
258
|
+
CSS
|
259
|
+
|
260
|
+
it { should_not report_lint }
|
261
|
+
end
|
262
|
+
|
263
|
+
context 'it ignores all invalid pseudo-selectors' do
|
264
|
+
let(:css) { <<-CSS }
|
265
|
+
:fooBar {
|
266
|
+
}
|
267
|
+
CSS
|
268
|
+
|
269
|
+
it { should_not report_lint }
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
@@ -225,4 +225,14 @@ describe SCSSLint::Linter::TrailingSemicolon do
|
|
225
225
|
|
226
226
|
it { should_not report_lint }
|
227
227
|
end
|
228
|
+
|
229
|
+
context 'when variable declaration ends with multiple semicolons' do
|
230
|
+
let(:css) { <<-CSS }
|
231
|
+
.foo {
|
232
|
+
$bar: 1;;
|
233
|
+
}
|
234
|
+
CSS
|
235
|
+
|
236
|
+
it { should report_lint line: 2 }
|
237
|
+
end
|
228
238
|
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SCSSLint::Linter::TrailingZero do
|
4
|
+
context 'when no values exist' do
|
5
|
+
let(:css) { 'p {}' }
|
6
|
+
|
7
|
+
it { should_not report_lint }
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'when a zero exists' do
|
11
|
+
let(:css) { <<-CSS }
|
12
|
+
p {
|
13
|
+
margin: 0;
|
14
|
+
}
|
15
|
+
CSS
|
16
|
+
|
17
|
+
it { should_not report_lint }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when an integer value exists' do
|
21
|
+
let(:css) { <<-CSS }
|
22
|
+
p {
|
23
|
+
line-height: 2;
|
24
|
+
}
|
25
|
+
CSS
|
26
|
+
|
27
|
+
it { should_not report_lint }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when an integer value with units exists' do
|
31
|
+
let(:css) { <<-CSS }
|
32
|
+
p {
|
33
|
+
margin: 5px;
|
34
|
+
}
|
35
|
+
CSS
|
36
|
+
|
37
|
+
it { should_not report_lint }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when a unitless fractional value with no trailing zero exists' do
|
41
|
+
let(:css) { <<-CSS }
|
42
|
+
p {
|
43
|
+
line-height: .5;
|
44
|
+
}
|
45
|
+
CSS
|
46
|
+
|
47
|
+
it { should_not report_lint }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when a negative unitless fractional value with no trailing zero exists' do
|
51
|
+
let(:css) { <<-CSS }
|
52
|
+
p {
|
53
|
+
line-height: -.5;
|
54
|
+
}
|
55
|
+
CSS
|
56
|
+
|
57
|
+
it { should_not report_lint }
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when a fractional value with units and no trailing zero exists' do
|
61
|
+
let(:css) { <<-CSS }
|
62
|
+
p {
|
63
|
+
margin: .5em;
|
64
|
+
}
|
65
|
+
CSS
|
66
|
+
|
67
|
+
it { should_not report_lint }
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when a negative fractional value with units and no trailing zero exists' do
|
71
|
+
let(:css) { <<-CSS }
|
72
|
+
p {
|
73
|
+
margin: -.5em;
|
74
|
+
}
|
75
|
+
CSS
|
76
|
+
|
77
|
+
it { should_not report_lint }
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when a fractional value with a trailing zero exists' do
|
81
|
+
let(:css) { <<-CSS }
|
82
|
+
p {
|
83
|
+
line-height: .50;
|
84
|
+
}
|
85
|
+
CSS
|
86
|
+
|
87
|
+
it { should report_lint line: 2 }
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when a fractional value with units and a trailing zero exists' do
|
91
|
+
let(:css) { <<-CSS }
|
92
|
+
p {
|
93
|
+
margin: .50em;
|
94
|
+
}
|
95
|
+
CSS
|
96
|
+
|
97
|
+
it { should report_lint line: 2 }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when a negative fractional value with units and a trailing zero exists' do
|
101
|
+
let(:css) { <<-CSS }
|
102
|
+
p {
|
103
|
+
margin: -.50em;
|
104
|
+
}
|
105
|
+
CSS
|
106
|
+
|
107
|
+
it { should report_lint line: 2 }
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'when a fractional value with a mantissa ending in zero exists' do
|
111
|
+
let(:css) { <<-CSS }
|
112
|
+
p {
|
113
|
+
line-height: 10.5;
|
114
|
+
}
|
115
|
+
CSS
|
116
|
+
|
117
|
+
it { should_not report_lint }
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'when multiple fractional values with trailing zeros exist' do
|
121
|
+
let(:css) { <<-CSS }
|
122
|
+
p {
|
123
|
+
margin: 0.50em .50 0.10px .90pt;
|
124
|
+
}
|
125
|
+
CSS
|
126
|
+
|
127
|
+
it { should report_lint count: 4, line: 2 }
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'when trailing zeros appear in function arguments' do
|
131
|
+
let(:css) { <<-CSS }
|
132
|
+
p {
|
133
|
+
margin: some-function(.50em, 0.40 0.30 .2);
|
134
|
+
}
|
135
|
+
CSS
|
136
|
+
|
137
|
+
it { should report_lint count: 3, line: 2 }
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when trailing zeros appear in mixin arguments' do
|
141
|
+
let(:css) { <<-CSS }
|
142
|
+
p {
|
143
|
+
@include some-mixin(0.50em, 0.40 0.30 .2);
|
144
|
+
}
|
145
|
+
CSS
|
146
|
+
|
147
|
+
it { should report_lint count: 3, line: 2 }
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'when trailiing zeros appear in variable declarations' do
|
151
|
+
let(:css) { '$some-var: .50em;' }
|
152
|
+
|
153
|
+
it { should report_lint line: 1 }
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'when trailing zeros appear in named arguments' do
|
157
|
+
let(:css) { <<-CSS }
|
158
|
+
p {
|
159
|
+
@include line-clamp($line-height: .90, $line-count: 2);
|
160
|
+
}
|
161
|
+
CSS
|
162
|
+
|
163
|
+
it { should report_lint line: 2 }
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'when trailing zeros appear in parameter defaults' do
|
167
|
+
let(:css) { <<-CSS }
|
168
|
+
@mixin my-mixin($bad-value: .50, $good-value: .9, $string-value: ".90") {
|
169
|
+
margin: $some-value;
|
170
|
+
padding: $some-other-value;
|
171
|
+
}
|
172
|
+
CSS
|
173
|
+
|
174
|
+
it { should report_lint count: 1, line: 1 }
|
175
|
+
end
|
176
|
+
end
|
@@ -52,6 +52,16 @@ describe SCSSLint::Linter::UnnecessaryParentReference do
|
|
52
52
|
it { should_not report_lint }
|
53
53
|
end
|
54
54
|
|
55
|
+
context 'when multiple ampersands exist with one concatenated' do
|
56
|
+
let(:css) { <<-CSS }
|
57
|
+
p {
|
58
|
+
& + &:hover {}
|
59
|
+
}
|
60
|
+
CSS
|
61
|
+
|
62
|
+
it { should_not report_lint }
|
63
|
+
end
|
64
|
+
|
55
65
|
context 'when an amperand is used in a comma sequence to DRY up code' do
|
56
66
|
let(:css) { <<-CSS }
|
57
67
|
p {
|
@@ -60,4 +60,14 @@ describe SCSSLint::Linter::UrlQuotes do
|
|
60
60
|
|
61
61
|
it { should_not report_lint }
|
62
62
|
end
|
63
|
+
|
64
|
+
context 'when property has a data URI' do
|
65
|
+
let(:css) { <<-CSS }
|
66
|
+
.tracking-pixel {
|
67
|
+
background: url(data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==);
|
68
|
+
}
|
69
|
+
CSS
|
70
|
+
|
71
|
+
it { should_not report_lint }
|
72
|
+
end
|
63
73
|
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SCSSLint::Reporter::JSONReporter do
|
4
|
+
subject { SCSSLint::Reporter::JSONReporter.new(lints) }
|
5
|
+
|
6
|
+
describe '#report_lints' do
|
7
|
+
let(:json) { JSON.parse(subject.report_lints) }
|
8
|
+
|
9
|
+
shared_examples_for 'parsed JSON' do
|
10
|
+
it 'is a Hash' do
|
11
|
+
json.is_a?(Hash)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when there are no lints' do
|
16
|
+
let(:lints) { [] }
|
17
|
+
|
18
|
+
it_should_behave_like 'parsed JSON'
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when there are lints' do
|
22
|
+
let(:filenames) { ['f1.scss', 'f2.scss', 'f1.scss'] }
|
23
|
+
# Include invalid XML characters in the third description to validate
|
24
|
+
# that escaping happens for preventing broken XML output
|
25
|
+
let(:descriptions) { ['lint 1', 'lint 2', 'lint 3 " \' < & >'] }
|
26
|
+
let(:severities) { [:warning] * 3 }
|
27
|
+
|
28
|
+
let(:locations) do
|
29
|
+
[
|
30
|
+
SCSSLint::Location.new(5, 2, 3),
|
31
|
+
SCSSLint::Location.new(7, 6, 2),
|
32
|
+
SCSSLint::Location.new(9, 10, 1)
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:lints) do
|
37
|
+
filenames.each_with_index.map do |filename, index|
|
38
|
+
SCSSLint::Lint.new(nil, filename, locations[index],
|
39
|
+
descriptions[index], severities[index])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it_should_behave_like 'parsed JSON'
|
44
|
+
|
45
|
+
it 'contains an <issue> node for each lint' do
|
46
|
+
json.values.inject(0) { |sum, issues| sum + issues.size }.should == 3
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'contains a group of issues for each file' do
|
50
|
+
json.keys.should == filenames.uniq
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'contains <issue> nodes grouped by <file>' do
|
54
|
+
json.values.map(&:size).should == [2, 1]
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'marks each issue with a line number' do
|
58
|
+
json.values.flat_map { |issues| issues.map { |issue| issue['line'] } }
|
59
|
+
.should =~ locations.map(&:line)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'marks each issue with a column number' do
|
63
|
+
json.values.flat_map { |issues| issues.map { |issue| issue['column'] } }
|
64
|
+
.should =~ locations.map(&:column)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'marks each issue with a length' do
|
68
|
+
json.values.flat_map { |issues| issues.map { |issue| issue['length'] } }
|
69
|
+
.should =~ locations.map(&:length)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'marks each issue with a reason containing the lint description' do
|
73
|
+
json.values.flat_map { |issues| issues.map { |issue| issue['reason'] } }
|
74
|
+
.should =~ descriptions
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when lints are warnings' do
|
78
|
+
it 'marks each issue with a severity of "warning"' do
|
79
|
+
json.values.inject(0) do |sum, issues|
|
80
|
+
sum + issues.select { |i| i['severity'] == 'warning' }.size
|
81
|
+
end.should == 3
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when lints are errors' do
|
86
|
+
let(:severities) { [:error] * 3 }
|
87
|
+
|
88
|
+
it 'marks each issue with a severity of "error"' do
|
89
|
+
json.values.inject(0) do |sum, issues|
|
90
|
+
sum + issues.select { |i| i['severity'] == 'error' }.size
|
91
|
+
end.should == 3
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
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.
|
4
|
+
version: 0.29.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Causes Engineering
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-10-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rainbow
|
@@ -73,14 +73,14 @@ dependencies:
|
|
73
73
|
requirements:
|
74
74
|
- - '='
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: 0.
|
76
|
+
version: 0.26.0
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
81
|
- - '='
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: 0.
|
83
|
+
version: 0.26.0
|
84
84
|
description: Configurable tool for writing clean and consistent SCSS
|
85
85
|
email:
|
86
86
|
- eng@causes.com
|
@@ -100,6 +100,7 @@ files:
|
|
100
100
|
- lib/scss_lint/reporter/files_reporter.rb
|
101
101
|
- lib/scss_lint/reporter/xml_reporter.rb
|
102
102
|
- lib/scss_lint/reporter/default_reporter.rb
|
103
|
+
- lib/scss_lint/reporter/json_reporter.rb
|
103
104
|
- lib/scss_lint/reporter/config_reporter.rb
|
104
105
|
- lib/scss_lint/runner.rb
|
105
106
|
- lib/scss_lint/reporter.rb
|
@@ -113,8 +114,8 @@ files:
|
|
113
114
|
- lib/scss_lint/config.rb
|
114
115
|
- lib/scss_lint/linter/compass.rb
|
115
116
|
- lib/scss_lint/linter/space_after_comma.rb
|
117
|
+
- lib/scss_lint/linter/trailing_zero.rb
|
116
118
|
- lib/scss_lint/linter/space_before_brace.rb
|
117
|
-
- lib/scss_lint/linter/capitalization_in_selector.rb
|
118
119
|
- lib/scss_lint/linter/hex_length.rb
|
119
120
|
- lib/scss_lint/linter/indentation.rb
|
120
121
|
- lib/scss_lint/linter/mergeable_selector.rb
|
@@ -128,6 +129,7 @@ files:
|
|
128
129
|
- lib/scss_lint/linter/placeholder_in_extend.rb
|
129
130
|
- lib/scss_lint/linter/selector_depth.rb
|
130
131
|
- lib/scss_lint/linter/else_placement.rb
|
132
|
+
- lib/scss_lint/linter/selector_format.rb
|
131
133
|
- lib/scss_lint/linter/hex_validation.rb
|
132
134
|
- lib/scss_lint/linter/compass/property_with_mixin.rb
|
133
135
|
- lib/scss_lint/linter/space_after_property_name.rb
|
@@ -157,6 +159,7 @@ files:
|
|
157
159
|
- lib/scss_lint.rb
|
158
160
|
- spec/scss_lint/location_spec.rb
|
159
161
|
- spec/scss_lint/reporter/files_reporter_spec.rb
|
162
|
+
- spec/scss_lint/reporter/json_reporter_spec.rb
|
160
163
|
- spec/scss_lint/reporter/xml_reporter_spec.rb
|
161
164
|
- spec/scss_lint/reporter/config_reporter_spec.rb
|
162
165
|
- spec/scss_lint/reporter/default_reporter_spec.rb
|
@@ -175,6 +178,7 @@ files:
|
|
175
178
|
- spec/scss_lint/linter/hex_length_spec.rb
|
176
179
|
- spec/scss_lint/linter/url_quotes_spec.rb
|
177
180
|
- spec/scss_lint/linter/space_between_parens_spec.rb
|
181
|
+
- spec/scss_lint/linter/selector_format_spec.rb
|
178
182
|
- spec/scss_lint/linter/border_zero_spec.rb
|
179
183
|
- spec/scss_lint/linter/property_spelling_spec.rb
|
180
184
|
- spec/scss_lint/linter/property_sort_order_spec.rb
|
@@ -183,7 +187,6 @@ files:
|
|
183
187
|
- spec/scss_lint/linter/mergeable_selector_spec.rb
|
184
188
|
- spec/scss_lint/linter/unnecessary_mantissa_spec.rb
|
185
189
|
- spec/scss_lint/linter/name_format_spec.rb
|
186
|
-
- spec/scss_lint/linter/capitalization_in_selector_spec.rb
|
187
190
|
- spec/scss_lint/linter/duplicate_property_spec.rb
|
188
191
|
- spec/scss_lint/linter/hex_validation_spec.rb
|
189
192
|
- spec/scss_lint/linter/space_before_brace_spec.rb
|
@@ -198,6 +201,7 @@ files:
|
|
198
201
|
- spec/scss_lint/linter/space_after_property_colon_spec.rb
|
199
202
|
- spec/scss_lint/linter/declaration_order_spec.rb
|
200
203
|
- spec/scss_lint/linter/leading_zero_spec.rb
|
204
|
+
- spec/scss_lint/linter/trailing_zero_spec.rb
|
201
205
|
- spec/scss_lint/linter/url_format_spec.rb
|
202
206
|
- spec/scss_lint/linter/comment_spec.rb
|
203
207
|
- spec/scss_lint/linter/trailing_semicolon_spec.rb
|
@@ -237,6 +241,7 @@ summary: SCSS lint tool
|
|
237
241
|
test_files:
|
238
242
|
- spec/scss_lint/location_spec.rb
|
239
243
|
- spec/scss_lint/reporter/files_reporter_spec.rb
|
244
|
+
- spec/scss_lint/reporter/json_reporter_spec.rb
|
240
245
|
- spec/scss_lint/reporter/xml_reporter_spec.rb
|
241
246
|
- spec/scss_lint/reporter/config_reporter_spec.rb
|
242
247
|
- spec/scss_lint/reporter/default_reporter_spec.rb
|
@@ -255,6 +260,7 @@ test_files:
|
|
255
260
|
- spec/scss_lint/linter/hex_length_spec.rb
|
256
261
|
- spec/scss_lint/linter/url_quotes_spec.rb
|
257
262
|
- spec/scss_lint/linter/space_between_parens_spec.rb
|
263
|
+
- spec/scss_lint/linter/selector_format_spec.rb
|
258
264
|
- spec/scss_lint/linter/border_zero_spec.rb
|
259
265
|
- spec/scss_lint/linter/property_spelling_spec.rb
|
260
266
|
- spec/scss_lint/linter/property_sort_order_spec.rb
|
@@ -263,7 +269,6 @@ test_files:
|
|
263
269
|
- spec/scss_lint/linter/mergeable_selector_spec.rb
|
264
270
|
- spec/scss_lint/linter/unnecessary_mantissa_spec.rb
|
265
271
|
- spec/scss_lint/linter/name_format_spec.rb
|
266
|
-
- spec/scss_lint/linter/capitalization_in_selector_spec.rb
|
267
272
|
- spec/scss_lint/linter/duplicate_property_spec.rb
|
268
273
|
- spec/scss_lint/linter/hex_validation_spec.rb
|
269
274
|
- spec/scss_lint/linter/space_before_brace_spec.rb
|
@@ -278,6 +283,7 @@ test_files:
|
|
278
283
|
- spec/scss_lint/linter/space_after_property_colon_spec.rb
|
279
284
|
- spec/scss_lint/linter/declaration_order_spec.rb
|
280
285
|
- spec/scss_lint/linter/leading_zero_spec.rb
|
286
|
+
- spec/scss_lint/linter/trailing_zero_spec.rb
|
281
287
|
- spec/scss_lint/linter/url_format_spec.rb
|
282
288
|
- spec/scss_lint/linter/comment_spec.rb
|
283
289
|
- spec/scss_lint/linter/trailing_semicolon_spec.rb
|
@@ -1,49 +0,0 @@
|
|
1
|
-
module SCSSLint
|
2
|
-
# Checks for capitalized letters in IDs, classes, types, etc. in selectors.
|
3
|
-
class Linter::CapitalizationInSelector < Linter
|
4
|
-
include LinterRegistry
|
5
|
-
|
6
|
-
def visit_root(_node)
|
7
|
-
@ignored_names = Array(config['ignored_names']).to_set
|
8
|
-
@ignored_types = Array(config['ignored_types']).to_set
|
9
|
-
yield
|
10
|
-
end
|
11
|
-
|
12
|
-
def visit_attribute(attribute)
|
13
|
-
check(attribute) unless @ignored_types.include?('attribute')
|
14
|
-
end
|
15
|
-
|
16
|
-
def visit_class(klass)
|
17
|
-
check(klass) unless @ignored_types.include?('class')
|
18
|
-
end
|
19
|
-
|
20
|
-
def visit_element(element)
|
21
|
-
check(element) unless @ignored_types.include?('element')
|
22
|
-
end
|
23
|
-
|
24
|
-
def visit_id(id)
|
25
|
-
check(id) unless @ignored_types.include?('id')
|
26
|
-
end
|
27
|
-
|
28
|
-
def visit_placeholder(placeholder)
|
29
|
-
check(placeholder) unless @ignored_types.include?('placeholder')
|
30
|
-
end
|
31
|
-
|
32
|
-
def visit_pseudo(pseudo)
|
33
|
-
check(pseudo, 'Pseudo-selector') unless @ignored_types.include?('pseudo-selector')
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def check(node, selector_name = nil)
|
39
|
-
name = node.name
|
40
|
-
|
41
|
-
return if @ignored_names.include?(name)
|
42
|
-
return unless name =~ /[A-Z]/
|
43
|
-
|
44
|
-
selector_name ||= node.class.name.split('::').last
|
45
|
-
add_lint(node, "#{selector_name} `#{name}` in selector should be " \
|
46
|
-
"written in all lowercase as `#{name.downcase}`")
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe SCSSLint::Linter::CapitalizationInSelector do
|
4
|
-
context 'when selector is all lowercase' do
|
5
|
-
let(:css) { <<-CSS }
|
6
|
-
span {
|
7
|
-
}
|
8
|
-
CSS
|
9
|
-
|
10
|
-
it { should_not report_lint }
|
11
|
-
end
|
12
|
-
|
13
|
-
context 'when selector is lowercase with non-alphabetic characters' do
|
14
|
-
let(:css) { <<-CSS }
|
15
|
-
.foo-bar {
|
16
|
-
}
|
17
|
-
CSS
|
18
|
-
|
19
|
-
it { should_not report_lint }
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'when selector is camelCase' do
|
23
|
-
let(:css) { <<-CSS }
|
24
|
-
.fooBar {
|
25
|
-
}
|
26
|
-
CSS
|
27
|
-
|
28
|
-
it { should report_lint line: 1 }
|
29
|
-
end
|
30
|
-
|
31
|
-
context 'when selector is UPPER CASE' do
|
32
|
-
let(:css) { <<-CSS }
|
33
|
-
SPAN {
|
34
|
-
}
|
35
|
-
CSS
|
36
|
-
|
37
|
-
it { should report_lint line: 1 }
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'when attribute selector has attribute containing uppercase letters' do
|
41
|
-
let(:css) { <<-CSS }
|
42
|
-
[dataText] {
|
43
|
-
}
|
44
|
-
CSS
|
45
|
-
|
46
|
-
it { should report_lint line: 1 }
|
47
|
-
end
|
48
|
-
|
49
|
-
context 'when attribute selector has value containing uppercase letters' do
|
50
|
-
let(:css) { <<-CSS }
|
51
|
-
[data-text=someText] {
|
52
|
-
}
|
53
|
-
CSS
|
54
|
-
|
55
|
-
it { should_not report_lint }
|
56
|
-
end
|
57
|
-
|
58
|
-
context 'when a selector name is whitelisted' do
|
59
|
-
let(:linter_config) { { 'ignored_names' => %w[Foo] } }
|
60
|
-
let(:css) { '.Foo {}' }
|
61
|
-
|
62
|
-
it { should_not report_lint }
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'when a certain type of selector is ignored' do
|
66
|
-
let(:linter_config) { { 'ignored_types' => %w[class] } }
|
67
|
-
let(:css) { '.Foo {}' }
|
68
|
-
|
69
|
-
it { should_not report_lint }
|
70
|
-
end
|
71
|
-
end
|