react-manifest-rails 0.2.23 → 0.2.24
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/react_manifest/generator.rb +37 -9
- data/lib/react_manifest/scanner.rb +6 -18
- data/lib/react_manifest/version.rb +1 -1
- data/lib/react_manifest/view_helpers.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 786d53e91fe8a65339def86bc62a94179762364cf13d1abcc8427ea9585f0c38
|
|
4
|
+
data.tar.gz: 90c58cd92bc06eb2911deaf829aca60ed8533e6dc58e535759e9f6d60eefdcd2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 30c7f0633646f06cfc497a617c76dbbb50f74e84104fd590f3054bff5c228a42e08aa6683dfdc96702656a52cec57533917b2438d4bb39ede667ef6c0686f219
|
|
7
|
+
data.tar.gz: 0ea044f3d55bb64be2ce9a725cc90cf9b33da8f343fde043707c098995ce6e88840e609947867203efe739623ce5dba3a32e4d444dfb9b3f8b252b56b991adbb
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.24] - 2026-04-22
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Controller manifests now inline files from bundles listed in `always_include` (for example `ux_main`), so runtime symbol availability no longer depends on cross-bundle script execution order in production.
|
|
14
|
+
- Scanner analysis no longer emits warnings for ux/app file naming convention mismatches, reducing noise for apps that intentionally use custom filename patterns.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Updated `Gemfile.lock` to keep lockfile state aligned with the released codebase.
|
|
18
|
+
|
|
10
19
|
## [0.2.23] - 2026-04-21
|
|
11
20
|
|
|
12
21
|
### Fixed
|
|
@@ -43,11 +43,11 @@ module ReactManifest
|
|
|
43
43
|
def run!
|
|
44
44
|
classification = @classifier.classify
|
|
45
45
|
scan_result = Scanner.new(@config).scan(classification)
|
|
46
|
-
controller_context = build_controller_context(classification.controller_dirs, classification.shared_dirs,
|
|
46
|
+
controller_context = build_controller_context(classification.controller_dirs, classification.shared_dirs,
|
|
47
|
+
scan_result)
|
|
47
48
|
|
|
48
49
|
# Phase 1: build all content in memory — no I/O.
|
|
49
|
-
manifests =
|
|
50
|
-
classification.controller_dirs.each { |ctrl| manifests << build_controller(ctrl, controller_context) }
|
|
50
|
+
manifests = classification.controller_dirs.map { |ctrl| build_controller(ctrl, controller_context) }
|
|
51
51
|
|
|
52
52
|
migrate_legacy_manifests!
|
|
53
53
|
|
|
@@ -62,12 +62,11 @@ module ReactManifest
|
|
|
62
62
|
|
|
63
63
|
# ------------------------------------------------------------------ shared
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
65
|
# --------------------------------------------------------------- controller
|
|
68
66
|
|
|
69
67
|
def build_controller(ctrl, controller_context)
|
|
70
68
|
lines = header_lines
|
|
69
|
+
always_include_reqs = controller_context[:always_include_requires].fetch(ctrl[:bundle_name], [])
|
|
71
70
|
dep_requires = controller_dependency_requires(ctrl[:bundle_name], controller_context)
|
|
72
71
|
lib_reqs = controller_context[:shared_lib_requires]
|
|
73
72
|
shared_reqs = controller_context[:shared_requires].fetch(ctrl[:bundle_name], Set.new).to_a.sort
|
|
@@ -75,7 +74,7 @@ module ReactManifest
|
|
|
75
74
|
|
|
76
75
|
files = js_files_in(ctrl[:path])
|
|
77
76
|
own_requires = files.map { |f| relative_require_path(f) }
|
|
78
|
-
all_requires = (dep_requires + lib_reqs + shared_reqs + ext_reqs + own_requires).uniq
|
|
77
|
+
all_requires = (always_include_reqs + dep_requires + lib_reqs + shared_reqs + ext_reqs + own_requires).uniq
|
|
79
78
|
|
|
80
79
|
if all_requires.empty?
|
|
81
80
|
lines << "// (no JSX files found in #{ctrl[:name]}/)"
|
|
@@ -86,6 +85,7 @@ module ReactManifest
|
|
|
86
85
|
{ filename: "#{ctrl[:bundle_name]}.js", content: "#{lines.join("\n")}\n" }
|
|
87
86
|
end
|
|
88
87
|
|
|
88
|
+
# rubocop:disable Metrics/AbcSize
|
|
89
89
|
def build_controller_context(controller_dirs, shared_dirs, scan_result)
|
|
90
90
|
bundle_files = {}
|
|
91
91
|
symbol_to_bundle = {}
|
|
@@ -103,10 +103,8 @@ module ReactManifest
|
|
|
103
103
|
end
|
|
104
104
|
shared_requires[ctrl[:bundle_name]] = expand_shared_requires(shared_requires[ctrl[:bundle_name]],
|
|
105
105
|
shared_dependency_map)
|
|
106
|
-
end
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
controller_dirs.each do |ctrl|
|
|
107
|
+
# Index controller-defined symbols for cross-app detection
|
|
110
108
|
bundle_name = ctrl[:bundle_name]
|
|
111
109
|
files = js_files_in(ctrl[:path])
|
|
112
110
|
bundle_files[bundle_name] = files
|
|
@@ -152,14 +150,18 @@ module ReactManifest
|
|
|
152
150
|
end
|
|
153
151
|
end
|
|
154
152
|
|
|
153
|
+
always_include_requires = build_always_include_requires(bundle_files, dependencies)
|
|
154
|
+
|
|
155
155
|
{
|
|
156
156
|
bundle_files: bundle_files,
|
|
157
157
|
dependencies: dependencies,
|
|
158
|
+
always_include_requires: always_include_requires,
|
|
158
159
|
shared_lib_requires: shared_lib_requires,
|
|
159
160
|
shared_requires: shared_requires,
|
|
160
161
|
external_requires: external_requires
|
|
161
162
|
}
|
|
162
163
|
end
|
|
164
|
+
# rubocop:enable Metrics/AbcSize
|
|
163
165
|
|
|
164
166
|
def controller_dependency_requires(bundle_name, controller_context)
|
|
165
167
|
deps = transitive_dependencies(bundle_name, controller_context[:dependencies])
|
|
@@ -189,6 +191,32 @@ module ReactManifest
|
|
|
189
191
|
ordered
|
|
190
192
|
end
|
|
191
193
|
|
|
194
|
+
def build_always_include_requires(bundle_files, dependencies)
|
|
195
|
+
bundles = @config.always_include.map(&:to_s).reject(&:empty?).uniq
|
|
196
|
+
return Hash.new { |h, k| h[k] = [] } if bundles.empty?
|
|
197
|
+
|
|
198
|
+
requires_by_bundle = Hash.new { |h, k| h[k] = [] }
|
|
199
|
+
|
|
200
|
+
bundle_files.each_key do |bundle_name|
|
|
201
|
+
requires = Set.new
|
|
202
|
+
|
|
203
|
+
bundles.each do |always_bundle|
|
|
204
|
+
next if always_bundle == bundle_name
|
|
205
|
+
|
|
206
|
+
transitive = [always_bundle] + transitive_dependencies(always_bundle, dependencies)
|
|
207
|
+
transitive.each do |dep_bundle|
|
|
208
|
+
bundle_files.fetch(dep_bundle, []).each do |abs_path|
|
|
209
|
+
requires << relative_require_path(abs_path)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
requires_by_bundle[bundle_name] = requires.to_a.sort
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
requires_by_bundle
|
|
218
|
+
end
|
|
219
|
+
|
|
192
220
|
# --------------------------------------------------------------- write
|
|
193
221
|
|
|
194
222
|
def write_manifest(filename, content)
|
|
@@ -23,7 +23,7 @@ module ReactManifest
|
|
|
23
23
|
/function\s+([A-Z][A-Za-z0-9_]*)\s*\(/, # function FooBar(
|
|
24
24
|
/class\s+([A-Z][A-Za-z0-9_]*)\s*(?:extends|\{)/, # class FooBar
|
|
25
25
|
/(?:const|let|var)\s+(use[A-Z][A-Za-z0-9_]*)\s*=/, # const useFoo = (hooks)
|
|
26
|
-
/function\s+(use[A-Z][A-Za-z0-9_]*)\s*\(/,
|
|
26
|
+
/function\s+(use[A-Z][A-Za-z0-9_]*)\s*\(/, # function useFoo(
|
|
27
27
|
|
|
28
28
|
# ES module style (export default / named exports)
|
|
29
29
|
/^export\s+default\s+(?:function|class)\s+([A-Z][A-Za-z0-9_]*)/,
|
|
@@ -130,7 +130,6 @@ module ReactManifest
|
|
|
130
130
|
warnings.add("Controller dir '#{ctrl[:name]}' has no JS/JSX files") if files.empty? && @config.verbose?
|
|
131
131
|
|
|
132
132
|
files.each do |file_path|
|
|
133
|
-
validate_naming(file_path, ctrl[:name], warnings)
|
|
134
133
|
content = read_controller_file(file_path, warnings)
|
|
135
134
|
next unless content
|
|
136
135
|
|
|
@@ -191,15 +190,6 @@ module ReactManifest
|
|
|
191
190
|
rel.sub(/\.js\.jsx$/, "").sub(/\.jsx$/, "").sub(/\.js$/, "")
|
|
192
191
|
end
|
|
193
192
|
|
|
194
|
-
def validate_naming(file_path, ctrl_name, warnings)
|
|
195
|
-
basename = File.basename(file_path, ".*").sub(/\.js$/, "")
|
|
196
|
-
# Expected: <controller>_index, <controller>_show, <controller>_form, etc.
|
|
197
|
-
return if basename.start_with?("#{ctrl_name}_") || basename == ctrl_name
|
|
198
|
-
|
|
199
|
-
warnings.add("File '#{File.basename(file_path)}' in '#{ctrl_name}' does not follow " \
|
|
200
|
-
"'#{ctrl_name}_<action>.js.jsx' naming convention")
|
|
201
|
-
end
|
|
202
|
-
|
|
203
193
|
def detect_shared_violations(shared_file_paths, controller_symbol_index, warnings)
|
|
204
194
|
violations = []
|
|
205
195
|
shared_file_paths.each do |file_path, relative|
|
|
@@ -222,8 +212,8 @@ module ReactManifest
|
|
|
222
212
|
violations << { shared_file: relative, symbol: sym,
|
|
223
213
|
controller: info[:controller], app_file: info[:file] }
|
|
224
214
|
warnings.add("Shared file '#{relative}' uses app-dir symbol '#{sym}' " \
|
|
225
|
-
|
|
226
|
-
|
|
215
|
+
"(from ux/app/#{info[:controller]}). " \
|
|
216
|
+
"Move '#{sym}' to a shared dir or the shared file will be incomplete.")
|
|
227
217
|
end
|
|
228
218
|
end
|
|
229
219
|
end
|
|
@@ -252,8 +242,8 @@ module ReactManifest
|
|
|
252
242
|
violations << { external_file: relative, symbol: sym,
|
|
253
243
|
controller: info[:controller], app_file: info[:file] }
|
|
254
244
|
warnings.add("External file '#{relative}' uses app-dir symbol '#{sym}' " \
|
|
255
|
-
|
|
256
|
-
|
|
245
|
+
"(from ux/app/#{info[:controller]}). " \
|
|
246
|
+
"Move '#{sym}' into a shared ux dir to avoid duplicate runtime declarations.")
|
|
257
247
|
end
|
|
258
248
|
end
|
|
259
249
|
end
|
|
@@ -268,9 +258,7 @@ module ReactManifest
|
|
|
268
258
|
end
|
|
269
259
|
|
|
270
260
|
fanout.each do |file, count|
|
|
271
|
-
if count > 3
|
|
272
|
-
warnings.add("High fan-out: '#{file}' is used by #{count} controllers")
|
|
273
|
-
end
|
|
261
|
+
warnings.add("High fan-out: '#{file}' is used by #{count} controllers") if count > 3
|
|
274
262
|
end
|
|
275
263
|
end
|
|
276
264
|
|