@dynatrace/react-native-plugin 2.339.1 → 2.341.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 (34) hide show
  1. package/README.md +116 -18
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +0 -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/jsx/CreateElement.js +5 -9
  8. package/instrumentation/jsx/ElementHelper.js +5 -6
  9. package/instrumentation/jsx/JsxDevRuntime.js +33 -31
  10. package/instrumentation/jsx/JsxRuntime.js +30 -30
  11. package/instrumentation/jsx/JsxRuntimeHelpers.js +14 -0
  12. package/instrumentation/jsx/components/ClassComponent.js +4 -8
  13. package/instrumentation/jsx/components/ComponentUtil.js +24 -25
  14. package/instrumentation/libs/UserInteraction.js +27 -24
  15. package/instrumentation/libs/react-native/RefreshControl.js +5 -9
  16. package/instrumentation/libs/withOnPressMonitoring.js +66 -57
  17. package/lib/core/DynatraceAction.js +1 -3
  18. package/lib/core/DynatraceInternal.js +38 -40
  19. package/lib/core/ErrorHandler.js +41 -21
  20. package/lib/core/NullAction.js +1 -3
  21. package/lib/core/util/JsonUtils.js +6 -0
  22. package/lib/features/ui-interaction/TouchMetaResolver.js +4 -3
  23. package/lib/next/events/HttpRequestEventData.js +2 -2
  24. package/lib/next/events/interface/HttpRequestEventDataTypes.js +2 -0
  25. package/lib/next/events/modifier/ModifyEventValidation.js +79 -51
  26. package/package.json +6 -5
  27. package/react-native-dynatrace.podspec +1 -1
  28. package/scripts/Config.js +6 -2
  29. package/scripts/DebugFlag.js +20 -0
  30. package/scripts/FileOperationHelper.js +15 -39
  31. package/scripts/Logger.js +2 -3
  32. package/scripts/core/InstrumentCall.js +101 -80
  33. package/scripts/util/CustomArgumentUtil.js +8 -6
  34. package/types.d.ts +159 -8
@@ -5,6 +5,7 @@ const ConsoleLogger_1 = require("../../../core/logging/ConsoleLogger");
5
5
  const LogMessages_1 = require("../../../core/logging/LogMessages");
6
6
  const EventSpecContstants_1 = require("../spec/EventSpecContstants");
7
7
  const EventModifierUtil_1 = require("./EventModifierUtil");
8
+ const JsonUtils_1 = require("../../../core/util/JsonUtils");
8
9
  class ModifyEventValidation {
9
10
  constructor() {
10
11
  this.customEventModifierChain = [];
@@ -23,35 +24,15 @@ class ModifyEventValidation {
23
24
  return false;
24
25
  }
25
26
  modifyEvent(event) {
26
- if (this.customEventModifierChain.length > 0) {
27
- const eventCopy = Object.assign({}, event);
28
- let exceptionOccured = false;
29
- let isDiscarded = false;
30
- for (const modifier of this.customEventModifierChain) {
31
- try {
32
- const eventRv = modifier.modifyEvent(event);
33
- if (!eventRv) {
34
- isDiscarded = true;
35
- break;
36
- }
37
- else {
38
- event = eventRv;
39
- }
40
- }
41
- catch (_a) {
42
- if (event != null) {
43
- exceptionOccured = true;
44
- }
45
- }
46
- }
47
- if (!isDiscarded) {
48
- event = this.sanitizeUserEnrichedEvent(eventCopy, event, exceptionOccured);
49
- }
50
- else {
51
- return null;
52
- }
27
+ if (this.customEventModifierChain.length === 0) {
28
+ return event;
53
29
  }
54
- return event;
30
+ const eventCopy = Object.assign({}, event);
31
+ const modifiedEventResult = this.applyCustomModifiers(event);
32
+ if (modifiedEventResult.isDiscarded) {
33
+ return null;
34
+ }
35
+ return this.sanitizeUserEnrichedEvent(eventCopy, modifiedEventResult.event, modifiedEventResult.exceptionOccured);
55
36
  }
56
37
  isCustomPropertiesAllowed(key, hasSessionPropertyCharacteristics) {
57
38
  if (hasSessionPropertyCharacteristics) {
@@ -155,32 +136,15 @@ class ModifyEventValidation {
155
136
  validEntries.push([prop, value]);
156
137
  continue;
157
138
  }
158
- if (!this.isCustomPropertiesAllowed(prop, originalJSONEvent["characteristics.has_session_properties"] === true)) {
139
+ const validationResult = this.validateModifiedEntry(prop, value, originalValue, originalJSONEvent, overriddenKeys);
140
+ if (validationResult.entry !== undefined) {
141
+ validEntries.push(validationResult.entry);
142
+ }
143
+ if (validationResult.droppedCustomProperties) {
159
144
  droppedCustomProperties = true;
160
- continue;
161
145
  }
162
- const isNewlyAdded = typeof originalValue === 'undefined';
163
- const isForbiddenKey = this.isKeyNameForbidden(prop, isNewlyAdded);
164
- if (isForbiddenKey) {
165
- if (!isNewlyAdded) {
166
- validEntries.push([prop, originalValue]);
167
- }
146
+ if (validationResult.droppedProperties) {
168
147
  droppedProperties = true;
169
- continue;
170
- }
171
- if (!isNewlyAdded && !overriddenKeys.includes(prop)) {
172
- overriddenKeys.push(prop);
173
- }
174
- if (!isNewlyAdded &&
175
- EventSpecContstants_1.MODIFY_EVENT_WHITELIST_STRING_FIELDS.includes(prop)) {
176
- const maximumLength = Math.max(originalJSONEvent[prop].toString().length, EventSpecContstants_1.MAX_CUSTOM_EVENT_VALUE_LENGTH);
177
- validEntries.push([
178
- prop,
179
- (0, EventModifierUtil_1.trimString)(prop, value.toString(), maximumLength),
180
- ]);
181
- }
182
- else {
183
- validEntries.push([prop, value]);
184
148
  }
185
149
  }
186
150
  if (droppedCustomProperties) {
@@ -241,6 +205,43 @@ class ModifyEventValidation {
241
205
  return entries;
242
206
  }, resultEntries);
243
207
  }
208
+ validateModifiedEntry(prop, value, originalValue, originalJSONEvent, overriddenKeys) {
209
+ if (!this.isCustomPropertiesAllowed(prop, originalJSONEvent["characteristics.has_session_properties"] === true)) {
210
+ return {
211
+ droppedCustomProperties: true,
212
+ droppedProperties: false,
213
+ };
214
+ }
215
+ const isNewlyAdded = originalValue === undefined;
216
+ const isForbiddenKey = this.isKeyNameForbidden(prop, isNewlyAdded);
217
+ if (isForbiddenKey) {
218
+ return {
219
+ entry: isNewlyAdded ? undefined : [prop, originalValue],
220
+ droppedCustomProperties: false,
221
+ droppedProperties: true,
222
+ };
223
+ }
224
+ if (!isNewlyAdded && !overriddenKeys.includes(prop)) {
225
+ overriddenKeys.push(prop);
226
+ }
227
+ if (!isNewlyAdded &&
228
+ EventSpecContstants_1.MODIFY_EVENT_WHITELIST_STRING_FIELDS.includes(prop)) {
229
+ const maximumLength = Math.max(JsonUtils_1.JsonUtils.stringify(originalJSONEvent[prop]).length, EventSpecContstants_1.MAX_CUSTOM_EVENT_VALUE_LENGTH);
230
+ return {
231
+ entry: [
232
+ prop,
233
+ (0, EventModifierUtil_1.trimString)(prop, JsonUtils_1.JsonUtils.stringify(value), maximumLength),
234
+ ],
235
+ droppedCustomProperties: false,
236
+ droppedProperties: false,
237
+ };
238
+ }
239
+ return {
240
+ entry: [prop, value],
241
+ droppedCustomProperties: false,
242
+ droppedProperties: false,
243
+ };
244
+ }
244
245
  validateAddedEntries(addedEntries) {
245
246
  const validEntries = [];
246
247
  let droppedProperties = false;
@@ -274,6 +275,33 @@ class ModifyEventValidation {
274
275
  }
275
276
  return validEntries;
276
277
  }
278
+ applyCustomModifiers(event) {
279
+ let currentEvent = event;
280
+ let exceptionOccured = false;
281
+ for (const modifier of this.customEventModifierChain) {
282
+ try {
283
+ const eventRv = modifier.modifyEvent(currentEvent);
284
+ if (!eventRv) {
285
+ return {
286
+ event: currentEvent,
287
+ exceptionOccured,
288
+ isDiscarded: true,
289
+ };
290
+ }
291
+ currentEvent = eventRv;
292
+ }
293
+ catch (_a) {
294
+ if (currentEvent != null) {
295
+ exceptionOccured = true;
296
+ }
297
+ }
298
+ }
299
+ return {
300
+ event: currentEvent,
301
+ exceptionOccured,
302
+ isDiscarded: false,
303
+ };
304
+ }
277
305
  enforcePropertyLimit(entries) {
278
306
  const result = [];
279
307
  let propertyCount = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynatrace/react-native-plugin",
3
- "version": "2.339.1",
3
+ "version": "2.341.1",
4
4
  "description": "This plugin gives you the ability to use the Dynatrace Mobile agent in your react native application.",
5
5
  "main": "index.js",
6
6
  "types": "types.d.ts",
@@ -26,7 +26,7 @@
26
26
  "test": "jest --runInBand",
27
27
  "test:coverage": "jest --runInBand --coverage",
28
28
  "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand",
29
- "test:local": "npm run lint && node runner.js test",
29
+ "test:local": "node cleanMacFiles.js && npm run lint && node runner.js test",
30
30
  "test:examples": "node tests/jsdoc_examples/RunJestTest.js",
31
31
  "tsc:local": "tsc -p tsconfig.local.json",
32
32
  "tsc:types": "tsc -p tsconfig.types.json && rollup -c rollup.config.types.mjs",
@@ -49,11 +49,11 @@
49
49
  "author": "Dynatrace",
50
50
  "license": "SEE LICENSE IN LICENSE.md",
51
51
  "dependencies": {
52
- "@babel/runtime": "^7.29.7",
52
+ "@babel/runtime": "^8.0.0",
53
53
  "jscodeshift": "^17.3.0",
54
54
  "plist": "^3.1.0",
55
55
  "proxy-polyfill": "^0.3.2",
56
- "semver": "^7.8.3"
56
+ "semver": "^7.8.5"
57
57
  },
58
58
  "homepage": "https://www.dynatrace.com/",
59
59
  "peerDependencies": {
@@ -68,7 +68,8 @@
68
68
  },
69
69
  "ast-types": "npm:ast-types-x",
70
70
  "flow-parser": "0.160",
71
- "tmp": ">=0.2.6"
71
+ "tmp": ">=0.2.6",
72
+ "ws": "^7.5.11"
72
73
  },
73
74
  "devDependencies": {
74
75
  "@babel/plugin-transform-class-properties": "^7.27.1",
@@ -111,7 +111,7 @@ Pod::Spec.new do |s|
111
111
  #
112
112
 
113
113
  s.dependency "React"
114
- s.dependency 'Dynatrace', '~> 8.339.1.1011'
114
+ s.dependency 'Dynatrace', '~> 8.341.1.1010'
115
115
 
116
116
  # Allows for better compatibility for older and newer versions
117
117
  if defined?(install_modules_dependencies)
package/scripts/Config.js CHANGED
@@ -46,7 +46,7 @@ exports.defaultConfig = {
46
46
  const readConfigDefault = () => {
47
47
  const customArguments = (0, CustomArgumentUtil_1.readCustomArguments)();
48
48
  const configPath = customArguments.isCustomConfigurationPathSet()
49
- ? path.join(PathsConstants_1.default.getApplicationPath(), customArguments.getCustomConfigurationPath())
49
+ ? path.resolve(PathsConstants_1.default.getApplicationPath(), customArguments.getCustomConfigurationPath())
50
50
  : PathsConstants_1.default.getConfigFilePath();
51
51
  return (0, exports.readConfig)(configPath);
52
52
  };
@@ -80,8 +80,12 @@ exports.checkConfiguration = checkConfiguration;
80
80
  const createNewConfiguration = (pathToDynatraceConfig) => __awaiter(void 0, void 0, void 0, function* () {
81
81
  const defaultConfigContent = yield FileOperationHelper_1.default.readTextFromFile(PathsConstants_1.default.getDefaultConfig());
82
82
  yield FileOperationHelper_1.default.writeTextToFile(pathToDynatraceConfig, defaultConfigContent);
83
- Logger_1.default.logMessageSync('Created dynatrace.config.js - Please insert your configuration and update the file!', Logger_1.default.INFO);
83
+ logConfigCreatedMessage();
84
84
  });
85
+ const logConfigCreatedMessage = () => {
86
+ const message = 'Created dynatrace.config.js - Please insert your configuration and update the file!';
87
+ Logger_1.default.logMessageSync(message, Logger_1.default.INFO);
88
+ };
85
89
  const patchMalformedConfiguration = (pathToDynatraceConfig) => {
86
90
  const configContent = FileOperationHelper_1.default.readTextFromFileSync(pathToDynatraceConfig);
87
91
  if (configContent.indexOf('\u200B') !== -1) {
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.isDebugEnabled = void 0;
5
+ const PathsConstants_1 = require("./PathsConstants");
6
+ let cached;
7
+ const isDebugEnabled = () => {
8
+ var _a;
9
+ if (cached === undefined) {
10
+ try {
11
+ const { readConfig } = require('./Config');
12
+ cached = ((_a = readConfig(PathsConstants_1.default.getConfigFilePath()).react) === null || _a === void 0 ? void 0 : _a.debug) === true;
13
+ }
14
+ catch (_b) {
15
+ cached = false;
16
+ }
17
+ }
18
+ return cached;
19
+ };
20
+ exports.isDebugEnabled = isDebugEnabled;
@@ -71,49 +71,25 @@ const mkdirSyncRecursive = (directory) => {
71
71
  }
72
72
  }
73
73
  };
74
- const deleteDirectory = (dir) => new Promise((resolve, reject) => {
75
- fs.access(dir, (err) => {
76
- if (err) {
77
- return reject(err);
78
- }
79
- fs.readdir(dir, (err, files) => {
80
- if (err) {
81
- return reject(err);
82
- }
83
- Promise.all(files.map((file) => deleteFile(path.join(dir, file)))).then(() => {
84
- fs.rmdir(dir, (err) => {
85
- if (err) {
86
- return reject(err);
87
- }
88
- resolve();
89
- });
90
- }).catch(reject);
91
- });
92
- });
74
+ const deleteDirectory = (dir) => __awaiter(void 0, void 0, void 0, function* () {
75
+ yield fsPromise.access(dir);
76
+ const files = yield fsPromise.readdir(dir);
77
+ yield Promise.all(files.map((file) => deleteFile(path.join(dir, file))));
78
+ yield fsPromise.rmdir(dir);
93
79
  });
94
80
  const deleteDirectorySync = (dir) => {
95
81
  fs.accessSync(dir);
96
82
  const files = fs.readdirSync(dir);
97
- files.map((file) => deleteFileSync(path.join(dir, file)));
83
+ files.forEach((file) => deleteFileSync(path.join(dir, file)));
98
84
  fs.rmdirSync(dir);
99
85
  };
100
- const deleteFile = (filePath) => new Promise((resolve, reject) => {
101
- fs.lstat(filePath, (err, stats) => {
102
- if (err) {
103
- return reject(err);
104
- }
105
- if (stats.isDirectory()) {
106
- resolve(deleteDirectory(filePath));
107
- }
108
- else {
109
- fs.unlink(filePath, (err) => {
110
- if (err) {
111
- return reject(err);
112
- }
113
- resolve();
114
- });
115
- }
116
- });
86
+ const deleteFile = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
87
+ const stats = yield fsPromise.lstat(filePath);
88
+ if (stats.isDirectory()) {
89
+ yield deleteDirectory(filePath);
90
+ return;
91
+ }
92
+ yield fsPromise.unlink(filePath);
117
93
  });
118
94
  const deleteFileSync = (filePath) => {
119
95
  const stats = fs.lstatSync(filePath);
@@ -157,7 +133,7 @@ const copyDirectory = (from, to) => {
157
133
  }
158
134
  });
159
135
  };
160
- const allowedRootFolders = ['src', 'node_modules'];
136
+ const allowedRootFolders = new Set(['src', 'node_modules']);
161
137
  const getAllFiles = (log, dir, base = '', isRoot = false) => __awaiter(void 0, void 0, void 0, function* () {
162
138
  const entries = yield fsPromise.readdir(dir);
163
139
  let files = [];
@@ -166,7 +142,7 @@ const getAllFiles = (log, dir, base = '', isRoot = false) => __awaiter(void 0, v
166
142
  const relPath = path.join(base, entry);
167
143
  const stat = yield fsPromise.stat(fullPath);
168
144
  if (stat.isDirectory()) {
169
- if (isRoot && !allowedRootFolders.includes(entry)) {
145
+ if (isRoot && !allowedRootFolders.has(entry)) {
170
146
  yield log(`🔸 Skipping folder: ${entry}`);
171
147
  continue;
172
148
  }
package/scripts/Logger.js CHANGED
@@ -5,7 +5,7 @@ const fs = require("fs");
5
5
  const nodePath = require("path");
6
6
  const FileOperationHelper_1 = require("./FileOperationHelper");
7
7
  const PathsConstants_1 = require("./PathsConstants");
8
- const Config_1 = require("./Config");
8
+ const DebugFlag_1 = require("./DebugFlag");
9
9
  const ERROR = 0;
10
10
  const INFO = 1;
11
11
  const WARNING = 2;
@@ -26,8 +26,7 @@ const closeLogFile = () => {
26
26
  .catch(errorHandling);
27
27
  };
28
28
  const logErrorSync = (_message) => {
29
- const config = (0, Config_1.readConfig)(PathsConstants_1.default.getConfigFilePath());
30
- if (config.react !== undefined && config.react.debug) {
29
+ if ((0, DebugFlag_1.isDebugEnabled)()) {
31
30
  logMessageSync(_message, ERROR, true);
32
31
  }
33
32
  };
@@ -1,20 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.instrumentCommand = 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 Config_1 = require("../Config");
7
7
  const android = require("../Android");
8
8
  const PathsConstants_1 = require("../PathsConstants");
9
- const nodePath = require("path");
10
9
  const Ios_1 = require("../Ios");
11
10
  const InstrumentUtil_1 = require("../util/InstrumentUtil");
12
11
  const CustomArgumentUtil_1 = require("../util/CustomArgumentUtil");
13
12
  const Platform_1 = require("../api/model/Platform");
14
13
  const SourceMapUtil_1 = require("../util/SourceMapUtil");
15
- const instrumentCommand = () => {
16
- if (process.argv.includes('--help')) {
17
- Logger_1.default.logMessageSync(`
14
+ const platformLogPrefix = { info: ' ℹ️ ', warning: ' ⚠️ ', error: ' ❌ ' };
15
+ const logHelpMessage = () => {
16
+ const iOSDefaultPath = (0, node_path_1.join)(PathsConstants_1.default.getIOSFolder(), '<appName>', 'Info.plist');
17
+ const iOSSupportingDefaultPath = (0, node_path_1.join)(PathsConstants_1.default.getIOSFolder(), '<appName>', 'Supporting', 'Info.plist');
18
+ Logger_1.default.logMessageSync(`
18
19
  Usage: npx instrumentDynatrace [options]
19
20
 
20
21
  Options:
@@ -28,8 +29,8 @@ const instrumentCommand = () => {
28
29
  plist="/custom/path/to/Info.plist"
29
30
  Specify a custom path to the Info.plist file of your ios project.
30
31
  Default: Extracts <appName> from app.json and then tries
31
- ${nodePath.join(PathsConstants_1.default.getIOSFolder(), "<appName>", 'Info.plist')}
32
- and ${nodePath.join(PathsConstants_1.default.getIOSFolder(), "<appName>", "Supporting", "Info.plist")}
32
+ ${iOSDefaultPath}
33
+ and ${iOSSupportingDefaultPath}
33
34
  in that order
34
35
 
35
36
  Examples:
@@ -38,94 +39,114 @@ const instrumentCommand = () => {
38
39
  npx instrumentDynatrace gradle="/custom/path/to/build.gradle"
39
40
  npx instrumentDynatrace plist="/custom/path/to/Info.plist"
40
41
  `, Logger_1.default.INFO);
42
+ };
43
+ const persistCustomArguments = (argv) => {
44
+ if (argv.isEmpty()) {
45
+ (0, CustomArgumentUtil_1.clearCustomArguments)();
41
46
  return;
42
47
  }
43
- Logger_1.default.logMessageSync('⏳ Starting instrumentation of React Native application ..', Logger_1.default.INFO);
44
- Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ' }, () => (0, InstrumentUtil_1.showVersionOfPlugin)());
48
+ (0, CustomArgumentUtil_1.writeCustomArguments)(argv);
49
+ };
50
+ const resolveInstrumentationPaths = (argv) => {
45
51
  let pathToConfig = PathsConstants_1.default.getConfigFilePath();
46
52
  let pathToGradle = PathsConstants_1.default.getAndroidGradleFile(PathsConstants_1.default.getAndroidFolder());
47
53
  let pathToAppGradle = PathsConstants_1.default.getAndroidAppGradleFile(PathsConstants_1.default.getAndroidFolder());
48
- let androidAvailable = true;
49
54
  let pathToPList;
50
- let iosAvailable = true;
51
- const argv = (0, CustomArgumentUtil_1.parseCommandLine)(process.argv.slice(2));
52
- if (argv.isEmpty()) {
53
- (0, CustomArgumentUtil_1.clearCustomArguments)();
54
- }
55
- else {
56
- (0, CustomArgumentUtil_1.writeCustomArguments)(argv);
57
- }
58
55
  if (argv.isCustomConfigurationPathSet()) {
59
56
  pathToConfig = argv.getCustomConfigurationPath();
60
57
  }
61
- Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ', error: ' ❌ ' }, () => {
62
- if (argv.isCustomGradlePathSet()) {
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);
69
- androidAvailable = (0, InstrumentUtil_1.isPlatformAvailable)(pathToGradle, Platform_1.Platform.Android);
70
- }
71
- else {
72
- androidAvailable = (0, InstrumentUtil_1.isPlatformAvailable)(PathsConstants_1.default.getAndroidFolder(), Platform_1.Platform.Android);
73
- }
74
- if (argv.isCustomPlistPathSet()) {
75
- pathToPList = (0, path_1.resolve)(argv.getCustomPlistPath());
76
- iosAvailable = (0, InstrumentUtil_1.isPlatformAvailable)(pathToPList, Platform_1.Platform.IOS);
58
+ if (argv.isCustomGradlePathSet()) {
59
+ pathToGradle = argv.getCustomGradlePath();
60
+ if (!/build\.gradle(\.kts)?$/.test(pathToGradle)) {
61
+ throw new Error(`--gradle must point to build.gradle or build.gradle.kts file, got ${pathToGradle}`);
77
62
  }
78
- else {
79
- iosAvailable = (0, InstrumentUtil_1.isPlatformAvailable)(PathsConstants_1.default.getIOSFolder(), Platform_1.Platform.IOS);
80
- }
81
- });
82
- pathToConfig = (0, path_1.resolve)(pathToConfig);
83
- pathToGradle = (0, path_1.resolve)(pathToGradle);
84
- pathToAppGradle = (0, path_1.resolve)(pathToAppGradle);
85
- if (iosAvailable || androidAvailable) {
86
- try {
87
- Logger_1.default.logMessageSync('⏳ Trying to read configuration file: ' + pathToConfig, Logger_1.default.INFO);
88
- const configAgent = (0, Config_1.readConfig)(pathToConfig);
89
- if (androidAvailable) {
90
- try {
91
- Logger_1.default.logMessageSync('⏳ Starting Android Instrumentation with Dynatrace!', Logger_1.default.INFO);
92
- Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ', error: ' ❌ ' }, () => {
93
- android.instrumentAndroidPlatform(pathToGradle, false);
94
- android.writeGradleConfig(configAgent.android, pathToGradle);
95
- android.ensureRuntimeScriptApplied(pathToAppGradle);
96
- });
97
- Logger_1.default.logMessageSync(' ✅ Finished Android Instrumentation with Dynatrace!', Logger_1.default.INFO);
98
- }
99
- catch (e) {
100
- if (e instanceof Error) {
101
- Logger_1.default.logMessageSync(' ❌ Android Instrumentation failed: ' + e.message, Logger_1.default.ERROR);
102
- }
103
- }
104
- }
105
- if (iosAvailable) {
106
- try {
107
- Logger_1.default.logMessageSync('⏳ Starting iOS Instrumentation with Dynatrace!', Logger_1.default.INFO);
108
- Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ', error: ' ❌ ' }, () => Ios_1.default.modifyPListFile(pathToPList, configAgent.ios, false));
109
- Logger_1.default.logMessageSync(' ✅ Finished iOS Instrumentation with Dynatrace!', Logger_1.default.INFO);
110
- }
111
- catch (e) {
112
- if (e instanceof Error) {
113
- Logger_1.default.logMessageSync(' ❌ iOS Instrumentation failed: ' + e.message, Logger_1.default.ERROR);
114
- }
115
- }
116
- }
117
- (0, SourceMapUtil_1.patchMetroSourceMap)();
118
- Logger_1.default.logMessageSync('🎉 Finished instrumentation of React Native application ..', Logger_1.default.INFO);
63
+ pathToAppGradle = PathsConstants_1.default.getAndroidAppGradleFile((0, node_path_1.dirname)(pathToGradle));
64
+ }
65
+ if (argv.isCustomPlistPathSet()) {
66
+ pathToPList = argv.getCustomPlistPath();
67
+ }
68
+ return {
69
+ pathToConfig: (0, node_path_1.resolve)(pathToConfig),
70
+ pathToGradle: (0, node_path_1.resolve)(pathToGradle),
71
+ pathToAppGradle: (0, node_path_1.resolve)(pathToAppGradle),
72
+ pathToPList: pathToPList ? (0, node_path_1.resolve)(pathToPList) : undefined,
73
+ };
74
+ };
75
+ const detectPlatformAvailability = (argv, paths) => {
76
+ const androidAvailable = argv.isCustomGradlePathSet()
77
+ ? (0, InstrumentUtil_1.isPlatformAvailable)(paths.pathToGradle, Platform_1.Platform.Android)
78
+ : (0, InstrumentUtil_1.isPlatformAvailable)(PathsConstants_1.default.getAndroidFolder(), Platform_1.Platform.Android);
79
+ const iosAvailable = argv.isCustomPlistPathSet()
80
+ ? (0, InstrumentUtil_1.isPlatformAvailable)(paths.pathToPList, Platform_1.Platform.IOS)
81
+ : (0, InstrumentUtil_1.isPlatformAvailable)(PathsConstants_1.default.getIOSFolder(), Platform_1.Platform.IOS);
82
+ return { androidAvailable, iosAvailable };
83
+ };
84
+ const instrumentAndroidIfAvailable = (androidAvailable, pathToGradle, pathToAppGradle, androidConfig) => {
85
+ if (!androidAvailable) {
86
+ return;
87
+ }
88
+ try {
89
+ Logger_1.default.logMessageSync('⏳ Starting Android Instrumentation with Dynatrace!', Logger_1.default.INFO);
90
+ Logger_1.default.withPrefix(platformLogPrefix, () => {
91
+ android.instrumentAndroidPlatform(pathToGradle, false);
92
+ android.writeGradleConfig(androidConfig, pathToGradle);
93
+ android.ensureRuntimeScriptApplied(pathToAppGradle);
94
+ });
95
+ Logger_1.default.logMessageSync(' ✅ Finished Android Instrumentation with Dynatrace!', Logger_1.default.INFO);
96
+ }
97
+ catch (e) {
98
+ if (e instanceof Error) {
99
+ Logger_1.default.logMessageSync(' ❌ Android Instrumentation failed: ' + e.message, Logger_1.default.ERROR);
119
100
  }
120
- catch (e) {
121
- if (e instanceof Error) {
122
- Logger_1.default.logMessageSync('❌ Instrumentation failed: ' + e.message, Logger_1.default.ERROR);
123
- }
101
+ }
102
+ };
103
+ const instrumentIosIfAvailable = (iosAvailable, pathToPList, iosConfig) => {
104
+ if (!iosAvailable) {
105
+ return;
106
+ }
107
+ try {
108
+ Logger_1.default.logMessageSync('⏳ Starting iOS Instrumentation with Dynatrace!', Logger_1.default.INFO);
109
+ Logger_1.default.withPrefix(platformLogPrefix, () => Ios_1.default.modifyPListFile(pathToPList, iosConfig, false));
110
+ Logger_1.default.logMessageSync(' ✅ Finished iOS Instrumentation with Dynatrace!', Logger_1.default.INFO);
111
+ }
112
+ catch (e) {
113
+ if (e instanceof Error) {
114
+ Logger_1.default.logMessageSync(' ❌ iOS Instrumentation failed: ' + e.message, Logger_1.default.ERROR);
124
115
  }
125
116
  }
126
- else {
117
+ };
118
+ const runPlatformInstrumentation = (paths, availability) => {
119
+ if (!availability.iosAvailable && !availability.androidAvailable) {
127
120
  Logger_1.default.logMessageSync('⚠️ Both Android and iOS Folder are not available - Skip instrumentation.', Logger_1.default.WARNING);
121
+ return;
128
122
  }
123
+ try {
124
+ Logger_1.default.logMessageSync('⏳ Trying to read configuration file: ' + paths.pathToConfig, Logger_1.default.INFO);
125
+ const configAgent = (0, Config_1.readConfig)(paths.pathToConfig);
126
+ instrumentAndroidIfAvailable(availability.androidAvailable, paths.pathToGradle, paths.pathToAppGradle, configAgent.android);
127
+ instrumentIosIfAvailable(availability.iosAvailable, paths.pathToPList, configAgent.ios);
128
+ (0, SourceMapUtil_1.patchMetroSourceMap)();
129
+ Logger_1.default.logMessageSync('🎉 Finished instrumentation of React Native application ..', Logger_1.default.INFO);
130
+ }
131
+ catch (e) {
132
+ if (e instanceof Error) {
133
+ Logger_1.default.logMessageSync('❌ Instrumentation failed: ' + e.message, Logger_1.default.ERROR);
134
+ }
135
+ }
136
+ };
137
+ const instrumentCommand = () => {
138
+ const commandArgs = process.argv;
139
+ if (commandArgs.includes('--help')) {
140
+ logHelpMessage();
141
+ return;
142
+ }
143
+ Logger_1.default.logMessageSync('⏳ Starting instrumentation of React Native application ..', Logger_1.default.INFO);
144
+ Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ' }, () => (0, InstrumentUtil_1.showVersionOfPlugin)());
145
+ const argv = (0, CustomArgumentUtil_1.parseCommandLine)(commandArgs.slice(2));
146
+ persistCustomArguments(argv);
147
+ const instrumentationPaths = resolveInstrumentationPaths(argv);
148
+ const availability = Logger_1.default.withPrefix(platformLogPrefix, () => detectPlatformAvailability(argv, instrumentationPaths));
149
+ runPlatformInstrumentation(instrumentationPaths, availability);
129
150
  Logger_1.default.closeLogFile();
130
151
  };
131
152
  exports.instrumentCommand = instrumentCommand;
@@ -10,17 +10,19 @@ exports.PROCESS_CUSTOM_ARGUMENT_NAME = 'dtCustomArguments';
10
10
  const parseCommandLine = (inputArgs) => {
11
11
  const parsedArgs = new CustomArgumentsBuilderImpl_1.CustomArgumentsBuilderImpl();
12
12
  inputArgs.forEach((entry) => {
13
- const parts = entry.split('=');
14
- if (parts.length === 2) {
15
- switch (parts[0]) {
13
+ const eqIndex = entry.indexOf('=');
14
+ if (eqIndex !== -1) {
15
+ const key = entry.slice(0, eqIndex);
16
+ const value = entry.slice(eqIndex + 1);
17
+ switch (key) {
16
18
  case "gradle":
17
- parsedArgs.withGradleArgument(parts[1]);
19
+ parsedArgs.withGradleArgument(value);
18
20
  break;
19
21
  case "config":
20
- parsedArgs.withConfigurationArgument(parts[1]);
22
+ parsedArgs.withConfigurationArgument(value);
21
23
  break;
22
24
  case "plist":
23
- parsedArgs.withPlistArgument(parts[1]);
25
+ parsedArgs.withPlistArgument(value);
24
26
  break;
25
27
  }
26
28
  }