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