scss-lint 0.16.1 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 400884121e0e088fafe2953b2c2bf56957bff0e9
4
- data.tar.gz: 59f9d1d2dd3c53c29f58acb39c2281f75e8520ff
3
+ metadata.gz: ee3e032cedba8042a60c3553efab8f57256e6d29
4
+ data.tar.gz: 4cc0c97f401c7d3fb69809a10a018ed6b963d5dd
5
5
  SHA512:
6
- metadata.gz: 901f0882c448ba16faa3d5c6022004e06a883855fa25c21f97daf017e7793fb175ecc4475fea140e2a563742c7a44014e8bea8942a68f8a755da5af9271ec21c
7
- data.tar.gz: a08001bb95198be920e2daa8c830ae569177ed6c0aeaf3d2e3497d482d296e0c8326f24d8dedb75f8d0712e7e2fa30fed4ebad7601a2b2e56f2d15d47e2d1c18
6
+ metadata.gz: a96e204786ee1c9c03753f89e76aabd7db21a6a65f595cfa757f7b6b02c3d69cb1b7c1aac4cdc0a97cd39038e39fd7aacf41e9bced89fd7913681af4eb4dfc3a
7
+ data.tar.gz: 65f3a369a456c75dcbfaa2a046c210e276a6f8a32d18c37bc32a7e646269a350eb3a599e9953d622a94e984d03349392072d74b881ee54779d21a0bbfa690797
@@ -79,9 +79,16 @@ linters:
79
79
  enabled: true
80
80
  spaces: 0
81
81
 
82
+ StringQuotes:
83
+ enabled: true
84
+ style: single_quotes # or double_quotes
85
+
82
86
  TrailingSemicolonAfterPropertyValue:
83
87
  enabled: true
84
88
 
89
+ UrlQuotes:
90
+ enabled: true
91
+
85
92
  UsageName:
86
93
  enabled: true
87
94
 
@@ -62,16 +62,17 @@ module SCSSLint
62
62
  file_contents = load_file_contents(file)
63
63
 
64
64
  options =
65
- if file_contents.strip.empty?
66
- {}
65
+ if yaml = YAML.load(file_contents)
66
+ yaml.to_hash
67
67
  else
68
- YAML.load(file_contents).to_hash
68
+ {}
69
69
  end
70
70
 
71
71
  options = convert_single_options_to_arrays(options)
72
72
  options = extend_inherited_configs(options, file)
73
73
  options = merge_wildcard_linter_options(options)
74
74
  options = ensure_exclude_paths_are_absolute(options, file)
75
+ options = ensure_linter_exclude_paths_are_absolute(options, file)
75
76
  options
76
77
  end
77
78
 
@@ -131,6 +132,19 @@ module SCSSLint
131
132
  options
132
133
  end
133
134
 
135
+ def ensure_linter_exclude_paths_are_absolute(options, original_file)
136
+ options = options.dup
137
+
138
+ options['linters'] ||= {}
139
+
140
+ options['linters'].keys.each do |linter_name|
141
+ options['linters'][linter_name] =
142
+ ensure_exclude_paths_are_absolute(options['linters'][linter_name], original_file)
143
+ end
144
+
145
+ options
146
+ end
147
+
134
148
  # Ensure all excludes are absolute paths
135
149
  def ensure_exclude_paths_are_absolute(options, original_file)
136
150
  options = options.dup
@@ -227,6 +241,14 @@ module SCSSLint
227
241
  end
228
242
  end
229
243
 
244
+ def excluded_file_for_linter?(file_path, linter)
245
+ abs_path = File.expand_path(file_path)
246
+
247
+ linter_options(linter).fetch('exclude', []).any? do |exclusion_glob|
248
+ File.fnmatch(exclusion_glob, abs_path)
249
+ end
250
+ end
251
+
230
252
  def exclude_file(file_path)
231
253
  abs_path = File.expand_path(file_path)
232
254
 
@@ -1,6 +1,8 @@
1
1
  require 'sass'
2
2
 
3
3
  module SCSSLint
4
+ class FileEncodingError < StandardError; end
5
+
4
6
  # Contains all information for a parsed SCSS file, including its name,
5
7
  # contents, and parse tree.
6
8
  class Engine
@@ -20,6 +22,15 @@ module SCSSLint
20
22
 
21
23
  @lines = @contents.split("\n")
22
24
  @tree = @engine.to_tree
25
+ rescue Encoding::UndefinedConversionError, ArgumentError => error
26
+ if error.is_a?(Encoding::UndefinedConversionError) ||
27
+ error.message.include?('invalid byte sequence')
28
+ raise FileEncodingError,
29
+ "Unable to parse SCSS file: #{error.to_s}",
30
+ error.backtrace
31
+ else
32
+ raise
33
+ end
23
34
  end
24
35
  end
25
36
  end
@@ -41,6 +41,29 @@ module SCSSLint
41
41
  engine.lines[actual_line][actual_offset]
42
42
  end
43
43
 
44
+ # Extracts the original source code given a range.
45
+ def source_from_range(source_range)
46
+ current_line = source_range.start_pos.line - 1
47
+ last_line = source_range.end_pos.line - 1
48
+
49
+ source = engine.lines[current_line][(source_range.start_pos.offset - 1)..-1]
50
+
51
+ current_line += 1
52
+ while current_line < last_line
53
+ source += "#{engine.lines[current_line]}\n"
54
+ current_line += 1
55
+ end
56
+
57
+ if source_range.start_pos.line != source_range.end_pos.line &&
58
+ # Sometimes the parser reports ranges ending on the first column of the
59
+ # line after the last line; don't include the last line in this case.
60
+ engine.lines.count == current_line - 1
61
+ source += "#{engine.lines[current_line][0...source_range.end_pos.offset]}\n"
62
+ end
63
+
64
+ source
65
+ end
66
+
44
67
  # Monkey-patched implementation that adds support for traversing
45
68
  # Sass::Script::Nodes (original implementation only supports
46
69
  # Sass::Tree::Nodes).
@@ -39,6 +39,7 @@ module SCSSLint
39
39
  end
40
40
 
41
41
  parent_selectors = simple_sequences.count do |item|
42
+ next if item.is_a?(Array) # @keyframe percentages end up as Arrays
42
43
  item.rest.any? { |i| i.is_a?(Sass::Selector::Parent) }
43
44
  end
44
45
 
@@ -4,16 +4,14 @@ module SCSSLint
4
4
  include LinterRegistry
5
5
 
6
6
  def visit_rule(node)
7
- add_lint(node) if invalid_comma_placement? node
7
+ add_lint(node, MESSAGE) if invalid_comma_placement?(node)
8
8
  yield # Continue linting children
9
9
  end
10
10
 
11
- def description
12
- 'Each selector should be on its own line'
13
- end
14
-
15
11
  private
16
12
 
13
+ MESSAGE = 'Each selector in a comma sequence should be on its own line'
14
+
17
15
  # A comma is invalid if it starts the line or is not the end of the line
18
16
  def invalid_comma_placement?(node)
19
17
  normalize_spacing(condense_to_string(node.rule)) =~ /\n,|,[^\n]/
@@ -23,10 +21,8 @@ module SCSSLint
23
21
  # Sass::Script::Nodes, we need to condense it into a single string that we
24
22
  # can run a regex against.
25
23
  def condense_to_string(sequence_list)
26
- sequence_list.inject('') do |combined, string_or_script|
27
- combined +
28
- (string_or_script.is_a?(String) ? string_or_script : string_or_script.to_sass)
29
- end
24
+ sequence_list.select { |item| item.is_a?(String) }
25
+ .inject('') { |combined, item| combined + item }
30
26
  end
31
27
 
32
28
  # Removes extra spacing between lines in a comma-separated sequence due to
@@ -19,21 +19,6 @@ module SCSSLint
19
19
  end
20
20
  end
21
21
 
22
- #def visit_script_number(node)
23
- #puts node.class
24
- #puts node.node_parent.class
25
- #puts node.node_parent.node_parent.class
26
- #puts node.inspect
27
- #yield
28
- #end
29
-
30
- #def visit_script_operation(node)
31
- #puts node.node_parent.class
32
- #puts node.inspect
33
- #puts node.source_range.inspect
34
- #yield
35
- #end
36
-
37
22
  private
38
23
 
39
24
  def check(str, index, engine)
@@ -0,0 +1,75 @@
1
+ module SCSSLint
2
+ # Checks the type of quotes used in string literals.
3
+ class Linter::StringQuotes < Linter
4
+ include LinterRegistry
5
+
6
+ def visit_script_string(node)
7
+ check_quotes(node, source_from_range(node.source_range))
8
+ end
9
+
10
+ def visit_import(node)
11
+ # @import source range conveniently includes only the quoted string
12
+ check_quotes(node, source_from_range(node.source_range))
13
+ end
14
+
15
+ def visit_charset(node)
16
+ # @charset source range includes entire declaration, so exclude '@charset' prefix
17
+ source = source_from_range(node.source_range)[('@charset'.length)..-1]
18
+
19
+ check_quotes(node, source)
20
+ end
21
+
22
+ private
23
+
24
+ def check_quotes(node, source)
25
+ source = source.strip
26
+ string = extract_string_without_quotes(source)
27
+ return unless string
28
+
29
+ case source[0]
30
+ when '"'
31
+ check_double_quotes(node, string)
32
+ when "'"
33
+ check_single_quotes(node, string)
34
+ end
35
+ end
36
+
37
+ STRING_WITHOUT_QUOTES_REGEX = %r{
38
+ \A
39
+ ["'](.*)["'] # Extract text between quotes
40
+ \s*\)?\s*;?\s* # Sometimes the Sass parser includes a trailing ) or ;
41
+ (//.*)? # Exclude any trailing comments that might have snuck in
42
+ \z
43
+ }x
44
+
45
+ def extract_string_without_quotes(source)
46
+ if match = STRING_WITHOUT_QUOTES_REGEX.match(source)
47
+ match[1]
48
+ end
49
+ end
50
+
51
+ def check_double_quotes(node, string)
52
+ if config['style'] == 'single_quotes'
53
+ add_lint(node, 'Prefer single quoted strings') if string !~ /'/
54
+ else
55
+ if string =~ /(?<! \\) \\"/x && string !~ /'/
56
+ add_lint(node, 'Use single-quoted strings when writing double quotes ' +
57
+ 'to avoid having to escape the double quotes')
58
+ end
59
+ end
60
+ end
61
+
62
+ def check_single_quotes(node, string)
63
+ if config['style'] == 'single_quotes'
64
+ if string =~ /(?<! \\) \\'/x && string !~ /"/
65
+ add_lint(node, 'Use double-quoted strings when writing single quotes ' +
66
+ 'to avoid having to escape the single quotes')
67
+ elsif string =~ /(?<! \\) \\"/x
68
+ add_lint(node, "Don't escape double quotes in single-quoted strings")
69
+ end
70
+ else
71
+ add_lint(node, 'Prefer double-quoted strings') if string !~ /"/
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,26 @@
1
+ module SCSSLint
2
+ # Checks for quotes in URLs.
3
+ class Linter::UrlQuotes < Linter
4
+ include LinterRegistry
5
+
6
+ def visit_prop(node)
7
+ case node.value
8
+ when Sass::Script::Tree::Literal
9
+ check(node, node.value.value.to_s)
10
+ when Sass::Script::Tree::ListLiteral
11
+ node.value.children.select { |child| child.is_a?(Sass::Script::Tree::Literal) }
12
+ .each { |child| check(node, child.value.to_s) }
13
+ end
14
+
15
+ yield
16
+ end
17
+
18
+ private
19
+
20
+ def check(node, string)
21
+ if string =~ /^\s*url\(\s*[^"']/
22
+ add_lint(node, 'URLs should be enclosed in quotes')
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,8 @@
1
+ module SCSSLint
2
+ # Reports a single line per file.
3
+ class Reporter::FilesReporter < Reporter
4
+ def report_lints
5
+ lints.map(&:filename).uniq.join("\n") + "\n" if lints.any?
6
+ end
7
+ end
8
+ end
@@ -34,6 +34,7 @@ module SCSSLint
34
34
 
35
35
  @linters.each do |linter|
36
36
  next unless config.linter_enabled?(linter)
37
+ next if config.excluded_file_for_linter?(file, linter)
37
38
 
38
39
  begin
39
40
  linter.run(engine, config.linter_options(linter))
@@ -46,6 +47,8 @@ module SCSSLint
46
47
  end
47
48
  rescue Sass::SyntaxError => ex
48
49
  @lints << Lint.new(ex.sass_filename, ex.sass_line, ex.to_s, :error)
50
+ rescue FileEncodingError => ex
51
+ @lints << Lint.new(file, 1, ex.to_s, :error)
49
52
  end
50
53
  end
51
54
  end
@@ -1,4 +1,4 @@
1
1
  # Defines the gem version.
2
2
  module SCSSLint
3
- VERSION = '0.16.1'
3
+ VERSION = '0.17.0'
4
4
  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.16.1
4
+ version: 0.17.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-01-07 00:00:00.000000000 Z
12
+ date: 2014-01-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: colorize
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - '='
19
19
  - !ruby/object:Gem::Version
20
- version: 0.5.8
20
+ version: 0.6.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - '='
26
26
  - !ruby/object:Gem::Version
27
- version: 0.5.8
27
+ version: 0.6.0
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: sass
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -59,14 +59,14 @@ dependencies:
59
59
  requirements:
60
60
  - - '='
61
61
  - !ruby/object:Gem::Version
62
- version: 2.13.0
62
+ version: 2.14.1
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - '='
68
68
  - !ruby/object:Gem::Version
69
- version: 2.13.0
69
+ version: 2.14.1
70
70
  description: Opinionated tool to help write clean and consistent SCSS
71
71
  email:
72
72
  - eng@causes.com
@@ -81,6 +81,7 @@ files:
81
81
  - lib/scss_lint/version.rb
82
82
  - lib/scss_lint/constants.rb
83
83
  - lib/scss_lint/utils.rb
84
+ - lib/scss_lint/reporter/files_reporter.rb
84
85
  - lib/scss_lint/reporter/xml_reporter.rb
85
86
  - lib/scss_lint/reporter/default_reporter.rb
86
87
  - lib/scss_lint/runner.rb
@@ -110,6 +111,7 @@ files:
110
111
  - lib/scss_lint/linter/space_after_property_name.rb
111
112
  - lib/scss_lint/linter/property_spelling.rb
112
113
  - lib/scss_lint/linter/usage_name.rb
114
+ - lib/scss_lint/linter/url_quotes.rb
113
115
  - lib/scss_lint/linter/space_between_parens.rb
114
116
  - lib/scss_lint/linter/border_zero.rb
115
117
  - lib/scss_lint/linter/space_after_property_colon.rb
@@ -117,6 +119,7 @@ files:
117
119
  - lib/scss_lint/linter/duplicate_property.rb
118
120
  - lib/scss_lint/linter/hex_format.rb
119
121
  - lib/scss_lint/linter/color_keyword.rb
122
+ - lib/scss_lint/linter/string_quotes.rb
120
123
  - lib/scss_lint/linter/leading_zero.rb
121
124
  - lib/scss_lint/linter/comment.rb
122
125
  - lib/scss_lint/linter/empty_rule.rb