haml_lint 0.13.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 (60) hide show
  1. checksums.yaml +7 -0
  2. data/bin/haml-lint +7 -0
  3. data/config/default.yml +91 -0
  4. data/lib/haml_lint/cli.rb +122 -0
  5. data/lib/haml_lint/configuration.rb +97 -0
  6. data/lib/haml_lint/configuration_loader.rb +68 -0
  7. data/lib/haml_lint/constants.rb +8 -0
  8. data/lib/haml_lint/exceptions.rb +15 -0
  9. data/lib/haml_lint/file_finder.rb +69 -0
  10. data/lib/haml_lint/haml_visitor.rb +36 -0
  11. data/lib/haml_lint/lint.rb +25 -0
  12. data/lib/haml_lint/linter/alt_text.rb +12 -0
  13. data/lib/haml_lint/linter/class_attribute_with_static_value.rb +51 -0
  14. data/lib/haml_lint/linter/classes_before_ids.rb +26 -0
  15. data/lib/haml_lint/linter/consecutive_comments.rb +20 -0
  16. data/lib/haml_lint/linter/consecutive_silent_scripts.rb +23 -0
  17. data/lib/haml_lint/linter/empty_script.rb +12 -0
  18. data/lib/haml_lint/linter/html_attributes.rb +14 -0
  19. data/lib/haml_lint/linter/implicit_div.rb +20 -0
  20. data/lib/haml_lint/linter/leading_comment_space.rb +14 -0
  21. data/lib/haml_lint/linter/line_length.rb +19 -0
  22. data/lib/haml_lint/linter/multiline_pipe.rb +43 -0
  23. data/lib/haml_lint/linter/multiline_script.rb +43 -0
  24. data/lib/haml_lint/linter/object_reference_attributes.rb +14 -0
  25. data/lib/haml_lint/linter/rubocop.rb +76 -0
  26. data/lib/haml_lint/linter/ruby_comments.rb +18 -0
  27. data/lib/haml_lint/linter/space_before_script.rb +52 -0
  28. data/lib/haml_lint/linter/space_inside_hash_attributes.rb +32 -0
  29. data/lib/haml_lint/linter/tag_name.rb +13 -0
  30. data/lib/haml_lint/linter/trailing_whitespace.rb +16 -0
  31. data/lib/haml_lint/linter/unnecessary_interpolation.rb +29 -0
  32. data/lib/haml_lint/linter/unnecessary_string_output.rb +39 -0
  33. data/lib/haml_lint/linter.rb +156 -0
  34. data/lib/haml_lint/linter_registry.rb +26 -0
  35. data/lib/haml_lint/logger.rb +107 -0
  36. data/lib/haml_lint/node_transformer.rb +28 -0
  37. data/lib/haml_lint/options.rb +89 -0
  38. data/lib/haml_lint/parser.rb +87 -0
  39. data/lib/haml_lint/rake_task.rb +107 -0
  40. data/lib/haml_lint/report.rb +16 -0
  41. data/lib/haml_lint/reporter/default_reporter.rb +39 -0
  42. data/lib/haml_lint/reporter/json_reporter.rb +44 -0
  43. data/lib/haml_lint/reporter.rb +36 -0
  44. data/lib/haml_lint/ruby_parser.rb +29 -0
  45. data/lib/haml_lint/runner.rb +76 -0
  46. data/lib/haml_lint/script_extractor.rb +181 -0
  47. data/lib/haml_lint/tree/comment_node.rb +5 -0
  48. data/lib/haml_lint/tree/doctype_node.rb +5 -0
  49. data/lib/haml_lint/tree/filter_node.rb +9 -0
  50. data/lib/haml_lint/tree/haml_comment_node.rb +18 -0
  51. data/lib/haml_lint/tree/node.rb +98 -0
  52. data/lib/haml_lint/tree/plain_node.rb +5 -0
  53. data/lib/haml_lint/tree/root_node.rb +5 -0
  54. data/lib/haml_lint/tree/script_node.rb +11 -0
  55. data/lib/haml_lint/tree/silent_script_node.rb +12 -0
  56. data/lib/haml_lint/tree/tag_node.rb +221 -0
  57. data/lib/haml_lint/utils.rb +58 -0
  58. data/lib/haml_lint/version.rb +4 -0
  59. data/lib/haml_lint.rb +36 -0
  60. metadata +175 -0
@@ -0,0 +1,107 @@
1
+ module HamlLint
2
+ # Encapsulates all communication to an output source.
3
+ class Logger
4
+ # Whether colored output via ANSI escape sequences is enabled.
5
+ # @return [true,false]
6
+ attr_accessor :color_enabled
7
+
8
+ # Creates a logger which outputs nothing.
9
+ # @return [HamlLint::Logger]
10
+ def self.silent
11
+ new(File.open('/dev/null', 'w'))
12
+ end
13
+
14
+ # Creates a new {HamlLint::Logger} instance.
15
+ #
16
+ # @param out [IO] the output destination.
17
+ def initialize(out)
18
+ @out = out
19
+ end
20
+
21
+ # Print the specified output.
22
+ #
23
+ # @param output [String] the output to send
24
+ # @param newline [true,false] whether to append a newline
25
+ # @return [nil]
26
+ def log(output, newline = true)
27
+ @out.print(output)
28
+ @out.print("\n") if newline
29
+ end
30
+
31
+ # Print the specified output in bold face.
32
+ # If output destination is not a TTY, behaves the same as {#log}.
33
+ #
34
+ # @param args [Array<String>]
35
+ # @return [nil]
36
+ def bold(*args)
37
+ color('1', *args)
38
+ end
39
+
40
+ # Print the specified output in a color indicative of error.
41
+ # If output destination is not a TTY, behaves the same as {#log}.
42
+ #
43
+ # @param args [Array<String>]
44
+ # @return [nil]
45
+ def error(*args)
46
+ color(31, *args)
47
+ end
48
+
49
+ # Print the specified output in a bold face and color indicative of error.
50
+ # If output destination is not a TTY, behaves the same as {#log}.
51
+ #
52
+ # @param args [Array<String>]
53
+ # @return [nil]
54
+ def bold_error(*args)
55
+ color('1;31', *args)
56
+ end
57
+
58
+ # Print the specified output in a color indicative of success.
59
+ # If output destination is not a TTY, behaves the same as {#log}.
60
+ #
61
+ # @param args [Array<String>]
62
+ # @return [nil]
63
+ def success(*args)
64
+ color(32, *args)
65
+ end
66
+
67
+ # Print the specified output in a color indicative of a warning.
68
+ # If output destination is not a TTY, behaves the same as {#log}.
69
+ #
70
+ # @param args [Array<String>]
71
+ # @return [nil]
72
+ def warning(*args)
73
+ color(33, *args)
74
+ end
75
+
76
+ # Print specified output in bold face in a color indicative of a warning.
77
+ # If output destination is not a TTY, behaves the same as {#log}.
78
+ #
79
+ # @param args [Array<String>]
80
+ # @return [nil]
81
+ def bold_warning(*args)
82
+ color('1;33', *args)
83
+ end
84
+
85
+ # Print the specified output in a color indicating information.
86
+ # If output destination is not a TTY, behaves the same as {#log}.
87
+ #
88
+ # @param args [Array<String>]
89
+ # @return [nil]
90
+ def info(*args)
91
+ color(36, *args)
92
+ end
93
+
94
+ # Whether this logger is outputting to a TTY.
95
+ #
96
+ # @return [true,false]
97
+ def tty?
98
+ @out.respond_to?(:tty?) && @out.tty?
99
+ end
100
+
101
+ private
102
+
103
+ def color(code, output, newline = true)
104
+ log(color_enabled ? "\033[#{code}m#{output}\033[0m" : output, newline)
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,28 @@
1
+ module HamlLint
2
+ # Responsible for transforming {Haml::Parser::ParseNode} objects into
3
+ # corresponding {HamlLint::Tree::Node} objects.
4
+ #
5
+ # The parse tree generated by HAML has a number of strange cases where certain
6
+ # types of nodes are created that don't necessarily correspond to what one
7
+ # would expect. This class is intended to isolate and handle these cases so
8
+ # that linters don't have to deal with them.
9
+ class NodeTransformer
10
+ # Creates a node transformer for the given parser context.
11
+ #
12
+ # @param parser [HamlLint::Parser]
13
+ def initialize(parser)
14
+ @parser = parser
15
+ end
16
+
17
+ # Transforms the given {Haml::Parser::ParseNode} into its corresponding
18
+ # {HamlLint::Tree::Node}.
19
+ def transform(haml_node)
20
+ node_class = "#{HamlLint::Utils.camel_case(haml_node.type.to_s)}Node"
21
+
22
+ HamlLint::Tree.const_get(node_class).new(@parser, haml_node)
23
+ rescue NameError
24
+ # TODO: Wrap in parser error?
25
+ raise
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,89 @@
1
+ require 'optparse'
2
+
3
+ module HamlLint
4
+ # Handles option parsing for the command line application.
5
+ class Options
6
+ # Parses command line options into an options hash.
7
+ #
8
+ # @param args [Array<String>] arguments passed via the command line
9
+ # @return [Hash] parsed options
10
+ def parse(args)
11
+ @options = {}
12
+
13
+ OptionParser.new do |parser|
14
+ parser.banner = "Usage: #{APP_NAME} [options] [file1, file2, ...]"
15
+
16
+ add_linter_options parser
17
+ add_file_options parser
18
+ add_info_options parser
19
+ end.parse!(args)
20
+
21
+ # Any remaining arguments are assumed to be files
22
+ @options[:files] = args
23
+
24
+ @options
25
+ rescue OptionParser::InvalidOption => ex
26
+ raise Exceptions::InvalidCLIOption,
27
+ ex.message,
28
+ ex.backtrace
29
+ end
30
+
31
+ private
32
+
33
+ def add_linter_options(parser)
34
+ parser.on('-e', '--exclude file,...', Array,
35
+ 'List of file names to exclude') do |files|
36
+ @options[:excluded_files] = files
37
+ end
38
+
39
+ parser.on('-i', '--include-linter linter,...', Array,
40
+ 'Specify which linters you want to run') do |linters|
41
+ @options[:included_linters] = linters
42
+ end
43
+
44
+ parser.on('-x', '--exclude-linter linter,...', Array,
45
+ "Specify which linters you don't want to run") do |linters|
46
+ @options[:excluded_linters] = linters
47
+ end
48
+
49
+ parser.on('-r', '--reporter reporter', String,
50
+ 'Specify which reporter you want to use to generate the output') do |reporter|
51
+ @options[:reporter] = HamlLint::Reporter.const_get("#{reporter.capitalize}Reporter")
52
+ end
53
+ end
54
+
55
+ def add_file_options(parser)
56
+ parser.on('-c', '--config config-file', String,
57
+ 'Specify which configuration file you want to use') do |conf_file|
58
+ @options[:config_file] = conf_file
59
+ end
60
+
61
+ parser.on('-e', '--exclude file,...', Array,
62
+ 'List of file names to exclude') do |files|
63
+ @options[:excluded_files] = files
64
+ end
65
+ end
66
+
67
+ def add_info_options(parser)
68
+ parser.on('--show-linters', 'Display available linters') do
69
+ @options[:show_linters] = true
70
+ end
71
+
72
+ parser.on('--show-reporters', 'Display available reporters') do
73
+ @options[:show_reporters] = true
74
+ end
75
+
76
+ parser.on('--[no-]color', 'Force output to be colorized') do |color|
77
+ @options[:color] = color
78
+ end
79
+
80
+ parser.on_tail('-h', '--help', 'Display help documentation') do
81
+ @options[:help] = parser.help
82
+ end
83
+
84
+ parser.on_tail('-v', '--version', 'Display version') do
85
+ @options[:version] = true
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,87 @@
1
+ require 'haml'
2
+
3
+ module HamlLint
4
+ # Parses a HAML document for inspection by linters.
5
+ class Parser
6
+ attr_reader :contents, :filename, :lines, :tree
7
+
8
+ # Creates a parser containing the parse tree of a HAML document.
9
+ #
10
+ # @param haml_or_filename [String]
11
+ # @param options [Hash]
12
+ # @option options [true,false] 'skip_frontmatter' Whether to skip
13
+ # frontmatter included by frameworks such as Middleman or Jekyll
14
+ def initialize(haml_or_filename, options = {})
15
+ if File.exist?(haml_or_filename)
16
+ build_from_file(haml_or_filename)
17
+ else
18
+ build_from_string(haml_or_filename)
19
+ end
20
+
21
+ process_options(options)
22
+
23
+ build_parse_tree
24
+ end
25
+
26
+ private
27
+
28
+ # @param path [String]
29
+ def build_from_file(path)
30
+ @filename = path
31
+ @contents = File.read(path)
32
+ end
33
+
34
+ # @param haml [String]
35
+ def build_from_string(haml)
36
+ @contents = haml
37
+ end
38
+
39
+ def build_parse_tree
40
+ original_tree = Haml::Parser.new(@contents, Haml::Options.new).parse
41
+
42
+ # Remove the trailing empty HAML comment that the parser creates to signal
43
+ # the end of the HAML document
44
+ if Gem::Requirement.new('~> 4.0.0').satisfied_by?(Gem.loaded_specs['haml'].version)
45
+ original_tree.children.pop
46
+ end
47
+
48
+ @node_transformer = HamlLint::NodeTransformer.new(self)
49
+ @tree = convert_tree(original_tree)
50
+ end
51
+
52
+ def process_options(options)
53
+ if options['skip_frontmatter'] &&
54
+ @contents =~ /
55
+ # From the start of the string
56
+ \A
57
+ # First-capture match --- followed by optional whitespace up
58
+ # to a newline then 0 or more chars followed by an optional newline.
59
+ # This matches the --- and the contents of the frontmatter
60
+ (---\s*\n.*?\n?)
61
+ # From the start of the line
62
+ ^
63
+ # Second capture match --- or ... followed by optional whitespace
64
+ # and newline. This matches the closing --- for the frontmatter.
65
+ (---|\.\.\.)\s*$\n?/mx
66
+ @contents = $POSTMATCH
67
+ end
68
+
69
+ @lines = @contents.split("\n")
70
+ end
71
+
72
+ # Converts a HAML parse tree to a tree of {HamlLint::Tree::Node} objects.
73
+ #
74
+ # This provides a cleaner interface with which the linters can interact with
75
+ # the parse tree.
76
+ def convert_tree(haml_node, parent = nil)
77
+ new_node = @node_transformer.transform(haml_node)
78
+ new_node.parent = parent
79
+
80
+ new_node.children = haml_node.children.map do |child|
81
+ convert_tree(child, new_node)
82
+ end
83
+
84
+ new_node
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,107 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ module HamlLint
5
+ # Rake task interface for haml-lint command line interface.
6
+ #
7
+ # @example
8
+ # # Add the following to your Rakefile...
9
+ # require 'haml_lint/rake_task'
10
+ #
11
+ # HamlLint::RakeTask.new do |t|
12
+ # t.config = 'path/to/custom/haml-lint.yml'
13
+ # t.files = %w[app/views/**/*.haml custom/*.haml]
14
+ # t.quiet = true # Don't display output from haml-lint
15
+ # end
16
+ #
17
+ # # ...and then execute from the command line:
18
+ # rake haml_lint
19
+ #
20
+ # You can also specify the list of files as explicit task arguments:
21
+ #
22
+ # @example
23
+ # # Add the following to your Rakefile...
24
+ # require 'haml_lint/rake_task'
25
+ #
26
+ # HamlLint::RakeTask.new
27
+ #
28
+ # # ...and then execute from the command line (single quotes prevent shell
29
+ # # glob expansion and allow us to have a space after commas):
30
+ # rake 'haml_lint[app/views/**/*.haml, other_files/**/*.haml]'
31
+ #
32
+ class RakeTask < Rake::TaskLib
33
+ # Name of the task.
34
+ # @return [String]
35
+ attr_accessor :name
36
+
37
+ # Configuration file to use.
38
+ # @return [String]
39
+ attr_accessor :config
40
+
41
+ # List of files to lint (can contain shell globs).
42
+ #
43
+ # Note that this will be ignored if you explicitly pass a list of files as
44
+ # task arguments via the command line or a task definition.
45
+ # @return [Array<String>]
46
+ attr_accessor :files
47
+
48
+ # Whether output from haml-lint should not be displayed to the standard out
49
+ # stream.
50
+ # @return [true,false]
51
+ attr_accessor :quiet
52
+
53
+ # Create the task so it exists in the current namespace.
54
+ def initialize(name = :haml_lint)
55
+ @name = name
56
+ @files = ['.'] # Search for everything under current directory by default
57
+ @quiet = false
58
+
59
+ yield self if block_given?
60
+
61
+ define
62
+ end
63
+
64
+ private
65
+
66
+ def define
67
+ desc default_description unless ::Rake.application.last_description
68
+
69
+ task(name, [:files]) do |_task, task_args|
70
+ # Lazy-load so task doesn't affect Rakefile load time
71
+ require 'haml_lint'
72
+ require 'haml_lint/cli'
73
+
74
+ run_cli(task_args)
75
+ end
76
+ end
77
+
78
+ def run_cli(task_args)
79
+ cli_args = ['--config', config] if config
80
+
81
+ logger = quiet ? HamlLint::Logger.silent : HamlLint::Logger.new(STDOUT)
82
+ result = HamlLint::CLI.new(logger).run(Array(cli_args) + files_to_lint(task_args))
83
+
84
+ fail "haml-lint failed with exit code #{result}" unless result == 0
85
+ end
86
+
87
+ def files_to_lint(task_args)
88
+ # Note: we're abusing Rake's argument handling a bit here. We call the
89
+ # first argument `files` but it's actually only the first file--we pull
90
+ # the rest out of the `extras` from the task arguments. This is so we
91
+ # can specify an arbitrary list of files separated by commas on the
92
+ # command line or in a custom task definition.
93
+ explicit_files = Array(task_args[:files]) + Array(task_args.extras)
94
+
95
+ explicit_files.any? ? explicit_files : files
96
+ end
97
+
98
+ # Friendly description that shows the full command that will be executed.
99
+ def default_description
100
+ description = 'Run `haml-lint'
101
+ description += " --config #{config}" if config
102
+ description += " #{files.join(' ')}" if files.any?
103
+ description += ' [files...]`'
104
+ description
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,16 @@
1
+ module HamlLint
2
+ # Contains information about all lints detected during a scan.
3
+ class Report
4
+ attr_accessor :lints
5
+ attr_reader :files
6
+
7
+ def initialize(lints, files)
8
+ @lints = lints.sort_by { |l| [l.filename, l.line] }
9
+ @files = files
10
+ end
11
+
12
+ def failed?
13
+ @lints.any?
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,39 @@
1
+ module HamlLint
2
+ # Outputs lints in a simple format with the filename, line number, and lint
3
+ # message.
4
+ class Reporter::DefaultReporter < Reporter
5
+ def report_lints
6
+ sorted_lints = lints.sort_by { |l| [l.filename, l.line] }
7
+
8
+ sorted_lints.each do |lint|
9
+ print_location(lint)
10
+ print_type(lint)
11
+ print_message(lint)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def print_location(lint)
18
+ log.info lint.filename, false
19
+ log.log ':', false
20
+ log.bold lint.line, false
21
+ end
22
+
23
+ def print_type(lint)
24
+ if lint.error?
25
+ log.error ' [E] ', false
26
+ else
27
+ log.warning ' [W] ', false
28
+ end
29
+ end
30
+
31
+ def print_message(lint)
32
+ if lint.linter
33
+ log.success("#{lint.linter.name}: ", false)
34
+ end
35
+
36
+ log.log lint.message
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,44 @@
1
+ module HamlLint
2
+ # Outputs report as a JSON document.
3
+ class Reporter::JsonReporter < Reporter
4
+ def report_lints
5
+ grouped = lints.group_by(&:filename)
6
+
7
+ report = {
8
+ metadata: {
9
+ hamllint_version: VERSION,
10
+ ruby_engine: RUBY_ENGINE,
11
+ ruby_patchlevel: RUBY_PATCHLEVEL.to_s,
12
+ ruby_platform: RUBY_PLATFORM,
13
+ },
14
+ files: grouped.map { |l| map_file(l) },
15
+ summary: {
16
+ offense_count: lints.length,
17
+ target_file_count: grouped.length,
18
+ inspected_file_count: files.length,
19
+ },
20
+ }
21
+
22
+ log.log report.to_json
23
+ end
24
+
25
+ private
26
+
27
+ def map_file(file)
28
+ {
29
+ path: file.first,
30
+ offenses: file.last.map { |o| map_offense(o) },
31
+ }
32
+ end
33
+
34
+ def map_offense(offense)
35
+ {
36
+ severity: offense.severity,
37
+ message: offense.message,
38
+ location: {
39
+ line: offense.line,
40
+ },
41
+ }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,36 @@
1
+ module HamlLint
2
+ # Abstract lint reporter. Subclass and override {#report_lints} to
3
+ # implement a custom lint reporter.
4
+ #
5
+ # @abstract
6
+ class Reporter
7
+ attr_reader :lints
8
+ attr_reader :files
9
+
10
+ # @param logger [HamlLint::Logger]
11
+ # @param report [HamlLint::Report]
12
+ def initialize(logger, report)
13
+ @log = logger
14
+ @lints = report.lints
15
+ @files = report.files
16
+ end
17
+
18
+ # Implemented by subclasses to display lints from a {HamlLint::Report}.
19
+ def report_lints
20
+ raise NotImplementedError
21
+ end
22
+
23
+ # Keep tracking all the descendants of this class for the list of available reporters
24
+ def self.descendants
25
+ @descendants ||= []
26
+ end
27
+
28
+ def self.inherited(descendant)
29
+ descendants << descendant
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :log
35
+ end
36
+ end
@@ -0,0 +1,29 @@
1
+ require 'astrolabe/builder'
2
+ require 'parser/current'
3
+
4
+ module HamlLint
5
+ # Parser for the Ruby language.
6
+ #
7
+ # This provides a convenient wrapper around the `parser` gem and the
8
+ # `astrolabe` integration to go with it. It is intended to be used for linter
9
+ # checks that require deep inspection of Ruby code.
10
+ class RubyParser
11
+ # Creates a reusable parser.
12
+ def initialize
13
+ @builder = ::Astrolabe::Builder.new
14
+ @parser = ::Parser::CurrentRuby.new(@builder)
15
+ end
16
+
17
+ # Parse the given Ruby source into an abstract syntax tree.
18
+ #
19
+ # @param source [String] Ruby source code
20
+ # @return [Array] syntax tree in the form returned by Parser gem
21
+ def parse(source)
22
+ buffer = ::Parser::Source::Buffer.new('(string)')
23
+ buffer.source = source
24
+
25
+ @parser.reset
26
+ @parser.parse(buffer)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,76 @@
1
+ module HamlLint
2
+ # Responsible for running the applicable linters against the desired files.
3
+ class Runner
4
+ # Make the list of applicable files available
5
+ attr_reader :files
6
+
7
+ # Runs the appropriate linters against the desired files given the specified
8
+ # options.
9
+ #
10
+ # @param options [Hash]
11
+ # @raise [HamlLint::Exceptions::NoLintersError] when no linters are enabled
12
+ # @return [HamlLint::Report] a summary of all lints found
13
+ def run(options = {})
14
+ config = load_applicable_config(options)
15
+ files = extract_applicable_files(options, config)
16
+ linters = extract_enabled_linters(config, options)
17
+
18
+ raise HamlLint::Exceptions::NoLintersError, 'No linters specified' if linters.empty?
19
+
20
+ @lints = []
21
+ files.each do |file|
22
+ find_lints(file, linters, config)
23
+ end
24
+
25
+ linters.each do |linter|
26
+ @lints += linter.lints
27
+ end
28
+
29
+ HamlLint::Report.new(@lints, files)
30
+ end
31
+
32
+ private
33
+
34
+ def load_applicable_config(options)
35
+ if options[:config_file]
36
+ HamlLint::ConfigurationLoader.load_file(options[:config_file])
37
+ else
38
+ HamlLint::ConfigurationLoader.load_applicable_config
39
+ end
40
+ end
41
+
42
+ def extract_enabled_linters(config, options)
43
+ included_linters = LinterRegistry
44
+ .extract_linters_from(options.fetch(:included_linters, []))
45
+
46
+ included_linters = LinterRegistry.linters if included_linters.empty?
47
+
48
+ excluded_linters = LinterRegistry
49
+ .extract_linters_from(options.fetch(:excluded_linters, []))
50
+
51
+ # After filtering out explicitly included/excluded linters, only include
52
+ # linters which are enabled in the configuration
53
+ (included_linters - excluded_linters).map do |linter_class|
54
+ linter_config = config.for_linter(linter_class)
55
+ linter_class.new(linter_config) if linter_config['enabled']
56
+ end.compact
57
+ end
58
+
59
+ def find_lints(file, linters, config)
60
+ parser = Parser.new(file, config.hash)
61
+
62
+ linters.each do |linter|
63
+ linter.run(parser)
64
+ end
65
+ rescue Haml::Error => ex
66
+ @lints << Lint.new(nil, file, ex.line, ex.to_s, :error)
67
+ end
68
+
69
+ def extract_applicable_files(options, config)
70
+ included_patterns = options[:files]
71
+ excluded_files = options.fetch(:excluded_files, [])
72
+
73
+ HamlLint::FileFinder.new(config).find(included_patterns, excluded_files)
74
+ end
75
+ end
76
+ end