scss-lint 0.13.0 → 0.14.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: 05986225943272819dc966c20d294f39f54bd7ef
4
- data.tar.gz: c5fb97b91c46be45d9a4bb72573356639e1f5afb
3
+ metadata.gz: e0c38097da925d1dcc77a8cc9c4d90468e598abb
4
+ data.tar.gz: e5e2f0352fc1e808b3ebe147c200c24727e425d0
5
5
  SHA512:
6
- metadata.gz: b38f342599f822cb5d26617986f264e5ef2ad00ddddc10c049a57369a191706e77b38b9a97b9735daaa424703d19b93829a33f0a09b2ebac208bec52a5874eba
7
- data.tar.gz: 45ecd691b23e170805dd1e45f509fbff7891c0f32880c1eeb4ff9d4967d7b7733128d1a3dcad4f367ac44309eca8ab79884dda18fe0436654c95d985a4f639b0
6
+ metadata.gz: 0e65ae3133dbdefac6e650b8561db659671280f659d050d37c5dc0704b3b592ac1d7ab8303a936ccaf0aa6fab6a02c50a2e8be254039e5cfc2caa741890cf600
7
+ data.tar.gz: e7677e4fe7bbc9337884d8cc423105a08d77361d9d50369ae41c4677677cf8626e920e791592d715db56d763dca2d91292469453a61b4201dbe66c1e3be25419
@@ -43,6 +43,10 @@ linters:
43
43
  PlaceholderInExtend:
44
44
  enabled: true
45
45
 
46
+ SelectorDepth:
47
+ enabled: true
48
+ max_depth: 3
49
+
46
50
  Shorthand:
47
51
  enabled: true
48
52
 
@@ -57,6 +57,10 @@ module SCSSLint
57
57
  @options[:excluded_files] = files
58
58
  end
59
59
 
60
+ opts.on('-f', '--format Formatter', 'Specify how to display lints', String) do |format|
61
+ set_output_format(format)
62
+ end
63
+
60
64
  opts.on('-i', '--include-linter linter,...', Array,
61
65
  'Specify which linters you want to run') do |linters|
62
66
  @options[:included_linters] = linters
@@ -78,10 +82,6 @@ module SCSSLint
78
82
  opts.on_tail('-v', '--version', 'Show version') do
79
83
  print_version opts.program_name, VERSION
80
84
  end
81
-
82
- opts.on('--xml', 'Output the results in XML format') do
83
- @options[:reporter] = SCSSLint::Reporter::XMLReporter
84
- end
85
85
  end
86
86
  end
87
87
 
@@ -175,6 +175,13 @@ module SCSSLint
175
175
  print output if output
176
176
  end
177
177
 
178
+ def set_output_format(format)
179
+ @options[:reporter] = SCSSLint::Reporter.const_get(format + 'Reporter')
180
+ rescue NameError
181
+ puts "Invalid output format specified: #{format}"
182
+ halt :config
183
+ end
184
+
178
185
  def print_linters
179
186
  puts 'Installed linters:'
180
187
 
@@ -68,27 +68,49 @@ module SCSSLint
68
68
  YAML.load(file_contents).to_hash
69
69
  end
70
70
 
71
+ options = convert_single_options_to_arrays(options)
72
+ options = extend_inherited_configs(options, file)
73
+ options = merge_wildcard_linter_options(options)
74
+ options = ensure_exclude_paths_are_absolute(options, file)
75
+ options
76
+ end
77
+
78
+ # Convert any config options that accept a single value or an array to an
79
+ # array form so that merging works.
80
+ def convert_single_options_to_arrays(options)
81
+ options = options.dup
82
+
71
83
  if options['exclude']
72
84
  # Ensure exclude is an array, since we allow user to specify a single
73
85
  # string. We do this before merging with the config loaded via
74
- # inherit_form since this allows us to merge the excludes from that,
86
+ # inherit_from since this allows us to merge the excludes from that,
75
87
  # rather than overwriting them.
76
88
  options['exclude'] = [options['exclude']].flatten
77
89
  end
78
90
 
79
- if options['inherit_from']
80
- includes = [options.delete('inherit_from')].flatten.map do |include_file|
81
- load_options_hash_from_file(path_relative_to_config(include_file, file))
82
- end
91
+ options
92
+ end
83
93
 
84
- merged_includes = includes[1..-1].inject(includes.first) do |merged, include_file|
85
- smart_merge(merged, include_file)
86
- end
94
+ # Loads and extends a list of inherited options with the given options.
95
+ def extend_inherited_configs(options, original_file)
96
+ return options unless options['inherit_from']
97
+ options = options.dup
87
98
 
88
- options = smart_merge(merged_includes, options)
99
+ includes = [options.delete('inherit_from')].flatten.map do |include_file|
100
+ load_options_hash_from_file(path_relative_to_config(include_file, original_file))
89
101
  end
90
102
 
91
- # Merge options from wildcard linters into individual linter configs
103
+ merged_includes = includes[1..-1].inject(includes.first) do |merged, include_file|
104
+ smart_merge(merged, include_file)
105
+ end
106
+
107
+ smart_merge(merged_includes, options)
108
+ end
109
+
110
+ # Merge options from wildcard linters into individual linter configs
111
+ def merge_wildcard_linter_options(options)
112
+ options = options.dup
113
+
92
114
  options.fetch('linters', {}).keys.each do |class_name|
93
115
  next unless class_name.include?('*')
94
116
 
@@ -106,7 +128,13 @@ module SCSSLint
106
128
  end
107
129
  end
108
130
 
109
- # Ensure all excludes are absolute paths
131
+ options
132
+ end
133
+
134
+ # Ensure all excludes are absolute paths
135
+ def ensure_exclude_paths_are_absolute(options, original_file)
136
+ options = options.dup
137
+
110
138
  if options['exclude']
111
139
  excludes = [options['exclude']].flatten
112
140
 
@@ -115,7 +143,7 @@ module SCSSLint
115
143
  exclusion_glob
116
144
  else
117
145
  # Expand the path assuming it is relative to the config file itself
118
- File.expand_path(exclusion_glob, File.expand_path(File.dirname(file)))
146
+ File.expand_path(exclusion_glob, File.expand_path(File.dirname(original_file)))
119
147
  end
120
148
  end
121
149
  end
@@ -1,6 +1,8 @@
1
1
  require 'sass'
2
2
 
3
3
  module SCSSLint
4
+ # Contains all information for a parsed SCSS file, including its name,
5
+ # contents, and parse tree.
4
6
  class Engine
5
7
  ENGINE_OPTIONS = { cache: false, syntax: :scss }
6
8
 
@@ -1,4 +1,5 @@
1
1
  module SCSSLint
2
+ # Stores information about a single problem that was detected by a [Linter].
2
3
  class Lint
3
4
  attr_reader :filename, :line, :description, :severity
4
5
 
@@ -11,7 +11,7 @@ module SCSSLint
11
11
  def visit_script_string(node)
12
12
  return unless node.type == :identifier
13
13
 
14
- remove_quoted_strings(node.value).scan(/[a-z]+/i) do |word|
14
+ remove_quoted_strings(node.value).scan(/(^|\s)([a-z]+)(?=\s|$)/i) do |_, word|
15
15
  add_color_lint(node, word) if color_keyword?(word)
16
16
  end
17
17
  end
@@ -10,8 +10,8 @@ module SCSSLint
10
10
  ]
11
11
 
12
12
  def visit_rule(node)
13
- children = node.children.select { |node| important_node?(node) }.
14
- map { |node| node.class }
13
+ children = node.children.select { |n| important_node?(n) }
14
+ .map { |n| n.class }
15
15
 
16
16
  sorted_children = children.sort do |a, b|
17
17
  DECLARATION_ORDER.index(a) <=> DECLARATION_ORDER.index(b)
@@ -1,4 +1,5 @@
1
1
  module SCSSLint
2
+ # Checks for a property declared twice in a rule set.
2
3
  class Linter::DuplicateProperty < Linter
3
4
  include LinterRegistry
4
5
 
@@ -1,4 +1,5 @@
1
1
  module SCSSLint
2
+ # Checks for rules with no content.
2
3
  class Linter::EmptyRule < Linter
3
4
  include LinterRegistry
4
5
 
@@ -1,4 +1,5 @@
1
1
  module SCSSLint
2
+ # Checks for hexadecimal colors that can be shortened.
2
3
  class Linter::HexFormat < Linter
3
4
  include LinterRegistry
4
5
 
@@ -0,0 +1,61 @@
1
+ module SCSSLint
2
+ # Checks for selectors with large depths of applicability.
3
+ class Linter::SelectorDepth < Linter
4
+ include LinterRegistry
5
+
6
+ def visit_root(node)
7
+ @max_depth = config['max_depth']
8
+ @depth = 0
9
+ yield # Continue
10
+ end
11
+
12
+ def visit_rule(node)
13
+ old_depth = @depth
14
+ @depth = max_sequence_depth(node.parsed_rules, @depth)
15
+
16
+ if @depth > @max_depth
17
+ add_lint(node.parsed_rules || node,
18
+ 'Selector should have depth of applicability no greater ' <<
19
+ "than #{@max_depth}, but was #{@depth}")
20
+ end
21
+
22
+ yield # Continue linting children
23
+ @depth = old_depth
24
+ end
25
+
26
+ private
27
+
28
+ # Find the maximum depth of all sequences in a comma sequence.
29
+ def max_sequence_depth(comma_sequence, current_depth)
30
+ # Sequence contains interpolation; assume a depth of 1
31
+ return current_depth + 1 unless comma_sequence
32
+
33
+ comma_sequence.members.map { |sequence| sequence_depth(sequence, current_depth) }.max
34
+ end
35
+
36
+ def sequence_depth(sequence, current_depth)
37
+ separators, simple_sequences = sequence.members.partition do |item|
38
+ item.is_a?(String)
39
+ end
40
+
41
+ parent_selectors = simple_sequences.count { |item| item.to_s == '&' }
42
+
43
+ # Take the number of simple sequences and subtract one for each sibling
44
+ # combinator, as these "combine" simple sequences such that they do not
45
+ # increase depth.
46
+ depth = simple_sequences.size -
47
+ separators.count { |item| item == '~' || item == '+' }
48
+
49
+ if parent_selectors > 0
50
+ # If parent selectors are present, add the current depth for each
51
+ # additional parent selector.
52
+ depth += parent_selectors * (current_depth - 1)
53
+ else
54
+ # Otherwise this just descends from the containing selector
55
+ depth += current_depth
56
+ end
57
+
58
+ depth
59
+ end
60
+ end
61
+ end
@@ -24,8 +24,8 @@ module SCSSLint
24
24
  # can run a regex against.
25
25
  def condense_to_string(sequence_list)
26
26
  sequence_list.inject('') do |combined, string_or_script|
27
- combined + (string_or_script.is_a?(String) ? string_or_script
28
- : string_or_script.to_sass)
27
+ combined +
28
+ (string_or_script.is_a?(String) ? string_or_script : string_or_script.to_sass)
29
29
  end
30
30
  end
31
31
 
@@ -1,4 +1,6 @@
1
1
  module SCSSLint
2
+ # Checks for variable/function/mixin/placeholder uses which contains uppercase
3
+ # characters or underscores.
2
4
  class Linter::UsageName < Linter
3
5
  include LinterRegistry
4
6
 
@@ -1,6 +1,7 @@
1
1
  module SCSSLint
2
2
  class NoSuchLinter < StandardError; end
3
3
 
4
+ # Stores all linters available to the application.
4
5
  module LinterRegistry
5
6
  @linters = []
6
7
 
@@ -16,7 +17,7 @@ module SCSSLint
16
17
  begin
17
18
  Linter.const_get(linter_name)
18
19
  rescue NameError
19
- raise NoSuchLinter.new("Linter #{linter_name} does not exist")
20
+ raise NoSuchLinter, "Linter #{linter_name} does not exist"
20
21
  end
21
22
  end
22
23
  end
@@ -1,4 +1,5 @@
1
1
  module SCSSLint
2
+ # Responsible for displaying lints to the user in some format.
2
3
  class Reporter
3
4
  attr_reader :lints
4
5
 
@@ -1,6 +1,7 @@
1
1
  require 'colorize'
2
2
 
3
3
  module SCSSLint
4
+ # Reports a single line per lint.
4
5
  class Reporter::DefaultReporter < Reporter
5
6
  def report_lints
6
7
  if lints.any?
@@ -1,4 +1,5 @@
1
1
  module SCSSLint
2
+ # Reports lints in an XML format.
2
3
  class Reporter::XMLReporter < Reporter
3
4
  def report_lints
4
5
  output = '<?xml version="1.0" encoding="utf-8"?>'
@@ -1,4 +1,7 @@
1
1
  module Sass::Script
2
+ # Ignore documentation lints as these aren't original implementations.
3
+ # rubocop:disable Documentation
4
+
2
5
  # Redefine some of the lexer helpers in order to store the original string
3
6
  # with the created object so that the original string can be inspected rather
4
7
  # than a typically normalized version.
@@ -3,6 +3,9 @@
3
3
  # breaks the Sass compiler, but since we're only doing lints this is fine for
4
4
  # now.
5
5
  module Sass::Tree
6
+ # Ignore documentation lints as these aren't original implementations.
7
+ # rubocop:disable Documentation
8
+
6
9
  # Define some common helper code for use in the various monkey patchings.
7
10
  class Node
8
11
  # Stores node for which this node is a direct child
@@ -1,3 +1,4 @@
1
+ # Defines the gem version.
1
2
  module SCSSLint
2
- VERSION = '0.13.0'
3
+ VERSION = '0.14.0'
3
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.13.0
4
+ version: 0.14.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: 2013-12-03 00:00:00.000000000 Z
12
+ date: 2013-12-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: colorize
@@ -103,6 +103,7 @@ files:
103
103
  - lib/scss_lint/linter/declaration_order.rb
104
104
  - lib/scss_lint/linter/zero_unit.rb
105
105
  - lib/scss_lint/linter/placeholder_in_extend.rb
106
+ - lib/scss_lint/linter/selector_depth.rb
106
107
  - lib/scss_lint/linter/compass/property_with_mixin.rb
107
108
  - lib/scss_lint/linter/space_after_property_name.rb
108
109
  - lib/scss_lint/linter/usage_name.rb
@@ -141,9 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
142
  version: '0'
142
143
  requirements: []
143
144
  rubyforge_project:
144
- rubygems_version: 2.0.2
145
+ rubygems_version: 2.0.14
145
146
  signing_key:
146
147
  specification_version: 4
147
148
  summary: SCSS lint tool
148
149
  test_files: []
149
- has_rdoc: