react-rails 2.4.7 → 2.7.1

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +99 -10
  3. data/LICENSE +0 -0
  4. data/README.md +304 -41
  5. data/lib/assets/javascripts/JSXTransformer.js +0 -0
  6. data/lib/assets/javascripts/react_ujs.js +1 -507
  7. data/lib/assets/react-source/development/react-server.js +166 -6795
  8. data/lib/assets/react-source/development/react.js +184 -21874
  9. data/lib/assets/react-source/production/react-server.js +2 -22
  10. data/lib/assets/react-source/production/react.js +2 -24
  11. data/lib/generators/react/component_generator.rb +91 -15
  12. data/lib/generators/react/install_generator.rb +22 -4
  13. data/lib/generators/templates/component.es6.jsx +0 -0
  14. data/lib/generators/templates/component.js.jsx +0 -0
  15. data/lib/generators/templates/component.js.jsx.coffee +0 -0
  16. data/lib/generators/templates/component.js.jsx.tsx +36 -0
  17. data/lib/generators/templates/react_server_rendering.rb +0 -0
  18. data/lib/generators/templates/server_rendering.js +0 -0
  19. data/lib/generators/templates/server_rendering_pack.js +3 -3
  20. data/lib/react/jsx/babel_transformer.rb +0 -0
  21. data/lib/react/jsx/jsx_transformer.rb +0 -0
  22. data/lib/react/jsx/processor.rb +0 -0
  23. data/lib/react/jsx/sprockets_strategy.rb +1 -1
  24. data/lib/react/jsx/template.rb +0 -0
  25. data/lib/react/jsx.rb +0 -0
  26. data/lib/react/rails/asset_variant.rb +0 -0
  27. data/lib/react/rails/component_mount.rb +7 -0
  28. data/lib/react/rails/controller_lifecycle.rb +0 -0
  29. data/lib/react/rails/controller_renderer.rb +0 -0
  30. data/lib/react/rails/railtie.rb +1 -0
  31. data/lib/react/rails/test_helper.rb +23 -0
  32. data/lib/react/rails/version.rb +1 -1
  33. data/lib/react/rails/view_helper.rb +0 -0
  34. data/lib/react/rails.rb +0 -0
  35. data/lib/react/server_rendering/bundle_renderer/console_polyfill.js +0 -0
  36. data/lib/react/server_rendering/bundle_renderer/console_replay.js +0 -0
  37. data/lib/react/server_rendering/bundle_renderer/console_reset.js +0 -0
  38. data/lib/react/server_rendering/bundle_renderer/timeout_polyfill.js +0 -0
  39. data/lib/react/server_rendering/bundle_renderer.rb +0 -0
  40. data/lib/react/server_rendering/environment_container.rb +0 -0
  41. data/lib/react/server_rendering/exec_js_renderer.rb +0 -0
  42. data/lib/react/server_rendering/manifest_container.rb +0 -0
  43. data/lib/react/server_rendering/webpacker_manifest_container.rb +4 -4
  44. data/lib/react/server_rendering/yaml_manifest_container.rb +0 -0
  45. data/lib/react/server_rendering.rb +0 -0
  46. data/lib/react-rails.rb +6 -0
  47. data/lib/react.rb +6 -4
  48. metadata +55 -12
@@ -55,6 +55,11 @@ module React
55
55
  default: false,
56
56
  desc: 'Output es6 class based component'
57
57
 
58
+ class_option :ts,
59
+ type: :boolean,
60
+ default: false,
61
+ desc: 'Output tsx class based component'
62
+
58
63
  class_option :coffee,
59
64
  type: :boolean,
60
65
  default: false,
@@ -89,9 +94,38 @@ module React
89
94
  }
90
95
  }
91
96
 
97
+ TYPESCRIPT_TYPES = {
98
+ 'node' => 'React.ReactNode',
99
+ 'bool' => 'boolean',
100
+ 'boolean' => 'boolean',
101
+ 'string' => 'string',
102
+ 'number' => 'number',
103
+ 'object' => 'object',
104
+ 'array' => 'Array<any>',
105
+ 'shape' => 'object',
106
+ 'element' => 'object',
107
+ 'func' => 'object',
108
+ 'function' => 'object',
109
+ 'any' => 'any',
110
+
111
+ 'instanceOf' => ->(type) {
112
+ type.to_s.camelize
113
+ },
114
+
115
+ 'oneOf' => ->(*opts) {
116
+ opts.map{ |k| "'#{k.to_s}'" }.join(" | ")
117
+ },
118
+
119
+ 'oneOfType' => ->(*opts) {
120
+ opts.map{ |k| "#{ts_lookup(k.to_s, k.to_s)}" }.join(" | ")
121
+ }
122
+ }
123
+
92
124
  def create_component_file
93
125
  template_extension = if options[:coffee]
94
126
  'js.jsx.coffee'
127
+ elsif options[:ts]
128
+ 'js.jsx.tsx'
95
129
  elsif options[:es6] || webpacker?
96
130
  'es6.jsx'
97
131
  else
@@ -101,7 +135,13 @@ module React
101
135
  # Prefer webpacker to sprockets:
102
136
  if webpacker?
103
137
  new_file_name = file_name.camelize
104
- extension = options[:coffee] ? 'coffee' : 'js'
138
+ extension = if options[:coffee]
139
+ 'coffee'
140
+ elsif options[:ts]
141
+ 'tsx'
142
+ else
143
+ 'js'
144
+ end
105
145
  target_dir = webpack_configuration.source_path
106
146
  .join('components')
107
147
  .relative_path_from(::Rails.root)
@@ -128,6 +168,7 @@ module React
128
168
 
129
169
  def file_header
130
170
  if webpacker?
171
+ return %|import * as React from "react"\n| if options[:ts]
131
172
  %|import React from "react"\nimport PropTypes from "prop-types"\n|
132
173
  else
133
174
  ''
@@ -146,23 +187,58 @@ module React
146
187
  defined?(Webpacker)
147
188
  end
148
189
 
149
- def parse_attributes!
150
- self.attributes = (attributes || []).map do |attr|
151
- name = ''
152
- type = ''
153
- options = ''
154
- options_regex = /(?<options>{.*})/
190
+ def parse_attributes!
191
+ self.attributes = (attributes || []).map do |attr|
192
+ name = ''
193
+ type = ''
194
+ args = ''
195
+ args_regex = /(?<args>{.*})/
196
+
197
+ name, type = attr.split(':')
198
+
199
+ if matchdata = args_regex.match(type)
200
+ args = matchdata[:args]
201
+ type = type.gsub(args_regex, '')
202
+ end
203
+
204
+ if options[:ts]
205
+ { :name => name, :type => ts_lookup(name, type, args), :union => union?(args) }
206
+ else
207
+ { :name => name, :type => lookup(type, args) }
208
+ end
209
+ end
210
+ end
211
+
212
+ def union?(args = '')
213
+ return args.to_s.gsub(/[{}]/, '').split(',').count > 1
214
+ end
155
215
 
156
- name, type = attr.split(':')
216
+ def self.ts_lookup(name, type = 'node', args = '')
217
+ ts_type = TYPESCRIPT_TYPES[type]
218
+ if ts_type.blank?
219
+ if type =~ /^[[:upper:]]/
220
+ ts_type = TYPESCRIPT_TYPES['instanceOf']
221
+ else
222
+ ts_type = TYPESCRIPT_TYPES['node']
223
+ end
224
+ end
157
225
 
158
- if matchdata = options_regex.match(type)
159
- options = matchdata[:options]
160
- type = type.gsub(options_regex, '')
161
- end
226
+ args = args.to_s.gsub(/[{}]/, '').split(',')
162
227
 
163
- { :name => name, :type => lookup(type, options) }
164
- end
165
- end
228
+ if ts_type.respond_to? :call
229
+ if args.blank?
230
+ return ts_type.call(type)
231
+ end
232
+
233
+ ts_type = ts_type.call(*args)
234
+ end
235
+
236
+ ts_type
237
+ end
238
+
239
+ def ts_lookup(name, type = 'node', args = '')
240
+ self.class.ts_lookup(name, type, args)
241
+ end
166
242
 
167
243
  def self.lookup(type = 'node', options = '')
168
244
  react_prop_type = REACT_PROP_TYPES[type]
@@ -16,6 +16,19 @@ module React
16
16
  default: false,
17
17
  desc: "Don't generate server_rendering.js or config/initializers/react_server_rendering.rb"
18
18
 
19
+ # For Shakapacker below version 7, we need to set relative path for source_entry_path
20
+ def modify_webpacker_yml
21
+ webpacker_yml_path = 'config/webpacker.yml'
22
+ if webpacker? && Pathname.new(webpacker_yml_path).exist?
23
+ gsub_file(
24
+ webpacker_yml_path,
25
+ "source_entry_path: /\n",
26
+ "source_entry_path: packs\n"
27
+ )
28
+ reloaded_webpacker_config
29
+ end
30
+ end
31
+
19
32
  # Make an empty `components/` directory in the right place:
20
33
  def create_directory
21
34
  components_dir = if webpacker?
@@ -25,7 +38,7 @@ module React
25
38
  end
26
39
  empty_directory File.join(components_dir, 'components')
27
40
  unless options[:skip_git]
28
- create_file File.join(components_dir, 'components/.gitkeep')
41
+ create_file File.join(components_dir, 'components/.keep')
29
42
  end
30
43
  end
31
44
 
@@ -96,9 +109,9 @@ module React
96
109
 
97
110
  WEBPACKER_SETUP_UJS = <<-JS
98
111
  // Support component names relative to this directory:
99
- var componentRequireContext = require.context("components", true)
100
- var ReactRailsUJS = require("react_ujs")
101
- ReactRailsUJS.useContext(componentRequireContext)
112
+ var componentRequireContext = require.context("components", true);
113
+ var ReactRailsUJS = require("react_ujs");
114
+ ReactRailsUJS.useContext(componentRequireContext);
102
115
  JS
103
116
 
104
117
  def setup_react_webpacker
@@ -119,6 +132,11 @@ JS
119
132
  Webpacker::Configuration.source_path.join(Webpacker::Configuration.entry_path) # Webpacker <3
120
133
  end
121
134
  end
135
+
136
+ def reloaded_webpacker_config
137
+ Webpacker.instance.instance_variable_set(:@config, nil)
138
+ Webpacker.config
139
+ end
122
140
  end
123
141
  end
124
142
  end
File without changes
File without changes
File without changes
@@ -0,0 +1,36 @@
1
+ <%= file_header %>
2
+ <% unions = attributes.select{ |a| a[:union] } -%>
3
+ <% if unions.size > 0 -%>
4
+ <% unions.each do |e| -%>
5
+ type <%= e[:name].titleize %> = <%= e[:type]%>
6
+ <% end -%>
7
+ <% end -%>
8
+
9
+ interface I<%= component_name %>Props {
10
+ <% if attributes.size > 0 -%>
11
+ <% attributes.each do | attribute | -%>
12
+ <% if attribute[:union] -%>
13
+ <%= attribute[:name].camelize(:lower) %>: <%= attribute[:name].titleize %>;
14
+ <% else -%>
15
+ <%= attribute[:name].camelize(:lower) %>: <%= attribute[:type] %>;
16
+ <% end -%>
17
+ <% end -%>
18
+ <% end -%>
19
+ }
20
+
21
+ interface I<%= component_name %>State {
22
+ }
23
+
24
+ class <%= component_name %> extends React.Component <I<%= component_name %>Props, I<%= component_name %>State> {
25
+ render() {
26
+ return (
27
+ <React.Fragment>
28
+ <% attributes.each do |attribute| -%>
29
+ <%= attribute[:name].titleize %>: {this.props.<%= attribute[:name].camelize(:lower) %>}
30
+ <% end -%>
31
+ </React.Fragment>
32
+ );
33
+ }
34
+ }
35
+
36
+ <%= file_footer %>
File without changes
File without changes
@@ -1,5 +1,5 @@
1
1
  // By default, this pack is loaded for server-side rendering.
2
2
  // It must expose react_ujs as `ReactRailsUJS` and prepare a require context.
3
- var componentRequireContext = require.context("components", true)
4
- var ReactRailsUJS = require("react_ujs")
5
- ReactRailsUJS.useContext(componentRequireContext)
3
+ var componentRequireContext = require.context("components", true);
4
+ var ReactRailsUJS = require("react_ujs");
5
+ ReactRailsUJS.useContext(componentRequireContext);
File without changes
File without changes
File without changes
@@ -23,7 +23,7 @@ module React
23
23
  # @return [Symbol] based on the environment, return a method name to call with the sprockets environment
24
24
  def detect_strategy
25
25
  sprockets_version = Gem::Version.new(Sprockets::VERSION)
26
- if sprockets_version >= Gem::Version.new('4.x')
26
+ if sprockets_version >= Gem::Version.new('4.a')
27
27
  :register_processors
28
28
  elsif sprockets_version >= Gem::Version.new('3.0.0')
29
29
  :register_engine_with_mime_type
File without changes
data/lib/react/jsx.rb CHANGED
File without changes
File without changes
@@ -11,6 +11,10 @@ module React
11
11
  attr_accessor :output_buffer
12
12
  mattr_accessor :camelize_props_switch
13
13
 
14
+ def initialize
15
+ @cache_ids = []
16
+ end
17
+
14
18
  # {ControllerLifecycle} calls these hooks
15
19
  # You can use them in custom helper implementations
16
20
  def setup(controller)
@@ -40,6 +44,9 @@ module React
40
44
  data[:react_class] = name
41
45
  data[:react_props] = (props.is_a?(String) ? props : props.to_json)
42
46
  data[:hydrate] = 't' if prerender_options
47
+
48
+ num_components = @cache_ids.count { |c| c.start_with? name }
49
+ data[:react_cache_id] = "#{name}-#{num_components}"
43
50
  end
44
51
  end
45
52
  html_tag = html_options[:tag] || :div
File without changes
File without changes
@@ -58,6 +58,7 @@ module React
58
58
 
59
59
  ActiveSupport.on_load(:action_view) do
60
60
  include ::React::Rails::ViewHelper
61
+ ActionDispatch::IntegrationTest.send(:include, React::Rails::TestHelper) if ::Rails.env.test?
61
62
  end
62
63
  end
63
64
 
@@ -0,0 +1,23 @@
1
+ module React
2
+ module Rails
3
+ module TestHelper
4
+ extend ActiveSupport::Concern
5
+
6
+ # assert react_component render
7
+ #
8
+ # assert_react_component("HelloWorld") do |props|
9
+ # assert_equal "Hello world", props[:message]
10
+ # end
11
+ def assert_react_component(name)
12
+ assert_select "div[data-react-class=?]", name do |dom|
13
+ if block_given?
14
+ props = JSON.parse(dom.attr("data-react-props"))
15
+ props.deep_symbolize_keys!
16
+
17
+ yield(props)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -2,6 +2,6 @@ module React
2
2
  module Rails
3
3
  # If you change this, make sure to update VERSIONS.md
4
4
  # and republish the UJS by updating package.json and `bundle exec rake ujs:publish`
5
- VERSION = '2.4.7'
5
+ VERSION = '2.7.1'
6
6
  end
7
7
  end
File without changes
data/lib/react/rails.rb CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -9,7 +9,7 @@ module React
9
9
  class WebpackerManifestContainer
10
10
 
11
11
  begin
12
- MAJOR, MINOR, PATCH, _ = Bundler.locked_gems.specs.find { |gem_spec| gem_spec.name == 'webpacker' }.version.segments
12
+ MAJOR, MINOR, PATCH, _ = Bundler.locked_gems.specs.find { |gem_spec| gem_spec.name == 'webpacker' || gem_spec.name == 'shakapacker' }.version.segments
13
13
  rescue
14
14
  MAJOR, MINOR, PATCH, _ = [0,0,0]
15
15
  end
@@ -27,7 +27,7 @@ module React
27
27
  asset_path = manifest.lookup(logical_path).to_s
28
28
  if asset_path.start_with?('http')
29
29
  # Get a file from the webpack-dev-server
30
- dev_server_asset = open(asset_path).read
30
+ dev_server_asset = URI.open(asset_path).read
31
31
  # Remove `webpack-dev-server/client/index.js` code which causes ExecJS to 💥
32
32
  dev_server_asset.sub!(CLIENT_REQUIRE, '//\0')
33
33
  dev_server_asset
@@ -44,7 +44,7 @@ module React
44
44
  ds = Webpacker.dev_server
45
45
  # Remove the protocol and host from the asset path. Sometimes webpacker includes this, sometimes it does not
46
46
  asset_path.slice!("#{ds.protocol}://#{ds.host_with_port}")
47
- dev_server_asset = open("#{ds.protocol}://#{ds.host_with_port}#{asset_path}").read
47
+ dev_server_asset = URI.open("#{ds.protocol}://#{ds.host_with_port}#{asset_path}").read
48
48
  dev_server_asset.sub!(CLIENT_REQUIRE, '//\0')
49
49
  dev_server_asset
50
50
  else
@@ -79,7 +79,7 @@ module React
79
79
  end
80
80
  elsif MAJOR >= 3
81
81
  def file_path path
82
- ::Rails.root.join('public', manifest.lookup(path)[1..-1])
82
+ ::Rails.root.join('public', manifest.lookup!(path)[1..-1])
83
83
  end
84
84
  else # 1.0 and 1.1 support
85
85
  def file_path path
File without changes
data/lib/react-rails.rb CHANGED
@@ -2,3 +2,9 @@ require 'react'
2
2
  require 'react/jsx'
3
3
  require 'react/rails'
4
4
  require 'react/server_rendering'
5
+
6
+ module React
7
+ module Rails
8
+ autoload :TestHelper, 'react/rails/test_helper'
9
+ end
10
+ end
data/lib/react.rb CHANGED
@@ -3,17 +3,19 @@ module React
3
3
  # @param props [Object] If it's a Hash or Array, it will be recursed. Otherwise it will be returned.
4
4
  # @return [Hash] a new hash whose keys are camelized strings
5
5
  def self.camelize_props(props)
6
- case props
6
+ props_as_json = props.as_json
7
+
8
+ case props_as_json
7
9
  when Hash
8
- props.each_with_object({}) do |(key, value), new_props|
10
+ props_as_json.each_with_object({}) do |(key, value), new_props|
9
11
  new_key = key.to_s.camelize(:lower)
10
12
  new_value = camelize_props(value)
11
13
  new_props[new_key] = new_value
12
14
  end
13
15
  when Array
14
- props.map { |item| camelize_props(item) }
16
+ props_as_json.map { |item| camelize_props(item) }
15
17
  else
16
- props
18
+ props_as_json
17
19
  end
18
20
  end
19
21
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.7
4
+ version: 2.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul O’Shannessy
8
8
  - Robert Mosolgo
9
9
  - Gregory Myers
10
10
  - Tsukuru Tanimichi
11
- autorequire:
11
+ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2018-08-03 00:00:00.000000000 Z
14
+ date: 2023-05-19 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: appraisal
@@ -31,16 +31,16 @@ dependencies:
31
31
  name: bundler
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
- - - ">="
34
+ - - '='
35
35
  - !ruby/object:Gem::Version
36
- version: 1.2.2
36
+ version: 2.4.9
37
37
  type: :development
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
- - - ">="
41
+ - - '='
42
42
  - !ruby/object:Gem::Version
43
- version: 1.2.2
43
+ version: 2.4.9
44
44
  - !ruby/object:Gem::Dependency
45
45
  name: codeclimate-test-reporter
46
46
  requirement: !ruby/object:Gem::Requirement
@@ -83,6 +83,20 @@ dependencies:
83
83
  - - ">="
84
84
  - !ruby/object:Gem::Version
85
85
  version: 2.0.5
86
+ - !ruby/object:Gem::Dependency
87
+ name: gem-release
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
86
100
  - !ruby/object:Gem::Dependency
87
101
  name: guard
88
102
  requirement: !ruby/object:Gem::Requirement
@@ -140,7 +154,7 @@ dependencies:
140
154
  - !ruby/object:Gem::Version
141
155
  version: 3.0.0
142
156
  - !ruby/object:Gem::Dependency
143
- name: chromedriver-helper
157
+ name: webdrivers
144
158
  requirement: !ruby/object:Gem::Requirement
145
159
  requirements:
146
160
  - - ">="
@@ -209,6 +223,34 @@ dependencies:
209
223
  - - ">="
210
224
  - !ruby/object:Gem::Version
211
225
  version: '3.2'
226
+ - !ruby/object:Gem::Dependency
227
+ name: pry-byebug
228
+ requirement: !ruby/object:Gem::Requirement
229
+ requirements:
230
+ - - ">="
231
+ - !ruby/object:Gem::Version
232
+ version: '0'
233
+ type: :development
234
+ prerelease: false
235
+ version_requirements: !ruby/object:Gem::Requirement
236
+ requirements:
237
+ - - ">="
238
+ - !ruby/object:Gem::Version
239
+ version: '0'
240
+ - !ruby/object:Gem::Dependency
241
+ name: turbolinks
242
+ requirement: !ruby/object:Gem::Requirement
243
+ requirements:
244
+ - - ">="
245
+ - !ruby/object:Gem::Version
246
+ version: '0'
247
+ type: :development
248
+ prerelease: false
249
+ version_requirements: !ruby/object:Gem::Requirement
250
+ requirements:
251
+ - - ">="
252
+ - !ruby/object:Gem::Version
253
+ version: '0'
212
254
  - !ruby/object:Gem::Dependency
213
255
  name: connection_pool
214
256
  requirement: !ruby/object:Gem::Requirement
@@ -304,6 +346,7 @@ files:
304
346
  - lib/generators/templates/component.es6.jsx
305
347
  - lib/generators/templates/component.js.jsx
306
348
  - lib/generators/templates/component.js.jsx.coffee
349
+ - lib/generators/templates/component.js.jsx.tsx
307
350
  - lib/generators/templates/react_server_rendering.rb
308
351
  - lib/generators/templates/server_rendering.js
309
352
  - lib/generators/templates/server_rendering_pack.js
@@ -321,6 +364,7 @@ files:
321
364
  - lib/react/rails/controller_lifecycle.rb
322
365
  - lib/react/rails/controller_renderer.rb
323
366
  - lib/react/rails/railtie.rb
367
+ - lib/react/rails/test_helper.rb
324
368
  - lib/react/rails/version.rb
325
369
  - lib/react/rails/view_helper.rb
326
370
  - lib/react/server_rendering.rb
@@ -338,7 +382,7 @@ homepage: https://github.com/reactjs/react-rails
338
382
  licenses:
339
383
  - Apache-2.0
340
384
  metadata: {}
341
- post_install_message:
385
+ post_install_message:
342
386
  rdoc_options: []
343
387
  require_paths:
344
388
  - lib
@@ -353,9 +397,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
353
397
  - !ruby/object:Gem::Version
354
398
  version: '0'
355
399
  requirements: []
356
- rubyforge_project:
357
- rubygems_version: 2.7.6
358
- signing_key:
400
+ rubygems_version: 3.4.12
401
+ signing_key:
359
402
  specification_version: 4
360
403
  summary: React integration for Ruby on Rails
361
404
  test_files: []