Skip to content

Commit 8382e94

Browse files
justin808claude
andcommitted
Improve doctor async checks: better error handling and comment filtering
Addressed code review feedback to make the async usage detection more robust and accurate: 1. Enhanced error handling: - Replace broad StandardError catches with specific exceptions (Errno::ENOENT, Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError) - Add debug logging when errors occur (if Rails logger available) 2. Add comment filtering to reduce false positives: - Filter out commented Ruby lines in config files (lines starting with #) - Skip ERB comments (<%# ... %>), HAML comments (-# ...), and HTML comments (<!-- ... -->) in view files - Prevent false alarms from commented-out code 3. Refactor for code quality: - Extract scan_pattern_for_async and file_has_async_pack_tag? helpers - Reduce cyclomatic complexity in scan_view_files_for_async_pack_tag - All RuboCop checks pass 4. Expand test coverage: - Add tests for ERB, HAML, and HTML comment scenarios - Add test for commented config with async strategy - All 13 async-related tests pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 044d7de commit 8382e94

File tree

2 files changed

+102
-17
lines changed

2 files changed

+102
-17
lines changed

lib/react_on_rails/doctor.rb

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,26 +1181,46 @@ def check_async_usage
11811181
end
11821182

11831183
def scan_view_files_for_async_pack_tag
1184-
files_with_async = []
1185-
1186-
# Scan app/views for .erb and .haml files
11871184
view_patterns = ["app/views/**/*.erb", "app/views/**/*.haml"]
1185+
files_with_async = view_patterns.flat_map { |pattern| scan_pattern_for_async(pattern) }
1186+
files_with_async.compact
1187+
rescue Errno::ENOENT, Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError => e
1188+
# Log the error if Rails logger is available
1189+
Rails.logger.debug("Error scanning view files for async: #{e.message}") if defined?(Rails) && Rails.logger
1190+
[]
1191+
end
11881192

1189-
view_patterns.each do |pattern|
1190-
Dir.glob(pattern).each do |file|
1191-
next unless File.exist?(file)
1193+
def scan_pattern_for_async(pattern)
1194+
Dir.glob(pattern).filter_map do |file|
1195+
next unless File.exist?(file)
11921196

1193-
content = File.read(file)
1194-
# Look for javascript_pack_tag with :async or "async"
1195-
if content.match?(/javascript_pack_tag.*:async/) || content.match?(/javascript_pack_tag.*["']async["']/)
1196-
files_with_async << relativize_path(file)
1197-
end
1198-
end
1197+
content = File.read(file)
1198+
next if content_has_only_commented_async?(content)
1199+
next unless file_has_async_pack_tag?(content)
1200+
1201+
relativize_path(file)
1202+
end
1203+
end
1204+
1205+
def file_has_async_pack_tag?(content)
1206+
content.match?(/javascript_pack_tag.*:async/) || content.match?(/javascript_pack_tag.*["']async["']/)
1207+
end
1208+
1209+
def content_has_only_commented_async?(content)
1210+
# Check if all occurrences of javascript_pack_tag with :async are in comments
1211+
has_uncommented_async = content.each_line.any? do |line|
1212+
# Skip ERB comments (<%# ... %>)
1213+
next if line.match?(/<%\s*#.*javascript_pack_tag.*:async/)
1214+
# Skip HAML comments (-# ...)
1215+
next if line.match?(/^\s*-#.*javascript_pack_tag.*:async/)
1216+
# Skip HTML comments (<!-- ... -->)
1217+
next if line.match?(/<!--.*javascript_pack_tag.*:async.*-->/)
1218+
1219+
# Check if line has javascript_pack_tag with :async
1220+
line.match?(/javascript_pack_tag.*:async/)
11991221
end
12001222

1201-
files_with_async
1202-
rescue StandardError
1203-
[]
1223+
!has_uncommented_async
12041224
end
12051225

12061226
def config_has_async_loading_strategy?
@@ -1209,8 +1229,13 @@ def config_has_async_loading_strategy?
12091229

12101230
content = File.read(config_path)
12111231
# Check if generated_component_packs_loading_strategy is set to :async
1212-
content.match?(/config\.generated_component_packs_loading_strategy\s*=\s*:async/)
1213-
rescue StandardError
1232+
# Filter out commented lines to avoid false positives
1233+
content.each_line.any? do |line|
1234+
line !~ /^\s*#/ && line.match?(/config\.generated_component_packs_loading_strategy\s*=\s*:async/)
1235+
end
1236+
rescue Errno::ENOENT, Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError => e
1237+
# Log the error if Rails logger is available
1238+
Rails.logger.debug("Error checking async loading strategy: #{e.message}") if defined?(Rails) && Rails.logger
12141239
false
12151240
end
12161241
end

spec/lib/react_on_rails/doctor_spec.rb

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,54 @@
307307
expect(files).to be_empty
308308
end
309309
end
310+
311+
context "when async is only in ERB comments" do
312+
before do
313+
allow(Dir).to receive(:glob).with("app/views/**/*.erb")
314+
.and_return(["app/views/layouts/application.html.erb"])
315+
allow(Dir).to receive(:glob).with("app/views/**/*.haml").and_return([])
316+
allow(File).to receive(:exist?).with("app/views/layouts/application.html.erb").and_return(true)
317+
allow(File).to receive(:read).with("app/views/layouts/application.html.erb")
318+
.and_return('<%# javascript_pack_tag "app", :async %>')
319+
end
320+
321+
it "returns empty array" do
322+
files = doctor.send(:scan_view_files_for_async_pack_tag)
323+
expect(files).to be_empty
324+
end
325+
end
326+
327+
context "when async is only in HAML comments" do
328+
before do
329+
allow(Dir).to receive(:glob).with("app/views/**/*.erb").and_return([])
330+
allow(Dir).to receive(:glob).with("app/views/**/*.haml")
331+
.and_return(["app/views/layouts/application.html.haml"])
332+
allow(File).to receive(:exist?).with("app/views/layouts/application.html.haml").and_return(true)
333+
allow(File).to receive(:read).with("app/views/layouts/application.html.haml")
334+
.and_return('-# javascript_pack_tag "app", :async')
335+
end
336+
337+
it "returns empty array" do
338+
files = doctor.send(:scan_view_files_for_async_pack_tag)
339+
expect(files).to be_empty
340+
end
341+
end
342+
343+
context "when async is only in HTML comments" do
344+
before do
345+
allow(Dir).to receive(:glob).with("app/views/**/*.erb")
346+
.and_return(["app/views/layouts/application.html.erb"])
347+
allow(Dir).to receive(:glob).with("app/views/**/*.haml").and_return([])
348+
allow(File).to receive(:exist?).with("app/views/layouts/application.html.erb").and_return(true)
349+
allow(File).to receive(:read).with("app/views/layouts/application.html.erb")
350+
.and_return('<!-- <%= javascript_pack_tag "app", :async %> -->')
351+
end
352+
353+
it "returns empty array" do
354+
files = doctor.send(:scan_view_files_for_async_pack_tag)
355+
expect(files).to be_empty
356+
end
357+
end
310358
end
311359

312360
describe "#config_has_async_loading_strategy?" do
@@ -343,5 +391,17 @@
343391
expect(doctor.send(:config_has_async_loading_strategy?)).to be false
344392
end
345393
end
394+
395+
context "when :async strategy is commented out" do
396+
before do
397+
allow(File).to receive(:exist?).with("config/initializers/react_on_rails.rb").and_return(true)
398+
allow(File).to receive(:read).with("config/initializers/react_on_rails.rb")
399+
.and_return("# config.generated_component_packs_loading_strategy = :async")
400+
end
401+
402+
it "returns false" do
403+
expect(doctor.send(:config_has_async_loading_strategy?)).to be false
404+
end
405+
end
346406
end
347407
end

0 commit comments

Comments
 (0)