react-manifest-rails 0.2.14 → 0.2.15
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/lib/react_manifest/generator.rb +103 -4
- data/lib/react_manifest/version.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: 292c5ccc8f0c7465c5b4fc176d7b28ff5c53e11bad16689ce9ebfcf028fdc75c
|
|
4
|
+
data.tar.gz: c77bf1b90b135fccc39b7c27ae2739c36cb891fcf504f33be2a87d3d415928d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a7630b06c178a9d7433aaeef8eaec5c27a32319a8c6c191347cd614b1dde047ee8584cde6a2d16da4436975210479ef3cca12f62953562a6e1f49f3794829ef7
|
|
7
|
+
data.tar.gz: 28af64d5d5424b6a86b7c8d3b6be5e5b3dd865e500561adc2e4035bd1f38fbbb98ad2211c502003f604bb976967ae8a3eeb6e06c72ca470c06bd4800cef50e8d
|
|
@@ -22,6 +22,7 @@ module ReactManifest
|
|
|
22
22
|
# to avoid partial reads from concurrent processes.
|
|
23
23
|
#
|
|
24
24
|
# Never touches application.js, application_dev.js, or files in exclude_paths.
|
|
25
|
+
# rubocop:disable Metrics/ClassLength
|
|
25
26
|
class Generator
|
|
26
27
|
HEADER = <<~JS.freeze
|
|
27
28
|
// AUTO-GENERATED — DO NOT EDIT
|
|
@@ -41,11 +42,12 @@ module ReactManifest
|
|
|
41
42
|
# written and others stale/missing.
|
|
42
43
|
def run!
|
|
43
44
|
classification = @classifier.classify
|
|
45
|
+
controller_context = build_controller_context(classification.controller_dirs)
|
|
44
46
|
|
|
45
47
|
# Phase 1: build all content in memory — no I/O.
|
|
46
48
|
manifests = []
|
|
47
49
|
manifests << build_shared(classification.shared_dirs)
|
|
48
|
-
classification.controller_dirs.each { |ctrl| manifests << build_controller(ctrl) }
|
|
50
|
+
classification.controller_dirs.each { |ctrl| manifests << build_controller(ctrl, controller_context) }
|
|
49
51
|
|
|
50
52
|
migrate_legacy_manifests!
|
|
51
53
|
|
|
@@ -79,19 +81,87 @@ module ReactManifest
|
|
|
79
81
|
|
|
80
82
|
# --------------------------------------------------------------- controller
|
|
81
83
|
|
|
82
|
-
def build_controller(ctrl)
|
|
84
|
+
def build_controller(ctrl, controller_context)
|
|
83
85
|
lines = header_lines
|
|
86
|
+
dep_requires = controller_dependency_requires(ctrl[:bundle_name], controller_context)
|
|
84
87
|
|
|
85
88
|
files = js_files_in(ctrl[:path])
|
|
86
|
-
|
|
89
|
+
own_requires = files.map { |f| relative_require_path(f) }
|
|
90
|
+
all_requires = (dep_requires + own_requires).uniq
|
|
91
|
+
|
|
92
|
+
if all_requires.empty?
|
|
87
93
|
lines << "// (no JSX files found in #{ctrl[:name]}/)"
|
|
88
94
|
else
|
|
89
|
-
|
|
95
|
+
all_requires.each { |req| lines << "//= require #{req}" }
|
|
90
96
|
end
|
|
91
97
|
|
|
92
98
|
{ filename: "#{ctrl[:bundle_name]}.js", content: "#{lines.join("\n")}\n" }
|
|
93
99
|
end
|
|
94
100
|
|
|
101
|
+
def build_controller_context(controller_dirs)
|
|
102
|
+
bundle_files = {}
|
|
103
|
+
symbol_to_bundle = {}
|
|
104
|
+
dependencies = Hash.new { |h, k| h[k] = Set.new }
|
|
105
|
+
|
|
106
|
+
controller_dirs.each do |ctrl|
|
|
107
|
+
bundle_name = ctrl[:bundle_name]
|
|
108
|
+
files = js_files_in(ctrl[:path])
|
|
109
|
+
bundle_files[bundle_name] = files
|
|
110
|
+
|
|
111
|
+
files.each do |file_path|
|
|
112
|
+
extract_defined_symbols(file_path).each do |sym|
|
|
113
|
+
next unless sym.match?(/\A[A-Z][A-Za-z0-9_]*\z/)
|
|
114
|
+
|
|
115
|
+
symbol_to_bundle[sym] ||= bundle_name
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
bundle_files.each do |bundle_name, files|
|
|
121
|
+
files.each do |file_path|
|
|
122
|
+
extract_used_component_symbols(file_path).each do |sym|
|
|
123
|
+
dep_bundle = symbol_to_bundle[sym]
|
|
124
|
+
next unless dep_bundle && dep_bundle != bundle_name
|
|
125
|
+
|
|
126
|
+
dependencies[bundle_name] << dep_bundle
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
{
|
|
132
|
+
bundle_files: bundle_files,
|
|
133
|
+
dependencies: dependencies
|
|
134
|
+
}
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def controller_dependency_requires(bundle_name, controller_context)
|
|
138
|
+
deps = transitive_dependencies(bundle_name, controller_context[:dependencies])
|
|
139
|
+
deps.flat_map { |dep_bundle| controller_context[:bundle_files].fetch(dep_bundle, []) }
|
|
140
|
+
.map { |abs_path| relative_require_path(abs_path) }
|
|
141
|
+
.uniq
|
|
142
|
+
.sort
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def transitive_dependencies(bundle_name, dependency_map)
|
|
146
|
+
ordered = []
|
|
147
|
+
visiting = Set.new
|
|
148
|
+
visited = Set.new
|
|
149
|
+
|
|
150
|
+
walk = lambda do |current|
|
|
151
|
+
return if visited.include?(current) || visiting.include?(current)
|
|
152
|
+
|
|
153
|
+
visiting << current
|
|
154
|
+
dependency_map.fetch(current, Set.new).each { |dep| walk.call(dep) }
|
|
155
|
+
visiting.delete(current)
|
|
156
|
+
|
|
157
|
+
visited << current
|
|
158
|
+
ordered << current unless current == bundle_name
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
walk.call(bundle_name)
|
|
162
|
+
ordered
|
|
163
|
+
end
|
|
164
|
+
|
|
95
165
|
# --------------------------------------------------------------- write
|
|
96
166
|
|
|
97
167
|
def write_manifest(filename, content)
|
|
@@ -207,6 +277,34 @@ module ReactManifest
|
|
|
207
277
|
rel.sub(/\.js\.jsx$/, "").sub(/\.jsx$/, "").sub(/\.js$/, "")
|
|
208
278
|
end
|
|
209
279
|
|
|
280
|
+
def extract_defined_symbols(file_path)
|
|
281
|
+
content = File.read(file_path, encoding: "utf-8")
|
|
282
|
+
symbols = []
|
|
283
|
+
ReactManifest::Scanner::DEFINITION_PATTERNS.each do |pattern|
|
|
284
|
+
content.scan(pattern) { |m| symbols << m[0] }
|
|
285
|
+
end
|
|
286
|
+
symbols.uniq
|
|
287
|
+
rescue Errno::ENOENT, Errno::EACCES, Encoding::InvalidByteSequenceError
|
|
288
|
+
[]
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def extract_used_component_symbols(file_path)
|
|
292
|
+
content = File.read(file_path, encoding: "utf-8")
|
|
293
|
+
symbols = []
|
|
294
|
+
|
|
295
|
+
content.scan(ReactManifest::Scanner::JSX_ELEMENT_PATTERN) { |m| symbols << m[0] }
|
|
296
|
+
content.scan(ReactManifest::Scanner::REACT_CREATE_PATTERN) { |m| symbols << m[0] }
|
|
297
|
+
content.scan(ReactManifest::Scanner::JSX_PROP_COMPONENT_PATTERN) { |m| symbols << m[0] }
|
|
298
|
+
content.scan(ReactManifest::Scanner::OBJECT_COMPONENT_PATTERN) { |m| symbols << m[0] }
|
|
299
|
+
content.scan(ReactManifest::Scanner::ARRAY_COMPONENT_LIST_PATTERN) do |m|
|
|
300
|
+
m[0].split(/\s*,\s*/).each { |sym| symbols << sym }
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
symbols.uniq
|
|
304
|
+
rescue Errno::ENOENT, Errno::EACCES, Encoding::InvalidByteSequenceError
|
|
305
|
+
[]
|
|
306
|
+
end
|
|
307
|
+
|
|
210
308
|
def auto_generated?(path)
|
|
211
309
|
# Avoid TOCTOU: don't check existence separately — just attempt the read
|
|
212
310
|
# and treat a missing/unreadable file as not auto-generated.
|
|
@@ -238,4 +336,5 @@ module ReactManifest
|
|
|
238
336
|
"#{counts[:skipped_pinned] || 0} skipped (not auto-generated)"
|
|
239
337
|
end
|
|
240
338
|
end
|
|
339
|
+
# rubocop:enable Metrics/ClassLength
|
|
241
340
|
end
|