Skip to content

Automate Pro generator gem/package swap and import updates#2822

Merged
justin808 merged 37 commits intomainfrom
jg-codex/2626-pro-generator-gem-package-swap
Apr 2, 2026
Merged

Automate Pro generator gem/package swap and import updates#2822
justin808 merged 37 commits intomainfrom
jg-codex/2626-pro-generator-gem-package-swap

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented Mar 24, 2026

Summary

  • Add first-class --rsc-pro install mode to the generator, unifying --rsc --pro into a single flag with matched Pro/RSC defaults, verification checklist, and recovery commands
  • Extend standalone react_on_rails:pro upgrade flow to automate Gemfile gem swap (react_on_railsreact_on_rails_pro) with mode-aware version requirements (~> for standard Pro, exact pin in RSC Pro mode when applicable), plus bundle install after swap and automatic rollback on failure
  • Rewrite JS/TS/Vue/Svelte imports from react-on-rails to react-on-rails-pro across common frontend roots using atomic file writes, with full comment-aware parsing (block comments, multiline imports, and inline template-literal masking to avoid false rewrites inside template strings)
  • Improve package_json add return handling — treat nil as success instead of falsy failure
  • Pin RSC dependencies to explicit versions (react/react-dom to ~19.0.4, react-on-rails-rsc to 19.0.4) with fallback to unpinned install when pinned install fails
  • Improve Pro flag detection: use_pro? and use_rsc? now respect --rsc-pro, and new use_rsc_pro_mode? helper controls RSC Pro–specific behavior
  • Add Pro gem version requirement helper (pro_gem_version_requirement) — exact pin for RSC Pro mode, pessimistic (~>) for standard Pro
  • Add prerelease messaging for RSC Pro mode when the gem version is a prerelease
  • Add RSC Pro post-install verification message with startup/streaming/hydration checklist

Closes #2626

Test Plan

  • bundle exec rspec react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb
  • bundle exec rspec react_on_rails/spec/react_on_rails/generators/generator_helper_spec.rb
  • bundle exec rspec react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb
  • bundle exec rspec react_on_rails/spec/react_on_rails/generators/js_dependency_manager_spec.rb
  • bundle exec rubocop react_on_rails/lib/generators/react_on_rails/pro_generator.rb react_on_rails/lib/generators/react_on_rails/pro_setup.rb react_on_rails/lib/generators/react_on_rails/install_generator.rb

🤖 Generated with Claude Code


Note

Medium Risk
Medium risk: generator behavior now mutates Gemfile/runs bundle install, pins RSC/Pro versions, and rewrites frontend imports, which could impact existing apps if edge cases in parsing or version constraints are missed.

Overview
Adds a first-class --rsc-pro installation mode (and use_rsc_pro_mode? helper) so install flows, sub-generator invocation, recovery commands, prerequisite errors, and post-install messaging treat RSC+Pro as a single, consistent mode.

Enhances dependency handling by treating package_json add returning nil as success, pinning RSC React versions to ~19.0.4, pinning react-on-rails-rsc to 19.0.4 with retry-to-latest fallback, and making Pro gem version requirements exact in RSC Pro mode.

Extends react_on_rails:pro to automatically swap react_on_railsreact_on_rails_pro in Gemfile (with atomic writes, bundle install, and rollback on failure) and to rewrite JS/TS/Vue/Svelte imports from react-on-rails to react-on-rails-pro, with extensive spec coverage for edge cases.

Written by Cursor Bugbot for commit 7c0ecb8. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Added --rsc-pro CLI option to enable first-class React Server Components with Pro features in a single installation command.
    • Automatic Gemfile gem swap from react_on_rails to react_on_rails_pro with bundler integration.
    • Automatic rewriting of module imports from react-on-rails to react-on-rails-pro across JavaScript/TypeScript files.
    • Introduced React version pinning (~19.0.4) for RSC installations.
  • Bug Fixes

    • Improved npm dependency installation return value handling to correctly interpret nil responses as successful.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new --rsc-pro install mode and predicates, pins and retries RSC npm installs, and automates Pro upgrades by swapping the Gemfile gem, running bundle install with rollback, updating frontend imports to the Pro package, and updating install messages and tests.

Changes

Cohort / File(s) Summary
Generator helpers & install options
react_on_rails/lib/generators/react_on_rails/generator_helper.rb, react_on_rails/lib/generators/react_on_rails/install_generator.rb
Add use_rsc_pro_mode? and --rsc-pro option; broaden use_pro?/use_rsc? to consider rsc_pro; propagate computed flags into downstream generators; add route constants and update install/recovery messaging.
JS dependency management
react_on_rails/lib/generators/react_on_rails/js_dependency_manager.rb
Add RSC semver constants and rsc_packages_with_version; pin RSC react/react-dom installs, warn-and-fallback to unpinned packages on failure; treat pj.manager.add returning nil as success.
Pro generator — Gemfile & imports migration
react_on_rails/lib/generators/react_on_rails/pro_generator.rb
Implement atomic Gemfile swap react_on_railsreact_on_rails_pro (preserve existing pro entry), run bundle install with timeout/rollback handling, and rewrite frontend imports (static/dynamic/require/side-effect) to react-on-rails-pro with comment/template-literal-aware parsing.
Pro setup & messaging
react_on_rails/lib/generators/react_on_rails/pro_setup.rb
Refactor missing-Pro messaging to compute required pro flag/version based on new predicates; use exact pin in RSC Pro mode and include optional prerelease note.
Tests
react_on_rails/spec/react_on_rails/generators/generator_helper_spec.rb, .../install_generator_spec.rb, .../js_dependency_manager_spec.rb, .../pro_generator_spec.rb
Add/extend specs for --rsc-pro, predicate behavior, npm add return semantics (false vs nil), pinned-RSC installs + fallback, Gemfile-swap permutations, bundle-install rollback, and import-rewrite edge cases across JS/TS/Vue/Svelte files.

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as CLI / Generator
    participant Helper as Generator Helper
    participant Installer as Install Generator
    participant ProGen as Pro Generator
    participant Gemfile as Gemfile (file)
    participant Bundle as Bundler
    participant NPM as npm / package.json
    participant Files as Frontend files

    User->>CLI: rails g react_on_rails:install --rsc-pro
    CLI->>Helper: use_rsc_pro_mode?
    Helper-->>CLI: true
    CLI->>Installer: run install (rsc_pro: true)
    Installer->>NPM: add RSC & Pro npm packages (pinned)
    NPM-->>Installer: success / fallback to unpinned

    User->>CLI: rails g react_on_rails:pro
    CLI->>ProGen: run_generator (invoked_by_install?)
    alt invoked_by_install == false
        ProGen->>Gemfile: atomically replace react_on_rails → react_on_rails_pro
        Gemfile-->>ProGen: updated
        ProGen->>Bundle: spawn bundle install (with timeout)
        Bundle-->>ProGen: success / fail
        alt fail
            ProGen->>Gemfile: rollback to previous content
        end
        ProGen->>Files: scan & rewrite imports to react-on-rails-pro
        Files-->>ProGen: files updated
    else invoked_by_install == true
        ProGen-->>CLI: skip Gemfile & import swaps
    end
    ProGen-->>User: Pro setup complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • AbanoubGhadban
  • alexeyr-ci2

Poem

🐰 A rabbit nibbles code by moonlit glow,
Swapping gems and imports in a gentle flow.
Bundles roll and packages align,
RSC Pro springs forward — tidy, fine.
Hop, hop, upgrade — hooray! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.74% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately describes the main changes: automating the Pro generator's gem and package swap, and updating imports.
Linked Issues check ✅ Passed The PR comprehensively implements all requirements from issue #2626: gem swap with exact version pinning, bundle install with rollback, package.json updates, and import rewriting across JS/TS/Vue/Svelte files with atomic writes and comment-aware parsing.
Out of Scope Changes check ✅ Passed All changes align with the PR objectives: generator mode helpers (use_rsc_pro_mode?, use_pro?, use_rsc?), RSC package version pinning, pro_generator.rb automation, install_generator.rb enhancements, and comprehensive test coverage are all in scope.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg-codex/2626-pro-generator-gem-package-swap

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 24, 2026

Greptile Summary

This PR extends the standalone react_on_rails:pro generator to automate three migration steps that users previously had to perform manually: swapping gem 'react_on_rails' for gem 'react_on_rails_pro' in the Gemfile, running bundle install after that swap, and rewriting JS/TS import statements from react-on-rails to react-on-rails-pro. Unit tests are added for both new methods.

Key changes:

  • swap_base_gem_for_pro_in_gemfile — regex-based Gemfile rewrite + Bundler.with_unbundled_env shell-out, with a graceful warning fallback if the shell command fails
  • update_imports_to_pro_package — globs app/javascript and client for JS/TS files and replaces react-on-rails (via negative-lookahead regex) with react-on-rails-pro
  • Both methods are guarded by unless options[:invoked_by_install] so they only run in the standalone generator path, not when called from InstallGenerator
  • New unit tests cover the Gemfile swap (with and without a matching entry) and the import rewrite

Issues found:

  • The import-rewrite regex /react-on-rails(?!-pro)/ is overly broad — it will silently corrupt package names like react-on-rails-hot-loader into react-on-rails-pro-hot-loader; a tighter delimiter-anchored pattern is recommended
  • No guard prevents a duplicate react_on_rails_pro entry if the gem is already present in the Gemfile alongside react_on_rails
  • The Gemfile replacement uses an exact version pin ('#{version}') while every other site in the codebase uses the pessimistic constraint ('~> #{version}'); if intentional, a comment explaining the reasoning would help

Confidence Score: 3/5

  • Safe to merge after addressing the overly-broad import regex, which can silently corrupt companion-package names.
  • The Gemfile swap and bundle-install logic are solid and idempotent in the common case. The duplicate-gem guard and version-pin consistency are straightforward follow-ups. However, the import-rewrite regex is a real logic issue: any react-on-rails-* package name (other than -pro) in JS/TS files will be silently and incorrectly renamed. Because this mutation is written to disk without an explicit preview or dry-run mode, it's a P1 concern that warrants a fix before merge.
  • react_on_rails/lib/generators/react_on_rails/pro_generator.rb — specifically the update_imports_to_pro_package regex and swap_base_gem_for_pro_in_gemfile duplicate-gem guard.

Important Files Changed

Filename Overview
react_on_rails/lib/generators/react_on_rails/pro_generator.rb Adds three private methods for automated migration: Gemfile gem swap, bundle install trigger, and JS/TS import rewriting. Two logic issues found: the import-rewrite regex is overly broad (can corrupt non-target package names), and there is no guard against creating a duplicate react_on_rails_pro entry when the gem is already present. Version pinning is also inconsistent with the rest of the codebase.
react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb Adds unit tests for swap_base_gem_for_pro_in_gemfile and update_imports_to_pro_package. Happy-path and no-op cases are covered well. Missing coverage for: duplicate pro-gem guard, already-correct-imports file count, and the new regex edge case with compound package names.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A([run_generator]) --> B{invoked_by_install?}
    B -- yes --> C[setup_pro]
    B -- no --> D{prerequisites_met?}
    D -- no --> E[add_error: prerequisites not met]
    D -- yes --> F[swap_base_gem_for_pro_in_gemfile]
    F --> G{Gemfile exists?}
    G -- no --> H[skip]
    G -- yes --> I{react_on_rails entry found?}
    I -- no --> H
    I -- yes --> J[Write updated Gemfile]
    J --> K[bundle_install_after_gem_swap]
    K --> L{bundle install succeeded?}
    L -- yes --> M[continue]
    L -- no --> N[add_warning: run manually]
    M --> C
    H --> C
    C --> O[add_pro_npm_dependencies]
    O --> P[update_imports_to_pro_package]
    P --> Q[glob JS/TS files in app/javascript + client]
    Q --> R{any imports to rewrite?}
    R -- no --> S[skip]
    R -- yes --> T[gsub react-on-rails -> react-on-rails-pro]
    T --> U[print_success_message]
    S --> U
    U --> V([ensure: print_generator_messages])
Loading

Reviews (1): Last reviewed commit: "Automate Pro generator gem and import up..." | Re-trigger Greptile

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7be45091ca

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 24, 2026

PR Review: Automate Pro Generator Gem/Package Swap

The feature intent is correct and the overall structure is sound. One issue should be fixed before merge; the rest are lower-priority.

Must Fix

Exact version pin instead of pessimistic constraint (see inline comment on line 87)

The replacement Gemfile line uses an exact pin (16.1.0) rather than ~> 16.1.0. This is inconsistent with every other place in this codebase that writes the pro gem (install_generator.rb:256, pro_setup.rb:72), and will prevent users from picking up patch releases. The corresponding spec assertion needs updating too.

Should Fix

Import regex can corrupt sibling package names (see inline comment on line 123)

The pattern /react-on-rails(?!-pro)/ will match prefixes of hypothetical packages like react-on-rails-utils, rewriting them to react-on-rails-pro-utils. Adding a trailing boundary makes the pattern safe against false positives.

Gemfile indentation not preserved (see inline comment on lines 84-87)

If the gem is inside a group block it will be rewritten flush-left. Capturing and re-emitting the leading whitespace keeps the file tidy.

Low Priority / Follow-up

  • Integration tests pass by coincidence — the existing run_generator integration contexts do not mock the new methods; they happen not to trigger them because the test fixture has an empty Gemfile and no JS directories. This is latently fragile. Consider adding explicit stubs or a guard comment.
  • Missing test case for non-existent Gemfile — the swap_base_gem_for_pro_in_gemfile unit tests cover two cases but not the return unless File.exist? branch.
  • Rescue message — consider logging the exception class alongside the message for easier debugging when bundle_install_after_gem_swap rescue fires.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Duplicate Gemfile entry after auto-install plus swap
    • The Gemfile swap now detects existing react_on_rails_pro entries and removes the react_on_rails line instead of adding a second pro gem declaration.
  • ✅ Fixed: Gemfile replacement drops leading whitespace from indented gems
    • The replacement regex now captures and reuses leading whitespace so indented gem lines keep their original indentation.

Create PR

Or push these changes by commenting:

@cursor push 41d1ea4a52
Preview (41d1ea4a52)
diff --git a/react_on_rails/lib/generators/react_on_rails/pro_generator.rb b/react_on_rails/lib/generators/react_on_rails/pro_generator.rb
--- a/react_on_rails/lib/generators/react_on_rails/pro_generator.rb
+++ b/react_on_rails/lib/generators/react_on_rails/pro_generator.rb
@@ -82,9 +82,16 @@
         return unless File.exist?(gemfile_path)
 
         gemfile_content = File.read(gemfile_path)
+        pro_gem_line_pattern = /^\s*gem\s+["']react_on_rails_pro["'][^\n]*$/
+        pro_gem_already_present = gemfile_content.match?(pro_gem_line_pattern)
         updated_content = gemfile_content.gsub(
-          /^\s*gem\s+["']react_on_rails["'][^\n]*$/,
-          "gem 'react_on_rails_pro', '#{recommended_pro_gem_version}'"
+          /^(\s*)gem\s+["']react_on_rails["'][^\n]*$/
+        ) do
+          if pro_gem_already_present
+            ""
+          else
+            "#{Regexp.last_match(1)}gem 'react_on_rails_pro', '#{recommended_pro_gem_version}'"
+          end
         )
         return if updated_content == gemfile_content
 

diff --git a/react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb b/react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb
--- a/react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb
+++ b/react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb
@@ -58,6 +58,7 @@
   describe "#swap_base_gem_for_pro_in_gemfile" do
     let(:generator) { described_class.new }
     let(:gemfile_path) { File.join(destination_root, "Gemfile") }
+    let(:expected_version) { Gem::Version.new(ReactOnRails::VERSION).release.to_s }
 
     before do
       prepare_destination
@@ -74,12 +75,44 @@
       generator.send(:swap_base_gem_for_pro_in_gemfile)
 
       gemfile_content = File.read(gemfile_path)
-      expected_version = Gem::Version.new(ReactOnRails::VERSION).release.to_s
       expect(gemfile_content).to include("gem 'react_on_rails_pro', '#{expected_version}'")
       expect(gemfile_content).not_to match(/gem\s+["']react_on_rails["']/)
       expect(generator).to have_received(:bundle_install_after_gem_swap)
     end
 
+    it "removes react_on_rails when react_on_rails_pro is already present" do
+      simulate_existing_file("Gemfile", <<~RUBY)
+        source "https://rubygems.org"
+        gem "react_on_rails", "~> 16.0"
+        gem "react_on_rails_pro", "~> 16.0"
+      RUBY
+      allow(generator).to receive(:bundle_install_after_gem_swap)
+
+      generator.send(:swap_base_gem_for_pro_in_gemfile)
+
+      gemfile_content = File.read(gemfile_path)
+      pro_gem_lines = gemfile_content.scan(/^\s*gem\s+["']react_on_rails_pro["'][^\n]*$/)
+      expect(pro_gem_lines.length).to eq(1)
+      expect(gemfile_content).not_to match(/gem\s+["']react_on_rails["']/)
+      expect(generator).to have_received(:bundle_install_after_gem_swap)
+    end
+
+    it "preserves leading whitespace when replacing indented react_on_rails entry" do
+      simulate_existing_file("Gemfile", <<~RUBY)
+        source "https://rubygems.org"
+
+        group :production do
+          gem "react_on_rails", "~> 16.0"
+        end
+      RUBY
+      allow(generator).to receive(:bundle_install_after_gem_swap)
+
+      generator.send(:swap_base_gem_for_pro_in_gemfile)
+
+      gemfile_content = File.read(gemfile_path)
+      expect(gemfile_content).to include("  gem 'react_on_rails_pro', '#{expected_version}'")
+    end
+
     it "does nothing when Gemfile has no react_on_rails entry" do
       simulate_existing_file("Gemfile", <<~RUBY)
         source "https://rubygems.org"

Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 24, 2026

Review: Automate Pro generator gem/package swap and import updates

Good overall direction — automating manual migration steps reduces friction for Pro upgrades. A few issues to address before merging.

Potential bugs / reliability issues

  1. Multiline gem declarations produce invalid Gemfile (line 86): The base_gem_pattern regex only handles single-line declarations. A Gemfile entry split across two lines will have its first line replaced while the version string on the second line is left as an orphaned string literal, resulting in invalid Ruby that breaks bundle install immediately after the generator runs. Uncommon but valid syntax worth guarding against.

  2. bundle install has no timeout (line 110): system("bundle install") blocks indefinitely. This is inconsistent with missing_pro_gem? in pro_setup.rb, which already uses Process.spawn + wait_for_bundle_process with a deadline. Prefer the same pattern here for consistency and to avoid hanging generators.

  3. JS import scan misses common directories (lines 149-153): Only app/javascript and client are scanned. Apps using app/frontend (Vite default), frontend, or javascript will silently skip the import rewrite, causing runtime failures. Should either expand the directory list or print which directories were scanned so users can verify.

Style / minor

  1. Quote style not preserved (line 96): The replacement always emits single-quoted gem 'react_on_rails_pro' regardless of what the original Gemfile used. Worth preserving the quote delimiter from the original match or documenting the intentional normalisation.

What looks good

  • The negative-lookahead regex for import rewriting correctly avoids false matches on packages like react-on-rails-utils.
  • The has_pro_gem_entry guard correctly prevents duplicate react_on_rails_pro entries when both gems are already present.
  • Test coverage is solid for the happy paths and key edge cases (indentation, existing pro gem, no-op when nothing to change).
  • The rescue in bundle_install_after_gem_swap gracefully degrades with a clear manual fallback message.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70acd651c6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 24, 2026

Review: Automate Pro generator gem/package swap and import updates

Overall this is a well-structured addition with solid test coverage. The three new methods each have a clear responsibility, the multiline Gemfile handling is correct, and the import-rewrite regex correctly avoids false positives on scoped packages, subpaths, and URLs. A few things to address:

Bug — inline Gemfile comments break the gem swap (needs fix)

base_gem_pattern uses a lookahead (?=\s*(?:,|$)) that doesn't allow a trailing # comment:

gem "react_on_rails" # pinned, don't upgrade automatically

This line won't be matched, so the base gem silently stays in the Gemfile alongside the new Pro entry. See inline comment on line 88.

Thread-safety: prefer Process.spawn's :chdir over Dir.chdir (low risk, but worth fixing)

Dir.chdir in bundle_install_after_gem_swap changes the process-wide working directory. Process.spawn accepts a :chdir option that only affects the child process — consistent with how run_bundle_add_with_captured_output avoids this issue. See inline comment on line 134.

Regex rewrites imports inside JS comments (cosmetic)

rewrite_react_on_rails_module_specifiers will rewrite from "react-on-rails" even inside // or /* */ comment blocks. Unlikely to cause real breakage, but can produce surprising diffs. See inline comment at line 205.

Nits

  • The test for #bundle_install_after_gem_swap covers only the timeout path; a case for the failure path (install_status non-nil but !success?) would round out coverage and confirm the warning message is correct.
  • js_files_for_import_update uses Dir.glob which follows symlinks by default — if any of those roots contain symlinks pointing outside the app, files outside the destination could be rewritten. Very low risk in practice.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d1d84e286d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb
Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 24, 2026

Review Summary

The PR cleanly automates the Pro upgrade path and the implementation is well-structured. Test coverage for the Gemfile swap edge cases is thorough. A few issues worth addressing before merge:

Medium: Gemfile left dirty if bundle install fails

swap_base_gem_for_pro_in_gemfile writes the modified Gemfile to disk before calling bundle_install_after_gem_swap. If the install fails (missing Pro gem credentials, network error, etc.) the Gemfile no longer references react_on_rails but Gemfile.lock still does, leaving the app in a silently broken state. Consider rolling back the Gemfile write on bundle install failure. See inline comment at lines 126-128.

Medium: gemspec-based Gemfiles silently skipped

Projects that pin react_on_rails inside a .gemspec and only call gemspec in their Gemfile will get no feedback and finish the generator with a half-migrated state. A targeted warning would help. See inline comment at line 84.

Minor: Process.spawn should use array form

"bundle install" as a single string is shell-interpolated. The array form ("bundle", "install") is safer and consistent with how run_bundle_add_with_captured_output works in pro_setup.rb. See inline comment at line 137.

Minor: .vue/.svelte files excluded from import rewriting

Vue SFCs and Svelte components frequently import from react-on-rails and are common in Rails + Vite apps. Either add them to the extension list or add a comment explaining the intentional boundary. See inline comment at line 191.

Nit: \bimport\s+ alternative in the regex can be tightened

The last alternative matches too broadly and causes unnecessary backtracking on every named/default import. Adding (?=["']) restricts it to side-effect imports only. See inline comment at lines 200-210.


The multiline Gemfile consumption loop was reviewed carefully and the logic is correct for all traced cases (single-line, multi-continuation, trailing-comment-after-comma, last-line-of-file).

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a52331289

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Comment-trailing commas falsely trigger multiline consumption
    • I updated comma-continuation detection to strip trailing comments before checking for a code-level comma and added a regression spec ensuring the next Gemfile line is preserved.

Create PR

Or push these changes by commenting:

@cursor push 1a3e8b72e2
Preview (1a3e8b72e2)
diff --git a/react_on_rails/lib/generators/react_on_rails/pro_generator.rb b/react_on_rails/lib/generators/react_on_rails/pro_generator.rb
--- a/react_on_rails/lib/generators/react_on_rails/pro_generator.rb
+++ b/react_on_rails/lib/generators/react_on_rails/pro_generator.rb
@@ -215,7 +215,8 @@
       end
 
       def line_continues_with_comma?(line)
-        line.rstrip.match?(/,\s*(?:#.*)?\z/)
+        code_without_comment = line.sub(/\s*#.*\z/, "")
+        code_without_comment.rstrip.end_with?(",")
       end
 
       def print_success_message

diff --git a/react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb b/react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb
--- a/react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb
+++ b/react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb
@@ -193,6 +193,23 @@
       expect(gemfile_content).not_to include("gem \"react_on_rails\" # pinned for compatibility")
       expect(generator).to have_received(:bundle_install_after_gem_swap)
     end
+
+    it "does not treat trailing comment commas as multiline continuation" do
+      simulate_existing_file("Gemfile", <<~RUBY)
+        source "https://rubygems.org"
+        gem "react_on_rails" # keep this one,
+        gem "rails"
+      RUBY
+      allow(generator).to receive(:bundle_install_after_gem_swap)
+
+      generator.send(:swap_base_gem_for_pro_in_gemfile)
+
+      gemfile_content = File.read(gemfile_path)
+      expected_version = Gem::Version.new(ReactOnRails::VERSION).release.to_s
+      expect(gemfile_content).to include("gem \"react_on_rails_pro\", \"~> #{expected_version}\"")
+      expect(gemfile_content).to include("gem \"rails\"")
+      expect(generator).to have_received(:bundle_install_after_gem_swap)
+    end
   end
 
   describe "#bundle_install_after_gem_swap" do

Comment thread react_on_rails/lib/generators/react_on_rails/pro_generator.rb

def line_has_unescaped_backtick?(line, line_for_tracking: nil)
line_to_track = line_for_tracking || line_for_template_literal_tracking(line)
update_multiline_template_literal_state(false, line_to_track)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug (edge case): wrong return value for lines with even backtick count

update_multiline_template_literal_state(false, line) returns false when the line has an even number of unescaped backticks (including 0, 2, 4 …), so line_has_unescaped_backtick? returns false for those lines even when backticks are actually present.

For the common case (2 backticks = one complete inline template literal), the line falls through to the normal yield path and rewrite_outside_inline_template_literals correctly masks the template content — so this is safe. However, for a line with 3 backticks, e.g.:

`done`; import("react-on-rails"); `multiline-start

the method returns true (odd count), so rewrite_line_before_template_literal_open is called. That method finds the first backtick at index 0, the opening_index&.positive? guard returns the line unchanged, and the import("react-on-rails") in the middle is never rewritten.

The Cursor autofix on this review (commit 2f35144a2a, branch cursor/template-literal-rewriting-bug-4fa1) fixes both this method and rewrite_line_before_template_literal_open to handle the single-line-then-multiline scenario. Applying that fix (or an equivalent) would close this gap.

This is an uncommon pattern in real JS, but it is a correctness hole in the import rewriter.

🚫 Failed to auto-install #{PRO_GEM_NAME} gem.

#{context_line}
#{prerelease_note}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: double blank line when prerelease note is empty

When rsc_pro_prerelease_note returns "" (non-RSC-pro mode, or non-prerelease version), the #{prerelease_note} interpolation expands to an empty string, leaving two consecutive blank lines between context_line and Please add manually …:

You specified --pro, which requires the react_on_rails_pro gem.


Please add manually to your Gemfile:

One option to suppress the extra blank line when the note is empty:

Suggested change
#{prerelease_note}
#{prerelease_note.empty? ? nil : "#{prerelease_note}\n"}

Or conditionally omit the line:

#{"          #{prerelease_note}\n" unless prerelease_note.empty?}

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 2, 2026

Code Review summary - see inline comments for specifics.

Overall this is a well-engineered PR: Gemfile swap with multiline/parenthesized gem support, atomic writes, rollback-on-failure for bundle install, and the comment/template-literal-aware import rewriter are all solid. Test coverage is thorough.

One remaining bug (inline comment on pro_generator.rb line 691): line_has_unescaped_backtick? delegates to update_multiline_template_literal_state(false, line) which returns false for lines with an even backtick count. For the 3-backtick case (complete template literal + dynamic import + multiline template literal start, all on one line), the odd count sends the line to rewrite_line_before_template_literal_open, which hits the opening_index not positive early return, and the import between the two template literals is never rewritten. The Cursor autofix on branch cursor/template-literal-rewriting-bug-4fa1 (commit 2f35144) addresses this.

Minor (inline comment on pro_setup.rb line 70): when rsc_pro_prerelease_note returns an empty string, the heredoc interpolation leaves two consecutive blank lines in the error output.

next_line = gemfile_lines[line_index]
current_line = next_line unless comment_or_blank_line?(next_line)
line_index += 1
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: options on non-parenthesized multiline continuation lines are silently dropped.

The suffix passed to build_pro_gem_replacement_line is taken exclusively from line[match.end(0)..] (the tail of the first matched line). When a non-parenthesized declaration spreads Ruby options across continuation lines, e.g.:

gem "react_on_rails",
  "~> 16.0",
  require: false   # ← this line is consumed below but never captured

the require: false line is consumed by this inner while loop but is never appended to suffix, so it's silently lost in the replacement.

The parenthesized form (gem(...)) handles this correctly via match_multiline_parenthesized_base_gem and the multi-line trailing_suffix construction. The non-parenthesized form needs the same treatment: collect every consumed non-version-string continuation line and append it to suffix.

There is no test covering this pattern (multiline non-parenthesized with a Ruby keyword argument on a continuation line).

temp_path = nil
ensure
temp_file&.close unless temp_file&.closed?
File.delete(temp_path) if temp_path && File.exist?(temp_path)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tempfile finalizer will attempt to unlink the already-moved file.

After FileUtils.mv(temp_path, path) succeeds and temp_path = nil is set, the temp_file object still holds the original path internally. When it is garbage-collected, Ruby's Tempfile finalizer will call unlink on that path — which no longer exists. This is harmless (the unlink silently fails) but it is a resource-management smell.

To be explicit and avoid the dangling finalizer, call temp_file.unlink immediately after the mv (before setting temp_path = nil):

Suggested change
File.delete(temp_path) if temp_path && File.exist?(temp_path)
FileUtils.mv(temp_path, path)
temp_file.unlink
File.chmod(original_mode, path) if original_mode
temp_path = nil

next [] unless Dir.exist?(root_path)

Dir.glob(File.join(root_path, "**", "*.{#{js_extensions}}"))
.reject { |f| f.include?("/node_modules/") }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unix-only path separator in node_modules exclusion.

f.include?("/node_modules/") uses a hard-coded forward slash. On Windows the path would contain \node_modules\, so this filter would silently fail and the generator would attempt to rewrite files inside node_modules.

Suggested change
.reject { |f| f.include?("/node_modules/") }
.reject { |f| f.include?("#{File::SEPARATOR}node_modules#{File::SEPARATOR}") }

Or simply:

Suggested change
.reject { |f| f.include?("/node_modules/") }
.reject { |f| f.split(File::SEPARATOR).include?("node_modules") }

Comment on lines +346 to +354
static_import_specifier_pattern = %r{
(?<prefix>
\A\s*(?:/\*.*?\*/\s*)?(?:import|export)(?:\s+type)?\s+.*?\s+from\s+|
\A\s*[\w\}\],\*\$\s]+\s+from\s+
)
(?<quote>["'])
react-on-rails(?!-pro)
(?=(?:["']|/))
}x
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\A anchor with String#gsub rewrites at most one match per line for static imports.

\A anchors to the very start of the string (here, one line). gsub can only find a second match after the first, but \A never matches except at position 0, so at most one static import per line is rewritten.

For the common case this is fine (one import per line). However a line like:

import A from "react-on-rails"; import B from "react-on-rails";

would have only the first import rewritten. The dynamic_or_require_specifier_pattern (no \A) handles its targets correctly for multi-occurrence lines.

This is a low-probability edge case, but it's worth documenting as a known limitation, or switching to ^ (start-of-line) with the m flag and \n? at the end of the match to stay line-scoped.

Comment on lines +239 to +247
pid = Process.spawn(
{ "BUNDLE_GEMFILE" => gemfile_path },
"bundle",
"install",
out: $stdout,
err: $stderr,
chdir: destination_root
)
wait_for_bundle_process(pid)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bundle install output is interleaved with generator output.

out: $stdout, err: $stderr routes the subprocess's stdio to the generator's own handles. During a normal rails generate run this means raw Bundler output (resolving gems, fetching sources, etc.) is printed inline with the generator's own say_status lines, without any visual distinction.

Consider buffering or suppressing subprocess output and only surfacing it on failure, similar to how attempt_pro_gem_auto_install in ProSetup works. If verbose output is desired, at minimum print a separator so users know what they're seeing:

say "─── bundle install output ───────────────────────────────────", :cyan

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 5 total unresolved issues (including 4 from previous reviews).

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: RSC Pro auto-install uses ~> instead of exact pin
    • Updated pro_gem_auto_install_command to omit --strict in RSC Pro mode so bundle add keeps the exact version pin, and adjusted the RSC Pro install spec expectations accordingly.

Create PR

Or push these changes by commenting:

@cursor push c86d3e44f1
Preview (c86d3e44f1)
diff --git a/react_on_rails/lib/generators/react_on_rails/pro_setup.rb b/react_on_rails/lib/generators/react_on_rails/pro_setup.rb
--- a/react_on_rails/lib/generators/react_on_rails/pro_setup.rb
+++ b/react_on_rails/lib/generators/react_on_rails/pro_setup.rb
@@ -483,7 +483,9 @@
       end
 
       def pro_gem_auto_install_command
-        "bundle add #{PRO_GEM_NAME} --version='#{pro_gem_version_requirement}' --strict"
+        command = "bundle add #{PRO_GEM_NAME} --version='#{pro_gem_version_requirement}'"
+        command += " --strict" unless use_rsc_pro_mode?
+        command
       end
 
       def pro_gem_version_requirement

diff --git a/react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb b/react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb
--- a/react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb
+++ b/react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb
@@ -2881,7 +2881,7 @@
       expect(install_generator.send(:missing_pro_gem?)).to be true
       expect(Bundler).to have_received(:with_unbundled_env)
       expect(Process).to have_received(:spawn)
-        .with("bundle add react_on_rails_pro --version='#{expected_pro_version}' --strict",
+        .with("bundle add react_on_rails_pro --version='#{expected_pro_version}'",
               out: anything,
               err: anything)
       error_text = GeneratorMessages.messages.join("\n")
@@ -2895,7 +2895,7 @@
 
       expect(install_generator.send(:missing_pro_gem?)).to be true
       expect(Process).to have_received(:spawn)
-        .with("bundle add react_on_rails_pro --version='16.4.0.rc.5' --strict",
+        .with("bundle add react_on_rails_pro --version='16.4.0.rc.5'",
               out: anything,
               err: anything)
       error_text = GeneratorMessages.messages.join("\n")

You can send follow-ups to this agent here.


def pro_gem_auto_install_command
"bundle add #{PRO_GEM_NAME} --version='~> #{recommended_pro_gem_version}' --strict"
"bundle add #{PRO_GEM_NAME} --version='#{pro_gem_version_requirement}' --strict"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RSC Pro auto-install uses ~> instead of exact pin

Low Severity

pro_gem_auto_install_command unconditionally appends --strict, which tells bundle add to use the ~> operator. In RSC Pro mode, pro_gem_version_requirement returns an exact version (e.g., "16.4.0"), so the command produces gem "react_on_rails_pro", "~> 16.4.0" instead of the intended exact pin "16.4.0". The standalone pro generator's swap corrects this, but the install generator skips the swap, leaving a pessimistic constraint.

Additional Locations (1)
Fix in Cursor Fix in Web

@justin808 justin808 merged commit 691ae70 into main Apr 2, 2026
40 checks passed
@justin808 justin808 deleted the jg-codex/2626-pro-generator-gem-package-swap branch April 2, 2026 06:36
ihabadham added a commit that referenced this pull request Apr 10, 2026
The --rsc-pro flag was redundant with --rsc (which already implies Pro)
and was originally closed as an "unnecessary parallel mode" in #2821 before
shipping unintentionally alongside the Pro upgrade automation in #2822.

Fold the useful behaviors previously gated on --rsc-pro into --rsc:

- Pro verification checklist message now fires on any --rsc install
  instead of only when use_rsc_pro_mode? was true.
- Prerelease installation note (rsc_prerelease_note) now fires on any
  --rsc install with a prerelease gem version.
- Exact version pin for the Pro gem now triggers on
  Gem::Version.new(ReactOnRails::VERSION).prerelease? instead of the flag.
  This is the real underlying reason: Bundler's ~> does not match
  prerelease versions, so stable --rsc installs continue to use ~> while
  prerelease cycles get an exact pin that actually installs.

Side effect: plain --rsc on a prerelease gem version now installs
correctly where it previously would have failed against ~> pinning.

Removes:

- class_option :rsc_pro
- use_rsc_pro_mode? helper
- the --rsc-pro branches in use_pro?, use_rsc?, pro_requirement_flag,
  recovery_install_command
- all --rsc-pro test contexts in install_generator_spec and the
  RSC Pro mode helpers describe block in generator_helper_spec

Does not touch pro_generator.rb or pro_generator_spec.rb; those cover
the #2626 upgrade automation scope (independent of this flag), and the
silent-failure bugs there are tracked separately in #3104.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
justin808 added a commit that referenced this pull request Apr 12, 2026
## Summary
- Add first-class `--rsc-pro` install mode to the generator, unifying
`--rsc --pro` into a single flag with matched Pro/RSC defaults,
verification checklist, and recovery commands
- Extend standalone `react_on_rails:pro` upgrade flow to automate
Gemfile gem swap (`react_on_rails` → `react_on_rails_pro`) with
mode-aware version requirements (`~>` for standard Pro, exact pin in RSC
Pro mode when applicable), plus `bundle install` after swap and
automatic rollback on failure
- Rewrite JS/TS/Vue/Svelte imports from `react-on-rails` to
`react-on-rails-pro` across common frontend roots using atomic file
writes, with full comment-aware parsing (block comments, multiline
imports, and inline template-literal masking to avoid false rewrites
inside template strings)
- Improve `package_json` add return handling — treat `nil` as success
instead of falsy failure
- Pin RSC dependencies to explicit versions (`react`/`react-dom` to
`~19.0.4`, `react-on-rails-rsc` to `19.0.4`) with fallback to unpinned
install when pinned install fails
- Improve Pro flag detection: `use_pro?` and `use_rsc?` now respect
`--rsc-pro`, and new `use_rsc_pro_mode?` helper controls RSC
Pro–specific behavior
- Add Pro gem version requirement helper (`pro_gem_version_requirement`)
— exact pin for RSC Pro mode, pessimistic (`~>`) for standard Pro
- Add prerelease messaging for RSC Pro mode when the gem version is a
prerelease
- Add RSC Pro post-install verification message with
startup/streaming/hydration checklist

Closes #2626

## Test Plan
- `bundle exec rspec
react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb`
- `bundle exec rspec
react_on_rails/spec/react_on_rails/generators/generator_helper_spec.rb`
- `bundle exec rspec
react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb`
- `bundle exec rspec
react_on_rails/spec/react_on_rails/generators/js_dependency_manager_spec.rb`
- `bundle exec rubocop
react_on_rails/lib/generators/react_on_rails/pro_generator.rb
react_on_rails/lib/generators/react_on_rails/pro_setup.rb
react_on_rails/lib/generators/react_on_rails/install_generator.rb`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk: generator behavior now mutates `Gemfile`/runs `bundle
install`, pins RSC/Pro versions, and rewrites frontend imports, which
could impact existing apps if edge cases in parsing or version
constraints are missed.
> 
> **Overview**
> Adds a first-class `--rsc-pro` installation mode (and
`use_rsc_pro_mode?` helper) so install flows, sub-generator invocation,
recovery commands, prerequisite errors, and post-install messaging treat
RSC+Pro as a single, consistent mode.
> 
> Enhances dependency handling by treating `package_json` `add`
returning `nil` as success, pinning RSC React versions to `~19.0.4`,
pinning `react-on-rails-rsc` to `19.0.4` with retry-to-latest fallback,
and making Pro gem version requirements exact in RSC Pro mode.
> 
> Extends `react_on_rails:pro` to automatically swap `react_on_rails` →
`react_on_rails_pro` in `Gemfile` (with atomic writes, `bundle install`,
and rollback on failure) and to rewrite JS/TS/Vue/Svelte imports from
`react-on-rails` to `react-on-rails-pro`, with extensive spec coverage
for edge cases.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7c0ecb8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added `--rsc-pro` CLI option to enable first-class React Server
Components with Pro features in a single installation command.
* Automatic Gemfile gem swap from `react_on_rails` to
`react_on_rails_pro` with bundler integration.
* Automatic rewriting of module imports from `react-on-rails` to
`react-on-rails-pro` across JavaScript/TypeScript files.
  * Introduced React version pinning (~19.0.4) for RSC installations.

* **Bug Fixes**
* Improved npm dependency installation return value handling to
correctly interpret `nil` responses as successful.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
justin808 added a commit that referenced this pull request Apr 12, 2026
## Summary
- Add first-class `--rsc-pro` install mode to the generator, unifying
`--rsc --pro` into a single flag with matched Pro/RSC defaults,
verification checklist, and recovery commands
- Extend standalone `react_on_rails:pro` upgrade flow to automate
Gemfile gem swap (`react_on_rails` → `react_on_rails_pro`) with
mode-aware version requirements (`~>` for standard Pro, exact pin in RSC
Pro mode when applicable), plus `bundle install` after swap and
automatic rollback on failure
- Rewrite JS/TS/Vue/Svelte imports from `react-on-rails` to
`react-on-rails-pro` across common frontend roots using atomic file
writes, with full comment-aware parsing (block comments, multiline
imports, and inline template-literal masking to avoid false rewrites
inside template strings)
- Improve `package_json` add return handling — treat `nil` as success
instead of falsy failure
- Pin RSC dependencies to explicit versions (`react`/`react-dom` to
`~19.0.4`, `react-on-rails-rsc` to `19.0.4`) with fallback to unpinned
install when pinned install fails
- Improve Pro flag detection: `use_pro?` and `use_rsc?` now respect
`--rsc-pro`, and new `use_rsc_pro_mode?` helper controls RSC
Pro–specific behavior
- Add Pro gem version requirement helper (`pro_gem_version_requirement`)
— exact pin for RSC Pro mode, pessimistic (`~>`) for standard Pro
- Add prerelease messaging for RSC Pro mode when the gem version is a
prerelease
- Add RSC Pro post-install verification message with
startup/streaming/hydration checklist

Closes #2626

## Test Plan
- `bundle exec rspec
react_on_rails/spec/react_on_rails/generators/pro_generator_spec.rb`
- `bundle exec rspec
react_on_rails/spec/react_on_rails/generators/generator_helper_spec.rb`
- `bundle exec rspec
react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb`
- `bundle exec rspec
react_on_rails/spec/react_on_rails/generators/js_dependency_manager_spec.rb`
- `bundle exec rubocop
react_on_rails/lib/generators/react_on_rails/pro_generator.rb
react_on_rails/lib/generators/react_on_rails/pro_setup.rb
react_on_rails/lib/generators/react_on_rails/install_generator.rb`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk: generator behavior now mutates `Gemfile`/runs `bundle
install`, pins RSC/Pro versions, and rewrites frontend imports, which
could impact existing apps if edge cases in parsing or version
constraints are missed.
> 
> **Overview**
> Adds a first-class `--rsc-pro` installation mode (and
`use_rsc_pro_mode?` helper) so install flows, sub-generator invocation,
recovery commands, prerequisite errors, and post-install messaging treat
RSC+Pro as a single, consistent mode.
> 
> Enhances dependency handling by treating `package_json` `add`
returning `nil` as success, pinning RSC React versions to `~19.0.4`,
pinning `react-on-rails-rsc` to `19.0.4` with retry-to-latest fallback,
and making Pro gem version requirements exact in RSC Pro mode.
> 
> Extends `react_on_rails:pro` to automatically swap `react_on_rails` →
`react_on_rails_pro` in `Gemfile` (with atomic writes, `bundle install`,
and rollback on failure) and to rewrite JS/TS/Vue/Svelte imports from
`react-on-rails` to `react-on-rails-pro`, with extensive spec coverage
for edge cases.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7c0ecb8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added `--rsc-pro` CLI option to enable first-class React Server
Components with Pro features in a single installation command.
* Automatic Gemfile gem swap from `react_on_rails` to
`react_on_rails_pro` with bundler integration.
* Automatic rewriting of module imports from `react-on-rails` to
`react-on-rails-pro` across JavaScript/TypeScript files.
  * Introduced React version pinning (~19.0.4) for RSC installations.

* **Bug Fixes**
* Improved npm dependency installation return value handling to
correctly interpret `nil` responses as successful.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
justin808 added a commit that referenced this pull request Apr 12, 2026
## Summary
- Add missing test assertions for the `--rsc-pro` generator context to
match the thoroughness of the `--rsc` tests
- Verifies node-renderer.js creation, RSC bundle watcher in
Procfile.dev, HelloServer replacing HelloWorld (controller + routes +
components), hello_server and rsc_payload routes, and
rscWebpackConfig.js

The `--rsc-pro` generator mode implementation was completed in #2822,
but the test coverage was incomplete — only version pinning and
DEFAULT_ROUTE were verified. This closes the gap by adding route,
component, Procfile, and webpack config assertions.

Closes #2793

## Test plan
- [x] `bundle exec rspec
react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb
-e "with --rsc-pro"` — 12 examples, 0 failures
- [x] `bundle exec rubocop` — no offenses

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: only adds RSpec assertions around generator output, with no
production code changes. Main risk is increased test brittleness if
templates evolve.
> 
> **Overview**
> Strengthens test coverage for the `react_on_rails:install --rsc-pro`
path by asserting generation of `client/node-renderer.js`, the RSC
bundle watcher entry in `Procfile.dev`, and the switch from `HelloWorld`
scaffolding to `HelloServer`.
> 
> Adds checks that `config/routes.rb` includes both `hello_server` and
`rsc_payload`, and verifies RSC-specific webpack artifacts
(`config/webpack/rscWebpackConfig.js` plus `RSCWebpackPlugin` usage and
the `rscBundle` parameter in `serverWebpackConfig`).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
1b5b1d1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Expanded test coverage for installation configuration validation,
including scaffold setup and configuration file generation checks.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
ihabadham added a commit that referenced this pull request Apr 21, 2026
The --rsc-pro flag was redundant with --rsc (which already implies Pro)
and was originally closed as an "unnecessary parallel mode" in #2821 before
shipping unintentionally alongside the Pro upgrade automation in #2822.

Fold the useful behaviors previously gated on --rsc-pro into --rsc:

- Pro verification checklist message now fires on any --rsc install
  instead of only when use_rsc_pro_mode? was true.
- Prerelease installation note (rsc_prerelease_note) now fires on any
  --rsc install with a prerelease gem version.
- Exact version pin for the Pro gem now triggers on
  Gem::Version.new(ReactOnRails::VERSION).prerelease? instead of the flag.
  This is the real underlying reason: Bundler's ~> does not match
  prerelease versions, so stable --rsc installs continue to use ~> while
  prerelease cycles get an exact pin that actually installs.

Side effect: plain --rsc on a prerelease gem version now installs
correctly where it previously would have failed against ~> pinning.

Removes:

- class_option :rsc_pro
- use_rsc_pro_mode? helper
- the --rsc-pro branches in use_pro?, use_rsc?, pro_requirement_flag,
  recovery_install_command
- all --rsc-pro test contexts in install_generator_spec and the
  RSC Pro mode helpers describe block in generator_helper_spec

Does not touch pro_generator.rb or pro_generator_spec.rb; those cover
the #2626 upgrade automation scope (independent of this flag), and the
silent-failure bugs there are tracked separately in #3104.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
ihabadham added a commit that referenced this pull request Apr 21, 2026
## Summary

#2821 introduced a dedicated `--rsc-pro` install flag. It was closed the
next
day with: "Closing as redundant: current generator semantics already
treat --rsc
as including Pro by design, so introducing --rsc-pro adds an unnecessary
parallel
mode."

The flag then shipped anyway in #2822, which was primarily about the Pro
upgrade
automation (#2626 — Gemfile swap, import rewriter). The --rsc-pro bits
rode along
as a ~10% passenger in that larger PR and were never removed after
#2821's close.

#3098 was then opened to add more tests for the flag, further
entrenching
something that was explicitly called redundant.

This PR completes the intent behind #2821's close: removes the flag and
folds
its useful behaviors into --rsc, where they belong.

## What moves from --rsc-pro to --rsc

- Pro verification checklist now fires on any --rsc install
- Prerelease installation note now fires on any --rsc install with a
prerelease
  gem version
- Exact version pin for the Pro gem now triggers on
`Gem::Version.new(ReactOnRails::VERSION).prerelease?` instead of the
flag —
this is the real reason exact pinning matters (Bundler's `~>` doesn't
match
  prereleases), not a flag-specific behavior

Side effect: plain `--rsc` on a prerelease gem version now installs
correctly
where it previously would have failed against `~>` pinning.

## What is removed

- `class_option :rsc_pro`
- `use_rsc_pro_mode?` helper
- `--rsc-pro` branches in `use_pro?`, `use_rsc?`,
`pro_requirement_flag`,
  `recovery_install_command`
- All `--rsc-pro` test contexts

## What is NOT touched

`pro_generator.rb` and `pro_generator_spec.rb` (the #2626 upgrade
automation —
Gemfile swap, import rewriter) are independent of this flag and
untouched. Bugs
in that code are tracked separately in #3104.

## Closes / supersedes

Supersedes #3098 (its test assertions were inside `context "with
--rsc-pro"`,
which no longer exists).

## Test plan

- `bundle exec rubocop` on all modified files — clean
- CI to run the full rspec suite

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Removed**
  * The Pro-specific install flag `--rsc-pro` has been removed.

* **Changed**
* Pro-related behaviors that previously required `--rsc-pro` now apply
when using `--rsc` (post-install verification checklist, prerelease
install notes, and exact Pro gem pinning for prereleases).

* **Chore**
* Added a URL exclusion to link-checking configuration to skip a
specific domain.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex PRs created from codex-named branches enhancement full-ci P1 Target this sprint P2 Backlog priority review-needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pro generator should automate gem/package swap during upgrade

2 participants