scss-lint 0.24.1 → 0.25.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 +5 -0
- data/lib/scss_lint/linter/else_placement.rb +48 -0
- data/lib/scss_lint/linter/empty_line_between_blocks.rb +0 -7
- data/lib/scss_lint/linter/indentation.rb +38 -2
- data/lib/scss_lint/linter/placeholder_in_extend.rb +6 -0
- data/lib/scss_lint/linter/space_after_property_colon.rb +48 -10
- data/lib/scss_lint/utils.rb +14 -0
- data/lib/scss_lint/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8878aa5e26975ddb7c46f6bfd18f7db76e50a27
|
4
|
+
data.tar.gz: 729a1794663d878b450c6ed221ad3bd538c5f5bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 329e54beb7daf2457817fb6e9be9c69f603b3b058d11f1dc241fc36f25f7038b524f80e2e7a332b6bfe2f53d4f5e80b80cac202641489ff6a643faca0849d6ea
|
7
|
+
data.tar.gz: ee4adc133055f837029d44500a0ae360829985922fb96a1dbc6fe76da64d5d318b6d94b1c223855448b69fca2e602f143eb6e6c8b2f0c6f1bb685f9d6bd95782
|
data/config/default.yml
CHANGED
@@ -21,6 +21,10 @@ linters:
|
|
21
21
|
DuplicateProperty:
|
22
22
|
enabled: true
|
23
23
|
|
24
|
+
ElsePlacement:
|
25
|
+
enabled: true
|
26
|
+
style: same_line # or 'new_line'
|
27
|
+
|
24
28
|
EmptyLineBetweenBlocks:
|
25
29
|
enabled: true
|
26
30
|
ignore_single_line_blocks: true
|
@@ -87,6 +91,7 @@ linters:
|
|
87
91
|
|
88
92
|
SpaceAfterPropertyColon:
|
89
93
|
enabled: true
|
94
|
+
style: one_space # or 'no_space', or 'at_least_one_space', or 'aligned'
|
90
95
|
|
91
96
|
SpaceAfterPropertyName:
|
92
97
|
enabled: true
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module SCSSLint
|
2
|
+
# Checks where `@else` and `@else if` directives are placed with respect to
|
3
|
+
# the previous curly brace.
|
4
|
+
class Linter::ElsePlacement < Linter
|
5
|
+
include LinterRegistry
|
6
|
+
|
7
|
+
def visit_if(node)
|
8
|
+
visit_else(node, node.else) if node.else
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_else(if_node, else_node)
|
12
|
+
# Check each @else branch if there are multiple `@else if`s
|
13
|
+
visit_else(else_node, else_node.else) if else_node.else
|
14
|
+
|
15
|
+
# Skip @else statements on the same line as the previous @if, since we
|
16
|
+
# don't care about placement in that case
|
17
|
+
return if if_node.line == else_node.line
|
18
|
+
|
19
|
+
spaces = 0
|
20
|
+
while (char = character_at(else_node.source_range.start_pos, - (spaces + 1)))
|
21
|
+
if char == '}'
|
22
|
+
curly_on_same_line = true
|
23
|
+
break
|
24
|
+
end
|
25
|
+
spaces += 1
|
26
|
+
end
|
27
|
+
|
28
|
+
check_placement(else_node, curly_on_same_line)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def check_placement(else_node, curly_on_same_line)
|
34
|
+
if same_line_preferred?
|
35
|
+
unless curly_on_same_line
|
36
|
+
add_lint(else_node,
|
37
|
+
'@else should be placed on same line as previous curly brace')
|
38
|
+
end
|
39
|
+
elsif curly_on_same_line
|
40
|
+
add_lint(else_node, '@else should be placed on its own line')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def same_line_preferred?
|
45
|
+
config['style'] == 'same_line'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -72,12 +72,5 @@ module SCSSLint
|
|
72
72
|
index = siblings.index(node)
|
73
73
|
siblings[index - 1] if index > 0 && siblings.count > 1
|
74
74
|
end
|
75
|
-
|
76
|
-
def node_siblings(node)
|
77
|
-
return unless node && node.node_parent
|
78
|
-
node.node_parent
|
79
|
-
.children
|
80
|
-
.select { |child| child.is_a?(Sass::Tree::Node) }
|
81
|
-
end
|
82
75
|
end
|
83
76
|
end
|
@@ -25,7 +25,9 @@ module SCSSLint
|
|
25
25
|
|
26
26
|
# Ignore the case where the node is on the same line as its previous
|
27
27
|
# sibling or its parent, as indentation isn't possible
|
28
|
-
return if (previous = previous_node(node)) &&
|
28
|
+
return if (previous = previous_node(node)) &&
|
29
|
+
(previous.line == node.line ||
|
30
|
+
previous.source_range.end_pos.line == node.line)
|
29
31
|
|
30
32
|
actual_indent = engine.lines[node.line - 1][/^(\s*)/, 1]
|
31
33
|
|
@@ -43,8 +45,34 @@ module SCSSLint
|
|
43
45
|
visit(node.else) if node.else
|
44
46
|
end
|
45
47
|
|
48
|
+
# Need to define this explicitly since @at-root directives can contain
|
49
|
+
# inline selectors which produces the same parse tree as if the selector was
|
50
|
+
# nested within it. For example:
|
51
|
+
#
|
52
|
+
# @at-root {
|
53
|
+
# .something {
|
54
|
+
# ...
|
55
|
+
# }
|
56
|
+
# }
|
57
|
+
#
|
58
|
+
# ...and...
|
59
|
+
#
|
60
|
+
# @at-root .something {
|
61
|
+
# ...
|
62
|
+
# }
|
63
|
+
#
|
64
|
+
# ...produce the same parse tree, but result in different indentation
|
65
|
+
# levels.
|
66
|
+
def visit_atroot(node, &block)
|
67
|
+
if at_root_contains_inline_selector?(node)
|
68
|
+
return if check_indentation(node)
|
69
|
+
yield
|
70
|
+
else
|
71
|
+
check_and_visit_children(node, &block)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
46
75
|
# Define node types that increase indentation level
|
47
|
-
alias_method :visit_atroot, :check_and_visit_children
|
48
76
|
alias_method :visit_directive, :check_and_visit_children
|
49
77
|
alias_method :visit_each, :check_and_visit_children
|
50
78
|
alias_method :visit_for, :check_and_visit_children
|
@@ -66,5 +94,13 @@ module SCSSLint
|
|
66
94
|
alias_method :visit_return, :check_indentation
|
67
95
|
alias_method :visit_variable, :check_indentation
|
68
96
|
alias_method :visit_warn, :check_indentation
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def at_root_contains_inline_selector?(node)
|
101
|
+
return unless node.children.any?
|
102
|
+
|
103
|
+
same_position?(node.source_range.end_pos, node.children.first.source_range.start_pos)
|
104
|
+
end
|
69
105
|
end
|
70
106
|
end
|
@@ -4,9 +4,15 @@ module SCSSLint
|
|
4
4
|
include LinterRegistry
|
5
5
|
|
6
6
|
def visit_extend(node)
|
7
|
+
# Ignore if it cannot be statically determined that this selector is a
|
8
|
+
# placeholder since its prefix is dynamically generated
|
9
|
+
return if node.selector.first.is_a?(Sass::Script::Tree::Node)
|
10
|
+
|
7
11
|
# The array returned by the parser is a bit awkward in that it splits on
|
8
12
|
# every word boundary (so %placeholder becomes ['%', 'placeholder']).
|
9
13
|
selector = node.selector.join
|
14
|
+
|
15
|
+
# Ignore if this is a placeholder
|
10
16
|
return if selector.start_with?('%')
|
11
17
|
|
12
18
|
add_lint(node, 'Prefer using placeholder selectors (e.g. ' \
|
@@ -4,25 +4,63 @@ module SCSSLint
|
|
4
4
|
class Linter::SpaceAfterPropertyColon < Linter
|
5
5
|
include LinterRegistry
|
6
6
|
|
7
|
-
|
7
|
+
def visit_rule(node)
|
8
|
+
if config['style'] == 'aligned'
|
9
|
+
check_properties_alignment(node)
|
10
|
+
end
|
11
|
+
|
12
|
+
yield # Continue linting children
|
13
|
+
end
|
8
14
|
|
9
15
|
def visit_prop(node)
|
10
16
|
spaces = spaces_after_colon(node)
|
11
17
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
"#{pluralize(MINIMUM_SPACES_AFTER_COLON, 'space')} " \
|
20
|
-
"instead of #{pluralize(spaces, 'space')}"
|
18
|
+
case config['style']
|
19
|
+
when 'no_space'
|
20
|
+
check_for_no_spaces(node, spaces)
|
21
|
+
when 'one_space'
|
22
|
+
check_for_one_space(node, spaces)
|
23
|
+
when 'at_least_one_space'
|
24
|
+
check_for_at_least_one_space(node, spaces)
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
24
28
|
private
|
25
29
|
|
30
|
+
def check_for_no_spaces(node, spaces)
|
31
|
+
return if spaces == 0
|
32
|
+
add_lint(node, 'Colon after property should not be followed by any spaces')
|
33
|
+
end
|
34
|
+
|
35
|
+
def check_for_one_space(node, spaces)
|
36
|
+
return if spaces == 1
|
37
|
+
add_lint(node, 'Colon after property should be followed by one space')
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_for_at_least_one_space(node, spaces)
|
41
|
+
return if spaces >= 1
|
42
|
+
add_lint(node, 'Colon after property should be followed by at least one space')
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_properties_alignment(rule_node)
|
46
|
+
properties = rule_node.children.select { |node| node.is_a?(Sass::Tree::PropNode) }
|
47
|
+
|
48
|
+
properties.each_slice(2) do |prop1, prop2|
|
49
|
+
next unless prop2
|
50
|
+
next unless value_offset(prop1) != value_offset(prop2)
|
51
|
+
add_lint(prop1, 'Property values should be aligned')
|
52
|
+
break
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Offset of value for property
|
57
|
+
def value_offset(prop)
|
58
|
+
src_range = prop.name_source_range
|
59
|
+
src_range.start_pos.offset +
|
60
|
+
(src_range.end_pos.offset - src_range.start_pos.offset) +
|
61
|
+
spaces_after_colon(prop)
|
62
|
+
end
|
63
|
+
|
26
64
|
def spaces_after_colon(node)
|
27
65
|
spaces = 0
|
28
66
|
offset = 1
|
data/lib/scss_lint/utils.rb
CHANGED
@@ -41,8 +41,22 @@ module SCSSLint
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def node_siblings(node)
|
45
|
+
return unless node && node.node_parent
|
46
|
+
node.node_parent
|
47
|
+
.children
|
48
|
+
.select { |child| child.is_a?(Sass::Tree::Node) }
|
49
|
+
end
|
50
|
+
|
44
51
|
def pluralize(value, word)
|
45
52
|
value == 1 ? "#{value} #{word}" : "#{value} #{word}s"
|
46
53
|
end
|
54
|
+
|
55
|
+
# Sass doesn't define an equality operator for Sass::Source::Position
|
56
|
+
# objects, so we define a helper for our own use.
|
57
|
+
def same_position?(pos1, pos2)
|
58
|
+
return unless pos1 && pos2
|
59
|
+
pos1.line == pos2.line && pos1.offset == pos2.offset
|
60
|
+
end
|
47
61
|
end
|
48
62
|
end
|
data/lib/scss_lint/version.rb
CHANGED
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.25.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-06-23 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.23.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.23.0
|
84
84
|
description: Configurable tool for writing clean and consistent SCSS
|
85
85
|
email:
|
86
86
|
- eng@causes.com
|
@@ -125,6 +125,7 @@ files:
|
|
125
125
|
- lib/scss_lint/linter/zero_unit.rb
|
126
126
|
- lib/scss_lint/linter/placeholder_in_extend.rb
|
127
127
|
- lib/scss_lint/linter/selector_depth.rb
|
128
|
+
- lib/scss_lint/linter/else_placement.rb
|
128
129
|
- lib/scss_lint/linter/hex_validation.rb
|
129
130
|
- lib/scss_lint/linter/compass/property_with_mixin.rb
|
130
131
|
- lib/scss_lint/linter/space_after_property_name.rb
|