Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile.development_dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ group :development, :test do
gem "pry-doc"
gem "pry-rails"
gem "pry-rescue"
gem "rbs", require: false
gem "rubocop", "1.61.0", require: false
gem "rubocop-performance", "~>1.20.0", require: false
gem "rubocop-rspec", "~>2.26", require: false
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rbs (3.9.5)
logger
rdoc (6.15.1)
erb
psych (>= 4.0.0)
Expand Down Expand Up @@ -437,6 +439,7 @@ DEPENDENCIES
pry-rescue
puma (~> 6.0)
rails (~> 7.1)
rbs
react_on_rails!
rspec-rails
rspec-retry
Expand Down
38 changes: 38 additions & 0 deletions rakelib/rbs.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

# rubocop:disable Metrics/BlockLength
namespace :rbs do
desc "Validate RBS type signatures"
task :validate do
require "rbs"
require "rbs/cli"

puts "Validating RBS type signatures..."

# Run RBS validate
result = system("bundle exec rbs -I sig validate")

case result
when true
puts "✓ RBS validation passed"
when false
puts "✗ RBS validation failed"
exit 1
when nil
puts "✗ RBS command not found or could not be executed"
exit 1
end
end

desc "Check RBS type signatures (alias for validate)"
task check: :validate

desc "List all RBS files"
task :list do
sig_files = Dir.glob("sig/**/*.rbs")
puts "RBS type signature files:"
sig_files.each { |f| puts " #{f}" }
puts "\nTotal: #{sig_files.count} files"
end
end
# rubocop:enable Metrics/BlockLength
52 changes: 52 additions & 0 deletions sig/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# RBS Type Signatures

This directory contains RBS (Ruby Signature) type definitions for the React on Rails gem.

## What is RBS?

RBS is Ruby's official type signature language. It provides type information for Ruby code, enabling:

- Better IDE support and autocomplete
- Static type checking with tools like Steep
- Improved documentation
- Early detection of type-related bugs

## Structure

The signatures are organized to mirror the `lib/` directory structure:

- `react_on_rails.rbs` - Main module and core classes
- `react_on_rails/configuration.rbs` - Configuration class types
- `react_on_rails/helper.rbs` - View helper method signatures
- `react_on_rails/server_rendering_pool.rbs` - Server rendering types
- `react_on_rails/utils.rbs` - Utility method signatures
- And more...

## Validation

To validate the RBS signatures:

```bash
bundle exec rake rbs:validate
```

Or directly:

```bash
bundle exec rbs -I sig validate
```

To list all RBS files:

```bash
bundle exec rake rbs:list
```

## Development

When adding new public methods or classes to the gem, please also add corresponding RBS signatures.

For more information about RBS:

- [RBS Documentation](https://github.com/ruby/rbs)
- [RBS Syntax Guide](https://github.com/ruby/rbs/blob/master/docs/syntax.md)
38 changes: 38 additions & 0 deletions sig/react_on_rails.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Type signatures for ReactOnRails gem

module ReactOnRails
VERSION: String

DEFAULT_GENERATED_ASSETS_DIR: String
DEFAULT_COMPONENT_REGISTRY_TIMEOUT: Integer

def self.configure: () { (Configuration) -> void } -> void
def self.configuration: () -> Configuration

class Error < StandardError
end

class PrerenderError < Error
attr_reader component_name: String?
attr_reader js_code: String?
attr_reader err: Hash[Symbol, untyped]?
attr_reader props: (Hash[Symbol, untyped] | String)?
attr_reader console_messages: Array[String]?

def initialize: (
?component_name: String?,
?js_code: String?,
?err: Hash[Symbol, untyped]?,
?props: (Hash[Symbol, untyped] | String)?,
?console_messages: Array[String]?
) -> void

def to_honeybadger_context: () -> Hash[Symbol, untyped]
def raven_context: () -> Hash[Symbol, untyped]
def to_error_context: () -> Hash[Symbol, untyped]
end

class JsonParseError < Error
def initialize: (Hash[Symbol, untyped] err) -> void
end
end
96 changes: 96 additions & 0 deletions sig/react_on_rails/configuration.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
module ReactOnRails
class Configuration
attr_accessor node_modules_location: String?
attr_accessor server_bundle_js_file: String
attr_accessor prerender: bool
attr_accessor replay_console: bool
attr_accessor trace: bool
attr_accessor development_mode: bool
attr_accessor logging_on_server: bool
attr_accessor server_renderer_pool_size: Integer
attr_accessor server_renderer_timeout: Integer
attr_accessor skip_display_none: bool?
attr_accessor raise_on_prerender_error: bool
attr_accessor generated_assets_dirs: Array[String]?
attr_accessor generated_assets_dir: String
attr_accessor components_subdirectory: String?
attr_accessor webpack_generated_files: Array[String]
attr_accessor rendering_extension: String?
attr_accessor build_test_command: String
attr_accessor build_production_command: String
attr_accessor i18n_dir: String?
attr_accessor i18n_yml_dir: String?
attr_accessor i18n_output_format: Symbol?
attr_accessor i18n_yml_safe_load_options: Hash[Symbol, untyped]?
attr_accessor defer_generated_component_packs: bool
attr_accessor server_render_method: String?
attr_accessor random_dom_id: bool
attr_accessor auto_load_bundle: bool
attr_accessor same_bundle_for_client_and_server: bool
attr_accessor rendering_props_extension: String?
attr_accessor make_generated_server_bundle_the_entrypoint: bool
attr_accessor generated_component_packs_loading_strategy: Symbol?
attr_accessor immediate_hydration: bool
attr_accessor component_registry_timeout: Integer
attr_accessor server_bundle_output_path: String?
attr_accessor enforce_private_server_bundles: bool

def initialize: (
?node_modules_location: String?,
?server_bundle_js_file: String?,
?prerender: bool?,
?replay_console: bool?,
?make_generated_server_bundle_the_entrypoint: bool?,
?trace: bool?,
?development_mode: bool?,
?defer_generated_component_packs: bool?,
?logging_on_server: bool?,
?server_renderer_pool_size: Integer?,
?server_renderer_timeout: Integer?,
?raise_on_prerender_error: bool?,
?skip_display_none: bool?,
?generated_assets_dirs: Array[String]?,
?generated_assets_dir: String?,
?webpack_generated_files: Array[String]?,
?rendering_extension: String?,
?build_test_command: String?,
?build_production_command: String?,
?generated_component_packs_loading_strategy: Symbol?,
?same_bundle_for_client_and_server: bool?,
?i18n_dir: String?,
?i18n_yml_dir: String?,
?i18n_output_format: Symbol?,
?i18n_yml_safe_load_options: Hash[Symbol, untyped]?,
?random_dom_id: bool?,
?server_render_method: String?,
?rendering_props_extension: String?,
?components_subdirectory: String?,
?auto_load_bundle: bool?,
?immediate_hydration: bool?,
?component_registry_timeout: Integer?,
?server_bundle_output_path: String?,
?enforce_private_server_bundles: bool?
) -> void

def setup_config_values: () -> void

private

def check_component_registry_timeout: () -> void
def validate_generated_component_packs_loading_strategy: () -> void
def validate_enforce_private_server_bundles: () -> void
def check_minimum_shakapacker_version: () -> void
def check_autobundling_requirements: () -> void
def adjust_precompile_task: () -> void
def error_if_using_packer_and_generated_assets_dir_not_match_public_output_path: () -> void
def check_server_render_method_is_only_execjs: () -> void
def configure_generated_assets_dirs_deprecation: () -> void
def ensure_webpack_generated_files_exists: () -> void
def configure_skip_display_none_deprecation: () -> void
def raise_missing_components_subdirectory: () -> void
def compile_command_conflict_message: () -> String
def rsc_bundle_js_file: () -> String?
def react_client_manifest_file: () -> String?
def react_server_client_manifest_file: () -> String?
end
end
15 changes: 15 additions & 0 deletions sig/react_on_rails/controller.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module ReactOnRails
module Controller
# Type alias for ActiveSupport::SafeBuffer (html_safe strings)
type safe_buffer = String

def redux_store: (
String store_name,
?props: untyped,
?immediate_hydration: bool
) -> void
Comment on lines +6 to +10
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Past issue resolved; verify props type consistency with Helper.

The immediate_hydration parameter is now correctly typed as bool (matching the past review recommendation). However, the props parameter is typed as untyped here, while the corresponding redux_store method in sig/react_on_rails/helper.rbs (lines 16-19) types it as Hash[Symbol, untyped]. Consider using the same type in both signatures to maintain consistency across the API surface.


🏁 Script executed:

#!/bin/bash
# Verify the actual implementation of redux_store in Controller to determine the correct props type
rg -nP "def redux_store" --type ruby -A 10 -g 'lib/react_on_rails/controller.rb'

Length of output: 814


I need to verify the actual Helper RBS signature that the review mentions. Let me search for it in the codebase.

I need to verify the actual RBS signatures in the repository since I can't do more web searches. Let me check the codebase directly.


🏁 Script executed:

#!/bin/bash
# Find and display helper.rbs file and its redux_store method if it exists
fd helper.rbs --type f -x cat {}

Length of output: 1834


🏁 Script executed:

#!/bin/bash
# Also find the controller.rbs to verify the full context
fd controller.rbs --type f -x cat {}

Length of output: 217


Correct props type in Controller RBS to match Helper and implementation.

The immediate_hydration parameter is correctly typed as bool. However, the props parameter in Controller RBS is typed as untyped, while both the Helper RBS (lines 12-14) and the actual Controller implementation (which defaults props to {}) indicate it should be Hash[Symbol, untyped]. Update sig/react_on_rails/controller.rbs line 5 to use ?props: Hash[Symbol, untyped] for consistency.

🤖 Prompt for AI Agents
In sig/react_on_rails/controller.rbs around lines 3 to 7, the props parameter is
currently typed as untyped but should match the Helper RBS and implementation;
change the signature so that line 5 uses ?props: Hash[Symbol, untyped] (keeping
immediate_hydration: bool) so the method reads with props optional and typed as
a symbol-keyed hash.


# Returns html_safe string (ActiveSupport::SafeBuffer)
def redux_store_hydration_data: () -> safe_buffer
end
end
8 changes: 8 additions & 0 deletions sig/react_on_rails/git_utils.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module ReactOnRails
module GitUtils
def self.uncommitted_changes?: (String path) -> bool
def self.git_installed?: () -> bool
def self.current_branch: () -> String?
def self.rspec_fixture_branches: () -> Array[String]
end
end
65 changes: 65 additions & 0 deletions sig/react_on_rails/helper.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module ReactOnRails
module Helper
# Type alias for ActiveSupport::SafeBuffer (html_safe strings)
type safe_buffer = String

COMPONENT_HTML_KEY: String

# Main helper methods
# Returns html_safe string (ActiveSupport::SafeBuffer)
def react_component: (
String component_name,
?Hash[Symbol, untyped] options
) ?{ () -> untyped } -> safe_buffer

# Returns hash with html_safe strings (ActiveSupport::SafeBuffer)
def react_component_hash: (
String component_name,
?Hash[Symbol, untyped] options
) ?{ () -> untyped } -> Hash[String, safe_buffer]

# Returns html_safe string (ActiveSupport::SafeBuffer)
def redux_store: (
String store_name,
?Hash[Symbol, untyped] props
) -> safe_buffer

# Returns html_safe string (ActiveSupport::SafeBuffer)
def redux_store_hydration_data: () -> safe_buffer

# Returns html_safe string (ActiveSupport::SafeBuffer)
def server_render_js: (
String js_expression,
?Hash[Symbol, untyped] options
) -> safe_buffer

def sanitized_props_string: (untyped props) -> String

def rails_context: (
?server_side: bool
) -> Hash[Symbol, untyped]

private

def internal_react_component: (
String component_name,
Hash[Symbol, untyped] options
) ?{ () -> untyped } -> Hash[Symbol, untyped]

def build_react_component_result_for_server_rendered_string: (
server_rendered_html: String,
component_specification_tag: String,
console_script: String,
render_options: Hash[Symbol, untyped]
) -> safe_buffer

def build_react_component_result_for_server_rendered_hash: (
server_rendered_html: Hash[String, untyped],
component_specification_tag: String,
console_script: String,
render_options: Hash[Symbol, untyped]
) -> Hash[String, safe_buffer]

def prepend_render_rails_context: (String result) -> safe_buffer
end
end
15 changes: 15 additions & 0 deletions sig/react_on_rails/packer_utils.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module ReactOnRails
module PackerUtils
def self.supports_autobundling?: () -> bool
def self.supports_basic_pack_generation?: () -> bool
def self.supports_async_loading?: () -> bool
def self.nested_entries?: () -> bool
def self.packer_public_output_path: () -> String
def self.precompile?: () -> bool
def self.shakapacker_precompile_hook_configured?: () -> bool
def self.shakapacker_precompile_hook_value: () -> String
def self.raise_shakapacker_version_incompatible_for_autobundling: () -> void
def self.raise_shakapacker_version_incompatible_for_basic_pack_generation: () -> void
def self.raise_nested_entries_disabled: () -> void
end
end
12 changes: 12 additions & 0 deletions sig/react_on_rails/server_rendering_pool.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module ReactOnRails
module ServerRenderingPool
def self.pool: () -> untyped

def self.reset_pool_if_server_bundle_was_modified: () -> void
def self.reset_pool: () -> void
def self.server_render_js_with_console_logging: (
String js_code,
Hash[Symbol, untyped] render_options
) -> Hash[String, untyped]
end
end
11 changes: 11 additions & 0 deletions sig/react_on_rails/test_helper.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module ReactOnRails
module TestHelper
def self.configure_rspec_to_compile_assets: (untyped config) -> void
def self.ensure_assets_compiled: (?force_compile: bool) -> void
def self.webpack_assets_compiled?: () -> bool

module EnsureAssetsCompiled
def self.has_been_run?: () -> bool
end
end
end
Loading
Loading