haml_lint 0.69.0 → 0.74.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +9 -4
  3. data/lib/haml_lint/cli.rb +5 -1
  4. data/lib/haml_lint/document.rb +0 -5
  5. data/lib/haml_lint/linter/class_attribute_with_static_value.rb +51 -11
  6. data/lib/haml_lint/linter/classes_before_ids.rb +16 -1
  7. data/lib/haml_lint/linter/consecutive_comments.rb +20 -1
  8. data/lib/haml_lint/linter/empty_object_reference.rb +16 -1
  9. data/lib/haml_lint/linter/empty_script.rb +31 -1
  10. data/lib/haml_lint/linter/final_newline.rb +31 -7
  11. data/lib/haml_lint/linter/implicit_div.rb +14 -1
  12. data/lib/haml_lint/linter/leading_comment_space.rb +13 -1
  13. data/lib/haml_lint/linter/multiline_script.rb +65 -5
  14. data/lib/haml_lint/linter/rubocop.rb +6 -18
  15. data/lib/haml_lint/linter/ruby_comments.rb +13 -3
  16. data/lib/haml_lint/linter/space_before_script.rb +36 -3
  17. data/lib/haml_lint/linter/space_inside_hash_attributes.rb +41 -3
  18. data/lib/haml_lint/linter/tag_name.rb +14 -1
  19. data/lib/haml_lint/linter/trailing_empty_lines.rb +13 -1
  20. data/lib/haml_lint/linter/trailing_whitespace.rb +15 -2
  21. data/lib/haml_lint/linter/unescaped_html.rb +27 -0
  22. data/lib/haml_lint/linter/unnecessary_interpolation.rb +30 -3
  23. data/lib/haml_lint/linter/unnecessary_string_output.rb +34 -2
  24. data/lib/haml_lint/linter.rb +111 -0
  25. data/lib/haml_lint/reporter/disabled_config_reporter.rb +26 -5
  26. data/lib/haml_lint/reporter/github_reporter.rb +26 -8
  27. data/lib/haml_lint/ruby_extraction/chunk_extractor.rb +41 -5
  28. data/lib/haml_lint/ruby_extraction/coordinator.rb +7 -2
  29. data/lib/haml_lint/runner.rb +17 -3
  30. data/lib/haml_lint/source.rb +2 -6
  31. data/lib/haml_lint/tree/filter_node.rb +13 -0
  32. data/lib/haml_lint/tree/tag_node.rb +55 -23
  33. data/lib/haml_lint/version.rb +1 -1
  34. metadata +5 -4
@@ -28,8 +28,12 @@ module HamlLint::RubyExtraction
28
28
  # @return [Array<String>] The ruby lines after correction by RuboCop
29
29
  attr_reader :corrected_ruby_lines
30
30
 
31
- def initialize(document)
31
+ # @return [Symbol, nil] The autocorrect mode (:safe, :all, or nil)
32
+ attr_reader :autocorrect
33
+
34
+ def initialize(document, autocorrect:)
32
35
  @document = document
36
+ @autocorrect = autocorrect
33
37
  @ruby_chunks = nil
34
38
  @assembled_ruby_lines = nil
35
39
  @corrected_ruby_lines = nil
@@ -46,7 +50,8 @@ module HamlLint::RubyExtraction
46
50
  pick_a_script_output_prefix
47
51
 
48
52
  @ruby_chunks = HamlLint::RubyExtraction::ChunkExtractor.new(@document,
49
- script_output_prefix: @script_output_prefix).extract
53
+ script_output_prefix: @script_output_prefix,
54
+ autocorrect: autocorrect).extract
50
55
  preprocess_chunks
51
56
 
52
57
  @assembled_ruby_lines = []
@@ -23,7 +23,8 @@ module HamlLint
23
23
  def run(options = {})
24
24
  @config = load_applicable_config(options)
25
25
  @sources = extract_applicable_sources(config, options)
26
- @linter_selector = HamlLint::LinterSelector.new(config, options)
26
+ @options = options
27
+ @linter_selector = build_linter_selector
27
28
  @fail_fast = options.fetch(:fail_fast, false)
28
29
  @cache = {}
29
30
  @autocorrect = options[:autocorrect]
@@ -61,6 +62,17 @@ module HamlLint
61
62
  # @return [HamlLint::LinterSelector]
62
63
  attr_reader :linter_selector
63
64
 
65
+ # Returns a fresh selector for this run.
66
+ #
67
+ # LinterSelector memoizes linter instances, and linters mutate instance
68
+ # state while processing a document. JRuby runs Parallel.map in threads, so
69
+ # parallel jobs must not share a selector.
70
+ #
71
+ # @return [HamlLint::LinterSelector]
72
+ def build_linter_selector
73
+ HamlLint::LinterSelector.new(config, @options)
74
+ end
75
+
64
76
  # Returns the {HamlLint::Configuration} that should be used given the
65
77
  # specified options.
66
78
  #
@@ -89,7 +101,6 @@ module HamlLint
89
101
  begin
90
102
  document = HamlLint::Document.new source.contents, file: source.path,
91
103
  config: config,
92
- file_on_disk: !source.stdin?,
93
104
  write_to_stdout: @autocorrect_stdout
94
105
  rescue HamlLint::Exceptions::ParseError => e
95
106
  return [HamlLint::Lint.new(HamlLint::Linter::Syntax.new(config), source.path,
@@ -122,6 +133,9 @@ module HamlLint
122
133
  lint_arrays = []
123
134
 
124
135
  autocorrecting_linters = linters.select(&:supports_autocorrect?)
136
+ .each_with_index
137
+ .sort_by { |linter, index| [linter.class.autocorrect_priority, index] }
138
+ .map(&:first)
125
139
  lint_arrays << autocorrecting_linters.map do |linter|
126
140
  linter.run(document, autocorrect: @autocorrect)
127
141
  end
@@ -191,7 +205,7 @@ module HamlLint
191
205
  # @return [void]
192
206
  def warm_cache
193
207
  results = Parallel.map(sources) do |source|
194
- lints = collect_lints(source, linter_selector, config)
208
+ lints = collect_lints(source, build_linter_selector, config)
195
209
  [source.path, lints]
196
210
  end
197
211
  @cache = results.to_h
@@ -13,17 +13,13 @@ module HamlLint
13
13
  # @param [IO] io
14
14
  def initialize(path: nil, io: nil)
15
15
  @path = path
16
+ @file_path = File.expand_path(path) if path
16
17
  @io = io
17
18
  end
18
19
 
19
20
  # @return [String] Contents of the given IO object.
20
21
  def contents
21
- @contents ||= @io&.read || File.read(path)
22
- end
23
-
24
- # @return [boolean] true if we're reading from stdin rather than a file path
25
- def stdin?
26
- !@io.nil?
22
+ @contents ||= @io&.read || File.read(@file_path)
27
23
  end
28
24
  end
29
25
  end
@@ -17,5 +17,18 @@ module HamlLint::Tree
17
17
 
18
18
  "#{"\n" * nb_blank_lines}#{super}"
19
19
  end
20
+
21
+ # The line numbers that are contained within the node.
22
+ #
23
+ # Unlike most nodes, a filter's content begins on the line *after* the
24
+ # `:filtername` declaration, so the span runs from the declaration line
25
+ # through all of the indented content lines.
26
+ #
27
+ # @return [Range]
28
+ def line_numbers
29
+ return super if lines.empty?
30
+
31
+ (line..(line + lines.count))
32
+ end
20
33
  end
21
34
  end
@@ -33,6 +33,16 @@ module HamlLint::Tree
33
33
  @value[:parse] && !@value[:value].strip.empty?
34
34
  end
35
35
 
36
+ # Whether this tag outputs unescaped HTML via a `!` marker, e.g. `%tag!=` or
37
+ # `%tag!~`.
38
+ #
39
+ # @return [true,false]
40
+ def unescape_html?
41
+ return false unless contains_script?
42
+
43
+ /\A\s*[<>]*\s*!/.match?(inline_marker_source)
44
+ end
45
+
36
46
  # Returns whether this tag has a specified attribute.
37
47
  #
38
48
  # @return [true,false]
@@ -94,30 +104,18 @@ module HamlLint::Tree
94
104
  #
95
105
  # @return [Hash]
96
106
  def attributes_source
97
- @attributes_source ||=
98
- begin
99
- _explicit_tag, static_attrs, rest =
100
- source_code.scan(/\A\s*(%[-:\w]+)?([-:\w.\#]*)(.*)/m)[0]
101
-
102
- attr_types = {
103
- '{' => [:hash, %w[{ }]],
104
- '(' => [:html, %w[( )]],
105
- '[' => [:object_ref, %w[[ ]]],
106
- }
107
-
108
- attr_source = { static: static_attrs }
109
- while rest
110
- type, chars = attr_types[rest[0]]
111
- break unless type # Not an attribute opening character, so we're done
112
-
113
- # Can't define multiple of the same attribute type (e.g. two {...})
114
- break if attr_source[type]
115
-
116
- attr_source[type], rest = Haml::Util.balance(rest, *chars)
117
- end
107
+ parsed_attributes_source[:attributes]
108
+ end
118
109
 
119
- attr_source
120
- end
110
+ # Source that follows the tag name and attributes. It begins with the
111
+ # content marker (e.g. `=`, `!=`, `~`, `!~`, or plain text).
112
+ #
113
+ # @example For `%tag.class!= foo`, this returns:
114
+ # '!= foo'
115
+ #
116
+ # @return [String]
117
+ def inline_marker_source
118
+ parsed_attributes_source[:marker]
121
119
  end
122
120
 
123
121
  # Whether this tag node has a set of hash attributes defined via the
@@ -229,6 +227,40 @@ module HamlLint::Tree
229
227
 
230
228
  private
231
229
 
230
+ # Parses the source code following the tag name once into its attribute
231
+ # sources and the remaining inline content marker.
232
+ #
233
+ # @return [Hash{Symbol => Object}] `:attributes` source hash (keyed by
234
+ # `:static`/`:hash`/`:html`/`:object_ref`) and the `:marker` string
235
+ def parsed_attributes_source
236
+ @parsed_attributes_source ||=
237
+ begin
238
+ _explicit_tag, static_attrs, rest =
239
+ source_code.scan(/\A\s*(%[-:\w]+)?([-:\w.\#]*)(.*)/m)[0]
240
+
241
+ attr_types = {
242
+ '{' => [:hash, %w[{ }]],
243
+ '(' => [:html, %w[( )]],
244
+ '[' => [:object_ref, %w[[ ]]],
245
+ }
246
+
247
+ attr_source = { static: static_attrs }
248
+ while rest
249
+ type, chars = attr_types[rest[0]]
250
+ break unless type # Not an attribute opening character, so we're done
251
+
252
+ # Can't define multiple of the same attribute type (e.g. two {...})
253
+ break if attr_source[type]
254
+
255
+ attr_source[type], rest = Haml::Util.balance(rest, *chars)
256
+ end
257
+
258
+ # Whatever remains after the tag name and attributes begins with the
259
+ # content marker (e.g. `=`, `!=`, `~`, `!~`, or plain text).
260
+ { attributes: attr_source, marker: rest.to_s }
261
+ end
262
+ end
263
+
232
264
  def existing_attributes
233
265
  parsed_attrs = parsed_attributes
234
266
  return {} unless parsed_attrs.respond_to?(:children)
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Defines the gem version.
4
4
  module HamlLint
5
- VERSION = '0.69.0'
5
+ VERSION = '0.74.0'
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.69.0
4
+ version: 0.74.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane da Silva
@@ -27,14 +27,14 @@ dependencies:
27
27
  name: parallel
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - "~>"
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '1.10'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '1.10'
40
40
  - !ruby/object:Gem::Dependency
@@ -138,6 +138,7 @@ files:
138
138
  - lib/haml_lint/linter/tag_name.rb
139
139
  - lib/haml_lint/linter/trailing_empty_lines.rb
140
140
  - lib/haml_lint/linter/trailing_whitespace.rb
141
+ - lib/haml_lint/linter/unescaped_html.rb
141
142
  - lib/haml_lint/linter/unnecessary_interpolation.rb
142
143
  - lib/haml_lint/linter/unnecessary_string_output.rb
143
144
  - lib/haml_lint/linter/view_length.rb
@@ -218,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
218
219
  - !ruby/object:Gem::Version
219
220
  version: '0'
220
221
  requirements: []
221
- rubygems_version: 3.6.9
222
+ rubygems_version: 4.0.10
222
223
  specification_version: 4
223
224
  summary: HAML lint tool
224
225
  test_files: []