@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.
@@ -1,1066 +1,625 @@
1
- function _iterableToArrayLimit(arr, i) {
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
- * MIT License
113
- *
114
- * Copyright (c) 2020 Engineering at FullStory
115
- *
116
- * Permission is hereby granted, free of charge, to any person obtaining a copy
117
- * of this software and associated documentation files (the "Software"), to deal
118
- * in the Software without restriction, including without limitation the rights
119
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
120
- * copies of the Software, and to permit persons to whom the Software is
121
- * furnished to do so, subject to the following conditions:
122
- *
123
- * The above copyright notice and this permission notice shall be included in all
124
- * copies or substantial portions of the Software.
125
- *
126
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
127
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
128
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
129
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
130
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
131
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
132
- * SOFTWARE.
133
- *
134
- */
135
-
136
- var KNOWN_INCOMPATIBLE_PLUGINS = [
137
- // This module might be causing an issue preventing clicks. For safety, we won't run on this module.
138
- "react-native-testfairy",
139
- // This module checks for unexpected property keys and throws an exception.
140
- "@react-navigation"];
141
- 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"];
142
-
143
- /**
144
- * MIT License
145
- *
146
- * Copyright (c) 2020 Engineering at FullStory
147
- *
148
- * Permission is hereby granted, free of charge, to any person obtaining a copy
149
- * of this software and associated documentation files (the "Software"), to deal
150
- * in the Software without restriction, including without limitation the rights
151
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
152
- * copies of the Software, and to permit persons to whom the Software is
153
- * furnished to do so, subject to the following conditions:
154
- *
155
- * The above copyright notice and this permission notice shall be included in all
156
- * copies or substantial portions of the Software.
157
- *
158
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
159
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
160
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
161
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
162
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
163
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
164
- * SOFTWARE.
165
- *
166
- */
167
-
168
- /**
169
- * The following code is based on the FullStory Babel plugin, but has been modified to work
170
- * with Sentry products:
171
- *
172
- * - Added `sentry` to data properties, i.e `data-sentry-component`
173
- * - Converted to TypeScript
174
- * - Code cleanups
175
- * - Highly modified to inject the data attributes into the root HTML elements of a component.
176
- */
177
-
178
- var REACT_NATIVE_ELEMENTS = ["Image", "Text", "View", "ScrollView", "TextInput", "TouchableOpacity", "TouchableHighlight", "TouchableWithoutFeedback", "FlatList", "SectionList", "ActivityIndicator", "Button", "Switch", "Modal", "SafeAreaView", "StatusBar", "KeyboardAvoidingView", "RefreshControl", "Picker", "Slider"];
179
-
180
- // Shared context object for all JSX processing functions
181
-
182
- // We must export the plugin as default, otherwise the Babel loader will not be able to resolve it when configured using its string identifier
183
- function experimentalComponentNameAnnotatePlugin(_ref) {
184
- var t = _ref.types;
185
- return {
186
- visitor: {
187
- Program: {
188
- enter: function enter(path, state) {
189
- var fragmentContext = collectFragmentContext$1(path);
190
- state.sentryFragmentContext = fragmentContext;
191
- }
192
- },
193
- FunctionDeclaration: function FunctionDeclaration(path, state) {
194
- if (!path.node.id || !path.node.id.name) {
195
- return;
196
- }
197
- var context = createJSXProcessingContext$1(state, t, path.node.id.name);
198
- functionBodyPushAttributes$1(context, path);
199
- },
200
- ArrowFunctionExpression: function ArrowFunctionExpression(path, state) {
201
- // We're expecting a `VariableDeclarator` like `const MyComponent =`
202
- var parent = path.parent;
203
- if (!parent || !("id" in parent) || !parent.id || !("name" in parent.id) || !parent.id.name) {
204
- return;
205
- }
206
- var context = createJSXProcessingContext$1(state, t, parent.id.name);
207
- functionBodyPushAttributes$1(context, path);
208
- },
209
- ClassDeclaration: function ClassDeclaration(path, state) {
210
- var _name$node;
211
- var name = path.get("id");
212
- var properties = path.get("body").get("body");
213
- var render = properties.find(function (prop) {
214
- return prop.isClassMethod() && prop.get("key").isIdentifier({
215
- name: "render"
216
- });
217
- });
218
- if (!render || !render.traverse) {
219
- return;
220
- }
221
- var context = createJSXProcessingContext$1(state, t, ((_name$node = name.node) === null || _name$node === void 0 ? void 0 : _name$node.name) || "");
222
- render.traverse({
223
- ReturnStatement: function ReturnStatement(returnStatement) {
224
- var arg = returnStatement.get("argument");
225
- if (!arg.isJSXElement() && !arg.isJSXFragment()) {
226
- return;
227
- }
228
- processJSX$1(context, arg);
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
- * Checks if an element name represents an HTML element (as opposed to a React component).
238
- * HTML elements include standard lowercase HTML tags and React Native elements.
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
- // Unknown elements are not HTML elements
242
- if (elementName === UNKNOWN_ELEMENT_NAME$1) {
243
- return false;
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
- * Creates a JSX processing context from the plugin state
263
- */
206
+ * Creates a JSX processing context from the plugin state
207
+ */
264
208
  function createJSXProcessingContext$1(state, t, componentName) {
265
- var _state$opts$ignoredCo;
266
- return {
267
- t: t,
268
- componentName: componentName,
269
- attributeName: attributeNamesFromState$1(state),
270
- ignoredComponents: (_state$opts$ignoredCo = state.opts.ignoredComponents) !== null && _state$opts$ignoredCo !== void 0 ? _state$opts$ignoredCo : [],
271
- fragmentContext: state.sentryFragmentContext
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
- * Processes the body of a function to add Sentry tracking attributes to JSX elements.
277
- * Handles various function body structures including direct JSX returns, conditional expressions,
278
- * and nested JSX elements.
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
- var jsxNode;
282
- var functionBody = path.get("body").get("body");
283
- if (!("length" in functionBody) && functionBody.parent && (functionBody.parent.type === "JSXElement" || functionBody.parent.type === "JSXFragment")) {
284
- var maybeJsxNode = functionBody.find(function (c) {
285
- return c.type === "JSXElement" || c.type === "JSXFragment";
286
- });
287
- if (!maybeJsxNode) {
288
- return;
289
- }
290
- jsxNode = maybeJsxNode;
291
- } else {
292
- var returnStatement = functionBody.find(function (c) {
293
- return c.type === "ReturnStatement";
294
- });
295
- if (!returnStatement) {
296
- return;
297
- }
298
- var arg = returnStatement.get("argument");
299
- if (!arg) {
300
- return;
301
- }
302
- if (Array.isArray(arg)) {
303
- return;
304
- }
305
-
306
- // Handle the case of a function body returning a ternary operation.
307
- // `return (maybeTrue ? '' : (<SubComponent />))`
308
- if (arg.isConditionalExpression()) {
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
- * Recursively processes JSX elements to add Sentry tracking attributes.
332
- * Handles both JSX elements and fragments, applying appropriate attributes
333
- * based on configuration and component context.
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
- if (!jsxNode) {
337
- return;
338
- }
339
-
340
- // NOTE: I don't know of a case where `openingElement` would have more than one item,
341
- // but it's safer to always iterate
342
- var paths = jsxNode.get("openingElement");
343
- var openingElements = Array.isArray(paths) ? paths : [paths];
344
- var hasInjectedAttributes = openingElements.reduce(function (prev, openingElement) {
345
- return prev || applyAttributes$1(context, openingElement, context.componentName);
346
- }, false);
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
- * Applies Sentry tracking attributes to a JSX opening element.
376
- * Adds component name, element name, and source file attributes while
377
- * respecting ignore lists and fragment detection.
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
- var t = context.t,
381
- componentAttributeName = context.attributeName,
382
- ignoredComponents = context.ignoredComponents,
383
- fragmentContext = context.fragmentContext;
384
-
385
- // e.g., Raw JSX text like the `A` in `<h1>a</h1>`
386
- if (!openingElement.node) {
387
- return false;
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
- if (state.opts["native"]) {
416
- return "dataSentryComponent";
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
- var fragmentAliases = new Set();
422
- var reactNamespaceAliases = new Set(["React"]); // Default React namespace
423
-
424
- programPath.traverse({
425
- ImportDeclaration: function ImportDeclaration(importPath) {
426
- var source = importPath.node.source.value;
427
-
428
- // Handle React imports
429
- if (source === "react" || source === "React") {
430
- importPath.node.specifiers.forEach(function (spec) {
431
- if (spec.type === "ImportSpecifier" && spec.imported.type === "Identifier") {
432
- // Detect aliased React.Fragment imports (e.g., `Fragment as F`)
433
- // so we can later identify <F> as a fragment in JSX.
434
- if (spec.imported.name === "Fragment") {
435
- fragmentAliases.add(spec.local.name);
436
- }
437
- } else if (spec.type === "ImportDefaultSpecifier" || spec.type === "ImportNamespaceSpecifier") {
438
- // import React from 'react' -> React OR
439
- // import * as React from 'react' -> React
440
- reactNamespaceAliases.add(spec.local.name);
441
- }
442
- });
443
- }
444
- },
445
- // Handle simple variable assignments only (avoid complex cases)
446
- VariableDeclarator: function VariableDeclarator(varPath) {
447
- if (varPath.node.init) {
448
- var init = varPath.node.init;
449
-
450
- // Handle identifier assignments: const MyFragment = Fragment
451
- if (varPath.node.id.type === "Identifier") {
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
- // Handle JSX fragments (<>)
493
- if (openingElement.isJSXFragment()) {
494
- return true;
495
- }
496
- var elementName = getPathName$1(t, openingElement);
497
-
498
- // Direct fragment references
499
- if (elementName === "Fragment" || elementName === "React.Fragment") {
500
- return true;
501
- }
502
-
503
- // TODO: All these objects are typed as unknown, maybe an oversight in Babel types?
504
-
505
- // Check if the element name is a known fragment alias
506
- if (context && elementName && context.fragmentAliases.has(elementName)) {
507
- return true;
508
- }
509
-
510
- // Handle JSXMemberExpression
511
- 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") {
512
- var nodeName = openingElement.node.name;
513
- if (_typeof(nodeName) !== "object" || !nodeName) {
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
- if (!name) {
551
- return false;
552
- }
553
- return openingElement.node.attributes.some(function (node) {
554
- if (node.type === "JSXAttribute") {
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
- if (!path.node) return UNKNOWN_ELEMENT_NAME$1;
562
- if (!("name" in path.node)) {
563
- return UNKNOWN_ELEMENT_NAME$1;
564
- }
565
- var name = path.node.name;
566
- if (typeof name === "string") {
567
- return name;
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
- if (t.isJSXIdentifier(object)) {
588
- return object.name;
589
- }
590
- if (t.isJSXMemberExpression(object)) {
591
- var objectName = getJSXMemberExpressionObjectName$1(t, object.object);
592
- return "".concat(objectName, ".").concat(object.property.name);
593
- }
594
- return UNKNOWN_ELEMENT_NAME$1;
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
- * Creates a JSX processing context from the plugin state
667
- */
412
+ * Creates a JSX processing context from the plugin state
413
+ */
668
414
  function createJSXProcessingContext(state, t, componentName) {
669
- var _state$opts$ignoredCo;
670
- return {
671
- annotateFragments: state.opts["annotate-fragments"] === true,
672
- t: t,
673
- componentName: componentName,
674
- sourceFileName: sourceFileNameFromState(state),
675
- attributeNames: attributeNamesFromState(state),
676
- ignoredComponents: (_state$opts$ignoredCo = state.opts.ignoredComponents) !== null && _state$opts$ignoredCo !== void 0 ? _state$opts$ignoredCo : [],
677
- fragmentContext: state.sentryFragmentContext
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
- * Processes the body of a function to add Sentry tracking attributes to JSX elements.
683
- * Handles various function body structures including direct JSX returns, conditional expressions,
684
- * and nested JSX elements.
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
- var jsxNode;
688
- var functionBody = path.get("body").get("body");
689
- if (!("length" in functionBody) && functionBody.parent && (functionBody.parent.type === "JSXElement" || functionBody.parent.type === "JSXFragment")) {
690
- var maybeJsxNode = functionBody.find(function (c) {
691
- return c.type === "JSXElement" || c.type === "JSXFragment";
692
- });
693
- if (!maybeJsxNode) {
694
- return;
695
- }
696
- jsxNode = maybeJsxNode;
697
- } else {
698
- var returnStatement = functionBody.find(function (c) {
699
- return c.type === "ReturnStatement";
700
- });
701
- if (!returnStatement) {
702
- return;
703
- }
704
- var arg = returnStatement.get("argument");
705
- if (!arg) {
706
- return;
707
- }
708
- if (Array.isArray(arg)) {
709
- return;
710
- }
711
-
712
- // Handle the case of a function body returning a ternary operation.
713
- // `return (maybeTrue ? '' : (<SubComponent />))`
714
- if (arg.isConditionalExpression()) {
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
- * Recursively processes JSX elements to add Sentry tracking attributes.
738
- * Handles both JSX elements and fragments, applying appropriate attributes
739
- * based on configuration and component context.
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
- if (!jsxNode) {
743
- return;
744
- }
745
-
746
- // Use provided componentName or fall back to context componentName
747
- var currentComponentName = componentName !== null && componentName !== void 0 ? componentName : context.componentName;
748
-
749
- // NOTE: I don't know of a case where `openingElement` would have more than one item,
750
- // but it's safer to always iterate
751
- var paths = jsxNode.get("openingElement");
752
- var openingElements = Array.isArray(paths) ? paths : [paths];
753
- openingElements.forEach(function (openingElement) {
754
- applyAttributes(context, openingElement, currentComponentName);
755
- });
756
- var children = jsxNode.get("children");
757
- // TODO: See why `Array.isArray` doesn't have correct behaviour here
758
- if (children && !("length" in children)) {
759
- // A single child was found, maybe a bit of static text
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
- * Applies Sentry tracking attributes to a JSX opening element.
787
- * Adds component name, element name, and source file attributes while
788
- * respecting ignore lists and fragment detection.
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
- var t = context.t,
792
- attributeNames = context.attributeNames,
793
- ignoredComponents = context.ignoredComponents,
794
- fragmentContext = context.fragmentContext,
795
- sourceFileName = context.sourceFileName;
796
- var _attributeNames = _slicedToArray(attributeNames, 3),
797
- componentAttributeName = _attributeNames[0],
798
- elementAttributeName = _attributeNames[1],
799
- sourceFileAttributeName = _attributeNames[2];
800
-
801
- // e.g., Raw JSX text like the `A` in `<h1>a</h1>`
802
- if (!openingElement.node) {
803
- return;
804
- }
805
-
806
- // Check if this is a React fragment - if so, skip attribute addition entirely
807
- var isFragment = isReactFragment(t, openingElement, fragmentContext);
808
- if (isFragment) {
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
- var name = fullSourceFileNameFromState(state);
849
- if (!name) {
850
- return undefined;
851
- }
852
- if (name.indexOf("/") !== -1) {
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
- var _state$file$opts$pars;
862
- // @ts-expect-error This type is incorrect in Babel, `sourceFileName` is the correct type
863
- var name = (_state$file$opts$pars = state.file.opts.parserOpts) === null || _state$file$opts$pars === void 0 ? void 0 : _state$file$opts$pars.sourceFileName;
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
- var fullSourceFileName = fullSourceFileNameFromState(state);
871
- if (!fullSourceFileName) {
872
- return false;
873
- }
874
- return KNOWN_INCOMPATIBLE_PLUGINS.some(function (pluginName) {
875
- if (fullSourceFileName.includes("/node_modules/".concat(pluginName, "/")) || fullSourceFileName.includes("\\node_modules\\".concat(pluginName, "\\"))) {
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
- if (state.opts["native"]) {
883
- return [nativeComponentName, nativeElementName, nativeSourceFileName];
884
- }
885
- return [webComponentName, webElementName, webSourceFileName];
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
- var fragmentAliases = new Set();
889
- var reactNamespaceAliases = new Set(["React"]); // Default React namespace
890
-
891
- programPath.traverse({
892
- ImportDeclaration: function ImportDeclaration(importPath) {
893
- var source = importPath.node.source.value;
894
-
895
- // Handle React imports
896
- if (source === "react" || source === "React") {
897
- importPath.node.specifiers.forEach(function (spec) {
898
- if (spec.type === "ImportSpecifier" && spec.imported.type === "Identifier") {
899
- // Detect aliased React.Fragment imports (e.g., `Fragment as F`)
900
- // so we can later identify <F> as a fragment in JSX.
901
- if (spec.imported.name === "Fragment") {
902
- fragmentAliases.add(spec.local.name);
903
- }
904
- } else if (spec.type === "ImportDefaultSpecifier" || spec.type === "ImportNamespaceSpecifier") {
905
- // import React from 'react' -> React OR
906
- // import * as React from 'react' -> React
907
- reactNamespaceAliases.add(spec.local.name);
908
- }
909
- });
910
- }
911
- },
912
- // Handle simple variable assignments only (avoid complex cases)
913
- VariableDeclarator: function VariableDeclarator(varPath) {
914
- if (varPath.node.init) {
915
- var init = varPath.node.init;
916
-
917
- // Handle identifier assignments: const MyFragment = Fragment
918
- if (varPath.node.id.type === "Identifier") {
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
- // Handle JSX fragments (<>)
960
- if (openingElement.isJSXFragment()) {
961
- return true;
962
- }
963
- var elementName = getPathName(t, openingElement);
964
-
965
- // Direct fragment references
966
- if (elementName === "Fragment" || elementName === "React.Fragment") {
967
- return true;
968
- }
969
-
970
- // TODO: All these objects are typed as unknown, maybe an oversight in Babel types?
971
-
972
- // Check if the element name is a known fragment alias
973
- if (context && elementName && context.fragmentAliases.has(elementName)) {
974
- return true;
975
- }
976
-
977
- // Handle JSXMemberExpression
978
- 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") {
979
- var nodeName = openingElement.node.name;
980
- if (_typeof(nodeName) !== "object" || !nodeName) {
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
- if (!name) {
1018
- return false;
1019
- }
1020
- return openingElement.node.attributes.some(function (node) {
1021
- if (node.type === "JSXAttribute") {
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
- if (!path.node) return UNKNOWN_ELEMENT_NAME;
1029
- if (!("name" in path.node)) {
1030
- return UNKNOWN_ELEMENT_NAME;
1031
- }
1032
- var name = path.node.name;
1033
- if (typeof name === "string") {
1034
- return name;
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
- if (t.isJSXIdentifier(object)) {
1055
- return object.name;
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
- var UNKNOWN_ELEMENT_NAME = "unknown";
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