react-manifest-rails 0.2.34 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +87 -0
- data/README.md +7 -2
- data/lib/react_manifest/ast_extractor.rb +11 -0
- data/lib/react_manifest/component_index.rb +136 -0
- data/lib/react_manifest/configuration.rb +19 -0
- data/lib/react_manifest/generator.rb +477 -83
- data/lib/react_manifest/gitignore_patcher.rb +81 -0
- data/lib/react_manifest/railtie.rb +6 -0
- data/lib/react_manifest/symbol_extractor.rb +27 -0
- data/lib/react_manifest/vendor/ast_extractor.js +11 -11
- data/lib/react_manifest/vendor/build/entry.js +32 -0
- data/lib/react_manifest/version.rb +1 -1
- data/lib/react_manifest/view_helpers.rb +42 -5
- data/lib/react_manifest.rb +31 -75
- data/tasks/react_manifest.rake +37 -0
- metadata +17 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: adc189b9603ad36c8d986e8f90cac383fcb65cfabafc60d64b3155681cd21ca7
|
|
4
|
+
data.tar.gz: 3cd94fbc6573c1548753ece80674a42d476619f7553b4fedffdd7d3b631cbe16
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b382bb1ae0d2d9464402dbca4cacc0294897eea15e4a9a9917c447219ad8e5788ed22a2062d4dd2f28c7635c8e09ba2629972d8fc04a0e3b22d6769d87ec7a2c
|
|
7
|
+
data.tar.gz: f32f2baa961dbcb50b048191ed46e81f5ea7f016994355b2cba3a332b7f846e7f889df41cbc3fefb5364e8a7c3189484f3181058d825e6935ca6fc9ddced033e
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,93 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.1] - 2026-10-13
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `react_bundle_tag` emits `data-turbolinks-track="reload"` on the shared bundle's tag only
|
|
14
|
+
(`config.shared_bundle`). Turbolinks 5 then full-reloads once after a deploy changes
|
|
15
|
+
`ux_shared`, so old shared code never runs with new controller code. Controller and
|
|
16
|
+
`always_include` bundles stay untracked to avoid a reload on every cross-controller visit.
|
|
17
|
+
- `react_manifest:generate` warns when two different files declare the same top-level
|
|
18
|
+
`const`/`let`/`class` (destructured names included) in different bundles. Classic scripts
|
|
19
|
+
share one global scope, so under Turbolinks the second bundle throws "Identifier X has
|
|
20
|
+
already been declared" and is rejected.
|
|
21
|
+
- `react_manifest:generate` (and the dev boot/watch generation) writes
|
|
22
|
+
`ux_manifests/component_index.json`, the component-symbol -> bundle maps. `react_component`
|
|
23
|
+
loads it instead of parsing `ux/app` with mini_racer on each process's first call (no V8
|
|
24
|
+
context, no per-worker RSS cost). It is used only when its content fingerprint matches;
|
|
25
|
+
a missing or stale sidecar falls back to the runtime parse. Gitignored alongside the
|
|
26
|
+
manifests; removed by `react_manifest:clean`.
|
|
27
|
+
- `rake react_manifest:check`: analysis only, writes nothing, exits 1 with the warnings on
|
|
28
|
+
stderr when any "declared twice" clash is found (cross-bundle lexical collisions,
|
|
29
|
+
`always_include` double-declares). Meant for CI.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- `mini_racer` is now a declared runtime dependency (`>= 0.2`); `AstExtractor` already
|
|
33
|
+
required it unconditionally.
|
|
34
|
+
- The built gem no longer ships `lib/react_manifest/vendor/build/node_modules`.
|
|
35
|
+
- `react_bundle_tag` now hoists bundle `<script>` tags into the layout `<head>`. Rails renders
|
|
36
|
+
the template before the layout, so `react_component` wrote ux_shared, `always_include` and
|
|
37
|
+
controller bundle tags into the `<body>`; Turbolinks re-evaluates body scripts on every
|
|
38
|
+
visit, giving "Identifier X has already been declared". `react_component` now marks its
|
|
39
|
+
inline tags (`data-react-manifest`) and `react_bundle_tag` moves them to the head, once, in
|
|
40
|
+
shared → always_include → controller order. Layouts without `react_bundle_tag` are unchanged.
|
|
41
|
+
- Collision warnings for `always_include` bundles now cover the every-page double.
|
|
42
|
+
Previously only a file that **directly** defined a collided symbol was warned about.
|
|
43
|
+
A file that is merely *tainted* (transitively depends on a collided symbol) and gets
|
|
44
|
+
pulled into **2+** `always_include` tags double-declares on every page but was not
|
|
45
|
+
warned. The warning now reports both a *multi-tag* double (a file carried by 2+
|
|
46
|
+
always_include tags — including tainted files, naming the file, symbol, and bundles)
|
|
47
|
+
and the *owner-page* double (single tag vs. the owning bundle), with wording accurate
|
|
48
|
+
to each case rather than always claiming the double happens "on the owner's page".
|
|
49
|
+
|
|
50
|
+
## [0.3.0] - 2026-07-15
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
- `always_include` no longer double-declares. Its bundles are delivered on every page
|
|
54
|
+
by their own `<script>` tag (both `react_bundle_tag`/`resolve_bundles` and
|
|
55
|
+
`react_component` now emit them), and their files are no longer inlined into each
|
|
56
|
+
controller manifest. Previously the separate tag plus the inline loaded an
|
|
57
|
+
always_include bundle's **private** files twice on any other controller's page, and a
|
|
58
|
+
**collided** symbol whose definer lives in an always_include bundle could pull a
|
|
59
|
+
second definer into the consumer — both causing "Identifier X has already been
|
|
60
|
+
declared". Controller dependency resolution now treats symbols provided by an
|
|
61
|
+
always_include bundle as already satisfied, and skips those bundles when inlining
|
|
62
|
+
dependencies (legacy `auto_shared = false` path included). The "already provided"
|
|
63
|
+
set is computed from the exact files the always_include `<script>` tag actually
|
|
64
|
+
carries (its own non-promoted files plus the canonical dependency files it inlines),
|
|
65
|
+
not from whole dependency bundles — so a consumer never drops a definer for a symbol
|
|
66
|
+
that lives in a sibling file the tag does not load. Symbol availability that the
|
|
67
|
+
previous inlining protected (added in 0.2.24) is preserved by the tag `react_component`
|
|
68
|
+
now emits.
|
|
69
|
+
- One case remains inherently unresolvable by dependency arithmetic: when an
|
|
70
|
+
`always_include` bundle *consumes* a collided symbol, its tag inlines the
|
|
71
|
+
first-writer definer, which also lives in that definer's own bundle manifest, so on
|
|
72
|
+
the definer's own page the file loads twice. `react_manifest:generate` now emits a
|
|
73
|
+
warning naming the always_include bundle, the duplicated file/symbol, and the owning
|
|
74
|
+
bundle, with the fix (rename or relocate the collided symbol). Detected in both the
|
|
75
|
+
default and legacy (`auto_shared = false`) modes.
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
- Auto-promotion: a component defined under `ux/app/<controller>/` but used by any
|
|
79
|
+
other bundle is now emitted into `ux_shared` (loaded once per page) instead of being
|
|
80
|
+
inlined into each consumer. This eliminates duplicate top-level `const` declarations
|
|
81
|
+
("Identifier X has already been declared") — and the cascading `X is not defined`
|
|
82
|
+
errors that follow when a SyntaxError aborts a concatenated bundle — for components
|
|
83
|
+
shared across controllers (e.g. a navbar component pulled in via `always_include`).
|
|
84
|
+
Files never move; only the `//= require` line's destination changes. Promotion is
|
|
85
|
+
transitive. `react_manifest:analyze` now lists what was promoted and why. Set
|
|
86
|
+
`config.auto_shared = false` to restore the previous inline behavior.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
- Generated `ux_manifests/*.js` are now treated as build artifacts. `react_manifest:setup`
|
|
90
|
+
and the development boot step add them to `.gitignore` (idempotently) and keep a
|
|
91
|
+
committed `.keep` so the directory always exists; setup prints a one-time
|
|
92
|
+
`git rm --cached` to untrack previously-committed manifests. Production is unaffected
|
|
93
|
+
(manifests regenerate during `assets:precompile`). Opt out with
|
|
94
|
+
`config.manage_gitignore = false`. Upgrading an existing app requires no manual step:
|
|
95
|
+
the first dev boot regenerates manifests and ensures the ignore entry.
|
|
96
|
+
|
|
10
97
|
## [0.2.34] - 2026-07-02
|
|
11
98
|
|
|
12
99
|
### Added
|
data/README.md
CHANGED
|
@@ -143,13 +143,14 @@ end
|
|
|
143
143
|
### Key option notes
|
|
144
144
|
|
|
145
145
|
- **`ignore`**: skips entire controller dirs under `ux/app/`. `ignore = ["admin"]` excludes `ux/app/admin/`.
|
|
146
|
-
- **`isolated_app_dirs`**: a controller dir's own `ux_<name>.js` is generated as usual, but its files/symbols are never inferred as a dependency of any *other* controller.
|
|
146
|
+
- **`isolated_app_dirs`**: a controller dir's own `ux_<name>.js` is generated as usual, but its files/symbols are never inferred as a dependency of any *other* controller. When the AST engine below is unavailable (e.g. `mini_racer` failed to load), symbol usage detection is regex-based, so a generic component name can collide with an unrelated word appearing as plain JSX text elsewhere (e.g. a `Show` component vs. a "Show More" button label in a different controller) and get wrongly inlined everywhere. Use this as a manual, always-available fallback for self-contained dirs — e.g. a page-builder tool bundling its own vendored library — that should never leak into other pages, whether or not `mini_racer` is installed. `isolated_app_dirs = ["rvb"]` isolates `ux/app/rvb/`.
|
|
147
147
|
- **`exclude_paths`**: excludes files whose path contains any listed segment. Not based on `application.js`.
|
|
148
148
|
- **`dry_run`**: also honoured by `DRY_RUN=1` environment variable at runtime.
|
|
149
149
|
- **`extensions`**: add `ts` and `tsx` to enable TypeScript source detection.
|
|
150
150
|
- **`external_roots` / `external_providers`**: do not point these at files already inside shared `ux/` dirs (`components/`, `hooks/`, `lib/`, etc.). The generator now skips those overlaps to prevent duplicate declarations in browser runtime.
|
|
151
151
|
- **`stdout_logging`**: `Rails.logger` always receives status lines regardless of this flag. Turn this on only if your `Rails.logger` does *not* already print to your terminal in development — if it does (common with `RAILS_LOG_TO_STDOUT`, Docker, or `bin/dev`/Foreman setups), enabling this prints every line twice.
|
|
152
|
-
- **
|
|
152
|
+
- **Component index**: `react_manifest:generate` (and dev boot/watch) also writes `ux_manifests/component_index.json`, a gitignored build artifact. `react_component` reads it instead of parsing `ux/app` with V8 on the first call in each web process. It is used only when its fingerprint (gem version, config, file list and contents) matches; otherwise the runtime parses as before.
|
|
153
|
+
- **AST-based symbol extraction**: `mini_racer` is a dependency of this gem. Definitions and usages are derived from a real JS/JSX AST (Acorn) instead of regex, which fixes false positives like a `Show` component colliding with unrelated text such as a "Show More" button label. Falls back to regex extraction per-file on any parse failure (always logged via `Rails.logger.warn` with file/line/column when available) — generation never breaks because of this.
|
|
153
154
|
|
|
154
155
|
## Commands
|
|
155
156
|
|
|
@@ -164,6 +165,10 @@ bundle exec rails react_manifest:generate
|
|
|
164
165
|
DRY_RUN=1 bundle exec rails react_manifest:setup
|
|
165
166
|
DRY_RUN=1 bundle exec rails react_manifest:generate
|
|
166
167
|
|
|
168
|
+
# CI gate: writes nothing; exits 1 and prints each "declared twice" warning to stderr
|
|
169
|
+
# (cross-bundle top-level const/let/class clashes, always_include double-declares)
|
|
170
|
+
bundle exec rails react_manifest:check
|
|
171
|
+
|
|
167
172
|
# Analyse which shared symbols are used per controller
|
|
168
173
|
bundle exec rails react_manifest:analyze
|
|
169
174
|
|
|
@@ -15,6 +15,9 @@ module ReactManifest
|
|
|
15
15
|
function __reactManifestExtractDefinitions(content) {
|
|
16
16
|
return JSON.stringify(__astExtractor.extractDefinitions(content));
|
|
17
17
|
}
|
|
18
|
+
function __reactManifestExtractLexicalBindings(content) {
|
|
19
|
+
return JSON.stringify(__astExtractor.extractLexicalBindings(content));
|
|
20
|
+
}
|
|
18
21
|
function __reactManifestExtractUsages(content) {
|
|
19
22
|
return JSON.stringify(__astExtractor.extractUsages(content));
|
|
20
23
|
}
|
|
@@ -31,6 +34,14 @@ module ReactManifest
|
|
|
31
34
|
nil
|
|
32
35
|
end
|
|
33
36
|
|
|
37
|
+
def extract_lexical_bindings(content, file_path: nil)
|
|
38
|
+
result = call_js("__reactManifestExtractLexicalBindings", content)
|
|
39
|
+
return result["bindings"] if result["success"]
|
|
40
|
+
|
|
41
|
+
report_error(file_path, result["error"])
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
|
|
34
45
|
def extract_usages(content, file_path: nil)
|
|
35
46
|
result = call_js("__reactManifestExtractUsages", content)
|
|
36
47
|
return result["usages"] if result["success"]
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
require "digest"
|
|
2
|
+
require "json"
|
|
3
|
+
require "set"
|
|
4
|
+
|
|
5
|
+
module ReactManifest
|
|
6
|
+
# The component-symbol -> bundle maps behind react_component bundle resolution.
|
|
7
|
+
#
|
|
8
|
+
# Parsing ux/app needs a V8 context (tens of MB per process), so the generator
|
|
9
|
+
# writes the maps to a JSON sidecar next to the generated manifests and the
|
|
10
|
+
# runtime loads that instead. The sidecar carries a fingerprint of everything the
|
|
11
|
+
# maps are derived from (gem version, config, controller dirs, file paths and
|
|
12
|
+
# contents); a missing, unreadable or mismatching sidecar falls back to parsing.
|
|
13
|
+
module ComponentIndex
|
|
14
|
+
FILENAME = "component_index.json".freeze
|
|
15
|
+
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
def path(config)
|
|
19
|
+
File.join(config.abs_manifest_dir, FILENAME)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Sidecar maps when fresh, else freshly parsed ones.
|
|
23
|
+
def maps(config)
|
|
24
|
+
controller_dirs = TreeClassifier.new(config).classify.controller_dirs
|
|
25
|
+
load_fresh(config, controller_dirs) || build(config, controller_dirs)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Write the sidecar (skipped when unchanged). Returns the path.
|
|
29
|
+
def write!(config, controller_dirs)
|
|
30
|
+
dest = path(config)
|
|
31
|
+
json = JSON.generate(serialize(config, controller_dirs, build(config, controller_dirs)))
|
|
32
|
+
return dest if File.exist?(dest) && File.read(dest, encoding: "utf-8") == json
|
|
33
|
+
|
|
34
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
|
35
|
+
File.write(dest, json, encoding: "utf-8")
|
|
36
|
+
dest
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def build(config, controller_dirs)
|
|
40
|
+
symbol_to_bundle = {}
|
|
41
|
+
bundle_own_symbols = Hash.new { |h, k| h[k] = Set.new }
|
|
42
|
+
bundle_files = Hash.new { |h, k| h[k] = [] }
|
|
43
|
+
bundle_dependencies = Hash.new { |h, k| h[k] = Set.new }
|
|
44
|
+
|
|
45
|
+
controller_dirs.each do |ctrl|
|
|
46
|
+
bundle_name = ctrl[:bundle_name]
|
|
47
|
+
files = js_files_in_controller(ctrl[:path], config)
|
|
48
|
+
bundle_files[bundle_name].concat(files)
|
|
49
|
+
isolated = config.isolated_app_dirs.include?(ctrl[:name])
|
|
50
|
+
|
|
51
|
+
files.each do |file_path|
|
|
52
|
+
extract(file_path, :extract_definitions).each do |symbol|
|
|
53
|
+
next unless symbol.match?(/\A[A-Z][A-Za-z0-9_]*\z/)
|
|
54
|
+
|
|
55
|
+
# Keep first writer to ensure deterministic behavior if a symbol is duplicated.
|
|
56
|
+
# Isolated dirs never register into the shared symbol index (see
|
|
57
|
+
# Generator#build_controller_context for the full rationale).
|
|
58
|
+
symbol_to_bundle[symbol] ||= bundle_name unless isolated
|
|
59
|
+
bundle_own_symbols[bundle_name] << symbol
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
bundle_files.each do |bundle_name, files|
|
|
65
|
+
own_symbols = bundle_own_symbols[bundle_name]
|
|
66
|
+
|
|
67
|
+
files.each do |file_path|
|
|
68
|
+
extract(file_path, :extract_usages).each do |symbol|
|
|
69
|
+
# A symbol the bundle defines itself is always satisfied locally —
|
|
70
|
+
# never attribute it to another bundle just because that symbol
|
|
71
|
+
# name happens to collide with something defined elsewhere.
|
|
72
|
+
next if own_symbols.include?(symbol)
|
|
73
|
+
|
|
74
|
+
dep_bundle = symbol_to_bundle[symbol]
|
|
75
|
+
next unless dep_bundle && dep_bundle != bundle_name
|
|
76
|
+
|
|
77
|
+
bundle_dependencies[bundle_name] << dep_bundle
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
{ symbol_to_bundle: symbol_to_bundle, bundle_dependencies: bundle_dependencies }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def load_fresh(config, controller_dirs)
|
|
86
|
+
data = JSON.parse(File.read(path(config), encoding: "utf-8"))
|
|
87
|
+
return unless data["fingerprint"] == fingerprint(config, controller_dirs)
|
|
88
|
+
|
|
89
|
+
bundle_dependencies = Hash.new { |h, k| h[k] = Set.new }
|
|
90
|
+
data["bundle_dependencies"].each { |bundle, deps| bundle_dependencies[bundle] = deps.to_set }
|
|
91
|
+
{ symbol_to_bundle: data["symbol_to_bundle"], bundle_dependencies: bundle_dependencies }
|
|
92
|
+
rescue StandardError
|
|
93
|
+
nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def serialize(config, controller_dirs, maps)
|
|
97
|
+
{
|
|
98
|
+
"fingerprint" => fingerprint(config, controller_dirs),
|
|
99
|
+
"symbol_to_bundle" => maps[:symbol_to_bundle],
|
|
100
|
+
"bundle_dependencies" => maps[:bundle_dependencies].transform_values { |deps| deps.to_a.sort }
|
|
101
|
+
}
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Digest of every input the maps depend on. File paths are relative to ux_root so
|
|
105
|
+
# a relocated release dir stays valid; contents (not mtimes) so a checkout that
|
|
106
|
+
# rewrites timestamps cannot make a stale sidecar look fresh or a fresh one stale.
|
|
107
|
+
def fingerprint(config, controller_dirs)
|
|
108
|
+
digest = Digest::SHA256.new
|
|
109
|
+
digest << JSON.generate([VERSION, config.extensions, config.isolated_app_dirs])
|
|
110
|
+
controller_dirs.each do |ctrl|
|
|
111
|
+
digest << "\0" << ctrl[:bundle_name]
|
|
112
|
+
js_files_in_controller(ctrl[:path], config).each do |file|
|
|
113
|
+
digest << "\0" << file.delete_prefix(config.abs_ux_root) << "\0" << File.binread(file)
|
|
114
|
+
rescue SystemCallError
|
|
115
|
+
digest << "\0unreadable"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
digest.hexdigest
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def js_files_in_controller(dir, config)
|
|
122
|
+
return [] unless Dir.exist?(dir)
|
|
123
|
+
|
|
124
|
+
Dir.glob(File.join(dir, "**", config.extensions_glob))
|
|
125
|
+
.reject { |f| File.directory?(f) }
|
|
126
|
+
.sort
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def extract(file_path, method)
|
|
130
|
+
content = File.read(file_path, encoding: "utf-8")
|
|
131
|
+
SymbolExtractor.public_send(method, content, file_path: file_path)
|
|
132
|
+
rescue Errno::ENOENT, Errno::EACCES, Encoding::InvalidByteSequenceError
|
|
133
|
+
[]
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -21,9 +21,18 @@ module ReactManifest
|
|
|
21
21
|
# Keeping generated files out of output_dir root avoids clutter.
|
|
22
22
|
attr_accessor :manifest_subdir
|
|
23
23
|
|
|
24
|
+
# When true (default), the gem ensures the generated manifest dir is gitignored
|
|
25
|
+
# (adds the entry on dev boot if missing). Set false to manage .gitignore yourself.
|
|
26
|
+
attr_accessor :manage_gitignore
|
|
27
|
+
|
|
24
28
|
# Bundle name for auto-generated shared bundle (all non-app/ dirs)
|
|
25
29
|
attr_accessor :shared_bundle
|
|
26
30
|
|
|
31
|
+
# When true (default), a component defined under app_dir but used by any other
|
|
32
|
+
# bundle is emitted into the shared bundle (loaded once per page) instead of
|
|
33
|
+
# being inlined into each consumer. Set false to restore legacy inlining.
|
|
34
|
+
attr_accessor :auto_shared
|
|
35
|
+
|
|
27
36
|
# Bundles always prepended by react_bundle_tag (e.g. ["ux_main"])
|
|
28
37
|
attr_accessor :always_include
|
|
29
38
|
|
|
@@ -101,7 +110,9 @@ module ReactManifest
|
|
|
101
110
|
@app_dir = "app"
|
|
102
111
|
@output_dir = "app/assets/javascripts"
|
|
103
112
|
@manifest_subdir = "ux_manifests"
|
|
113
|
+
@manage_gitignore = true
|
|
104
114
|
@shared_bundle = "ux_shared"
|
|
115
|
+
@auto_shared = true
|
|
105
116
|
@always_include = []
|
|
106
117
|
@ignore = []
|
|
107
118
|
@isolated_app_dirs = []
|
|
@@ -119,6 +130,10 @@ module ReactManifest
|
|
|
119
130
|
!!@dry_run
|
|
120
131
|
end
|
|
121
132
|
|
|
133
|
+
def auto_shared?
|
|
134
|
+
!!@auto_shared
|
|
135
|
+
end
|
|
136
|
+
|
|
122
137
|
def verbose?
|
|
123
138
|
!!@verbose
|
|
124
139
|
end
|
|
@@ -127,6 +142,10 @@ module ReactManifest
|
|
|
127
142
|
!!@stdout_logging
|
|
128
143
|
end
|
|
129
144
|
|
|
145
|
+
def manage_gitignore?
|
|
146
|
+
!!@manage_gitignore
|
|
147
|
+
end
|
|
148
|
+
|
|
130
149
|
# Glob fragment used by Dir.glob, e.g. "*.{js,jsx}" or "*.{js,jsx,ts,tsx}"
|
|
131
150
|
def extensions_glob
|
|
132
151
|
"*.{#{extensions.join(',')}}"
|