react-manifest-rails 0.2.21 → 0.2.22

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a68f022a75a440c68e741e931c5453e6c96c126380356757825a984de94e2143
4
- data.tar.gz: 52d20e65e685a1b82d833ee650677c91a6fc5faa9e7b32c1075d85a2e6f53fa7
3
+ metadata.gz: c87f68d7ed8248c19732ce3b946a1207ed85907a92bd39ab5a2eda665f5b001e
4
+ data.tar.gz: 7ee42c73f25048a31d8ca713d0cdfc23b344eb99ec68d1f72c58b5cfda3b635d
5
5
  SHA512:
6
- metadata.gz: bfd3abb4dde7e8d661df2623b42345a6f5a191f6b119ce25d8913ab094261ea76592ea435709a9fd80d320703673deb073b4df2a8de90a2fb76d6cf43532272b
7
- data.tar.gz: cef2fd10f820ebf0a1583772fa7236e34f5c5d2744e076f682111d374cf220c265b2625d02a6f88d0274baaaa8e215eb55cfec353e528d85ac82327ef466dc6f
6
+ metadata.gz: d71e1c8b255678a3b1a72df766134b80dadd8bf7553d4380e240d3a8b526dff5e6f6ef848574b93c86f6778feef896cc04b945a0f020d03d0bccf034acfe7d74
7
+ data.tar.gz: 874538d0cd06e8b8a121d9343a3846649b6612cd3ad4bb8c0c28a7c1589c1e05bf2f48b80ae0fe6a8af478d07a3d4309d9a5bc692536f4cdebeeed90b89ca74c
data/README.md CHANGED
@@ -235,6 +235,18 @@ If you see errors like `UserSignInForm is not defined` (often from `eval` inside
235
235
 
236
236
  Using `defer: true` can cause `react_component` inline scripts to run before your `ux_*.js` bundles are executed.
237
237
 
238
+ ### `Identifier '<Name>' has already been declared`
239
+
240
+ This usually means the same component/function is being loaded from two separate bundles.
241
+
242
+ Common cause: a file outside `ux/` (for example `app/assets/javascripts/components/navbar/*` loaded by `application.js`) references a symbol defined in `ux/app/<controller>/...`, while that controller bundle is also loaded via `react_bundle_tag`.
243
+
244
+ Recommended fix:
245
+ - Move globally reused symbols out of `ux/app/*` into a shared dir (`ux/components`, `ux/hooks`, `ux/lib`) so they are emitted once via `ux_shared.js`.
246
+ - Keep controller-specific symbols in `ux/app/*` and avoid importing/using them from non-ux global assets.
247
+
248
+ If you use `external_roots`, `react_manifest:analyze` and generation warnings will now flag this pattern explicitly.
249
+
238
250
  ## Compatibility
239
251
 
240
252
  - Ruby: 3.2+
@@ -132,6 +132,8 @@ module ReactManifest
132
132
  next
133
133
  end
134
134
 
135
+ warn_on_external_controller_references(file_path, symbol_to_bundle)
136
+
135
137
  extract_defined_symbols(file_path).each do |sym|
136
138
  external_symbol_to_require[sym] ||= req_path
137
139
  end
@@ -372,6 +374,17 @@ module ReactManifest
372
374
  path.to_s.sub(/\.js\.jsx$/, "").sub(/\.jsx$/, "").sub(/\.js$/, "")
373
375
  end
374
376
 
377
+ def warn_on_external_controller_references(file_path, symbol_to_bundle)
378
+ extract_used_component_symbols(file_path).each do |sym|
379
+ dep_bundle = symbol_to_bundle[sym]
380
+ next unless dep_bundle
381
+
382
+ warn "[ReactManifest] External file '#{relative_require_path(file_path)}' references " \
383
+ "controller-only symbol '#{sym}' (#{dep_bundle}). " \
384
+ "Move '#{sym}' to a shared ux dir to avoid duplicate runtime declarations."
385
+ end
386
+ end
387
+
375
388
  def auto_generated?(path)
376
389
  # Avoid TOCTOU: don't check existence separately — just attempt the read
377
390
  # and treat a missing/unreadable file as not auto-generated.
@@ -57,7 +57,8 @@ module ReactManifest
57
57
  Object Array String Number Boolean Symbol Map Set WeakMap
58
58
  ].freeze
59
59
 
60
- Result = Struct.new(:symbol_index, :controller_usages, :warnings, :shared_violations, keyword_init: true)
60
+ Result = Struct.new(:symbol_index, :controller_usages, :warnings, :shared_violations,
61
+ :external_violations, keyword_init: true)
61
62
 
62
63
  def initialize(config = ReactManifest.configuration)
63
64
  @config = config
@@ -67,6 +68,7 @@ module ReactManifest
67
68
  def scan(classification)
68
69
  warnings = []
69
70
  symbol_index = {}
71
+ external_file_paths = {} # file_path => relative_require_path for external_roots files
70
72
 
71
73
  # Phase 1a: index symbols from shared dirs
72
74
  shared_file_paths = {} # file_path => relative_require_path for all shared files
@@ -90,7 +92,8 @@ module ReactManifest
90
92
  abs_root = abs_external_root(root_path)
91
93
  js_files_in(abs_root).each do |file_path|
92
94
  relative = relative_require_path(file_path)
93
- symbols = extract_definitions(file_path)
95
+ external_file_paths[file_path] = relative
96
+ symbols = extract_definitions(file_path)
94
97
  symbols.each do |sym|
95
98
  symbol_index[sym] ||= relative
96
99
  end
@@ -119,6 +122,7 @@ module ReactManifest
119
122
 
120
123
  # Phase 1e: detect shared files that use app-dir (controller) symbols
121
124
  shared_violations = detect_shared_violations(shared_file_paths, controller_symbol_index, warnings)
125
+ external_violations = detect_external_root_violations(external_file_paths, controller_symbol_index, warnings)
122
126
 
123
127
  # Phase 2: scan controller dirs for usage
124
128
  controller_usages = {}
@@ -147,7 +151,8 @@ module ReactManifest
147
151
  symbol_index: symbol_index,
148
152
  controller_usages: controller_usages,
149
153
  warnings: warnings,
150
- shared_violations: shared_violations
154
+ shared_violations: shared_violations,
155
+ external_violations: external_violations
151
156
  )
152
157
  end
153
158
  # rubocop:enable Metrics/MethodLength,Metrics/AbcSize,Metrics/PerceivedComplexity
@@ -229,6 +234,36 @@ module ReactManifest
229
234
  violations
230
235
  end
231
236
 
237
+ def detect_external_root_violations(external_file_paths, controller_symbol_index, warnings)
238
+ violations = []
239
+ external_file_paths.each do |file_path, relative|
240
+ content = begin
241
+ File.read(file_path, encoding: "utf-8")
242
+ rescue Errno::ENOENT, Errno::EACCES, Encoding::InvalidByteSequenceError
243
+ next
244
+ end
245
+
246
+ local_syms = Set.new
247
+ DEFINITION_PATTERNS.each { |p| content.scan(p) { |m| local_syms << m[0] } }
248
+
249
+ [PASCAL_TOKEN_PATTERN, HOOK_TOKEN_PATTERN].each do |pattern|
250
+ content.scan(pattern) do |match|
251
+ sym = match[0]
252
+ next if local_syms.include?(sym)
253
+ next unless controller_symbol_index.key?(sym)
254
+
255
+ info = controller_symbol_index[sym]
256
+ violations << { external_file: relative, symbol: sym,
257
+ controller: info[:controller], app_file: info[:file] }
258
+ warnings << "External file '#{relative}' uses app-dir symbol '#{sym}' " \
259
+ "(from ux/app/#{info[:controller]}). " \
260
+ "Move '#{sym}' into a shared ux dir to avoid duplicate runtime declarations."
261
+ end
262
+ end
263
+ end
264
+ violations
265
+ end
266
+
232
267
  # Count how many controllers use each shared file
233
268
  def emit_fanout_warnings(controller_usages, warnings)
234
269
  fanout = Hash.new(0)
@@ -1,3 +1,3 @@
1
1
  module ReactManifest
2
- VERSION = "0.2.21".freeze
2
+ VERSION = "0.2.22".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react-manifest-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.21
4
+ version: 0.2.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Noonan