@sentry/babel-plugin-component-annotate 4.9.1 → 5.0.0
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/dist/cjs/index.js +566 -1009
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.mjs +564 -1005
- package/dist/esm/index.mjs.map +1 -1
- package/package.json +6 -10
package/dist/esm/index.mjs
CHANGED
|
@@ -1,1066 +1,625 @@
|
|
|
1
|
-
|
|
2
|
-
var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"];
|
|
3
|
-
if (null != _i) {
|
|
4
|
-
var _s,
|
|
5
|
-
_e,
|
|
6
|
-
_x,
|
|
7
|
-
_r,
|
|
8
|
-
_arr = [],
|
|
9
|
-
_n = !0,
|
|
10
|
-
_d = !1;
|
|
11
|
-
try {
|
|
12
|
-
if (_x = (_i = _i.call(arr)).next, 0 === i) {
|
|
13
|
-
if (Object(_i) !== _i) return;
|
|
14
|
-
_n = !1;
|
|
15
|
-
} else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0);
|
|
16
|
-
} catch (err) {
|
|
17
|
-
_d = !0, _e = err;
|
|
18
|
-
} finally {
|
|
19
|
-
try {
|
|
20
|
-
if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return;
|
|
21
|
-
} finally {
|
|
22
|
-
if (_d) throw _e;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return _arr;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function _typeof(obj) {
|
|
29
|
-
"@babel/helpers - typeof";
|
|
30
|
-
|
|
31
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
|
|
32
|
-
return typeof obj;
|
|
33
|
-
} : function (obj) {
|
|
34
|
-
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
35
|
-
}, _typeof(obj);
|
|
36
|
-
}
|
|
37
|
-
function _slicedToArray(arr, i) {
|
|
38
|
-
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
|
39
|
-
}
|
|
40
|
-
function _arrayWithHoles(arr) {
|
|
41
|
-
if (Array.isArray(arr)) return arr;
|
|
42
|
-
}
|
|
43
|
-
function _unsupportedIterableToArray(o, minLen) {
|
|
44
|
-
if (!o) return;
|
|
45
|
-
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
|
46
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
47
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
48
|
-
if (n === "Map" || n === "Set") return Array.from(o);
|
|
49
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
|
50
|
-
}
|
|
51
|
-
function _arrayLikeToArray(arr, len) {
|
|
52
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
53
|
-
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
|
54
|
-
return arr2;
|
|
55
|
-
}
|
|
56
|
-
function _nonIterableRest() {
|
|
57
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
58
|
-
}
|
|
59
|
-
function _createForOfIteratorHelper(o, allowArrayLike) {
|
|
60
|
-
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
|
|
61
|
-
if (!it) {
|
|
62
|
-
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
|
|
63
|
-
if (it) o = it;
|
|
64
|
-
var i = 0;
|
|
65
|
-
var F = function () {};
|
|
66
|
-
return {
|
|
67
|
-
s: F,
|
|
68
|
-
n: function () {
|
|
69
|
-
if (i >= o.length) return {
|
|
70
|
-
done: true
|
|
71
|
-
};
|
|
72
|
-
return {
|
|
73
|
-
done: false,
|
|
74
|
-
value: o[i++]
|
|
75
|
-
};
|
|
76
|
-
},
|
|
77
|
-
e: function (e) {
|
|
78
|
-
throw e;
|
|
79
|
-
},
|
|
80
|
-
f: F
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
84
|
-
}
|
|
85
|
-
var normalCompletion = true,
|
|
86
|
-
didErr = false,
|
|
87
|
-
err;
|
|
88
|
-
return {
|
|
89
|
-
s: function () {
|
|
90
|
-
it = it.call(o);
|
|
91
|
-
},
|
|
92
|
-
n: function () {
|
|
93
|
-
var step = it.next();
|
|
94
|
-
normalCompletion = step.done;
|
|
95
|
-
return step;
|
|
96
|
-
},
|
|
97
|
-
e: function (e) {
|
|
98
|
-
didErr = true;
|
|
99
|
-
err = e;
|
|
100
|
-
},
|
|
101
|
-
f: function () {
|
|
102
|
-
try {
|
|
103
|
-
if (!normalCompletion && it.return != null) it.return();
|
|
104
|
-
} finally {
|
|
105
|
-
if (didErr) throw err;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
1
|
+
//#region src/constants.ts
|
|
111
2
|
/**
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"
|
|
139
|
-
|
|
140
|
-
"
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
3
|
+
* MIT License
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2020 Engineering at FullStory
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
* copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
* SOFTWARE.
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
26
|
+
const KNOWN_INCOMPATIBLE_PLUGINS = ["react-native-testfairy", "@react-navigation"];
|
|
27
|
+
const DEFAULT_IGNORED_ELEMENTS = [
|
|
28
|
+
"a",
|
|
29
|
+
"abbr",
|
|
30
|
+
"address",
|
|
31
|
+
"area",
|
|
32
|
+
"article",
|
|
33
|
+
"aside",
|
|
34
|
+
"audio",
|
|
35
|
+
"b",
|
|
36
|
+
"base",
|
|
37
|
+
"bdi",
|
|
38
|
+
"bdo",
|
|
39
|
+
"blockquote",
|
|
40
|
+
"body",
|
|
41
|
+
"br",
|
|
42
|
+
"button",
|
|
43
|
+
"canvas",
|
|
44
|
+
"caption",
|
|
45
|
+
"cite",
|
|
46
|
+
"code",
|
|
47
|
+
"col",
|
|
48
|
+
"colgroup",
|
|
49
|
+
"data",
|
|
50
|
+
"datalist",
|
|
51
|
+
"dd",
|
|
52
|
+
"del",
|
|
53
|
+
"details",
|
|
54
|
+
"dfn",
|
|
55
|
+
"dialog",
|
|
56
|
+
"div",
|
|
57
|
+
"dl",
|
|
58
|
+
"dt",
|
|
59
|
+
"em",
|
|
60
|
+
"embed",
|
|
61
|
+
"fieldset",
|
|
62
|
+
"figure",
|
|
63
|
+
"footer",
|
|
64
|
+
"form",
|
|
65
|
+
"h1",
|
|
66
|
+
"h2",
|
|
67
|
+
"h3",
|
|
68
|
+
"h4",
|
|
69
|
+
"h5",
|
|
70
|
+
"h6",
|
|
71
|
+
"head",
|
|
72
|
+
"header",
|
|
73
|
+
"hgroup",
|
|
74
|
+
"hr",
|
|
75
|
+
"html",
|
|
76
|
+
"i",
|
|
77
|
+
"iframe",
|
|
78
|
+
"img",
|
|
79
|
+
"input",
|
|
80
|
+
"ins",
|
|
81
|
+
"kbd",
|
|
82
|
+
"keygen",
|
|
83
|
+
"label",
|
|
84
|
+
"legend",
|
|
85
|
+
"li",
|
|
86
|
+
"link",
|
|
87
|
+
"main",
|
|
88
|
+
"map",
|
|
89
|
+
"mark",
|
|
90
|
+
"menu",
|
|
91
|
+
"menuitem",
|
|
92
|
+
"meter",
|
|
93
|
+
"nav",
|
|
94
|
+
"noscript",
|
|
95
|
+
"object",
|
|
96
|
+
"ol",
|
|
97
|
+
"optgroup",
|
|
98
|
+
"option",
|
|
99
|
+
"output",
|
|
100
|
+
"p",
|
|
101
|
+
"param",
|
|
102
|
+
"pre",
|
|
103
|
+
"progress",
|
|
104
|
+
"q",
|
|
105
|
+
"rb",
|
|
106
|
+
"rp",
|
|
107
|
+
"rt",
|
|
108
|
+
"rtc",
|
|
109
|
+
"ruby",
|
|
110
|
+
"s",
|
|
111
|
+
"samp",
|
|
112
|
+
"script",
|
|
113
|
+
"section",
|
|
114
|
+
"select",
|
|
115
|
+
"small",
|
|
116
|
+
"source",
|
|
117
|
+
"span",
|
|
118
|
+
"strong",
|
|
119
|
+
"style",
|
|
120
|
+
"sub",
|
|
121
|
+
"summary",
|
|
122
|
+
"sup",
|
|
123
|
+
"table",
|
|
124
|
+
"tbody",
|
|
125
|
+
"td",
|
|
126
|
+
"template",
|
|
127
|
+
"textarea",
|
|
128
|
+
"tfoot",
|
|
129
|
+
"th",
|
|
130
|
+
"thead",
|
|
131
|
+
"time",
|
|
132
|
+
"title",
|
|
133
|
+
"tr",
|
|
134
|
+
"track",
|
|
135
|
+
"u",
|
|
136
|
+
"ul",
|
|
137
|
+
"var",
|
|
138
|
+
"video",
|
|
139
|
+
"wbr"
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/experimental.ts
|
|
144
|
+
const REACT_NATIVE_ELEMENTS = [
|
|
145
|
+
"Image",
|
|
146
|
+
"Text",
|
|
147
|
+
"View",
|
|
148
|
+
"ScrollView",
|
|
149
|
+
"TextInput",
|
|
150
|
+
"TouchableOpacity",
|
|
151
|
+
"TouchableHighlight",
|
|
152
|
+
"TouchableWithoutFeedback",
|
|
153
|
+
"FlatList",
|
|
154
|
+
"SectionList",
|
|
155
|
+
"ActivityIndicator",
|
|
156
|
+
"Button",
|
|
157
|
+
"Switch",
|
|
158
|
+
"Modal",
|
|
159
|
+
"SafeAreaView",
|
|
160
|
+
"StatusBar",
|
|
161
|
+
"KeyboardAvoidingView",
|
|
162
|
+
"RefreshControl",
|
|
163
|
+
"Picker",
|
|
164
|
+
"Slider"
|
|
165
|
+
];
|
|
166
|
+
function experimentalComponentNameAnnotatePlugin({ types: t }) {
|
|
167
|
+
return { visitor: {
|
|
168
|
+
Program: { enter(path, state) {
|
|
169
|
+
state.sentryFragmentContext = collectFragmentContext$1(path);
|
|
170
|
+
} },
|
|
171
|
+
FunctionDeclaration(path, state) {
|
|
172
|
+
if (!path.node.id || !path.node.id.name) return;
|
|
173
|
+
functionBodyPushAttributes$1(createJSXProcessingContext$1(state, t, path.node.id.name), path);
|
|
174
|
+
},
|
|
175
|
+
ArrowFunctionExpression(path, state) {
|
|
176
|
+
const parent = path.parent;
|
|
177
|
+
if (!parent || !("id" in parent) || !parent.id || !("name" in parent.id) || !parent.id.name) return;
|
|
178
|
+
functionBodyPushAttributes$1(createJSXProcessingContext$1(state, t, parent.id.name), path);
|
|
179
|
+
},
|
|
180
|
+
ClassDeclaration(path, state) {
|
|
181
|
+
const name = path.get("id");
|
|
182
|
+
const render = path.get("body").get("body").find((prop) => {
|
|
183
|
+
return prop.isClassMethod() && prop.get("key").isIdentifier({ name: "render" });
|
|
184
|
+
});
|
|
185
|
+
if (!render || !render.traverse) return;
|
|
186
|
+
const context = createJSXProcessingContext$1(state, t, name.node?.name || "");
|
|
187
|
+
render.traverse({ ReturnStatement(returnStatement) {
|
|
188
|
+
const arg = returnStatement.get("argument");
|
|
189
|
+
if (!arg.isJSXElement() && !arg.isJSXFragment()) return;
|
|
190
|
+
processJSX$1(context, arg);
|
|
191
|
+
} });
|
|
192
|
+
}
|
|
193
|
+
} };
|
|
234
194
|
}
|
|
235
|
-
|
|
236
195
|
/**
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
196
|
+
* Checks if an element name represents an HTML element (as opposed to a React component).
|
|
197
|
+
* HTML elements include standard lowercase HTML tags and React Native elements.
|
|
198
|
+
*/
|
|
240
199
|
function isHtmlElement(elementName) {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
// Check for lowercase first letter (standard HTML elements)
|
|
247
|
-
if (elementName.length > 0 && elementName.charAt(0) === elementName.charAt(0).toLowerCase()) {
|
|
248
|
-
return true;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// React Native elements typically start with uppercase but are still "native" elements
|
|
252
|
-
// We consider them HTML-like elements for annotation purposes
|
|
253
|
-
if (REACT_NATIVE_ELEMENTS.includes(elementName)) {
|
|
254
|
-
return true;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Otherwise, assume it's a React component (PascalCase)
|
|
258
|
-
return false;
|
|
200
|
+
if (elementName === UNKNOWN_ELEMENT_NAME$1) return false;
|
|
201
|
+
if (elementName.length > 0 && elementName.charAt(0) === elementName.charAt(0).toLowerCase()) return true;
|
|
202
|
+
if (REACT_NATIVE_ELEMENTS.includes(elementName)) return true;
|
|
203
|
+
return false;
|
|
259
204
|
}
|
|
260
|
-
|
|
261
205
|
/**
|
|
262
|
-
|
|
263
|
-
|
|
206
|
+
* Creates a JSX processing context from the plugin state
|
|
207
|
+
*/
|
|
264
208
|
function createJSXProcessingContext$1(state, t, componentName) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
};
|
|
209
|
+
return {
|
|
210
|
+
t,
|
|
211
|
+
componentName,
|
|
212
|
+
attributeName: attributeNamesFromState$1(state),
|
|
213
|
+
ignoredComponents: state.opts.ignoredComponents ?? [],
|
|
214
|
+
fragmentContext: state.sentryFragmentContext
|
|
215
|
+
};
|
|
273
216
|
}
|
|
274
|
-
|
|
275
217
|
/**
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
218
|
+
* Processes the body of a function to add Sentry tracking attributes to JSX elements.
|
|
219
|
+
* Handles various function body structures including direct JSX returns, conditional expressions,
|
|
220
|
+
* and nested JSX elements.
|
|
221
|
+
*/
|
|
280
222
|
function functionBodyPushAttributes$1(context, path) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
var consequent = arg.get("consequent");
|
|
310
|
-
if (consequent.isJSXFragment() || consequent.isJSXElement()) {
|
|
311
|
-
processJSX$1(context, consequent);
|
|
312
|
-
}
|
|
313
|
-
var alternate = arg.get("alternate");
|
|
314
|
-
if (alternate.isJSXFragment() || alternate.isJSXElement()) {
|
|
315
|
-
processJSX$1(context, alternate);
|
|
316
|
-
}
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
if (!arg.isJSXFragment() && !arg.isJSXElement()) {
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
jsxNode = arg;
|
|
323
|
-
}
|
|
324
|
-
if (!jsxNode) {
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
processJSX$1(context, jsxNode);
|
|
223
|
+
let jsxNode;
|
|
224
|
+
const functionBody = path.get("body").get("body");
|
|
225
|
+
if (!("length" in functionBody) && functionBody.parent && (functionBody.parent.type === "JSXElement" || functionBody.parent.type === "JSXFragment")) {
|
|
226
|
+
const maybeJsxNode = functionBody.find((c) => {
|
|
227
|
+
return c.type === "JSXElement" || c.type === "JSXFragment";
|
|
228
|
+
});
|
|
229
|
+
if (!maybeJsxNode) return;
|
|
230
|
+
jsxNode = maybeJsxNode;
|
|
231
|
+
} else {
|
|
232
|
+
const returnStatement = functionBody.find((c) => {
|
|
233
|
+
return c.type === "ReturnStatement";
|
|
234
|
+
});
|
|
235
|
+
if (!returnStatement) return;
|
|
236
|
+
const arg = returnStatement.get("argument");
|
|
237
|
+
if (!arg) return;
|
|
238
|
+
if (Array.isArray(arg)) return;
|
|
239
|
+
if (arg.isConditionalExpression()) {
|
|
240
|
+
const consequent = arg.get("consequent");
|
|
241
|
+
if (consequent.isJSXFragment() || consequent.isJSXElement()) processJSX$1(context, consequent);
|
|
242
|
+
const alternate = arg.get("alternate");
|
|
243
|
+
if (alternate.isJSXFragment() || alternate.isJSXElement()) processJSX$1(context, alternate);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (!arg.isJSXFragment() && !arg.isJSXElement()) return;
|
|
247
|
+
jsxNode = arg;
|
|
248
|
+
}
|
|
249
|
+
if (!jsxNode) return;
|
|
250
|
+
processJSX$1(context, jsxNode);
|
|
328
251
|
}
|
|
329
|
-
|
|
330
252
|
/**
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
253
|
+
* Recursively processes JSX elements to add Sentry tracking attributes.
|
|
254
|
+
* Handles both JSX elements and fragments, applying appropriate attributes
|
|
255
|
+
* based on configuration and component context.
|
|
256
|
+
*/
|
|
335
257
|
function processJSX$1(context, jsxNode) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
if (hasInjectedAttributes) {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
var children = jsxNode.get("children");
|
|
351
|
-
// TODO: See why `Array.isArray` doesn't have correct behaviour here
|
|
352
|
-
if (children && !("length" in children)) {
|
|
353
|
-
// A single child was found, maybe a bit of static text
|
|
354
|
-
children = [children];
|
|
355
|
-
}
|
|
356
|
-
children.forEach(function (child) {
|
|
357
|
-
// Happens for some node types like plain text
|
|
358
|
-
if (!child.node) {
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// If the current element is a fragment, children are still considered at root level
|
|
363
|
-
// Otherwise, children are not at root level
|
|
364
|
-
var openingElement = child.get("openingElement");
|
|
365
|
-
// TODO: Improve this. We never expect to have multiple opening elements
|
|
366
|
-
// but if it's possible, this should work
|
|
367
|
-
if (Array.isArray(openingElement)) {
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
processJSX$1(context, child);
|
|
371
|
-
});
|
|
258
|
+
if (!jsxNode) return;
|
|
259
|
+
const paths = jsxNode.get("openingElement");
|
|
260
|
+
if ((Array.isArray(paths) ? paths : [paths]).reduce((prev, openingElement) => prev || applyAttributes$1(context, openingElement, context.componentName), false)) return;
|
|
261
|
+
let children = jsxNode.get("children");
|
|
262
|
+
if (children && !("length" in children)) children = [children];
|
|
263
|
+
children.forEach((child) => {
|
|
264
|
+
if (!child.node) return;
|
|
265
|
+
const openingElement = child.get("openingElement");
|
|
266
|
+
if (Array.isArray(openingElement)) return;
|
|
267
|
+
processJSX$1(context, child);
|
|
268
|
+
});
|
|
372
269
|
}
|
|
373
|
-
|
|
374
270
|
/**
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
271
|
+
* Applies Sentry tracking attributes to a JSX opening element.
|
|
272
|
+
* Adds component name, element name, and source file attributes while
|
|
273
|
+
* respecting ignore lists and fragment detection.
|
|
274
|
+
*/
|
|
379
275
|
function applyAttributes$1(context, openingElement, componentName) {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// Check if this is a React fragment - if so, skip attribute addition entirely
|
|
391
|
-
var isFragment = isReactFragment$1(t, openingElement, fragmentContext);
|
|
392
|
-
if (isFragment) {
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
if (!openingElement.node.attributes) {
|
|
396
|
-
openingElement.node.attributes = [];
|
|
397
|
-
}
|
|
398
|
-
var elementName = getPathName$1(t, openingElement);
|
|
399
|
-
if (!isHtmlElement(elementName)) {
|
|
400
|
-
return false;
|
|
401
|
-
}
|
|
402
|
-
var isAnIgnoredComponent = ignoredComponents.some(function (ignoredComponent) {
|
|
403
|
-
return ignoredComponent === componentName || ignoredComponent === elementName;
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
// Add a stable attribute for the component name (only for root elements)
|
|
407
|
-
if (!isAnIgnoredComponent && !hasAttributeWithName$1(openingElement, componentAttributeName)) {
|
|
408
|
-
if (componentAttributeName) {
|
|
409
|
-
openingElement.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(componentAttributeName), t.stringLiteral(componentName)));
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
return true;
|
|
276
|
+
const { t, attributeName: componentAttributeName, ignoredComponents, fragmentContext } = context;
|
|
277
|
+
if (!openingElement.node) return false;
|
|
278
|
+
if (isReactFragment$1(t, openingElement, fragmentContext)) return false;
|
|
279
|
+
if (!openingElement.node.attributes) openingElement.node.attributes = [];
|
|
280
|
+
const elementName = getPathName$1(t, openingElement);
|
|
281
|
+
if (!isHtmlElement(elementName)) return false;
|
|
282
|
+
if (!ignoredComponents.some((ignoredComponent) => ignoredComponent === componentName || ignoredComponent === elementName) && !hasAttributeWithName$1(openingElement, componentAttributeName)) {
|
|
283
|
+
if (componentAttributeName) openingElement.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(componentAttributeName), t.stringLiteral(componentName)));
|
|
284
|
+
}
|
|
285
|
+
return true;
|
|
413
286
|
}
|
|
414
287
|
function attributeNamesFromState$1(state) {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
return "data-sentry-component";
|
|
288
|
+
if (state.opts.native) return "dataSentryComponent";
|
|
289
|
+
return "data-sentry-component";
|
|
419
290
|
}
|
|
420
291
|
function collectFragmentContext$1(programPath) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
// Handle: const MyFragment = Fragment (only if Fragment is a known alias)
|
|
453
|
-
if (init.type === "Identifier" && fragmentAliases.has(init.name)) {
|
|
454
|
-
fragmentAliases.add(varPath.node.id.name);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Handle: const MyFragment = React.Fragment (only for known React namespaces)
|
|
458
|
-
if (init.type === "MemberExpression" && init.object.type === "Identifier" && init.property.type === "Identifier" && init.property.name === "Fragment" && reactNamespaceAliases.has(init.object.name)) {
|
|
459
|
-
fragmentAliases.add(varPath.node.id.name);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// Handle destructuring assignments: const { Fragment } = React
|
|
464
|
-
if (varPath.node.id.type === "ObjectPattern") {
|
|
465
|
-
if (init.type === "Identifier" && reactNamespaceAliases.has(init.name)) {
|
|
466
|
-
var properties = varPath.node.id.properties;
|
|
467
|
-
var _iterator = _createForOfIteratorHelper(properties),
|
|
468
|
-
_step;
|
|
469
|
-
try {
|
|
470
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
471
|
-
var prop = _step.value;
|
|
472
|
-
if (prop.type === "ObjectProperty" && prop.key && prop.key.type === "Identifier" && prop.value && prop.value.type === "Identifier" && prop.key.name === "Fragment") {
|
|
473
|
-
fragmentAliases.add(prop.value.name);
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
} catch (err) {
|
|
477
|
-
_iterator.e(err);
|
|
478
|
-
} finally {
|
|
479
|
-
_iterator.f();
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
});
|
|
486
|
-
return {
|
|
487
|
-
fragmentAliases: fragmentAliases,
|
|
488
|
-
reactNamespaceAliases: reactNamespaceAliases
|
|
489
|
-
};
|
|
292
|
+
const fragmentAliases = /* @__PURE__ */ new Set();
|
|
293
|
+
const reactNamespaceAliases = new Set(["React"]);
|
|
294
|
+
programPath.traverse({
|
|
295
|
+
ImportDeclaration(importPath) {
|
|
296
|
+
const source = importPath.node.source.value;
|
|
297
|
+
if (source === "react" || source === "React") importPath.node.specifiers.forEach((spec) => {
|
|
298
|
+
if (spec.type === "ImportSpecifier" && spec.imported.type === "Identifier") {
|
|
299
|
+
if (spec.imported.name === "Fragment") fragmentAliases.add(spec.local.name);
|
|
300
|
+
} else if (spec.type === "ImportDefaultSpecifier" || spec.type === "ImportNamespaceSpecifier") reactNamespaceAliases.add(spec.local.name);
|
|
301
|
+
});
|
|
302
|
+
},
|
|
303
|
+
VariableDeclarator(varPath) {
|
|
304
|
+
if (varPath.node.init) {
|
|
305
|
+
const init = varPath.node.init;
|
|
306
|
+
if (varPath.node.id.type === "Identifier") {
|
|
307
|
+
if (init.type === "Identifier" && fragmentAliases.has(init.name)) fragmentAliases.add(varPath.node.id.name);
|
|
308
|
+
if (init.type === "MemberExpression" && init.object.type === "Identifier" && init.property.type === "Identifier" && init.property.name === "Fragment" && reactNamespaceAliases.has(init.object.name)) fragmentAliases.add(varPath.node.id.name);
|
|
309
|
+
}
|
|
310
|
+
if (varPath.node.id.type === "ObjectPattern") {
|
|
311
|
+
if (init.type === "Identifier" && reactNamespaceAliases.has(init.name)) {
|
|
312
|
+
const properties = varPath.node.id.properties;
|
|
313
|
+
for (const prop of properties) if (prop.type === "ObjectProperty" && prop.key && prop.key.type === "Identifier" && prop.value && prop.value.type === "Identifier" && prop.key.name === "Fragment") fragmentAliases.add(prop.value.name);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
return {
|
|
320
|
+
fragmentAliases,
|
|
321
|
+
reactNamespaceAliases
|
|
322
|
+
};
|
|
490
323
|
}
|
|
491
324
|
function isReactFragment$1(t, openingElement, context) {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
return false;
|
|
515
|
-
}
|
|
516
|
-
if ("object" in nodeName && "property" in nodeName) {
|
|
517
|
-
var nodeNameObject = nodeName.object;
|
|
518
|
-
var nodeNameProperty = nodeName.property;
|
|
519
|
-
if (_typeof(nodeNameObject) !== "object" || _typeof(nodeNameProperty) !== "object") {
|
|
520
|
-
return false;
|
|
521
|
-
}
|
|
522
|
-
if (!nodeNameObject || !nodeNameProperty) {
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
var objectName = "name" in nodeNameObject && nodeNameObject.name;
|
|
526
|
-
var propertyName = "name" in nodeNameProperty && nodeNameProperty.name;
|
|
527
|
-
|
|
528
|
-
// React.Fragment check
|
|
529
|
-
if (objectName === "React" && propertyName === "Fragment") {
|
|
530
|
-
return true;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Enhanced checks using context
|
|
534
|
-
if (context) {
|
|
535
|
-
// Check React.Fragment pattern with known React namespaces
|
|
536
|
-
if (context.reactNamespaceAliases.has(objectName) && propertyName === "Fragment") {
|
|
537
|
-
return true;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
// Check MyFragment.Fragment pattern
|
|
541
|
-
if (context.fragmentAliases.has(objectName) && propertyName === "Fragment") {
|
|
542
|
-
return true;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
return false;
|
|
325
|
+
if (openingElement.isJSXFragment()) return true;
|
|
326
|
+
const elementName = getPathName$1(t, openingElement);
|
|
327
|
+
if (elementName === "Fragment" || elementName === "React.Fragment") return true;
|
|
328
|
+
if (context && elementName && context.fragmentAliases.has(elementName)) return true;
|
|
329
|
+
if (openingElement.node && "name" in openingElement.node && openingElement.node.name && typeof openingElement.node.name === "object" && "type" in openingElement.node.name && openingElement.node.name.type === "JSXMemberExpression") {
|
|
330
|
+
const nodeName = openingElement.node.name;
|
|
331
|
+
if (typeof nodeName !== "object" || !nodeName) return false;
|
|
332
|
+
if ("object" in nodeName && "property" in nodeName) {
|
|
333
|
+
const nodeNameObject = nodeName.object;
|
|
334
|
+
const nodeNameProperty = nodeName.property;
|
|
335
|
+
if (typeof nodeNameObject !== "object" || typeof nodeNameProperty !== "object") return false;
|
|
336
|
+
if (!nodeNameObject || !nodeNameProperty) return false;
|
|
337
|
+
const objectName = "name" in nodeNameObject && nodeNameObject.name;
|
|
338
|
+
const propertyName = "name" in nodeNameProperty && nodeNameProperty.name;
|
|
339
|
+
if (objectName === "React" && propertyName === "Fragment") return true;
|
|
340
|
+
if (context) {
|
|
341
|
+
if (context.reactNamespaceAliases.has(objectName) && propertyName === "Fragment") return true;
|
|
342
|
+
if (context.fragmentAliases.has(objectName) && propertyName === "Fragment") return true;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return false;
|
|
548
347
|
}
|
|
549
348
|
function hasAttributeWithName$1(openingElement, name) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
return node.name.name === name;
|
|
556
|
-
}
|
|
557
|
-
return false;
|
|
558
|
-
});
|
|
349
|
+
if (!name) return false;
|
|
350
|
+
return openingElement.node.attributes.some((node) => {
|
|
351
|
+
if (node.type === "JSXAttribute") return node.name.name === name;
|
|
352
|
+
return false;
|
|
353
|
+
});
|
|
559
354
|
}
|
|
560
355
|
function getPathName$1(t, path) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
if (t.isIdentifier(name) || t.isJSXIdentifier(name)) {
|
|
570
|
-
return name.name;
|
|
571
|
-
}
|
|
572
|
-
if (t.isJSXNamespacedName(name)) {
|
|
573
|
-
return name.name.name;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
// Handle JSX member expressions like Tab.Group
|
|
577
|
-
if (t.isJSXMemberExpression(name)) {
|
|
578
|
-
var objectName = getJSXMemberExpressionObjectName$1(t, name.object);
|
|
579
|
-
var propertyName = name.property.name;
|
|
580
|
-
return "".concat(objectName, ".").concat(propertyName);
|
|
581
|
-
}
|
|
582
|
-
return UNKNOWN_ELEMENT_NAME$1;
|
|
356
|
+
if (!path.node) return UNKNOWN_ELEMENT_NAME$1;
|
|
357
|
+
if (!("name" in path.node)) return UNKNOWN_ELEMENT_NAME$1;
|
|
358
|
+
const name = path.node.name;
|
|
359
|
+
if (typeof name === "string") return name;
|
|
360
|
+
if (t.isIdentifier(name) || t.isJSXIdentifier(name)) return name.name;
|
|
361
|
+
if (t.isJSXNamespacedName(name)) return name.name.name;
|
|
362
|
+
if (t.isJSXMemberExpression(name)) return `${getJSXMemberExpressionObjectName$1(t, name.object)}.${name.property.name}`;
|
|
363
|
+
return UNKNOWN_ELEMENT_NAME$1;
|
|
583
364
|
}
|
|
584
|
-
|
|
585
|
-
// Recursively handle nested member expressions (e.g. Components.UI.Header)
|
|
586
365
|
function getJSXMemberExpressionObjectName$1(t, object) {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
366
|
+
if (t.isJSXIdentifier(object)) return object.name;
|
|
367
|
+
if (t.isJSXMemberExpression(object)) return `${getJSXMemberExpressionObjectName$1(t, object.object)}.${object.property.name}`;
|
|
368
|
+
return UNKNOWN_ELEMENT_NAME$1;
|
|
369
|
+
}
|
|
370
|
+
const UNKNOWN_ELEMENT_NAME$1 = "unknown";
|
|
371
|
+
|
|
372
|
+
//#endregion
|
|
373
|
+
//#region src/index.ts
|
|
374
|
+
const webComponentName = "data-sentry-component";
|
|
375
|
+
const webElementName = "data-sentry-element";
|
|
376
|
+
const webSourceFileName = "data-sentry-source-file";
|
|
377
|
+
const nativeComponentName = "dataSentryComponent";
|
|
378
|
+
const nativeElementName = "dataSentryElement";
|
|
379
|
+
const nativeSourceFileName = "dataSentrySourceFile";
|
|
380
|
+
function componentNameAnnotatePlugin({ types: t }) {
|
|
381
|
+
return { visitor: {
|
|
382
|
+
Program: { enter(path, state) {
|
|
383
|
+
state.sentryFragmentContext = collectFragmentContext(path);
|
|
384
|
+
} },
|
|
385
|
+
FunctionDeclaration(path, state) {
|
|
386
|
+
if (!path.node.id || !path.node.id.name) return;
|
|
387
|
+
if (isKnownIncompatiblePluginFromState(state)) return;
|
|
388
|
+
functionBodyPushAttributes(createJSXProcessingContext(state, t, path.node.id.name), path);
|
|
389
|
+
},
|
|
390
|
+
ArrowFunctionExpression(path, state) {
|
|
391
|
+
const parent = path.parent;
|
|
392
|
+
if (!parent || !("id" in parent) || !parent.id || !("name" in parent.id) || !parent.id.name) return;
|
|
393
|
+
if (isKnownIncompatiblePluginFromState(state)) return;
|
|
394
|
+
functionBodyPushAttributes(createJSXProcessingContext(state, t, parent.id.name), path);
|
|
395
|
+
},
|
|
396
|
+
ClassDeclaration(path, state) {
|
|
397
|
+
const name = path.get("id");
|
|
398
|
+
const render = path.get("body").get("body").find((prop) => {
|
|
399
|
+
return prop.isClassMethod() && prop.get("key").isIdentifier({ name: "render" });
|
|
400
|
+
});
|
|
401
|
+
if (!render || !render.traverse || isKnownIncompatiblePluginFromState(state)) return;
|
|
402
|
+
const context = createJSXProcessingContext(state, t, name.node?.name || "");
|
|
403
|
+
render.traverse({ ReturnStatement(returnStatement) {
|
|
404
|
+
const arg = returnStatement.get("argument");
|
|
405
|
+
if (!arg.isJSXElement() && !arg.isJSXFragment()) return;
|
|
406
|
+
processJSX(context, arg);
|
|
407
|
+
} });
|
|
408
|
+
}
|
|
409
|
+
} };
|
|
595
410
|
}
|
|
596
|
-
var UNKNOWN_ELEMENT_NAME$1 = "unknown";
|
|
597
|
-
|
|
598
|
-
var webComponentName = "data-sentry-component";
|
|
599
|
-
var webElementName = "data-sentry-element";
|
|
600
|
-
var webSourceFileName = "data-sentry-source-file";
|
|
601
|
-
var nativeComponentName = "dataSentryComponent";
|
|
602
|
-
var nativeElementName = "dataSentryElement";
|
|
603
|
-
var nativeSourceFileName = "dataSentrySourceFile";
|
|
604
|
-
|
|
605
|
-
// We must export the plugin as default, otherwise the Babel loader will not be able to resolve it when configured using its string identifier
|
|
606
|
-
function componentNameAnnotatePlugin(_ref) {
|
|
607
|
-
var t = _ref.types;
|
|
608
|
-
return {
|
|
609
|
-
visitor: {
|
|
610
|
-
Program: {
|
|
611
|
-
enter: function enter(path, state) {
|
|
612
|
-
var fragmentContext = collectFragmentContext(path);
|
|
613
|
-
state.sentryFragmentContext = fragmentContext;
|
|
614
|
-
}
|
|
615
|
-
},
|
|
616
|
-
FunctionDeclaration: function FunctionDeclaration(path, state) {
|
|
617
|
-
if (!path.node.id || !path.node.id.name) {
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
if (isKnownIncompatiblePluginFromState(state)) {
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
var context = createJSXProcessingContext(state, t, path.node.id.name);
|
|
624
|
-
functionBodyPushAttributes(context, path);
|
|
625
|
-
},
|
|
626
|
-
ArrowFunctionExpression: function ArrowFunctionExpression(path, state) {
|
|
627
|
-
// We're expecting a `VariableDeclarator` like `const MyComponent =`
|
|
628
|
-
var parent = path.parent;
|
|
629
|
-
if (!parent || !("id" in parent) || !parent.id || !("name" in parent.id) || !parent.id.name) {
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
if (isKnownIncompatiblePluginFromState(state)) {
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
var context = createJSXProcessingContext(state, t, parent.id.name);
|
|
636
|
-
functionBodyPushAttributes(context, path);
|
|
637
|
-
},
|
|
638
|
-
ClassDeclaration: function ClassDeclaration(path, state) {
|
|
639
|
-
var _name$node;
|
|
640
|
-
var name = path.get("id");
|
|
641
|
-
var properties = path.get("body").get("body");
|
|
642
|
-
var render = properties.find(function (prop) {
|
|
643
|
-
return prop.isClassMethod() && prop.get("key").isIdentifier({
|
|
644
|
-
name: "render"
|
|
645
|
-
});
|
|
646
|
-
});
|
|
647
|
-
if (!render || !render.traverse || isKnownIncompatiblePluginFromState(state)) {
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
var context = createJSXProcessingContext(state, t, ((_name$node = name.node) === null || _name$node === void 0 ? void 0 : _name$node.name) || "");
|
|
651
|
-
render.traverse({
|
|
652
|
-
ReturnStatement: function ReturnStatement(returnStatement) {
|
|
653
|
-
var arg = returnStatement.get("argument");
|
|
654
|
-
if (!arg.isJSXElement() && !arg.isJSXFragment()) {
|
|
655
|
-
return;
|
|
656
|
-
}
|
|
657
|
-
processJSX(context, arg);
|
|
658
|
-
}
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
|
|
665
411
|
/**
|
|
666
|
-
|
|
667
|
-
|
|
412
|
+
* Creates a JSX processing context from the plugin state
|
|
413
|
+
*/
|
|
668
414
|
function createJSXProcessingContext(state, t, componentName) {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
};
|
|
415
|
+
return {
|
|
416
|
+
annotateFragments: state.opts["annotate-fragments"] === true,
|
|
417
|
+
t,
|
|
418
|
+
componentName,
|
|
419
|
+
sourceFileName: sourceFileNameFromState(state),
|
|
420
|
+
attributeNames: attributeNamesFromState(state),
|
|
421
|
+
ignoredComponents: state.opts.ignoredComponents ?? [],
|
|
422
|
+
fragmentContext: state.sentryFragmentContext
|
|
423
|
+
};
|
|
679
424
|
}
|
|
680
|
-
|
|
681
425
|
/**
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
426
|
+
* Processes the body of a function to add Sentry tracking attributes to JSX elements.
|
|
427
|
+
* Handles various function body structures including direct JSX returns, conditional expressions,
|
|
428
|
+
* and nested JSX elements.
|
|
429
|
+
*/
|
|
686
430
|
function functionBodyPushAttributes(context, path) {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
var consequent = arg.get("consequent");
|
|
716
|
-
if (consequent.isJSXFragment() || consequent.isJSXElement()) {
|
|
717
|
-
processJSX(context, consequent);
|
|
718
|
-
}
|
|
719
|
-
var alternate = arg.get("alternate");
|
|
720
|
-
if (alternate.isJSXFragment() || alternate.isJSXElement()) {
|
|
721
|
-
processJSX(context, alternate);
|
|
722
|
-
}
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
if (!arg.isJSXFragment() && !arg.isJSXElement()) {
|
|
726
|
-
return;
|
|
727
|
-
}
|
|
728
|
-
jsxNode = arg;
|
|
729
|
-
}
|
|
730
|
-
if (!jsxNode) {
|
|
731
|
-
return;
|
|
732
|
-
}
|
|
733
|
-
processJSX(context, jsxNode);
|
|
431
|
+
let jsxNode;
|
|
432
|
+
const functionBody = path.get("body").get("body");
|
|
433
|
+
if (!("length" in functionBody) && functionBody.parent && (functionBody.parent.type === "JSXElement" || functionBody.parent.type === "JSXFragment")) {
|
|
434
|
+
const maybeJsxNode = functionBody.find((c) => {
|
|
435
|
+
return c.type === "JSXElement" || c.type === "JSXFragment";
|
|
436
|
+
});
|
|
437
|
+
if (!maybeJsxNode) return;
|
|
438
|
+
jsxNode = maybeJsxNode;
|
|
439
|
+
} else {
|
|
440
|
+
const returnStatement = functionBody.find((c) => {
|
|
441
|
+
return c.type === "ReturnStatement";
|
|
442
|
+
});
|
|
443
|
+
if (!returnStatement) return;
|
|
444
|
+
const arg = returnStatement.get("argument");
|
|
445
|
+
if (!arg) return;
|
|
446
|
+
if (Array.isArray(arg)) return;
|
|
447
|
+
if (arg.isConditionalExpression()) {
|
|
448
|
+
const consequent = arg.get("consequent");
|
|
449
|
+
if (consequent.isJSXFragment() || consequent.isJSXElement()) processJSX(context, consequent);
|
|
450
|
+
const alternate = arg.get("alternate");
|
|
451
|
+
if (alternate.isJSXFragment() || alternate.isJSXElement()) processJSX(context, alternate);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (!arg.isJSXFragment() && !arg.isJSXElement()) return;
|
|
455
|
+
jsxNode = arg;
|
|
456
|
+
}
|
|
457
|
+
if (!jsxNode) return;
|
|
458
|
+
processJSX(context, jsxNode);
|
|
734
459
|
}
|
|
735
|
-
|
|
736
460
|
/**
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
461
|
+
* Recursively processes JSX elements to add Sentry tracking attributes.
|
|
462
|
+
* Handles both JSX elements and fragments, applying appropriate attributes
|
|
463
|
+
* based on configuration and component context.
|
|
464
|
+
*/
|
|
741
465
|
function processJSX(context, jsxNode, componentName) {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
children = [children];
|
|
761
|
-
}
|
|
762
|
-
var shouldSetComponentName = context.annotateFragments;
|
|
763
|
-
children.forEach(function (child) {
|
|
764
|
-
// Happens for some node types like plain text
|
|
765
|
-
if (!child.node) {
|
|
766
|
-
return;
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// Children don't receive the data-component attribute so we pass null for componentName unless it's the first child of a Fragment with a node and `annotateFragments` is true
|
|
770
|
-
var openingElement = child.get("openingElement");
|
|
771
|
-
// TODO: Improve this. We never expect to have multiple opening elements
|
|
772
|
-
// but if it's possible, this should work
|
|
773
|
-
if (Array.isArray(openingElement)) {
|
|
774
|
-
return;
|
|
775
|
-
}
|
|
776
|
-
if (shouldSetComponentName && openingElement && openingElement.node) {
|
|
777
|
-
shouldSetComponentName = false;
|
|
778
|
-
processJSX(context, child, currentComponentName);
|
|
779
|
-
} else {
|
|
780
|
-
processJSX(context, child, "");
|
|
781
|
-
}
|
|
782
|
-
});
|
|
466
|
+
if (!jsxNode) return;
|
|
467
|
+
const currentComponentName = componentName ?? context.componentName;
|
|
468
|
+
const paths = jsxNode.get("openingElement");
|
|
469
|
+
(Array.isArray(paths) ? paths : [paths]).forEach((openingElement) => {
|
|
470
|
+
applyAttributes(context, openingElement, currentComponentName);
|
|
471
|
+
});
|
|
472
|
+
let children = jsxNode.get("children");
|
|
473
|
+
if (children && !("length" in children)) children = [children];
|
|
474
|
+
let shouldSetComponentName = context.annotateFragments;
|
|
475
|
+
children.forEach((child) => {
|
|
476
|
+
if (!child.node) return;
|
|
477
|
+
const openingElement = child.get("openingElement");
|
|
478
|
+
if (Array.isArray(openingElement)) return;
|
|
479
|
+
if (shouldSetComponentName && openingElement && openingElement.node) {
|
|
480
|
+
shouldSetComponentName = false;
|
|
481
|
+
processJSX(context, child, currentComponentName);
|
|
482
|
+
} else processJSX(context, child, "");
|
|
483
|
+
});
|
|
783
484
|
}
|
|
784
|
-
|
|
785
485
|
/**
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
486
|
+
* Applies Sentry tracking attributes to a JSX opening element.
|
|
487
|
+
* Adds component name, element name, and source file attributes while
|
|
488
|
+
* respecting ignore lists and fragment detection.
|
|
489
|
+
*/
|
|
790
490
|
function applyAttributes(context, openingElement, componentName) {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
811
|
-
if (!openingElement.node.attributes) openingElement.node.attributes = [];
|
|
812
|
-
var elementName = getPathName(t, openingElement);
|
|
813
|
-
var isAnIgnoredComponent = ignoredComponents.some(function (ignoredComponent) {
|
|
814
|
-
return ignoredComponent === componentName || ignoredComponent === elementName;
|
|
815
|
-
});
|
|
816
|
-
|
|
817
|
-
// Add a stable attribute for the element name but only for non-DOM names
|
|
818
|
-
var isAnIgnoredElement = false;
|
|
819
|
-
if (!isAnIgnoredComponent && !hasAttributeWithName(openingElement, elementAttributeName)) {
|
|
820
|
-
if (DEFAULT_IGNORED_ELEMENTS.includes(elementName)) {
|
|
821
|
-
isAnIgnoredElement = true;
|
|
822
|
-
} else {
|
|
823
|
-
// Always add element attribute for non-ignored elements
|
|
824
|
-
if (elementAttributeName) {
|
|
825
|
-
openingElement.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(elementAttributeName), t.stringLiteral(elementName)));
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
// Add a stable attribute for the component name (absent for non-root elements)
|
|
831
|
-
if (componentName && !isAnIgnoredComponent && !hasAttributeWithName(openingElement, componentAttributeName)) {
|
|
832
|
-
if (componentAttributeName) {
|
|
833
|
-
openingElement.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(componentAttributeName), t.stringLiteral(componentName)));
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
// Add a stable attribute for the source file name
|
|
838
|
-
// Updated condition: add source file for elements that have either:
|
|
839
|
-
// 1. A component name (root elements), OR
|
|
840
|
-
// 2. An element name that's not ignored (child elements)
|
|
841
|
-
if (sourceFileName && !isAnIgnoredComponent && (componentName || !isAnIgnoredElement) && !hasAttributeWithName(openingElement, sourceFileAttributeName)) {
|
|
842
|
-
if (sourceFileAttributeName) {
|
|
843
|
-
openingElement.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(sourceFileAttributeName), t.stringLiteral(sourceFileName)));
|
|
844
|
-
}
|
|
845
|
-
}
|
|
491
|
+
const { t, attributeNames, ignoredComponents, fragmentContext, sourceFileName } = context;
|
|
492
|
+
const [componentAttributeName, elementAttributeName, sourceFileAttributeName] = attributeNames;
|
|
493
|
+
if (!openingElement.node) return;
|
|
494
|
+
if (isReactFragment(t, openingElement, fragmentContext)) return;
|
|
495
|
+
if (!openingElement.node.attributes) openingElement.node.attributes = [];
|
|
496
|
+
const elementName = getPathName(t, openingElement);
|
|
497
|
+
const isAnIgnoredComponent = ignoredComponents.some((ignoredComponent) => ignoredComponent === componentName || ignoredComponent === elementName);
|
|
498
|
+
let isAnIgnoredElement = false;
|
|
499
|
+
if (!isAnIgnoredComponent && !hasAttributeWithName(openingElement, elementAttributeName)) {
|
|
500
|
+
if (DEFAULT_IGNORED_ELEMENTS.includes(elementName)) isAnIgnoredElement = true;
|
|
501
|
+
else if (elementAttributeName) openingElement.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(elementAttributeName), t.stringLiteral(elementName)));
|
|
502
|
+
}
|
|
503
|
+
if (componentName && !isAnIgnoredComponent && !hasAttributeWithName(openingElement, componentAttributeName)) {
|
|
504
|
+
if (componentAttributeName) openingElement.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(componentAttributeName), t.stringLiteral(componentName)));
|
|
505
|
+
}
|
|
506
|
+
if (sourceFileName && !isAnIgnoredComponent && (componentName || !isAnIgnoredElement) && !hasAttributeWithName(openingElement, sourceFileAttributeName)) {
|
|
507
|
+
if (sourceFileAttributeName) openingElement.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(sourceFileAttributeName), t.stringLiteral(sourceFileName)));
|
|
508
|
+
}
|
|
846
509
|
}
|
|
847
510
|
function sourceFileNameFromState(state) {
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
return name.split("/").pop();
|
|
854
|
-
} else if (name.indexOf("\\") !== -1) {
|
|
855
|
-
return name.split("\\").pop();
|
|
856
|
-
} else {
|
|
857
|
-
return name;
|
|
858
|
-
}
|
|
511
|
+
const name = fullSourceFileNameFromState(state);
|
|
512
|
+
if (!name) return;
|
|
513
|
+
if (name.indexOf("/") !== -1) return name.split("/").pop();
|
|
514
|
+
else if (name.indexOf("\\") !== -1) return name.split("\\").pop();
|
|
515
|
+
else return name;
|
|
859
516
|
}
|
|
860
517
|
function fullSourceFileNameFromState(state) {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
if (typeof name === "string") {
|
|
865
|
-
return name;
|
|
866
|
-
}
|
|
867
|
-
return null;
|
|
518
|
+
const name = state.file.opts.parserOpts?.sourceFileName;
|
|
519
|
+
if (typeof name === "string") return name;
|
|
520
|
+
return null;
|
|
868
521
|
}
|
|
869
522
|
function isKnownIncompatiblePluginFromState(state) {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
return true;
|
|
877
|
-
}
|
|
878
|
-
return false;
|
|
879
|
-
});
|
|
523
|
+
const fullSourceFileName = fullSourceFileNameFromState(state);
|
|
524
|
+
if (!fullSourceFileName) return false;
|
|
525
|
+
return KNOWN_INCOMPATIBLE_PLUGINS.some((pluginName) => {
|
|
526
|
+
if (fullSourceFileName.includes(`/node_modules/${pluginName}/`) || fullSourceFileName.includes(`\\node_modules\\${pluginName}\\`)) return true;
|
|
527
|
+
return false;
|
|
528
|
+
});
|
|
880
529
|
}
|
|
881
530
|
function attributeNamesFromState(state) {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
531
|
+
if (state.opts.native) return [
|
|
532
|
+
nativeComponentName,
|
|
533
|
+
nativeElementName,
|
|
534
|
+
nativeSourceFileName
|
|
535
|
+
];
|
|
536
|
+
return [
|
|
537
|
+
webComponentName,
|
|
538
|
+
webElementName,
|
|
539
|
+
webSourceFileName
|
|
540
|
+
];
|
|
886
541
|
}
|
|
887
542
|
function collectFragmentContext(programPath) {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
// Handle: const MyFragment = Fragment (only if Fragment is a known alias)
|
|
920
|
-
if (init.type === "Identifier" && fragmentAliases.has(init.name)) {
|
|
921
|
-
fragmentAliases.add(varPath.node.id.name);
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
// Handle: const MyFragment = React.Fragment (only for known React namespaces)
|
|
925
|
-
if (init.type === "MemberExpression" && init.object.type === "Identifier" && init.property.type === "Identifier" && init.property.name === "Fragment" && reactNamespaceAliases.has(init.object.name)) {
|
|
926
|
-
fragmentAliases.add(varPath.node.id.name);
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
// Handle destructuring assignments: const { Fragment } = React
|
|
931
|
-
if (varPath.node.id.type === "ObjectPattern") {
|
|
932
|
-
if (init.type === "Identifier" && reactNamespaceAliases.has(init.name)) {
|
|
933
|
-
var properties = varPath.node.id.properties;
|
|
934
|
-
var _iterator = _createForOfIteratorHelper(properties),
|
|
935
|
-
_step;
|
|
936
|
-
try {
|
|
937
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
938
|
-
var prop = _step.value;
|
|
939
|
-
if (prop.type === "ObjectProperty" && prop.key && prop.key.type === "Identifier" && prop.value && prop.value.type === "Identifier" && prop.key.name === "Fragment") {
|
|
940
|
-
fragmentAliases.add(prop.value.name);
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
} catch (err) {
|
|
944
|
-
_iterator.e(err);
|
|
945
|
-
} finally {
|
|
946
|
-
_iterator.f();
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
});
|
|
953
|
-
return {
|
|
954
|
-
fragmentAliases: fragmentAliases,
|
|
955
|
-
reactNamespaceAliases: reactNamespaceAliases
|
|
956
|
-
};
|
|
543
|
+
const fragmentAliases = /* @__PURE__ */ new Set();
|
|
544
|
+
const reactNamespaceAliases = new Set(["React"]);
|
|
545
|
+
programPath.traverse({
|
|
546
|
+
ImportDeclaration(importPath) {
|
|
547
|
+
const source = importPath.node.source.value;
|
|
548
|
+
if (source === "react" || source === "React") importPath.node.specifiers.forEach((spec) => {
|
|
549
|
+
if (spec.type === "ImportSpecifier" && spec.imported.type === "Identifier") {
|
|
550
|
+
if (spec.imported.name === "Fragment") fragmentAliases.add(spec.local.name);
|
|
551
|
+
} else if (spec.type === "ImportDefaultSpecifier" || spec.type === "ImportNamespaceSpecifier") reactNamespaceAliases.add(spec.local.name);
|
|
552
|
+
});
|
|
553
|
+
},
|
|
554
|
+
VariableDeclarator(varPath) {
|
|
555
|
+
if (varPath.node.init) {
|
|
556
|
+
const init = varPath.node.init;
|
|
557
|
+
if (varPath.node.id.type === "Identifier") {
|
|
558
|
+
if (init.type === "Identifier" && fragmentAliases.has(init.name)) fragmentAliases.add(varPath.node.id.name);
|
|
559
|
+
if (init.type === "MemberExpression" && init.object.type === "Identifier" && init.property.type === "Identifier" && init.property.name === "Fragment" && reactNamespaceAliases.has(init.object.name)) fragmentAliases.add(varPath.node.id.name);
|
|
560
|
+
}
|
|
561
|
+
if (varPath.node.id.type === "ObjectPattern") {
|
|
562
|
+
if (init.type === "Identifier" && reactNamespaceAliases.has(init.name)) {
|
|
563
|
+
const properties = varPath.node.id.properties;
|
|
564
|
+
for (const prop of properties) if (prop.type === "ObjectProperty" && prop.key && prop.key.type === "Identifier" && prop.value && prop.value.type === "Identifier" && prop.key.name === "Fragment") fragmentAliases.add(prop.value.name);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
return {
|
|
571
|
+
fragmentAliases,
|
|
572
|
+
reactNamespaceAliases
|
|
573
|
+
};
|
|
957
574
|
}
|
|
958
575
|
function isReactFragment(t, openingElement, context) {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
return false;
|
|
982
|
-
}
|
|
983
|
-
if ("object" in nodeName && "property" in nodeName) {
|
|
984
|
-
var nodeNameObject = nodeName.object;
|
|
985
|
-
var nodeNameProperty = nodeName.property;
|
|
986
|
-
if (_typeof(nodeNameObject) !== "object" || _typeof(nodeNameProperty) !== "object") {
|
|
987
|
-
return false;
|
|
988
|
-
}
|
|
989
|
-
if (!nodeNameObject || !nodeNameProperty) {
|
|
990
|
-
return false;
|
|
991
|
-
}
|
|
992
|
-
var objectName = "name" in nodeNameObject && nodeNameObject.name;
|
|
993
|
-
var propertyName = "name" in nodeNameProperty && nodeNameProperty.name;
|
|
994
|
-
|
|
995
|
-
// React.Fragment check
|
|
996
|
-
if (objectName === "React" && propertyName === "Fragment") {
|
|
997
|
-
return true;
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
// Enhanced checks using context
|
|
1001
|
-
if (context) {
|
|
1002
|
-
// Check React.Fragment pattern with known React namespaces
|
|
1003
|
-
if (context.reactNamespaceAliases.has(objectName) && propertyName === "Fragment") {
|
|
1004
|
-
return true;
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
// Check MyFragment.Fragment pattern
|
|
1008
|
-
if (context.fragmentAliases.has(objectName) && propertyName === "Fragment") {
|
|
1009
|
-
return true;
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
return false;
|
|
576
|
+
if (openingElement.isJSXFragment()) return true;
|
|
577
|
+
const elementName = getPathName(t, openingElement);
|
|
578
|
+
if (elementName === "Fragment" || elementName === "React.Fragment") return true;
|
|
579
|
+
if (context && elementName && context.fragmentAliases.has(elementName)) return true;
|
|
580
|
+
if (openingElement.node && "name" in openingElement.node && openingElement.node.name && typeof openingElement.node.name === "object" && "type" in openingElement.node.name && openingElement.node.name.type === "JSXMemberExpression") {
|
|
581
|
+
const nodeName = openingElement.node.name;
|
|
582
|
+
if (typeof nodeName !== "object" || !nodeName) return false;
|
|
583
|
+
if ("object" in nodeName && "property" in nodeName) {
|
|
584
|
+
const nodeNameObject = nodeName.object;
|
|
585
|
+
const nodeNameProperty = nodeName.property;
|
|
586
|
+
if (typeof nodeNameObject !== "object" || typeof nodeNameProperty !== "object") return false;
|
|
587
|
+
if (!nodeNameObject || !nodeNameProperty) return false;
|
|
588
|
+
const objectName = "name" in nodeNameObject && nodeNameObject.name;
|
|
589
|
+
const propertyName = "name" in nodeNameProperty && nodeNameProperty.name;
|
|
590
|
+
if (objectName === "React" && propertyName === "Fragment") return true;
|
|
591
|
+
if (context) {
|
|
592
|
+
if (context.reactNamespaceAliases.has(objectName) && propertyName === "Fragment") return true;
|
|
593
|
+
if (context.fragmentAliases.has(objectName) && propertyName === "Fragment") return true;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return false;
|
|
1015
598
|
}
|
|
1016
599
|
function hasAttributeWithName(openingElement, name) {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
return node.name.name === name;
|
|
1023
|
-
}
|
|
1024
|
-
return false;
|
|
1025
|
-
});
|
|
600
|
+
if (!name) return false;
|
|
601
|
+
return openingElement.node.attributes.some((node) => {
|
|
602
|
+
if (node.type === "JSXAttribute") return node.name.name === name;
|
|
603
|
+
return false;
|
|
604
|
+
});
|
|
1026
605
|
}
|
|
1027
606
|
function getPathName(t, path) {
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
if (t.isIdentifier(name) || t.isJSXIdentifier(name)) {
|
|
1037
|
-
return name.name;
|
|
1038
|
-
}
|
|
1039
|
-
if (t.isJSXNamespacedName(name)) {
|
|
1040
|
-
return name.name.name;
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
// Handle JSX member expressions like Tab.Group
|
|
1044
|
-
if (t.isJSXMemberExpression(name)) {
|
|
1045
|
-
var objectName = getJSXMemberExpressionObjectName(t, name.object);
|
|
1046
|
-
var propertyName = name.property.name;
|
|
1047
|
-
return "".concat(objectName, ".").concat(propertyName);
|
|
1048
|
-
}
|
|
1049
|
-
return UNKNOWN_ELEMENT_NAME;
|
|
607
|
+
if (!path.node) return UNKNOWN_ELEMENT_NAME;
|
|
608
|
+
if (!("name" in path.node)) return UNKNOWN_ELEMENT_NAME;
|
|
609
|
+
const name = path.node.name;
|
|
610
|
+
if (typeof name === "string") return name;
|
|
611
|
+
if (t.isIdentifier(name) || t.isJSXIdentifier(name)) return name.name;
|
|
612
|
+
if (t.isJSXNamespacedName(name)) return name.name.name;
|
|
613
|
+
if (t.isJSXMemberExpression(name)) return `${getJSXMemberExpressionObjectName(t, name.object)}.${name.property.name}`;
|
|
614
|
+
return UNKNOWN_ELEMENT_NAME;
|
|
1050
615
|
}
|
|
1051
|
-
|
|
1052
|
-
// Recursively handle nested member expressions (e.g. Components.UI.Header)
|
|
1053
616
|
function getJSXMemberExpressionObjectName(t, object) {
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
if (t.isJSXMemberExpression(object)) {
|
|
1058
|
-
var objectName = getJSXMemberExpressionObjectName(t, object.object);
|
|
1059
|
-
return "".concat(objectName, ".").concat(object.property.name);
|
|
1060
|
-
}
|
|
1061
|
-
return UNKNOWN_ELEMENT_NAME;
|
|
617
|
+
if (t.isJSXIdentifier(object)) return object.name;
|
|
618
|
+
if (t.isJSXMemberExpression(object)) return `${getJSXMemberExpressionObjectName(t, object.object)}.${object.property.name}`;
|
|
619
|
+
return UNKNOWN_ELEMENT_NAME;
|
|
1062
620
|
}
|
|
1063
|
-
|
|
621
|
+
const UNKNOWN_ELEMENT_NAME = "unknown";
|
|
1064
622
|
|
|
623
|
+
//#endregion
|
|
1065
624
|
export { componentNameAnnotatePlugin as default, experimentalComponentNameAnnotatePlugin };
|
|
1066
|
-
//# sourceMappingURL=index.mjs.map
|
|
625
|
+
//# sourceMappingURL=index.mjs.map
|