stimulus_reflex 3.5.0.rc3 → 3.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +144 -101
  3. data/README.md +2 -2
  4. data/app/assets/javascripts/stimulus_reflex.js +15 -13
  5. data/app/assets/javascripts/stimulus_reflex.umd.js +15 -12
  6. data/app/channels/stimulus_reflex/channel.rb +49 -53
  7. data/lib/generators/stimulus_reflex/stimulus_reflex_generator.rb +2 -2
  8. data/lib/generators/stimulus_reflex/templates/app/javascript/config/cable_ready.js.tt +1 -1
  9. data/lib/generators/stimulus_reflex/templates/app/javascript/config/index.js.tt +1 -1
  10. data/lib/generators/stimulus_reflex/templates/app/javascript/config/stimulus_reflex.js.tt +1 -1
  11. data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/%file_name%_controller.js.tt +1 -1
  12. data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/application.js.tt +1 -1
  13. data/lib/install/action_cable.rb +30 -30
  14. data/lib/install/broadcaster.rb +11 -11
  15. data/lib/install/bundle.rb +9 -9
  16. data/lib/install/compression.rb +5 -5
  17. data/lib/install/config.rb +22 -22
  18. data/lib/install/development.rb +19 -19
  19. data/lib/install/esbuild.rb +28 -28
  20. data/lib/install/example.rb +3 -3
  21. data/lib/install/importmap.rb +29 -29
  22. data/lib/install/initializers.rb +3 -3
  23. data/lib/install/mrujs.rb +25 -25
  24. data/lib/install/npm_packages.rb +7 -7
  25. data/lib/install/reflexes.rb +2 -2
  26. data/lib/install/shakapacker.rb +23 -23
  27. data/lib/install/spring.rb +7 -7
  28. data/lib/install/updatable.rb +7 -7
  29. data/lib/install/vite.rb +22 -22
  30. data/lib/install/webpacker.rb +27 -27
  31. data/lib/install/yarn.rb +9 -9
  32. data/lib/stimulus_reflex/html/document_fragment.rb +5 -3
  33. data/lib/stimulus_reflex/installer.rb +305 -277
  34. data/lib/stimulus_reflex/reflex.rb +14 -29
  35. data/lib/stimulus_reflex/reflex_data.rb +17 -17
  36. data/lib/stimulus_reflex/reflex_factory.rb +49 -26
  37. data/lib/stimulus_reflex/version.rb +1 -1
  38. data/lib/stimulus_reflex.rb +2 -0
  39. data/lib/tasks/stimulus_reflex/stimulus_reflex.rake +8 -8
  40. data/package.json +10 -10
  41. data/stimulus_reflex.gemspec +10 -8
  42. data/web-test-runner.config.mjs +14 -0
  43. data/yarn.lock +1278 -830
  44. metadata +34 -42
@@ -3,20 +3,6 @@
3
3
  require "stimulus_reflex/cable_readiness"
4
4
  require "stimulus_reflex/version_checker"
5
5
 
6
- # TODO remove xpath_controller and xpath_element for v4
7
- ClientAttributes = Struct.new(
8
- :id,
9
- :tab_id,
10
- :reflex_controller,
11
- :xpath_controller,
12
- :xpath_element,
13
- :permanent_attribute_name,
14
- :version,
15
- :npm_version,
16
- :suppress_logging,
17
- keyword_init: true
18
- )
19
-
20
6
  class StimulusReflex::Reflex
21
7
  prepend StimulusReflex::CableReadiness
22
8
  include StimulusReflex::VersionChecker
@@ -26,32 +12,27 @@ class StimulusReflex::Reflex
26
12
  include CableReady::Identifiable
27
13
 
28
14
  attr_accessor :payload, :headers
29
- attr_reader :channel, :url, :element, :selectors, :method_name, :broadcaster, :client_attributes, :logger
30
-
31
- alias_method :action_name, :method_name # for compatibility with controller libraries like Pundit that expect an action name
15
+ attr_reader :channel, :reflex_data, :broadcaster
32
16
 
33
17
  delegate :connection, :stream_name, to: :channel
34
18
  delegate :controller_class, :flash, :session, to: :request
35
19
  delegate :broadcast, :broadcast_halt, :broadcast_forbid, :broadcast_error, to: :broadcaster
20
+
36
21
  # TODO remove xpath_controller and xpath_element for v4
37
- delegate :id, :tab_id, :reflex_controller, :xpath_controller, :xpath_element, :permanent_attribute_name, :version, :npm_version, :suppress_logging, to: :client_attributes
22
+ delegate :url, :element, :selectors, :method_name, :id, :tab_id, :reflex_controller, :xpath_controller, :xpath_element, :permanent_attribute_name, :version, :npm_version, :suppress_logging, to: :reflex_data
23
+ # END TODO: remove
38
24
 
39
- def initialize(channel, url: nil, element: nil, selectors: [], method_name: nil, params: {}, client_attributes: {})
25
+ alias_method :action_name, :method_name # for compatibility with controller libraries like Pundit that expect an action name
26
+ alias_method :data, :reflex_data
27
+
28
+ def initialize(channel, reflex_data:)
40
29
  @channel = channel
41
- @url = url
42
- @element = element
43
- @selectors = selectors
44
- @method_name = method_name
45
- @params = params
46
- @client_attributes = ClientAttributes.new(client_attributes)
30
+ @reflex_data = reflex_data
47
31
  @broadcaster = StimulusReflex::PageBroadcaster.new(self)
48
- @logger = suppress_logging ? nil : StimulusReflex::Logger.new(self)
49
32
  @payload = {}
50
33
  @headers = {}
51
34
 
52
35
  check_version!
53
-
54
- self.params
55
36
  end
56
37
 
57
38
  # TODO: remove this for v4
@@ -61,6 +42,10 @@ class StimulusReflex::Reflex
61
42
  end
62
43
  # END TODO: remove
63
44
 
45
+ def logger
46
+ @logger ||= StimulusReflex::Logger.new(self) unless suppress_logging
47
+ end
48
+
64
49
  def request
65
50
  @request ||= begin
66
51
  uri = URI.parse(url)
@@ -91,7 +76,7 @@ class StimulusReflex::Reflex
91
76
  req = ActionDispatch::Request.new(env)
92
77
 
93
78
  # fetch path params (controller, action, ...) and apply them
94
- request_params = StimulusReflex::RequestParameters.new(params: @params, req: req, url: url)
79
+ request_params = StimulusReflex::RequestParameters.new(params: reflex_data.params, req: req, url: url)
95
80
  req = request_params.apply!
96
81
 
97
82
  req
@@ -4,7 +4,7 @@ class StimulusReflex::ReflexData
4
4
  attr_reader :data
5
5
 
6
6
  def initialize(data)
7
- @data = data
7
+ @data = data.deep_merge(data.deep_transform_keys { |k| k.to_s.underscore }).with_indifferent_access
8
8
  end
9
9
 
10
10
  def reflex_name
@@ -14,13 +14,13 @@ class StimulusReflex::ReflexData
14
14
  end
15
15
 
16
16
  def selectors
17
- selectors = (data["selectors"] || []).select(&:present?)
18
- selectors = data["selectors"] = ["body"] if selectors.blank?
17
+ selectors = (data[:selectors] || []).select(&:present?)
18
+ selectors = data[:selectors] = ["body"] if selectors.blank?
19
19
  selectors
20
20
  end
21
21
 
22
22
  def target
23
- data["target"].to_s
23
+ data[:target].to_s
24
24
  end
25
25
 
26
26
  def method_name
@@ -28,11 +28,11 @@ class StimulusReflex::ReflexData
28
28
  end
29
29
 
30
30
  def arguments
31
- (data["args"] || []).map { |arg| object_with_indifferent_access arg } || []
31
+ (data[:args] || []).map { |arg| object_with_indifferent_access arg } || []
32
32
  end
33
33
 
34
34
  def url
35
- data["url"].to_s
35
+ data[:url].to_s
36
36
  end
37
37
 
38
38
  def element
@@ -40,15 +40,15 @@ class StimulusReflex::ReflexData
40
40
  end
41
41
 
42
42
  def permanent_attribute_name
43
- data["permanentAttributeName"]
43
+ data[:permanent_attribute_name]
44
44
  end
45
45
 
46
46
  def suppress_logging
47
- data["suppressLogging"]
47
+ data[:suppress_logging]
48
48
  end
49
49
 
50
50
  def form_data
51
- Rack::Utils.parse_nested_query(data["formData"])
51
+ Rack::Utils.parse_nested_query(data[:form_data])
52
52
  end
53
53
 
54
54
  def params
@@ -56,7 +56,7 @@ class StimulusReflex::ReflexData
56
56
  end
57
57
 
58
58
  def form_params
59
- form_data.deep_merge(data["params"] || {})
59
+ form_data.deep_merge(data[:params] || {})
60
60
  end
61
61
 
62
62
  def url_params
@@ -64,33 +64,33 @@ class StimulusReflex::ReflexData
64
64
  end
65
65
 
66
66
  def id
67
- data["id"]
67
+ data[:id]
68
68
  end
69
69
 
70
70
  def tab_id
71
- data["tabId"]
71
+ data[:tab_id]
72
72
  end
73
73
 
74
74
  # TODO: remove this in v4
75
75
  def xpath_controller
76
- data["xpathController"]
76
+ data[:xpath_controller]
77
77
  end
78
78
 
79
79
  def xpath_element
80
- data["xpathElement"]
80
+ data[:xpath_element]
81
81
  end
82
82
  # END TODO remove
83
83
 
84
84
  def reflex_controller
85
- data["reflexController"]
85
+ data[:reflex_controller]
86
86
  end
87
87
 
88
88
  def npm_version
89
- data["version"].to_s
89
+ data[:version].to_s
90
90
  end
91
91
 
92
92
  def version
93
- data["version"].to_s.gsub("-pre", ".pre").gsub("-rc", ".rc")
93
+ npm_version.gsub("-pre", ".pre").gsub("-rc", ".rc")
94
94
  end
95
95
 
96
96
  private
@@ -1,36 +1,59 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class StimulusReflex::ReflexFactory
4
- class << self
5
- attr_reader :reflex_data
6
-
7
- def create_reflex_from_data(channel, reflex_data)
8
- @reflex_data = reflex_data
9
- reflex_class.new(channel,
10
- url: reflex_data.url,
11
- element: reflex_data.element,
12
- selectors: reflex_data.selectors,
13
- method_name: reflex_data.method_name,
14
- params: reflex_data.params,
15
- client_attributes: {
16
- id: reflex_data.id,
17
- tab_id: reflex_data.tab_id,
18
- xpath_controller: reflex_data.xpath_controller,
19
- xpath_element: reflex_data.xpath_element,
20
- reflex_controller: reflex_data.reflex_controller,
21
- permanent_attribute_name: reflex_data.permanent_attribute_name,
22
- suppress_logging: reflex_data.suppress_logging,
23
- version: reflex_data.version,
24
- npm_version: reflex_data.npm_version
25
- })
4
+ attr_reader :channel, :data
5
+
6
+ delegate :reflex_name, :method_name, to: :data
7
+
8
+ def initialize(channel, data)
9
+ @channel = channel
10
+ @data = StimulusReflex::ReflexData.new(data)
11
+ end
12
+
13
+ def call
14
+ verify_method_name!
15
+ reflex_class.new(channel, reflex_data: data)
16
+ end
17
+
18
+ private
19
+
20
+ def verify_method_name!
21
+ return if default_reflex?
22
+
23
+ argument_error = ArgumentError.new("Reflex method '#{method_name}' is not defined on class '#{reflex_name}' or on any of its ancestors")
24
+
25
+ if reflex_method.nil?
26
+ raise argument_error
26
27
  end
27
28
 
28
- def reflex_class
29
- reflex_data.reflex_name.constantize.tap { |klass| raise ArgumentError.new("#{reflex_name} is not a StimulusReflex::Reflex") unless is_reflex?(klass) }
29
+ if !safe_ancestors.include?(reflex_method.owner)
30
+ raise argument_error
30
31
  end
32
+ end
31
33
 
32
- def is_reflex?(klass)
33
- klass.ancestors.include? StimulusReflex::Reflex
34
+ def reflex_class
35
+ @reflex_class ||= reflex_name.constantize.tap do |klass|
36
+ unless klass.ancestors.include?(StimulusReflex::Reflex)
37
+ raise ArgumentError.new("#{reflex_name} is not a StimulusReflex::Reflex")
38
+ end
34
39
  end
35
40
  end
41
+
42
+ def reflex_method
43
+ if reflex_class.public_instance_methods.include?(method_name.to_sym)
44
+ reflex_class.public_instance_method(method_name)
45
+ end
46
+ end
47
+
48
+ def default_reflex?
49
+ method_name == "default_reflex" && reflex_method.owner == ::StimulusReflex::Reflex
50
+ end
51
+
52
+ def safe_ancestors
53
+ # We want to include every class and module up to the `StimulusReflex::Reflex` class,
54
+ # but not the StimulusReflex::Reflex itself
55
+ reflex_class_index = reflex_class.ancestors.index(StimulusReflex::Reflex) - 1
56
+
57
+ reflex_class.ancestors.to(reflex_class_index)
58
+ end
36
59
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StimulusReflex
4
- VERSION = "3.5.0.rc3"
4
+ VERSION = "3.5.3"
5
5
  end
@@ -3,11 +3,13 @@
3
3
  require "uri"
4
4
  require "open-uri"
5
5
  require "rack"
6
+ require "ostruct"
6
7
  require "active_support/all"
7
8
  require "action_dispatch"
8
9
  require "action_cable"
9
10
  require "action_view"
10
11
  require "nokogiri"
12
+ require "nokogiri/html5/inference"
11
13
  require "cable_ready"
12
14
  require "stimulus_reflex/version"
13
15
  require "stimulus_reflex/open_struct_fix"
@@ -53,8 +53,8 @@ end
53
53
  namespace :stimulus_reflex do
54
54
  desc "✨ Install StimulusReflex and CableReady ✨"
55
55
  task :install do
56
- create_dir_if_not_exists(Rails.root.join("tmp/stimulus_reflex_installer/templates"))
57
- create_dir_if_not_exists(Rails.root.join("tmp/stimulus_reflex_installer/working"))
56
+ StimulusReflex::Installer.create_dir_if_not_exists(Rails.root.join("tmp/stimulus_reflex_installer/templates"))
57
+ StimulusReflex::Installer.create_dir_if_not_exists(Rails.root.join("tmp/stimulus_reflex_installer/working"))
58
58
 
59
59
  install_complete = Rails.root.join("tmp/stimulus_reflex_installer/complete")
60
60
 
@@ -93,8 +93,8 @@ namespace :stimulus_reflex do
93
93
  end
94
94
 
95
95
  # if there is an installation in progress, continue where we left off
96
- if installer_entrypoint_path.exist?
97
- entrypoint = installer_entrypoint_path.read
96
+ if StimulusReflex::Installer.installer_entrypoint_path.exist?
97
+ entrypoint = StimulusReflex::Installer.installer_entrypoint_path.read
98
98
 
99
99
  puts "✨ Resuming \e[38;5;220mStimulusReflex\e[0m and \e[38;5;220mCableReady\e[0m installation ✨"
100
100
  puts
@@ -118,18 +118,18 @@ namespace :stimulus_reflex do
118
118
  entrypoint = if options.key? "entrypoint"
119
119
  options["entrypoint"]
120
120
  else
121
- auto_detect_entrypoint
121
+ StimulusReflex::Installer.auto_detect_entrypoint
122
122
  end
123
123
 
124
- installer_entrypoint_path.write(entrypoint)
124
+ StimulusReflex::Installer.installer_entrypoint_path.write(entrypoint)
125
125
  end
126
126
 
127
127
  # verify their bundler before starting, unless they explicitly specified on CLI
128
128
  if !used_bundler
129
- used_bundler = bundler
129
+ used_bundler = StimulusReflex::Installer.bundler
130
130
  end
131
131
 
132
- installer_bundler_path.write(used_bundler)
132
+ StimulusReflex::Installer.installer_bundler_path.write(used_bundler)
133
133
 
134
134
  FileUtils.touch("tmp/stimulus_reflex_installer/backups")
135
135
  File.write("tmp/stimulus_reflex_installer/template_src", File.expand_path("../../generators/stimulus_reflex/templates/", __dir__))
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stimulus_reflex",
3
- "version": "3.5.0-rc3",
3
+ "version": "3.5.3",
4
4
  "description": "Build reactive applications with the Rails tooling you already know and love.",
5
5
  "keywords": [
6
6
  "ruby",
@@ -57,18 +57,18 @@
57
57
  "dependencies": {
58
58
  "@hotwired/stimulus": "^3",
59
59
  "@rails/actioncable": "^6 || ^7",
60
- "cable_ready": "^5.0.0"
60
+ "cable_ready": "^5.0.6"
61
61
  },
62
62
  "devDependencies": {
63
- "@open-wc/testing": "^3.1.7",
64
- "@rollup/plugin-json": "^6.0.0",
65
- "@rollup/plugin-node-resolve": "^15.0.1",
66
- "@rollup/plugin-terser": "^0.4.0",
67
- "@web/dev-server-esbuild": "^0.3.3",
68
- "@web/dev-server-rollup": "^0.3.21",
69
- "@web/test-runner": "^0.15.1",
63
+ "@open-wc/testing": "^4.0.0",
64
+ "@rollup/plugin-json": "^6.1.0",
65
+ "@rollup/plugin-node-resolve": "^15.3.0",
66
+ "@rollup/plugin-terser": "^0.4.4",
67
+ "@web/dev-server-esbuild": "^1.0.2",
68
+ "@web/dev-server-rollup": "^0.6.4",
69
+ "@web/test-runner": "^0.19.0",
70
70
  "prettier-standard": "^16.4.1",
71
- "rollup": "^3.19.1",
71
+ "rollup": "^4.22.4",
72
72
  "toastify-js": "^1.12.0",
73
73
  "vitepress": "^1.0.0-beta.1"
74
74
  }
@@ -37,24 +37,26 @@ Gem::Specification.new do |gem|
37
37
  "[A-Z]*"
38
38
  ]
39
39
 
40
- gem.required_ruby_version = ">= 2.7.0"
40
+ gem.required_ruby_version = ">= 3.0.0"
41
41
 
42
- rails_version = [">= 5.2", "< 8"]
43
- gem.add_dependency "actioncable", *rails_version
44
- gem.add_dependency "actionpack", *rails_version
45
- gem.add_dependency "actionview", *rails_version
46
- gem.add_dependency "activesupport", *rails_version
47
- gem.add_dependency "railties", *rails_version
42
+ rails_version = ">= 5.2"
43
+ gem.add_dependency "actioncable", rails_version
44
+ gem.add_dependency "actionpack", rails_version
45
+ gem.add_dependency "actionview", rails_version
46
+ gem.add_dependency "activesupport", rails_version
47
+ gem.add_dependency "railties", rails_version
48
48
 
49
49
  gem.add_dependency "cable_ready", "~> 5.0"
50
50
  gem.add_dependency "nokogiri", "~> 1.0"
51
51
  gem.add_dependency "rack", ">= 2", "< 4"
52
52
  gem.add_dependency "redis", ">= 4.0", "< 6.0"
53
+ gem.add_dependency "nokogiri-html5-inference", "~> 0.3"
53
54
 
54
55
  gem.add_development_dependency "bundler", "~> 2.0"
55
56
  gem.add_development_dependency "magic_frozen_string_literal", "~> 1.2"
56
57
  gem.add_development_dependency "mocha", "~> 1.13"
57
- gem.add_development_dependency "rails", *rails_version
58
+ gem.add_development_dependency "rails", rails_version
58
59
  gem.add_development_dependency "rake", "~> 13.0"
59
60
  gem.add_development_dependency "standard", "~> 1.24"
61
+ gem.add_development_dependency "minitest", "5.18.1"
60
62
  end
@@ -3,8 +3,22 @@ import { fromRollup } from '@web/dev-server-rollup'
3
3
 
4
4
  const json = fromRollup(rollupJson)
5
5
 
6
+ const filteredLogs = [
7
+ 'Lit is in dev mode. Not recommended for production! See https://lit.dev/msg/dev-mode for more information.'
8
+ ]
9
+
10
+ const filterBrowserLogs = (log) => {
11
+ for (const arg of log.args) {
12
+ if (typeof arg === 'string' && filteredLogs.some(l => arg.includes(l))) {
13
+ return false
14
+ }
15
+ }
16
+ return true
17
+ }
18
+
6
19
  export default {
7
20
  nodeResolve: true,
21
+ filterBrowserLogs,
8
22
  mimeTypes: {
9
23
  '**/*.json': 'js'
10
24
  },