immosquare-cleaner 0.1.93 → 0.1.95
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef4743e368013a24d51795c0401fb25551318cf708de34ede70da2463732fb14
|
|
4
|
+
data.tar.gz: d071271dcda68ef78e8c042217d39ba13f484b8081e120384c7c01b3c8e0deaa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 11cda1db31886b571cf81a294798e080eef10e30870adeb23071d37242415d047e0b7916c3c6af0bca855f116c49808a2bd38aeba1744f7e29bd1fbd768a5385
|
|
7
|
+
data.tar.gz: 2451ad2ef109bf3847a554d7d557bd182e24fae97c7be882e85e8ff1392cffc0a14258f724b2197e386ca6905a51e46c302d2c54d483eea8fc3b5ecd748b5520
|
data/lib/immosquare-cleaner.rb
CHANGED
|
@@ -168,7 +168,7 @@ module ImmosquareCleaner
|
|
|
168
168
|
File.write(temp_file_path, File.read(file_path))
|
|
169
169
|
cmds = []
|
|
170
170
|
cmds << "bundle exec erb_lint --config #{erblint_config_with_version_path} #{file_path} #{ImmosquareCleaner.configuration.erblint_options || "--autocorrect"}" if file_path.end_with?(".erb")
|
|
171
|
-
cmds << "bun #{gem_root}/linters/normalize-comments.mjs #{temp_file_path}"
|
|
171
|
+
cmds << "bun #{gem_root}/linters/normalize-comments.mjs #{temp_file_path}" if !file_path.end_with?(".erb")
|
|
172
172
|
cmds << "bun eslint --config #{gem_root}/linters/eslint.config.mjs #{temp_file_path} --fix"
|
|
173
173
|
|
|
174
174
|
launch_cmds(cmds)
|
|
@@ -19,8 +19,19 @@ namespace :immosquare_cleaner do
|
|
|
19
19
|
]
|
|
20
20
|
extensions_to_exclude = [
|
|
21
21
|
".lock",
|
|
22
|
-
".lockb"
|
|
22
|
+
".lockb",
|
|
23
|
+
".otf",
|
|
24
|
+
".ttf",
|
|
25
|
+
".png",
|
|
26
|
+
".jpg",
|
|
27
|
+
".jpeg",
|
|
28
|
+
".gif",
|
|
29
|
+
".svg",
|
|
30
|
+
".ico",
|
|
31
|
+
".webp",
|
|
32
|
+
".csv"
|
|
23
33
|
]
|
|
34
|
+
|
|
24
35
|
file_paths = Dir.glob("#{Rails.root}/**/*").reject do |file_path|
|
|
25
36
|
File.directory?(file_path) || file_path.gsub("#{Rails.root}/", "").start_with?(*paths_to_exclude) || file_path.end_with?(*extensions_to_exclude)
|
|
26
37
|
end
|
|
@@ -213,21 +213,31 @@ module ERBLint
|
|
|
213
213
|
##============================================================##
|
|
214
214
|
## Extract single ERB output node from text node
|
|
215
215
|
## Returns nil if text contains anything other than whitespace
|
|
216
|
-
## and a single ERB output
|
|
216
|
+
## and a single ERB output. Also rejects if there are nested tags.
|
|
217
217
|
##============================================================##
|
|
218
218
|
def extract_single_erb_output(text_node)
|
|
219
219
|
erb_nodes = []
|
|
220
220
|
has_non_whitespace_text = false
|
|
221
|
+
has_nested_tags = false
|
|
221
222
|
|
|
222
223
|
text_node.children.each do |child|
|
|
223
224
|
if child.is_a?(String)
|
|
224
225
|
has_non_whitespace_text = true unless child.match?(/\A\s*\z/)
|
|
225
|
-
elsif child
|
|
226
|
-
|
|
226
|
+
elsif child.respond_to?(:type)
|
|
227
|
+
case child.type
|
|
228
|
+
when :erb
|
|
229
|
+
erb_nodes << child
|
|
230
|
+
when :tag
|
|
231
|
+
##============================================================##
|
|
232
|
+
## If there's any nested tag, don't convert the parent
|
|
233
|
+
##============================================================##
|
|
234
|
+
has_nested_tags = true
|
|
235
|
+
end
|
|
227
236
|
end
|
|
228
237
|
end
|
|
229
238
|
|
|
230
239
|
return nil if has_non_whitespace_text
|
|
240
|
+
return nil if has_nested_tags
|
|
231
241
|
return nil if erb_nodes.size != 1
|
|
232
242
|
|
|
233
243
|
erb_node = erb_nodes.first
|
|
@@ -256,41 +266,37 @@ module ERBLint
|
|
|
256
266
|
def excluded_method?(erb_code)
|
|
257
267
|
return false unless erb_code
|
|
258
268
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
method_name = call_node.name.to_s
|
|
263
|
-
return true if EXCLUDED_METHODS.include?(method_name)
|
|
269
|
+
result = Prism.parse(erb_code)
|
|
270
|
+
node = result.value.statements.body.first
|
|
264
271
|
|
|
265
272
|
##============================================================##
|
|
266
|
-
##
|
|
267
|
-
##
|
|
273
|
+
## yield is a YieldNode, not a CallNode - always exclude it
|
|
274
|
+
## Note: Prism reports yield outside block as syntax error,
|
|
275
|
+
## but still creates the node, so check before result.success?
|
|
268
276
|
##============================================================##
|
|
269
|
-
return true if
|
|
270
|
-
|
|
271
|
-
false
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
##============================================================##
|
|
275
|
-
## Extract the CallNode from Ruby code using Prism parser
|
|
276
|
-
## Handles both direct calls and calls with if/unless modifiers
|
|
277
|
-
##============================================================##
|
|
278
|
-
def extract_call_node(erb_code)
|
|
279
|
-
result = Prism.parse(erb_code)
|
|
280
|
-
return nil unless result.success?
|
|
277
|
+
return true if node.is_a?(Prism::YieldNode)
|
|
281
278
|
|
|
282
|
-
|
|
279
|
+
return false unless result.success?
|
|
283
280
|
|
|
284
281
|
##============================================================##
|
|
285
282
|
## Handle if/unless modifiers: `render(...) if condition`
|
|
286
283
|
##============================================================##
|
|
287
284
|
node = node.statements&.body&.first if node.is_a?(Prism::IfNode) || node.is_a?(Prism::UnlessNode)
|
|
288
285
|
|
|
289
|
-
return
|
|
286
|
+
return false unless node.is_a?(Prism::CallNode)
|
|
287
|
+
|
|
288
|
+
method_name = node.name.to_s
|
|
289
|
+
return true if EXCLUDED_METHODS.include?(method_name)
|
|
290
290
|
|
|
291
|
-
|
|
291
|
+
##============================================================##
|
|
292
|
+
## If method is a form builder method called on a receiver,
|
|
293
|
+
## skip conversion (e.g., f.input, form.text_field, etc.)
|
|
294
|
+
##============================================================##
|
|
295
|
+
return true if node.receiver && FORM_BUILDER_METHODS.include?(method_name)
|
|
296
|
+
|
|
297
|
+
false
|
|
292
298
|
rescue StandardError
|
|
293
|
-
|
|
299
|
+
false
|
|
294
300
|
end
|
|
295
301
|
|
|
296
302
|
##============================================================##
|
|
@@ -322,25 +328,54 @@ module ERBLint
|
|
|
322
328
|
|
|
323
329
|
##============================================================##
|
|
324
330
|
## Extract attribute value, handling both static and ERB values
|
|
331
|
+
## Returns a hash with :type (:static, :dynamic, :erb_only)
|
|
332
|
+
## For :dynamic, also includes :parts array for proper escaping
|
|
325
333
|
##============================================================##
|
|
326
334
|
def extract_attribute_value(value_node)
|
|
327
335
|
return nil unless value_node
|
|
328
336
|
|
|
329
337
|
parts = []
|
|
338
|
+
erb_parts = []
|
|
339
|
+
static_parts = []
|
|
340
|
+
|
|
330
341
|
value_node.children.each do |child|
|
|
331
342
|
if child.is_a?(String)
|
|
332
|
-
parts << child
|
|
343
|
+
parts << {:type => :static, :value => child}
|
|
344
|
+
static_parts << child
|
|
333
345
|
elsif child.respond_to?(:type)
|
|
334
346
|
next if child.type == :quote
|
|
335
347
|
|
|
336
348
|
if child.type == :erb
|
|
337
349
|
erb_code = extract_erb_code(child)
|
|
338
|
-
parts <<
|
|
350
|
+
parts << {:type => :erb, :value => erb_code}
|
|
351
|
+
erb_parts << erb_code
|
|
339
352
|
end
|
|
340
353
|
end
|
|
341
354
|
end
|
|
342
355
|
|
|
343
|
-
|
|
356
|
+
##============================================================##
|
|
357
|
+
## Determine the attribute value type:
|
|
358
|
+
## - :erb_only: Only ERB, no static text (use Ruby directly)
|
|
359
|
+
## - :dynamic: Mix of static and ERB (use interpolation)
|
|
360
|
+
## - :static: Only static text (use quoted string)
|
|
361
|
+
##============================================================##
|
|
362
|
+
if erb_parts.any? && static_parts.all? {|s| s.match?(/\A\s*\z/) }
|
|
363
|
+
##============================================================##
|
|
364
|
+
## Pure ERB value: class="<%= expr %>" -> :class => (expr)
|
|
365
|
+
##============================================================##
|
|
366
|
+
{:type => :erb_only, :value => erb_parts.first}
|
|
367
|
+
elsif erb_parts.any?
|
|
368
|
+
##============================================================##
|
|
369
|
+
## Mixed value: keep parts separate for proper escaping
|
|
370
|
+
## class="foo <%= expr %>" -> :class => "foo #{expr}"
|
|
371
|
+
##============================================================##
|
|
372
|
+
{:type => :dynamic, :parts => parts}
|
|
373
|
+
else
|
|
374
|
+
##============================================================##
|
|
375
|
+
## Static value: class="foo" -> :class => "foo"
|
|
376
|
+
##============================================================##
|
|
377
|
+
{:type => :static, :value => static_parts.join}
|
|
378
|
+
end
|
|
344
379
|
end
|
|
345
380
|
|
|
346
381
|
##============================================================##
|
|
@@ -367,10 +402,10 @@ module ERBLint
|
|
|
367
402
|
if attributes.empty?
|
|
368
403
|
base = "content_tag(#{formatted_tag}, #{wrapped_content})"
|
|
369
404
|
else
|
|
370
|
-
attrs_str = attributes.map do |name,
|
|
405
|
+
attrs_str = attributes.map do |name, attr_data|
|
|
371
406
|
key = normalize_attribute_name(name)
|
|
372
|
-
|
|
373
|
-
"#{key} => #{
|
|
407
|
+
formatted_value = format_attribute_value(attr_data)
|
|
408
|
+
"#{key} => #{formatted_value}"
|
|
374
409
|
end.join(", ")
|
|
375
410
|
|
|
376
411
|
base = "content_tag(#{formatted_tag}, #{wrapped_content}, #{attrs_str})"
|
|
@@ -451,27 +486,76 @@ module ERBLint
|
|
|
451
486
|
end
|
|
452
487
|
|
|
453
488
|
##============================================================##
|
|
454
|
-
##
|
|
455
|
-
## -
|
|
456
|
-
## -
|
|
457
|
-
## -
|
|
489
|
+
## Format attribute value based on its type
|
|
490
|
+
## - :erb_only: Pure ERB -> (expr) with parentheses if needed
|
|
491
|
+
## - :dynamic: Mixed -> "text #{expr}" with interpolation
|
|
492
|
+
## - :static: Pure text -> "value" with proper quoting
|
|
458
493
|
##============================================================##
|
|
459
|
-
def
|
|
460
|
-
return '""' if
|
|
494
|
+
def format_attribute_value(attr_data)
|
|
495
|
+
return '""' if attr_data.nil?
|
|
461
496
|
|
|
462
|
-
|
|
463
|
-
has_double_quotes = value.include?('"')
|
|
497
|
+
type = attr_data[:type]
|
|
464
498
|
|
|
465
|
-
|
|
499
|
+
case type
|
|
500
|
+
when :erb_only
|
|
466
501
|
##============================================================##
|
|
467
|
-
##
|
|
502
|
+
## Pure ERB: wrap in parentheses for safety
|
|
503
|
+
## class="<%= x if y %>" -> :class => (x if y)
|
|
468
504
|
##============================================================##
|
|
469
|
-
|
|
470
|
-
"
|
|
471
|
-
|
|
505
|
+
value = attr_data[:value]
|
|
506
|
+
return '""' if value.nil? || value.empty?
|
|
507
|
+
|
|
508
|
+
"(#{value})"
|
|
509
|
+
when :dynamic
|
|
472
510
|
##============================================================##
|
|
473
|
-
##
|
|
511
|
+
## Mixed static and ERB: build string from parts
|
|
512
|
+
## Escape quotes only in static parts, not in ERB parts
|
|
513
|
+
## class="foo <%= bar %>" -> :class => "foo #{bar}"
|
|
514
|
+
##============================================================##
|
|
515
|
+
parts = attr_data[:parts]
|
|
516
|
+
return '""' if parts.nil? || parts.empty?
|
|
517
|
+
|
|
518
|
+
build_interpolated_string(parts)
|
|
519
|
+
else
|
|
474
520
|
##============================================================##
|
|
521
|
+
## Static value: simple quoting
|
|
522
|
+
##============================================================##
|
|
523
|
+
value = attr_data[:value]
|
|
524
|
+
return '""' if value.nil? || value.empty?
|
|
525
|
+
|
|
526
|
+
quote_static_string(value)
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
##============================================================##
|
|
531
|
+
## Build an interpolated string from parts
|
|
532
|
+
## Static parts have quotes escaped, ERB parts are wrapped in #{}
|
|
533
|
+
##============================================================##
|
|
534
|
+
def build_interpolated_string(parts)
|
|
535
|
+
result = parts.map do |part|
|
|
536
|
+
if part[:type] == :erb
|
|
537
|
+
##============================================================##
|
|
538
|
+
## ERB part: wrap in interpolation, no escaping needed
|
|
539
|
+
##============================================================##
|
|
540
|
+
"\#{#{part[:value]}}"
|
|
541
|
+
else
|
|
542
|
+
##============================================================##
|
|
543
|
+
## Static part: escape double quotes
|
|
544
|
+
##============================================================##
|
|
545
|
+
part[:value].gsub('"', '\\"')
|
|
546
|
+
end
|
|
547
|
+
end.join
|
|
548
|
+
|
|
549
|
+
"\"#{result}\""
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
##============================================================##
|
|
553
|
+
## Quote a static string value for Ruby output
|
|
554
|
+
## - Uses double quotes by default
|
|
555
|
+
## - Switches to single quotes if value contains double quotes
|
|
556
|
+
##============================================================##
|
|
557
|
+
def quote_static_string(value)
|
|
558
|
+
if value.include?('"')
|
|
475
559
|
"'#{value}'"
|
|
476
560
|
else
|
|
477
561
|
"\"#{value}\""
|
|
@@ -497,8 +581,10 @@ module ERBLint
|
|
|
497
581
|
if node.is_a?(Prism::IfNode) || node.is_a?(Prism::UnlessNode)
|
|
498
582
|
##============================================================##
|
|
499
583
|
## Only handle modifier form (no else, single statement body)
|
|
584
|
+
## Use subsequent for IfNode, else_clause for UnlessNode
|
|
500
585
|
##============================================================##
|
|
501
|
-
|
|
586
|
+
else_branch = node.is_a?(Prism::IfNode) ? node.subsequent : node.else_clause
|
|
587
|
+
if else_branch.nil? && node.statements&.body&.size == 1
|
|
502
588
|
keyword = node.is_a?(Prism::IfNode) ? "if" : "unless"
|
|
503
589
|
condition = node.predicate.slice
|
|
504
590
|
content = node.statements.body.first.slice
|
|
@@ -87,6 +87,18 @@ const groupConsecutiveComments = (comments, originalLines) => {
|
|
|
87
87
|
return
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
//============================================================//
|
|
91
|
+
// Skip Sprockets directives (//= link, //= require, etc.)
|
|
92
|
+
//============================================================//
|
|
93
|
+
if (comment.value.startsWith("=")) {
|
|
94
|
+
if (currentBlock.length > 0) {
|
|
95
|
+
blocks.push(currentBlock)
|
|
96
|
+
currentBlock = []
|
|
97
|
+
}
|
|
98
|
+
lastLine = -2
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
90
102
|
//============================================================//
|
|
91
103
|
// Check if this is a standalone comment (line starts with //)
|
|
92
104
|
// Skip end-of-line comments (e.g., const x = 1 // comment)
|