@dynatrace/react-native-plugin 2.335.1 → 2.337.2

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 (35) hide show
  1. package/README.md +145 -61
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +1 -1
  4. package/files/plugin.gradle +1 -1
  5. package/instrumentation/BabelPluginDynatrace.js +1 -1
  6. package/instrumentation/DynatraceInstrumentation.js +1 -1
  7. package/instrumentation/libs/community/Picker.js +1 -1
  8. package/instrumentation/libs/react-navigation/ReactNavigation.js +9 -0
  9. package/instrumentation/libs/withOnPressMonitoring.js +59 -14
  10. package/lib/core/Dynatrace.js +3 -0
  11. package/lib/core/DynatraceBridge.js +5 -7
  12. package/lib/core/configuration/ActionNameOptions.js +2 -0
  13. package/lib/core/configuration/Configuration.js +5 -1
  14. package/lib/core/configuration/ConfigurationBuilder.js +11 -1
  15. package/lib/core/configuration/ConfigurationDefaults.js +3 -1
  16. package/lib/core/configuration/ConfigurationHandler.js +64 -0
  17. package/lib/core/configuration/ConfigurationPreset.js +6 -0
  18. package/lib/core/configuration/ManualStartupConfiguration.js +9 -1
  19. package/lib/features/ui-interaction/Runtime.js +31 -19
  20. package/lib/next/Dynatrace.js +44 -0
  21. package/lib/next/configuration/INativeRuntimeConfiguration.js +9 -0
  22. package/lib/next/configuration/RuntimeConfigurationObserver.js +50 -6
  23. package/lib/next/events/EventPipeline.js +14 -6
  24. package/lib/next/events/HttpRequestEventData.js +26 -30
  25. package/lib/next/provider/TimestampProvider.js +20 -7
  26. package/lib/next/util/TraceContextUtils.js +108 -0
  27. package/package.json +4 -3
  28. package/react-native-dynatrace.podspec +1 -1
  29. package/scripts/Android.js +27 -10
  30. package/scripts/Config.js +1 -1
  31. package/scripts/Ios.js +288 -71
  32. package/scripts/PathsConstants.js +34 -20
  33. package/scripts/core/InstrumentCall.js +7 -1
  34. package/scripts/util/SourceMapUtil.js +49 -11
  35. package/types.d.ts +178 -39
package/scripts/Ios.js CHANGED
@@ -1,63 +1,68 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- const nodePath = require("path");
4
+ const nodePath = require("node:path");
5
+ const fs = require("node:fs");
5
6
  const plist_1 = require("plist");
6
7
  const Logger_1 = require("./Logger");
7
8
  const FileOperationHelper_1 = require("./FileOperationHelper");
8
9
  const PathsConstants_1 = require("./PathsConstants");
9
10
  const PlistConstants_1 = require("./util/PlistConstants");
11
+ const NON_APP_TARGET_SEGMENTS = new Set(['test', 'tests', 'uitest', 'uitests', 'tvos', 'watch', 'widget', 'extension', 'appex']);
12
+ const NON_APP_TARGET_SEGMENT_SUFFIXES = ['tests', 'uitests', 'tvos', 'watch', 'widget', 'extension', 'appex'];
13
+ const isNonAppTargetPath = (filePath) => {
14
+ const normalizedSegments = filePath
15
+ .toLowerCase()
16
+ .split(/[\\/]+/)
17
+ .filter((segment) => segment.length > 0);
18
+ const directorySegments = normalizedSegments.slice(0, -1);
19
+ const candidateSegments = directorySegments.slice(-3);
20
+ return candidateSegments.some((segment) => NON_APP_TARGET_SEGMENTS.has(segment) ||
21
+ NON_APP_TARGET_SEGMENT_SUFFIXES.some((suffix) => segment.endsWith(suffix)));
22
+ };
10
23
  const modifyPListFile = (pathToPList, iosConfig, removeOnly) => {
24
+ const resolvedPListPath = resolvePListPath(pathToPList);
25
+ if (removeOnly) {
26
+ removePListConfig(resolvedPListPath);
27
+ return;
28
+ }
29
+ const configProps = iosConfig === null || iosConfig === void 0 ? void 0 : iosConfig.config;
30
+ if (iosConfig === undefined || configProps == null) {
31
+ throw new Error("Can't write configuration of iOS agent because it is missing!");
32
+ }
33
+ if (hasDuplicateProperties(configProps)) {
34
+ throw new Error('Duplicate properties found! Please remove duplicates and try again.');
35
+ }
36
+ validateAutoStartConfiguration(configProps);
37
+ createNewPListIfRequired(parsePList(resolvedPListPath), configProps, resolvedPListPath);
38
+ };
39
+ const resolvePListPath = (pathToPList) => {
11
40
  if (pathToPList === undefined) {
12
- pathToPList = findPListFile();
41
+ return findPListFile();
13
42
  }
14
- else {
15
- if (!pathToPList.endsWith('.plist')) {
16
- throw new Error("Can't find .plist file. plist path must also include the plist file!");
17
- }
18
- try {
19
- FileOperationHelper_1.default.checkIfFileExistsSync(pathToPList);
20
- }
21
- catch (e) {
22
- throw new Error('Could not read plist file: ' + pathToPList);
23
- }
43
+ if (!pathToPList.endsWith('.plist')) {
44
+ throw new Error("Can't find .plist file. plist path must also include the plist file!");
24
45
  }
25
- const parsedPList = parsePList(pathToPList);
26
- const configProps = iosConfig === null || iosConfig === void 0 ? void 0 : iosConfig.config;
27
- if (removeOnly) {
28
- removePListConfig(pathToPList);
46
+ if (!fs.existsSync(pathToPList)) {
47
+ throw new Error('Could not read plist file: ' + pathToPList);
29
48
  }
30
- else {
31
- if (iosConfig && (configProps != null)) {
32
- if (hasDuplicateProperties(configProps)) {
33
- throw new Error('Duplicate properties found! Please remove duplicates and try again.');
34
- }
35
- if (isAutoStartEnabled(configProps)) {
36
- if (checkForBeaconUrlAndAppId(configProps)) {
37
- createNewPListIfRequired(parsedPList, configProps, pathToPList);
38
- }
39
- else {
40
- throw new Error('The dynatrace.config.js file does not contain DTXBeaconURL or DTXApplicationID properties. ' +
41
- 'If you want to auto-start the iOS agent, please add these two properties at minimum as they are required. ' +
42
- 'If you are using a manual startup of the iOS agent, please add just the DTXAutoStart property ' +
43
- '(no other properties are needed and none will be considered) with the value set to false.');
44
- }
45
- }
46
- else {
47
- if (checkForBeaconUrlAndAppId(configProps)) {
48
- throw new Error('The dynatrace.config.js file contains DTXBeaconURL and or DTXApplicationID properties while ' +
49
- 'DTXAutoStart is set to false. Any properties that you add to the dynatrace.config.js file will not be used ' +
50
- 'if DTXAutoStart is set to false. If you want to manually start the iOS agent, please only add the ' +
51
- 'DTXAutoStart property and set the value to false.');
52
- }
53
- else {
54
- createNewPListIfRequired(parsedPList, configProps, pathToPList);
55
- }
56
- }
57
- }
58
- else {
59
- throw new Error("Can't write configuration of iOS agent because it is missing!");
49
+ return pathToPList;
50
+ };
51
+ const validateAutoStartConfiguration = (configProps) => {
52
+ if (isAutoStartEnabled(configProps)) {
53
+ if (!checkForBeaconUrlAndAppId(configProps)) {
54
+ throw new Error('The dynatrace.config.js file does not contain DTXBeaconURL or DTXApplicationID properties. ' +
55
+ 'If you want to auto-start the iOS agent, please add these two properties at minimum as they are required. ' +
56
+ 'If you are using a manual startup of the iOS agent, please add just the DTXAutoStart property ' +
57
+ '(no other properties are needed and none will be considered) with the value set to false.');
60
58
  }
59
+ return;
60
+ }
61
+ if (checkForBeaconUrlAndAppId(configProps)) {
62
+ throw new Error('The dynatrace.config.js file contains DTXBeaconURL and or DTXApplicationID properties while ' +
63
+ 'DTXAutoStart is set to false. Any properties that you add to the dynatrace.config.js file will not be used ' +
64
+ 'if DTXAutoStart is set to false. If you want to manually start the iOS agent, please only add the ' +
65
+ 'DTXAutoStart property and set the value to false.');
61
66
  }
62
67
  };
63
68
  const removePListConfig = (file) => {
@@ -79,52 +84,264 @@ const addAgentConfigToPListFile = (file, config) => {
79
84
  Logger_1.default.logMessageSync('Updated configuration in plist file: ' + file, Logger_1.default.INFO);
80
85
  };
81
86
  const findPListFile = () => {
82
- const appJson = FileOperationHelper_1.default.readTextFromFileSync(PathsConstants_1.default.getAppJsonFile());
83
- const appJsonObj = JSON.parse(appJson);
84
- let appName;
85
- if (appJsonObj.expo !== undefined) {
86
- appName = appJsonObj.expo.name;
87
+ const iosFolder = PathsConstants_1.default.getIOSFolder();
88
+ if (!fs.existsSync(iosFolder)) {
89
+ throw new Error('Could not find iOS folder. For Expo managed projects, run "expo prebuild" first or provide plist=... custom argument.');
87
90
  }
88
- else if (appJsonObj.name !== undefined) {
89
- appName = appJsonObj.name;
91
+ const appRoot = nodePath.dirname(iosFolder);
92
+ const appNames = resolveAppNames(appRoot);
93
+ const fromXcode = resolvePlistsFromXcodeProject(iosFolder, appNames);
94
+ const appXcodePlists = fromXcode.filter((pathToPlist) => !isNonAppTargetPath(pathToPlist));
95
+ const xcodeCandidates = appXcodePlists.length > 0 ? appXcodePlists : fromXcode;
96
+ if (xcodeCandidates.length === 1) {
97
+ return xcodeCandidates[0];
90
98
  }
91
- else {
92
- throw new Error('Name of the application is unknown. Check your app.json file!');
99
+ if (xcodeCandidates.length > 1) {
100
+ const examples = xcodeCandidates.slice(0, 5).join(', ');
101
+ throw new Error(`Found multiple plist files from Xcode build settings: ${examples}. ` +
102
+ 'Please provide plist=... custom argument to select the correct one.');
103
+ }
104
+ const byName = resolvePlistByAppNames(iosFolder, appNames);
105
+ if (byName !== undefined) {
106
+ return byName;
107
+ }
108
+ const scanned = scanPlistCandidates(iosFolder);
109
+ if (scanned.length === 1) {
110
+ return scanned[0];
93
111
  }
94
- const pListPaths = [];
95
- pListPaths.push(nodePath.join(PathsConstants_1.default.getIOSFolder(), appName, 'Info.plist'));
96
- pListPaths.push(nodePath.join(PathsConstants_1.default.getIOSFolder(), appName, 'Supporting', 'Info.plist'));
97
- for (const pListPath of pListPaths) {
98
- try {
99
- FileOperationHelper_1.default.checkIfFileExistsSync(pListPath);
100
- return pListPath;
112
+ if (scanned.length > 1) {
113
+ const examples = scanned.slice(0, 5).join(', ');
114
+ throw new Error(`Found multiple plist files in iOS folder: ${examples}. ` +
115
+ 'Please provide plist=... custom argument to select the correct one.');
116
+ }
117
+ throw new Error("Can't find .plist file in iOS Folder! Try to use plist= custom argument. See documentation for help!");
118
+ };
119
+ const resolvePlistByAppNames = (iosFolder, appNames) => {
120
+ for (const appName of appNames) {
121
+ const pListPaths = [
122
+ nodePath.join(iosFolder, appName, 'Info.plist'),
123
+ nodePath.join(iosFolder, appName, `${appName}.plist`),
124
+ nodePath.join(iosFolder, appName, 'Supporting', 'Info.plist'),
125
+ nodePath.join(iosFolder, appName, 'Supporting', `${appName}.plist`),
126
+ ];
127
+ for (const pListPath of pListPaths) {
128
+ if (fs.existsSync(pListPath)) {
129
+ return pListPath;
130
+ }
101
131
  }
102
- catch (e) {
132
+ }
133
+ return undefined;
134
+ };
135
+ const resolveAppNames = (appRoot) => {
136
+ const candidates = [
137
+ nodePath.join(appRoot, 'app.json'),
138
+ nodePath.join(appRoot, 'app.config.js'),
139
+ nodePath.join(appRoot, 'app.config.ts'),
140
+ ];
141
+ const names = [];
142
+ for (const filePath of candidates) {
143
+ if (!fs.existsSync(filePath)) {
144
+ continue;
103
145
  }
146
+ const fileText = FileOperationHelper_1.default.readTextFromFileSync(filePath);
147
+ const parsedNames = extractAppNames(fileText, filePath.endsWith('.json'));
148
+ parsedNames.forEach((name) => {
149
+ if (!names.includes(name)) {
150
+ names.push(name);
151
+ }
152
+ });
104
153
  }
105
- throw new Error("Can't find .plist file in iOS Folder! Try to use plist= custom argument. See documentation for help!");
154
+ return names;
155
+ };
156
+ const resolvePlistsFromXcodeProject = (iosFolder, appNames) => {
157
+ const xcodeProjDirs = fs.readdirSync(iosFolder, { withFileTypes: true })
158
+ .filter((entry) => entry.isDirectory() && entry.name.endsWith('.xcodeproj'))
159
+ .map((entry) => nodePath.join(iosFolder, entry.name));
160
+ if (xcodeProjDirs.length === 0) {
161
+ return [];
162
+ }
163
+ const plistPaths = [];
164
+ for (const xcodeProjDir of xcodeProjDirs) {
165
+ const projectFile = nodePath.join(xcodeProjDir, 'project.pbxproj');
166
+ if (!fs.existsSync(projectFile)) {
167
+ continue;
168
+ }
169
+ const projectContent = FileOperationHelper_1.default.readTextFromFileSync(projectFile);
170
+ const srcRoot = nodePath.dirname(xcodeProjDir);
171
+ const projectName = nodePath.basename(xcodeProjDir, '.xcodeproj');
172
+ const plistSettingValues = extractInfoPlistSettingValues(projectContent);
173
+ for (const plistSettingValue of plistSettingValues) {
174
+ const resolvedPath = resolvePbxPlistPath(plistSettingValue, srcRoot, projectName, appNames);
175
+ if (resolvedPath !== undefined && fs.existsSync(resolvedPath) && !plistPaths.includes(resolvedPath)) {
176
+ plistPaths.push(resolvedPath);
177
+ }
178
+ }
179
+ }
180
+ return plistPaths.sort((a, b) => rankPlistCandidate(a, appNames) - rankPlistCandidate(b, appNames));
181
+ };
182
+ const extractInfoPlistSettingValues = (projectContent) => {
183
+ const settings = [];
184
+ const marker = 'INFOPLIST_FILE';
185
+ for (const line of projectContent.split(/\r?\n/)) {
186
+ const markerIndex = line.indexOf(marker);
187
+ if (markerIndex < 0) {
188
+ continue;
189
+ }
190
+ const equalsIndex = line.indexOf('=', markerIndex + marker.length);
191
+ if (equalsIndex < 0) {
192
+ continue;
193
+ }
194
+ const semicolonIndex = line.indexOf(';', equalsIndex + 1);
195
+ if (semicolonIndex < 0) {
196
+ continue;
197
+ }
198
+ const settingValue = line.slice(equalsIndex + 1, semicolonIndex).trim();
199
+ if (settingValue.length > 0) {
200
+ settings.push(settingValue);
201
+ }
202
+ }
203
+ return settings;
204
+ };
205
+ const resolvePbxPlistPath = (plistValue, srcRoot, projectName, appNames) => {
206
+ const trimmedValue = plistValue.trim();
207
+ const cleanedValue = trimmedValue.startsWith('"') && trimmedValue.endsWith('"')
208
+ ? trimmedValue.slice(1, -1)
209
+ : trimmedValue;
210
+ const substitutions = buildPbxPathSubstitutions(srcRoot, projectName, appNames);
211
+ for (const substitution of substitutions) {
212
+ let candidate = cleanedValue;
213
+ for (const [key, value] of Object.entries(substitution)) {
214
+ candidate = candidate
215
+ .split(`$(${key})`).join(value)
216
+ .split(`\${${key}}`).join(value);
217
+ }
218
+ if (/\$\(|\$\{/.test(candidate)) {
219
+ continue;
220
+ }
221
+ if (!nodePath.isAbsolute(candidate)) {
222
+ candidate = nodePath.join(srcRoot, candidate);
223
+ }
224
+ const normalized = nodePath.normalize(candidate);
225
+ if (normalized.endsWith('.plist')) {
226
+ return normalized;
227
+ }
228
+ }
229
+ return undefined;
230
+ };
231
+ const buildPbxPathSubstitutions = (srcRoot, projectName, appNames) => {
232
+ const productNames = [projectName, ...appNames].filter((name, index, arr) => arr.indexOf(name) === index);
233
+ const substitutions = [];
234
+ for (const productName of productNames) {
235
+ substitutions.push({
236
+ SRCROOT: srcRoot,
237
+ PROJECT_DIR: srcRoot,
238
+ PROJECT_NAME: projectName,
239
+ TARGET_NAME: productName,
240
+ PRODUCT_NAME: productName,
241
+ });
242
+ }
243
+ return substitutions;
244
+ };
245
+ const extractAppNames = (content, isJson) => {
246
+ var _a;
247
+ if (!isJson) {
248
+ return [];
249
+ }
250
+ const names = [];
251
+ try {
252
+ const parsed = JSON.parse(content);
253
+ const expoName = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.expo) === null || _a === void 0 ? void 0 : _a.name;
254
+ const rootName = parsed === null || parsed === void 0 ? void 0 : parsed.name;
255
+ if (typeof expoName === 'string' && expoName.length > 0) {
256
+ names.push(expoName);
257
+ }
258
+ if (typeof rootName === 'string' && rootName.length > 0 && !names.includes(rootName)) {
259
+ names.push(rootName);
260
+ }
261
+ }
262
+ catch (_b) {
263
+ }
264
+ return names;
265
+ };
266
+ const scanPlistCandidates = (iosFolder) => {
267
+ const excludedDirs = new Set(['Pods', 'build', 'DerivedData', 'node_modules', '.git']);
268
+ const results = [];
269
+ const walk = (dir) => {
270
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
271
+ for (const entry of entries) {
272
+ if (entry.isDirectory()) {
273
+ if (!excludedDirs.has(entry.name)) {
274
+ walk(nodePath.join(dir, entry.name));
275
+ }
276
+ continue;
277
+ }
278
+ if (entry.name.endsWith('.plist')) {
279
+ results.push(nodePath.join(dir, entry.name));
280
+ }
281
+ }
282
+ };
283
+ try {
284
+ walk(iosFolder);
285
+ }
286
+ catch (e) {
287
+ Logger_1.default.logMessageSync(`Failed to scan iOS folder for plist files: ${String(e)}`, Logger_1.default.INFO);
288
+ return [];
289
+ }
290
+ return results.sort((a, b) => rankPlistCandidate(a) - rankPlistCandidate(b));
291
+ };
292
+ const rankPlistCandidate = (filePath, appNames = []) => {
293
+ const normalizedPath = filePath.toLowerCase();
294
+ const fileName = nodePath.basename(filePath).toLowerCase();
295
+ let rank = 0;
296
+ if (fileName === 'info.plist') {
297
+ rank -= 30;
298
+ }
299
+ if (normalizedPath.includes(`${nodePath.sep}supporting${nodePath.sep}`)) {
300
+ rank -= 20;
301
+ }
302
+ if (isNonAppTargetPath(filePath)) {
303
+ rank += 200;
304
+ }
305
+ for (const appName of appNames) {
306
+ const escapedName = escapeRegexLiteral(appName).toLowerCase();
307
+ if (normalizedPath.includes(`${nodePath.sep}${escapedName}${nodePath.sep}`)) {
308
+ rank -= 40;
309
+ break;
310
+ }
311
+ }
312
+ const parts = filePath.split(nodePath.sep);
313
+ rank += parts.length;
314
+ return rank;
315
+ };
316
+ const escapeRegexLiteral = (value) => {
317
+ const specialChars = new Set(['\\', '^', '$', '.', '|', '?', '*', '+', '(', ')', '[', ']', '{', '}']);
318
+ let escaped = '';
319
+ for (const char of value) {
320
+ escaped += specialChars.has(char) ? `\\${char}` : char;
321
+ }
322
+ return escaped;
106
323
  };
107
324
  const parsePList = (file) => {
108
325
  const pListContent = FileOperationHelper_1.default.readTextFromFileSync(file);
109
- let pListObj = (0, plist_1.parse)(pListContent);
110
- return pListObj = Object.assign({}, pListObj);
326
+ const pListObj = (0, plist_1.parse)(pListContent);
327
+ return Object.assign({}, pListObj);
111
328
  };
112
329
  const isAutoStartEnabled = (config) => {
113
- if (config !== undefined && config.indexOf(PlistConstants_1.AUTO_START_PROP) >= 0) {
330
+ if ((config === null || config === void 0 ? void 0 : config.includes(PlistConstants_1.AUTO_START_PROP)) === true) {
114
331
  const configObj = PlistConstants_1.START_PLIST + config + PlistConstants_1.END_PLIST;
115
332
  const configObjCopy = (0, plist_1.parse)(configObj);
116
333
  const configKeys = Object.keys(configObjCopy);
117
334
  const configValues = Object.values(configObjCopy);
118
335
  for (const key in configKeys) {
119
336
  if (configKeys[key] === 'DTXAutoStart' && typeof configValues[key] === 'boolean') {
120
- return configValues[key];
337
+ return configValues[key] === true;
121
338
  }
122
339
  }
123
340
  }
124
341
  return true;
125
342
  };
126
- const checkForBeaconUrlAndAppId = (config) => config != null && config.indexOf('DTXApplicationID') >= 0 && config.indexOf('DTXBeaconURL') >= 0;
127
- const checkForExcludedControls = (config) => config != null && config.indexOf('DTXExcludedControls') >= 0;
343
+ const checkForBeaconUrlAndAppId = (config) => config != null && config.includes('DTXApplicationID') && config.includes('DTXBeaconURL');
344
+ const checkForExcludedControls = (config) => (config === null || config === void 0 ? void 0 : config.includes('DTXExcludedControls')) === true;
128
345
  const updatedExcludedStr = (config) => {
129
346
  if (checkForExcludedControls(config)) {
130
347
  const controlsArr = Object.keys(PlistConstants_1.CONTROLS_PROP_OPTIONS);
@@ -132,7 +349,7 @@ const updatedExcludedStr = (config) => {
132
349
  for (let index = 0; index < controlsArr.length; index++) {
133
350
  if (controlsArr[index] !== 'PickerView'
134
351
  && controlsArr[index] !== 'Switch'
135
- && config.indexOf(PlistConstants_1.CONTROLS_PROP_OPTIONS[controlsArr[index]].trim()) >= 0) {
352
+ && config.includes(PlistConstants_1.CONTROLS_PROP_OPTIONS[controlsArr[index]].trim())) {
136
353
  updatedStr = updatedStr + PlistConstants_1.CONTROLS_PROP_OPTIONS[controlsArr[index]];
137
354
  }
138
355
  }
@@ -2,35 +2,49 @@
2
2
  'use strict';
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.DYNATRACE_CONFIG_GRADLE_FILE = void 0;
5
- const path_1 = require("path");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
6
7
  const PATH_FILES = 'files';
7
8
  const PATH_LOGS = 'logs';
8
9
  exports.DYNATRACE_CONFIG_GRADLE_FILE = 'dynatrace.gradle';
10
+ const GRADLE_FILE = 'build.gradle';
11
+ const GRADLE_KTS_FILE = 'build.gradle.kts';
9
12
  let rootPath = __dirname;
13
+ const resolveAndroidGradleFile = (folder) => {
14
+ const gradlePath = (0, node_path_1.join)(folder, GRADLE_FILE);
15
+ if ((0, node_fs_1.existsSync)(gradlePath)) {
16
+ return gradlePath;
17
+ }
18
+ const gradleKtsPath = (0, node_path_1.join)(folder, GRADLE_KTS_FILE);
19
+ if ((0, node_fs_1.existsSync)(gradleKtsPath)) {
20
+ return gradleKtsPath;
21
+ }
22
+ return gradlePath;
23
+ };
10
24
  exports.default = {
11
25
  setRoot: (newRoot) => {
12
- rootPath = (0, path_1.resolve)(newRoot);
26
+ rootPath = (0, node_path_1.resolve)(newRoot);
13
27
  },
14
- getApplicationPath: () => (0, path_1.join)(getPluginPath(), '..', '..', '..'),
15
- getAppJsonFile: () => (0, path_1.join)(getApplicationPath(), 'app.json'),
28
+ getApplicationPath: () => (0, node_path_1.join)(getPluginPath(), '..', '..', '..'),
29
+ getAppJsonFile: () => (0, node_path_1.join)(getApplicationPath(), 'app.json'),
16
30
  getPackageJsonFile() {
17
- return (0, path_1.join)(this.getApplicationPath(), 'package.json');
31
+ return (0, node_path_1.join)(this.getApplicationPath(), 'package.json');
18
32
  },
19
33
  getMetroSouceMapPath() {
20
- return (0, path_1.join)(this.getApplicationPath(), 'node_modules', 'metro', 'src', 'DeltaBundler', 'Serializers', 'helpers');
34
+ return (0, node_path_1.join)(this.getApplicationPath(), 'node_modules', 'metro', 'src', 'DeltaBundler', 'Serializers', 'helpers');
21
35
  },
22
- getOurSourceMapFile: () => (0, path_1.join)(getPluginPath(), 'lib', 'metro', 'getSourceMapInfo.js'),
23
- getInternalPackageJsonFile: () => (0, path_1.join)(getPluginPath(), 'package.json'),
24
- getDefaultConfig: () => (0, path_1.join)(getPluginPath(), PATH_FILES, 'default.config.js'),
25
- getBuildPath: () => (0, path_1.join)(getPluginPath(), 'build'),
26
- getConfigFilePath: () => (0, path_1.join)(getApplicationPath(), 'dynatrace.config.js'),
27
- getAndroidFolder: () => (0, path_1.join)(getApplicationPath(), 'android'),
28
- getAndroidGradleFile: (androidFolder) => (0, path_1.join)(androidFolder, 'build.gradle'),
29
- getAndroidAppGradleFile: (androidFolder) => (0, path_1.join)(androidFolder, 'app', 'build.gradle'),
30
- getIOSFolder: () => (0, path_1.join)(getApplicationPath(), 'ios'),
31
- getDynatraceGradleFile: () => (0, path_1.join)(getPluginPath(), PATH_FILES, exports.DYNATRACE_CONFIG_GRADLE_FILE),
32
- getCurrentLogPath: () => (0, path_1.join)(getPluginPath(), PATH_LOGS, 'currentLog.txt'),
33
- getLogPath: () => (0, path_1.join)(getPluginPath(), PATH_LOGS),
36
+ getOurSourceMapFile: () => (0, node_path_1.join)(getPluginPath(), 'lib', 'metro', 'getSourceMapInfo.js'),
37
+ getInternalPackageJsonFile: () => (0, node_path_1.join)(getPluginPath(), 'package.json'),
38
+ getDefaultConfig: () => (0, node_path_1.join)(getPluginPath(), PATH_FILES, 'default.config.js'),
39
+ getBuildPath: () => (0, node_path_1.join)(getPluginPath(), 'build'),
40
+ getConfigFilePath: () => (0, node_path_1.join)(getApplicationPath(), 'dynatrace.config.js'),
41
+ getAndroidFolder: () => (0, node_path_1.join)(getApplicationPath(), 'android'),
42
+ getAndroidGradleFile: (androidFolder) => resolveAndroidGradleFile(androidFolder),
43
+ getAndroidAppGradleFile: (androidFolder) => resolveAndroidGradleFile((0, node_path_1.join)(androidFolder, 'app')),
44
+ getIOSFolder: () => (0, node_path_1.join)(getApplicationPath(), 'ios'),
45
+ getDynatraceGradleFile: () => (0, node_path_1.join)(getPluginPath(), PATH_FILES, exports.DYNATRACE_CONFIG_GRADLE_FILE),
46
+ getCurrentLogPath: () => (0, node_path_1.join)(getPluginPath(), PATH_LOGS, 'currentLog.txt'),
47
+ getLogPath: () => (0, node_path_1.join)(getPluginPath(), PATH_LOGS),
34
48
  };
35
- const getPluginPath = () => (0, path_1.join)(rootPath, '..');
36
- const getApplicationPath = () => (0, path_1.join)(getPluginPath(), '..', '..', '..');
49
+ const getPluginPath = () => (0, node_path_1.join)(rootPath, '..');
50
+ const getApplicationPath = () => (0, node_path_1.join)(getPluginPath(), '..', '..', '..');
@@ -44,7 +44,7 @@ const instrumentCommand = () => {
44
44
  Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ' }, () => (0, InstrumentUtil_1.showVersionOfPlugin)());
45
45
  let pathToConfig = PathsConstants_1.default.getConfigFilePath();
46
46
  let pathToGradle = PathsConstants_1.default.getAndroidGradleFile(PathsConstants_1.default.getAndroidFolder());
47
- const pathToAppGradle = PathsConstants_1.default.getAndroidAppGradleFile(PathsConstants_1.default.getAndroidFolder());
47
+ let pathToAppGradle = PathsConstants_1.default.getAndroidAppGradleFile(PathsConstants_1.default.getAndroidFolder());
48
48
  let androidAvailable = true;
49
49
  let pathToPList;
50
50
  let iosAvailable = true;
@@ -61,6 +61,11 @@ const instrumentCommand = () => {
61
61
  Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ', error: ' ❌ ' }, () => {
62
62
  if (argv.isCustomGradlePathSet()) {
63
63
  pathToGradle = argv.getCustomGradlePath();
64
+ if (!/build\.gradle(\.kts)?$/.test(pathToGradle)) {
65
+ throw new Error(`--gradle must point to build.gradle or build.gradle.kts file, got ${pathToGradle}`);
66
+ }
67
+ const androidFolder = nodePath.dirname(pathToGradle);
68
+ pathToAppGradle = PathsConstants_1.default.getAndroidAppGradleFile(androidFolder);
64
69
  androidAvailable = (0, InstrumentUtil_1.isPlatformAvailable)(pathToGradle, Platform_1.Platform.Android);
65
70
  }
66
71
  else {
@@ -76,6 +81,7 @@ const instrumentCommand = () => {
76
81
  });
77
82
  pathToConfig = (0, path_1.resolve)(pathToConfig);
78
83
  pathToGradle = (0, path_1.resolve)(pathToGradle);
84
+ pathToAppGradle = (0, path_1.resolve)(pathToAppGradle);
79
85
  if (iosAvailable || androidAvailable) {
80
86
  try {
81
87
  Logger_1.default.logMessageSync('⏳ Trying to read configuration file: ' + pathToConfig, Logger_1.default.INFO);
@@ -1,30 +1,68 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.patchMetroSourceMap = exports.SOURCE_MAP_FILE = exports.SOURCE_MAP_BACKUP_FILE = void 0;
4
- const path_1 = require("path");
4
+ const node_path_1 = require("node:path");
5
5
  const Logger_1 = require("../Logger");
6
6
  const PathsConstants_1 = require("../PathsConstants");
7
7
  const FileOperationHelper_1 = require("../FileOperationHelper");
8
8
  exports.SOURCE_MAP_BACKUP_FILE = 'getSourceMapInfoOrig.js';
9
9
  exports.SOURCE_MAP_FILE = 'getSourceMapInfo.js';
10
- const patchMetroSourceMap = () => {
11
- Logger_1.default.logMessageSync('⏳ Patching SourceMap generation of Metro .. ', Logger_1.default.INFO);
12
- const origSourceMapPath = (0, path_1.join)(PathsConstants_1.default.getMetroSouceMapPath(), exports.SOURCE_MAP_BACKUP_FILE);
13
- try {
14
- FileOperationHelper_1.default.checkIfFileExistsSync(origSourceMapPath);
15
- Logger_1.default.logMessageSync(' ℹ️ Patching of SourceMap already happened!', Logger_1.default.INFO);
10
+ const getMetroResolveLookupPaths = () => {
11
+ const lookupPaths = [];
12
+ let currentPath = process.cwd();
13
+ while (true) {
14
+ lookupPaths.push(currentPath);
15
+ const pnpmLookupPath = (0, node_path_1.join)(currentPath, 'node_modules', '.pnpm', 'node_modules');
16
+ if (!lookupPaths.includes(pnpmLookupPath)) {
17
+ lookupPaths.push(pnpmLookupPath);
18
+ }
19
+ const parentPath = (0, node_path_1.dirname)(currentPath);
20
+ if (parentPath === currentPath) {
21
+ break;
22
+ }
23
+ currentPath = parentPath;
16
24
  }
17
- catch (e) {
25
+ return lookupPaths;
26
+ };
27
+ const resolveMetroSourceMapPaths = (resolveModule) => {
28
+ const paths = [PathsConstants_1.default.getMetroSouceMapPath()];
29
+ for (const lookupPath of getMetroResolveLookupPaths()) {
30
+ try {
31
+ const resolvedMetroSourceMapFile = resolveModule('metro/src/DeltaBundler/Serializers/helpers/getSourceMapInfo.js', { paths: [lookupPath] });
32
+ const resolvedMetroSourceMapDir = (0, node_path_1.dirname)(resolvedMetroSourceMapFile);
33
+ if (!paths.includes(resolvedMetroSourceMapDir)) {
34
+ paths.push(resolvedMetroSourceMapDir);
35
+ }
36
+ break;
37
+ }
38
+ catch (_a) {
39
+ }
40
+ }
41
+ return paths;
42
+ };
43
+ const patchMetroSourceMap = (resolveModule = require.resolve) => {
44
+ Logger_1.default.logMessageSync('⏳ Patching SourceMap generation of Metro .. ', Logger_1.default.INFO);
45
+ const metroSourceMapPaths = resolveMetroSourceMapPaths(resolveModule);
46
+ for (const metroSourceMapPath of metroSourceMapPaths) {
47
+ const origSourceMapPath = (0, node_path_1.join)(metroSourceMapPath, exports.SOURCE_MAP_BACKUP_FILE);
48
+ try {
49
+ FileOperationHelper_1.default.checkIfFileExistsSync(origSourceMapPath);
50
+ Logger_1.default.logMessageSync(' ℹ️ Patching of SourceMap already happened!', Logger_1.default.INFO);
51
+ return;
52
+ }
53
+ catch (_a) {
54
+ }
18
55
  try {
19
- const currentSourceMapPath = (0, path_1.join)(PathsConstants_1.default.getMetroSouceMapPath(), exports.SOURCE_MAP_FILE);
56
+ const currentSourceMapPath = (0, node_path_1.join)(metroSourceMapPath, exports.SOURCE_MAP_FILE);
20
57
  FileOperationHelper_1.default.checkIfFileExistsSync(currentSourceMapPath);
21
58
  FileOperationHelper_1.default.renameFileSync(currentSourceMapPath, origSourceMapPath);
22
59
  FileOperationHelper_1.default.copyFileSync(PathsConstants_1.default.getOurSourceMapFile(), currentSourceMapPath);
23
60
  Logger_1.default.logMessageSync(' ✅ Patching of SourceMap successful!', Logger_1.default.INFO);
61
+ return;
24
62
  }
25
- catch (e) {
26
- Logger_1.default.logMessageSync(' ❌ Patching of SourceMap generation failed!', Logger_1.default.ERROR);
63
+ catch (_b) {
27
64
  }
28
65
  }
66
+ Logger_1.default.logMessageSync(' ❌ Patching of SourceMap generation failed!', Logger_1.default.ERROR);
29
67
  };
30
68
  exports.patchMetroSourceMap = patchMetroSourceMap;