haml_lint 0.23.2 → 0.24.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: 5e1e7727e9ee3dadac7fe5fbc6ba6e4a42e482b5
4
- data.tar.gz: 7176808267f479eeb56757133e8c0015c4841b77
3
+ metadata.gz: fe12a287eaf253fd83053061ac62a26b908918e6
4
+ data.tar.gz: cf8bae7a2e75dde6befbe09a9764fb223ea72583
5
5
  SHA512:
6
- metadata.gz: c944db1432ca3b9133769fde9173b0dee6ec253f0ac1d16d5d194fce086bfce9952ae49603a196b3d9fc30dbd93572d067169490483ee01b14c36433cdb49c32
7
- data.tar.gz: e533c56866c2ad9702be3461068cb2aab5fe73c1a39eaf059bfae0850628a1145c67e832eae29f663f6b336d96bff8851d0dcafd8feebb1972767af8c89c6e67
6
+ metadata.gz: 55334bc83c7c8f377c78b290db34ba08a2939bd9179e06541d27f3919118d3942500c85a5028ad2dde31a868ac82c4bd49b7ebf6492ec14400ae0f8b213e72d5
7
+ data.tar.gz: 84e178971e6068b40dd896f49efac863a244a8ed952b4d4d45d93872d6a2030a68134721c2cffbba94cffc5d3b11b88283b487c35a1d3907132eab86df44eb26
data/config/default.yml CHANGED
@@ -47,6 +47,11 @@ linters:
47
47
  ImplicitDiv:
48
48
  enabled: true
49
49
 
50
+ Indentation:
51
+ enabled: true
52
+ character: space # or tab
53
+ width: 2 # ignored if character == tab
54
+
50
55
  InstanceVariables:
51
56
  enabled: true
52
57
  file_types: partials
@@ -108,10 +113,6 @@ linters:
108
113
  enabled: true
109
114
  style: space
110
115
 
111
- Indentation:
112
- enabled: true
113
- character: space # or tab
114
-
115
116
  TagName:
116
117
  enabled: true
117
118
 
data/lib/haml_lint/cli.rb CHANGED
@@ -83,12 +83,26 @@ module HamlLint
83
83
  end
84
84
  end
85
85
 
86
+ # Instantiates a new reporter based on the options.
87
+ #
88
+ # @param options [HamlLint::Configuration]
89
+ # @option options [true, nil] :auto_gen_config whether to use the config
90
+ # generating reporter
91
+ # @option options [Class] :reporter the class of reporter to use
92
+ # @return [HamlLint::Reporter]
93
+ def reporter_from_options(options)
94
+ if options[:auto_gen_config]
95
+ HamlLint::Reporter::DisabledConfigReporter.new(log)
96
+ else
97
+ options.fetch(:reporter, HamlLint::Reporter::DefaultReporter).new(log)
98
+ end
99
+ end
100
+
86
101
  # Scans the files specified by the given options for lints.
87
102
  #
88
103
  # @return [Integer] exit status code
89
104
  def scan_for_lints(options)
90
- reporter = options.fetch(:reporter,
91
- HamlLint::Reporter::DefaultReporter).new(log)
105
+ reporter = reporter_from_options(options)
92
106
  report = Runner.new.run(options.merge(reporter: reporter))
93
107
  report.display
94
108
  report.failed? ? Sysexits::EX_DATAERR : Sysexits::EX_OK
@@ -6,6 +6,7 @@ require 'yaml'
6
6
  module HamlLint
7
7
  # Manages configuration file loading.
8
8
  class ConfigurationLoader
9
+ AUTO_GENERATED_FILE = '.haml-lint_todo.yml'.freeze
9
10
  DEFAULT_CONFIG_PATH = File.join(HamlLint::HOME, 'config', 'default.yml').freeze
10
11
  CONFIG_FILE_NAME = '.haml-lint.yml'.freeze
11
12
 
@@ -31,11 +32,14 @@ module HamlLint
31
32
  # Loads a configuration, ensuring it extends the default configuration.
32
33
  #
33
34
  # @param file [String]
35
+ # @param loaded_files [Array<String>] any previously loaded files in an
36
+ # inheritance chain
34
37
  # @return [HamlLint::Configuration]
35
- def load_file(file)
38
+ def load_file(file, loaded_files = [])
36
39
  config = load_from_file(file)
37
40
 
38
- default_configuration.merge(config)
41
+ [default_configuration, resolve_inheritance(config, loaded_files), config]
42
+ .reduce { |acc, elem| acc.merge(elem) }
39
43
  rescue Psych::SyntaxError, Errno::ENOENT => error
40
44
  raise HamlLint::Exceptions::ConfigurationError,
41
45
  "Unable to load configuration from '#{file}': #{error}",
@@ -67,6 +71,11 @@ module HamlLint
67
71
  {}
68
72
  end
69
73
 
74
+ if hash.key?('inherit_from')
75
+ hash['inherits_from'] ||= []
76
+ hash['inherits_from'].concat(Array(hash.delete('inherit_from')))
77
+ end
78
+
70
79
  HamlLint::Configuration.new(hash)
71
80
  end
72
81
 
@@ -81,6 +90,33 @@ module HamlLint
81
90
  .map { |path| path + CONFIG_FILE_NAME }
82
91
  files << Pathname.new(CONFIG_FILE_NAME)
83
92
  end
93
+
94
+ # Resolves an inherited file and loads it.
95
+ #
96
+ # @param file [String] the path to the file
97
+ # @param loaded_files [Array<String>] previously loaded files in the
98
+ # inheritance chain
99
+ # @return [HamlLint::Configuration, nil]
100
+ def resolve(file, loaded_files)
101
+ return unless File.exist?(file)
102
+ return if loaded_files.include?(file)
103
+
104
+ loaded_files << file
105
+ load_file(file, loaded_files)
106
+ end
107
+
108
+ # Resolves the chain of `inherits_from` directives in a configuration.
109
+ #
110
+ # @param config [HamlLint::Configuration] the pre-existing configuration
111
+ # @param loaded_files [Array<String>] any previously loaded files in an
112
+ # inheritance chain
113
+ # @return [HamlLint::Configuration]
114
+ def resolve_inheritance(config, loaded_files)
115
+ Array(config['inherits_from'])
116
+ .map { |config_file| resolve(config_file, loaded_files) }
117
+ .compact
118
+ .reduce { |acc, elem| acc.merge(elem) } || config
119
+ end
84
120
  end
85
121
  end
86
122
  end
@@ -9,15 +9,51 @@ module HamlLint
9
9
  tab: /^\t*(?![ ])/,
10
10
  }.freeze
11
11
 
12
+ LEADING_SPACES_REGEX = /^( +)(?! )/
13
+
12
14
  def visit_root(root)
13
- regex = INDENT_REGEX[config['character'].to_sym]
15
+ character = config['character'].to_sym
16
+ check_character(character, root)
17
+
18
+ width = config['width'].to_i
19
+ check_width(width, root) if character == :space && width > 0
20
+ end
21
+
22
+ private
23
+
24
+ # validate that indentation matches config characters (either spaces or tabs)
25
+ def check_character(character, root)
26
+ wrong_characters = character == :space ? 'tabs' : 'spaces'
27
+ regex = INDENT_REGEX[character]
14
28
  dummy_node = Struct.new(:line)
15
29
 
16
30
  document.source_lines.each_with_index do |line, index|
17
31
  next if line =~ regex
18
32
 
19
33
  unless root.node_for_line(index).disabled?(self)
20
- record_lint dummy_node.new(index + 1), 'Line contains tabs in indentation'
34
+ record_lint dummy_node.new(index + 1), "Line contains #{wrong_characters} in indentation"
35
+ end
36
+ end
37
+ end
38
+
39
+ # validate that indentation matches config width (only for spaces)
40
+ def check_width(width, root)
41
+ dummy_node = Struct.new(:line)
42
+
43
+ root.children.each do |top_node|
44
+ # once we've found one line with leading space, there's no need to check any more lines
45
+ # `haml` will check indenting_at_start, deeper_indenting, inconsistent_indentation
46
+ break if top_node.children.find do |node|
47
+ line = node.source_code
48
+ leading_space = LEADING_SPACES_REGEX.match(line)
49
+
50
+ break unless leading_space && !node.disabled?(self)
51
+
52
+ if leading_space[1] != ' ' * width
53
+ record_lint dummy_node.new(node.line), "File does not use #{width}-space indentation"
54
+ end
55
+
56
+ break true
21
57
  end
22
58
  end
23
59
  end
@@ -27,6 +27,16 @@ module HamlLint
27
27
  @lints = []
28
28
  visit(document.tree)
29
29
  @lints
30
+ rescue Parser::SyntaxError => ex
31
+ location = ex.diagnostic.location
32
+ @lints <<
33
+ HamlLint::Lint.new(
34
+ HamlLint::Linter::Syntax.new(config),
35
+ document.file,
36
+ location.line,
37
+ ex.to_s,
38
+ :error
39
+ )
30
40
  end
31
41
 
32
42
  # Returns the simple name for this linter.
@@ -21,7 +21,7 @@ module HamlLint
21
21
  end.parse!(args)
22
22
 
23
23
  # Any remaining arguments are assumed to be files
24
- @options[:files] = args
24
+ @options[:files] = args.empty? ? ["."] : args
25
25
 
26
26
  @options
27
27
  rescue OptionParser::InvalidOption => ex
@@ -33,6 +33,10 @@ module HamlLint
33
33
  private
34
34
 
35
35
  def add_linter_options(parser)
36
+ parser.on('--auto-gen-config', 'Generate a configuration file acting as a TODO list') do
37
+ @options[:auto_gen_config] = true
38
+ end
39
+
36
40
  parser.on('-i', '--include-linter linter,...', Array,
37
41
  'Specify which linters you want to run') do |linters|
38
42
  @options[:included_linters] = linters
@@ -0,0 +1,105 @@
1
+ require 'haml_lint/reporter/progress_reporter'
2
+
3
+ module HamlLint
4
+ # Outputs a YAML configuration file based on existing violations.
5
+ class Reporter::DisabledConfigReporter < Reporter::ProgressReporter
6
+ HEADING =
7
+ ['# This configuration was generated by',
8
+ '# `haml-lint --auto-gen-config`',
9
+ "# on #{Time.now} using Haml-Lint version #{HamlLint::VERSION}.",
10
+ '# The point is for the user to remove these configuration records',
11
+ '# one by one as the lints are removed from the code base.',
12
+ '# Note that changes in the inspected code, or installation of new',
13
+ '# versions of Haml-Lint, may require this file to be generated again.']
14
+ .join("\n")
15
+
16
+ # Disables this reporter on the CLI since it doesn't output anything.
17
+ #
18
+ # @return [false]
19
+ def self.available?
20
+ false
21
+ end
22
+
23
+ # Create the reporter that will display the report and write the config.
24
+ #
25
+ # @param _log [HamlLint::Logger]
26
+ def initialize(_log)
27
+ super
28
+ @linters_with_lints = Hash.new { |hash, key| hash[key] = [] }
29
+ @linters_lint_count = Hash.new(0)
30
+ end
31
+
32
+ # A hash of linters with the files that have that type of lint.
33
+ #
34
+ # @return [Hash<String, Integer] a Hash with linter name keys and lint
35
+ # count values
36
+ attr_reader :linters_lint_count
37
+
38
+ # A hash of linters with the files that have that type of lint.
39
+ #
40
+ # @return [Hash<String, Array<String>>] a Hash with linter name keys and file
41
+ # name list values
42
+ attr_reader :linters_with_lints
43
+
44
+ # Prints the standard progress reporter output and writes the new config file.
45
+ #
46
+ # @param report [HamlLint::Report]
47
+ # @return [void]
48
+ def display_report(report)
49
+ super
50
+
51
+ File.write(ConfigurationLoader::AUTO_GENERATED_FILE, config_file_contents)
52
+ log.log "Created #{ConfigurationLoader::AUTO_GENERATED_FILE}."
53
+ log.log "Run `haml-lint --config #{ConfigurationLoader::AUTO_GENERATED_FILE}`" \
54
+ ", or add `inherits_from: #{ConfigurationLoader::AUTO_GENERATED_FILE}` in a " \
55
+ '.haml-lint.yml file.'
56
+ end
57
+
58
+ # Prints the standard progress report marks and tracks files with lint.
59
+ #
60
+ # @param file [String]
61
+ # @param lints [Array<HamlLint::Lint>]
62
+ # @return [void]
63
+ def finished_file(file, lints)
64
+ super
65
+
66
+ if lints.any?
67
+ lints.each do |lint|
68
+ linters_with_lints[lint.linter.name] |= [lint.filename]
69
+ linters_lint_count[lint.linter.name] += 1
70
+ end
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ # The contents of the generated configuration file based on captured lint.
77
+ #
78
+ # @return [String] a Yaml-formatted configuration file's contents
79
+ def config_file_contents
80
+ output = []
81
+ output << HEADING
82
+ output << 'linters:' if linters_with_lints.any?
83
+ linters_with_lints.each do |linter, files|
84
+ output << generate_config_for_linter(linter, files)
85
+ end
86
+ output.join("\n\n")
87
+ end
88
+
89
+ # Constructs the configuration for excluding a linter in some files.
90
+ #
91
+ # @param linter [String] the name of the linter to exclude
92
+ # @param files [Array<String>] the files in which the linter is excluded
93
+ # @return [String] a Yaml-formatted configuration
94
+ def generate_config_for_linter(linter, files)
95
+ [].tap do |output|
96
+ output << " # Offense count: #{linters_lint_count[linter]}"
97
+ output << " #{linter}:"
98
+ output << ' exclude:'
99
+ files.each do |filename|
100
+ output << %{ - "#{filename}"}
101
+ end
102
+ end.join("\n")
103
+ end
104
+ end
105
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Defines the gem version.
4
4
  module HamlLint
5
- VERSION = '0.23.2'.freeze
5
+ VERSION = '0.24.0'.freeze
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haml_lint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.2
4
+ version: 0.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brigade Engineering
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-03-15 00:00:00.000000000 Z
12
+ date: 2017-03-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: haml
@@ -160,6 +160,7 @@ files:
160
160
  - lib/haml_lint/reporter.rb
161
161
  - lib/haml_lint/reporter/checkstyle_reporter.rb
162
162
  - lib/haml_lint/reporter/default_reporter.rb
163
+ - lib/haml_lint/reporter/disabled_config_reporter.rb
163
164
  - lib/haml_lint/reporter/hash_reporter.rb
164
165
  - lib/haml_lint/reporter/hooks.rb
165
166
  - lib/haml_lint/reporter/json_reporter.rb