Skip to content

Commit d152364

Browse files
authored
Merge pull request #9921 from getsentry/feat/component-name-util
feat(utils): Add function to extract relevant component name
2 parents 1621214 + 61094d4 commit d152364

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

packages/utils/src/browser.ts

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ const WINDOW = getGlobalObject<Window>();
66

77
const DEFAULT_MAX_STRING_LENGTH = 80;
88

9+
type SimpleNode = {
10+
parentNode: SimpleNode;
11+
} | null;
12+
913
/**
1014
* Given a child DOM element, returns a query-selector statement describing that
1115
* and its ancestors
@@ -16,10 +20,6 @@ export function htmlTreeAsString(
1620
elem: unknown,
1721
options: string[] | { keyAttrs?: string[]; maxStringLength?: number } = {},
1822
): string {
19-
type SimpleNode = {
20-
parentNode: SimpleNode;
21-
} | null;
22-
2323
if (!elem) {
2424
return '<unknown>';
2525
}
@@ -86,6 +86,14 @@ function _htmlElementAsString(el: unknown, keyAttrs?: string[]): string {
8686
return '';
8787
}
8888

89+
// @ts-expect-error WINDOW has HTMLElement
90+
if (WINDOW.HTMLElement) {
91+
// If using the component name annotation plugin, this value may be available on the DOM node
92+
if (elem instanceof HTMLElement && elem.dataset && elem.dataset['sentryComponent']) {
93+
return elem.dataset['sentryComponent'];
94+
}
95+
}
96+
8997
out.push(elem.tagName.toLowerCase());
9098

9199
// Pairs of attribute keys defined in `serializeAttribute` and their values on element.
@@ -157,3 +165,33 @@ export function getDomElement<E = any>(selector: string): E | null {
157165
}
158166
return null;
159167
}
168+
169+
/**
170+
* Given a DOM element, traverses up the tree until it finds the first ancestor node
171+
* that has the `data-sentry-component` attribute. This attribute is added at build-time
172+
* by projects that have the component name annotation plugin installed.
173+
*
174+
* @returns a string representation of the component for the provided DOM element, or `null` if not found
175+
*/
176+
export function getComponentName(elem: unknown): string | null {
177+
// @ts-expect-error WINDOW has HTMLElement
178+
if (!WINDOW.HTMLElement) {
179+
return null;
180+
}
181+
182+
let currentElem = elem as SimpleNode;
183+
const MAX_TRAVERSE_HEIGHT = 5;
184+
for (let i = 0; i < MAX_TRAVERSE_HEIGHT; i++) {
185+
if (!currentElem) {
186+
return null;
187+
}
188+
189+
if (currentElem instanceof HTMLElement && currentElem.dataset['sentryComponent']) {
190+
return currentElem.dataset['sentryComponent'];
191+
}
192+
193+
currentElem = currentElem.parentNode;
194+
}
195+
196+
return null;
197+
}

packages/utils/test/browser.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ beforeAll(() => {
66
const dom = new JSDOM();
77
// @ts-expect-error need to override global document
88
global.document = dom.window.document;
9+
// @ts-expect-error need to add HTMLElement type or it will not be found
10+
global.HTMLElement = new JSDOM().window.HTMLElement;
911
});
1012

1113
describe('htmlTreeAsString', () => {

0 commit comments

Comments
 (0)