haml_lint 0.45.0 → 0.48.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.
- checksums.yaml +4 -4
- data/bin/haml-lint +1 -1
- data/config/default.yml +6 -28
- data/config/forced_rubocop_config.yml +171 -0
- data/lib/haml_lint/adapter/haml_4.rb +18 -0
- data/lib/haml_lint/adapter/haml_5.rb +11 -0
- data/lib/haml_lint/adapter/haml_6.rb +11 -0
- data/lib/haml_lint/cli.rb +8 -3
- data/lib/haml_lint/configuration_loader.rb +9 -10
- data/lib/haml_lint/document.rb +89 -8
- data/lib/haml_lint/exceptions.rb +6 -0
- data/lib/haml_lint/extensions/haml_util_unescape_interpolation_tracking.rb +35 -0
- data/lib/haml_lint/file_finder.rb +2 -2
- data/lib/haml_lint/lint.rb +10 -1
- data/lib/haml_lint/linter/final_newline.rb +4 -3
- data/lib/haml_lint/linter/implicit_div.rb +1 -1
- data/lib/haml_lint/linter/indentation.rb +3 -3
- data/lib/haml_lint/linter/no_placeholders.rb +18 -0
- data/lib/haml_lint/linter/repeated_id.rb +2 -1
- data/lib/haml_lint/linter/rubocop.rb +353 -60
- data/lib/haml_lint/linter/space_before_script.rb +8 -10
- data/lib/haml_lint/linter/unnecessary_string_output.rb +1 -1
- data/lib/haml_lint/linter/view_length.rb +1 -1
- data/lib/haml_lint/linter.rb +60 -10
- data/lib/haml_lint/linter_registry.rb +3 -5
- data/lib/haml_lint/logger.rb +2 -2
- data/lib/haml_lint/options.rb +26 -2
- data/lib/haml_lint/rake_task.rb +2 -2
- data/lib/haml_lint/reporter/hash_reporter.rb +1 -3
- data/lib/haml_lint/reporter/offense_count_reporter.rb +1 -1
- data/lib/haml_lint/reporter/utils.rb +33 -4
- data/lib/haml_lint/ruby_extraction/ad_hoc_chunk.rb +24 -0
- data/lib/haml_lint/ruby_extraction/base_chunk.rb +114 -0
- data/lib/haml_lint/ruby_extraction/chunk_extractor.rb +630 -0
- data/lib/haml_lint/ruby_extraction/coordinator.rb +181 -0
- data/lib/haml_lint/ruby_extraction/haml_comment_chunk.rb +34 -0
- data/lib/haml_lint/ruby_extraction/implicit_end_chunk.rb +17 -0
- data/lib/haml_lint/ruby_extraction/interpolation_chunk.rb +26 -0
- data/lib/haml_lint/ruby_extraction/non_ruby_filter_chunk.rb +32 -0
- data/lib/haml_lint/ruby_extraction/placeholder_marker_chunk.rb +40 -0
- data/lib/haml_lint/ruby_extraction/ruby_filter_chunk.rb +33 -0
- data/lib/haml_lint/ruby_extraction/ruby_source.rb +5 -0
- data/lib/haml_lint/ruby_extraction/script_chunk.rb +244 -0
- data/lib/haml_lint/ruby_extraction/tag_attributes_chunk.rb +63 -0
- data/lib/haml_lint/ruby_extraction/tag_script_chunk.rb +30 -0
- data/lib/haml_lint/runner.rb +35 -3
- data/lib/haml_lint/spec/matchers/report_lint.rb +22 -7
- data/lib/haml_lint/spec/normalize_indent.rb +2 -2
- data/lib/haml_lint/spec/shared_linter_context.rb +9 -1
- data/lib/haml_lint/spec/shared_rubocop_autocorrect_context.rb +158 -0
- data/lib/haml_lint/spec.rb +1 -0
- data/lib/haml_lint/tree/filter_node.rb +10 -0
- data/lib/haml_lint/tree/node.rb +13 -4
- data/lib/haml_lint/tree/tag_node.rb +5 -9
- data/lib/haml_lint/utils.rb +135 -5
- data/lib/haml_lint/version.rb +1 -1
- data/lib/haml_lint/version_comparer.rb +25 -0
- data/lib/haml_lint.rb +12 -0
- metadata +24 -6
- data/lib/haml_lint/ruby_extractor.rb +0 -223
data/lib/haml_lint.rb
CHANGED
@@ -21,8 +21,14 @@ require 'haml_lint/file_finder'
|
|
21
21
|
require 'haml_lint/runner'
|
22
22
|
require 'haml_lint/utils'
|
23
23
|
require 'haml_lint/version'
|
24
|
+
require 'haml_lint/version_comparer'
|
24
25
|
require 'haml_lint/severity'
|
25
26
|
|
27
|
+
# Lead all extensions to external source code
|
28
|
+
Dir[File.expand_path('haml_lint/extensions/*.rb', File.dirname(__FILE__))].sort.each do |file|
|
29
|
+
require file
|
30
|
+
end
|
31
|
+
|
26
32
|
# Load all parse tree node classes
|
27
33
|
require 'haml_lint/tree/node'
|
28
34
|
require 'haml_lint/node_transformer'
|
@@ -39,3 +45,9 @@ end
|
|
39
45
|
Dir[File.expand_path('haml_lint/reporter/*.rb', File.dirname(__FILE__))].sort.each do |file|
|
40
46
|
require file
|
41
47
|
end
|
48
|
+
|
49
|
+
# Load all the chunks for RubyExtraction
|
50
|
+
require 'haml_lint/ruby_extraction/base_chunk'
|
51
|
+
Dir[File.expand_path('haml_lint/ruby_extraction/*.rb', File.dirname(__FILE__))].sort.each do |file|
|
52
|
+
require file
|
53
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: haml_lint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.48.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shane da Silva
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: haml
|
@@ -64,14 +64,14 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - ">="
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: '1.0'
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
74
|
+
version: '1.0'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: sysexits
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,6 +96,7 @@ extra_rdoc_files: []
|
|
96
96
|
files:
|
97
97
|
- bin/haml-lint
|
98
98
|
- config/default.yml
|
99
|
+
- config/forced_rubocop_config.yml
|
99
100
|
- lib/haml_lint.rb
|
100
101
|
- lib/haml_lint/adapter.rb
|
101
102
|
- lib/haml_lint/adapter/haml_4.rb
|
@@ -109,6 +110,7 @@ files:
|
|
109
110
|
- lib/haml_lint/directive.rb
|
110
111
|
- lib/haml_lint/document.rb
|
111
112
|
- lib/haml_lint/exceptions.rb
|
113
|
+
- lib/haml_lint/extensions/haml_util_unescape_interpolation_tracking.rb
|
112
114
|
- lib/haml_lint/file_finder.rb
|
113
115
|
- lib/haml_lint/haml_visitor.rb
|
114
116
|
- lib/haml_lint/lint.rb
|
@@ -132,6 +134,7 @@ files:
|
|
132
134
|
- lib/haml_lint/linter/line_length.rb
|
133
135
|
- lib/haml_lint/linter/multiline_pipe.rb
|
134
136
|
- lib/haml_lint/linter/multiline_script.rb
|
137
|
+
- lib/haml_lint/linter/no_placeholders.rb
|
135
138
|
- lib/haml_lint/linter/object_reference_attributes.rb
|
136
139
|
- lib/haml_lint/linter/repeated_id.rb
|
137
140
|
- lib/haml_lint/linter/rubocop.rb
|
@@ -162,7 +165,20 @@ files:
|
|
162
165
|
- lib/haml_lint/reporter/offense_count_reporter.rb
|
163
166
|
- lib/haml_lint/reporter/progress_reporter.rb
|
164
167
|
- lib/haml_lint/reporter/utils.rb
|
165
|
-
- lib/haml_lint/
|
168
|
+
- lib/haml_lint/ruby_extraction/ad_hoc_chunk.rb
|
169
|
+
- lib/haml_lint/ruby_extraction/base_chunk.rb
|
170
|
+
- lib/haml_lint/ruby_extraction/chunk_extractor.rb
|
171
|
+
- lib/haml_lint/ruby_extraction/coordinator.rb
|
172
|
+
- lib/haml_lint/ruby_extraction/haml_comment_chunk.rb
|
173
|
+
- lib/haml_lint/ruby_extraction/implicit_end_chunk.rb
|
174
|
+
- lib/haml_lint/ruby_extraction/interpolation_chunk.rb
|
175
|
+
- lib/haml_lint/ruby_extraction/non_ruby_filter_chunk.rb
|
176
|
+
- lib/haml_lint/ruby_extraction/placeholder_marker_chunk.rb
|
177
|
+
- lib/haml_lint/ruby_extraction/ruby_filter_chunk.rb
|
178
|
+
- lib/haml_lint/ruby_extraction/ruby_source.rb
|
179
|
+
- lib/haml_lint/ruby_extraction/script_chunk.rb
|
180
|
+
- lib/haml_lint/ruby_extraction/tag_attributes_chunk.rb
|
181
|
+
- lib/haml_lint/ruby_extraction/tag_script_chunk.rb
|
166
182
|
- lib/haml_lint/ruby_parser.rb
|
167
183
|
- lib/haml_lint/runner.rb
|
168
184
|
- lib/haml_lint/severity.rb
|
@@ -170,6 +186,7 @@ files:
|
|
170
186
|
- lib/haml_lint/spec/matchers/report_lint.rb
|
171
187
|
- lib/haml_lint/spec/normalize_indent.rb
|
172
188
|
- lib/haml_lint/spec/shared_linter_context.rb
|
189
|
+
- lib/haml_lint/spec/shared_rubocop_autocorrect_context.rb
|
173
190
|
- lib/haml_lint/tree/comment_node.rb
|
174
191
|
- lib/haml_lint/tree/doctype_node.rb
|
175
192
|
- lib/haml_lint/tree/filter_node.rb
|
@@ -183,6 +200,7 @@ files:
|
|
183
200
|
- lib/haml_lint/tree/tag_node.rb
|
184
201
|
- lib/haml_lint/utils.rb
|
185
202
|
- lib/haml_lint/version.rb
|
203
|
+
- lib/haml_lint/version_comparer.rb
|
186
204
|
homepage: https://github.com/sds/haml-lint
|
187
205
|
licenses:
|
188
206
|
- MIT
|
@@ -195,7 +213,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
195
213
|
requirements:
|
196
214
|
- - ">="
|
197
215
|
- !ruby/object:Gem::Version
|
198
|
-
version: 2.
|
216
|
+
version: 2.6.0
|
199
217
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
200
218
|
requirements:
|
201
219
|
- - ">="
|
@@ -1,223 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module HamlLint
|
4
|
-
# Utility class for extracting Ruby script from a HAML file that can then be
|
5
|
-
# linted with a Ruby linter (i.e. is "legal" Ruby). The goal is to turn this:
|
6
|
-
#
|
7
|
-
# - if signed_in?(viewer)
|
8
|
-
# %span Stuff
|
9
|
-
# = link_to 'Sign Out', sign_out_path
|
10
|
-
# - else
|
11
|
-
# .some-class{ class: my_method }= my_method
|
12
|
-
# = link_to 'Sign In', sign_in_path
|
13
|
-
#
|
14
|
-
# into this:
|
15
|
-
#
|
16
|
-
# if signed_in?(viewer)
|
17
|
-
# link_to 'Sign Out', sign_out_path
|
18
|
-
# else
|
19
|
-
# { class: my_method }
|
20
|
-
# my_method
|
21
|
-
# link_to 'Sign In', sign_in_path
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# The translation won't be perfect, and won't make any real sense, but the
|
25
|
-
# relationship between variable declarations/uses and the flow control graph
|
26
|
-
# will remain intact.
|
27
|
-
class RubyExtractor # rubocop:disable Metrics/ClassLength
|
28
|
-
include HamlVisitor
|
29
|
-
|
30
|
-
# Stores the extracted source and a map of lines of generated source to the
|
31
|
-
# original source that created them.
|
32
|
-
#
|
33
|
-
# @attr_reader source [String] generated source code
|
34
|
-
# @attr_reader source_map [Hash] map of line numbers from generated source
|
35
|
-
# to original source line number
|
36
|
-
RubySource = Struct.new(:source, :source_map)
|
37
|
-
|
38
|
-
# Extracts Ruby code from Sexp representing a Slim document.
|
39
|
-
#
|
40
|
-
# @param document [HamlLint::Document]
|
41
|
-
# @return [HamlLint::RubyExtractor::RubySource]
|
42
|
-
def extract(document)
|
43
|
-
visit(document.tree)
|
44
|
-
RubySource.new(@source_lines.join("\n"), @source_map)
|
45
|
-
end
|
46
|
-
|
47
|
-
def visit_root(_node)
|
48
|
-
@source_lines = []
|
49
|
-
@source_map = {}
|
50
|
-
@line_count = 0
|
51
|
-
@indent_level = 0
|
52
|
-
@output_count = 0
|
53
|
-
|
54
|
-
yield # Collect lines of code from children
|
55
|
-
end
|
56
|
-
|
57
|
-
def visit_plain(node)
|
58
|
-
# Don't output the text, as we don't want to have to deal with any RuboCop
|
59
|
-
# cops regarding StringQuotes or AsciiComments, and it's not important to
|
60
|
-
# overall document anyway.
|
61
|
-
add_dummy_puts(node)
|
62
|
-
end
|
63
|
-
|
64
|
-
def visit_tag(node)
|
65
|
-
additional_attributes = node.dynamic_attributes_sources
|
66
|
-
|
67
|
-
# Include dummy references to code executed in attributes list
|
68
|
-
# (this forces a "use" of a variable to prevent "assigned but unused
|
69
|
-
# variable" lints)
|
70
|
-
additional_attributes.each do |attributes_code|
|
71
|
-
# Normalize by removing excess whitespace to avoid format lints
|
72
|
-
attributes_code = attributes_code.gsub(/\s*\n\s*/, "\n").strip
|
73
|
-
|
74
|
-
# Attributes can either be a method call or a literal hash, so wrap it
|
75
|
-
# in a method call itself in order to avoid having to differentiate the
|
76
|
-
# two.
|
77
|
-
add_line("{}.merge(#{attributes_code})", node)
|
78
|
-
end
|
79
|
-
|
80
|
-
check_tag_static_hash_source(node)
|
81
|
-
|
82
|
-
# We add a dummy puts statement to represent the tag name being output.
|
83
|
-
# This prevents some erroneous RuboCop warnings.
|
84
|
-
add_dummy_puts(node, node.tag_name)
|
85
|
-
|
86
|
-
code = node.script.strip
|
87
|
-
add_line(code, node) unless code.empty?
|
88
|
-
end
|
89
|
-
|
90
|
-
def after_visit_tag(node)
|
91
|
-
# We add a dummy puts statement for closing tag.
|
92
|
-
add_dummy_puts(node, "#{node.tag_name}/")
|
93
|
-
end
|
94
|
-
|
95
|
-
def visit_script(node)
|
96
|
-
code = node.text
|
97
|
-
|
98
|
-
add_line(code.strip, node)
|
99
|
-
|
100
|
-
start_block = anonymous_block?(code) || start_block_keyword?(code)
|
101
|
-
|
102
|
-
if start_block
|
103
|
-
@indent_level += 1
|
104
|
-
end
|
105
|
-
|
106
|
-
yield # Continue extracting code from children
|
107
|
-
|
108
|
-
if start_block
|
109
|
-
@indent_level -= 1
|
110
|
-
add_line('end', node)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def visit_haml_comment(node)
|
115
|
-
# We want to preseve leading whitespace if it exists, but include leading
|
116
|
-
# whitespace if it doesn't exist so that RuboCop's LeadingCommentSpace
|
117
|
-
# doesn't complain
|
118
|
-
comment = node.text
|
119
|
-
.gsub(/\n(\S)/, "\n# \\1")
|
120
|
-
.gsub(/\n(\s)/, "\n#\\1")
|
121
|
-
add_line("##{comment}", node)
|
122
|
-
end
|
123
|
-
|
124
|
-
def visit_silent_script(node, &block)
|
125
|
-
visit_script(node, &block)
|
126
|
-
end
|
127
|
-
|
128
|
-
def visit_filter(node)
|
129
|
-
if node.filter_type == 'ruby'
|
130
|
-
node.text.split("\n").each_with_index do |line, index|
|
131
|
-
add_line(line, node.line + index + 1, false)
|
132
|
-
end
|
133
|
-
else
|
134
|
-
add_dummy_puts(node, ":#{node.filter_type}")
|
135
|
-
HamlLint::Utils.extract_interpolated_values(node.text) do |interpolated_code, line|
|
136
|
-
add_line(interpolated_code, node.line + line)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
private
|
142
|
-
|
143
|
-
def check_tag_static_hash_source(node)
|
144
|
-
# Haml::Parser converts hashrocket-style hash attributes of strings and symbols
|
145
|
-
# to static attributes, and excludes them from the dynamic attribute sources:
|
146
|
-
# https://github.com/haml/haml/blob/08f97ec4dc8f59fe3d7f6ab8f8807f86f2a15b68/lib/haml/parser.rb#L400-L404
|
147
|
-
# https://github.com/haml/haml/blob/08f97ec4dc8f59fe3d7f6ab8f8807f86f2a15b68/lib/haml/parser.rb#L540-L554
|
148
|
-
# Here, we add the hash source back in so it can be inspected by rubocop.
|
149
|
-
if node.hash_attributes? && node.dynamic_attributes_sources.empty?
|
150
|
-
normalized_attr_source = node.dynamic_attributes_source[:hash].gsub(/\s*\n\s*/, ' ')
|
151
|
-
|
152
|
-
add_line(normalized_attr_source, node)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
# Adds a dummy method call with a unique name so we don't get
|
157
|
-
# Style/IdenticalConditionalBranches RuboCop warnings
|
158
|
-
def add_dummy_puts(node, annotation = nil)
|
159
|
-
annotation = " # #{annotation}" if annotation
|
160
|
-
add_line("_haml_lint_puts_#{@output_count}#{annotation}", node)
|
161
|
-
@output_count += 1
|
162
|
-
end
|
163
|
-
|
164
|
-
def add_line(code, node_or_line, discard_blanks = true)
|
165
|
-
return if code.empty? && discard_blanks
|
166
|
-
|
167
|
-
indent_level = @indent_level
|
168
|
-
|
169
|
-
if node_or_line.respond_to?(:line)
|
170
|
-
# Since mid-block keywords are children of the corresponding start block
|
171
|
-
# keyword, we need to reduce their indentation level by 1. However, we
|
172
|
-
# don't do this unless this is an actual tag node (a raw line number
|
173
|
-
# means this came from a `:ruby` filter).
|
174
|
-
indent_level -= 1 if mid_block_keyword?(code)
|
175
|
-
end
|
176
|
-
|
177
|
-
indent = (' ' * 2 * indent_level)
|
178
|
-
|
179
|
-
@source_lines << indent_code(code, indent)
|
180
|
-
|
181
|
-
original_line =
|
182
|
-
node_or_line.respond_to?(:line) ? node_or_line.line : node_or_line
|
183
|
-
|
184
|
-
# For interpolated code in filters that spans multiple lines, the
|
185
|
-
# resulting code will span multiple lines, so we need to create a
|
186
|
-
# mapping for each line.
|
187
|
-
(code.count("\n") + 1).times do
|
188
|
-
@line_count += 1
|
189
|
-
@source_map[@line_count] = original_line
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def indent_code(code, indent)
|
194
|
-
codes = code.split("\n")
|
195
|
-
codes.map { |c| indent + c }.join("\n")
|
196
|
-
end
|
197
|
-
|
198
|
-
def anonymous_block?(text)
|
199
|
-
text =~ /\bdo\s*(\|\s*[^\|]*\s*\|)?(\s*#.*)?\z/
|
200
|
-
end
|
201
|
-
|
202
|
-
START_BLOCK_KEYWORDS = %w[if unless case begin for until while].freeze
|
203
|
-
def start_block_keyword?(text)
|
204
|
-
START_BLOCK_KEYWORDS.include?(block_keyword(text))
|
205
|
-
end
|
206
|
-
|
207
|
-
MID_BLOCK_KEYWORDS = %w[else elsif when rescue ensure].freeze
|
208
|
-
def mid_block_keyword?(text)
|
209
|
-
MID_BLOCK_KEYWORDS.include?(block_keyword(text))
|
210
|
-
end
|
211
|
-
|
212
|
-
LOOP_KEYWORDS = %w[for until while].freeze
|
213
|
-
def block_keyword(text)
|
214
|
-
# Need to handle 'for'/'while' since regex stolen from HAML parser doesn't
|
215
|
-
if keyword = text[/\A\s*([^\s]+)\s+/, 1]
|
216
|
-
return keyword if LOOP_KEYWORDS.include?(keyword)
|
217
|
-
end
|
218
|
-
|
219
|
-
return unless keyword = text.scan(Haml::Parser::BLOCK_KEYWORD_REGEX)[0]
|
220
|
-
keyword[0] || keyword[1]
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|