(target: HTMLElement, maxDepth = 4)
| 60 | * Supports elements inside shadow DOM by crossing shadow boundaries. |
| 61 | */ |
| 62 | export function getElementPath(target: HTMLElement, maxDepth = 4): string { |
| 63 | const parts: string[] = []; |
| 64 | let current: HTMLElement | null = target; |
| 65 | let depth = 0; |
| 66 | |
| 67 | while (current && depth < maxDepth) { |
| 68 | const tag = current.tagName.toLowerCase(); |
| 69 | |
| 70 | // Skip generic wrappers |
| 71 | if (tag === "html" || tag === "body") break; |
| 72 | |
| 73 | // Get identifier |
| 74 | let identifier = tag; |
| 75 | if (current.id) { |
| 76 | identifier = `#${current.id}`; |
| 77 | } else if (current.className && typeof current.className === "string") { |
| 78 | const meaningfulClass = current.className |
| 79 | .split(/\s+/) |
| 80 | .find(c => c.length > 2 && !c.match(/^[a-z]{1,2}$/) && !c.match(/[A-Z0-9]{5,}/)); |
| 81 | if (meaningfulClass) { |
| 82 | identifier = `.${meaningfulClass.split("_")[0]}`; |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | // Mark shadow boundary crossings |
| 87 | const nextParent = getParentElement(current); |
| 88 | if (!current.parentElement && nextParent) { |
| 89 | identifier = `⟨shadow⟩ ${identifier}`; |
| 90 | } |
| 91 | |
| 92 | parts.unshift(identifier); |
| 93 | current = nextParent as HTMLElement | null; |
| 94 | depth++; |
| 95 | } |
| 96 | |
| 97 | return parts.join(" > "); |
| 98 | } |
| 99 | |
| 100 | /** |
| 101 | * Identifies an element and returns a human-readable name + path |
no test coverage detected
searching dependent graphs…