scss-lint 0.29.0 → 0.30.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 +31 -1
- data/data/prefixed-identifiers/base.txt +107 -0
- data/data/prefixed-identifiers/bourbon.txt +71 -0
- data/lib/scss_lint/cli.rb +34 -7
- data/lib/scss_lint/config.rb +12 -1
- data/lib/scss_lint/engine.rb +3 -1
- data/lib/scss_lint/linter/bang_format.rb +40 -0
- data/lib/scss_lint/linter/declaration_order.rb +35 -14
- data/lib/scss_lint/linter/import_path.rb +62 -0
- data/lib/scss_lint/linter/name_format.rb +1 -1
- data/lib/scss_lint/linter/nesting_depth.rb +24 -0
- data/lib/scss_lint/linter/property_sort_order.rb +4 -11
- data/lib/scss_lint/linter/property_spelling.rb +25 -8
- data/lib/scss_lint/linter/qualifying_element.rb +42 -0
- data/lib/scss_lint/linter/selector_format.rb +23 -11
- data/lib/scss_lint/linter/space_after_property_colon.rb +4 -4
- data/lib/scss_lint/linter/space_after_property_name.rb +16 -1
- data/lib/scss_lint/linter/space_before_brace.rb +36 -9
- data/lib/scss_lint/linter/trailing_semicolon.rb +6 -2
- data/lib/scss_lint/linter/vendor_prefixes.rb +64 -0
- data/lib/scss_lint/rake_task.rb +1 -0
- data/lib/scss_lint/runner.rb +2 -1
- data/lib/scss_lint/sass/script.rb +10 -0
- data/lib/scss_lint/version.rb +1 -1
- data/spec/scss_lint/cli_spec.rb +45 -2
- data/spec/scss_lint/linter/bang_format_spec.rb +79 -0
- data/spec/scss_lint/linter/declaration_order_spec.rb +466 -0
- data/spec/scss_lint/linter/import_path_spec.rb +300 -0
- data/spec/scss_lint/linter/nesting_depth_spec.rb +114 -0
- data/spec/scss_lint/linter/property_spelling_spec.rb +27 -0
- data/spec/scss_lint/linter/qualifying_element_spec.rb +125 -0
- data/spec/scss_lint/linter/selector_format_spec.rb +329 -0
- data/spec/scss_lint/linter/space_after_property_colon_spec.rb +14 -0
- data/spec/scss_lint/linter/space_after_property_name_spec.rb +14 -0
- data/spec/scss_lint/linter/space_before_brace_spec.rb +401 -17
- data/spec/scss_lint/linter/trailing_semicolon_spec.rb +47 -0
- data/spec/scss_lint/linter/vendor_prefixes_spec.rb +350 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63daef837600174964f65634095dac45b13a1bb2
|
4
|
+
data.tar.gz: 8b8e1fdebc6d40d577c02a0092c092212f0d46ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ed4cbb25cacdfdf0645ea476ccc86032ae8032c22fdb1b3cf8fdd6934601bdc075aa4ed71fa1a05d2dec08785ceb591d53eeb2c6541b5567f434ff4ce161d20
|
7
|
+
data.tar.gz: 07a85bc0d214819857e179babe4b465193adf01391f7eecadd25611264c28605e0990911e1eb6dd75ed79b65b0cb50b6529187513e6842674e5c5abeafeca5f2
|
data/config/default.yml
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Default application configuration that all configurations inherit from.
|
2
|
+
|
3
|
+
scss_files: "**/*.scss"
|
4
|
+
|
2
5
|
linters:
|
6
|
+
BangFormat:
|
7
|
+
enabled: true
|
8
|
+
space_before_bang: true
|
9
|
+
space_after_bang: false
|
10
|
+
|
3
11
|
BorderZero:
|
4
12
|
enabled: true
|
5
13
|
|
@@ -47,6 +55,11 @@ linters:
|
|
47
55
|
IdWithExtraneousSelector:
|
48
56
|
enabled: true
|
49
57
|
|
58
|
+
ImportPath:
|
59
|
+
enabled: true
|
60
|
+
leading_underscore: false
|
61
|
+
filename_extension: false
|
62
|
+
|
50
63
|
Indentation:
|
51
64
|
enabled: true
|
52
65
|
character: space # or 'tab'
|
@@ -64,6 +77,10 @@ linters:
|
|
64
77
|
enabled: true
|
65
78
|
convention: hyphenated_lowercase # or 'BEM', or a regex pattern
|
66
79
|
|
80
|
+
NestingDepth:
|
81
|
+
enabled: true
|
82
|
+
max_depth: 3
|
83
|
+
|
67
84
|
PlaceholderInExtend:
|
68
85
|
enabled: true
|
69
86
|
|
@@ -75,13 +92,19 @@ linters:
|
|
75
92
|
enabled: true
|
76
93
|
extra_properties: []
|
77
94
|
|
95
|
+
QualifyingElement:
|
96
|
+
enabled: true
|
97
|
+
allow_with_attribute: false
|
98
|
+
allow_with_class: false
|
99
|
+
allow_with_id: false
|
100
|
+
|
78
101
|
SelectorDepth:
|
79
102
|
enabled: true
|
80
103
|
max_depth: 3
|
81
104
|
|
82
105
|
SelectorFormat:
|
83
106
|
enabled: true
|
84
|
-
convention: hyphenated_lowercase # or 'snake_case', or 'camel_case', or a regex pattern
|
107
|
+
convention: hyphenated_lowercase # or 'BEM', or 'snake_case', or 'camel_case', or a regex pattern
|
85
108
|
|
86
109
|
Shorthand:
|
87
110
|
enabled: true
|
@@ -105,6 +128,7 @@ linters:
|
|
105
128
|
|
106
129
|
SpaceBeforeBrace:
|
107
130
|
enabled: true
|
131
|
+
style: space
|
108
132
|
allow_single_line_padding: false
|
109
133
|
|
110
134
|
SpaceBetweenParens:
|
@@ -133,6 +157,12 @@ linters:
|
|
133
157
|
UrlQuotes:
|
134
158
|
enabled: true
|
135
159
|
|
160
|
+
VendorPrefixes:
|
161
|
+
enabled: true
|
162
|
+
identifier_list: base
|
163
|
+
include: []
|
164
|
+
exclude: []
|
165
|
+
|
136
166
|
ZeroUnit:
|
137
167
|
enabled: true
|
138
168
|
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# Based on Autoprefixer --info
|
2
|
+
|
3
|
+
# At-Rules
|
4
|
+
keyframes
|
5
|
+
|
6
|
+
# Selectors
|
7
|
+
selection
|
8
|
+
placeholder
|
9
|
+
fullscreen
|
10
|
+
|
11
|
+
# Properties
|
12
|
+
transition
|
13
|
+
transition-property
|
14
|
+
border-radius
|
15
|
+
border-top-left-radius
|
16
|
+
border-top-right-radius
|
17
|
+
border-bottom-right-radius
|
18
|
+
border-bottom-left-radius
|
19
|
+
box-shadow
|
20
|
+
animation
|
21
|
+
animation-name
|
22
|
+
animation-duration
|
23
|
+
animation-delay
|
24
|
+
animation-direction
|
25
|
+
animation-fill-mode
|
26
|
+
animation-iteration-count
|
27
|
+
animation-play-state
|
28
|
+
animation-timing-function
|
29
|
+
transition-duration
|
30
|
+
transition-delay
|
31
|
+
transition-timing-function
|
32
|
+
transform
|
33
|
+
transform-origin
|
34
|
+
perspective
|
35
|
+
perspective-origin
|
36
|
+
transform-style
|
37
|
+
backface-visibility
|
38
|
+
border-image
|
39
|
+
box-sizing
|
40
|
+
filter
|
41
|
+
columns
|
42
|
+
column-width
|
43
|
+
column-gap
|
44
|
+
column-rule
|
45
|
+
column-rule-color
|
46
|
+
column-rule-width
|
47
|
+
column-count
|
48
|
+
column-rule-style
|
49
|
+
column-span
|
50
|
+
column-fill
|
51
|
+
break-before
|
52
|
+
break-after
|
53
|
+
break-inside
|
54
|
+
user-select
|
55
|
+
flex
|
56
|
+
flex-grow
|
57
|
+
flex-shrink
|
58
|
+
flex-basis
|
59
|
+
flex-direction
|
60
|
+
flex-wrap
|
61
|
+
flex-flow
|
62
|
+
justify-content
|
63
|
+
order
|
64
|
+
align-items
|
65
|
+
align-self
|
66
|
+
align-content
|
67
|
+
background-clip
|
68
|
+
background-origin
|
69
|
+
background-size
|
70
|
+
font-feature-settings
|
71
|
+
font-variant-ligatures
|
72
|
+
font-language-override
|
73
|
+
font-kerning
|
74
|
+
hyphens
|
75
|
+
tab-size
|
76
|
+
touch-action
|
77
|
+
text-decoration-style
|
78
|
+
text-decoration-line
|
79
|
+
text-decoration-color
|
80
|
+
text-size-adjust
|
81
|
+
clip-path
|
82
|
+
mask
|
83
|
+
mask-clip
|
84
|
+
mask-composite
|
85
|
+
mask-image
|
86
|
+
mask-origin
|
87
|
+
mask-position
|
88
|
+
mask-repeat
|
89
|
+
mask-size
|
90
|
+
|
91
|
+
# Values
|
92
|
+
linear-gradient
|
93
|
+
repeating-linear-gradient
|
94
|
+
radial-gradient
|
95
|
+
repeating-radial-gradient
|
96
|
+
flex
|
97
|
+
inline-flex
|
98
|
+
calc
|
99
|
+
max-content
|
100
|
+
min-content
|
101
|
+
fit-content
|
102
|
+
fill-available
|
103
|
+
zoom-in
|
104
|
+
zoom-out
|
105
|
+
grab
|
106
|
+
grabbing
|
107
|
+
sticky
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Identifiers covered by Bourbon mixins
|
2
|
+
|
3
|
+
# At-Rules
|
4
|
+
keyframes
|
5
|
+
|
6
|
+
# Selectors
|
7
|
+
placeholder
|
8
|
+
|
9
|
+
# Properties
|
10
|
+
animation
|
11
|
+
animation-delay
|
12
|
+
animation-direction
|
13
|
+
animation-duration
|
14
|
+
animation-fill-mode
|
15
|
+
animation-iteration-count
|
16
|
+
animation-name
|
17
|
+
animation-play-state
|
18
|
+
animation-timing-function
|
19
|
+
appearance
|
20
|
+
backface-visibility
|
21
|
+
background
|
22
|
+
border-image
|
23
|
+
border-top-left-radius
|
24
|
+
border-top-right-radius
|
25
|
+
border-bottom-right-radius
|
26
|
+
border-bottom-left-radius
|
27
|
+
box-sizing
|
28
|
+
calc
|
29
|
+
columns
|
30
|
+
column-width
|
31
|
+
column-gap
|
32
|
+
column-rule
|
33
|
+
column-rule-color
|
34
|
+
column-rule-width
|
35
|
+
column-count
|
36
|
+
column-rule-style
|
37
|
+
column-span
|
38
|
+
column-fill
|
39
|
+
filter
|
40
|
+
flex
|
41
|
+
flex-grow
|
42
|
+
flex-shrink
|
43
|
+
flex-basis
|
44
|
+
flex-direction
|
45
|
+
flex-wrap
|
46
|
+
flex-flow
|
47
|
+
justify-content
|
48
|
+
order
|
49
|
+
align-items
|
50
|
+
align-self
|
51
|
+
align-content
|
52
|
+
font-feature-settings
|
53
|
+
hyphens
|
54
|
+
perspective
|
55
|
+
perspective-origin
|
56
|
+
transform
|
57
|
+
transform-origin
|
58
|
+
transform-style
|
59
|
+
transition
|
60
|
+
transition-property
|
61
|
+
transition-duration
|
62
|
+
transition-delay
|
63
|
+
transition-timing-function
|
64
|
+
user-select
|
65
|
+
|
66
|
+
|
67
|
+
# Values
|
68
|
+
crisp-edges
|
69
|
+
optimize-contrast
|
70
|
+
linear-gradient
|
71
|
+
radial-gradient
|
data/lib/scss_lint/cli.rb
CHANGED
@@ -20,10 +20,12 @@ module SCSSLint
|
|
20
20
|
config: 78, # Configuration error
|
21
21
|
}
|
22
22
|
|
23
|
+
DEFAULT_REPORTER = [SCSSLint::Reporter::DefaultReporter, :stdout]
|
24
|
+
|
23
25
|
# @param args [Array]
|
24
26
|
def initialize(args = [])
|
25
27
|
@args = args
|
26
|
-
@options = {}
|
28
|
+
@options = { reporters: [DEFAULT_REPORTER] }
|
27
29
|
@config = Config.default
|
28
30
|
end
|
29
31
|
|
@@ -32,7 +34,13 @@ module SCSSLint
|
|
32
34
|
options_parser.parse!(@args)
|
33
35
|
|
34
36
|
# Take the rest of the arguments as files/directories
|
35
|
-
|
37
|
+
|
38
|
+
if @args.empty?
|
39
|
+
@options[:files] = @config.scss_files
|
40
|
+
else
|
41
|
+
@options[:files] = @args
|
42
|
+
end
|
43
|
+
|
36
44
|
rescue OptionParser::InvalidOption => ex
|
37
45
|
print_help options_parser.help, ex
|
38
46
|
end
|
@@ -66,6 +74,14 @@ module SCSSLint
|
|
66
74
|
define_output_format(format)
|
67
75
|
end
|
68
76
|
|
77
|
+
opts.on('-o', '--out path', 'Write output to a file instead of STDOUT', String) do |path|
|
78
|
+
define_output_path(path)
|
79
|
+
end
|
80
|
+
|
81
|
+
opts.on('-r', '--require path', 'Require Ruby file', String) do |path|
|
82
|
+
require path
|
83
|
+
end
|
84
|
+
|
69
85
|
opts.on_tail('--show-formatters', 'Shows available formatters') do
|
70
86
|
print_formatters
|
71
87
|
end
|
@@ -192,20 +208,31 @@ module SCSSLint
|
|
192
208
|
# @param lints [Array<Lint>]
|
193
209
|
def report_lints(lints)
|
194
210
|
sorted_lints = lints.sort_by { |l| [l.filename, l.location] }
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
211
|
+
@options.fetch(:reporters).each do |reporter, output|
|
212
|
+
results = reporter.new(sorted_lints).report_lints
|
213
|
+
io = (output == :stdout ? $stdout : File.new(output, 'w+'))
|
214
|
+
io.print results if results
|
215
|
+
end
|
199
216
|
end
|
200
217
|
|
201
218
|
# @param format [String]
|
202
219
|
def define_output_format(format)
|
203
|
-
@options[:
|
220
|
+
unless @options[:reporters] == [DEFAULT_REPORTER] && format == 'Default'
|
221
|
+
@options[:reporters].reject! { |i| i == DEFAULT_REPORTER }
|
222
|
+
reporter = SCSSLint::Reporter.const_get(format + 'Reporter')
|
223
|
+
@options[:reporters] << [reporter, :stdout]
|
224
|
+
end
|
204
225
|
rescue NameError
|
205
226
|
puts "Invalid output format specified: #{format}"
|
206
227
|
halt :config
|
207
228
|
end
|
208
229
|
|
230
|
+
# @param path [String]
|
231
|
+
def define_output_path(path)
|
232
|
+
last_reporter, _output = @options[:reporters].pop
|
233
|
+
@options[:reporters] << [last_reporter, path]
|
234
|
+
end
|
235
|
+
|
209
236
|
def print_formatters
|
210
237
|
puts 'Installed formatters:'
|
211
238
|
|
data/lib/scss_lint/config.rb
CHANGED
@@ -175,7 +175,9 @@ module SCSSLint
|
|
175
175
|
if relative_include_path.start_with?('/')
|
176
176
|
relative_include_path
|
177
177
|
else
|
178
|
-
File.join(File.dirname(base_config_path), relative_include_path)
|
178
|
+
path = File.join(File.dirname(base_config_path), relative_include_path)
|
179
|
+
# Remove double backslashes appearing in Windows paths.
|
180
|
+
path.gsub(%r{^//}, File::SEPARATOR)
|
179
181
|
end
|
180
182
|
end
|
181
183
|
|
@@ -262,6 +264,15 @@ module SCSSLint
|
|
262
264
|
@options['exclude'] << abs_path
|
263
265
|
end
|
264
266
|
|
267
|
+
# @return Array
|
268
|
+
def scss_files
|
269
|
+
if path = @options['scss_files']
|
270
|
+
Dir[path]
|
271
|
+
else
|
272
|
+
[]
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
265
276
|
private
|
266
277
|
|
267
278
|
def validate_linters
|
data/lib/scss_lint/engine.rb
CHANGED
@@ -20,7 +20,9 @@ module SCSSLint
|
|
20
20
|
@contents = scss_or_filename
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
# Need to force encoding to avoid Windows-related bugs.
|
24
|
+
# Need `to_a` for Ruby 1.9.3.
|
25
|
+
@lines = @contents.force_encoding('UTF-8').lines.to_a
|
24
26
|
@tree = @engine.to_tree
|
25
27
|
rescue Encoding::UndefinedConversionError, Sass::SyntaxError => error
|
26
28
|
if error.is_a?(Encoding::UndefinedConversionError) ||
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module SCSSLint
|
2
|
+
# Checks spacing of ! declarations, like !important and !default
|
3
|
+
class Linter::BangFormat < Linter
|
4
|
+
include LinterRegistry
|
5
|
+
|
6
|
+
def visit_prop(node)
|
7
|
+
return unless node.to_sass.include?('!')
|
8
|
+
return unless check_spacing(node)
|
9
|
+
|
10
|
+
before_qualifier = config['space_before_bang'] ? '' : 'not '
|
11
|
+
after_qualifier = config['space_after_bang'] ? '' : 'not '
|
12
|
+
|
13
|
+
add_lint(node, "! should #{before_qualifier}be preceeded by a space, " \
|
14
|
+
"and should #{after_qualifier}be followed by a space")
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def find_bang_offset(range)
|
20
|
+
offset = 0
|
21
|
+
offset += 1 while character_at(range.start_pos, offset) != '!'
|
22
|
+
offset
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_spacing(node)
|
26
|
+
range = node.value_source_range
|
27
|
+
offset = find_bang_offset(range)
|
28
|
+
|
29
|
+
before_expected = config['space_before_bang'] ? / / : /[^ ]/
|
30
|
+
before_actual = character_at(range.start_pos, offset - 1)
|
31
|
+
before_is_wrong = (before_actual =~ before_expected).nil?
|
32
|
+
|
33
|
+
after_expected = config['space_after_bang'] ? / / : /[^ ]/
|
34
|
+
after_actual = character_at(range.start_pos, offset + 1)
|
35
|
+
after_is_wrong = (after_actual =~ after_expected).nil?
|
36
|
+
|
37
|
+
before_is_wrong || after_is_wrong
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -3,35 +3,56 @@ module SCSSLint
|
|
3
3
|
class Linter::DeclarationOrder < Linter
|
4
4
|
include LinterRegistry
|
5
5
|
|
6
|
+
def check_order(node)
|
7
|
+
check_node(node)
|
8
|
+
yield # Continue linting children
|
9
|
+
end
|
10
|
+
|
11
|
+
alias_method :visit_rule, :check_order
|
12
|
+
alias_method :visit_mixin, :check_order
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
MESSAGE =
|
17
|
+
'Rule sets should be ordered as follows: '\
|
18
|
+
'@extends, @includes without @content, ' \
|
19
|
+
'properties, @includes with @content, ' \
|
20
|
+
'nested rule sets'
|
21
|
+
|
22
|
+
MIXIN_WITH_CONTENT = 'mixin_with_content'
|
23
|
+
|
6
24
|
DECLARATION_ORDER = [
|
7
25
|
Sass::Tree::ExtendNode,
|
26
|
+
Sass::Tree::MixinNode,
|
8
27
|
Sass::Tree::PropNode,
|
28
|
+
MIXIN_WITH_CONTENT,
|
9
29
|
Sass::Tree::RuleNode,
|
10
30
|
]
|
11
31
|
|
12
|
-
def
|
32
|
+
def important_node?(node)
|
33
|
+
DECLARATION_ORDER.include?(node.class)
|
34
|
+
end
|
35
|
+
|
36
|
+
def check_node(node)
|
13
37
|
children = node.children.select { |n| important_node?(n) }
|
14
|
-
.map(
|
38
|
+
.map { |n| node_declaration_type(n) }
|
15
39
|
|
16
40
|
sorted_children = children.sort do |a, b|
|
17
41
|
DECLARATION_ORDER.index(a) <=> DECLARATION_ORDER.index(b)
|
18
42
|
end
|
19
43
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
yield # Continue linting children
|
44
|
+
return unless children != sorted_children
|
45
|
+
add_lint(node.children.first, MESSAGE)
|
25
46
|
end
|
26
47
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
'Rule sets should start with @extend declarations, followed by ' \
|
31
|
-
'properties and nested rule sets, in that order'
|
48
|
+
def node_declaration_type(node)
|
49
|
+
# If the node has no children, return the class.
|
50
|
+
return node.class unless node.has_children
|
32
51
|
|
33
|
-
|
34
|
-
|
52
|
+
# If the node is a mixin with children, indicate that;
|
53
|
+
# otherwise, just return the class.
|
54
|
+
return node.class unless node.is_a?(Sass::Tree::MixinNode)
|
55
|
+
MIXIN_WITH_CONTENT
|
35
56
|
end
|
36
57
|
end
|
37
58
|
end
|