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 +4 -4
- data/config/default.yml +1 -1
- data/data/property-sort-orders/smacss.txt +2 -0
- data/lib/scss_lint/linter/debug_statement.rb +1 -1
- data/lib/scss_lint/linter/else_placement.rb +2 -2
- data/lib/scss_lint/linter/extend_directive.rb +1 -1
- data/lib/scss_lint/linter/length_variable.rb +107 -0
- data/lib/scss_lint/linter/name_format.rb +27 -9
- data/lib/scss_lint/linter/property_sort_order.rb +4 -4
- data/lib/scss_lint/linter/shorthand.rb +3 -0
- data/lib/scss_lint/linter/space_around_operator.rb +1 -2
- data/lib/scss_lint/linter/trailing_zero.rb +1 -1
- data/lib/scss_lint/reporter/default_reporter.rb +5 -1
- data/lib/scss_lint/version.rb +1 -1
- data/spec/scss_lint/linter/indentation_spec.rb +2 -1
- data/spec/scss_lint/linter/length_variable_spec.rb +388 -0
- data/spec/scss_lint/linter/property_sort_order_spec.rb +27 -0
- data/spec/scss_lint/linter/shorthand_spec.rb +11 -0
- data/spec/scss_lint/linter/trailing_zero_spec.rb +10 -0
- data/spec/scss_lint/reporter/default_reporter_spec.rb +11 -4
- data/spec/scss_lint/reporter/stats_reporter_spec.rb +3 -3
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 881e2595ce6e859e53e9148db36e2f3d11bcb429
|
4
|
+
data.tar.gz: e28e168aa7ec435017b415278fe3fc68c8b911ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f27ed9d01d9a7920c3d88d0d9345b8ba107978fd536d90618d406af9cc8209221cc220054d1f118320af98927fce38b91144c4af1c4686d2a09b7dda2394aaaa
|
7
|
+
data.tar.gz: c6cfb9ba3bf3a0957cbd756b7e0cf9b4702432a94275214b97c98fd2884e63bc225adaec713148d41fae2b0078e070ed6e77ded6d3c4c4139b0cb8e4aaa0b3ec
|
data/config/default.yml
CHANGED
@@ -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
|
-
'
|
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, '
|
42
|
+
add_lint(else_node, '`@else` should be placed on its own line')
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -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
|
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
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
109
|
-
'
|
110
|
-
"properties ending with
|
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 =~
|
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
|
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
|
-
|
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)
|
data/lib/scss_lint/version.rb
CHANGED
@@ -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
|
-
{
|
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(:
|
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
|
-
|
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
|
-
|
45
|
-
subject.report_lints.scan(
|
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
|
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
|
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
|
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.
|
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-
|
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.
|
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.
|
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.
|
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:
|