@dynatrace/react-native-plugin 2.331.1 → 2.333.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.
- package/README.md +96 -6
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +7 -1
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceUtils.kt +1 -0
- package/android/src/new/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +1 -0
- package/android/src/old/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +2 -1
- package/files/plugin.gradle +1 -1
- package/instrumentation/DynatraceInstrumentation.js +1 -1
- package/instrumentation/jsx/CreateElement.js +106 -6
- package/instrumentation/jsx/JsxDevRuntime.js +2 -6
- package/instrumentation/jsx/JsxRuntime.js +2 -6
- package/instrumentation/libs/withOnPressMonitoring.js +49 -3
- package/ios/DynatraceRNBridge.mm +8 -1
- package/lib/core/Application.js +2 -0
- package/lib/core/Dynatrace.js +2 -1
- package/lib/core/UserPrivacyOptions.js +8 -1
- package/lib/core/configuration/ConfigurationHandler.js +21 -0
- package/lib/features/ui-interaction/Config.js +36 -0
- package/lib/features/ui-interaction/IUserInteractionEvent.js +16 -0
- package/lib/features/ui-interaction/Plugin.js +945 -0
- package/lib/features/ui-interaction/RootDetection.js +51 -0
- package/lib/features/ui-interaction/RootWrapper.js +236 -0
- package/lib/features/ui-interaction/Run.js +34 -0
- package/lib/features/ui-interaction/Runtime.js +1494 -0
- package/lib/features/ui-interaction/Types.js +75 -0
- package/lib/next/Dynatrace.js +1 -1
- package/lib/next/configuration/INativeRuntimeConfiguration.js +1 -0
- package/lib/next/configuration/RuntimeConfigurationObserver.js +47 -12
- package/lib/next/events/EventPipeline.js +9 -0
- package/package.json +19 -10
- package/react-native-dynatrace.podspec +1 -1
- package/scripts/Config.js +1 -0
- package/src/lib/core/interface/NativeDynatraceBridge.ts +1 -0
- package/types.d.ts +22 -9
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectRootRegistrations = void 0;
|
|
4
|
+
const j = require("jscodeshift");
|
|
5
|
+
const isProjectFile = (filename) => filename && !/\/node_modules\//.test(filename);
|
|
6
|
+
const detectRootRegistrations = (root, filename) => {
|
|
7
|
+
if (!isProjectFile(filename)) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
const regs = [];
|
|
11
|
+
root.find(j.ImportDeclaration).forEach((p) => {
|
|
12
|
+
const importSource = (p.node.source.value || '');
|
|
13
|
+
if (importSource === 'expo-router' ||
|
|
14
|
+
importSource === 'expo-router/entry') {
|
|
15
|
+
regs.push({ type: 'expo_router_entry', path: p });
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
root.find(j.CallExpression, {
|
|
19
|
+
callee: { type: 'Identifier', name: 'registerRootComponent' },
|
|
20
|
+
}).forEach((p) => {
|
|
21
|
+
var _a;
|
|
22
|
+
const componentFactoryArg = (_a = p.node.arguments) === null || _a === void 0 ? void 0 : _a[0];
|
|
23
|
+
if (!componentFactoryArg) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
regs.push({
|
|
27
|
+
type: 'expo_register',
|
|
28
|
+
path: p,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
root.find(j.CallExpression, {
|
|
32
|
+
callee: {
|
|
33
|
+
type: 'MemberExpression',
|
|
34
|
+
object: { type: 'Identifier', name: 'AppRegistry' },
|
|
35
|
+
property: { type: 'Identifier', name: 'registerComponent' },
|
|
36
|
+
},
|
|
37
|
+
}).forEach((p) => {
|
|
38
|
+
var _a, _b;
|
|
39
|
+
const appNameArg = (_a = p.node.arguments) === null || _a === void 0 ? void 0 : _a[0];
|
|
40
|
+
const componentFactoryArg = (_b = p.node.arguments) === null || _b === void 0 ? void 0 : _b[1];
|
|
41
|
+
if (!appNameArg || !componentFactoryArg) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
regs.push({
|
|
45
|
+
type: 'rn_register',
|
|
46
|
+
path: p,
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
return regs;
|
|
50
|
+
};
|
|
51
|
+
exports.detectRootRegistrations = detectRootRegistrations;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapDetectedRoots = void 0;
|
|
4
|
+
const jsc = require("jscodeshift");
|
|
5
|
+
const Config_1 = require("./Config");
|
|
6
|
+
const Types_1 = require("./Types");
|
|
7
|
+
const DT_CFG_NAME = 'DT_ANALYTICS_CONFIG';
|
|
8
|
+
const ensureReactImportAST = (j, root) => {
|
|
9
|
+
const has = root
|
|
10
|
+
.find(j.ImportDeclaration, { source: { value: 'react' } })
|
|
11
|
+
.filter((p) => (p.node.specifiers || []).some((s) => {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
return (j.ImportDefaultSpecifier.check(s) &&
|
|
14
|
+
((_a = s.local) === null || _a === void 0 ? void 0 : _a.name) === 'React') ||
|
|
15
|
+
(j.ImportNamespaceSpecifier.check(s) &&
|
|
16
|
+
((_b = s.local) === null || _b === void 0 ? void 0 : _b.name) === 'React');
|
|
17
|
+
}))
|
|
18
|
+
.size() > 0;
|
|
19
|
+
if (has) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const firstImport = root.find(j.ImportDeclaration).at(0);
|
|
23
|
+
const imp = j.importDeclaration([j.importNamespaceSpecifier(j.identifier('React'))], j.literal('react'));
|
|
24
|
+
if (firstImport.size() > 0) {
|
|
25
|
+
firstImport.insertBefore(imp);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
root.get().node.program.body.unshift(imp);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const ensureRuntimeImportAST = (j, root) => {
|
|
32
|
+
const from = Types_1.Literals.DefaultRuntimeImport;
|
|
33
|
+
const has = root
|
|
34
|
+
.find(j.ImportDeclaration, { source: { value: from } })
|
|
35
|
+
.filter((p) => (p.node.specifiers || []).some((s) => {
|
|
36
|
+
var _a;
|
|
37
|
+
return j.ImportSpecifier.check(s) &&
|
|
38
|
+
((_a = s.imported) === null || _a === void 0 ? void 0 : _a.name) === 'AnalyticsRoot';
|
|
39
|
+
}))
|
|
40
|
+
.size() > 0;
|
|
41
|
+
if (has) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const decl = j.importDeclaration([j.importSpecifier(j.identifier('AnalyticsRoot'))], j.literal(from));
|
|
45
|
+
const firstImport = root.find(j.ImportDeclaration).at(0);
|
|
46
|
+
if (firstImport.size() > 0) {
|
|
47
|
+
firstImport.insertBefore(decl);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
root.get().node.program.body.unshift(decl);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const valueToExpression = (j, v) => {
|
|
54
|
+
if (v === null) {
|
|
55
|
+
return j.nullLiteral();
|
|
56
|
+
}
|
|
57
|
+
const t = typeof v;
|
|
58
|
+
if (t === 'string' || t === 'number' || t === 'boolean') {
|
|
59
|
+
return j.literal(v);
|
|
60
|
+
}
|
|
61
|
+
if (Array.isArray(v)) {
|
|
62
|
+
return j.arrayExpression(v.map((x) => valueToExpression(j, x)));
|
|
63
|
+
}
|
|
64
|
+
if (t === 'object') {
|
|
65
|
+
return j.objectExpression(Object.keys(v).map((k) => j.objectProperty(j.identifier(k), valueToExpression(j, v[k]))));
|
|
66
|
+
}
|
|
67
|
+
return j.nullLiteral();
|
|
68
|
+
};
|
|
69
|
+
const ensureConfigConstAST = (j, root) => {
|
|
70
|
+
const exists = root
|
|
71
|
+
.find(j.VariableDeclaration)
|
|
72
|
+
.filter((p) => (p.node.declarations || []).some((d) => j.VariableDeclarator.check(d) &&
|
|
73
|
+
j.Identifier.check(d.id) &&
|
|
74
|
+
d.id.name === DT_CFG_NAME))
|
|
75
|
+
.size() > 0;
|
|
76
|
+
if (exists) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const init = valueToExpression(j, Config_1.DT_UII_ROOT_CONFIG);
|
|
80
|
+
const decl = j.variableDeclaration('const', [
|
|
81
|
+
j.variableDeclarator(j.identifier(DT_CFG_NAME), init),
|
|
82
|
+
]);
|
|
83
|
+
const firstImport = root.find(j.ImportDeclaration).at(0);
|
|
84
|
+
if (firstImport.size() > 0) {
|
|
85
|
+
firstImport.insertAfter(decl);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
root.get().node.program.body.unshift(decl);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const isCreateAnalyticsRoot = (j, n) => j.CallExpression.check(n) &&
|
|
92
|
+
j.MemberExpression.check(n.callee) &&
|
|
93
|
+
j.Identifier.check(n.callee.object) &&
|
|
94
|
+
n.callee.object.name === 'React' &&
|
|
95
|
+
j.Identifier.check(n.callee.property) &&
|
|
96
|
+
n.callee.property.name === 'createElement' &&
|
|
97
|
+
n.arguments.length >= 1 &&
|
|
98
|
+
j.Identifier.check(n.arguments[0]) &&
|
|
99
|
+
n.arguments[0].name === 'AnalyticsRoot';
|
|
100
|
+
const funcBodyContainsAnalyticsRoot = (j, f) => {
|
|
101
|
+
if (!j.ArrowFunctionExpression.check(f) && !j.FunctionExpression.check(f)) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (j.BlockStatement.check(f.body)) {
|
|
105
|
+
let found = false;
|
|
106
|
+
j(f.body)
|
|
107
|
+
.find(j.CallExpression)
|
|
108
|
+
.forEach((p) => {
|
|
109
|
+
if (isCreateAnalyticsRoot(j, p.node)) {
|
|
110
|
+
found = true;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
return found;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
return isCreateAnalyticsRoot(j, f.body);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const createAnalyticsWrappedElement = (j, componentExpr, propsId) => j.callExpression(j.memberExpression(j.identifier('React'), j.identifier('createElement')), [
|
|
120
|
+
j.identifier('AnalyticsRoot'),
|
|
121
|
+
j.objectExpression([
|
|
122
|
+
j.property('init', j.identifier('name'), j.literal('App')),
|
|
123
|
+
j.property('init', j.identifier('config'), j.identifier(DT_CFG_NAME)),
|
|
124
|
+
]),
|
|
125
|
+
j.callExpression(j.memberExpression(j.identifier('React'), j.identifier('createElement')), [
|
|
126
|
+
componentExpr,
|
|
127
|
+
propsId ? j.identifier(propsId) : j.nullLiteral(),
|
|
128
|
+
]),
|
|
129
|
+
]);
|
|
130
|
+
const makeWrappedFactoryArrow = (j, innerCreateExpr) => j.arrowFunctionExpression([], j.blockStatement([
|
|
131
|
+
j.returnStatement(j.functionExpression(j.identifier('Wrapped'), [j.identifier('props')], j.blockStatement([
|
|
132
|
+
j.returnStatement(j.callExpression(j.memberExpression(j.identifier('React'), j.identifier('createElement')), [
|
|
133
|
+
j.identifier('AnalyticsRoot'),
|
|
134
|
+
j.objectExpression([
|
|
135
|
+
j.property('init', j.identifier('name'), j.literal('App')),
|
|
136
|
+
j.property('init', j.identifier('config'), j.identifier(DT_CFG_NAME)),
|
|
137
|
+
]),
|
|
138
|
+
j.callExpression(j.memberExpression(j.identifier('React'), j.identifier('createElement')), [
|
|
139
|
+
innerCreateExpr,
|
|
140
|
+
j.identifier('props'),
|
|
141
|
+
]),
|
|
142
|
+
])),
|
|
143
|
+
]))),
|
|
144
|
+
]));
|
|
145
|
+
const wrapExpoRegister = (j, callPath) => {
|
|
146
|
+
var _a;
|
|
147
|
+
const a0 = (_a = callPath.node.arguments) === null || _a === void 0 ? void 0 : _a[0];
|
|
148
|
+
if (!a0) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
if (j.ArrowFunctionExpression.check(a0) || j.FunctionExpression.check(a0)) {
|
|
152
|
+
if (funcBodyContainsAnalyticsRoot(j, a0)) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (j.Identifier.check(a0)) {
|
|
157
|
+
const inner = createAnalyticsWrappedElement(j, j.identifier(a0.name));
|
|
158
|
+
callPath.node.arguments[0] = j.arrowFunctionExpression([], inner);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
if (j.ArrowFunctionExpression.check(a0) || j.FunctionExpression.check(a0)) {
|
|
162
|
+
const res = j.callExpression(a0, []);
|
|
163
|
+
const inner = createAnalyticsWrappedElement(j, res);
|
|
164
|
+
callPath.node.arguments[0] = j.arrowFunctionExpression([], inner);
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
if (j.JSXElement.check(a0) || j.CallExpression.check(a0)) {
|
|
168
|
+
const inner = createAnalyticsWrappedElement(j, a0);
|
|
169
|
+
callPath.node.arguments[0] = j.arrowFunctionExpression([], inner);
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
};
|
|
174
|
+
const wrapRNRegister = (j, callPath) => {
|
|
175
|
+
var _a;
|
|
176
|
+
const facArg = (_a = callPath.node.arguments) === null || _a === void 0 ? void 0 : _a[1];
|
|
177
|
+
if (!facArg) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
if (j.ArrowFunctionExpression.check(facArg) ||
|
|
181
|
+
j.FunctionExpression.check(facArg)) {
|
|
182
|
+
if (funcBodyContainsAnalyticsRoot(j, facArg)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
const body = j.BlockStatement.check(facArg.body)
|
|
186
|
+
? j.callExpression(facArg, [])
|
|
187
|
+
: facArg.body;
|
|
188
|
+
const chooseComp = j.conditionalExpression(j.callExpression(j.memberExpression(j.identifier('React'), j.identifier('isValidElement')), [body]), j.arrowFunctionExpression([], body), body);
|
|
189
|
+
callPath.node.arguments[1] = makeWrappedFactoryArrow(j, chooseComp);
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
if (j.Identifier.check(facArg) || j.MemberExpression.check(facArg)) {
|
|
193
|
+
const callComp = j.callExpression(facArg, []);
|
|
194
|
+
const chooseComp = j.conditionalExpression(j.callExpression(j.memberExpression(j.identifier('React'), j.identifier('isValidElement')), [callComp]), j.arrowFunctionExpression([], callComp), callComp);
|
|
195
|
+
callPath.node.arguments[1] = makeWrappedFactoryArrow(j, chooseComp);
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
if (j.JSXElement.check(facArg) || j.CallExpression.check(facArg)) {
|
|
199
|
+
const elem = j.ArrowFunctionExpression.check(facArg)
|
|
200
|
+
? facArg.body
|
|
201
|
+
: facArg;
|
|
202
|
+
const chooseComp = j.arrowFunctionExpression([], elem);
|
|
203
|
+
callPath.node.arguments[1] = makeWrappedFactoryArrow(j, chooseComp);
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
};
|
|
208
|
+
const wrapDetectedRoots = (root, regs) => {
|
|
209
|
+
const j = jsc.withParser('tsx');
|
|
210
|
+
let changed = false;
|
|
211
|
+
if (!regs.length) {
|
|
212
|
+
return { root, changed };
|
|
213
|
+
}
|
|
214
|
+
ensureReactImportAST(j, root);
|
|
215
|
+
ensureRuntimeImportAST(j, root);
|
|
216
|
+
ensureConfigConstAST(j, root);
|
|
217
|
+
regs.forEach((r) => {
|
|
218
|
+
if (r.type === 'expo_register') {
|
|
219
|
+
const ok = wrapExpoRegister(j, r.path);
|
|
220
|
+
if (ok) {
|
|
221
|
+
changed = true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else if (r.type === 'rn_register') {
|
|
225
|
+
const ok = wrapRNRegister(j, r.path);
|
|
226
|
+
if (ok) {
|
|
227
|
+
changed = true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
changed = changed || false;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
return { root, changed };
|
|
235
|
+
};
|
|
236
|
+
exports.wrapDetectedRoots = wrapDetectedRoots;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runDTUserInteraction = void 0;
|
|
4
|
+
const Config_1 = require("./Config");
|
|
5
|
+
const Plugin_1 = require("./Plugin");
|
|
6
|
+
const RootDetection_1 = require("./RootDetection");
|
|
7
|
+
const RootWrapper_1 = require("./RootWrapper");
|
|
8
|
+
const runDTUserInteraction = (root, filename, dynatraceOptions) => {
|
|
9
|
+
var _a;
|
|
10
|
+
const dtUiEnabled = (dynatraceOptions === null || dynatraceOptions === void 0 ? void 0 : dynatraceOptions.userInteraction) === true;
|
|
11
|
+
if (!dtUiEnabled) {
|
|
12
|
+
return { root, modified: false };
|
|
13
|
+
}
|
|
14
|
+
const shouldInjectPressableImport = typeof ((_a = dynatraceOptions === null || dynatraceOptions === void 0 ? void 0 : dynatraceOptions.input) === null || _a === void 0 ? void 0 : _a.instrument) === 'function'
|
|
15
|
+
? dynatraceOptions.input.instrument(filename) !== false
|
|
16
|
+
: true;
|
|
17
|
+
let modified = false;
|
|
18
|
+
const regs = (0, RootDetection_1.detectRootRegistrations)(root, filename);
|
|
19
|
+
if (regs.length) {
|
|
20
|
+
const r = (0, RootWrapper_1.wrapDetectedRoots)(root, regs);
|
|
21
|
+
root = r.root;
|
|
22
|
+
if (r.changed) {
|
|
23
|
+
modified = true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const mergedDT = Object.assign(Object.assign({}, (0, Config_1.getDTConfig)()), { shouldInjectPressableImport });
|
|
27
|
+
const dt = (0, Plugin_1.default)(root, filename, mergedDT);
|
|
28
|
+
root = dt.root;
|
|
29
|
+
if (dt.changed) {
|
|
30
|
+
modified = true;
|
|
31
|
+
}
|
|
32
|
+
return { root, modified };
|
|
33
|
+
};
|
|
34
|
+
exports.runDTUserInteraction = runDTUserInteraction;
|