haml_lint 0.45.0 → 0.48.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|