scss_lint 0.38.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.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/bin/scss-lint +6 -0
  3. data/config/default.yml +205 -0
  4. data/data/prefixed-identifiers/base.txt +107 -0
  5. data/data/prefixed-identifiers/bourbon.txt +71 -0
  6. data/data/properties.txt +477 -0
  7. data/data/property-sort-orders/concentric.txt +134 -0
  8. data/data/property-sort-orders/recess.txt +149 -0
  9. data/data/property-sort-orders/smacss.txt +137 -0
  10. data/lib/scss_lint.rb +31 -0
  11. data/lib/scss_lint/cli.rb +215 -0
  12. data/lib/scss_lint/config.rb +251 -0
  13. data/lib/scss_lint/constants.rb +8 -0
  14. data/lib/scss_lint/control_comment_processor.rb +126 -0
  15. data/lib/scss_lint/engine.rb +56 -0
  16. data/lib/scss_lint/exceptions.rb +21 -0
  17. data/lib/scss_lint/file_finder.rb +68 -0
  18. data/lib/scss_lint/lint.rb +24 -0
  19. data/lib/scss_lint/linter.rb +161 -0
  20. data/lib/scss_lint/linter/bang_format.rb +52 -0
  21. data/lib/scss_lint/linter/border_zero.rb +39 -0
  22. data/lib/scss_lint/linter/color_keyword.rb +32 -0
  23. data/lib/scss_lint/linter/color_variable.rb +60 -0
  24. data/lib/scss_lint/linter/comment.rb +21 -0
  25. data/lib/scss_lint/linter/compass.rb +7 -0
  26. data/lib/scss_lint/linter/compass/property_with_mixin.rb +47 -0
  27. data/lib/scss_lint/linter/debug_statement.rb +10 -0
  28. data/lib/scss_lint/linter/declaration_order.rb +71 -0
  29. data/lib/scss_lint/linter/duplicate_property.rb +58 -0
  30. data/lib/scss_lint/linter/else_placement.rb +48 -0
  31. data/lib/scss_lint/linter/empty_line_between_blocks.rb +85 -0
  32. data/lib/scss_lint/linter/empty_rule.rb +11 -0
  33. data/lib/scss_lint/linter/final_newline.rb +20 -0
  34. data/lib/scss_lint/linter/hex_length.rb +56 -0
  35. data/lib/scss_lint/linter/hex_notation.rb +38 -0
  36. data/lib/scss_lint/linter/hex_validation.rb +23 -0
  37. data/lib/scss_lint/linter/id_selector.rb +10 -0
  38. data/lib/scss_lint/linter/import_path.rb +62 -0
  39. data/lib/scss_lint/linter/important_rule.rb +12 -0
  40. data/lib/scss_lint/linter/indentation.rb +197 -0
  41. data/lib/scss_lint/linter/leading_zero.rb +49 -0
  42. data/lib/scss_lint/linter/mergeable_selector.rb +60 -0
  43. data/lib/scss_lint/linter/name_format.rb +117 -0
  44. data/lib/scss_lint/linter/nesting_depth.rb +24 -0
  45. data/lib/scss_lint/linter/placeholder_in_extend.rb +22 -0
  46. data/lib/scss_lint/linter/property_count.rb +44 -0
  47. data/lib/scss_lint/linter/property_sort_order.rb +198 -0
  48. data/lib/scss_lint/linter/property_spelling.rb +49 -0
  49. data/lib/scss_lint/linter/property_units.rb +59 -0
  50. data/lib/scss_lint/linter/qualifying_element.rb +42 -0
  51. data/lib/scss_lint/linter/selector_depth.rb +64 -0
  52. data/lib/scss_lint/linter/selector_format.rb +102 -0
  53. data/lib/scss_lint/linter/shorthand.rb +139 -0
  54. data/lib/scss_lint/linter/single_line_per_property.rb +59 -0
  55. data/lib/scss_lint/linter/single_line_per_selector.rb +35 -0
  56. data/lib/scss_lint/linter/space_after_comma.rb +110 -0
  57. data/lib/scss_lint/linter/space_after_property_colon.rb +92 -0
  58. data/lib/scss_lint/linter/space_after_property_name.rb +27 -0
  59. data/lib/scss_lint/linter/space_before_brace.rb +72 -0
  60. data/lib/scss_lint/linter/space_between_parens.rb +35 -0
  61. data/lib/scss_lint/linter/string_quotes.rb +94 -0
  62. data/lib/scss_lint/linter/trailing_semicolon.rb +67 -0
  63. data/lib/scss_lint/linter/trailing_zero.rb +41 -0
  64. data/lib/scss_lint/linter/unnecessary_mantissa.rb +42 -0
  65. data/lib/scss_lint/linter/unnecessary_parent_reference.rb +49 -0
  66. data/lib/scss_lint/linter/url_format.rb +56 -0
  67. data/lib/scss_lint/linter/url_quotes.rb +27 -0
  68. data/lib/scss_lint/linter/variable_for_property.rb +30 -0
  69. data/lib/scss_lint/linter/vendor_prefix.rb +64 -0
  70. data/lib/scss_lint/linter/zero_unit.rb +39 -0
  71. data/lib/scss_lint/linter_registry.rb +26 -0
  72. data/lib/scss_lint/location.rb +38 -0
  73. data/lib/scss_lint/options.rb +109 -0
  74. data/lib/scss_lint/rake_task.rb +106 -0
  75. data/lib/scss_lint/reporter.rb +18 -0
  76. data/lib/scss_lint/reporter/config_reporter.rb +26 -0
  77. data/lib/scss_lint/reporter/default_reporter.rb +27 -0
  78. data/lib/scss_lint/reporter/files_reporter.rb +8 -0
  79. data/lib/scss_lint/reporter/json_reporter.rb +30 -0
  80. data/lib/scss_lint/reporter/xml_reporter.rb +33 -0
  81. data/lib/scss_lint/runner.rb +51 -0
  82. data/lib/scss_lint/sass/script.rb +78 -0
  83. data/lib/scss_lint/sass/tree.rb +168 -0
  84. data/lib/scss_lint/selector_visitor.rb +34 -0
  85. data/lib/scss_lint/utils.rb +112 -0
  86. data/lib/scss_lint/version.rb +4 -0
  87. data/spec/scss_lint/cli_spec.rb +177 -0
  88. data/spec/scss_lint/config_spec.rb +253 -0
  89. data/spec/scss_lint/engine_spec.rb +24 -0
  90. data/spec/scss_lint/file_finder_spec.rb +134 -0
  91. data/spec/scss_lint/linter/bang_format_spec.rb +121 -0
  92. data/spec/scss_lint/linter/border_zero_spec.rb +118 -0
  93. data/spec/scss_lint/linter/color_keyword_spec.rb +83 -0
  94. data/spec/scss_lint/linter/color_variable_spec.rb +155 -0
  95. data/spec/scss_lint/linter/comment_spec.rb +79 -0
  96. data/spec/scss_lint/linter/compass/property_with_mixin_spec.rb +55 -0
  97. data/spec/scss_lint/linter/debug_statement_spec.rb +21 -0
  98. data/spec/scss_lint/linter/declaration_order_spec.rb +575 -0
  99. data/spec/scss_lint/linter/duplicate_property_spec.rb +189 -0
  100. data/spec/scss_lint/linter/else_placement_spec.rb +106 -0
  101. data/spec/scss_lint/linter/empty_line_between_blocks_spec.rb +276 -0
  102. data/spec/scss_lint/linter/empty_rule_spec.rb +27 -0
  103. data/spec/scss_lint/linter/final_newline_spec.rb +49 -0
  104. data/spec/scss_lint/linter/hex_length_spec.rb +104 -0
  105. data/spec/scss_lint/linter/hex_notation_spec.rb +104 -0
  106. data/spec/scss_lint/linter/hex_validation_spec.rb +40 -0
  107. data/spec/scss_lint/linter/id_selector_spec.rb +62 -0
  108. data/spec/scss_lint/linter/import_path_spec.rb +300 -0
  109. data/spec/scss_lint/linter/important_rule_spec.rb +43 -0
  110. data/spec/scss_lint/linter/indentation_spec.rb +347 -0
  111. data/spec/scss_lint/linter/leading_zero_spec.rb +233 -0
  112. data/spec/scss_lint/linter/mergeable_selector_spec.rb +283 -0
  113. data/spec/scss_lint/linter/name_format_spec.rb +282 -0
  114. data/spec/scss_lint/linter/nesting_depth_spec.rb +114 -0
  115. data/spec/scss_lint/linter/placeholder_in_extend_spec.rb +63 -0
  116. data/spec/scss_lint/linter/property_count_spec.rb +104 -0
  117. data/spec/scss_lint/linter/property_sort_order_spec.rb +482 -0
  118. data/spec/scss_lint/linter/property_spelling_spec.rb +84 -0
  119. data/spec/scss_lint/linter/property_units_spec.rb +229 -0
  120. data/spec/scss_lint/linter/qualifying_element_spec.rb +125 -0
  121. data/spec/scss_lint/linter/selector_depth_spec.rb +159 -0
  122. data/spec/scss_lint/linter/selector_format_spec.rb +632 -0
  123. data/spec/scss_lint/linter/shorthand_spec.rb +198 -0
  124. data/spec/scss_lint/linter/single_line_per_property_spec.rb +73 -0
  125. data/spec/scss_lint/linter/single_line_per_selector_spec.rb +130 -0
  126. data/spec/scss_lint/linter/space_after_comma_spec.rb +332 -0
  127. data/spec/scss_lint/linter/space_after_property_colon_spec.rb +373 -0
  128. data/spec/scss_lint/linter/space_after_property_name_spec.rb +37 -0
  129. data/spec/scss_lint/linter/space_before_brace_spec.rb +829 -0
  130. data/spec/scss_lint/linter/space_between_parens_spec.rb +263 -0
  131. data/spec/scss_lint/linter/string_quotes_spec.rb +335 -0
  132. data/spec/scss_lint/linter/trailing_semicolon_spec.rb +304 -0
  133. data/spec/scss_lint/linter/trailing_zero_spec.rb +176 -0
  134. data/spec/scss_lint/linter/unnecessary_mantissa_spec.rb +67 -0
  135. data/spec/scss_lint/linter/unnecessary_parent_reference_spec.rb +98 -0
  136. data/spec/scss_lint/linter/url_format_spec.rb +55 -0
  137. data/spec/scss_lint/linter/url_quotes_spec.rb +73 -0
  138. data/spec/scss_lint/linter/variable_for_property_spec.rb +145 -0
  139. data/spec/scss_lint/linter/vendor_prefix_spec.rb +371 -0
  140. data/spec/scss_lint/linter/zero_unit_spec.rb +113 -0
  141. data/spec/scss_lint/linter_registry_spec.rb +50 -0
  142. data/spec/scss_lint/linter_spec.rb +292 -0
  143. data/spec/scss_lint/location_spec.rb +42 -0
  144. data/spec/scss_lint/options_spec.rb +34 -0
  145. data/spec/scss_lint/rake_task_spec.rb +43 -0
  146. data/spec/scss_lint/reporter/config_reporter_spec.rb +42 -0
  147. data/spec/scss_lint/reporter/default_reporter_spec.rb +73 -0
  148. data/spec/scss_lint/reporter/files_reporter_spec.rb +38 -0
  149. data/spec/scss_lint/reporter/json_reporter_spec.rb +96 -0
  150. data/spec/scss_lint/reporter/xml_reporter_spec.rb +103 -0
  151. data/spec/scss_lint/reporter_spec.rb +11 -0
  152. data/spec/scss_lint/runner_spec.rb +123 -0
  153. data/spec/scss_lint/selector_visitor_spec.rb +264 -0
  154. data/spec/spec_helper.rb +34 -0
  155. data/spec/support/isolated_environment.rb +25 -0
  156. data/spec/support/matchers/report_lint.rb +48 -0
  157. metadata +328 -0
@@ -0,0 +1,38 @@
1
+ module SCSSLint
2
+ # Stores a location of {Lint} in a source.
3
+ class Location
4
+ include Comparable
5
+
6
+ attr_reader :line, :column, :length
7
+
8
+ # @param line [Integer] One-based index
9
+ # @param column [Integer] One-based index
10
+ # @param length [Integer] Number of characters, including the first character
11
+ def initialize(line = 1, column = 1, length = 1)
12
+ raise ArgumentError, "Line must be more than 0, passed #{line}" if line < 1
13
+ raise ArgumentError, "Column must be more than 0, passed #{column}" if column < 1
14
+ raise ArgumentError, "Length must be more than 0, passed #{length}" if length < 1
15
+
16
+ @line = line
17
+ @column = column
18
+ @length = length
19
+ end
20
+
21
+ def ==(other)
22
+ [:line, :column, :length].all? do |attr|
23
+ send(attr) == other.send(attr)
24
+ end
25
+ end
26
+
27
+ alias_method :eql?, :==
28
+
29
+ def <=>(other)
30
+ [:line, :column, :length].each do |attr|
31
+ result = send(attr) <=> other.send(attr)
32
+ return result unless result == 0
33
+ end
34
+
35
+ 0
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,109 @@
1
+ require 'optparse'
2
+
3
+ module SCSSLint
4
+ # Handles option parsing for the command line application.
5
+ class Options
6
+ DEFAULT_REPORTER = ['Default', :stdout]
7
+
8
+ # Parses command line options into an options hash.
9
+ #
10
+ # @param args [Array<String>] arguments passed via the command line
11
+ # @return [Hash] parsed options
12
+ def parse(args)
13
+ @options = {
14
+ reporters: [DEFAULT_REPORTER],
15
+ }
16
+
17
+ OptionParser.new do |parser|
18
+ parser.banner = "Usage: #{parser.program_name} [options] [scss-files]"
19
+
20
+ add_display_options parser
21
+ add_linter_options parser
22
+ add_file_options parser
23
+ add_info_options parser
24
+ end.parse!(args)
25
+
26
+ # Any remaining arguments are assumed to be files
27
+ @options[:files] = args
28
+
29
+ @options
30
+ rescue OptionParser::InvalidOption => ex
31
+ raise SCSSLint::Exceptions::InvalidCLIOption,
32
+ ex.message,
33
+ ex.backtrace
34
+ end
35
+
36
+ private
37
+
38
+ def add_display_options(parser)
39
+ parser.on('-f', '--format Formatter', 'Specify how to display lints', String) do |format|
40
+ define_output_format(format)
41
+ end
42
+
43
+ parser.on('-r', '--require path', 'Require Ruby file', String) do |path|
44
+ @options[:required_paths] ||= []
45
+ @options[:required_paths] << path
46
+ end
47
+ end
48
+
49
+ # @param format [String]
50
+ def define_output_format(format)
51
+ return if @options[:reporters] == [DEFAULT_REPORTER] && format == 'Default'
52
+
53
+ @options[:reporters].reject! { |i| i == DEFAULT_REPORTER }
54
+ @options[:reporters] << [format, :stdout]
55
+ end
56
+
57
+ def add_linter_options(parser)
58
+ parser.on('-i', '--include-linter linter,...', Array,
59
+ 'Specify which linters you want to run') do |linters|
60
+ @options[:included_linters] = linters
61
+ end
62
+
63
+ parser.on('-x', '--exclude-linter linter,...', Array,
64
+ "Specify which linters you don't want to run") do |linters|
65
+ @options[:excluded_linters] = linters
66
+ end
67
+ end
68
+
69
+ def add_file_options(parser)
70
+ parser.on('-c', '--config config-file', String,
71
+ 'Specify which configuration file you want to use') do |conf_file|
72
+ @options[:config_file] = conf_file
73
+ end
74
+
75
+ parser.on('-e', '--exclude file,...', Array,
76
+ 'List of file names to exclude') do |files|
77
+ @options[:excluded_files] = files
78
+ end
79
+
80
+ parser.on('-o', '--out path', 'Write output to a file instead of STDOUT', String) do |path|
81
+ define_output_path(path)
82
+ end
83
+ end
84
+
85
+ # @param path [String]
86
+ def define_output_path(path)
87
+ last_reporter, _output = @options[:reporters].pop
88
+ @options[:reporters] << [last_reporter, path]
89
+ end
90
+
91
+ def add_info_options(parser)
92
+ parser.on_tail('--show-formatters', 'Shows available formatters') do
93
+ @options[:show_formatters] = true
94
+ end
95
+
96
+ parser.on_tail('--show-linters', 'Display available linters') do
97
+ @options[:show_linters] = true
98
+ end
99
+
100
+ parser.on_tail('-h', '--help', 'Display help documentation') do
101
+ @options[:help] = parser.help
102
+ end
103
+
104
+ parser.on_tail('-v', '--version', 'Display version') do
105
+ @options[:version] = true
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,106 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ module SCSSLint
5
+ # Rake task for scss-lint CLI.
6
+ #
7
+ # @example
8
+ # # Add the following to your Rakefile...
9
+ # require 'scss_lint/rake_task'
10
+ # SCSSLint::RakeTask.new
11
+ #
12
+ # # ...and then execute from the command line:
13
+ # rake scss_lint
14
+ #
15
+ # You can also specify the list of files as explicit task arguments:
16
+ #
17
+ # @example
18
+ # # Add the following to your Rakefile...
19
+ # require 'scss_lint/rake_task'
20
+ # SCSSLint::RakeTask.new
21
+ #
22
+ # # ...and then execute from the command line (single quotes prevent shell
23
+ # # glob expansion and allow us to have a space after commas):
24
+ # rake 'scss_lint[app/assets/**/*.scss, other_files/**/*.scss]'
25
+ class RakeTask < Rake::TaskLib
26
+ # Name of the task.
27
+ # @return [String]
28
+ attr_accessor :name
29
+
30
+ # Configuration file to use.
31
+ # @return [String]
32
+ attr_accessor :config
33
+
34
+ # List of files to lint (can contain shell globs).
35
+ #
36
+ # Note that this will be ignored if you explicitly pass a list of files as
37
+ # task arguments via the command line or in the task definition.
38
+ # @return [Array<String>]
39
+ attr_accessor :files
40
+
41
+ # Create the task so it is accessible via +Rake::Task['scss_lint']+.
42
+ def initialize(name = :scss_lint)
43
+ @name = name
44
+ @files = ['.'] # Search for everything under current directory by default
45
+ @quiet = false
46
+
47
+ yield self if block_given?
48
+
49
+ define
50
+ end
51
+
52
+ private
53
+
54
+ def define
55
+ # Generate a default description if one hasn't been provided
56
+ desc default_description unless ::Rake.application.last_description
57
+
58
+ task(name, [:files]) do |_task, task_args|
59
+ # Lazy-load so task doesn't affect Rakefile load time
60
+ require 'scss_lint'
61
+ require 'scss_lint/cli'
62
+
63
+ run_cli(task_args)
64
+ end
65
+ end
66
+
67
+ def run_cli(task_args)
68
+ cli_args = ['--config', config] if config
69
+
70
+ result = SCSSLint::CLI.new.run(Array(cli_args) + files_to_lint(task_args))
71
+
72
+ message =
73
+ case result
74
+ when CLI::EXIT_CODES[:error], CLI::EXIT_CODES[:warning]
75
+ 'scss-lint found one or more lints'
76
+ when CLI::EXIT_CODES[:ok]
77
+ 'scss-lint found no lints'
78
+ else
79
+ 'scss-lint failed with an error'
80
+ end
81
+
82
+ puts message
83
+ exit result unless result == 0
84
+ end
85
+
86
+ def files_to_lint(task_args)
87
+ # Note: we're abusing Rake's argument handling a bit here. We call the
88
+ # first argument `files` but it's actually only the first file--we pull
89
+ # the rest out of the `extras` from the task arguments. This is so we
90
+ # can specify an arbitrary list of files separated by commas on the
91
+ # command line or in a custom task definition.
92
+ explicit_files = Array(task_args[:files]) + Array(task_args.extras)
93
+
94
+ explicit_files.any? ? explicit_files : files
95
+ end
96
+
97
+ # Friendly description that shows the full command that will be executed.
98
+ def default_description
99
+ description = 'Run `scss-lint'
100
+ description += " --config #{config}" if config
101
+ description += " #{files.join(' ')}" if files.any?
102
+ description += ' [files...]`'
103
+ description
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,18 @@
1
+ module SCSSLint
2
+ # Responsible for displaying lints to the user in some format.
3
+ class Reporter
4
+ attr_reader :lints
5
+
6
+ def self.descendants
7
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
8
+ end
9
+
10
+ def initialize(lints)
11
+ @lints = lints
12
+ end
13
+
14
+ def report_lints
15
+ raise NotImplementedError, 'You must implement report_lints'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ module SCSSLint
2
+ # Returns a YAML configuration where all linters are disabled which
3
+ # caused a lint.
4
+ class Reporter::ConfigReporter < Reporter
5
+ def report_lints
6
+ { 'linters' => disabled_linters }.to_yaml unless lints.empty?
7
+ end
8
+
9
+ private
10
+
11
+ def disabled_linters
12
+ linters.each_with_object({}) do |linter, m|
13
+ m[linter] = { 'enabled' => false }
14
+ end
15
+ end
16
+
17
+ def linters
18
+ lints.map { |lint| linter_name(lint.linter) }.compact.uniq.sort
19
+ end
20
+
21
+ def linter_name(linter)
22
+ return unless linter
23
+ linter.class.to_s.split('::').last
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ module SCSSLint
2
+ # Reports a single line per lint.
3
+ class Reporter::DefaultReporter < Reporter
4
+ def report_lints
5
+ return unless lints.any?
6
+
7
+ lints.map do |lint|
8
+ "#{location(lint)} #{type(lint)} #{message(lint)}"
9
+ end.join("\n") + "\n"
10
+ end
11
+
12
+ private
13
+
14
+ def location(lint)
15
+ "#{lint.filename.color(:cyan)}:#{lint.location.line.to_s.color(:magenta)}"
16
+ end
17
+
18
+ def type(lint)
19
+ lint.error? ? '[E]'.color(:red) : '[W]'.color(:yellow)
20
+ end
21
+
22
+ def message(lint)
23
+ linter_name = "#{lint.linter.name}: ".color(:green) if lint.linter
24
+ "#{linter_name}#{lint.description}"
25
+ end
26
+ end
27
+ 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
@@ -0,0 +1,30 @@
1
+ require 'json'
2
+
3
+ module SCSSLint
4
+ # Reports lints in a JSON format.
5
+ class Reporter::JSONReporter < Reporter
6
+ def report_lints
7
+ output = {}
8
+ lints.group_by(&:filename).each do |filename, file_lints|
9
+ output[filename] = file_lints.map do |lint|
10
+ issue_hash(lint)
11
+ end
12
+ end
13
+ JSON.pretty_generate(output)
14
+ end
15
+
16
+ private
17
+
18
+ def issue_hash(lint)
19
+ {
20
+ 'line' => lint.location.line,
21
+ 'column' => lint.location.column,
22
+ 'length' => lint.location.length,
23
+ 'severity' => lint.severity,
24
+ 'reason' => lint.description,
25
+ }.tap do |hash|
26
+ hash['linter'] = lint.linter.name if lint.linter
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ module SCSSLint
2
+ # Reports lints in an XML format.
3
+ class Reporter::XMLReporter < Reporter
4
+ def report_lints
5
+ output = '<?xml version="1.0" encoding="utf-8"?>'
6
+
7
+ output << '<lint>'
8
+ lints.group_by(&:filename).each do |filename, file_lints|
9
+ output << "<file name=#{filename.encode(xml: :attr)}>"
10
+
11
+ file_lints.each do |lint|
12
+ output << issue_tag(lint)
13
+ end
14
+
15
+ output << '</file>'
16
+ end
17
+ output << '</lint>'
18
+
19
+ output
20
+ end
21
+
22
+ private
23
+
24
+ def issue_tag(lint)
25
+ "<issue linter=\"#{lint.linter.name if lint.linter}\" " \
26
+ "line=\"#{lint.location.line}\" " \
27
+ "column=\"#{lint.location.column}\" " \
28
+ "length=\"#{lint.location.length}\" " \
29
+ "severity=\"#{lint.severity}\" " \
30
+ "reason=#{lint.description.encode(xml: :attr)} />"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ module SCSSLint
2
+ # Finds and aggregates all lints found by running the registered linters
3
+ # against a set of SCSS files.
4
+ class Runner
5
+ attr_reader :lints
6
+
7
+ # @param config [Config]
8
+ def initialize(config)
9
+ @config = config
10
+ @lints = []
11
+ @linters = LinterRegistry.linters.map(&:new)
12
+ end
13
+
14
+ # @param files [Array]
15
+ def run(files)
16
+ files.each do |file|
17
+ find_lints(file)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ # @param file [String]
24
+ def find_lints(file)
25
+ engine = Engine.new(file: file)
26
+
27
+ @linters.each do |linter|
28
+ begin
29
+ run_linter(linter, engine, file)
30
+ rescue => error
31
+ raise SCSSLint::Exceptions::LinterError,
32
+ "#{linter.class} raised unexpected error linting file #{file}: " \
33
+ "'#{error.message}'",
34
+ error.backtrace
35
+ end
36
+ end
37
+ rescue Sass::SyntaxError => ex
38
+ @lints << Lint.new(nil, ex.sass_filename, Location.new(ex.sass_line),
39
+ "Syntax Error: #{ex}", :error)
40
+ rescue FileEncodingError => ex
41
+ @lints << Lint.new(nil, file, Location.new, ex.to_s, :error)
42
+ end
43
+
44
+ # For stubbing in tests.
45
+ def run_linter(linter, engine, file)
46
+ return unless @config.linter_enabled?(linter)
47
+ return if @config.excluded_file_for_linter?(file, linter)
48
+ @lints += linter.run(engine, @config.linter_options(linter))
49
+ end
50
+ end
51
+ end