diff --git a/lib/generators/stimulus_reflex/stimulus_reflex_generator.rb b/lib/generators/stimulus_reflex/stimulus_reflex_generator.rb index 30b20bab..b0c01f0a 100644 --- a/lib/generators/stimulus_reflex/stimulus_reflex_generator.rb +++ b/lib/generators/stimulus_reflex/stimulus_reflex_generator.rb @@ -20,13 +20,13 @@ def execute template(reflex_src, reflex_path) unless options[:skip_reflex] - if !options[:skip_stimulus] && entrypoint.blank? + if !options[:skip_stimulus] && StimulusReflex::Installer.entrypoint.blank? puts "❌ You must specify a valid JavaScript entrypoint." exit end stimulus_controller_src = "app/javascript/controllers/%file_name%_controller.js.tt" - stimulus_controller_path = Rails.root.join(entrypoint, "controllers/#{file_name}_controller.js") + stimulus_controller_path = Rails.root.join(StimulusReflex::Installer.entrypoint, "controllers/#{file_name}_controller.js") template(stimulus_controller_src, stimulus_controller_path) unless options[:skip_stimulus] diff --git a/lib/generators/stimulus_reflex/templates/app/javascript/config/cable_ready.js.tt b/lib/generators/stimulus_reflex/templates/app/javascript/config/cable_ready.js.tt index 39974256..124ade2d 100644 --- a/lib/generators/stimulus_reflex/templates/app/javascript/config/cable_ready.js.tt +++ b/lib/generators/stimulus_reflex/templates/app/javascript/config/cable_ready.js.tt @@ -1,4 +1,4 @@ -<%- if bundler.importmap? -%> +<%- if StimulusReflex::Installer.bundler.importmap? -%> import consumer from "channels/consumer" <%- else -%> import consumer from "../channels/consumer" diff --git a/lib/generators/stimulus_reflex/templates/app/javascript/config/index.js.tt b/lib/generators/stimulus_reflex/templates/app/javascript/config/index.js.tt index 298e570a..3c5fe145 100644 --- a/lib/generators/stimulus_reflex/templates/app/javascript/config/index.js.tt +++ b/lib/generators/stimulus_reflex/templates/app/javascript/config/index.js.tt @@ -1,4 +1,4 @@ -<%- if bundler.importmap? -%> +<%- if StimulusReflex::Installer.bundler.importmap? -%> import "config/cable_ready" import "config/stimulus_reflex" <%- else -%> diff --git a/lib/generators/stimulus_reflex/templates/app/javascript/config/stimulus_reflex.js.tt b/lib/generators/stimulus_reflex/templates/app/javascript/config/stimulus_reflex.js.tt index 045d9b7d..a91936a5 100644 --- a/lib/generators/stimulus_reflex/templates/app/javascript/config/stimulus_reflex.js.tt +++ b/lib/generators/stimulus_reflex/templates/app/javascript/config/stimulus_reflex.js.tt @@ -1,4 +1,4 @@ -<%- if bundler.importmap? -%> +<%- if StimulusReflex::Installer.bundler.importmap? -%> import { application } from "controllers/application" import controller from "controllers/application_controller" <%- else -%> diff --git a/lib/generators/stimulus_reflex/templates/app/javascript/controllers/%file_name%_controller.js.tt b/lib/generators/stimulus_reflex/templates/app/javascript/controllers/%file_name%_controller.js.tt index 1c935cef..674e4afe 100644 --- a/lib/generators/stimulus_reflex/templates/app/javascript/controllers/%file_name%_controller.js.tt +++ b/lib/generators/stimulus_reflex/templates/app/javascript/controllers/%file_name%_controller.js.tt @@ -1,4 +1,4 @@ -<%- if bundler.importmap? -%> +<%- if StimulusReflex::Installer.bundler.importmap? -%> import ApplicationController from "controllers/application_controller" <%- else -%> import ApplicationController from "./application_controller" diff --git a/lib/generators/stimulus_reflex/templates/app/javascript/controllers/application.js.tt b/lib/generators/stimulus_reflex/templates/app/javascript/controllers/application.js.tt index 952aa517..9a518cf1 100644 --- a/lib/generators/stimulus_reflex/templates/app/javascript/controllers/application.js.tt +++ b/lib/generators/stimulus_reflex/templates/app/javascript/controllers/application.js.tt @@ -1,5 +1,5 @@ import { Application } from "@hotwired/stimulus" -<%- if bundler.importmap? %> +<%- if StimulusReflex::Installer.bundler.importmap? %> import consumer from "channels/consumer" <%- else %> import consumer from "../channels/consumer" diff --git a/lib/install/action_cable.rb b/lib/install/action_cable.rb index 349319e1..a24e8965 100644 --- a/lib/install/action_cable.rb +++ b/lib/install/action_cable.rb @@ -6,11 +6,11 @@ if defined?(ActionCable::Engine) say "⏩ ActionCable::Engine is already loaded and in scope. Skipping" else - halt "ActionCable::Engine is not loaded, please add or uncomment `require \"action_cable/engine\"` to your `config/application.rb`" + StimulusReflex::Installer.halt "ActionCable::Engine is not loaded, please add or uncomment `require \"action_cable/engine\"` to your `config/application.rb`" return end -return if pack_path_missing? +return if StimulusReflex::Installer.pack_path_missing? # verify that the Action Cable pubsub config is created cable_config = Rails.root.join("config/cable.yml") @@ -37,7 +37,7 @@ "url" => "<%= ENV.fetch(\"REDIS_URL\") { \"redis://localhost:6379/1\" } %>", "channel_prefix" => "#{app_name}_development" } - backup(cable_config) do + StimulusReflex::Installer.backup(cable_config) do cable_config.write(yaml.to_yaml) end say "✅ config/cable.yml was updated to use the redis adapter in development" @@ -45,29 +45,29 @@ say "🤷 config/cable.yml should use the redis adapter - or something like it - in development. You have something else specified, and we trust that you know what you're doing." end -if gemfile.match?(/gem ['"]redis['"]/) +if StimulusReflex::Installer.gemfile.match?(/gem ['"]redis['"]/) say "⏩ redis gem is already present in Gemfile. Skipping." elsif Rails::VERSION::MAJOR >= 7 - add_gem "redis@~> 5" + StimulusReflex::Installer.add_gem "redis@~> 5" else - add_gem "redis@~> 4" + StimulusReflex::Installer.add_gem "redis@~> 4" end # install action-cable-redis-backport gem if using Action Cable < 7.1 unless ActionCable::VERSION::MAJOR >= 7 && ActionCable::VERSION::MINOR >= 1 - if gemfile.match?(/gem ['"]action-cable-redis-backport['"]/) + if StimulusReflex::Installer.gemfile.match?(/gem ['"]action-cable-redis-backport['"]/) say "⏩ action-cable-redis-backport gem is already present in Gemfile. Skipping." else - add_gem "action-cable-redis-backport@~> 1" + StimulusReflex::Installer.add_gem "action-cable-redis-backport@~> 1" end end # verify that the Action Cable channels folder and consumer class is available step_path = "/app/javascript/channels/" -channels_path = Rails.root.join(entrypoint, "channels") -consumer_src = fetch(step_path, "consumer.js.tt") +channels_path = Rails.root.join(StimulusReflex::Installer.entrypoint, "channels") +consumer_src = StimulusReflex::Installer.fetch(step_path, "consumer.js.tt") consumer_path = channels_path / "consumer.js" -index_src = fetch(step_path, "index.js.#{bundler}.tt") +index_src = StimulusReflex::Installer.fetch(step_path, "index.js.#{StimulusReflex::Installer.bundler}.tt") index_path = channels_path / "index.js" friendly_index_path = index_path.relative_path_from(Rails.root).to_s @@ -79,7 +79,7 @@ if index_path.read == index_src.read say "⏩ #{friendly_index_path} is already present. Skipping." else - backup(index_path) do + StimulusReflex::Installer.backup(index_path) do copy_file(index_src, index_path, verbose: false) end say "✅ #{friendly_index_path} has been updated" @@ -92,45 +92,45 @@ # import Action Cable channels into application pack channels_pattern = /import ['"](\.\.\/|\.\/)?channels['"]/ channels_commented_pattern = /\s*\/\/\s*#{channels_pattern}/ -channel_import = "import \"#{prefix}channels\"\n" +channel_import = "import \"#{StimulusReflex::Installer.prefix}channels\"\n" -if pack.match?(channels_pattern) - if pack.match?(channels_commented_pattern) - proceed = if options.key? "uncomment" - options["uncomment"] +if StimulusReflex::Installer.pack.match?(channels_pattern) + if StimulusReflex::Installer.pack.match?(channels_commented_pattern) + proceed = if StimulusReflex::Installer.options.key? "uncomment" + StimulusReflex::Installer.options["uncomment"] else !no?("✨ Action Cable seems to be commented out in your application.js. Do you want to uncomment it? (Y/n)") end if proceed # uncomment_lines only works with Ruby comments 🙄 - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ channels_commented_pattern } lines[lines.index(matches.last).to_i] = channel_import - pack_path.write lines.join - say "✅ Uncommented channels import in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ Uncommented channels import in #{StimulusReflex::Installer.friendly_pack_path}" else say "🤷 your Action Cable channels are not being imported in your application.js. We trust that you have a reason for this." end else - say "⏩ channels are already being imported in #{friendly_pack_path}. Skipping." + say "⏩ channels are already being imported in #{StimulusReflex::Installer.friendly_pack_path}. Skipping." end else - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ /^import / } lines.insert lines.index(matches.last).to_i + 1, channel_import - pack_path.write lines.join - say "✅ channels imported in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ channels imported in #{StimulusReflex::Installer.friendly_pack_path}" end # create working copy of Action Cable initializer in tmp -if action_cable_initializer_path.exist? - FileUtils.cp(action_cable_initializer_path, action_cable_initializer_working_path) +if StimulusReflex::Installer.action_cable_initializer_path.exist? + FileUtils.cp(StimulusReflex::Installer.action_cable_initializer_path, StimulusReflex::Installer.action_cable_initializer_working_path) say "⏩ Action Cable initializer already exists. Skipping" else # create Action Cable initializer if it doesn't already exist - create_file(action_cable_initializer_working_path, verbose: false) do + create_file(StimulusReflex::Installer.action_cable_initializer_working_path, verbose: false) do <<~RUBY # frozen_string_literal: true @@ -140,10 +140,10 @@ end # silence notoriously chatty Action Cable logs -if action_cable_initializer_working_path.read.match?(/^[^#]*ActionCable.server.config.logger/) +if StimulusReflex::Installer.action_cable_initializer_working_path.read.match?(/^[^#]*ActionCable.server.config.logger/) say "⏩ Action Cable logger is already being silenced. Skipping" else - append_file(action_cable_initializer_working_path, verbose: false) do + append_file(StimulusReflex::Installer.action_cable_initializer_working_path, verbose: false) do <<~RUBY ActionCable.server.config.logger = Logger.new(nil) @@ -152,4 +152,4 @@ say "✅ Action Cable logger silenced for performance and legibility" end -complete_step :action_cable +StimulusReflex::Installer.complete_step :action_cable diff --git a/lib/install/broadcaster.rb b/lib/install/broadcaster.rb index e56a239c..cee4fbd4 100644 --- a/lib/install/broadcaster.rb +++ b/lib/install/broadcaster.rb @@ -11,7 +11,7 @@ def needs_broadcaster?(path) channel_path = Rails.root.join("app/channels/application_cable/channel.rb") controller_path = Rails.root.join("app/controllers/application_controller.rb") job_path = Rails.root.join("app/jobs/application_job.rb") -model_path = Rails.root.join(application_record_path) +model_path = Rails.root.join(StimulusReflex::Installer.application_record_path) include_in_channel = needs_broadcaster?(channel_path) include_in_controller = needs_broadcaster?(controller_path) @@ -21,20 +21,20 @@ def needs_broadcaster?(path) proceed = [include_in_channel, include_in_controller, include_in_job, include_in_model].reduce(:|) unless proceed - complete_step :broadcaster + StimulusReflex::Installer.complete_step :broadcaster puts "⏩ CableReady::Broadcaster already included in all files. Skipping." return end -proceed = if options.key? "broadcaster" - options["broadcaster"] +proceed = if StimulusReflex::Installer.options.key? "broadcaster" + StimulusReflex::Installer.options["broadcaster"] else !no?("✨ Make CableReady::Broadcaster available to channels, controllers, jobs and models? (Y/n)") end unless proceed - complete_step :broadcaster + StimulusReflex::Installer.complete_step :broadcaster puts "⏩ Skipping." return @@ -44,7 +44,7 @@ def needs_broadcaster?(path) # include CableReady::Broadcaster in Action Cable Channel classes if include_in_channel - backup(channel_path) do + StimulusReflex::Installer.backup(channel_path) do inject_into_file channel_path, broadcaster_include, after: /class (ApplicationCable::)?Channel < ActionCable::Channel::Base/, verbose: false end @@ -55,7 +55,7 @@ def needs_broadcaster?(path) # include CableReady::Broadcaster in Action Controller classes if include_in_controller - backup(controller_path) do + StimulusReflex::Installer.backup(controller_path) do inject_into_class controller_path, "ApplicationController", broadcaster_include, verbose: false end @@ -67,7 +67,7 @@ def needs_broadcaster?(path) # include CableReady::Broadcaster in Active Job classes, if present if include_in_job - backup(job_path) do + StimulusReflex::Installer.backup(job_path) do inject_into_class job_path, "ApplicationJob", broadcaster_include, verbose: false end @@ -78,8 +78,8 @@ def needs_broadcaster?(path) # include CableReady::Broadcaster in Active Record model classes if include_in_model - backup(application_record_path) do - inject_into_class application_record_path, "ApplicationRecord", broadcaster_include, verbose: false + StimulusReflex::Installer.backup(StimulusReflex::Installer.application_record_path) do + inject_into_class StimulusReflex::Installer.application_record_path, "ApplicationRecord", broadcaster_include, verbose: false end puts "✅ include CableReady::Broadcaster in ApplicationRecord" @@ -87,4 +87,4 @@ def needs_broadcaster?(path) puts "⏩ Not including CableReady::Broadcaster in ApplicationRecord. Skipping" end -complete_step :broadcaster +StimulusReflex::Installer.complete_step :broadcaster diff --git a/lib/install/bundle.rb b/lib/install/bundle.rb index 7a851efc..46ba6987 100644 --- a/lib/install/bundle.rb +++ b/lib/install/bundle.rb @@ -2,14 +2,14 @@ require "stimulus_reflex/installer" -hash = gemfile_hash +hash = StimulusReflex::Installer.gemfile_hash # run bundle only when gems are waiting to be added or removed -add = add_gem_list.exist? ? add_gem_list.readlines.map(&:chomp) : [] -remove = remove_gem_list.exist? ? remove_gem_list.readlines.map(&:chomp) : [] +add = StimulusReflex::Installer.add_gem_list.exist? ? StimulusReflex::Installer.add_gem_list.readlines.map(&:chomp) : [] +remove = StimulusReflex::Installer.remove_gem_list.exist? ? StimulusReflex::Installer.remove_gem_list.readlines.map(&:chomp) : [] if add.present? || remove.present? - lines = gemfile_path.readlines + lines = StimulusReflex::Installer.gemfile_path.readlines remove.each do |name| index = lines.index { |line| line =~ /gem ['"]#{name}['"]/ } @@ -40,17 +40,17 @@ end end - gemfile_path.write lines.join + StimulusReflex::Installer.gemfile_path.write lines.join - bundle_command("install --quiet", "BUNDLE_IGNORE_MESSAGES" => "1") if hash != gemfile_hash + bundle_command("install --quiet", "BUNDLE_IGNORE_MESSAGES" => "1") if hash != StimulusReflex::Installer.gemfile_hash else say "⏩ No rubygems depedencies to install. Skipping." end -FileUtils.cp(development_working_path, development_path) +FileUtils.cp(StimulusReflex::Installer.development_working_path, StimulusReflex::Installer.development_path) say "✅ development environment configuration installed" -FileUtils.cp(action_cable_initializer_working_path, action_cable_initializer_path) +FileUtils.cp(StimulusReflex::Installer.action_cable_initializer_working_path, StimulusReflex::Installer.action_cable_initializer_path) say "✅ Action Cable initializer installed" -complete_step :bundle +StimulusReflex::Installer.complete_step :bundle diff --git a/lib/install/compression.rb b/lib/install/compression.rb index fe264708..c61379ca 100644 --- a/lib/install/compression.rb +++ b/lib/install/compression.rb @@ -2,17 +2,17 @@ require "stimulus_reflex/installer" -initializer = action_cable_initializer_working_path.read +initializer = StimulusReflex::Installer.action_cable_initializer_working_path.read -if gemfile.match?(/gem ['"]permessage_deflate['"]/) +if StimulusReflex::Installer.gemfile.match?(/gem ['"]permessage_deflate['"]/) say "⏩ permessage_deflate already present in Gemfile. Skipping." else - add_gem "permessage_deflate@>= 0.1" + StimulusReflex::Installer.add_gem "permessage_deflate@>= 0.1" end # add permessage_deflate config to Action Cable initializer if initializer.exclude? "PermessageDeflate.configure" - create_or_append(action_cable_initializer_working_path, verbose: false) do + StimulusReflex::Installer.create_or_append(StimulusReflex::Installer.action_cable_initializer_working_path, verbose: false) do <<~RUBY module ActionCable module Connection @@ -38,4 +38,4 @@ def initialize(env, event_target, event_loop, protocols) say "⏩ Action Cable initializer is already patched to deflate websocket traffic. Skipping." end -complete_step :compression +StimulusReflex::Installer.complete_step :compression diff --git a/lib/install/config.rb b/lib/install/config.rb index 2d3ad739..2b4f09bf 100644 --- a/lib/install/config.rb +++ b/lib/install/config.rb @@ -2,24 +2,24 @@ require "stimulus_reflex/installer" -return if pack_path_missing? +return if StimulusReflex::Installer.pack_path_missing? step_path = "/app/javascript/config/" -index_src = fetch(step_path, "index.js.tt") -index_path = config_path / "index.js" +index_src = StimulusReflex::Installer.fetch(step_path, "index.js.tt") +index_path = StimulusReflex::Installer.config_path / "index.js" friendly_index_path = index_path.relative_path_from(Rails.root).to_s -stimulus_reflex_src = fetch(step_path, "stimulus_reflex.js.tt") -stimulus_reflex_path = config_path / "stimulus_reflex.js" +stimulus_reflex_src = StimulusReflex::Installer.fetch(step_path, "stimulus_reflex.js.tt") +stimulus_reflex_path = StimulusReflex::Installer.config_path / "stimulus_reflex.js" friendly_stimulus_reflex_path = stimulus_reflex_path.relative_path_from(Rails.root).to_s -cable_ready_src = fetch(step_path, "cable_ready.js.tt") -cable_ready_path = config_path / "cable_ready.js" +cable_ready_src = StimulusReflex::Installer.fetch(step_path, "cable_ready.js.tt") +cable_ready_path = StimulusReflex::Installer.config_path / "cable_ready.js" -empty_directory config_path unless config_path.exist? +empty_directory StimulusReflex::Installer.config_path unless StimulusReflex::Installer.config_path.exist? if index_path.exist? say "⏩ #{friendly_index_path} already exists. Skipping" else - backup(index_path, delete: true) do + StimulusReflex::Installer.backup(index_path, delete: true) do template(index_src, index_path) end say "✅ Created #{friendly_index_path}" @@ -27,26 +27,26 @@ index_pattern = /import ['"](\.\.\/|\.\/)?config['"]/ index_commented_pattern = /\s*\/\/\s*#{index_pattern}/ -index_import = "import \"#{prefix}config\"\n" +index_import = "import \"#{StimulusReflex::Installer.prefix}config\"\n" -if pack.match?(index_pattern) - if pack.match?(index_commented_pattern) - lines = pack_path.readlines +if StimulusReflex::Installer.pack.match?(index_pattern) + if StimulusReflex::Installer.pack.match?(index_commented_pattern) + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ index_commented_pattern } lines[lines.index(matches.last).to_i] = index_import - pack_path.write lines.join + StimulusReflex::Installer.pack_path.write lines.join - say "✅ Uncommented StimulusReflex and CableReady configs imports in #{friendly_pack_path}" + say "✅ Uncommented StimulusReflex and CableReady configs imports in #{StimulusReflex::Installer.friendly_pack_path}" else - say "⏩ StimulusReflex and CableReady configs are already being imported in #{friendly_pack_path}. Skipping" + say "⏩ StimulusReflex and CableReady configs are already being imported in #{StimulusReflex::Installer.friendly_pack_path}. Skipping" end else - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ /^import / } lines.insert lines.index(matches.last).to_i + 1, index_import - pack_path.write lines.join + StimulusReflex::Installer.pack_path.write lines.join - say "✅ StimulusReflex and CableReady configs will be imported in #{friendly_pack_path}" + say "✅ StimulusReflex and CableReady configs will be imported in #{StimulusReflex::Installer.friendly_pack_path}" end # create entrypoint/config/cable_ready.js and make sure it's imported in application.js @@ -58,14 +58,14 @@ if stimulus_reflex_path.read.include?("StimulusReflex.debug =") say "⏩ Development environment options are already set in #{friendly_stimulus_reflex_path}. Skipping" else - if bundler.webpacker? || bundler.shakapacker? + if StimulusReflex::Installer.bundler.webpacker? || StimulusReflex::Installer.bundler.shakapacker? append_file(stimulus_reflex_path, <<~JS, verbose: false) if (process.env.RAILS_ENV === 'development') { StimulusReflex.debug = true } JS - elsif bundler.vite? + elsif StimulusReflex::Installer.bundler.vite? append_file(stimulus_reflex_path, <<~JS, verbose: false) unless stimulus_reflex_path.read.include?("StimulusReflex.debug") if (import.meta.env.MODE === "development") { @@ -84,4 +84,4 @@ say "✅ Set useful development environment options in #{friendly_stimulus_reflex_path}" end -complete_step :config +StimulusReflex::Installer.complete_step :config diff --git a/lib/install/development.rb b/lib/install/development.rb index d3721831..dd3e4e4d 100644 --- a/lib/install/development.rb +++ b/lib/install/development.rb @@ -3,56 +3,56 @@ require "stimulus_reflex/installer" # mutate working copy of development.rb to avoid bundle alerts -FileUtils.cp(development_path, development_working_path) +FileUtils.cp(StimulusReflex::Installer.development_path, StimulusReflex::Installer.development_working_path) # add default_url_options to development.rb for Action Mailer if defined?(ActionMailer) - lines = development_working_path.readlines + lines = StimulusReflex::Installer.development_working_path.readlines if lines.find { |line| line.include?("config.action_mailer.default_url_options") } say "⏩ Action Mailer default_url_options already defined. Skipping." else index = lines.index { |line| line =~ /^Rails.application.configure do/ } lines.insert index + 1, " config.action_mailer.default_url_options = {host: \"localhost\", port: 3000}\n\n" - development_working_path.write lines.join + StimulusReflex::Installer.development_working_path.write lines.join say "✅ Action Mailer default_url_options defined" end end # add default_url_options to development.rb for Action Controller -lines = development_working_path.readlines +lines = StimulusReflex::Installer.development_working_path.readlines if lines.find { |line| line.include?("config.action_controller.default_url_options") } say "⏩ Action Controller default_url_options already defined. Skipping." else index = lines.index { |line| line =~ /^Rails.application.configure do/ } lines.insert index + 1, " config.action_controller.default_url_options = {host: \"localhost\", port: 3000}\n" - development_working_path.write lines.join + StimulusReflex::Installer.development_working_path.write lines.join say "✅ Action Controller default_url_options defined" end -# halt with instructions if using cookie store, otherwise, nudge towards Redis -lines = development_working_path.readlines +# StimulusReflex::Installer.halt with instructions if using cookie store, otherwise, nudge towards Redis +lines = StimulusReflex::Installer.development_working_path.readlines if (index = lines.index { |line| line =~ /^[^#]*config.session_store/ }) if /^[^#]*cookie_store/.match?(lines[index]) - write_redis_recommendation(development_working_path, lines, index, gemfile) - halt "StimulusReflex does not support session cookies. See https://docs.stimulusreflex.com/hello-world/setup#session-storage" + StimulusReflex::Installer.write_redis_recommendation(StimulusReflex::Installer.development_working_path, lines, index, StimulusReflex::Installer.gemfile) + StimulusReflex::Installer.halt "StimulusReflex does not support session cookies. See https://docs.stimulusreflex.com/hello-world/setup#session-storage" return elsif /^[^#]*redis_session_store/.match?(lines[index]) say "⏩ Already using redis-session-store for session storage. Skipping." else - write_redis_recommendation(development_working_path, lines, index, gemfile) + StimulusReflex::Installer.write_redis_recommendation(StimulusReflex::Installer.development_working_path, lines, index, StimulusReflex::Installer.gemfile) say "🤷 We recommend using redis-session-store for session storage. See https://docs.stimulusreflex.com/hello-world/setup#session-storage" end # no session store defined, so let's opt-in to redis-session-store else # add redis-session-store to Gemfile - if !gemfile.match?(/gem ['"]redis-session-store['"]/) + if !StimulusReflex::Installer.gemfile.match?(/gem ['"]redis-session-store['"]/) if ActionCable::VERSION::MAJOR >= 7 - add_gem "redis-session-store@~> 0.11.5" + StimulusReflex::Installer.add_gem "redis-session-store@~> 0.11.5" else - add_gem "redis-session-store@0.11.4" + StimulusReflex::Installer.add_gem "redis-session-store@0.11.4" end end @@ -68,12 +68,12 @@ url: ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } } RUBY - development_working_path.write lines.join + StimulusReflex::Installer.development_working_path.write lines.join say "✅ Using redis-session-store for session storage" end # switch to redis for caching if using memory store, otherwise nudge with a comment -lines = development_working_path.readlines +lines = StimulusReflex::Installer.development_working_path.readlines if (index = lines.index { |line| line =~ /^[^#]*config.cache_store = :memory_store/ }) lines[index] = <<~RUBY @@ -81,13 +81,13 @@ url: ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } } RUBY - development_working_path.write lines.join + StimulusReflex::Installer.development_working_path.write lines.join say "✅ Using Redis for caching" elsif lines.index { |line| line =~ /^[^#]*config.cache_store = :redis_cache_store/ } say "⏩ Already using Redis for caching. Skipping." else if !lines.index { |line| line.include?("We couldn't identify your cache store") } - lines.insert find_index(lines), <<~RUBY + lines.insert StimulusReflex::Installer.find_index(lines), <<~RUBY # We couldn't identify your cache store, but recommend using Redis: @@ -95,7 +95,7 @@ # url: ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } # } RUBY - development_working_path.write lines.join + StimulusReflex::Installer.development_working_path.write lines.join end say "🤷 We couldn't identify your cache store, but recommend using Redis. See https://docs.stimulusreflex.com/appendices/deployment#use-redis-as-your-cache-store" end @@ -107,4 +107,4 @@ say "✅ Enabled caching in development" end -complete_step :development +StimulusReflex::Installer.complete_step :development diff --git a/lib/install/esbuild.rb b/lib/install/esbuild.rb index d5f3adcd..e42527b0 100644 --- a/lib/install/esbuild.rb +++ b/lib/install/esbuild.rb @@ -2,46 +2,46 @@ require "stimulus_reflex/installer" -return if pack_path_missing? +return if StimulusReflex::Installer.pack_path_missing? # verify that all critical dependencies are up to date; if not, queue for later -lines = package_json_path.readlines +lines = StimulusReflex::Installer.package_json_path.readlines if !lines.index { |line| line =~ /^\s*["']esbuild-rails["']: ["']\^1.0.3["']/ } - add_package "esbuild-rails@^1.0.3" + StimulusReflex::Installer.add_package "esbuild-rails@^1.0.3" else say "⏩ esbuild-rails npm package is already present. Skipping." end # copy esbuild.config.mjs to app root -esbuild_src = fetch("/", "esbuild.config.mjs.tt") +esbuild_src = StimulusReflex::Installer.fetch("/", "esbuild.config.mjs.tt") esbuild_path = Rails.root.join("esbuild.config.mjs") if esbuild_path.exist? if esbuild_path.read == esbuild_src.read say "⏩ esbuild.config.mjs already present in app root. Skipping." else - backup(esbuild_path) do - template(esbuild_src, esbuild_path, verbose: false, entrypoint: entrypoint) + StimulusReflex::Installer.backup(esbuild_path) do + template(esbuild_src, esbuild_path, verbose: false, entrypoint: StimulusReflex::Installer.entrypoint) end say "✅ updated esbuild.config.mjs in app root" end else - template(esbuild_src, esbuild_path, entrypoint: entrypoint) + template(esbuild_src, esbuild_path, entrypoint: StimulusReflex::Installer.entrypoint) say "✅ Created esbuild.config.mjs in app root" end step_path = "/app/javascript/controllers/" -application_controller_src = fetch(step_path, "application_controller.js.tt") -application_controller_path = controllers_path / "application_controller.js" -application_js_src = fetch(step_path, "application.js.tt") -application_js_path = controllers_path / "application.js" -index_src = fetch(step_path, "index.js.esbuild.tt") -index_path = controllers_path / "index.js" +application_controller_src = StimulusReflex::Installer.fetch(step_path, "application_controller.js.tt") +application_controller_path = StimulusReflex::Installer.controllers_path / "application_controller.js" +application_js_src = StimulusReflex::Installer.fetch(step_path, "application.js.tt") +application_js_path = StimulusReflex::Installer.controllers_path / "application.js" +index_src = StimulusReflex::Installer.fetch(step_path, "index.js.esbuild.tt") +index_path = StimulusReflex::Installer.controllers_path / "index.js" friendly_index_path = index_path.relative_path_from(Rails.root).to_s # create entrypoint/controllers, if necessary -empty_directory controllers_path unless controllers_path.exist? +empty_directory StimulusReflex::Installer.controllers_path unless StimulusReflex::Installer.controllers_path.exist? # copy application_controller.js, if necessary copy_file(application_controller_src, application_controller_path) unless application_controller_path.exist? @@ -50,7 +50,7 @@ friendly_application_js_path = application_js_path.relative_path_from(Rails.root).to_s if application_js_path.exist? - backup(application_js_path) do + StimulusReflex::Installer.backup(application_js_path) do if application_js_path.read.include?("import consumer") say "⏩ #{friendly_application_js_path} is already present. Skipping." else @@ -68,7 +68,7 @@ if index_path.read == index_src.read say "⏩ #{friendly_index_path} already present. Skipping." else - backup(index_path, delete: true) do + StimulusReflex::Installer.backup(index_path, delete: true) do copy_file(index_src, index_path, verbose: false) end @@ -82,33 +82,33 @@ controllers_pattern = /import ['"].\/controllers['"]/ controllers_commented_pattern = /\s*\/\/\s*#{controllers_pattern}/ -if pack.match?(controllers_pattern) - if pack.match?(controllers_commented_pattern) - proceed = if options.key? "uncomment" - options["uncomment"] +if StimulusReflex::Installer.pack.match?(controllers_pattern) + if StimulusReflex::Installer.pack.match?(controllers_commented_pattern) + proceed = if StimulusReflex::Installer.options.key? "uncomment" + StimulusReflex::Installer.options["uncomment"] else !no?("✨ Stimulus seems to be commented out in your application.js. Do you want to import your controllers? (Y/n)") end if proceed # uncomment_lines only works with Ruby comments 🙄 - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ controllers_commented_pattern } lines[lines.index(matches.last).to_i] = "import \".\/controllers\"\n" # standard:disable Style/RedundantStringEscape - pack_path.write lines.join - say "✅ Uncommented Stimulus controllers import in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ Uncommented Stimulus controllers import in #{StimulusReflex::Installer.friendly_pack_path}" else say "🤷 your Stimulus controllers are not being imported in your application.js. We trust that you have a reason for this." end else - say "⏩ Stimulus controllers are already being imported in #{friendly_pack_path}. Skipping." + say "⏩ Stimulus controllers are already being imported in #{StimulusReflex::Installer.friendly_pack_path}. Skipping." end else - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ /^import / } lines.insert lines.index(matches.last).to_i + 1, "import \".\/controllers\"\n" # standard:disable Style/RedundantStringEscape - pack_path.write lines.join - say "✅ Stimulus controllers imported in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ Stimulus controllers imported in #{StimulusReflex::Installer.friendly_pack_path}" end -complete_step :esbuild +StimulusReflex::Installer.complete_step :esbuild diff --git a/lib/install/example.rb b/lib/install/example.rb index 8f0f2237..acc96f2e 100644 --- a/lib/install/example.rb +++ b/lib/install/example.rb @@ -4,8 +4,8 @@ proceed = false if !Rails.root.join("app/reflexes/example_reflex.rb").exist? - proceed = if options.key? "example" - options["example"] + proceed = if StimulusReflex::Installer.options.key? "example" + StimulusReflex::Installer.options["example"] else !no?("✨ Generate an example Reflex with a quick demo? You can remove it later with a single command. (Y/n)") end @@ -19,4 +19,4 @@ say "⏩ Skipping." end -complete_step :example +StimulusReflex::Installer.complete_step :example diff --git a/lib/install/importmap.rb b/lib/install/importmap.rb index de1b98f2..cec98c52 100644 --- a/lib/install/importmap.rb +++ b/lib/install/importmap.rb @@ -2,37 +2,37 @@ require "stimulus_reflex/installer" -return if pack_path_missing? +return if StimulusReflex::Installer.pack_path_missing? -if !importmap_path.exist? - halt "#{friendly_importmap_path} is missing. You need a valid importmap config file to proceed." +if !StimulusReflex::Installer.importmap_path.exist? + StimulusReflex::Installer.halt "#{friendly_StimulusReflex::Installer.importmap_path} is missing. You need a valid importmap config file to proceed." return end -importmap = importmap_path.read +importmap = StimulusReflex::Installer.importmap_path.read -backup(importmap_path) do - if !importmap.include?("pin_all_from \"#{entrypoint}/controllers\"") - append_file(importmap_path, <<~RUBY, verbose: false) - pin_all_from "#{entrypoint}/controllers", under: "controllers" +StimulusReflex::Installer.backup(StimulusReflex::Installer.importmap_path) do + if !importmap.include?("pin_all_from \"#{StimulusReflex::Installer.entrypoint}/controllers\"") + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) + pin_all_from "#{StimulusReflex::Installer.entrypoint}/controllers", under: "controllers" RUBY say "✅ pin_all_from controllers" else say "⏩ pin_all_from controllers already pinned. Skipping." end - if !importmap.include?("pin_all_from \"#{entrypoint}/channels\"") - append_file(importmap_path, <<~RUBY, verbose: false) - pin_all_from "#{entrypoint}/channels", under: "channels" + if !importmap.include?("pin_all_from \"#{StimulusReflex::Installer.entrypoint}/channels\"") + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) + pin_all_from "#{StimulusReflex::Installer.entrypoint}/channels", under: "channels" RUBY say "✅ pin_all_from channels" else say "⏩ pin_all_from channels already pinned. Skipping." end - if !importmap.include?("pin_all_from \"#{entrypoint}/config\"") - append_file(importmap_path, <<~RUBY, verbose: false) - pin_all_from "#{entrypoint}/config", under: "config" + if !importmap.include?("pin_all_from \"#{StimulusReflex::Installer.entrypoint}/config\"") + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) + pin_all_from "#{StimulusReflex::Installer.entrypoint}/config", under: "config" RUBY say "✅ pin_all_from config" else @@ -40,7 +40,7 @@ end if !importmap.include?("pin \"@rails/actioncable\"") - append_file(importmap_path, <<~RUBY, verbose: false) + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) pin "@rails/actioncable", to: "actioncable.esm.js", preload: true RUBY say "✅ pin @rails/actioncable" @@ -49,7 +49,7 @@ end if !importmap.include?("pin \"@hotwired/stimulus\"") - append_file(importmap_path, <<~RUBY, verbose: false) + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) pin "@hotwired/stimulus", to: "stimulus.js", preload: true RUBY say "✅ pin @hotwired/stimulus" @@ -58,7 +58,7 @@ end if !importmap.include?("pin \"morphdom\"") - append_file(importmap_path, <<~RUBY, verbose: false) + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) pin "morphdom", to: "https://ga.jspm.io/npm:morphdom@2.6.1/dist/morphdom.js", preload: true RUBY say "✅ pin morphdom" @@ -67,7 +67,7 @@ end if !importmap.include?("pin \"cable_ready\"") - append_file(importmap_path, <<~RUBY, verbose: false) + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) pin "cable_ready", to: "cable_ready.js", preload: true RUBY say "✅ pin cable_ready" @@ -76,7 +76,7 @@ end if !importmap.include?("pin \"stimulus_reflex\"") - append_file(importmap_path, <<~RUBY, verbose: false) + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) pin "stimulus_reflex", to: "stimulus_reflex.js", preload: true RUBY say "✅ pin stimulus_reflex" @@ -85,20 +85,20 @@ end end -application_controller_src = fetch("/", "app/javascript/controllers/application_controller.js.tt") -application_controller_path = controllers_path / "application_controller.js" -application_js_src = fetch("/", "app/javascript/controllers/application.js.tt") -application_js_path = controllers_path / "application.js" -index_src = fetch("/", "app/javascript/controllers/index.js.importmap.tt") -index_path = controllers_path / "index.js" +application_controller_src = StimulusReflex::Installer.fetch("/", "app/javascript/controllers/application_controller.js.tt") +application_controller_path = StimulusReflex::Installer.controllers_path / "application_controller.js" +application_js_src = StimulusReflex::Installer.fetch("/", "app/javascript/controllers/application.js.tt") +application_js_path = StimulusReflex::Installer.controllers_path / "application.js" +index_src = StimulusReflex::Installer.fetch("/", "app/javascript/controllers/index.js.importmap.tt") +index_path = StimulusReflex::Installer.controllers_path / "index.js" # create entrypoint/controllers, as well as the index, application and application_controller -empty_directory controllers_path unless controllers_path.exist? +empty_directory StimulusReflex::Installer.controllers_path unless StimulusReflex::Installer.controllers_path.exist? copy_file(application_controller_src, application_controller_path) unless application_controller_path.exist? # configure Stimulus application superclass to import Action Cable consumer -backup(application_js_path) do +StimulusReflex::Installer.backup(application_js_path) do if application_js_path.exist? friendly_application_js_path = application_js_path.relative_path_from(Rails.root).to_s if application_js_path.read.include?("import consumer") @@ -120,7 +120,7 @@ if index_path.read == index_src.read say "⏩ #{friendly_index_path} is present. Skipping" else - backup(index_path, delete: true) do + StimulusReflex::Installer.backup(index_path, delete: true) do copy_file(index_src, index_path, verbose: false) end say "✅ #{friendly_index_path} has been updated" @@ -130,4 +130,4 @@ say "✅ #{friendly_index_path} has been created." end -complete_step :importmap +StimulusReflex::Installer.complete_step :importmap diff --git a/lib/install/initializers.rb b/lib/install/initializers.rb index ba08e1c4..773fb6fd 100644 --- a/lib/install/initializers.rb +++ b/lib/install/initializers.rb @@ -2,10 +2,10 @@ require "stimulus_reflex/installer" -sr_initializer_src = fetch("/", "config/initializers/stimulus_reflex.rb") +sr_initializer_src = StimulusReflex::Installer.fetch("/", "config/initializers/stimulus_reflex.rb") sr_initializer_path = Rails.root.join("config/initializers/stimulus_reflex.rb") -cr_initializer_src = fetch("/", "config/initializers/cable_ready.rb") +cr_initializer_src = StimulusReflex::Installer.fetch("/", "config/initializers/cable_ready.rb") cr_initializer_path = Rails.root.join("config/initializers/cable_ready.rb") if !sr_initializer_path.exist? @@ -22,4 +22,4 @@ say "⏩ config/initializers/cable_ready.rb already exists. Skipping." end -complete_step :initializers +StimulusReflex::Installer.complete_step :initializers diff --git a/lib/install/mrujs.rb b/lib/install/mrujs.rb index 1b3a91c1..3fab1e0d 100644 --- a/lib/install/mrujs.rb +++ b/lib/install/mrujs.rb @@ -2,34 +2,34 @@ require "stimulus_reflex/installer" -return if pack_path_missing? +return if StimulusReflex::Installer.pack_path_missing? -mrujs_path = config_path / "mrujs.js" +mrujs_path = StimulusReflex::Installer.config_path / "mrujs.js" proceed = false if !File.exist?(mrujs_path) - proceed = if options.key? "mrujs" - options["mrujs"] + proceed = if StimulusReflex::Installer.options.key? "mrujs" + StimulusReflex::Installer.options["mrujs"] else !no?("✨ Would you like to install and enable mrujs? It's a modern, drop-in replacement for rails-ujs (Y/n)") end end if proceed - if bundler.importmap? + if StimulusReflex::Installer.bundler.importmap? - if !importmap_path.exist? - halt "#{friendly_importmap_path} is missing. You need a valid importmap config file to proceed." + if !StimulusReflex::Installer.importmap_path.exist? + StimulusReflex::Installer.halt "#{friendly_StimulusReflex::Installer.importmap_path} is missing. You need a valid importmap config file to proceed." return end - importmap = importmap_path.read + importmap = StimulusReflex::Installer.importmap_path.read if importmap.include?("pin \"mrujs\"") say "⏩ mrujs already pinned. Skipping." else - append_file(importmap_path, <<~RUBY, verbose: false) + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) pin "mrujs", to: "https://ga.jspm.io/npm:mrujs@0.10.1/dist/index.module.js" RUBY say "✅ pin mrujs" @@ -38,40 +38,40 @@ if importmap.include?("pin \"mrujs/plugins\"") say "⏩ mrujs/plugins already pinned. Skipping." else - append_file(importmap_path, <<~RUBY, verbose: false) + append_file(StimulusReflex::Installer.importmap_path, <<~RUBY, verbose: false) pin "mrujs/plugins", to: "https://ga.jspm.io/npm:mrujs@0.10.1/plugins/dist/plugins.module.js" RUBY say "✅ pin mrujs/plugins" end else # queue mrujs for installation - if package_json_path.read.include?('"mrujs":') + if StimulusReflex::Installer.package_json_path.read.include?('"mrujs":') say "⏩ mrujs already present. Skipping." else - add_package "mrujs@^0.10.1" + StimulusReflex::Installer.add_package "mrujs@^0.10.1" end # queue @rails/ujs for removal - if package_json_path.read.include?('"@rails/ujs":') - drop_package "@rails/ujs" + if StimulusReflex::Installer.package_json_path.read.include?('"@rails/ujs":') + StimulusReflex::Installer.drop_package "@rails/ujs" else say "⏩ @rails/ujs not present. Skipping." end end step_path = "/app/javascript/config/" - mrujs_src = fetch(step_path, "mrujs.js.tt") + mrujs_src = StimulusReflex::Installer.fetch(step_path, "mrujs.js.tt") # create entrypoint/config/mrujs.js if necessary copy_file(mrujs_src, mrujs_path) unless mrujs_path.exist? # import mrujs config in entrypoint/config/index.js - index_path = config_path / "index.js" + index_path = StimulusReflex::Installer.config_path / "index.js" index = index_path.read friendly_index_path = index_path.relative_path_from(Rails.root).to_s mrujs_pattern = /import ['"].\/mrujs['"]/ - mrujs_import = if bundler.importmap? + mrujs_import = if StimulusReflex::Installer.bundler.importmap? %(import "config/mrujs"\n) else %(import "./mrujs"\n) @@ -87,12 +87,12 @@ # remove @rails/ujs from application.js rails_ujs_pattern = /import Rails from ['"]@rails\/ujs['"]/ - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines if lines.index { |line| line =~ rails_ujs_pattern } - gsub_file pack_path, rails_ujs_pattern, "", verbose: false - say "✅ @rails/ujs removed from #{friendly_pack_path}" + gsub_file StimulusReflex::Installer.pack_path, rails_ujs_pattern, "", verbose: false + say "✅ @rails/ujs removed from #{StimulusReflex::Installer.friendly_pack_path}" else - say "⏩ @rails/ujs not present in #{friendly_pack_path}. Skipping." + say "⏩ @rails/ujs not present in #{StimulusReflex::Installer.friendly_pack_path}. Skipping." end # set Action View to generate remote forms when using form_with @@ -101,7 +101,7 @@ defaults_pattern = /config\.load_defaults \d\.\d/ lines = application_path.readlines - backup(application_path) do + StimulusReflex::Installer.backup(application_path) do if !lines.index { |line| line =~ application_pattern } if (index = lines.index { |line| line =~ /^[^#]*#{defaults_pattern}/ }) gsub_file application_path, /\s*#{defaults_pattern}\n/, verbose: false do @@ -127,12 +127,12 @@ # remove turbolinks from Gemfile because it's incompatible with mrujs (and unnecessary) turbolinks_pattern = /^[^#]*gem ["']turbolinks["']/ - lines = gemfile_path.readlines + lines = StimulusReflex::Installer.gemfile_path.readlines if lines.index { |line| line =~ turbolinks_pattern } - remove_gem :turbolinks + StimulusReflex::Installer.remove_gem :turbolinks else say "⏩ turbolinks is not present in Gemfile. Skipping." end end -complete_step :mrujs +StimulusReflex::Installer.complete_step :mrujs diff --git a/lib/install/npm_packages.rb b/lib/install/npm_packages.rb index 5694b259..954bbb5f 100644 --- a/lib/install/npm_packages.rb +++ b/lib/install/npm_packages.rb @@ -2,24 +2,24 @@ require "stimulus_reflex/installer" -lines = package_json_path.readlines +lines = StimulusReflex::Installer.package_json_path.readlines -if !lines.index { |line| line =~ /^\s*["']cable_ready["']: ["'].*#{cr_npm_version}["']/ } - add_package "cable_ready@#{cr_npm_version}" +if !lines.index { |line| line =~ /^\s*["']cable_ready["']: ["'].*#{StimulusReflex::Installer.cr_npm_version}["']/ } + StimulusReflex::Installer.add_package "cable_ready@#{StimulusReflex::Installer.cr_npm_version}" else say "⏩ cable_ready npm package is already present. Skipping." end -if !lines.index { |line| line =~ /^\s*["']stimulus_reflex["']: ["'].*#{sr_npm_version}["']/ } - add_package "stimulus_reflex@#{sr_npm_version}" +if !lines.index { |line| line =~ /^\s*["']stimulus_reflex["']: ["'].*#{StimulusReflex::Installer.sr_npm_version}["']/ } + StimulusReflex::Installer.add_package "stimulus_reflex@#{StimulusReflex::Installer.sr_npm_version}" else say "⏩ stimulus_reflex npm package is already present. Skipping." end if !lines.index { |line| line =~ /^\s*["']@hotwired\/stimulus["']:/ } - add_package "@hotwired/stimulus@^3.2" + StimulusReflex::Installer.add_package "@hotwired/stimulus@^3.2" else say "⏩ @hotwired/stimulus npm package is already present. Skipping." end -complete_step :npm_packages +StimulusReflex::Installer.complete_step :npm_packages diff --git a/lib/install/reflexes.rb b/lib/install/reflexes.rb index 64ea2feb..13f02a0c 100644 --- a/lib/install/reflexes.rb +++ b/lib/install/reflexes.rb @@ -5,7 +5,7 @@ reflexes_path = Rails.root.join("app/reflexes") step_path = "/app/reflexes/" application_reflex_path = reflexes_path / "application_reflex.rb" -application_reflex_src = fetch(step_path, "application_reflex.rb.tt") +application_reflex_src = StimulusReflex::Installer.fetch(step_path, "application_reflex.rb.tt") # verify app/reflexes exists and create if necessary if reflexes_path.exist? @@ -22,4 +22,4 @@ say "✅ Created app/reflexes/application_reflex.rb" end -complete_step :reflexes +StimulusReflex::Installer.complete_step :reflexes diff --git a/lib/install/shakapacker.rb b/lib/install/shakapacker.rb index 53f31a34..5ef1249b 100644 --- a/lib/install/shakapacker.rb +++ b/lib/install/shakapacker.rb @@ -2,28 +2,28 @@ require "stimulus_reflex/installer" -return if pack_path_missing? +return if StimulusReflex::Installer.pack_path_missing? # verify that all critical dependencies are up to date; if not, queue for later -lines = package_json_path.readlines +lines = StimulusReflex::Installer.package_json_path.readlines if !lines.index { |line| line =~ /^\s*["']@hotwired\/stimulus-webpack-helpers["']: ["']\^1.0.1["']/ } - add_package "@hotwired/stimulus-webpack-helpers@^1.0.1" + StimulusReflex::Installer.add_package "@hotwired/stimulus-webpack-helpers@^1.0.1" else say "⏩ @hotwired/stimulus-webpack-helpers npm package is already present. Skipping." end step_path = "/app/javascript/controllers/" -# controller_templates_path = File.expand_path(template_src + "/app/javascript/controllers", File.join(File.dirname(__FILE__))) -application_controller_src = fetch(step_path, "application_controller.js.tt") -application_controller_path = controllers_path / "application_controller.js" -application_js_src = fetch(step_path, "application.js.tt") -application_js_path = controllers_path / "application.js" -index_src = fetch(step_path, "index.js.shakapacker.tt") -index_path = controllers_path / "index.js" +# controller_templates_path = File.expand_path(StimulusReflex::Installer.template_src + "/app/javascript/controllers", File.join(File.dirname(__FILE__))) +application_controller_src = StimulusReflex::Installer.fetch(step_path, "application_controller.js.tt") +application_controller_path = StimulusReflex::Installer.controllers_path / "application_controller.js" +application_js_src = StimulusReflex::Installer.fetch(step_path, "application.js.tt") +application_js_path = StimulusReflex::Installer.controllers_path / "application.js" +index_src = StimulusReflex::Installer.fetch(step_path, "index.js.shakapacker.tt") +index_path = StimulusReflex::Installer.controllers_path / "index.js" # create entrypoint/controllers, as well as the index, application and application_controller -empty_directory controllers_path unless controllers_path.exist? +empty_directory StimulusReflex::Installer.controllers_path unless StimulusReflex::Installer.controllers_path.exist? copy_file(application_controller_src, application_controller_path) unless application_controller_path.exist? copy_file(application_js_src, application_js_path) unless application_js_path.exist? @@ -32,33 +32,33 @@ controllers_pattern = /import ['"]controllers['"]/ controllers_commented_pattern = /\s*\/\/\s*#{controllers_pattern}/ -if pack.match?(controllers_pattern) - if pack.match?(controllers_commented_pattern) - proceed = if options.key? "uncomment" - options["uncomment"] +if StimulusReflex::Installer.pack.match?(controllers_pattern) + if StimulusReflex::Installer.pack.match?(controllers_commented_pattern) + proceed = if StimulusReflex::Installer.options.key? "uncomment" + StimulusReflex::Installer.options["uncomment"] else !no?("✨ Do you want to import your Stimulus controllers in application.js? (Y/n)") end if proceed # uncomment_lines only works with Ruby comments 🙄 - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ controllers_commented_pattern } lines[lines.index(matches.last).to_i] = "import \"controllers\"\n" - pack_path.write lines.join - say "✅ Stimulus controllers imported in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ Stimulus controllers imported in #{StimulusReflex::Installer.friendly_pack_path}" else say "🤷 your Stimulus controllers are not being imported in your application.js. We trust that you have a reason for this." end else - say "✅ Stimulus controllers imported in #{friendly_pack_path}" + say "✅ Stimulus controllers imported in #{StimulusReflex::Installer.friendly_pack_path}" end else - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ /^import / } lines.insert lines.index(matches.last).to_i + 1, "import \"controllers\"\n" - pack_path.write lines.join - say "✅ Stimulus controllers imported in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ Stimulus controllers imported in #{StimulusReflex::Installer.friendly_pack_path}" end -complete_step :shakapacker +StimulusReflex::Installer.complete_step :shakapacker diff --git a/lib/install/spring.rb b/lib/install/spring.rb index 0ed753db..8e99ec5b 100644 --- a/lib/install/spring.rb +++ b/lib/install/spring.rb @@ -5,11 +5,11 @@ spring_pattern = /^[^#]*gem ["']spring["']/ proceed = false -lines = gemfile_path.readlines +lines = StimulusReflex::Installer.gemfile_path.readlines if lines.index { |line| line =~ spring_pattern } - proceed = if options.key? "spring" - options["spring"] + proceed = if StimulusReflex::Installer.options.key? "spring" + StimulusReflex::Installer.options["spring"] else !no?("✨ Would you like to disable the spring gem? \nIt's been removed from Rails 7, and is the frequent culprit behind countless mystery bugs. (Y/n)") end @@ -22,7 +22,7 @@ bin_rails_pattern = /^[^#]*load File.expand_path\("spring", __dir__\)/ if (index = lines.index { |line| line =~ spring_pattern }) - remove_gem :spring + StimulusReflex::Installer.remove_gem :spring bin_spring = Rails.root.join("bin/spring") if bin_spring.exist? @@ -33,7 +33,7 @@ bin_rails = Rails.root.join("bin/rails") bin_rails_content = bin_rails.readlines if (index = bin_rails_content.index { |line| line =~ bin_rails_pattern }) - backup(bin_rails) do + StimulusReflex::Installer.backup(bin_rails) do bin_rails_content[index] = "# #{bin_rails_content[index]}" bin_rails.write bin_rails_content.join end @@ -45,10 +45,10 @@ end if lines.index { |line| line =~ spring_watcher_pattern } - remove_gem "spring-watcher-listen" + StimulusReflex::Installer.remove_gem "spring-watcher-listen" end else say "⏩ Skipping." end -complete_step :spring +StimulusReflex::Installer.complete_step :spring diff --git a/lib/install/updatable.rb b/lib/install/updatable.rb index 366eaac9..a981a02e 100644 --- a/lib/install/updatable.rb +++ b/lib/install/updatable.rb @@ -2,18 +2,18 @@ require "stimulus_reflex/installer" -if application_record_path.exist? - lines = application_record_path.readlines +if StimulusReflex::Installer.application_record_path.exist? + lines = StimulusReflex::Installer.application_record_path.readlines if !lines.index { |line| line =~ /^\s*include CableReady::Updatable/ } - proceed = if options.key? "updatable" - options["updatable"] + proceed = if StimulusReflex::Installer.options.key? "updatable" + StimulusReflex::Installer.options["updatable"] else !no?("✨ Include CableReady::Updatable in Active Record model classes? (Y/n)") end unless proceed - complete_step :updatable + StimulusReflex::Installer.complete_step :updatable puts "⏩ Skipping." return @@ -21,7 +21,7 @@ index = lines.index { |line| line.include?("class ApplicationRecord < ActiveRecord::Base") } lines.insert index + 1, " include CableReady::Updatable\n" - application_record_path.write lines.join + StimulusReflex::Installer.application_record_path.write lines.join say "✅ included CableReady::Updatable in ApplicationRecord" else @@ -31,4 +31,4 @@ say "⏩ ApplicationRecord doesn't exist. Skipping." end -complete_step :updatable +StimulusReflex::Installer.complete_step :updatable diff --git a/lib/install/vite.rb b/lib/install/vite.rb index 479e87cc..3beae3fc 100644 --- a/lib/install/vite.rb +++ b/lib/install/vite.rb @@ -2,27 +2,27 @@ require "stimulus_reflex/installer" -return if pack_path_missing? +return if StimulusReflex::Installer.pack_path_missing? # verify that all critical dependencies are up to date; if not, queue for later -lines = package_json_path.readlines +lines = StimulusReflex::Installer.package_json_path.readlines if !lines.index { |line| line =~ /^\s*["']stimulus-vite-helpers["']: ["']\^3["']/ } - add_package "stimulus-vite-helpers@^3" + StimulusReflex::Installer.add_package "stimulus-vite-helpers@^3" else say "⏩ @stimulus-vite-helpers npm package is already present. Skipping." end step_path = "/app/javascript/controllers/" -application_controller_src = fetch(step_path, "application_controller.js.tt") -application_controller_path = controllers_path / "application_controller.js" -application_js_src = fetch(step_path, "application.js.tt") -application_js_path = controllers_path / "application.js" -index_src = fetch(step_path, "index.js.vite.tt") -index_path = controllers_path / "index.js" +application_controller_src = StimulusReflex::Installer.fetch(step_path, "application_controller.js.tt") +application_controller_path = StimulusReflex::Installer.controllers_path / "application_controller.js" +application_js_src = StimulusReflex::Installer.fetch(step_path, "application.js.tt") +application_js_path = StimulusReflex::Installer.controllers_path / "application.js" +index_src = StimulusReflex::Installer.fetch(step_path, "index.js.vite.tt") +index_path = StimulusReflex::Installer.controllers_path / "index.js" # create entrypoint/controllers, as well as the index, application and application_controller -empty_directory controllers_path unless controllers_path.exist? +empty_directory StimulusReflex::Installer.controllers_path unless StimulusReflex::Installer.controllers_path.exist? copy_file(application_controller_src, application_controller_path) unless application_controller_path.exist? copy_file(application_js_src, application_js_path) unless application_js_path.exist? @@ -32,33 +32,33 @@ controllers_commented_pattern = /\s*\/\/\s*#{controllers_pattern}/ prefix = "..\/" # standard:disable Style/RedundantStringEscape -if pack.match?(controllers_pattern) - if pack.match?(controllers_commented_pattern) - proceed = if options.key? "uncomment" - options["uncomment"] +if StimulusReflex::Installer.pack.match?(controllers_pattern) + if StimulusReflex::Installer.pack.match?(controllers_commented_pattern) + proceed = if StimulusReflex::Installer.options.key? "uncomment" + StimulusReflex::Installer.options["uncomment"] else !no?("✨ Do you want to import your Stimulus controllers in application.js? (Y/n)") end if proceed # uncomment_lines only works with Ruby comments 🙄 - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ controllers_commented_pattern } lines[lines.index(matches.last).to_i] = "import \"#{prefix}controllers\"\n" - pack_path.write lines.join - say "✅ Uncommented Stimulus controllers import in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ Uncommented Stimulus controllers import in #{StimulusReflex::Installer.friendly_pack_path}" else say "🤷 your Stimulus controllers are not being imported in your application.js. We trust that you have a reason for this." end else - say "⏩ Stimulus controllers are already being imported in #{friendly_pack_path}. Skipping." + say "⏩ Stimulus controllers are already being imported in #{StimulusReflex::Installer.friendly_pack_path}. Skipping." end else - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ /^import / } lines.insert lines.index(matches.last).to_i + 1, "import \"#{prefix}controllers\"\n" - pack_path.write lines.join - say "✅ Stimulus controllers imported in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ Stimulus controllers imported in #{StimulusReflex::Installer.friendly_pack_path}" end -complete_step :vite +StimulusReflex::Installer.complete_step :vite diff --git a/lib/install/webpacker.rb b/lib/install/webpacker.rb index ddfce7ce..b4776f7e 100644 --- a/lib/install/webpacker.rb +++ b/lib/install/webpacker.rb @@ -2,50 +2,50 @@ require "stimulus_reflex/installer" -return if pack_path_missing? +return if StimulusReflex::Installer.pack_path_missing? # verify that all critical dependencies are up to date; if not, queue for later -lines = package_json_path.readlines +lines = StimulusReflex::Installer.package_json_path.readlines if !lines.index { |line| line =~ /^\s*["']webpack["']: ["']\^4.46.0["']/ } - add_package "webpack@^4.46.0" + StimulusReflex::Installer.add_package "webpack@^4.46.0" else say "⏩ webpack npm package is already present. Skipping." end if !lines.index { |line| line =~ /^\s*["']webpack-cli["']: ["']\^3.3.12["']/ } - add_package "webpack-cli@^3.3.12" + StimulusReflex::Installer.add_package "webpack-cli@^3.3.12" else say "⏩ webpack-cli npm package is already present. Skipping." end if !lines.index { |line| line =~ /^\s*["']@rails\/webpacker["']: ["']\^5.4.3["']/ } - add_package "@rails/webpacker@^5.4.3" + StimulusReflex::Installer.add_package "@rails/webpacker@^5.4.3" else say "⏩ @rails/webpacker npm package is already present. Skipping." end if !lines.index { |line| line =~ /^\s*["']@hotwired\/stimulus-webpack-helpers["']: ["']\^1.0.1["']/ } - add_package "@hotwired/stimulus-webpack-helpers@^1.0.1" + StimulusReflex::Installer.add_package "@hotwired/stimulus-webpack-helpers@^1.0.1" else say "⏩ @hotwired/stimulus-webpack-helpers npm package is already present. Skipping." end if !lines.index { |line| line =~ /^\s*["']webpack-dev-server["']: ["']\^3.11.3["']/ } - add_dev_package "webpack-dev-server@^3.11.3" + StimulusReflex::Installer.add_dev_package "webpack-dev-server@^3.11.3" else say "⏩ @webpack-dev-server is already present. Skipping." end step_path = "/app/javascript/controllers/" -application_controller_src = fetch(step_path, "application_controller.js.tt") -application_controller_path = controllers_path / "application_controller.js" -application_js_src = fetch(step_path, "application.js.tt") -application_js_path = controllers_path / "application.js" -index_src = fetch(step_path, "index.js.webpacker.tt") -index_path = controllers_path / "index.js" +application_controller_src = StimulusReflex::Installer.fetch(step_path, "application_controller.js.tt") +application_controller_path = StimulusReflex::Installer.controllers_path / "application_controller.js" +application_js_src = StimulusReflex::Installer.fetch(step_path, "application.js.tt") +application_js_path = StimulusReflex::Installer.controllers_path / "application.js" +index_src = StimulusReflex::Installer.fetch(step_path, "index.js.webpacker.tt") +index_path = StimulusReflex::Installer.controllers_path / "index.js" # create entrypoint/controllers, as well as the index, application and application_controller -empty_directory controllers_path unless controllers_path.exist? +empty_directory StimulusReflex::Installer.controllers_path unless StimulusReflex::Installer.controllers_path.exist? copy_file(application_controller_src, application_controller_path) unless application_controller_path.exist? # webpacker 5.4 did not colloquially feature a controllers/application.js file @@ -55,36 +55,36 @@ controllers_pattern = /import ['"]controllers['"]/ controllers_commented_pattern = /\s*\/\/\s*#{controllers_pattern}/ -if pack.match?(controllers_pattern) - if pack.match?(controllers_commented_pattern) - proceed = if options.key? "uncomment" - options["uncomment"] +if StimulusReflex::Installer.pack.match?(controllers_pattern) + if StimulusReflex::Installer.pack.match?(controllers_commented_pattern) + proceed = if StimulusReflex::Installer.options.key? "uncomment" + StimulusReflex::Installer.options["uncomment"] else !no?("✨ Do you want to import your Stimulus controllers in application.js? (Y/n)") end if proceed # uncomment_lines only works with Ruby comments 🙄 - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ controllers_commented_pattern } lines[lines.index(matches.last).to_i] = "import \"controllers\"\n" - pack_path.write lines.join - say "✅ Uncommented Stimulus controllers import in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ Uncommented Stimulus controllers import in #{StimulusReflex::Installer.friendly_pack_path}" else say "🤷 your Stimulus controllers are not being imported in your application.js. We trust that you have a reason for this." end else - say "⏩ Stimulus controllers are already being imported in #{friendly_pack_path}. Skipping." + say "⏩ Stimulus controllers are already being imported in #{StimulusReflex::Installer.friendly_pack_path}. Skipping." end else - lines = pack_path.readlines + lines = StimulusReflex::Installer.pack_path.readlines matches = lines.select { |line| line =~ /^import / } lines.insert lines.index(matches.last).to_i + 1, "import \"controllers\"\n" - pack_path.write lines.join - say "✅ Stimulus controllers imported in #{friendly_pack_path}" + StimulusReflex::Installer.pack_path.write lines.join + say "✅ Stimulus controllers imported in #{StimulusReflex::Installer.friendly_pack_path}" end # ensure webpacker is installed in the Gemfile -add_gem "webpacker@5.4.3" +StimulusReflex::Installer.add_gem "webpacker@5.4.3" -complete_step :webpacker +StimulusReflex::Installer.complete_step :webpacker diff --git a/lib/install/yarn.rb b/lib/install/yarn.rb index 36d53dff..19a402a4 100644 --- a/lib/install/yarn.rb +++ b/lib/install/yarn.rb @@ -2,18 +2,18 @@ require "stimulus_reflex/installer" -if !package_json_path.exist? +if !StimulusReflex::Installer.package_json_path.exist? say "⏩ No package.json file found. Skipping." return end # run yarn install only when packages are waiting to be added or removed -add = package_list.exist? ? package_list.readlines.map(&:chomp) : [] -dev = dev_package_list.exist? ? dev_package_list.readlines.map(&:chomp) : [] -drop = drop_package_list.exist? ? drop_package_list.readlines.map(&:chomp) : [] +add = StimulusReflex::Installer.package_list.exist? ? StimulusReflex::Installer.package_list.readlines.map(&:chomp) : [] +dev = StimulusReflex::Installer.dev_package_list.exist? ? StimulusReflex::Installer.dev_package_list.readlines.map(&:chomp) : [] +drop = StimulusReflex::Installer.drop_package_list.exist? ? StimulusReflex::Installer.drop_package_list.readlines.map(&:chomp) : [] -json = JSON.parse(package_json_path.read) +json = JSON.parse(StimulusReflex::Installer.package_json_path.read) if add.present? || dev.present? || drop.present? @@ -36,20 +36,20 @@ json["devDependencies"].delete(package) end - package_json_path.write JSON.pretty_generate(json) + StimulusReflex::Installer.package_json_path.write JSON.pretty_generate(json) system "yarn install --silent" else say "⏩ No yarn depdencies to add or remove. Skipping." end -if bundler == "esbuild" && json["scripts"]["build"] != "node esbuild.config.mjs" +if StimulusReflex::Installer.bundler == "esbuild" && json["scripts"]["build"] != "node esbuild.config.mjs" json["scripts"]["build:default"] = json["scripts"]["build"] json["scripts"]["build"] = "node esbuild.config.mjs" - package_json_path.write JSON.pretty_generate(json) + StimulusReflex::Installer.package_json_path.write JSON.pretty_generate(json) say "✅ Your yarn build script has been updated to use esbuild.config.mjs" else say "⏩ Your yarn build script is already setup. Skipping." end -complete_step :yarn +StimulusReflex::Installer.complete_step :yarn diff --git a/lib/stimulus_reflex/installer.rb b/lib/stimulus_reflex/installer.rb index 72eda879..70b33b4f 100644 --- a/lib/stimulus_reflex/installer.rb +++ b/lib/stimulus_reflex/installer.rb @@ -1,355 +1,381 @@ # frozen_string_literal: true -### general utilities +module StimulusReflex + class Installer + include Thor::Base + include Thor::Actions -def fetch(step_path, file) - relative_path = step_path + file - location = template_src + relative_path + source_root Dir.pwd - Pathname.new(location) -end + ## Thor wrapper -def complete_step(step) - create_file "tmp/stimulus_reflex_installer/#{step}", verbose: false -end + def self.create_file(...) + new.create_file(...) + end -def create_or_append(path, *args, &block) - FileUtils.touch(path) - append_file(path, *args, &block) -end + def self.append_file(...) + new.append_file(...) + end -def current_template - ENV["LOCATION"].split("/").last.gsub(".rb", "") -end + def self.copy_file(...) + new.copy_file(...) + end -def pack_path_missing? - return false unless pack_path.nil? - halt "#{friendly_pack_path} is missing. You need a valid application pack file to proceed." -end + def self.say(...) + new.say(...) + end -def halt(message) - say "❌ #{message}", :red - create_file "tmp/stimulus_reflex_installer/halt", verbose: false -end + ### general utilities -def backup(path, delete: false) - if !path.exist? - yield - return - end + def self.fetch(step_path, file) + relative_path = step_path + file + location = template_src + relative_path - backup_path = Pathname.new("#{path}.bak") - old_path = path.relative_path_from(Rails.root).to_s - filename = path.to_path.split("/").last + Pathname.new(location) + end - if backup_path.exist? - if backup_path.read == path.read - path.delete if delete - yield - return + def self.complete_step(step) + create_file "tmp/stimulus_reflex_installer/#{step}", verbose: false end - backup_path.delete - end - copy_file(path, backup_path, verbose: false) - path.delete if delete + def self.create_or_append(path, *args, &block) + FileUtils.touch(path) + append_file(path, *args, &block) + end - yield + def self.current_template + ENV["LOCATION"].split("/").last.gsub(".rb", "") + end - if path.read != backup_path.read - create_or_append(backups_path, "#{old_path}\n", verbose: false) - end - say "📦 #{old_path} backed up as #{filename}.bak" -end + def self.pack_path_missing? + return false unless pack_path.nil? + halt "#{friendly_pack_path} is missing. You need a valid application pack file to proceed." + end -def add_gem(name) - create_or_append(add_gem_list, "#{name}\n", verbose: false) - say "☑️ Added #{name} to the Gemfile" -end + def self.halt(message) + say "❌ #{message}", :red + create_file "tmp/stimulus_reflex_installer/halt", verbose: false + end -def remove_gem(name) - create_or_append(remove_gem_list, "#{name}\n", verbose: false) - say "❎ Removed #{name} from Gemfile" -end + def self.backup(path, delete: false) + if !path.exist? + yield + return + end -def add_package(name) - create_or_append(package_list, "#{name}\n", verbose: false) - say "☑️ Enqueued #{name} to be added to dependencies" -end + backup_path = Pathname.new("#{path}.bak") + old_path = path.relative_path_from(Rails.root).to_s + filename = path.to_path.split("/").last + + if backup_path.exist? + if backup_path.read == path.read + path.delete if delete + yield + return + end + backup_path.delete + end -def add_dev_package(name) - create_or_append(dev_package_list, "#{name}\n", verbose: false) - say "☑️ Enqueued #{name} to be added to dev dependencies" -end + copy_file(path, backup_path, verbose: false) + path.delete if delete -def drop_package(name) - create_or_append(drop_package_list, "#{name}\n", verbose: false) - say "❎ Enqueued #{name} to be removed from dependencies" -end + yield -def gemfile_hash - Digest::MD5.hexdigest(gemfile_path.read) -end + if path.read != backup_path.read + create_or_append(backups_path, "#{old_path}\n", verbose: false) + end + say "📦 #{old_path} backed up as #{filename}.bak" + end -### memoized values + def self.add_gem(name) + create_or_append(add_gem_list, "#{name}\n", verbose: false) + say "☑️ Added #{name} to the Gemfile" + end -def sr_npm_version - @sr_npm_version ||= StimulusReflex::VERSION.gsub(".pre", "-pre").gsub(".rc", "-rc") -end + def self.remove_gem(name) + create_or_append(remove_gem_list, "#{name}\n", verbose: false) + say "❎ Removed #{name} from Gemfile" + end -def cr_npm_version - @cr_npm_version ||= CableReady::VERSION.gsub(".pre", "-pre").gsub(".rc", "-rc") -end + def self.add_package(name) + create_or_append(package_list, "#{name}\n", verbose: false) + say "☑️ Enqueued #{name} to be added to dependencies" + end -def package_json_path - @package_json_path ||= Rails.root.join("package.json") -end + def self.add_dev_package(name) + create_or_append(dev_package_list, "#{name}\n", verbose: false) + say "☑️ Enqueued #{name} to be added to dev dependencies" + end -def installer_entrypoint_path - create_dir_for_file_if_not_exists("tmp/stimulus_reflex_installer/entrypoint") -end + def self.drop_package(name) + create_or_append(drop_package_list, "#{name}\n", verbose: false) + say "❎ Enqueued #{name} to be removed from dependencies" + end -def entrypoint - path = installer_entrypoint_path - @entrypoint ||= File.exist?(path) ? File.read(path) : auto_detect_entrypoint -end + def self.gemfile_hash + Digest::MD5.hexdigest(gemfile_path.read) + end -def auto_detect_entrypoint - entrypoint = [ - "app/javascript", - "app/frontend", - "app/client", - "app/webpack" - ].find { |path| File.exist?(Rails.root.join(path)) } || "app/javascript" + ### memoized values - puts - puts "Where do JavaScript files live in your app? Our best guess is: \e[1m#{entrypoint}\e[22m 🤔" - puts "Press enter to accept this, or type a different path." - print "> " + def self.sr_npm_version + @sr_npm_version ||= StimulusReflex::VERSION.gsub(".pre", "-pre").gsub(".rc", "-rc") + end - input = Rails.env.test? ? "tmp/app/javascript" : $stdin.gets.chomp - entrypoint = input unless input.blank? + def self.cr_npm_version + @cr_npm_version ||= CableReady::VERSION.gsub(".pre", "-pre").gsub(".rc", "-rc") + end - File.write(installer_entrypoint_path, entrypoint) + def self.package_json_path + @package_json_path ||= Rails.root.join("package.json") + end - entrypoint -end + def self.installer_entrypoint_path + create_dir_for_file_if_not_exists("tmp/stimulus_reflex_installer/entrypoint") + end -def installer_bundler_path - create_dir_for_file_if_not_exists("tmp/stimulus_reflex_installer/bundler") -end + def self.entrypoint + path = installer_entrypoint_path + @entrypoint ||= File.exist?(path) ? File.read(path) : auto_detect_entrypoint + end -def bundler - path = installer_bundler_path - @bundler ||= File.exist?(path) ? File.read(path) : auto_detect_bundler + def self.auto_detect_entrypoint + entrypoint = [ + "app/javascript", + "app/frontend", + "app/client", + "app/webpack" + ].find { |path| File.exist?(Rails.root.join(path)) } || "app/javascript" - @bundler.inquiry -end + puts + puts "Where do JavaScript files live in your app? Our best guess is: \e[1m#{entrypoint}\e[22m 🤔" + puts "Press enter to accept this, or type a different path." + print "> " -def auto_detect_bundler - # auto-detect build tool based on existing packages and configuration - if importmap_path.exist? - bundler = "importmap" - elsif package_json_path.exist? - package_json = package_json_path.read - - bundler = "webpacker" if package_json.include?('"@rails/webpacker":') - bundler = "esbuild" if package_json.include?('"esbuild":') - bundler = "vite" if package_json.include?('"vite":') - bundler = "shakapacker" if package_json.include?('"shakapacker":') - - if !bundler - puts "❌ You must be using a node-based bundler such as esbuild, webpacker, vite or shakapacker (package.json) or importmap (config/importmap.rb) to use StimulusReflex." - exit - end - else - puts "❌ You must be using a node-based bundler such as esbuild, webpacker, vite or shakapacker (package.json) or importmap (config/importmap.rb) to use StimulusReflex." - exit - end + input = Rails.env.test? ? "tmp/app/javascript" : $stdin.gets.chomp + entrypoint = input unless input.blank? - puts - puts "It looks like you're using \e[1m#{bundler}\e[22m as your bundler. Is that correct? (Y/n)" - print "> " + File.write(installer_entrypoint_path, entrypoint) - input = $stdin.gets.chomp + entrypoint + end - if input.downcase == "n" - puts - puts "StimulusReflex installation supports: esbuild, webpacker, vite, shakapacker and importmap." - puts "Please run \e[1;94mrails stimulus_reflex:install [bundler]\e[0m to install StimulusReflex and CableReady." - exit - end + def self.installer_bundler_path + create_dir_for_file_if_not_exists("tmp/stimulus_reflex_installer/bundler") + end - File.write(installer_bundler_path, bundler) + def self.bundler + path = installer_bundler_path + @bundler ||= File.exist?(path) ? File.read(path) : auto_detect_bundler - bundler -end + @bundler.inquiry + end -def create_dir_if_not_exists(dir_path) - FileUtils.mkdir_p(dir_path) + def self.auto_detect_bundler + # auto-detect build tool based on existing packages and configuration + if importmap_path.exist? + bundler = "importmap" + elsif package_json_path.exist? + package_json = package_json_path.read + + bundler = "webpacker" if package_json.include?('"@rails/webpacker":') + bundler = "esbuild" if package_json.include?('"esbuild":') + bundler = "vite" if package_json.include?('"vite":') + bundler = "shakapacker" if package_json.include?('"shakapacker":') + + if !bundler + puts "❌ You must be using a node-based bundler such as esbuild, webpacker, vite or shakapacker (package.json) or importmap (config/importmap.rb) to use StimulusReflex." + exit + end + else + puts "❌ You must be using a node-based bundler such as esbuild, webpacker, vite or shakapacker (package.json) or importmap (config/importmap.rb) to use StimulusReflex." + exit + end - Pathname.new(dir_path) -end + puts + puts "It looks like you're using \e[1m#{bundler}\e[22m as your bundler. Is that correct? (Y/n)" + print "> " -def create_dir_for_file_if_not_exists(file_path) - dir_path = File.dirname(file_path) - create_dir_if_not_exists(dir_path) + input = $stdin.gets.chomp - Pathname.new(file_path) -end + if input.downcase == "n" + puts + puts "StimulusReflex installation supports: esbuild, webpacker, vite, shakapacker and importmap." + puts "Please run \e[1;94mrails stimulus_reflex:install[bundler]\e[0m to install StimulusReflex and CableReady." + exit + end -def config_path - @config_path ||= create_dir_if_not_exists(Rails.root.join(entrypoint, "config")) -end + File.write(installer_bundler_path, bundler) -def importmap_path - @importmap_path ||= Rails.root.join("config/importmap.rb") -end + bundler + end -def friendly_importmap_path - @friendly_importmap_path ||= importmap_path.relative_path_from(Rails.root).to_s -end + def self.create_dir_if_not_exists(dir_path) + FileUtils.mkdir_p(dir_path) -def pack - @pack ||= pack_path.read -end + Pathname.new(dir_path) + end -def friendly_pack_path - @friendly_pack_path ||= pack_path.relative_path_from(Rails.root).to_s -end + def self.create_dir_for_file_if_not_exists(file_path) + dir_path = File.dirname(file_path) + create_dir_if_not_exists(dir_path) -def pack_path - @pack_path ||= [ - Rails.root.join(entrypoint, "application.js"), - Rails.root.join(entrypoint, "packs/application.js"), - Rails.root.join(entrypoint, "entrypoints/application.js") - ].find(&:exist?) -end + Pathname.new(file_path) + end -def package_list - @package_list ||= Rails.root.join("tmp/stimulus_reflex_installer/npm_package_list") -end + def self.config_path + @config_path ||= create_dir_if_not_exists(Rails.root.join(entrypoint, "config")) + end -def dev_package_list - @dev_package_list ||= Rails.root.join("tmp/stimulus_reflex_installer/npm_dev_package_list") -end + def self.importmap_path + @importmap_path ||= Rails.root.join("config/importmap.rb") + end -def drop_package_list - @drop_package_list ||= Rails.root.join("tmp/stimulus_reflex_installer/drop_npm_package_list") -end + def self.friendly_importmap_path + @friendly_importmap_path ||= importmap_path.relative_path_from(Rails.root).to_s + end -def template_src - @template_src ||= File.read("tmp/stimulus_reflex_installer/template_src") -end + def self.pack + @pack ||= pack_path.read + end -def controllers_path - @controllers_path ||= Rails.root.join(entrypoint, "controllers") -end + def self.friendly_pack_path + @friendly_pack_path ||= pack_path.relative_path_from(Rails.root).to_s + end -def gemfile_path - @gemfile_path ||= Rails.root.join("Gemfile") -end + def self.pack_path + @pack_path ||= [ + Rails.root.join(entrypoint, "application.js"), + Rails.root.join(entrypoint, "packs/application.js"), + Rails.root.join(entrypoint, "entrypoints/application.js") + ].find(&:exist?) + end -def gemfile - @gemfile ||= gemfile_path.read -end + def self.package_list + @package_list ||= Rails.root.join("tmp/stimulus_reflex_installer/npm_package_list") + end -def prefix - # standard:disable Style/RedundantStringEscape - @prefix ||= { - "vite" => "..\/", - "webpacker" => "", - "shakapacker" => "", - "importmap" => "", - "esbuild" => ".\/" - }[bundler] - # standard:enable Style/RedundantStringEscape -end + def self.dev_package_list + @dev_package_list ||= Rails.root.join("tmp/stimulus_reflex_installer/npm_dev_package_list") + end -def application_record_path - @application_record_path ||= Rails.root.join("app/models/application_record.rb") -end + def self.drop_package_list + @drop_package_list ||= Rails.root.join("tmp/stimulus_reflex_installer/drop_npm_package_list") + end -def action_cable_initializer_path - @action_cable_initializer_path ||= Rails.root.join("config/initializers/action_cable.rb") -end + def self.template_src + @template_src ||= File.read("tmp/stimulus_reflex_installer/template_src") + end -def action_cable_initializer_working_path - @action_cable_initializer_working_path ||= Rails.root.join(working, "action_cable.rb") -end + def self.controllers_path + @controllers_path ||= Rails.root.join(entrypoint, "controllers") + end -def development_path - @development_path ||= Rails.root.join("config/environments/development.rb") -end + def self.gemfile_path + @gemfile_path ||= Rails.root.join("Gemfile") + end -def development_working_path - @development_working_path ||= Rails.root.join(working, "development.rb") -end + def self.gemfile + @gemfile ||= gemfile_path.read + end -def backups_path - @backups_path ||= Rails.root.join("tmp/stimulus_reflex_installer/backups") -end + def self.prefix + # standard:disable Style/RedundantStringEscape + @prefix ||= { + "vite" => "..\/", + "webpacker" => "", + "shakapacker" => "", + "importmap" => "", + "esbuild" => ".\/" + }[bundler] + # standard:enable Style/RedundantStringEscape + end -def add_gem_list - @add_gem_list ||= Rails.root.join("tmp/stimulus_reflex_installer/add_gem_list") -end + def self.application_record_path + @application_record_path ||= Rails.root.join("app/models/application_record.rb") + end -def remove_gem_list - @remove_gem_list ||= Rails.root.join("tmp/stimulus_reflex_installer/remove_gem_list") -end + def self.action_cable_initializer_path + @action_cable_initializer_path ||= Rails.root.join("config/initializers/action_cable.rb") + end -def options_path - @options_path ||= Rails.root.join("tmp/stimulus_reflex_installer/options") -end + def self.action_cable_initializer_working_path + @action_cable_initializer_working_path ||= Rails.root.join(working, "action_cable.rb") + end -def options - @options ||= YAML.safe_load(File.read(options_path)) -end + def self.development_path + @development_path ||= Rails.root.join("config/environments/development.rb") + end -def working - @working ||= Rails.root.join("tmp/stimulus_reflex_installer/working") -end + def self.development_working_path + @development_working_path ||= Rails.root.join(working, "development.rb") + end + + def self.backups_path + @backups_path ||= Rails.root.join("tmp/stimulus_reflex_installer/backups") + end -### support for development step - -def write_redis_recommendation(development_working, lines, index, gemfile) - # provide a recommendation for using redis-session-store, including commented source code - if !lines.index { |line| line.include?("StimulusReflex does not support :cookie_store") } - lines.insert index + 1, <(*a) { Rails.logger.error("Redis down! \#{a.inspect}") }, - # redis: { - # expire_after: 120.minutes, - # key_prefix: "session:", - # url: ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } - # } -RUBY - development_working.write lines.join - # add redis-session-store to Gemfile, but comment it out - if !gemfile.match?(/gem ['"]redis-session-store['"]/) - append_file(gemfile_path, verbose: false) do - <<~RUBY - - # StimulusReflex recommends using Redis for session storage - # gem "redis-session-store", "0.11.5" + def self.add_gem_list + @add_gem_list ||= Rails.root.join("tmp/stimulus_reflex_installer/add_gem_list") + end + + def self.remove_gem_list + @remove_gem_list ||= Rails.root.join("tmp/stimulus_reflex_installer/remove_gem_list") + end + + def self.options_path + @options_path ||= Rails.root.join("tmp/stimulus_reflex_installer/options") + end + + def self.options + @options ||= YAML.safe_load(File.read(options_path)) + end + + def self.working + @working ||= Rails.root.join("tmp/stimulus_reflex_installer/working") + end + + ### support for development step + + def self.write_redis_recommendation(development_working, lines, index, gemfile) + # provide a recommendation for using redis-session-store, including commented source code + if !lines.index { |line| line.include?("StimulusReflex does not support :cookie_store") } + lines.insert index + 1, <<~RUBY + # StimulusReflex does not support :cookie_store, and we recommend switching to Redis. + # To use `redis-session-store`, make sure to add it to your Gemfile and run `bundle install + # config.session_store :redis_session_store, + # serializer: :json, + # on_redis_down: ->(*a) { Rails.logger.error("Redis down! \#{a.inspect}") }, + # redis: { + # expire_after: 120.minutes, + # key_prefix: "session:", + # url: ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } + # } RUBY + + development_working.write lines.join + # add redis-session-store to Gemfile, but comment it out + if !gemfile.match?(/gem ['"]redis-session-store['"]/) + append_file(gemfile_path, verbose: false) do + <<~RUBY + + # StimulusReflex recommends using Redis for session storage + # gem "redis-session-store", "0.11.5" + RUBY + end + say "💡 Added redis-session-store 0.11.5 to the Gemfile, commented out" + end end - say "💡 Added redis-session-store 0.11.5 to the Gemfile, commented out" end - end -end -def find_index(lines) - # accomodate devs who modify their development.rb file structure - if (index = lines.index { |line| line =~ /caching-dev/ }) - index += 3 - else - index = lines.index { |line| line =~ /^Rails.application.configure do/ } + 1 + def self.find_index(lines) + # accomodate devs who modify their development.rb file structure + if (index = lines.index { |line| line =~ /caching-dev/ }) + index += 3 + else + index = lines.index { |line| line =~ /^Rails.application.configure do/ } + 1 + end + index + end end - index end diff --git a/lib/tasks/stimulus_reflex/stimulus_reflex.rake b/lib/tasks/stimulus_reflex/stimulus_reflex.rake index beaf9908..cce02fa4 100644 --- a/lib/tasks/stimulus_reflex/stimulus_reflex.rake +++ b/lib/tasks/stimulus_reflex/stimulus_reflex.rake @@ -53,8 +53,8 @@ end namespace :stimulus_reflex do desc "✨ Install StimulusReflex and CableReady ✨" task :install do - create_dir_if_not_exists(Rails.root.join("tmp/stimulus_reflex_installer/templates")) - create_dir_if_not_exists(Rails.root.join("tmp/stimulus_reflex_installer/working")) + StimulusReflex::Installer.create_dir_if_not_exists(Rails.root.join("tmp/stimulus_reflex_installer/templates")) + StimulusReflex::Installer.create_dir_if_not_exists(Rails.root.join("tmp/stimulus_reflex_installer/working")) install_complete = Rails.root.join("tmp/stimulus_reflex_installer/complete") @@ -93,8 +93,8 @@ namespace :stimulus_reflex do end # if there is an installation in progress, continue where we left off - if installer_entrypoint_path.exist? - entrypoint = installer_entrypoint_path.read + if StimulusReflex::Installer.installer_entrypoint_path.exist? + entrypoint = StimulusReflex::Installer.installer_entrypoint_path.read puts "✨ Resuming \e[38;5;220mStimulusReflex\e[0m and \e[38;5;220mCableReady\e[0m installation ✨" puts @@ -118,18 +118,18 @@ namespace :stimulus_reflex do entrypoint = if options.key? "entrypoint" options["entrypoint"] else - auto_detect_entrypoint + StimulusReflex::Installer.auto_detect_entrypoint end - installer_entrypoint_path.write(entrypoint) + StimulusReflex::Installer.installer_entrypoint_path.write(entrypoint) end # verify their bundler before starting, unless they explicitly specified on CLI if !used_bundler - used_bundler = bundler + used_bundler = StimulusReflex::Installer.bundler end - installer_bundler_path.write(used_bundler) + StimulusReflex::Installer.installer_bundler_path.write(used_bundler) FileUtils.touch("tmp/stimulus_reflex_installer/backups") File.write("tmp/stimulus_reflex_installer/template_src", File.expand_path("../../generators/stimulus_reflex/templates/", __dir__))