@@ -73,17 +73,28 @@ def print_header
7373 def run_all_checks
7474 checks = [
7575 [ "Environment Prerequisites" , :check_environment ] ,
76+ [ "React on Rails Versions" , :check_react_on_rails_versions ] ,
7677 [ "React on Rails Packages" , :check_packages ] ,
7778 [ "Dependencies" , :check_dependencies ] ,
79+ [ "Key Configuration Files" , :check_key_files ] ,
80+ [ "Configuration Analysis" , :check_configuration_details ] ,
81+ [ "bin/dev Launcher Setup" , :check_bin_dev_launcher ] ,
7882 [ "Rails Integration" , :check_rails ] ,
7983 [ "Webpack Configuration" , :check_webpack ] ,
84+ [ "Testing Setup" , :check_testing_setup ] ,
8085 [ "Development Environment" , :check_development ]
8186 ]
8287
8388 checks . each do |section_name , check_method |
84- print_section_header ( section_name )
89+ initial_message_count = checker . messages . length
8590 send ( check_method )
86- puts
91+
92+ # Only print header if messages were added
93+ if checker . messages . length > initial_message_count
94+ print_section_header ( section_name )
95+ print_recent_messages ( initial_message_count )
96+ puts
97+ end
8798 end
8899 end
89100
@@ -92,11 +103,24 @@ def print_section_header(section_name)
92103 puts Rainbow ( "-" * ( section_name . length + 1 ) ) . blue
93104 end
94105
106+ def print_recent_messages ( start_index )
107+ checker . messages [ start_index ..-1 ] . each do |message |
108+ color = MESSAGE_COLORS [ message [ :type ] ] || :blue
109+ puts Rainbow ( message [ :content ] ) . send ( color )
110+ end
111+ end
112+
95113 def check_environment
96114 checker . check_node_installation
97115 checker . check_package_manager
98116 end
99117
118+ def check_react_on_rails_versions
119+ check_gem_version
120+ check_npm_package_version
121+ check_version_wildcards
122+ end
123+
100124 def check_packages
101125 checker . check_react_on_rails_packages
102126 checker . check_shakapacker_configuration
@@ -114,6 +138,27 @@ def check_webpack
114138 checker . check_webpack_configuration
115139 end
116140
141+ def check_key_files
142+ check_key_configuration_files
143+ end
144+
145+ def check_configuration_details
146+ check_shakapacker_configuration_details
147+ check_react_on_rails_configuration_details
148+ end
149+
150+ def check_bin_dev_launcher
151+ checker . add_info ( "🚀 bin/dev Launcher:" )
152+ check_bin_dev_launcher_setup
153+
154+ checker . add_info ( "\n 📄 Launcher Procfiles:" )
155+ check_launcher_procfiles
156+ end
157+
158+ def check_testing_setup
159+ check_rspec_helper_setup
160+ end
161+
117162 def check_development
118163 check_javascript_bundles
119164 check_procfile_dev
@@ -177,13 +222,12 @@ def check_individual_procfile(filename, config)
177222 if File . exist? ( filename )
178223 checker . add_success ( "✅ #{ filename } exists (#{ config [ :description ] } )" )
179224
225+ # Only check for critical missing components, not optional suggestions
180226 content = File . read ( filename )
181- config [ :should_contain ] . each do |expected_content |
182- if content . include? ( expected_content )
183- checker . add_success ( " ✓ Contains #{ expected_content } " )
184- else
185- checker . add_info ( " ℹ️ Could include #{ expected_content } for #{ config [ :description ] } " )
186- end
227+ if filename == "Procfile.dev" && !content . include? ( "shakapacker-dev-server" )
228+ checker . add_warning ( " ⚠️ Missing shakapacker-dev-server for HMR development" )
229+ elsif filename == "Procfile.dev-static-assets" && !content . include? ( "shakapacker" )
230+ checker . add_warning ( " ⚠️ Missing shakapacker for static asset compilation" )
187231 end
188232 else
189233 checker . add_info ( "ℹ️ #{ filename } not found (needed for #{ config [ :required_for ] } )" )
@@ -274,9 +318,11 @@ def print_summary_message(counts)
274318 end
275319
276320 def print_detailed_results_if_needed ( counts )
277- return unless verbose || counts [ :error ] . positive? || counts [ :warning ] . positive?
321+ # Skip detailed results since messages are now printed under section headers
322+ # Only show detailed results in verbose mode for debugging
323+ return unless verbose
278324
279- puts "\n Detailed Results:"
325+ puts "\n Detailed Results (Verbose Mode) :"
280326 print_all_messages
281327 end
282328
@@ -378,6 +424,226 @@ def print_next_steps
378424 end
379425 # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
380426
427+ def check_gem_version
428+ gem_version = ReactOnRails ::VERSION
429+ checker . add_success ( "✅ React on Rails gem version: #{ gem_version } " )
430+ rescue StandardError
431+ checker . add_error ( "🚫 Unable to determine React on Rails gem version" )
432+ end
433+
434+ def check_npm_package_version
435+ return unless File . exist? ( "package.json" )
436+
437+ begin
438+ package_json = JSON . parse ( File . read ( "package.json" ) )
439+ all_deps = package_json [ "dependencies" ] &.merge ( package_json [ "devDependencies" ] || { } ) || { }
440+
441+ npm_version = all_deps [ "react-on-rails" ]
442+ if npm_version
443+ checker . add_success ( "✅ react-on-rails npm package version: #{ npm_version } " )
444+ else
445+ checker . add_warning ( "⚠️ react-on-rails npm package not found in package.json" )
446+ end
447+ rescue JSON ::ParserError
448+ checker . add_error ( "🚫 Unable to parse package.json" )
449+ rescue StandardError
450+ checker . add_error ( "🚫 Error reading package.json" )
451+ end
452+ end
453+
454+ def check_version_wildcards
455+ check_gem_wildcards
456+ check_npm_wildcards
457+ end
458+
459+ # rubocop:disable Metrics/CyclomaticComplexity
460+ def check_gem_wildcards
461+ gemfile_path = ENV [ "BUNDLE_GEMFILE" ] || "Gemfile"
462+ return unless File . exist? ( gemfile_path )
463+
464+ begin
465+ content = File . read ( gemfile_path )
466+ react_line = content . lines . find { |line | line . match ( /^\s *gem\s +['"]react_on_rails['"]/ ) }
467+
468+ if react_line
469+ if /['"][~^]/ . match? ( react_line )
470+ checker . add_warning ( "⚠️ Gemfile uses wildcard version pattern (~, ^) for react_on_rails" )
471+ elsif />=\s */ . match? ( react_line )
472+ checker . add_warning ( "⚠️ Gemfile uses version range (>=) for react_on_rails" )
473+ else
474+ checker . add_success ( "✅ Gemfile uses exact version for react_on_rails" )
475+ end
476+ end
477+ rescue StandardError
478+ # Ignore errors reading Gemfile
479+ end
480+ end
481+ # rubocop:enable Metrics/CyclomaticComplexity
482+
483+ # rubocop:disable Metrics/CyclomaticComplexity
484+ def check_npm_wildcards
485+ return unless File . exist? ( "package.json" )
486+
487+ begin
488+ package_json = JSON . parse ( File . read ( "package.json" ) )
489+ all_deps = package_json [ "dependencies" ] &.merge ( package_json [ "devDependencies" ] || { } ) || { }
490+
491+ npm_version = all_deps [ "react-on-rails" ]
492+ if npm_version
493+ if /[~^]/ . match? ( npm_version )
494+ checker . add_warning ( "⚠️ package.json uses wildcard version pattern (~, ^) for react-on-rails" )
495+ else
496+ checker . add_success ( "✅ package.json uses exact version for react-on-rails" )
497+ end
498+ end
499+ rescue JSON ::ParserError
500+ # Ignore JSON parsing errors
501+ rescue StandardError
502+ # Ignore other errors
503+ end
504+ end
505+ # rubocop:enable Metrics/CyclomaticComplexity
506+
507+ def check_key_configuration_files
508+ files_to_check = {
509+ "config/shakapacker.yml" => "Shakapacker configuration" ,
510+ "config/initializers/react_on_rails.rb" => "React on Rails initializer" ,
511+ "bin/shakapacker" => "Shakapacker binary" ,
512+ "bin/shakapacker-dev-server" => "Shakapacker dev server binary" ,
513+ "config/webpack/webpack.config.js" => "Webpack configuration"
514+ }
515+
516+ files_to_check . each do |file_path , description |
517+ if File . exist? ( file_path )
518+ checker . add_success ( "✅ #{ description } : #{ file_path } " )
519+ else
520+ checker . add_warning ( "⚠️ Missing #{ description } : #{ file_path } " )
521+ end
522+ end
523+ end
524+
525+ def check_shakapacker_configuration_details
526+ return unless File . exist? ( "config/shakapacker.yml" )
527+
528+ # For now, just indicate that the configuration file exists
529+ # TODO: Parse YAML directly or improve Shakapacker integration
530+ checker . add_info ( "📋 Shakapacker Configuration:" )
531+ checker . add_info ( " Configuration file: config/shakapacker.yml" )
532+ checker . add_info ( " ℹ️ Run 'rake shakapacker:info' for detailed configuration" )
533+ end
534+
535+ def check_react_on_rails_configuration_details
536+ config_path = "config/initializers/react_on_rails.rb"
537+ return unless File . exist? ( config_path )
538+
539+ begin
540+ content = File . read ( config_path )
541+
542+ checker . add_info ( "📋 React on Rails Configuration:" )
543+
544+ # Extract key configuration values
545+ config_patterns = {
546+ "server_bundle_js_file" => /config\. server_bundle_js_file\s *=\s *["']([^"']+)["']/ ,
547+ "prerender" => /config\. prerender\s *=\s *([^\s \n ]+)/ ,
548+ "trace" => /config\. trace\s *=\s *([^\s \n ]+)/ ,
549+ "development_mode" => /config\. development_mode\s *=\s *([^\s \n ]+)/ ,
550+ "logging_on_server" => /config\. logging_on_server\s *=\s *([^\s \n ]+)/
551+ }
552+
553+ config_patterns . each do |setting , pattern |
554+ match = content . match ( pattern )
555+ checker . add_info ( " #{ setting } : #{ match [ 1 ] } " ) if match
556+ end
557+ rescue StandardError => e
558+ checker . add_warning ( "⚠️ Unable to read react_on_rails.rb: #{ e . message } " )
559+ end
560+ end
561+
562+ def check_bin_dev_launcher_setup
563+ bin_dev_path = "bin/dev"
564+
565+ unless File . exist? ( bin_dev_path )
566+ checker . add_error ( " 🚫 bin/dev script not found" )
567+ return
568+ end
569+
570+ content = File . read ( bin_dev_path )
571+
572+ if content . include? ( "ReactOnRails::Dev::ServerManager" )
573+ checker . add_success ( " ✅ bin/dev uses ReactOnRails Launcher (ReactOnRails::Dev::ServerManager)" )
574+ elsif content . include? ( "run_from_command_line" )
575+ checker . add_success ( " ✅ bin/dev uses ReactOnRails Launcher (run_from_command_line)" )
576+ else
577+ checker . add_warning ( " ⚠️ bin/dev exists but doesn't use ReactOnRails Launcher" )
578+ checker . add_info ( " 💡 Consider upgrading: rails generate react_on_rails:install" )
579+ end
580+ end
581+
582+ def check_launcher_procfiles
583+ procfiles = {
584+ "Procfile.dev" => "HMR development (bin/dev default)" ,
585+ "Procfile.dev-static-assets" => "Static development (bin/dev static)" ,
586+ "Procfile.dev-prod-assets" => "Production assets (bin/dev prod)"
587+ }
588+
589+ missing_count = 0
590+
591+ procfiles . each do |filename , description |
592+ if File . exist? ( filename )
593+ checker . add_success ( " ✅ #{ filename } - #{ description } " )
594+ else
595+ checker . add_warning ( " ⚠️ Missing #{ filename } - #{ description } " )
596+ missing_count += 1
597+ end
598+ end
599+
600+ if missing_count . zero?
601+ checker . add_success ( " ✅ All Launcher Procfiles available" )
602+ else
603+ checker . add_info ( " 💡 Run: rails generate react_on_rails:install" )
604+ end
605+ end
606+
607+ # rubocop:disable Metrics/CyclomaticComplexity
608+ def check_rspec_helper_setup
609+ spec_helper_paths = [
610+ "spec/rails_helper.rb" ,
611+ "spec/spec_helper.rb"
612+ ]
613+
614+ react_on_rails_test_helper_found = false
615+
616+ spec_helper_paths . each do |helper_path |
617+ next unless File . exist? ( helper_path )
618+
619+ content = File . read ( helper_path )
620+
621+ unless content . include? ( "ReactOnRails::TestHelper" ) || content . include? ( "configure_rspec_to_compile_assets" )
622+ next
623+ end
624+
625+ checker . add_success ( "✅ ReactOnRails RSpec helper configured in #{ helper_path } " )
626+ react_on_rails_test_helper_found = true
627+
628+ # Check specific configurations
629+ checker . add_success ( " ✓ Assets compilation enabled for tests" ) if content . include? ( "ensure_assets_compiled" )
630+
631+ checker . add_success ( " ✓ RSpec configuration present" ) if content . include? ( "RSpec.configure" )
632+ end
633+
634+ return if react_on_rails_test_helper_found
635+
636+ if File . exist? ( "spec" )
637+ checker . add_warning ( "⚠️ ReactOnRails RSpec helper not found" )
638+ checker . add_info ( " Add to spec/rails_helper.rb:" )
639+ checker . add_info ( " require 'react_on_rails/test_helper'" )
640+ checker . add_info ( " ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)" )
641+ else
642+ checker . add_info ( "ℹ️ No RSpec directory found - skipping RSpec helper check" )
643+ end
644+ end
645+ # rubocop:enable Metrics/CyclomaticComplexity
646+
381647 def npm_test_script?
382648 return false unless File . exist? ( "package.json" )
383649
@@ -452,6 +718,43 @@ def exit_with_status
452718 exit ( 0 )
453719 end
454720 end
721+
722+ def relativize_path ( absolute_path )
723+ return absolute_path unless absolute_path . is_a? ( String )
724+
725+ project_root = Dir . pwd
726+ if absolute_path . start_with? ( project_root )
727+ # Remove project root and leading slash to make it relative
728+ relative = absolute_path . sub ( project_root , "" ) . sub ( /^\/ / , "" )
729+ relative . empty? ? "." : relative
730+ else
731+ absolute_path
732+ end
733+ end
734+
735+ def safe_display_config_path ( label , path_value )
736+ return unless path_value
737+
738+ begin
739+ # Convert to string and relativize
740+ path_str = path_value . to_s
741+ relative_path = relativize_path ( path_str )
742+ checker . add_info ( " #{ label } : #{ relative_path } " )
743+ rescue StandardError => e
744+ checker . add_info ( " #{ label } : <error reading path: #{ e . message } >" )
745+ end
746+ end
747+
748+ def safe_display_config_value ( label , config , method_name )
749+ return unless config . respond_to? ( method_name )
750+
751+ begin
752+ value = config . send ( method_name )
753+ checker . add_info ( " #{ label } : #{ value } " )
754+ rescue StandardError => e
755+ checker . add_info ( " #{ label } : <error reading value: #{ e . message } >" )
756+ end
757+ end
455758 end
456759 # rubocop:enable Metrics/ClassLength, Metrics/AbcSize
457760end
0 commit comments