diff --git a/lib/generators/react_on_rails/base_generator.rb b/lib/generators/react_on_rails/base_generator.rb index 9e47f210c..c059bcc43 100644 --- a/lib/generators/react_on_rails/base_generator.rb +++ b/lib/generators/react_on_rails/base_generator.rb @@ -4,10 +4,12 @@ require "fileutils" require_relative "generator_messages" require_relative "generator_helper" +require_relative "js_dependency_manager" module ReactOnRails module Generators class BaseGenerator < Rails::Generators::Base include GeneratorHelper + include JsDependencyManager Rails::Generators.hide_namespace(namespace) source_root(File.expand_path("templates", __dir__)) @@ -134,123 +136,6 @@ def append_to_spec_rails_helper private - def setup_js_dependencies - add_js_dependencies - install_js_dependencies - end - - def add_js_dependencies - add_react_on_rails_package - add_react_dependencies - add_css_dependencies - add_dev_dependencies - end - - def add_react_on_rails_package - major_minor_patch_only = /\A\d+\.\d+\.\d+\z/ - - # Try to use package_json gem first, fall back to direct npm commands - react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only) - ["react-on-rails@#{ReactOnRails::VERSION}"] - else - puts "Adding the latest react-on-rails NPM module. " \ - "Double check this is correct in package.json" - ["react-on-rails"] - end - - puts "Installing React on Rails package..." - return if add_npm_dependencies(react_on_rails_pkg) - - puts "Using direct npm commands as fallback" - success = system("npm", "install", *react_on_rails_pkg) - handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success - end - - def add_react_dependencies - puts "Installing React dependencies..." - react_deps = %w[ - react - react-dom - @babel/preset-react - prop-types - babel-plugin-transform-react-remove-prop-types - babel-plugin-macros - ] - return if add_npm_dependencies(react_deps) - - success = system("npm", "install", *react_deps) - handle_npm_failure("React dependencies", react_deps) unless success - end - - def add_css_dependencies - puts "Installing CSS handling dependencies..." - css_deps = %w[ - css-loader - css-minimizer-webpack-plugin - mini-css-extract-plugin - style-loader - ] - return if add_npm_dependencies(css_deps) - - success = system("npm", "install", *css_deps) - handle_npm_failure("CSS dependencies", css_deps) unless success - end - - def add_dev_dependencies - puts "Installing development dependencies..." - dev_deps = %w[ - @pmmmwh/react-refresh-webpack-plugin - react-refresh - ] - return if add_npm_dependencies(dev_deps, dev: true) - - success = system("npm", "install", "--save-dev", *dev_deps) - handle_npm_failure("development dependencies", dev_deps, dev: true) unless success - end - - def install_js_dependencies - # Detect which package manager to use - success = if File.exist?(File.join(destination_root, "yarn.lock")) - system("yarn", "install") - elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml")) - system("pnpm", "install") - elsif File.exist?(File.join(destination_root, "package-lock.json")) || - File.exist?(File.join(destination_root, "package.json")) - # Use npm for package-lock.json or as default fallback - system("npm", "install") - else - true # No package manager detected, skip - end - - unless success - GeneratorMessages.add_warning(<<~MSG.strip) - ⚠️ JavaScript dependencies installation failed. - - This could be due to network issues or missing package manager. - You can install dependencies manually later by running: - • npm install (if using npm) - • yarn install (if using yarn) - • pnpm install (if using pnpm) - MSG - end - - success - end - - def handle_npm_failure(dependency_type, packages, dev: false) - install_command = dev ? "npm install --save-dev" : "npm install" - GeneratorMessages.add_warning(<<~MSG.strip) - ⚠️ Failed to install #{dependency_type}. - - The following packages could not be installed automatically: - #{packages.map { |pkg| " • #{pkg}" }.join("\n")} - - This could be due to network issues or missing package manager. - You can install them manually later by running: - #{install_command} #{packages.join(' ')} - MSG - end - def copy_webpack_main_config(base_path, config) webpack_config_path = "config/webpack/webpack.config.js" diff --git a/lib/generators/react_on_rails/install_generator.rb b/lib/generators/react_on_rails/install_generator.rb index b95593fd8..1aeb617e4 100644 --- a/lib/generators/react_on_rails/install_generator.rb +++ b/lib/generators/react_on_rails/install_generator.rb @@ -4,12 +4,14 @@ require "json" require_relative "generator_helper" require_relative "generator_messages" +require_relative "js_dependency_manager" module ReactOnRails module Generators # rubocop:disable Metrics/ClassLength class InstallGenerator < Rails::Generators::Base include GeneratorHelper + include JsDependencyManager # fetch USAGE file for details generator description source_root(File.expand_path(__dir__)) @@ -83,10 +85,7 @@ def invoke_generators end def setup_react_dependencies - @added_dependencies_to_package_json ||= false - @ran_direct_installs ||= false - add_js_dependencies - install_js_dependencies if @added_dependencies_to_package_json && !@ran_direct_installs + setup_js_dependencies end # NOTE: other requirements for existing files such as .gitignore or application. @@ -346,11 +345,17 @@ def install_typescript_dependencies ] # Try using GeneratorHelper first (package manager agnostic) - return if add_npm_dependencies(typescript_packages, dev: true) + if add_npm_dependencies(typescript_packages, dev: true) + @added_dependencies_to_package_json = true + return + end # Fallback to npm if GeneratorHelper fails success = system("npm", "install", "--save-dev", *typescript_packages) - return if success + if success + @ran_direct_installs = true + return + end warning = <<~MSG.strip ⚠️ Failed to install TypeScript dependencies automatically. @@ -420,134 +425,6 @@ def create_typescript_config puts Rainbow("✅ Created tsconfig.json").green end - def add_js_dependencies - add_react_on_rails_package - add_react_dependencies - add_css_dependencies - add_dev_dependencies - end - - def add_react_on_rails_package - major_minor_patch_only = /\A\d+\.\d+\.\d+\z/ - - # Try to use package_json gem first, fall back to direct npm commands - react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only) - ["react-on-rails@#{ReactOnRails::VERSION}"] - else - puts "Adding the latest react-on-rails NPM module. " \ - "Double check this is correct in package.json" - ["react-on-rails"] - end - - puts "Installing React on Rails package..." - if add_npm_dependencies(react_on_rails_pkg) - @added_dependencies_to_package_json = true - return - end - - puts "Using direct npm commands as fallback" - success = system("npm", "install", *react_on_rails_pkg) - @ran_direct_installs = true if success - handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success - end - - def add_react_dependencies - puts "Installing React dependencies..." - react_deps = %w[ - react - react-dom - @babel/preset-react - prop-types - babel-plugin-transform-react-remove-prop-types - babel-plugin-macros - ] - if add_npm_dependencies(react_deps) - @added_dependencies_to_package_json = true - return - end - - success = system("npm", "install", *react_deps) - @ran_direct_installs = true if success - handle_npm_failure("React dependencies", react_deps) unless success - end - - def add_css_dependencies - puts "Installing CSS handling dependencies..." - css_deps = %w[ - css-loader - css-minimizer-webpack-plugin - mini-css-extract-plugin - style-loader - ] - if add_npm_dependencies(css_deps) - @added_dependencies_to_package_json = true - return - end - - success = system("npm", "install", *css_deps) - @ran_direct_installs = true if success - handle_npm_failure("CSS dependencies", css_deps) unless success - end - - def add_dev_dependencies - puts "Installing development dependencies..." - dev_deps = %w[ - @pmmmwh/react-refresh-webpack-plugin - react-refresh - ] - if add_npm_dependencies(dev_deps, dev: true) - @added_dependencies_to_package_json = true - return - end - - success = system("npm", "install", "--save-dev", *dev_deps) - @ran_direct_installs = true if success - handle_npm_failure("development dependencies", dev_deps, dev: true) unless success - end - - def install_js_dependencies - # Detect which package manager to use - success = if File.exist?(File.join(destination_root, "yarn.lock")) - system("yarn", "install") - elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml")) - system("pnpm", "install") - elsif File.exist?(File.join(destination_root, "package-lock.json")) || - File.exist?(File.join(destination_root, "package.json")) - # Use npm for package-lock.json or as default fallback - system("npm", "install") - else - true # No package manager detected, skip - end - - unless success - GeneratorMessages.add_warning(<<~MSG.strip) - ⚠️ JavaScript dependencies installation failed. - - This could be due to network issues or missing package manager. - You can install dependencies manually later by running: - • npm install (if using npm) - • yarn install (if using yarn) - • pnpm install (if using pnpm) - MSG - end - - success - end - - def handle_npm_failure(dependency_type, packages, dev: false) - install_command = dev ? "npm install --save-dev" : "npm install" - GeneratorMessages.add_warning(<<~MSG.strip) - ⚠️ Failed to install #{dependency_type}. - - The following packages could not be installed automatically: - #{packages.map { |pkg| " • #{pkg}" }.join("\n")} - - This could be due to network issues or missing package manager. - You can install them manually later by running: - #{install_command} #{packages.join(' ')} - MSG - end - # Removed: Shakapacker auto-installation logic (now explicit dependency) # Removed: Shakapacker 8+ is now required as explicit dependency diff --git a/lib/generators/react_on_rails/js_dependency_manager.rb b/lib/generators/react_on_rails/js_dependency_manager.rb new file mode 100644 index 000000000..5c8f49bf4 --- /dev/null +++ b/lib/generators/react_on_rails/js_dependency_manager.rb @@ -0,0 +1,161 @@ +# frozen_string_literal: true + +require_relative "generator_messages" + +module ReactOnRails + module Generators + # Shared module for managing JavaScript dependencies across generators + # This module provides common functionality for adding and installing + # JS dependencies to avoid code duplication between generators. + # + # Since react_on_rails requires shakapacker, and shakapacker includes + # package_json as a dependency, the package_json gem is always available. + # + # == Required Instance Variables + # Including classes must support these instance variables: + # - @added_dependencies_to_package_json: Boolean tracking if package_json gem was used + # + # == Required Methods + # Including classes must include GeneratorHelper module which provides: + # - add_npm_dependencies(packages, dev: false): Add packages via package_json gem + # - package_json: Access to PackageJson instance (always available via shakapacker) + # - destination_root: Generator destination directory + # + # == Usage + # Include this module in generator classes and call setup_js_dependencies + # to handle all JS dependency installation via package_json gem. + module JsDependencyManager + # Core React dependencies required for React on Rails + REACT_DEPENDENCIES = %w[ + react + react-dom + @babel/preset-react + prop-types + babel-plugin-transform-react-remove-prop-types + babel-plugin-macros + ].freeze + + # CSS processing dependencies for webpack + CSS_DEPENDENCIES = %w[ + css-loader + css-minimizer-webpack-plugin + mini-css-extract-plugin + style-loader + ].freeze + + # Development-only dependencies for hot reloading + DEV_DEPENDENCIES = %w[ + @pmmmwh/react-refresh-webpack-plugin + react-refresh + ].freeze + + private + + def setup_js_dependencies + @added_dependencies_to_package_json ||= false + add_js_dependencies + install_js_dependencies + end + + def add_js_dependencies + add_react_on_rails_package + add_react_dependencies + add_css_dependencies + add_dev_dependencies + end + + def add_react_on_rails_package + # Always use exact version match between gem and npm package + react_on_rails_pkg = "react-on-rails@#{ReactOnRails::VERSION}" + + puts "Installing React on Rails package..." + if add_js_dependency(react_on_rails_pkg) + @added_dependencies_to_package_json = true + else + # This should not happen since package_json is always available via shakapacker + raise "Failed to add react-on-rails package via package_json gem" + end + end + + def add_react_dependencies + puts "Installing React dependencies..." + + if add_js_dependencies_batch(REACT_DEPENDENCIES) + @added_dependencies_to_package_json = true + else + # This should not happen since package_json is always available via shakapacker + raise "Failed to add React dependencies via package_json gem" + end + end + + def add_css_dependencies + puts "Installing CSS handling dependencies..." + + if add_js_dependencies_batch(CSS_DEPENDENCIES) + @added_dependencies_to_package_json = true + else + # This should not happen since package_json is always available via shakapacker + raise "Failed to add CSS dependencies via package_json gem" + end + end + + def add_dev_dependencies + puts "Installing development dependencies..." + + if add_js_dependencies_batch(DEV_DEPENDENCIES, dev: true) + @added_dependencies_to_package_json = true + else + # This should not happen since package_json is always available via shakapacker + raise "Failed to add development dependencies via package_json gem" + end + end + + # Add a single dependency using package_json gem + def add_js_dependency(package, dev: false) + pj = package_json + return false unless pj + + begin + # Ensure package is in array format for package_json gem + packages_array = [package] + if dev + pj.manager.add(packages_array, type: :dev) + else + pj.manager.add(packages_array) + end + true + rescue StandardError => e + puts "Warning: Could not add #{package} via package_json gem: #{e.message}" + false + end + end + + # Add multiple dependencies at once using package_json gem + def add_js_dependencies_batch(packages, dev: false) + # Use the add_npm_dependencies helper from GeneratorHelper + add_npm_dependencies(packages, dev: dev) + end + + def install_js_dependencies + # Use package_json gem's install method (always available via shakapacker) + begin + package_json.manager.install + true + rescue StandardError => e + GeneratorMessages.add_warning(<<~MSG.strip) + ⚠️ JavaScript dependencies installation failed: #{e.message} + + This could be due to network issues or package manager problems. + You can install dependencies manually later by running: + • npm install (if using npm) + • yarn install (if using yarn) + • pnpm install (if using pnpm) + MSG + false + end + end + + # No longer needed since package_json gem handles package manager detection + end + end +end diff --git a/spec/react_on_rails/generators/message_deduplication_spec.rb b/spec/react_on_rails/generators/message_deduplication_spec.rb new file mode 100644 index 000000000..11bdd24ac --- /dev/null +++ b/spec/react_on_rails/generators/message_deduplication_spec.rb @@ -0,0 +1,133 @@ +# frozen_string_literal: true + +require_relative "../support/generator_spec_helper" +require_relative "../support/version_test_helpers" + +describe "Message Deduplication", type: :generator do + include GeneratorSpec::TestCase + + destination File.expand_path("../dummy-for-generators", __dir__) + tests ReactOnRails::Generators::InstallGenerator + + describe "Post-install message handling" do + before do + # Clear any previous messages to ensure clean test state + GeneratorMessages.clear + # Mock Shakapacker installation to succeed + allow(File).to receive(:exist?).and_call_original + allow(File).to receive(:exist?).with("bin/shakapacker").and_return(true) + allow(File).to receive(:exist?).with("bin/shakapacker-dev-server").and_return(true) + allow(File).to receive(:exist?).with("config/shakapacker.yml").and_return(true) + allow(File).to receive(:exist?).with("config/webpack/webpack.config.js").and_return(true) + # Mock file reading for webpack config - use call_original first, then specific mock + allow(File).to receive(:read).and_call_original + allow(File).to receive(:read).with("config/webpack/webpack.config.js").and_return("// mock webpack config") + end + + context "with non-Redux installation" do + it "shows the success message exactly once" do + run_generator_test_with_args(%w[], package_json: true) + output_text = GeneratorMessages.output.join("\n") + + # Count occurrences of the success message + success_count = output_text.scan("🎉 React on Rails Successfully Installed!").count + expect(success_count).to( + eq(1), + "Expected success message to appear exactly once, but appeared #{success_count} times" + ) + + # Ensure post-install message components are present + expect(output_text).to include("📋 QUICK START:") + expect(output_text).to include("✨ KEY FEATURES:") + end + end + + context "with Redux installation" do + it "shows the success message exactly once" do + run_generator_test_with_args(%w[--redux], package_json: true) + output_text = GeneratorMessages.output.join("\n") + + # Count occurrences of the success message + success_count = output_text.scan("🎉 React on Rails Successfully Installed!").count + expect(success_count).to( + eq(1), + "Expected success message to appear exactly once with Redux, but appeared #{success_count} times" + ) + + # Ensure post-install message components are present + expect(output_text).to include("📋 QUICK START:") + expect(output_text).to include("✨ KEY FEATURES:") + + # The message should be from the Redux generator, containing Redux-specific info + expect(output_text).to include("HelloWorldApp") + end + end + end + + describe "NPM install execution" do + let(:install_generator) { ReactOnRails::Generators::InstallGenerator.new } + + before do + # Mock the system to track NPM install calls + allow(install_generator).to receive_messages( + system: true, + add_npm_dependencies: false, + destination_root: "/test/path" + ) + allow(File).to receive(:exist?).and_return(false) + allow(File).to receive(:exist?).with(a_string_matching(/package\.json$/)).and_return(true) + + # Initialize instance variables + install_generator.instance_variable_set(:@added_dependencies_to_package_json, false) + end + + context "when using package_json gem (always available via shakapacker)" do + before do + # Mock that the package_json gem methods succeed + allow(install_generator).to receive_messages(add_js_dependency: true, add_js_dependencies_batch: true, + install_js_dependencies: true) + end + + it "does not run duplicate install commands" do + # When package_json gem methods work, it should NOT call system() commands + expect(install_generator).not_to receive(:system) + + # Run the dependency setup + install_generator.send(:setup_js_dependencies) + + # Verify state was set correctly to indicate package_json was used + expect(install_generator.instance_variable_get(:@added_dependencies_to_package_json)).to be true + end + end + end + + describe "JS dependency method organization" do + it "uses the shared JsDependencyManager module in base_generator" do + expect(ReactOnRails::Generators::BaseGenerator.ancestors) + .to include(ReactOnRails::Generators::JsDependencyManager) + end + + it "uses the shared JsDependencyManager module in install_generator" do + expect(ReactOnRails::Generators::InstallGenerator.ancestors) + .to include(ReactOnRails::Generators::JsDependencyManager) + end + + it "does not duplicate JS dependency methods between generators" do + base_generator = ReactOnRails::Generators::BaseGenerator.new + install_generator = ReactOnRails::Generators::InstallGenerator.new + + # Both should respond to the shared methods + shared_methods = %i[setup_js_dependencies add_js_dependencies install_js_dependencies] + + shared_methods.each do |method| + expect(base_generator.respond_to?(method, true)).to be(true) + expect(install_generator.respond_to?(method, true)).to be(true) + # Verify the methods are defined by the shared module + expect(ReactOnRails::Generators::BaseGenerator.instance_method(method).owner) + .to eq(ReactOnRails::Generators::JsDependencyManager) + expect(ReactOnRails::Generators::InstallGenerator.instance_method(method).owner) + .to eq(ReactOnRails::Generators::JsDependencyManager) + end + end + end +end diff --git a/yarn.lock b/yarn.lock index 1b66416ab..74e1abb9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1440,7 +1440,7 @@ "@nodelib/fs.stat" "4.0.0" run-parallel "^1.2.0" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1450,14 +1450,6 @@ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-4.0.0.tgz" integrity sha512-ctr6bByzksKRCV0bavi8WoQevU6plSp2IkllIsEqaiKe2mwNNnaluhnRhcsgGZHrrHk57B3lf95MkLMO3STYcg== -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - "@nodelib/fs.walk@3.0.1": version "3.0.1" resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-3.0.1.tgz" @@ -1466,6 +1458,14 @@ "@nodelib/fs.scandir" "4.0.1" fastq "^1.15.0" +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + "@pkgr/core@^0.1.0": version "0.1.1" resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz" @@ -1741,7 +1741,7 @@ "@typescript-eslint/types" "^8.35.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@^8.15.0", "@typescript-eslint/scope-manager@8.35.0": +"@typescript-eslint/scope-manager@8.35.0", "@typescript-eslint/scope-manager@^8.15.0": version "8.35.0" resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.0.tgz" integrity sha512-+AgL5+mcoLxl1vGjwNfiWq5fLDZM1TmTPYs2UkyHfFhgERxBbqHlNjRzhThJqz+ktBqTChRYY6zwbMwy0591AA== @@ -1749,7 +1749,7 @@ "@typescript-eslint/types" "8.35.0" "@typescript-eslint/visitor-keys" "8.35.0" -"@typescript-eslint/tsconfig-utils@^8.35.0", "@typescript-eslint/tsconfig-utils@8.35.0": +"@typescript-eslint/tsconfig-utils@8.35.0", "@typescript-eslint/tsconfig-utils@^8.35.0": version "8.35.0" resolved "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.0.tgz" integrity sha512-04k/7247kZzFraweuEirmvUj+W3bJLI9fX6fbo1Qm2YykuBvEhRTPl8tcxlYO8kZZW+HIXfkZNoasVb8EV4jpA== @@ -1764,7 +1764,7 @@ debug "^4.3.4" ts-api-utils "^2.1.0" -"@typescript-eslint/types@^8.35.0", "@typescript-eslint/types@8.35.0": +"@typescript-eslint/types@8.35.0", "@typescript-eslint/types@^8.35.0": version "8.35.0" resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.0.tgz" integrity sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ== @@ -1785,7 +1785,7 @@ semver "^7.6.0" ts-api-utils "^2.1.0" -"@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/utils@^8.15.0", "@typescript-eslint/utils@8.35.0": +"@typescript-eslint/utils@8.35.0", "@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/utils@^8.15.0": version "8.35.0" resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.0.tgz" integrity sha512-nqoMu7WWM7ki5tPgLVsmPM8CkqtoPUG6xXGeefM5t4x3XumOEKMoUZPdi+7F+/EotukN4R9OWdmDxN80fqoZeg== @@ -1892,14 +1892,7 @@ ansi-regex@^6.1.0: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz" integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== -ansi-styles@^3.2.0: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -1943,11 +1936,6 @@ argparse@^2.0.1: resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -aria-query@^5.0.0, aria-query@^5.3.2: - version "5.3.2" - resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz" - integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== - aria-query@5.3.0: version "5.3.0" resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz" @@ -1955,6 +1943,11 @@ aria-query@5.3.0: dependencies: dequal "^2.0.3" +aria-query@^5.0.0, aria-query@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz" @@ -2394,16 +2387,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -2574,6 +2567,13 @@ data-view-byte-offset@^1.0.1: es-errors "^1.3.0" is-data-view "^1.0.1" +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.4.0" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" @@ -2581,13 +2581,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@4: - version "4.4.0" - resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== - dependencies: - ms "^2.1.3" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" @@ -2921,7 +2914,7 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-airbnb-base@^15.0.0, eslint-config-airbnb-base@15.0.0: +eslint-config-airbnb-base@15.0.0, eslint-config-airbnb-base@^15.0.0: version "15.0.0" resolved "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz" integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig== @@ -3074,14 +3067,6 @@ eslint-plugin-testing-library@^7.5.3: "@typescript-eslint/scope-manager" "^8.15.0" "@typescript-eslint/utils" "^8.15.0" -eslint-scope@^8.3.0: - version "8.3.0" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz" - integrity sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" @@ -3090,6 +3075,14 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" +eslint-scope@^8.3.0: + version "8.3.0" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz" + integrity sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + eslint-visitor-keys@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" @@ -3254,7 +3247,7 @@ fast-glob@^3.3.2, fast-glob@^3.3.3: merge2 "^1.3.0" micromatch "^4.0.8" -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0, fast-json-stable-stringify@2.x: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -4947,14 +4940,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^2.2.0: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -5285,6 +5271,11 @@ react-on-rails-rsc@19.0.2: neo-async "^2.6.1" webpack-sources "^3.2.0" +react-on-rails@^16.1.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/react-on-rails/-/react-on-rails-16.1.0.tgz#1d6a91edf6c5675f22f4449483b604690471a76e" + integrity sha512-EZbs868+V6gkxY52jeim64oETHSg6ztym5aL9FFBY5uEadb/FaAAoCNrutyObFR/XgzGqmeSKQdW1DvPl8BVyA== + react@^19.0.0: version "19.0.0" resolved "https://registry.npmjs.org/react/-/react-19.0.0.tgz" @@ -5507,22 +5498,7 @@ semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.3: - version "7.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz" - integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== - -semver@^7.5.4: - version "7.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz" - integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== - -semver@^7.6.0: - version "7.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz" - integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== - -semver@^7.6.3: +semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: version "7.7.1" resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== @@ -5829,16 +5805,16 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - strip-json-comments@5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz" integrity sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw== +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + summary@2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/summary/-/summary-2.1.0.tgz" @@ -5919,7 +5895,7 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -through@~2.3, through@~2.3.1, through@2: +through@2, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -6000,7 +5976,7 @@ tslib@^2.6.2: resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== -type-check@^0.4.0: +type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== @@ -6014,14 +5990,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-detect@^4.0.3, type-detect@4.0.8: +type-detect@4.0.8, type-detect@^4.0.3: version "4.0.8" resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== @@ -6085,16 +6054,16 @@ typescript-eslint@^8.35.0: "@typescript-eslint/parser" "8.35.0" "@typescript-eslint/utils" "8.35.0" -typescript@^5.8.3: - version "5.8.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz" - integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== - typescript@5.6.1-rc: version "5.6.1-rc" resolved "https://registry.npmjs.org/typescript/-/typescript-5.6.1-rc.tgz" integrity sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ== +typescript@^5.8.3: + version "5.8.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== + unbox-primitive@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz" @@ -6236,15 +6205,7 @@ whatwg-url@^11.0.0: tr46 "^3.0.0" webidl-conversions "^7.0.0" -whatwg-url@^12.0.0: - version "12.0.1" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz" - integrity sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ== - dependencies: - tr46 "^4.1.1" - webidl-conversions "^7.0.0" - -whatwg-url@^12.0.1: +whatwg-url@^12.0.0, whatwg-url@^12.0.1: version "12.0.1" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz" integrity sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ== @@ -6409,6 +6370,23 @@ yargs-parser@^21.1.1: resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== +yargs@14.2.0: + version "14.2.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-14.2.0.tgz" + integrity sha512-/is78VKbKs70bVZH7w4YaZea6xcJWOAwkhbR0CFuZBmYtfTYF0xjGJF43AYd8g2Uii1yJwmS5GR2vBmrc32sbg== + dependencies: + cliui "^5.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^15.0.0" + yargs@^16.0.0: version "16.2.0" resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" @@ -6435,23 +6413,6 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.1.1" -yargs@14.2.0: - version "14.2.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-14.2.0.tgz" - integrity sha512-/is78VKbKs70bVZH7w4YaZea6xcJWOAwkhbR0CFuZBmYtfTYF0xjGJF43AYd8g2Uii1yJwmS5GR2vBmrc32sbg== - dependencies: - cliui "^5.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^15.0.0" - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"