@@ -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 } #{ 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 } #{ 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 } #{ 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 } #{ 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 } #{ e . message }  ) 
756+       end 
757+     end 
455758  end 
456759  # rubocop:enable Metrics/ClassLength, Metrics/AbcSize 
457760end 
0 commit comments