txlemetry-react-native 4.55.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 (123) hide show
  1. package/LICENSE +353 -0
  2. package/README.md +13 -0
  3. package/dist/PostHogContext.d.ts +5 -0
  4. package/dist/PostHogContext.js +1 -0
  5. package/dist/PostHogErrorBoundary.d.ts +27 -0
  6. package/dist/PostHogErrorBoundary.js +1 -0
  7. package/dist/PostHogMaskView.d.ts +39 -0
  8. package/dist/PostHogMaskView.js +1 -0
  9. package/dist/PostHogProvider.d.ts +100 -0
  10. package/dist/PostHogProvider.js +1 -0
  11. package/dist/autocapture.d.ts +4 -0
  12. package/dist/autocapture.js +1 -0
  13. package/dist/error-tracking/index.d.ts +98 -0
  14. package/dist/error-tracking/index.js +1 -0
  15. package/dist/error-tracking/utils.d.ts +5 -0
  16. package/dist/error-tracking/utils.js +1 -0
  17. package/dist/frameworks/wix-navigation.d.ts +3 -0
  18. package/dist/frameworks/wix-navigation.js +1 -0
  19. package/dist/hooks/useFeatureFlag.d.ts +5 -0
  20. package/dist/hooks/useFeatureFlag.js +1 -0
  21. package/dist/hooks/useFeatureFlagResult.d.ts +3 -0
  22. package/dist/hooks/useFeatureFlagResult.js +1 -0
  23. package/dist/hooks/useFeatureFlags.d.ts +3 -0
  24. package/dist/hooks/useFeatureFlags.js +1 -0
  25. package/dist/hooks/useNavigationTracker.d.ts +6 -0
  26. package/dist/hooks/useNavigationTracker.js +1 -0
  27. package/dist/hooks/usePostHog.d.ts +2 -0
  28. package/dist/hooks/usePostHog.js +1 -0
  29. package/dist/hooks/utils.d.ts +14 -0
  30. package/dist/hooks/utils.js +1 -0
  31. package/dist/index.d.ts +14 -0
  32. package/dist/index.js +1 -0
  33. package/dist/index.txlemetry.d.ts +36 -0
  34. package/dist/index.txlemetry.js +21 -0
  35. package/dist/logs-defaults.d.ts +9 -0
  36. package/dist/logs-defaults.js +1 -0
  37. package/dist/native-deps.d.ts +4 -0
  38. package/dist/native-deps.js +1 -0
  39. package/dist/optional/OptionalAsyncStorage.d.ts +2 -0
  40. package/dist/optional/OptionalAsyncStorage.js +1 -0
  41. package/dist/optional/OptionalExpoApplication.d.ts +2 -0
  42. package/dist/optional/OptionalExpoApplication.js +1 -0
  43. package/dist/optional/OptionalExpoDevice.d.ts +2 -0
  44. package/dist/optional/OptionalExpoDevice.js +1 -0
  45. package/dist/optional/OptionalExpoFileSystem.d.ts +2 -0
  46. package/dist/optional/OptionalExpoFileSystem.js +1 -0
  47. package/dist/optional/OptionalExpoFileSystemLegacy.d.ts +2 -0
  48. package/dist/optional/OptionalExpoFileSystemLegacy.js +1 -0
  49. package/dist/optional/OptionalExpoLocalization.d.ts +2 -0
  50. package/dist/optional/OptionalExpoLocalization.js +1 -0
  51. package/dist/optional/OptionalPlugin.d.ts +20 -0
  52. package/dist/optional/OptionalPlugin.js +1 -0
  53. package/dist/optional/OptionalReactNativeDeviceInfo.d.ts +2 -0
  54. package/dist/optional/OptionalReactNativeDeviceInfo.js +1 -0
  55. package/dist/optional/OptionalReactNativeLocalize.d.ts +13 -0
  56. package/dist/optional/OptionalReactNativeLocalize.js +1 -0
  57. package/dist/optional/OptionalReactNativeNavigation.d.ts +2 -0
  58. package/dist/optional/OptionalReactNativeNavigation.js +1 -0
  59. package/dist/optional/OptionalReactNativeNavigationWix.d.ts +2 -0
  60. package/dist/optional/OptionalReactNativeNavigationWix.js +1 -0
  61. package/dist/optional/OptionalReactNativeSafeArea.d.ts +2 -0
  62. package/dist/optional/OptionalReactNativeSafeArea.js +1 -0
  63. package/dist/optional/OptionalReactNativeSvg.d.ts +2 -0
  64. package/dist/optional/OptionalReactNativeSvg.js +1 -0
  65. package/dist/posthog-rn.d.ts +1096 -0
  66. package/dist/posthog-rn.js +1 -0
  67. package/dist/storage.d.ts +41 -0
  68. package/dist/storage.js +1 -0
  69. package/dist/surveys/PostHogSurveyProvider.d.ts +23 -0
  70. package/dist/surveys/PostHogSurveyProvider.js +1 -0
  71. package/dist/surveys/components/BottomSection.d.ts +9 -0
  72. package/dist/surveys/components/BottomSection.js +1 -0
  73. package/dist/surveys/components/Cancel.d.ts +5 -0
  74. package/dist/surveys/components/Cancel.js +1 -0
  75. package/dist/surveys/components/ConfirmationMessage.d.ts +12 -0
  76. package/dist/surveys/components/ConfirmationMessage.js +1 -0
  77. package/dist/surveys/components/QuestionHeader.d.ts +8 -0
  78. package/dist/surveys/components/QuestionHeader.js +1 -0
  79. package/dist/surveys/components/QuestionTypes.d.ts +26 -0
  80. package/dist/surveys/components/QuestionTypes.js +1 -0
  81. package/dist/surveys/components/SurveyModal.d.ts +11 -0
  82. package/dist/surveys/components/SurveyModal.js +1 -0
  83. package/dist/surveys/components/Surveys.d.ts +16 -0
  84. package/dist/surveys/components/Surveys.js +1 -0
  85. package/dist/surveys/getActiveMatchingSurveys.d.ts +2 -0
  86. package/dist/surveys/getActiveMatchingSurveys.js +1 -0
  87. package/dist/surveys/icons.d.ts +11 -0
  88. package/dist/surveys/icons.js +1 -0
  89. package/dist/surveys/index.d.ts +6 -0
  90. package/dist/surveys/index.js +1 -0
  91. package/dist/surveys/safeStyleSheet.d.ts +8 -0
  92. package/dist/surveys/safeStyleSheet.js +1 -0
  93. package/dist/surveys/survey-translations.d.ts +7 -0
  94. package/dist/surveys/survey-translations.js +1 -0
  95. package/dist/surveys/surveys-utils.d.ts +54 -0
  96. package/dist/surveys/surveys-utils.js +1 -0
  97. package/dist/surveys/useActivatedSurveys.d.ts +3 -0
  98. package/dist/surveys/useActivatedSurveys.js +1 -0
  99. package/dist/surveys/useSurveyStorage.d.ts +8 -0
  100. package/dist/surveys/useSurveyStorage.js +1 -0
  101. package/dist/tooling/expoconfig.d.ts +64 -0
  102. package/dist/tooling/expoconfig.js +1 -0
  103. package/dist/tooling/metroconfig.d.ts +21 -0
  104. package/dist/tooling/metroconfig.js +1 -0
  105. package/dist/tooling/posthogMetroSerializer.d.ts +17 -0
  106. package/dist/tooling/posthogMetroSerializer.js +1 -0
  107. package/dist/tooling/utils.d.ts +58 -0
  108. package/dist/tooling/utils.js +1 -0
  109. package/dist/tooling/vendor/expo/expoconfig.d.ts +23 -0
  110. package/dist/tooling/vendor/expo/expoconfig.js +1 -0
  111. package/dist/tooling/vendor/metro/countLines.d.ts +2 -0
  112. package/dist/tooling/vendor/metro/countLines.js +1 -0
  113. package/dist/tooling/vendor/metro/utils.d.ts +22 -0
  114. package/dist/tooling/vendor/metro/utils.js +1 -0
  115. package/dist/types.d.ts +205 -0
  116. package/dist/types.js +1 -0
  117. package/dist/utils.d.ts +25 -0
  118. package/dist/utils.js +1 -0
  119. package/dist/version.d.ts +1 -0
  120. package/dist/version.js +1 -0
  121. package/package.json +149 -0
  122. package/tooling/txlemetry-xcode.sh +222 -0
  123. package/tooling/txlemetry.gradle +407 -0
@@ -0,0 +1,407 @@
1
+ // Portions of this file are derived from getsentry/sentry-react-native
2
+ // Copyright (c) 2017 Sentry
3
+ // Licensed under the MIT License: https://github.com/getsentry/sentry-react-native/blob/main/LICENSE.md
4
+
5
+ import org.apache.tools.ant.taskdefs.condition.Os
6
+
7
+ import java.util.regex.Matcher
8
+ import java.util.regex.Pattern
9
+
10
+ import org.gradle.api.logging.Logging
11
+
12
+ interface InjectedExecOps {
13
+ @Inject //@javax.inject.Inject
14
+ ExecOperations getExecOps()
15
+ }
16
+
17
+ plugins.withId('com.android.application') {
18
+ def androidComponents = extensions.getByName("androidComponents")
19
+
20
+ androidComponents.onVariants(androidComponents.selector().all()) { v ->
21
+ if (!v.name.toLowerCase().contains("debug")) {
22
+ // separately we then hook into the bundle task of react native to inject
23
+ // sourcemap generation parameters. In case for whatever reason no release
24
+ // was found for the asset folder we just bail.
25
+ def bundleTasks = tasks.findAll { task -> (task.name.startsWith("createBundle") || task.name.startsWith("bundle")) && task.name.endsWith("JsAndAssets") && !task.name.contains("Debug") && task.enabled }
26
+ // this is the task that calls react-native bundle {params}
27
+ bundleTasks.each { bundleTask ->
28
+ def shouldCleanUp
29
+ def sourcemapOutput
30
+ def bundleOutput
31
+ def packagerSourcemapOutput
32
+ def bundleCommand
33
+ def props = bundleTask.getProperties()
34
+ def reactRoot = props.get("workingDir")
35
+ if (reactRoot == null) {
36
+ reactRoot = props.get("root").get() // RN 0.71 and above
37
+ }
38
+
39
+ (shouldCleanUp, bundleOutput, sourcemapOutput, packagerSourcemapOutput, bundleCommand) = forceSourceMapOutputFromBundleTask(bundleTask)
40
+
41
+ // Lets leave this here if we need to debug
42
+ // println bundleTask.properties
43
+ // .sort{it.key}
44
+ // .collect{it}
45
+ // .findAll{!['class', 'active'].contains(it.key)}
46
+ // .join('\n')
47
+
48
+ def currentVariants = extractCurrentVariants(bundleTask, v)
49
+ if (currentVariants == null) return
50
+
51
+ def previousCliTask = null
52
+ def applicationVariant = null
53
+
54
+ def nameCleanup = "${bundleTask.name}_TxlemetryUploadCleanUp"
55
+ // Upload the source map several times if necessary: once for each release and versionCode.
56
+ currentVariants.each { key, currentVariant ->
57
+ def variant = currentVariant[0]
58
+ def releaseName = currentVariant[1]
59
+ def versionCode = currentVariant[2]
60
+ applicationVariant = currentVariant[3]
61
+ def appId = currentVariant[4]
62
+ def versionName = currentVariant[5]
63
+
64
+ try {
65
+ if (versionCode instanceof String) {
66
+ versionCode = Integer.parseInt(versionCode)
67
+ versionCode = Math.abs(versionCode)
68
+ }
69
+ } catch (NumberFormatException e) {
70
+ project.logger.info("versionCode: '$versionCode' isn't an Integer, using the plain value.")
71
+ }
72
+
73
+ def nameCliTask = "${bundleTask.name}_TxlemetryUpload_${releaseName}_${versionCode}"
74
+
75
+ // If several outputs have the same releaseName and versionCode, we'd do the exact same
76
+ // upload for each of them. No need to repeat.
77
+ try { tasks.named(nameCliTask); return } catch (Exception e) {}
78
+
79
+ /** Upload source map file to the Txlemetry server via CLI call. */
80
+ def cliTask = tasks.register(nameCliTask) {
81
+ description = "upload sourcemaps to Txlemetry"
82
+ group = 'txlemetry.com'
83
+
84
+ def extraArgs = []
85
+ if (appId != null && !appId.isEmpty()) {
86
+ extraArgs.addAll(["--release-name", appId.toString()])
87
+ }
88
+ if (versionName != null && !versionName.toString().isEmpty()) {
89
+ extraArgs.addAll(["--release-version", versionName.toString()])
90
+ }
91
+ if (versionCode != null) {
92
+ extraArgs.addAll(["--build", versionCode.toString()])
93
+ }
94
+
95
+ def txlemetryUploadArgs = []
96
+ if ((project.ext.has("txlemetryReactNativeSkipOnConflict") && project.ext.get("txlemetryReactNativeSkipOnConflict") == true) ||
97
+ (project.ext.has("posthogReactNativeSkipOnConflict") && project.ext.get("posthogReactNativeSkipOnConflict") == true)) {
98
+ txlemetryUploadArgs.add("--skip-on-conflict")
99
+ }
100
+
101
+ def injected = project.objects.newInstance(InjectedExecOps)
102
+
103
+ // Resolve the txlemetry-cli path at execution time, not during
104
+ // configuration. The resolver starts node/npm via Groovy's `.execute()`,
105
+ // and Gradle's configuration cache forbids starting external processes at
106
+ // configuration time. Resolution lives in the static
107
+ // TxlemetryCli.resolveCliPackagePath() so these serialized task actions can
108
+ // call it without relying on the apply-from script's owner chain — a
109
+ // script-level method fails under the configuration cache with "Could not
110
+ // find method ... on object of type DefaultExecAction_Decorated". rootDir
111
+ // is captured as plain serializable state; `Task.project` must not be read
112
+ // at execution time, so logging uses the task's own `logger`.
113
+ def rootDirFile = rootDir
114
+ def osCompatibility = Os.isFamily(Os.FAMILY_WINDOWS) ? ['cmd', '/c', 'node'] : []
115
+
116
+ doFirst {
117
+ def cliPackage = TxlemetryCli.resolveCliPackagePath(rootDirFile, reactRoot)
118
+ def args = [cliPackage]
119
+ args.addAll(["hermes", "clone",
120
+ "--minified-map-path", packagerSourcemapOutput, // The path to a sourcemap
121
+ "--composed-map-path", sourcemapOutput // The path of the composed source map
122
+ ])
123
+ args.addAll(extraArgs)
124
+ logger.info("txlemetry-cli clone arguments: ${args}")
125
+
126
+ injected.execOps.exec {
127
+ workingDir reactRoot
128
+ commandLine(*osCompatibility, *args)
129
+ }
130
+ }
131
+
132
+ doLast {
133
+ def cliPackage = TxlemetryCli.resolveCliPackagePath(rootDirFile, reactRoot)
134
+ def args = [cliPackage]
135
+ args.addAll(["hermes", "upload",
136
+ "--directory", sourcemapOutput.getParent() // The path to a sourcemap that should be uploaded.
137
+ ])
138
+ args.addAll(extraArgs)
139
+ args.addAll(txlemetryUploadArgs)
140
+ logger.info("txlemetry-cli upload arguments: ${args}")
141
+
142
+ injected.execOps.exec {
143
+ workingDir reactRoot
144
+ commandLine(*osCompatibility, *args)
145
+ }
146
+ }
147
+
148
+ enabled true
149
+ }
150
+
151
+ // chain the upload tasks so they run sequentially in order to run
152
+ // the cliCleanUpTask after the final upload task is run
153
+ if (previousCliTask != null) {
154
+ previousCliTask.configure { finalizedBy cliTask }
155
+ } else {
156
+ bundleTask.configure { finalizedBy cliTask }
157
+ }
158
+ previousCliTask = cliTask
159
+ }
160
+
161
+ /** Delete sourcemap files */
162
+ def cliCleanUpTask = tasks.register(nameCleanup, Delete) {
163
+ description = "clean up extra sourcemap"
164
+ group = 'txlemetry.com'
165
+
166
+ delete sourcemapOutput
167
+ delete "$buildDir/intermediates/assets/release/index.android.bundle.map"
168
+ // react native default bundle dir
169
+ }
170
+
171
+ // register clean task extension
172
+ cliCleanUpTask.configure { onlyIf { shouldCleanUp } }
173
+ // due to chaining the last value of previousCliTask will be the final
174
+ // upload task, after which the cleanup can be done
175
+ previousCliTask.configure { finalizedBy cliCleanUpTask }
176
+
177
+ def packageTasks = tasks.matching {
178
+ task -> ("package${applicationVariant}".equalsIgnoreCase(task.name) || "package${applicationVariant}Bundle".equalsIgnoreCase(task.name)) && task.enabled
179
+ }
180
+ }
181
+ }
182
+ }
183
+ }
184
+
185
+ // Static so the serialized sourcemap-upload task actions can call it under the
186
+ // Gradle configuration cache. It starts node/npm, so it must run at execution
187
+ // time — starting external processes at configuration time is rejected by the
188
+ // configuration cache. Uses its own logger (not `project.logger`) and takes
189
+ // rootDir as a parameter so it never touches `Task.project` at execution time.
190
+ abstract class TxlemetryCli {
191
+ static String resolveCliPackagePath(File rootDir, reactRoot) {
192
+ def logger = Logging.getLogger(TxlemetryCli)
193
+
194
+ // First, try to find @txlemetry/cli folder from require.resolve
195
+ try {
196
+ def resolvedPath = new File(["node", "--print", "require.resolve('@txlemetry/cli/package.json')"].execute(null, rootDir).text.trim()).getParentFile()
197
+ if (resolvedPath != null && resolvedPath.exists()) {
198
+ def runTxlemetryCliFile = new File(resolvedPath, "run-txlemetry-cli.js")
199
+ if (runTxlemetryCliFile.exists()) {
200
+ logger.info("resolved txlemetry-cli dynamically: `${runTxlemetryCliFile.getAbsolutePath()}`")
201
+ return runTxlemetryCliFile.getAbsolutePath()
202
+ }
203
+ }
204
+ } catch (Throwable ignored) {}
205
+
206
+ // Second, check if @txlemetry/cli exists in $reactRoot/node_modules
207
+ def nodeModulesPath = new File("$reactRoot/node_modules/@txlemetry/cli")
208
+ if (nodeModulesPath.exists()) {
209
+ def runTxlemetryCliFile = new File(nodeModulesPath, "run-txlemetry-cli.js")
210
+ if (runTxlemetryCliFile.exists()) {
211
+ logger.info("resolved txlemetry-cli hard-coded path (yarn or npm): `${runTxlemetryCliFile.getAbsolutePath()}`")
212
+ return runTxlemetryCliFile.getAbsolutePath()
213
+ }
214
+ }
215
+
216
+ // Third, check for pnpm installation with node_modules/.bin/txlemetry-cli
217
+ def pnpmBinPath = new File("$reactRoot/node_modules/.bin/txlemetry-cli")
218
+ if (pnpmBinPath.exists()) {
219
+ logger.info("resolved txlemetry-cli hard-coded path (pnpm): `${pnpmBinPath.getAbsolutePath()}`")
220
+ return pnpmBinPath.getAbsolutePath()
221
+ }
222
+
223
+ // Fourth, check using npm root for local installation
224
+ try {
225
+ def npmRoot = ["npm", "root"].execute(null, rootDir).text.trim()
226
+ def npmTxlemetryCliPath = new File(npmRoot, "@txlemetry/cli")
227
+ if (npmTxlemetryCliPath.exists()) {
228
+ def runTxlemetryCliFile = new File(npmTxlemetryCliPath, "run-txlemetry-cli.js")
229
+ if (runTxlemetryCliFile.exists()) {
230
+ logger.info("resolved txlemetry-cli via npm root: `${runTxlemetryCliFile.getAbsolutePath()}`")
231
+ return runTxlemetryCliFile.getAbsolutePath()
232
+ }
233
+ }
234
+ } catch (Throwable ignored) {}
235
+
236
+ // Fifth, check for global npm installation of @txlemetry/cli
237
+ try {
238
+ def globalPrefix = ["npm", "prefix", "-g"].execute().text.trim()
239
+ def globalTxlemetryCliPath = new File(globalPrefix, "lib/node_modules/@txlemetry/cli")
240
+ if (globalTxlemetryCliPath.exists()) {
241
+ def runTxlemetryCliFile = new File(globalTxlemetryCliPath, "run-txlemetry-cli.js")
242
+ if (runTxlemetryCliFile.exists()) {
243
+ logger.info("resolved txlemetry-cli from global npm installation: `${runTxlemetryCliFile.getAbsolutePath()}`")
244
+ return runTxlemetryCliFile.getAbsolutePath()
245
+ }
246
+ }
247
+ } catch (Throwable ignored) {}
248
+
249
+ // Finally, fallback to global install
250
+ logger.info("falling back to global txlemetry-cli")
251
+ return "txlemetry-cli"
252
+ }
253
+ }
254
+
255
+ def resolveTxlemetryReactNativeSDKPath(reactRoot) {
256
+ def resolvedPath = null
257
+ try {
258
+ resolvedPath = new File(["node", "--print", "require.resolve('txlemetry-react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile();
259
+ } catch (Throwable ignored) {} // if the resolve fails we fallback to the default path
260
+ def packagePath = resolvedPath != null && resolvedPath.exists() ? resolvedPath.getAbsolutePath() : "$reactRoot/node_modules/txlemetry-react-native"
261
+ return packagePath
262
+ }
263
+
264
+ /** Extract from arguments collection bundle and sourcemap files output names. */
265
+ static extractBundleTaskArgumentsLegacy(cmdArgs, Project project) {
266
+ def bundleOutput = null
267
+ def sourcemapOutput = null
268
+ def packagerSourcemapOutput = null
269
+ // packagerBundleOutput doesn't exist, because packager output is overwritten by Hermes
270
+
271
+ cmdArgs.eachWithIndex { String arg, int i ->
272
+ if (arg == "--bundle-output") {
273
+ bundleOutput = cmdArgs[i + 1]
274
+ project.logger.info("--bundle-output: `${bundleOutput}`")
275
+ } else if (arg == "--sourcemap-output") {
276
+ sourcemapOutput = cmdArgs[i + 1]
277
+ packagerSourcemapOutput = sourcemapOutput
278
+ project.logger.info("--sourcemap-output param: `${sourcemapOutput}`")
279
+ }
280
+ }
281
+
282
+ // Best thing would be if we just had access to the local gradle variables here:
283
+ // https://github.com/facebook/react-native/blob/ff3b839e9a5a6c9e398a1327cde6dd49a3593092/react.gradle#L89-L97
284
+ // Now, the issue is that hermes builds have a different pipeline:
285
+ // `metro -> hermes -> compose-source-maps`, which then combines both intermediate sourcemaps into the final one.
286
+ // In this function here, we only grep through the first `metro` step, which only generates an intermediate sourcemap,
287
+ // which is wrong. We need the final one. Luckily, we can just generate the path from the `bundleOutput`, since
288
+ // the paths seem to be well defined.
289
+
290
+ // if sourcemapOutput is null, it means there's no source maps at all
291
+ // if hermes is enabled and has intermediates folder, we need to fix paths
292
+ // if hermes is disabled, sourcemapOutput is already ok
293
+ def enableHermes = project.ext.react.get("enableHermes", false);
294
+ project.logger.info("enableHermes: `${enableHermes}`")
295
+
296
+ if (bundleOutput != null && sourcemapOutput != null && enableHermes) {
297
+ // react-native < 0.60.1
298
+ def pattern = Pattern.compile("(/|\\\\)intermediates\\1sourcemaps\\1react\\1")
299
+ Matcher matcher = pattern.matcher(sourcemapOutput)
300
+ // if its intermediates/sourcemaps/react then it should be generated/sourcemaps/react
301
+ if (matcher.find()) {
302
+ project.logger.info("sourcemapOutput has the wrong path, let's fix it.")
303
+ // replacing from bundleOutput which is more reliable
304
+ sourcemapOutput = bundleOutput.replaceAll("(/|\\\\)generated\\1assets\\1react\\1", "\$1generated\$1sourcemaps\$1react\$1") + ".map"
305
+ project.logger.info("sourcemapOutput new path: `${sourcemapOutput}`")
306
+ }
307
+ }
308
+
309
+ // get the current bundle command, if not peresent use default plain "bundle"
310
+ // we use this later to decide how to upload source maps
311
+ def bundleCommand = project.ext.react.get("bundleCommand", "bundle")
312
+
313
+ return [bundleOutput, sourcemapOutput, packagerSourcemapOutput, bundleCommand]
314
+ }
315
+
316
+ /** Extract bundle and sourcemap paths from bundle task props.
317
+ * Based on https://github.com/facebook/react-native/blob/93c17cd0c43ba7fe3bc09f547b64771984992fbb/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt
318
+ * Output source map path is the same for both Hermes and JSC.
319
+ */
320
+ static extractBundleTaskArgumentsRN71AndAbove(bundleTask, logger) {
321
+ def props = bundleTask.getProperties()
322
+ def bundleAssetName = props.bundleAssetName?.get()
323
+
324
+ if (bundleAssetName == null) {
325
+ return [null, null]
326
+ }
327
+
328
+ def bundleCommand = props.bundleCommand.get()
329
+ def bundleFile = new File(props.jsBundleDir.get().asFile.absolutePath, bundleAssetName)
330
+ def outputSourceMap = new File(props.jsSourceMapsDir.get().asFile.absolutePath, "${bundleAssetName}.map")
331
+ def packagerOutputSourceMap = new File(props.jsIntermediateSourceMapsDir.get().asFile.absolutePath, "${bundleAssetName}.packager.map")
332
+
333
+ logger.info("bundleFile: `${bundleFile}`")
334
+ logger.info("outputSourceMap: `${outputSourceMap}`")
335
+ logger.info("packagerOutputSourceMap: `${packagerOutputSourceMap}`")
336
+ return [bundleFile, outputSourceMap, packagerOutputSourceMap, bundleCommand]
337
+ }
338
+
339
+ /** Force Bundle task to produce sourcemap files if they are not pre-configured by user yet. */
340
+ def forceSourceMapOutputFromBundleTask(bundleTask) {
341
+ def props = bundleTask.getProperties()
342
+ def cmd = props.get("commandLine") as List<String>
343
+ def cmdArgs = props.get("args") as List<String>
344
+ def shouldCleanUp = false
345
+ def bundleOutput = null
346
+ def sourcemapOutput = null
347
+ def packagerSourcemapOutput = null
348
+ def bundleCommand = null
349
+
350
+ (bundleOutput, sourcemapOutput, packagerSourcemapOutput, bundleCommand) = extractBundleTaskArgumentsRN71AndAbove(bundleTask, logger)
351
+ if (bundleOutput == null) {
352
+ (bundleOutput, sourcemapOutput, packagerSourcemapOutput, bundleCommand) = extractBundleTaskArgumentsLegacy(cmdArgs, project)
353
+ }
354
+
355
+ if (sourcemapOutput == null) {
356
+ sourcemapOutput = bundleOutput + ".map"
357
+
358
+ cmd.addAll(["--sourcemap-output", sourcemapOutput])
359
+ cmdArgs.addAll(["--sourcemap-output", sourcemapOutput])
360
+
361
+ shouldCleanUp = true
362
+
363
+ bundleTask.setProperty("commandLine", cmd)
364
+ bundleTask.setProperty("args", cmdArgs)
365
+
366
+ project.logger.info("forced sourcemap file output for `${bundleTask.name}` task")
367
+ } else {
368
+ project.logger.info("Info: used pre-configured source map files: ${sourcemapOutput}")
369
+ }
370
+
371
+ return [shouldCleanUp, bundleOutput, sourcemapOutput, packagerSourcemapOutput, bundleCommand]
372
+ }
373
+
374
+ /** compose array with one item - current build flavor name */
375
+ static extractCurrentVariants(bundleTask, variant) {
376
+ // examples: bundleLocalReleaseJsAndAssets, createBundleYellowDebugJsAndAssets
377
+ def pattern = Pattern.compile("(?:create)?(?:B|b)undle([A-Z][A-Za-z0-9_]+)JsAndAssets")
378
+
379
+ def currentRelease = ""
380
+
381
+ Matcher matcher = pattern.matcher(bundleTask.name)
382
+ if (matcher.find()) {
383
+ def match = matcher.group(1)
384
+ currentRelease = match.substring(0, 1).toLowerCase() + match.substring(1)
385
+ }
386
+
387
+ def currentVariants = null
388
+ if (variant.name.equalsIgnoreCase(currentRelease)) {
389
+ currentVariants = [:]
390
+ def variantName = variant.name
391
+ variant.outputs.each { output ->
392
+ def defaultVersionCode = output.versionCode.getOrElse(0)
393
+ def versionCode = defaultVersionCode
394
+ def appId = variant.applicationId.get()
395
+ def versionName = output.versionName.getOrElse('') // may be empty if not set
396
+ def defaultReleaseName = "${appId}@${versionName}+${versionCode}"
397
+ def releaseName = defaultReleaseName
398
+
399
+ def outputName = output.baseName
400
+
401
+ if (currentVariants[outputName] == null) currentVariants[outputName] = []
402
+ currentVariants[outputName] = [outputName, releaseName, versionCode, variantName, appId, versionName]
403
+ }
404
+ }
405
+
406
+ return currentVariants
407
+ }