{"version":3,"file":"htmlTreeAsString.js","sources":["../../src/htmlTreeAsString.ts"],"sourcesContent":["import { isString } from '@sentry/core';\n\nconst DEFAULT_MAX_STRING_LENGTH = 80;\n\ntype SimpleNode = {\n parentNode: SimpleNode;\n} | null;\n\n// Native DOM accessors cached at module load. Calling these instead of reading\n// instance properties bypasses user-defined getters that shadow the prototypes.\n// Stored unbound and rebound via .call(el) — the unbound-method lint is expected.\n// See https://github.com/getsentry/sentry-javascript/issues/21353\ntype AccessorKey = 'parentNode' | 'tagName' | 'id' | 'className' | 'getAttribute' | 'dataset';\nconst accessors: Partial> = {};\n\n// oxlint-disable typescript-eslint(unbound-method)\ntry {\n if (typeof Node !== 'undefined') {\n accessors.parentNode = Object.getOwnPropertyDescriptor(Node.prototype, 'parentNode')!.get!;\n }\n if (typeof Element !== 'undefined') {\n accessors.tagName = Object.getOwnPropertyDescriptor(Element.prototype, 'tagName')!.get!;\n accessors.id = Object.getOwnPropertyDescriptor(Element.prototype, 'id')!.get!;\n accessors.className = Object.getOwnPropertyDescriptor(Element.prototype, 'className')!.get!;\n accessors.getAttribute = Element.prototype.getAttribute;\n }\n if (typeof HTMLElement !== 'undefined') {\n accessors.dataset = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'dataset')!.get!;\n }\n} catch {\n // Polyfilled or stubbed prototypes may not have the expected descriptors.\n // _safeRead falls back to direct property access.\n}\n// oxlint-enable typescript-eslint(unbound-method)\n\nfunction _safeRead(el: unknown, prop: AccessorKey, arg?: string): T {\n const fn = accessors[prop];\n if (fn) {\n try {\n return fn.call(el, arg) as T;\n } catch {\n // Fall through to direct access\n }\n }\n const val = (el as Record)[prop];\n return typeof val === 'function' ? val.call(el, arg) : (val as T);\n}\n\n/**\n * Given a child DOM element, returns a query-selector statement describing that\n * and its ancestors\n * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]\n * @returns generated DOM path\n */\nexport function htmlTreeAsString(\n elem: unknown,\n options: string[] | { keyAttrs?: string[]; maxStringLength?: number } = {},\n): string {\n if (!elem) {\n return '';\n }\n\n // try/catch both:\n // - accessing event.target (see getsentry/raven-js#838, #768)\n // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly\n // - can throw an exception in some circumstances.\n try {\n let currentElem = elem as SimpleNode;\n const MAX_TRAVERSE_HEIGHT = 5;\n const out = [];\n let height = 0;\n let len = 0;\n const separator = ' > ';\n const sepLength = separator.length;\n let nextStr;\n const keyAttrs = Array.isArray(options) ? options : options.keyAttrs;\n const maxStringLength = (!Array.isArray(options) && options.maxStringLength) || DEFAULT_MAX_STRING_LENGTH;\n\n while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) {\n nextStr = _htmlElementAsString(currentElem, keyAttrs);\n // bail out if\n // - nextStr is the 'html' element\n // - the length of the string that would be created exceeds maxStringLength\n // (ignore this limit if we are on the first iteration)\n if (nextStr === 'html' || (height > 1 && len + out.length * sepLength + nextStr.length >= maxStringLength)) {\n break;\n }\n\n out.push(nextStr);\n\n len += nextStr.length;\n currentElem = _safeRead(currentElem, 'parentNode');\n }\n\n return out.reverse().join(separator);\n } catch {\n return '';\n }\n}\n\n/**\n * Returns a simple, query-selector representation of a DOM element\n * e.g. [HTMLElement] => input#foo.btn[name=baz]\n * @returns generated DOM path\n */\nfunction _htmlElementAsString(el: unknown, keyAttrs?: string[]): string {\n const out = [];\n\n const tagName = _safeRead(el, 'tagName');\n if (!tagName) {\n return '';\n }\n\n if (typeof HTMLElement !== 'undefined') {\n // If using the component name annotation plugin, this value may be available on the DOM node\n if (el instanceof HTMLElement) {\n const dataset = _safeRead(el, 'dataset');\n if (dataset) {\n if (dataset['sentryComponent']) {\n return dataset['sentryComponent'];\n }\n if (dataset['sentryElement']) {\n return dataset['sentryElement'];\n }\n }\n }\n }\n\n out.push(tagName.toLowerCase());\n\n // Pairs of attribute keys defined in `serializeAttribute` and their values on element.\n const keyAttrPairs = keyAttrs?.length\n ? keyAttrs\n .filter(keyAttr => _safeRead(el, 'getAttribute', keyAttr))\n .map(keyAttr => [keyAttr, _safeRead(el, 'getAttribute', keyAttr)])\n : null;\n\n if (keyAttrPairs?.length) {\n keyAttrPairs.forEach(keyAttrPair => {\n out.push(`[${keyAttrPair[0]}=\"${keyAttrPair[1]}\"]`);\n });\n } else {\n const id = _safeRead(el, 'id');\n if (id) {\n out.push(`#${id}`);\n }\n\n const className = _safeRead(el, 'className');\n if (className && isString(className)) {\n const classes = className.split(/\\s+/);\n for (const c of classes) {\n out.push(`.${c}`);\n }\n }\n }\n for (const k of ['aria-label', 'type', 'name', 'title', 'alt']) {\n const attr = _safeRead(el, 'getAttribute', k);\n if (attr) {\n out.push(`[${k}=\"${attr}\"]`);\n }\n }\n\n return out.join('');\n}\n"],"names":[],"mappings":"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"}