ff-dom 3.0.0-beta.2 → 3.0.0-beta.3

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 +1 @@
1
- {"version":3,"file":"index.browser.cjs","sources":["../src/utils/xpathHelpers.ts","../src/utils/xpath.ts","../src/utils/referenceXpath.ts","../src/utils/cssSelector.ts","../src/utils/getElementsFromHTML.ts","../src/utils/iosSelector.ts","../src/browser/xpath.ts"],"sourcesContent":["export const reWhiteSpace = /^[\\S]+( [\\S]+)*$/i;\r\nexport let cspEnabled: boolean = false;\r\nconst xpathCache: { [x: string]: number } = {};\r\n\r\nexport const timeLog = (label: string, start: number) => {\r\n const duration = performance.now() - start;\r\n console.log(`⏱️ ${label}: ${duration.toFixed(2)}ms time`);\r\n};\r\n\r\ntype EvalResult = {\r\n first: Node | null;\r\n second: Node | null;\r\n};\r\n\r\n// cache per context node → avoids cross-context pollution\r\nlet xpathEvalCache = new WeakMap<Node, Map<string, EvalResult>>();\r\n\r\nconst getXPathContext = (docmt: Node) => {\r\n const owner: Document =\r\n docmt.nodeType === 9\r\n ? (docmt as Document)\r\n : docmt.ownerDocument || document;\r\n\r\n // valid XPath context nodes: Element(1), Document(9), DocumentFragment/ShadowRoot(11)\r\n const contextNode: Node =\r\n docmt.nodeType === 1 || docmt.nodeType === 9 || docmt.nodeType === 11\r\n ? docmt\r\n : owner;\r\n\r\n return { owner, contextNode };\r\n};\r\n\r\nconst getMutationCacheContexts = (node: Node): Node[] => {\r\n const contexts: Node[] = [];\r\n const addContext = (candidate: Node | null | undefined) => {\r\n if (!candidate || contexts.includes(candidate)) return;\r\n contexts.push(candidate);\r\n };\r\n\r\n addContext(node);\r\n\r\n const rootNode = node.getRootNode?.();\r\n if (rootNode instanceof Document || rootNode instanceof ShadowRoot) {\r\n addContext(rootNode);\r\n }\r\n\r\n const ownerDocument =\r\n node.nodeType === Node.DOCUMENT_NODE\r\n ? (node as Document)\r\n : node.ownerDocument;\r\n addContext(ownerDocument);\r\n\r\n return contexts;\r\n};\r\n\r\nexport const clearXPathEvalCache = (node?: Node | null) => {\r\n if (!node) {\r\n xpathEvalCache = new WeakMap<Node, Map<string, EvalResult>>();\r\n return;\r\n }\r\n\r\n getMutationCacheContexts(node).forEach((contextNode) => {\r\n xpathEvalCache.delete(contextNode);\r\n });\r\n};\r\n\r\nexport const evaluateXPathOnce = (xpath: string, docmt: Node): EvalResult => {\r\n const { owner, contextNode } = getXPathContext(docmt);\r\n\r\n // get or create cache for this context node\r\n let nodeCache = xpathEvalCache.get(contextNode);\r\n if (!nodeCache) {\r\n nodeCache = new Map<string, EvalResult>();\r\n xpathEvalCache.set(contextNode, nodeCache);\r\n }\r\n\r\n // cache hit\r\n const cached = nodeCache.get(xpath);\r\n if (cached) return cached;\r\n\r\n // evaluate once, stop after 2 nodes\r\n const result = owner.evaluate(\r\n xpath,\r\n contextNode,\r\n null,\r\n XPathResult.ORDERED_NODE_ITERATOR_TYPE,\r\n null\r\n );\r\n\r\n const first = result.iterateNext();\r\n const second = result.iterateNext();\r\n\r\n const evalResult: EvalResult = { first, second };\r\n nodeCache.set(xpath, evalResult);\r\n\r\n return evalResult;\r\n};\r\nlet relativeXPathCache = new Map();\r\nexport let modifiedElementAttributes: {\r\n url: string | null;\r\n attributeName: string | null;\r\n element: HTMLElement | Element;\r\n doc: Document;\r\n}[] = [];\r\nlet mutationObserver: MutationObserver;\r\nconst INTERNAL_CLASS_TOKENS = new Set([\r\n \"marked-element-temp\",\r\n \"removePointers\"\r\n]);\r\n\r\nconst normalizeClassTokens = (\r\n classValue: string | null | undefined\r\n): string[] =>\r\n (classValue || \"\")\r\n .split(/\\s+/)\r\n .map((token) => token.trim())\r\n .filter((token) => token && !INTERNAL_CLASS_TOKENS.has(token))\r\n .sort();\r\n\r\nexport const hasNumericAttributeValue = (value: string | null | undefined) =>\r\n /\\d/.test(value || \"\");\r\n\r\nexport const getClassTokenConditions = (\r\n element: HTMLElement | Element,\r\n classValue: string | null | undefined,\r\n docmt: Document | ShadowRoot,\r\n allowNumericToken = false\r\n): string[] => {\r\n // Class is tokenized: numeric-looking tokens are unstable, but stable\r\n // non-numeric tokens in the same class attribute should all be tried.\r\n const allClassTokens = normalizeClassTokens(classValue);\r\n const classTokens = allClassTokens.filter((token) =>\r\n allowNumericToken ? true : !hasNumericAttributeValue(token)\r\n );\r\n\r\n if (!classTokens.length) return [];\r\n\r\n if (allClassTokens.length === 1 && classTokens.length === 1) {\r\n // Single class value: exact class is more precise and not affected by\r\n // class-token ordering because there is no competing token.\r\n return [`@class=${escapeCharacters(classTokens[0])}`];\r\n }\r\n\r\n return classTokens\r\n .map((token) => {\r\n const xpath = buildPattern(\r\n `contains(@class,${escapeCharacters(token)})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n\r\n return {\r\n token,\r\n count: getTagOnlyXpathCandidateCount(xpath, element, docmt)\r\n };\r\n })\r\n .sort((left, right) => {\r\n // Multi-token class value: prefer the shortest stable token; uniqueness\r\n // is still validated by the caller/final XPath count.\r\n if (left.token.length !== right.token.length) {\r\n return left.token.length - right.token.length;\r\n }\r\n\r\n return left.count - right.count;\r\n })\r\n .map(({ token }) => `contains(@class,${escapeCharacters(token)})`);\r\n};\r\n\r\nexport const getClassTokenCondition = (\r\n element: HTMLElement | Element,\r\n classValue: string | null | undefined,\r\n docmt: Document | ShadowRoot,\r\n allowNumericToken = false\r\n): string | null => {\r\n return (\r\n getClassTokenConditions(element, classValue, docmt, allowNumericToken)[0] ||\r\n null\r\n );\r\n};\r\n\r\nconst TEST_ID_ATTRIBUTE_NAMES = new Set([\r\n \"data-testid\",\r\n \"data-test-id\",\r\n \"data-test\",\r\n \"data-cy\",\r\n \"testid\"\r\n]);\r\n\r\nconst hasGeneratedNumericSegment = (attributeValue: string): boolean =>\r\n /(?:^|[-_:])\\d{4,}(?:$|[-_:])/.test(attributeValue);\r\n\r\nconst isGeneratedTestIdAttribute = (\r\n attributeName: string,\r\n attributeValue: string\r\n): boolean =>\r\n TEST_ID_ATTRIBUTE_NAMES.has(attributeName.toLowerCase()) &&\r\n hasGeneratedNumericSegment(attributeValue);\r\n\r\nexport const sanitizeAttributeValue = (\r\n attributeName: string,\r\n attributeValue: string | null | undefined\r\n): string => {\r\n if (!attributeValue) {\r\n return \"\";\r\n }\r\n\r\n if (attributeName === \"class\" || attributeName === \"className\") {\r\n return normalizeClassTokens(attributeValue).join(\" \");\r\n }\r\n\r\n return attributeValue.replace(\"removePointers\", \"\").trim();\r\n};\r\n\r\nconst isInternalClassOnlyMutation = (mutation: MutationRecord): boolean => {\r\n if (\r\n mutation.type !== \"attributes\" ||\r\n mutation.attributeName !== \"class\" ||\r\n !(mutation.target instanceof Element)\r\n ) {\r\n return false;\r\n }\r\n\r\n if (\r\n isSvg(mutation.target) &&\r\n mutation.oldValue?.trim() === mutation.target.classList.value?.trim()\r\n ) {\r\n return true;\r\n }\r\n\r\n const previousTokens = normalizeClassTokens(mutation.oldValue);\r\n const currentTokens = normalizeClassTokens(\r\n mutation.target.getAttribute(\"class\")\r\n );\r\n\r\n return previousTokens.join(\" \") === currentTokens.join(\" \");\r\n};\r\n\r\nexport const createObserver = (addedNodeCallBack: Function) => {\r\n mutationObserver = new MutationObserver((mutations) => {\r\n mutations.forEach((mutation) => {\r\n const shouldInvalidateXPathCache =\r\n mutation.type === \"childList\" ||\r\n mutation.type === \"characterData\" ||\r\n (mutation.type === \"attributes\" &&\r\n mutation.attributeName !== \"flndisabled\" &&\r\n !isInternalClassOnlyMutation(mutation));\r\n\r\n if (shouldInvalidateXPathCache) {\r\n clearXPathEvalCache(mutation.target);\r\n }\r\n\r\n if (mutation?.addedNodes?.length) {\r\n addedNodeCallBack(mutation?.addedNodes);\r\n }\r\n\r\n if (mutation.target instanceof HTMLElement) {\r\n if (isInternalClassOnlyMutation(mutation)) {\r\n } else if (\r\n mutation?.type === \"attributes\" &&\r\n ![\"flndisabled\"].includes(mutation.attributeName!)\r\n ) {\r\n modifiedElementAttributes.push({\r\n url: mutation.target.baseURI,\r\n attributeName: mutation.attributeName,\r\n element: mutation.target,\r\n doc: mutation.target.ownerDocument\r\n });\r\n }\r\n }\r\n });\r\n });\r\n};\r\nexport const startObserver = (\r\n target: Node,\r\n options: MutationObserverInit | undefined\r\n) => {\r\n mutationObserver?.observe(target, options);\r\n};\r\n\r\nexport const stopObserver = () => {\r\n mutationObserver?.disconnect();\r\n};\r\n\r\nexport const isNumberExist = (str: string): boolean => {\r\n const hasNumber = /\\d/;\r\n return hasNumber.test(str);\r\n};\r\n\r\nexport const buildPattern = (\r\n pattern: string,\r\n isSvg: boolean,\r\n tagName: string\r\n): string => {\r\n return isSvg\r\n ? `//*[local-name()='${tagName}' and ${pattern}]`\r\n : `//${tagName}[${pattern}]`;\r\n};\r\n\r\nexport const getTextContent = (\r\n targetElement: HTMLElement | Element\r\n): string => {\r\n const textContent = targetElement?.textContent;\r\n if (cspEnabled) {\r\n if (textContent) {\r\n const tooltip = document.querySelector(\".flntooltip\") as HTMLElement;\r\n if (tooltip) {\r\n const lastIndex = textContent.lastIndexOf(tooltip.innerText);\r\n if (\r\n lastIndex &&\r\n textContent.length === lastIndex + tooltip.innerText.length\r\n ) {\r\n return textContent.substring(0, lastIndex);\r\n }\r\n } else {\r\n return textContent;\r\n }\r\n }\r\n } else {\r\n return textContent;\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nexport const getFilteredText = (element: Node): string => {\r\n return element?.childNodes[0]?.nodeValue || \"\";\r\n};\r\n\r\nexport const getCountOfXPath = (\r\n xpath: string,\r\n element: HTMLElement | Element,\r\n docmt: Node,\r\n multiElementReferenceMode: boolean = false\r\n): number => {\r\n try {\r\n const { first, second } = evaluateXPathOnce(xpath, docmt);\r\n\r\n if (!first) return 0;\r\n\r\n // exactly one match\r\n if (!second) {\r\n return first === element ? 1 : 0;\r\n }\r\n\r\n // multiple matches\r\n if (multiElementReferenceMode && Array.isArray(element)) {\r\n let matchCount = 0;\r\n\r\n if (element.includes(first)) matchCount++;\r\n if (element.includes(second)) matchCount++;\r\n\r\n if (matchCount === 2) return 2;\r\n const owner =\r\n docmt.nodeType === 9 ? (docmt as Document) : docmt.ownerDocument!;\r\n\r\n const result = owner.evaluate(\r\n xpath,\r\n docmt,\r\n null,\r\n XPathResult.ORDERED_NODE_ITERATOR_TYPE,\r\n null\r\n );\r\n\r\n let node: Node | null;\r\n while ((node = result.iterateNext())) {\r\n if (element.includes(node)) {\r\n matchCount++;\r\n if (matchCount === 2) return 2;\r\n }\r\n }\r\n\r\n return 0;\r\n }\r\n\r\n return 2;\r\n } catch (error) {\r\n console.error(`Error evaluating XPath: ${xpath}`, error);\r\n return 0;\r\n }\r\n};\r\n\r\nexport const escapeCharacters = (text: string): string => {\r\n if (text) {\r\n if (!(text.indexOf('\"') === -1)) {\r\n return `'${text}'`;\r\n }\r\n if (!(text.indexOf(\"'\") === -1)) {\r\n return `\"${text}\"`;\r\n }\r\n }\r\n return `'${text}'`;\r\n};\r\n\r\nexport const removeParenthesis = (xpath: string): string => {\r\n const charArr = xpath.split(\"\");\r\n\r\n let count = charArr.length;\r\n const indexArray = [];\r\n\r\n while (charArr[count - 2] !== \"[\") {\r\n indexArray.push(charArr[count - 2]);\r\n count--;\r\n }\r\n\r\n indexArray.reverse();\r\n let finalStr = \"\";\r\n for (let i = 0; i < indexArray.length; i++) {\r\n finalStr += indexArray[i];\r\n }\r\n\r\n const endBracketLength = finalStr.length + 2;\r\n let firstpart = xpath.slice(0, xpath.length - endBracketLength);\r\n\r\n if (firstpart.startsWith(\"(\") && firstpart.endsWith(\")\")) {\r\n firstpart = firstpart.slice(1, -1);\r\n } else {\r\n firstpart = xpath;\r\n }\r\n\r\n return firstpart;\r\n};\r\n\r\nexport const findXpathWithIndex = (\r\n val: string,\r\n node: HTMLElement | Element,\r\n docmt: Node,\r\n count: number\r\n) => {\r\n try {\r\n const owner =\r\n docmt.nodeType === 9 // DOCUMENT_NODE\r\n ? (docmt as Document)\r\n : docmt.ownerDocument!;\r\n\r\n let index = 0;\r\n if (count) {\r\n if (getCountOfXPath(`${val}[${count}]`, node, docmt) === 1) {\r\n return `${val}[${count}]`;\r\n }\r\n\r\n if (getCountOfXPath(`(${val})[${count}]`, node, docmt) === 1) {\r\n return `(${val})[${count}]`;\r\n }\r\n }\r\n\r\n const nodes = owner.evaluate(val, docmt, null, XPathResult.ANY_TYPE, null);\r\n let nodex: Node | null = null;\r\n while ((nodex = nodes.iterateNext())) {\r\n index++;\r\n if (nodex.isSameNode(node)) {\r\n if (getCountOfXPath(`${val}[${index}]`, node, docmt) === 1) {\r\n return `${val}[${index}]`;\r\n }\r\n if (getCountOfXPath(`(${val})[${index}]`, node, docmt) === 1) {\r\n return `(${val})[${index}]`;\r\n }\r\n return;\r\n }\r\n }\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n};\r\n\r\nconst deleteLineGap = (a: string): string => {\r\n a &&= a.split(\"\\n\")[0].length > 0 ? a.split(\"\\n\")[0] : a.split(\"\\n\")[1];\r\n return a;\r\n};\r\n\r\nconst deleteGarbageFromInnerText = (a: string): string => {\r\n a = deleteLineGap(a);\r\n a = a\r\n .split(/[^\\u0000-\\u00ff]/)\r\n .reduce((b, c) => {\r\n return b.length > c.length ? b : c;\r\n }, \"\")\r\n .trim();\r\n return (a = a.split(\"/\")[0].trim());\r\n};\r\n\r\nexport const replaceWhiteSpaces = (str: string): string => {\r\n if (str) {\r\n return str.replace(/\\s\\s+/g, \" \").trim();\r\n }\r\n\r\n return str;\r\n};\r\n\r\nexport const getContainerTextCondition = (\r\n element: HTMLElement | Element,\r\n text: string | null | undefined\r\n): string => {\r\n const normalizedText = replaceWhiteSpaces((text || \"\").trim());\r\n\r\n if (!element.children.length || normalizedText.length <= 50) {\r\n return \"\";\r\n }\r\n\r\n const fragment = normalizedText.split(/\\s+/).slice(0, 3).join(\" \");\r\n\r\n // Long container text is usually flattened descendant text. Use a short\r\n // visible fragment instead of exact matching the whole menu/header content.\r\n return fragment.length > 2\r\n ? `contains(normalize-space(.),${escapeCharacters(fragment)})`\r\n : \"\";\r\n};\r\n\r\nexport const getStableTargetTextCandidates = (\r\n text: string | null | undefined\r\n): { prefix: string; fragment: string } => {\r\n const normalizedText = replaceWhiteSpaces((text || \"\").trim());\r\n\r\n if (!normalizedText || !hasNumericAttributeValue(normalizedText)) {\r\n return { prefix: normalizedText, fragment: normalizedText };\r\n }\r\n\r\n const prefix = normalizedText\r\n .split(/[0-9]/)[0]\r\n .replace(/[₹$€£¥₫₽₩₦₱₲₴₵₡₭₮₺฿៛]+/g, \"\")\r\n .trim();\r\n const fragment = prefix\r\n .split(/[^a-zA-Z]+/)\r\n .map((part) => replaceWhiteSpaces(part).trim())\r\n .filter((part) => part.length > 2 && /[a-zA-Z]/.test(part))\r\n .join(\" \")\r\n .trim();\r\n\r\n // Target text containing numbers is dynamic. Keep only a meaningful\r\n // non-numeric prefix/fragment, so price/count text never becomes exact XPath.\r\n return {\r\n prefix: prefix.length > 2 && /[a-zA-Z]/.test(prefix) ? prefix : \"\",\r\n fragment: fragment.length > 2 ? fragment : \"\"\r\n };\r\n};\r\n\r\nexport const getStableTargetText = (\r\n text: string | null | undefined\r\n): string => getStableTargetTextCandidates(text).fragment;\r\n\r\nexport const getShadowRoot = (el: HTMLElement | Element): Element | null => {\r\n if (!el || !el?.getRootNode) return null;\r\n\r\n const root = el.getRootNode() as ShadowRoot;\r\n return root && root?.host ? (root as unknown as Element) : null;\r\n};\r\n\r\nconst isShadowRootNode = (node: Node): node is ShadowRoot => {\r\n return node?.nodeType === Node.DOCUMENT_FRAGMENT_NODE && \"host\" in node;\r\n};\r\n\r\nconst getElementPathFromRoot = (\r\n root: ShadowRoot,\r\n element: Element\r\n): number[] | null => {\r\n const path: number[] = [];\r\n let current: Element | null = element;\r\n\r\n while (current && current.parentElement) {\r\n const parent: Element = current.parentElement as Element;\r\n path.unshift(Array.from(parent.children).indexOf(current));\r\n current = parent;\r\n }\r\n\r\n if (!current || current.parentNode !== root) {\r\n return null;\r\n }\r\n\r\n path.unshift(Array.from(root.children).indexOf(current));\r\n return path;\r\n};\r\n\r\nconst getElementAtPath = (\r\n container: ParentNode & { children: HTMLCollection },\r\n path: number[]\r\n): Element | null => {\r\n let current: (ParentNode & { children: HTMLCollection }) | Element =\r\n container;\r\n\r\n for (const index of path) {\r\n const next: Element | null = current.children.item(index) as Element | null;\r\n if (!next) {\r\n return null;\r\n }\r\n\r\n current = next;\r\n }\r\n\r\n return current as Element | null;\r\n};\r\n\r\nexport const createShadowEvaluationContext = (\r\n root: ShadowRoot,\r\n element?: HTMLElement | Element | (HTMLElement | Element)[]\r\n) => {\r\n const tempDoc =\r\n root.ownerDocument.implementation.createHTMLDocument(\"shadow-xpath\");\r\n const wrapper = tempDoc.createElement(\"div\");\r\n wrapper.innerHTML = root.innerHTML;\r\n tempDoc.body.appendChild(wrapper);\r\n\r\n const cloneForElement = (candidate?: HTMLElement | Element | null) => {\r\n if (\r\n !candidate ||\r\n !(candidate instanceof root.ownerDocument.defaultView!.Element)\r\n ) {\r\n return null;\r\n }\r\n\r\n const path = getElementPathFromRoot(root, candidate);\r\n return path ? getElementAtPath(wrapper, path) : null;\r\n };\r\n\r\n const cloneElements = Array.isArray(element)\r\n ? element.map((candidate) => cloneForElement(candidate)).filter(Boolean)\r\n : [];\r\n\r\n const cloneElement = Array.isArray(element)\r\n ? null\r\n : cloneForElement(element ?? null);\r\n\r\n return {\r\n owner: tempDoc,\r\n contextNode: wrapper,\r\n cloneElement,\r\n cloneElements\r\n };\r\n};\r\n\r\nexport const checkBlockedAttributes = (\r\n attribute: {\r\n name: string;\r\n value: string;\r\n },\r\n targetElement: HTMLElement | Element,\r\n isTarget: boolean\r\n): boolean => {\r\n const sanitizedValue = sanitizeAttributeValue(\r\n attribute.name,\r\n attribute.value\r\n );\r\n\r\n if (!sanitizedValue || typeof attribute?.value === \"boolean\") {\r\n return false;\r\n }\r\n const blockedValues = [\r\n \"true\",\r\n \"false\",\r\n \"on\",\r\n \"off\",\r\n \"flntooltip\",\r\n \"flutter-highlight-overlay\"\r\n ];\r\n if (blockedValues.some((x) => x === sanitizedValue)) {\r\n return false;\r\n }\r\n const blockedNames = [\"style\", \"locator-data-tooltip\", \"value\"];\r\n if (blockedNames.some((x) => x === attribute.name)) {\r\n return false;\r\n }\r\n\r\n const isModified = modifiedElementAttributes?.find(\r\n (x) =>\r\n x.doc === targetElement.ownerDocument &&\r\n x.element === targetElement &&\r\n x.attributeName === attribute.name\r\n );\r\n if (isModified) {\r\n return false;\r\n }\r\n\r\n if (attribute?.name?.indexOf(\"on\") === 0 && attribute?.name?.length > 3) {\r\n return false;\r\n }\r\n\r\n if (typeof attribute.value === \"function\") {\r\n return false;\r\n }\r\n\r\n if (isGeneratedTestIdAttribute(attribute.name, sanitizedValue)) {\r\n return false;\r\n }\r\n\r\n // Strict numeric-attribute validation: numeric attribute values are treated\r\n // as unstable before candidate creation. Class is handled token-by-token by\r\n // getClassTokenCondition, so only numeric class tokens are rejected there.\r\n if (attribute.name !== \"class\" && hasNumericAttributeValue(sanitizedValue)) {\r\n return false;\r\n }\r\n\r\n return true;\r\n};\r\n\r\nexport const getRelationship = (a: HTMLElement, b: HTMLElement): string => {\r\n let pos = a.compareDocumentPosition(b);\r\n return pos === 2\r\n ? \"preceding\"\r\n : pos === 4\r\n ? \"following\"\r\n : pos === 8\r\n ? \"ancestor\"\r\n : pos === 16\r\n ? \"descendant\"\r\n : pos === 32\r\n ? \"self\"\r\n : \"\";\r\n};\r\n\r\nexport const isSvg = (element: HTMLElement | Element) => {\r\n return element instanceof SVGElement;\r\n};\r\n\r\nexport const replaceTempAttributes = (str: string): string => {\r\n if (!str) return str;\r\n\r\n return str.replace(/\\b[a-zA-Z_]*disabled\\b/gi, \"disabled\");\r\n};\r\n\r\nconst getElementFromXpath = (xpath: string, docmt: Node, multi = false) => {\r\n let contextNode: Node = docmt;\r\n\r\n // XPath does NOT support DocumentFragment / ShadowRoot\r\n if (docmt.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\r\n contextNode = (docmt as ShadowRoot).host ?? docmt;\r\n }\r\n\r\n const owner =\r\n contextNode.nodeType === Node.DOCUMENT_NODE\r\n ? (contextNode as Document)\r\n : contextNode.ownerDocument!;\r\n\r\n if (multi) {\r\n return owner.evaluate(xpath, contextNode, null, XPathResult.ANY_TYPE, null);\r\n }\r\n\r\n return owner.evaluate(\r\n xpath,\r\n contextNode,\r\n null,\r\n XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n ).singleNodeValue;\r\n};\r\n\r\nexport const getPropertyXPath = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n prop: string,\r\n value: string,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n if (value) {\r\n const { tagName } = element;\r\n let count;\r\n let combinePattern = \"\";\r\n const mergePattern = [];\r\n let pattern;\r\n\r\n const isAttributeProp = prop.startsWith(\"@\");\r\n const isTextProp = prop === \".\" || prop === \"text()\";\r\n const normalizedTextProp = isTextProp ? \".\" : prop;\r\n const hasTextSpacing = isTextProp && /\\s/.test(value.trim());\r\n const stableTargetText = isTextProp ? getStableTargetText(value) : value;\r\n const textValueForPredicate =\r\n isTextProp && hasNumericAttributeValue(value) ? stableTargetText : value;\r\n const containerTextCondition = isTextProp\r\n ? getContainerTextCondition(element, textValueForPredicate)\r\n : \"\";\r\n\r\n if (prop === \"@class\") {\r\n for (const classCondition of getClassTokenConditions(\r\n element,\r\n value,\r\n docmt\r\n )) {\r\n // Single-mode class generation tries every stable token and lets the\r\n // normal uniqueness check choose the first usable XPath.\r\n pattern = buildPattern(\r\n classCondition,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n if (isTextProp && hasNumericAttributeValue(value) && !stableTargetText) {\r\n // Target text with only dynamic numeric content should not produce a\r\n // text XPath. Other attribute/relative fallbacks can still run.\r\n return;\r\n }\r\n\r\n if (value && (!isAttributeProp || !isNumberExist(value))) {\r\n if (containerTextCondition) {\r\n pattern = buildPattern(\r\n containerTextCondition,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n } else if (hasTextSpacing) {\r\n pattern = buildPattern(\r\n `normalize-space(${normalizedTextProp})=${escapeCharacters(\r\n replaceWhiteSpaces(textValueForPredicate)\r\n ).trim()}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n } else if (!reWhiteSpace.test(value)) {\r\n pattern = buildPattern(\r\n `normalize-space(${prop})=${escapeCharacters(\r\n replaceWhiteSpaces(textValueForPredicate)\r\n ).trim()}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n } else {\r\n pattern = `//${tagName}[${prop}=${escapeCharacters(\r\n textValueForPredicate\r\n )}]`;\r\n }\r\n\r\n count = getCountOfXPath(pattern, element, docmt);\r\n\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n\r\n if (isAttributeProp && hasNumericAttributeValue(value)) {\r\n // Strict numeric-attribute validation: do not split numeric attribute\r\n // values into starts-with/contains fallbacks.\r\n return;\r\n }\r\n\r\n if (value && isTarget) {\r\n const splitText = value.split(\" \");\r\n if (splitText?.length) {\r\n if (splitText.length === 1) {\r\n const contentRes = [...new Set(splitText[0].match(/([^0-9]+)/g))];\r\n if (contentRes?.length >= 1) {\r\n if (\r\n contentRes[0] &&\r\n replaceWhiteSpaces(contentRes[0].trim())?.length > 1\r\n ) {\r\n if (value.startsWith(contentRes[0])) {\r\n if (!reWhiteSpace.test(contentRes[0])) {\r\n combinePattern = `starts-with(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[0])\r\n ).trim()})`;\r\n } else {\r\n combinePattern = `starts-with(${prop},${escapeCharacters(\r\n contentRes[0]\r\n ).trim()})`;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (contentRes?.length > 1) {\r\n if (\r\n contentRes[contentRes.length - 1] &&\r\n replaceWhiteSpaces(contentRes[contentRes.length - 1].trim())\r\n ?.length > 1\r\n ) {\r\n if (value.endsWith(contentRes[contentRes.length - 1])) {\r\n if (!reWhiteSpace.test(contentRes[contentRes.length - 1])) {\r\n combinePattern = `ends-with(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[contentRes.length - 1])\r\n ).trim()})`;\r\n } else {\r\n combinePattern = `ends-with(${prop},${escapeCharacters(\r\n contentRes[contentRes.length - 1]\r\n ).trim()})`;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and ${combinePattern}]`;\r\n } else {\r\n pattern = `//${tagName}[${combinePattern}]`;\r\n }\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n } else {\r\n const endIndex =\r\n splitText.length % 2 === 0\r\n ? splitText.length / 2\r\n : splitText.length % 2;\r\n const startIndexString = splitText.slice(0, endIndex).join(\" \");\r\n let contentRes = [...new Set(startIndexString.match(/([^0-9]+)/g))];\r\n if (contentRes?.length) {\r\n if (\r\n contentRes[0] &&\r\n replaceWhiteSpaces(contentRes[0].trim())?.length\r\n ) {\r\n if (value.startsWith(contentRes[0])) {\r\n if (!reWhiteSpace.test(contentRes[0])) {\r\n combinePattern = `starts-with(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[0])\r\n ).trim()})`;\r\n } else {\r\n combinePattern = `starts-with(${prop},${escapeCharacters(\r\n contentRes[0]\r\n ).trim()})`;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and ${combinePattern}]`;\r\n } else {\r\n pattern = `//${tagName}[${combinePattern}]`;\r\n }\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n\r\n const endIndexString = splitText\r\n .slice(endIndex, splitText.length - 1)\r\n .join(\" \");\r\n contentRes = [...new Set(endIndexString.match(/([^0-9]+)/g))];\r\n if (contentRes?.length) {\r\n if (\r\n contentRes[0] &&\r\n replaceWhiteSpaces(contentRes[0].trim())?.length > 3\r\n ) {\r\n if (value.endsWith(contentRes[0])) {\r\n if (!reWhiteSpace.test(contentRes[0])) {\r\n combinePattern = `ends-with(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[0])\r\n ).trim()})`;\r\n } else {\r\n combinePattern = `ends-with(${prop},${escapeCharacters(\r\n contentRes[0]\r\n ).trim()})`;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and ${combinePattern}]`;\r\n } else {\r\n pattern = `//${tagName}[${combinePattern}]`;\r\n }\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (value && isTarget && isNumberExist(value)) {\r\n const contentRes = [...new Set(value.match(/([^0-9]+)/g))];\r\n if (contentRes?.length) {\r\n for (let i = 0; i < contentRes?.length; i++) {\r\n if (\r\n contentRes[i] &&\r\n replaceWhiteSpaces(contentRes[i].trim())?.length > 1\r\n ) {\r\n if (!reWhiteSpace.test(contentRes[i])) {\r\n mergePattern.push(\r\n `contains(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[i])\r\n ).trim()})`\r\n );\r\n } else {\r\n mergePattern.push(\r\n `contains(${prop},${escapeCharacters(\r\n contentRes[i].trim()\r\n ).trim()})`\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (mergePattern?.length) {\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and ${mergePattern.join(\r\n \" and \"\r\n )}]`;\r\n } else {\r\n pattern = `//${tagName}[${mergePattern.join(\" and \")}]`;\r\n }\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n }\r\n\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and text()]`;\r\n } else {\r\n pattern = `//${tagName}[text()]`;\r\n }\r\n\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n};\r\n\r\nexport const getAbsoluteXPath = (\r\n domNode: HTMLElement | Element | null,\r\n docmt: Document\r\n): string => {\r\n try {\r\n if (!domNode) {\r\n return \"\";\r\n }\r\n\r\n let xpathe = isSvg(domNode)\r\n ? `/*[local-name()='${domNode.tagName}']`\r\n : `/${domNode.tagName}`;\r\n\r\n // // If this node has siblings of the same tagName, get the index of this node\r\n if (domNode.parentElement) {\r\n // Get the siblings\r\n const childNodes = Array.prototype.slice\r\n .call(domNode.parentElement.children, 0)\r\n .filter(\r\n (childNode: HTMLElement) => childNode.tagName === domNode.tagName\r\n );\r\n\r\n // // If there's more than one sibling, append the index\r\n if (childNodes.length > 1) {\r\n const index = childNodes.indexOf(domNode);\r\n xpathe += `[${index + 1}]`;\r\n }\r\n } else if (domNode instanceof HTMLElement) {\r\n if (domNode.offsetParent) {\r\n const childNodes = Array.prototype.slice\r\n .call(domNode.offsetParent.children, 0)\r\n .filter(\r\n (childNode: HTMLElement) => childNode.tagName === domNode.tagName\r\n );\r\n\r\n // // If there's more than one sibling, append the index\r\n if (childNodes.length > 1) {\r\n const index = childNodes.indexOf(domNode);\r\n xpathe += `[${index + 1}]`;\r\n }\r\n }\r\n }\r\n\r\n // // Make a recursive call to this nodes parents and prepend it to this xpath\r\n return getAbsoluteXPath(domNode?.parentElement, docmt) + xpathe;\r\n } catch (error) {\r\n // If there's an unexpected exception, abort and don't get an XPath\r\n console.log(\"xpath\", error);\r\n\r\n return \"\";\r\n }\r\n};\r\n\r\nexport const getRelativeXPath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean = false,\r\n attributesArray: Attr[]\r\n) => {\r\n try {\r\n // Generate a cache key based on the node's identifier, index, and target flag\r\n // Check if the result for this node is already cached\r\n if (relativeXPathCache.has(domNode)) {\r\n return relativeXPathCache.get(domNode);\r\n }\r\n\r\n // Initialize an array to hold parts of the XPath\r\n const xpathParts = [];\r\n let currentNode = domNode;\r\n\r\n // Traverse up the DOM tree iteratively instead of using recursion\r\n while (currentNode) {\r\n let xpathe: string | undefined = \"\";\r\n let hasUniqueAttr = false;\r\n let attributes =\r\n domNode === currentNode\r\n ? (attributesArray ?? currentNode.attributes)\r\n : currentNode.attributes;\r\n\r\n // Loop through attributes to check for unique identifiers\r\n for (const attrName of Array.from(attributes)) {\r\n if (checkBlockedAttributes(attrName, currentNode, isTarget)) {\r\n const attrValue = sanitizeAttributeValue(\r\n attrName.name,\r\n attrName.nodeValue\r\n );\r\n\r\n const elementName = attrName.name;\r\n\r\n // Class can produce multiple stable token candidates; try each\r\n // before moving to text/index fallbacks.\r\n for (const xpathCandidate of getXpathStrings(\r\n currentNode,\r\n elementName,\r\n attrValue\r\n )) {\r\n xpathe = xpathCandidate;\r\n let othersWithAttr: number = 0;\r\n othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n if (othersWithAttr === 1) {\r\n xpathParts.unshift(replaceTempAttributes(xpathe));\r\n hasUniqueAttr = true;\r\n break;\r\n }\r\n\r\n if (othersWithAttr > 1 && isIndex) {\r\n xpathe = findXpathWithIndex(\r\n xpathe,\r\n currentNode,\r\n docmt,\r\n othersWithAttr\r\n );\r\n if (xpathe) {\r\n xpathParts.unshift(replaceTempAttributes(xpathe));\r\n hasUniqueAttr = true;\r\n break;\r\n }\r\n // return replaceTempAttributes(xpathe);\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (currentNode.textContent) {\r\n if (\r\n !isTarget ||\r\n (isTarget && !isNumberExist(currentNode.textContent))\r\n ) {\r\n let reWhiteSpace = new RegExp(/^[\\S]+( [\\S]+)*$/gi);\r\n const filteredText = getFilteredText(currentNode);\r\n const containerTextCondition = getContainerTextCondition(\r\n currentNode,\r\n filteredText\r\n );\r\n\r\n if (containerTextCondition) {\r\n xpathe = buildPattern(\r\n containerTextCondition,\r\n isSvg(currentNode),\r\n currentNode.tagName || \"*\"\r\n );\r\n } else if (!reWhiteSpace.test(currentNode.textContent)) {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and normalize-space(.)=${escapeCharacters(\r\n filteredText\r\n )}]`\r\n : `//${\r\n currentNode.tagName || \"*\"\r\n }[normalize-space(.)=${escapeCharacters(\r\n filteredText\r\n )}]`;\r\n } else {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and .=${escapeCharacters(filteredText)}]`\r\n : `//${currentNode.tagName || \"*\"}[.=${escapeCharacters(\r\n filteredText\r\n )}]`;\r\n }\r\n\r\n let othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n if (othersWithAttr === 1) {\r\n return xpathe;\r\n }\r\n\r\n if (othersWithAttr > 1 && isIndex) {\r\n xpathe = findXpathWithIndex(\r\n xpathe,\r\n currentNode,\r\n docmt,\r\n othersWithAttr\r\n );\r\n return xpathe;\r\n }\r\n } else {\r\n let combinePattern: string[] = [];\r\n const contentRes = [\r\n ...new Set(getFilteredText(currentNode).match(/([^0-9]+)/g))\r\n ];\r\n let reWhiteSpace = new RegExp(/^[\\S]+( [\\S]+)*$/gi);\r\n if (contentRes?.length) {\r\n for (let i = 0; i < contentRes?.length; i++) {\r\n if (\r\n contentRes[i] &&\r\n replaceWhiteSpaces((contentRes[i] as string).trim())\r\n ) {\r\n if (!reWhiteSpace.test(contentRes[i] as string)) {\r\n combinePattern.push(\r\n `contains(.,${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[i])\r\n ).trim()})`\r\n );\r\n } else {\r\n combinePattern.push(\r\n `contains(.,${escapeCharacters(\r\n (contentRes[i] as string).trim()\r\n ).trim()})`\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and ${combinePattern.join(\" and \")}]`\r\n : `//${currentNode.tagName || \"*\"}[${combinePattern.join(\r\n \" and \"\r\n )}]`;\r\n let othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n if (othersWithAttr === 1) {\r\n return xpathe;\r\n }\r\n\r\n if (othersWithAttr > 1 && isIndex) {\r\n xpathe = findXpathWithIndex(\r\n xpathe,\r\n currentNode,\r\n docmt,\r\n othersWithAttr\r\n );\r\n return xpathe;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // If no unique attribute was found, construct XPath by tag name\r\n if (!hasUniqueAttr) {\r\n let tagBasedXPath = isSvg(currentNode)\r\n ? `/*[local-name()='${currentNode.tagName}']`\r\n : `/${currentNode.tagName}`;\r\n\r\n // Handle sibling nodes\r\n if (currentNode.parentElement) {\r\n const siblings = Array.from(\r\n currentNode.parentElement.children\r\n ).filter((childNode) => childNode.tagName === currentNode.tagName);\r\n\r\n // Append index to distinguish between siblings\r\n if (siblings.length > 1) {\r\n const index = siblings.indexOf(currentNode);\r\n tagBasedXPath += `[${index + 1}]`;\r\n }\r\n }\r\n\r\n // Add the constructed tag-based XPath to the parts array\r\n xpathParts.unshift(tagBasedXPath);\r\n } else {\r\n break;\r\n }\r\n\r\n // Move up to the parent node for the next iteration\r\n currentNode = currentNode.parentElement!;\r\n }\r\n\r\n // Combine all parts into the final XPath\r\n const finalXPath = `${xpathParts.join(\"\")}`;\r\n\r\n // Cache the final XPath for this node\r\n relativeXPathCache.set(domNode, finalXPath);\r\n return finalXPath;\r\n } catch (error) {\r\n console.log(error);\r\n return null;\r\n }\r\n};\r\n\r\nexport const getCombinationXpath = (\r\n attribute: Attr,\r\n domNode: HTMLElement | Element\r\n) => {\r\n const combinePattern = [];\r\n let pattern: string = \"\";\r\n\r\n if (\r\n attribute &&\r\n typeof attribute.nodeValue !== \"function\" // &&\r\n // !modifiedElementAttributes?.find(\r\n // (x) => x.element === domNode && x.attributeName === attribute.name\r\n // )\r\n ) {\r\n if (attribute.name === \"class\") {\r\n const docmt =\r\n (domNode.getRootNode?.() as Document | ShadowRoot | null) ??\r\n domNode.ownerDocument;\r\n const classConditions = getClassTokenConditions(\r\n domNode,\r\n attribute.value,\r\n docmt\r\n );\r\n\r\n // Class values are handled token-by-token so numeric tokens are blocked\r\n // without throwing away the other stable class tokens.\r\n for (const classCondition of classConditions) {\r\n pattern = isSvg(domNode)\r\n ? `//*[local-name()='${domNode.tagName}' and ${classCondition}]`\r\n : `//${domNode.tagName}[${classCondition}]`;\r\n\r\n if (pattern) {\r\n return pattern;\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n if (isNumberExist(attribute.value)) {\r\n return;\r\n }\r\n\r\n const contentRes = [...new Set(attribute.value.match(/([^0-9]+)/g))];\r\n if (contentRes?.length) {\r\n for (let i = 0; i < contentRes?.length; i++) {\r\n if (\r\n contentRes[i] &&\r\n replaceWhiteSpaces(contentRes[i].trim())?.length > 2\r\n ) {\r\n if (!reWhiteSpace.test(contentRes[i])) {\r\n combinePattern.push(\r\n `contains(@${attribute.name},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[i])\r\n ).trim()})`\r\n );\r\n } else {\r\n combinePattern.push(\r\n `contains(@${attribute.name},${escapeCharacters(\r\n contentRes[i].trim()\r\n )})`\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n pattern = isSvg(domNode)\r\n ? `//*[local-name()='${domNode.tagName}' and ${combinePattern.join(\r\n \" and \"\r\n )}]`\r\n : `//${domNode.tagName}[${combinePattern.join(\" and \")}]`;\r\n return pattern;\r\n }\r\n }\r\n};\r\n\r\nexport const getAttributeCombinationXpath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document | ShadowRoot,\r\n uniqueAttributes: Attr[],\r\n isTarget: boolean\r\n): string | undefined => {\r\n try {\r\n const candidateAttributes = uniqueAttributes.filter((attr) =>\r\n checkBlockedAttributes(attr, domNode, isTarget)\r\n );\r\n\r\n const buildAttributeConditions = (attribute: Attr): string[] => {\r\n const attrValue = sanitizeAttributeValue(\r\n attribute.name,\r\n attribute.nodeValue\r\n );\r\n\r\n if (!attrValue) return [];\r\n\r\n if (attribute.name === \"class\") {\r\n return getClassTokenConditions(\r\n domNode,\r\n attrValue,\r\n docmt\r\n );\r\n }\r\n\r\n // Strict numeric-attribute validation for direct callers.\r\n if (hasNumericAttributeValue(attrValue)) return [];\r\n\r\n if (!reWhiteSpace.test(attrValue)) {\r\n return [`normalize-space(@${attribute.name})=\"${attrValue}\"`];\r\n }\r\n\r\n return [`@${attribute.name}=\"${attrValue}\"`];\r\n };\r\n\r\n const getTextConditions = (): string[] => {\r\n const rawText = replaceWhiteSpaces(getTextContent(domNode)?.trim() || \"\");\r\n const stableTargetText = getStableTargetText(rawText);\r\n if (hasNumericAttributeValue(rawText)) {\r\n return stableTargetText\r\n ? [\r\n `contains(normalize-space(.),${escapeCharacters(\r\n stableTargetText\r\n )})`\r\n ]\r\n : [];\r\n }\r\n\r\n if (!rawText || rawText.length > 80 || /^\\d+$/.test(rawText)) {\r\n const containerTextCondition = getContainerTextCondition(\r\n domNode,\r\n rawText\r\n );\r\n return containerTextCondition ? [containerTextCondition] : [];\r\n }\r\n\r\n const conditions = new Set<string>();\r\n const containerTextCondition = getContainerTextCondition(\r\n domNode,\r\n rawText\r\n );\r\n\r\n if (containerTextCondition) {\r\n conditions.add(containerTextCondition);\r\n return Array.from(conditions);\r\n }\r\n\r\n if (reWhiteSpace.test(rawText) && rawText.length <= 40 && !rawText.includes(\" \")) {\r\n conditions.add(`text()=${escapeCharacters(rawText)}`);\r\n }\r\n\r\n if (rawText.includes(\" \")) {\r\n conditions.add(\r\n `normalize-space(.)=${escapeCharacters(replaceWhiteSpaces(rawText))}`\r\n );\r\n }\r\n\r\n conditions.add(`contains(text(),${escapeCharacters(rawText)})`);\r\n\r\n return Array.from(conditions);\r\n };\r\n\r\n const generateAttributeCombinations = (\r\n attributes: Attr[],\r\n combinationSize: number\r\n ): Attr[][] => {\r\n const results: Attr[][] = [];\r\n\r\n const build = (startIndex: number, currentGroup: Attr[]) => {\r\n if (currentGroup.length === combinationSize) {\r\n results.push([...currentGroup]);\r\n return;\r\n }\r\n\r\n for (let i = startIndex; i < attributes.length; i++) {\r\n currentGroup.push(attributes[i]);\r\n build(i + 1, currentGroup);\r\n currentGroup.pop();\r\n }\r\n };\r\n\r\n build(0, []);\r\n return results;\r\n };\r\n\r\n const buildXPath = (conditions: string[]) =>\r\n isSvg(domNode)\r\n ? `//*[local-name()='${domNode.tagName}' and ${conditions.join(\" and \")}]`\r\n : `//${domNode.tagName}[${conditions.join(\" and \")}]`;\r\n\r\n const tryAttributeOnlyCombinations = () => {\r\n if (candidateAttributes.length < 2) {\r\n return undefined;\r\n }\r\n\r\n for (\r\n let combinationSize = 2;\r\n combinationSize <= candidateAttributes.length;\r\n combinationSize++\r\n ) {\r\n const attributeGroups = generateAttributeCombinations(\r\n candidateAttributes,\r\n combinationSize\r\n );\r\n\r\n for (const attributeGroup of attributeGroups) {\r\n let xpathConditions: string[] = [];\r\n\r\n for (const attribute of attributeGroup) {\r\n const attributeConditions = buildAttributeConditions(attribute);\r\n\r\n if (!attributeConditions.length) continue;\r\n\r\n xpathConditions.push(...attributeConditions);\r\n }\r\n\r\n if (xpathConditions.length < 2) continue;\r\n\r\n const xpath = buildXPath(xpathConditions);\r\n\r\n let matchCount: number;\r\n\r\n try {\r\n matchCount = getCountOfXPath(xpath, domNode, docmt);\r\n } catch {\r\n continue;\r\n }\r\n\r\n if (matchCount === 1) {\r\n return xpath;\r\n }\r\n }\r\n }\r\n\r\n return undefined;\r\n };\r\n\r\n const attributeOnlyXpath = tryAttributeOnlyCombinations();\r\n if (attributeOnlyXpath) {\r\n return attributeOnlyXpath;\r\n }\r\n\r\n const textConditions = getTextConditions();\r\n if (!textConditions.length || !candidateAttributes.length) {\r\n return;\r\n }\r\n\r\n for (\r\n let combinationSize = 1;\r\n combinationSize <= candidateAttributes.length;\r\n combinationSize++\r\n ) {\r\n const attributeGroups = generateAttributeCombinations(\r\n candidateAttributes,\r\n combinationSize\r\n );\r\n\r\n for (const attributeGroup of attributeGroups) {\r\n let attributeConditions: string[] = [];\r\n\r\n for (const attribute of attributeGroup) {\r\n attributeConditions.push(...buildAttributeConditions(attribute));\r\n }\r\n\r\n if (!attributeConditions.length) {\r\n continue;\r\n }\r\n\r\n for (const textCondition of textConditions) {\r\n const xpathConditions = [...attributeConditions, textCondition];\r\n const xpath = buildXPath(xpathConditions);\r\n\r\n try {\r\n if (getCountOfXPath(xpath, domNode, docmt) === 1) {\r\n return xpath;\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.log(`XPath generation error: ${JSON.stringify(error, null, 2)}`);\r\n }\r\n};\r\n\r\nexport const intermediateXpathStep = (\r\n targetElemt: HTMLElement | Element,\r\n attr: { name: string; value: string },\r\n isTarget: boolean\r\n): string => {\r\n return intermediateXpathSteps(targetElemt, attr, isTarget)[0] || \"\";\r\n};\r\n\r\nexport const intermediateXpathSteps = (\r\n targetElemt: HTMLElement | Element,\r\n attr: { name: string; value: string },\r\n isTarget: boolean\r\n): string[] => {\r\n let isSvgElement = isSvg(targetElemt);\r\n let expression: string = \"\";\r\n\r\n if (checkBlockedAttributes(attr, targetElemt, isTarget)) {\r\n let attrValue = sanitizeAttributeValue(attr.name, attr.value);\r\n const elementName = attr.name;\r\n\r\n if (elementName === \"class\") {\r\n const docmt =\r\n (targetElemt.getRootNode?.() as Document | ShadowRoot | null) ??\r\n targetElemt.ownerDocument;\r\n\r\n // Relative child/parent steps follow the same class-token rule as direct\r\n // XPath candidates: try every stable token, never numeric tokens.\r\n return getClassTokenConditions(targetElemt, attrValue, docmt).map(\r\n (classCondition) =>\r\n isSvgElement\r\n ? `*[local-name()='${targetElemt.tagName}' and ${classCondition}]`\r\n : `${targetElemt.tagName || \"*\"}[${classCondition}]`\r\n );\r\n }\r\n\r\n // Strict numeric-attribute validation for direct callers.\r\n if (hasNumericAttributeValue(attrValue)) {\r\n return [];\r\n }\r\n\r\n if (!reWhiteSpace.test(attrValue)) {\r\n expression = isSvgElement\r\n ? `*[local-name()='${\r\n targetElemt.tagName\r\n }' and normalize-space(@${elementName})=${escapeCharacters(\r\n attrValue\r\n )}]`\r\n : `${\r\n targetElemt.tagName || \"*\"\r\n }[normalize-space(@${elementName})=${escapeCharacters(attrValue)}]`;\r\n } else {\r\n expression = isSvgElement\r\n ? `*[local-name()='${\r\n targetElemt.tagName\r\n }' and @${elementName}=${escapeCharacters(attrValue)}]`\r\n : `${targetElemt.tagName || \"*\"}[@${elementName}=${escapeCharacters(\r\n attrValue\r\n )}]`;\r\n }\r\n }\r\n\r\n return expression ? [expression] : [];\r\n};\r\n\r\nexport const getFilteredTextXPath = (\r\n node: HTMLElement | Element,\r\n docmt: Document | ShadowRoot\r\n): string => {\r\n if (!node.textContent) return \"\";\r\n\r\n const filteredText = getFilteredText(node);\r\n const stableTargetText = getStableTargetText(filteredText);\r\n if (hasNumericAttributeValue(filteredText) && !stableTargetText) {\r\n // Do not build text XPath from purely numeric/dynamic target text.\r\n return \"\";\r\n }\r\n\r\n const textForPredicate =\r\n hasNumericAttributeValue(filteredText) ? stableTargetText : filteredText;\r\n const containerTextCondition = getContainerTextCondition(\r\n node,\r\n textForPredicate\r\n );\r\n\r\n let xpathe;\r\n\r\n if (containerTextCondition) {\r\n xpathe = buildPattern(\r\n containerTextCondition,\r\n isSvg(node),\r\n node.tagName || \"*\"\r\n );\r\n } else if (hasNumericAttributeValue(filteredText)) {\r\n xpathe = buildPattern(\r\n `contains(normalize-space(.),${escapeCharacters(textForPredicate)})`,\r\n isSvg(node),\r\n node.tagName || \"*\"\r\n );\r\n } else if (!reWhiteSpace.test(filteredText) || /\\s/.test(filteredText.trim())) {\r\n xpathe = buildPattern(\r\n `normalize-space(.)=${escapeCharacters(textForPredicate)}`,\r\n isSvg(node),\r\n node.tagName || \"*\"\r\n );\r\n } else {\r\n xpathe = isSvg(node)\r\n ? `//*[local-name()='${node.tagName}' and .=${escapeCharacters(\r\n textForPredicate\r\n )}]`\r\n : `//${node.tagName || \"*\"}[.=${escapeCharacters(textForPredicate)}]`;\r\n }\r\n\r\n return xpathe;\r\n};\r\n\r\nexport const getNormalizedPropertyXPath = (\r\n element: HTMLElement | Element,\r\n prop: string,\r\n value: string\r\n): string => {\r\n if ((prop === \".\" || prop === \"text()\") && hasNumericAttributeValue(value)) {\r\n const { fragment } = getStableTargetTextCandidates(value);\r\n\r\n return fragment\r\n ? buildPattern(\r\n `contains(normalize-space(.),${escapeCharacters(fragment)})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n )\r\n : \"\";\r\n }\r\n\r\n return buildPattern(\r\n `normalize-space(${prop})=${escapeCharacters(replaceWhiteSpaces(value)).trim()}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n};\r\n\r\nexport const getStartsWithPropertyXPath = (\r\n element: HTMLElement | Element,\r\n prop: string,\r\n value: string\r\n): string => {\r\n if ((prop === \".\" || prop === \"text()\") && hasNumericAttributeValue(value)) {\r\n const { prefix, fragment } = getStableTargetTextCandidates(value);\r\n const stableText = prefix || fragment;\r\n\r\n return stableText\r\n ? buildPattern(\r\n `starts-with(normalize-space(.),${escapeCharacters(stableText)})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n )\r\n : \"\";\r\n }\r\n\r\n return buildPattern(\r\n `starts-with(${prop},${escapeCharacters(replaceWhiteSpaces(value)).trim()})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n};\r\n\r\nexport const getContainsPropertyXPath = (\r\n element: HTMLElement | Element,\r\n prop: string,\r\n value: string\r\n): string => {\r\n if ((prop === \".\" || prop === \"text()\") && hasNumericAttributeValue(value)) {\r\n const { fragment } = getStableTargetTextCandidates(value);\r\n\r\n return fragment\r\n ? buildPattern(\r\n `contains(normalize-space(.),${escapeCharacters(fragment)})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n )\r\n : \"\";\r\n }\r\n\r\n return buildPattern(\r\n `contains(${prop},${escapeCharacters(replaceWhiteSpaces(value)).trim()})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n};\r\n\r\nexport const getOrAttributesXPath = (\r\n element: HTMLElement | Element,\r\n attributes: Attr[]\r\n): string => {\r\n const buildAttributeConditions = (attribute: Attr): string[] => {\r\n const attrValue = sanitizeAttributeValue(attribute.name, attribute.value);\r\n\r\n if (!attrValue) {\r\n return [];\r\n }\r\n\r\n if (attribute.name === \"class\") {\r\n const docmt =\r\n (element.getRootNode?.() as Document | ShadowRoot | null) ??\r\n element.ownerDocument;\r\n\r\n return getClassTokenConditions(element, attrValue, docmt);\r\n }\r\n\r\n // Strict numeric-attribute validation for direct callers.\r\n if (hasNumericAttributeValue(attrValue)) return [];\r\n\r\n if (!reWhiteSpace.test(attrValue)) {\r\n return [\r\n `normalize-space(@${attribute.name})=${escapeCharacters(attrValue)}`\r\n ];\r\n }\r\n\r\n return [`@${attribute.name}=${escapeCharacters(attrValue)}`];\r\n };\r\n\r\n const buildTextCondition = (): string | null => {\r\n const rawText = replaceWhiteSpaces(getTextContent(element)?.trim() || \"\");\r\n const stableTargetText = getStableTargetText(rawText);\r\n if (hasNumericAttributeValue(rawText)) {\r\n // OR conditions must not reintroduce full dynamic numeric target text.\r\n return stableTargetText\r\n ? `contains(normalize-space(.),${escapeCharacters(stableTargetText)})`\r\n : null;\r\n }\r\n\r\n const containerTextCondition = getContainerTextCondition(element, rawText);\r\n\r\n if (containerTextCondition) {\r\n return containerTextCondition;\r\n }\r\n\r\n if (!rawText || rawText.length > 80 || /^\\d+$/.test(rawText)) {\r\n return null;\r\n }\r\n\r\n if (reWhiteSpace.test(rawText) && rawText.length <= 40 && !rawText.includes(\" \")) {\r\n return `text()=${escapeCharacters(rawText)}`;\r\n }\r\n\r\n if (rawText.includes(\" \")) {\r\n return `normalize-space(.)=${escapeCharacters(rawText)}`;\r\n }\r\n\r\n return `contains(text(),${escapeCharacters(rawText)})`;\r\n };\r\n\r\n const attributeConditions = attributes\r\n .flatMap((attribute) => buildAttributeConditions(attribute))\r\n .filter(Boolean);\r\n\r\n if (attributeConditions.length >= 2) {\r\n return buildPattern(\r\n `${attributeConditions[0]} or ${attributeConditions[1]}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n }\r\n\r\n const textCondition = buildTextCondition();\r\n if (attributeConditions.length === 1 && textCondition) {\r\n return buildPattern(\r\n `${attributeConditions[0]} or ${textCondition}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getTagOnlyXpathCandidateCount = (\r\n xpath: string,\r\n element: HTMLElement | Element,\r\n docmt: Document | ShadowRoot\r\n) => {\r\n try {\r\n return getCountOfXPath(xpath, element, docmt);\r\n } catch (_error) {\r\n return 0;\r\n }\r\n};\r\n\r\nconst getAncestorAnchorCandidates = (\r\n node: HTMLElement | Element,\r\n docmt: Document | ShadowRoot\r\n): string[] => {\r\n const anchors: string[] = [];\r\n const seen = new Set<string>();\r\n const attributes = Array.from(node.attributes || []);\r\n const priorityAttrs = [\r\n \"id\",\r\n \"data-testid\",\r\n \"data-test\",\r\n \"data-qa\",\r\n \"name\",\r\n \"aria-label\",\r\n \"role\"\r\n ];\r\n const orderedAttributes = [\r\n ...priorityAttrs\r\n .map((attrName) => attributes.find((attr) => attr.name === attrName))\r\n .filter(Boolean),\r\n ...attributes.filter((attr) => !priorityAttrs.includes(attr.name))\r\n ] as Attr[];\r\n\r\n const pushAnchor = (xpath: string) => {\r\n if (!xpath || seen.has(xpath)) return;\r\n if (isExactUniqueXpath(xpath, node, docmt)) {\r\n seen.add(xpath);\r\n anchors.push(xpath);\r\n }\r\n };\r\n\r\n orderedAttributes.forEach((attr) => {\r\n if (!checkBlockedAttributes(attr, node, false)) return;\r\n\r\n for (const xpath of getXpathStrings(node, attr.name, attr.value)) {\r\n pushAnchor(xpath);\r\n }\r\n });\r\n\r\n const text = node.textContent?.trim();\r\n if (text && text.length < 40 && node.children.length === 0) {\r\n const textXpath = getFilteredTextXPath(node, docmt);\r\n if (textXpath) {\r\n pushAnchor(textXpath);\r\n }\r\n }\r\n\r\n if (attributes.length > 1) {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n node,\r\n docmt,\r\n attributes,\r\n false\r\n );\r\n if (combinationXpath) {\r\n pushAnchor(combinationXpath);\r\n }\r\n }\r\n\r\n return anchors;\r\n};\r\n\r\nconst getStructuralPathFromAncestor = (\r\n ancestor: HTMLElement | Element,\r\n element: HTMLElement | Element\r\n): string => {\r\n const steps: string[] = [];\r\n let current: Element | null = element;\r\n\r\n while (current && current !== ancestor) {\r\n steps.unshift(getAxisNodeTest(current));\r\n current = current.parentElement;\r\n }\r\n\r\n return current === ancestor ? steps.join(\"/\") : \"\";\r\n};\r\n\r\nexport const getTagOnlyXPath = (\r\n element: HTMLElement | Element,\r\n docmt?: Document | ShadowRoot\r\n): string => {\r\n const root =\r\n docmt ??\r\n ((element.getRootNode?.() as Document | ShadowRoot) ||\r\n element.ownerDocument);\r\n const tagName = getAxisNodeTest(element);\r\n const fallbackXpath = isSvg(element)\r\n ? `//*[local-name()='${element.tagName.toLowerCase()}']`\r\n : `//${element.tagName.toLowerCase()}`;\r\n\r\n for (\r\n let ancestor = element.parentElement;\r\n ancestor;\r\n ancestor = ancestor.parentElement\r\n ) {\r\n const ancestorAnchors = getAncestorAnchorCandidates(ancestor, root);\r\n\r\n for (const ancestorXpath of ancestorAnchors) {\r\n console.log(`Trying ancestor XPath: ${ancestorXpath}`);\r\n\r\n const descendantXpath = `${ancestorXpath}/descendant::${tagName}`;\r\n console.log(`Trying descendant XPath: ${descendantXpath}`);\r\n\r\n const count = getTagOnlyXpathCandidateCount(\r\n descendantXpath,\r\n element,\r\n root\r\n );\r\n console.log(`Match count: ${count}`);\r\n\r\n if (\r\n count === 1 &&\r\n getFirstMatchedNode(descendantXpath, root) === element\r\n ) {\r\n console.log(`Selected XPath: ${descendantXpath}`);\r\n return descendantXpath;\r\n }\r\n\r\n const structuralPath = getStructuralPathFromAncestor(ancestor, element);\r\n if (structuralPath) {\r\n const parentChainXpath = `${ancestorXpath}/${structuralPath}`;\r\n console.log(`Trying descendant XPath: ${parentChainXpath}`);\r\n\r\n const parentChainCount = getTagOnlyXpathCandidateCount(\r\n parentChainXpath,\r\n element,\r\n root\r\n );\r\n console.log(`Match count: ${parentChainCount}`);\r\n\r\n if (\r\n parentChainCount === 1 &&\r\n getFirstMatchedNode(parentChainXpath, root) === element\r\n ) {\r\n console.log(`Selected XPath: ${parentChainXpath}`);\r\n return parentChainXpath;\r\n }\r\n }\r\n }\r\n }\r\n\r\n console.log(`Trying descendant XPath: ${fallbackXpath}`);\r\n const fallbackCount = getTagOnlyXpathCandidateCount(\r\n fallbackXpath,\r\n element,\r\n root\r\n );\r\n console.log(`Match count: ${fallbackCount}`);\r\n\r\n if (\r\n fallbackCount === 1 &&\r\n getFirstMatchedNode(fallbackXpath, root) === element\r\n ) {\r\n console.log(`Selected XPath: ${fallbackXpath}`);\r\n return fallbackXpath;\r\n }\r\n\r\n console.log(\"Selected XPath: \");\r\n return \"\";\r\n};\r\n\r\nexport const getFirstMatchedNode = (\r\n xpath: string,\r\n docmt: Document | ShadowRoot\r\n): HTMLElement | Element | null => {\r\n try {\r\n if (isShadowRootNode(docmt)) {\r\n const { owner, contextNode, cloneElement } =\r\n createShadowEvaluationContext(docmt);\r\n const result = owner.evaluate(\r\n xpath,\r\n contextNode,\r\n null,\r\n XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n\r\n return (result.singleNodeValue || cloneElement) as\r\n | HTMLElement\r\n | Element\r\n | null;\r\n }\r\n\r\n const result = docmt.evaluate(\r\n xpath,\r\n docmt,\r\n null,\r\n docmt.defaultView!.XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n\r\n return result.singleNodeValue as HTMLElement | Element | null;\r\n } catch (_error) {\r\n return null;\r\n }\r\n};\r\n\r\nexport const isExactUniqueXpath = (\r\n xpath: string,\r\n element: HTMLElement | Element,\r\n docmt: Document | ShadowRoot\r\n): boolean => {\r\n try {\r\n const { first, second } = evaluateXPathOnce(xpath, docmt);\r\n\r\n return !!first && !second && first === element;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n\r\nexport const getAxisNodeTest = (element: HTMLElement | Element): string => {\r\n return isSvg(element)\r\n ? `*[local-name()='${element.tagName.toLowerCase()}']`\r\n : element.tagName.toLowerCase();\r\n};\r\n\r\nconst hasAnyNumber = (value: string) => /\\d/.test(value);\r\n\r\nexport const getUniqueNodeAnchorXpaths = (\r\n node: HTMLElement | Element,\r\n docmt: Document | ShadowRoot,\r\n isTarget: boolean\r\n): { key: string; value: string }[] => {\r\n if (!(node instanceof Element)) return [];\r\n const seen = new Set<string>();\r\n const anchors: { key: string; value: string }[] = [];\r\n\r\n const attributes = Array.from(node.attributes || []).filter(\r\n (attribute) =>\r\n attribute?.value &&\r\n !hasAnyNumber(attribute.value) &&\r\n checkBlockedAttributes(attribute, node, isTarget)\r\n );\r\n\r\n const pushAnchor = (key: string, value: string) => {\r\n if (!value || seen.has(value)) return;\r\n seen.add(value);\r\n anchors.push({ key, value });\r\n };\r\n\r\n // Priority attributes\r\n const priorityAttrs = [\r\n \"id\",\r\n \"data-testid\",\r\n \"data-test\",\r\n \"data-qa\",\r\n \"name\",\r\n \"aria-label\",\r\n \"role\"\r\n ];\r\n\r\n priorityAttrs.forEach((attrName) => {\r\n const attr = attributes.find((a) => a.name === attrName);\r\n if (!attr) return;\r\n\r\n for (const xpath of getXpathStrings(node, attr.name, attr.value)) {\r\n if (xpath && isExactUniqueXpath(xpath, node, docmt)) {\r\n pushAnchor(`anchor by ${attr.name}`, xpath);\r\n }\r\n }\r\n });\r\n\r\n // Other attributes\r\n attributes.forEach((attribute) => {\r\n if (priorityAttrs.includes(attribute.name)) return;\r\n\r\n for (const xpath of getXpathStrings(node, attribute.name, attribute.value)) {\r\n if (xpath && isExactUniqueXpath(xpath, node, docmt)) {\r\n pushAnchor(`anchor by ${attribute.name}`, xpath);\r\n }\r\n }\r\n });\r\n\r\n // Text (controlled)\r\n const text = node.textContent?.trim();\r\n if (text && text.length < 40 && node.children.length === 0) {\r\n const textXpath = getFilteredTextXPath(node, docmt);\r\n if (textXpath && isExactUniqueXpath(textXpath, node, docmt)) {\r\n pushAnchor(\"anchor by text\", textXpath);\r\n }\r\n }\r\n\r\n // Combination\r\n if (attributes.length > 1) {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n node,\r\n docmt,\r\n attributes,\r\n isTarget\r\n );\r\n\r\n if (combinationXpath && isExactUniqueXpath(combinationXpath, node, docmt)) {\r\n pushAnchor(\"anchor by combination\", combinationXpath);\r\n }\r\n }\r\n\r\n // Tag (last fallback)\r\n const tagXpath = getTagOnlyXPath(node, docmt);\r\n if (tagXpath && isExactUniqueXpath(tagXpath, node, docmt)) {\r\n pushAnchor(\"anchor by tag\", tagXpath);\r\n }\r\n\r\n return anchors;\r\n};\r\n\r\nexport const getTextXpathFunction = (\r\n domNode: HTMLElement | Element\r\n): string | undefined => {\r\n const trimmedText = getTextContent(domNode)?.trim();\r\n const stableTargetText = getStableTargetText(trimmedText);\r\n if (trimmedText && hasNumericAttributeValue(trimmedText)) {\r\n return stableTargetText\r\n ? `contains(normalize-space(.),${escapeCharacters(stableTargetText)})`\r\n : undefined;\r\n }\r\n\r\n const containerTextCondition = getContainerTextCondition(\r\n domNode,\r\n trimmedText\r\n );\r\n\r\n if (containerTextCondition) {\r\n return containerTextCondition;\r\n }\r\n\r\n const filteredText = trimmedText\r\n ? escapeCharacters(deleteGarbageFromInnerText(trimmedText))\r\n : trimmedText;\r\n if (filteredText) {\r\n if (filteredText !== `'${trimmedText}'`) {\r\n return `contains(.,${filteredText})`;\r\n }\r\n if (/\\s/.test(trimmedText)) {\r\n return `normalize-space(.)='${replaceWhiteSpaces(trimmedText)}'`;\r\n }\r\n return `normalize-space(.)='${trimmedText}'`;\r\n }\r\n};\r\n\r\nexport const getXpathString = (\r\n node: HTMLElement | Element,\r\n attrName: string,\r\n attrValue: string\r\n): string => {\r\n return getXpathStrings(node, attrName, attrValue)[0] || \"\";\r\n};\r\n\r\nexport const getXpathStrings = (\r\n node: HTMLElement | Element,\r\n attrName: string,\r\n attrValue: string\r\n): string[] => {\r\n const reWhiteSpace = new RegExp(/^[\\S]+( [\\S]+)*$/gi);\r\n let xpathe: string = \"\";\r\n attrValue = sanitizeAttributeValue(attrName, attrValue);\r\n\r\n if (attrValue) {\r\n if (attrName === \"class\") {\r\n const docmt =\r\n (node.getRootNode?.() as Document | ShadowRoot | null) ??\r\n node.ownerDocument;\r\n // Try every stable class token; numeric tokens are filtered by the\r\n // shared class helper before any XPath candidate is created.\r\n return getClassTokenConditions(node, attrValue, docmt).map((condition) =>\r\n isSvg(node)\r\n ? `//*[local-name()='${node.tagName}' and ${condition}]`\r\n : `//${node.tagName || \"*\"}[${condition}]`\r\n );\r\n }\r\n\r\n // Strict numeric-attribute validation: do not derive contains/starts-with\r\n // predicates from numeric attributes.\r\n if (hasNumericAttributeValue(attrValue)) return [];\r\n\r\n if (!reWhiteSpace.test(attrValue)) {\r\n xpathe = isSvg(node)\r\n ? `//*[local-name()='${\r\n node.tagName\r\n }' and contains(@${attrName},${escapeCharacters(attrValue)})]`\r\n : `//${node.tagName || \"*\"}[contains(@${attrName},${escapeCharacters(\r\n attrValue\r\n )})]`;\r\n } else {\r\n xpathe = isSvg(node)\r\n ? `//*[local-name()='${\r\n node.tagName\r\n }' and @${attrName}=${escapeCharacters(attrValue)}]`\r\n : `//${node.tagName || \"*\"}[@${attrName}=${escapeCharacters(\r\n attrValue\r\n )}]`;\r\n }\r\n }\r\n\r\n return xpathe ? [xpathe] : [];\r\n};\r\n\r\nexport const replaceActualAttributes = (\r\n str: string,\r\n element: { attributes: any }\r\n): string => {\r\n if (str) {\r\n return str.replace(/\\bdisabled\\b/gi, \"flndisabled\");\r\n }\r\n return str;\r\n};\r\n\r\nconst addAttributeSplitCombineXpaths = (\r\n attributes: NamedNodeMap,\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean\r\n): { key: string; value: string }[] => {\r\n const attributesArray = Array.prototype.slice.call(attributes);\r\n const xpaths: { key: string; value: string }[] = [];\r\n try {\r\n attributesArray.map((element) => {\r\n if (checkBlockedAttributes(element, targetElemt, isTarget)) {\r\n const xpth = getCombinationXpath(element, targetElemt);\r\n if (xpth) {\r\n xpaths.push({\r\n key: `split xpath by ${element.name}`,\r\n value: xpth\r\n });\r\n }\r\n }\r\n });\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n\r\n return xpaths;\r\n};\r\n\r\nconst trimAttributePart = (value: string): string =>\r\n value.replace(/^[-_:\\s.]+|[-_:\\s.]+$/g, \"\").trim();\r\n\r\nconst getStableAttributePart = (attributeValue: string): string => {\r\n const value = attributeValue.trim();\r\n const prefix = trimAttributePart(value.split(/\\d/)[0] || \"\");\r\n const prefixParts = prefix\r\n .split(/[-_:\\s.]+/)\r\n .filter(Boolean);\r\n\r\n if (prefixParts.length > 1 && prefixParts[prefixParts.length - 1].length <= 2) {\r\n prefixParts.pop();\r\n }\r\n\r\n const stablePrefix = prefixParts.join(\"-\");\r\n if (stablePrefix.length > 2 && /[a-zA-Z]/.test(stablePrefix)) {\r\n return stablePrefix;\r\n }\r\n\r\n const parts = value\r\n .split(/[\\d\\s\\-_:./\\\\]+/)\r\n .map((part) => trimAttributePart(part))\r\n .filter((part) => part.length > 2 && /[a-zA-Z]/.test(part));\r\n\r\n return parts?.sort((left, right) => right.length - left.length)[0] || \"\";\r\n};\r\n\r\nconst getNumericSafeAttributeCondition = (\r\n attributeName: string,\r\n attributeValue: string\r\n): string => {\r\n // Strict numeric-attribute validation: numeric attributes must not be\r\n // converted into \"safe\" attribute predicates.\r\n return \"\";\r\n};\r\n\r\nconst getNumericSafeAttributeXpath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n attributeName: string,\r\n attributeValue: string\r\n): string => {\r\n // Strict numeric-attribute validation: all numeric attribute XPath fallbacks\r\n // are disabled; callers should continue to text/context strategies.\r\n return \"\";\r\n};\r\n\r\nexport const getReferenceElementsXpath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean\r\n): { key: string; value: string }[] => {\r\n let nodeXpath1;\r\n const xpaths1 = [];\r\n if (\r\n domNode.textContent &&\r\n (!isTarget || (isTarget && !isNumberExist(domNode.textContent)))\r\n ) {\r\n if (!reWhiteSpace.test(domNode.textContent)) {\r\n const textCondition = getTextXpathFunction(domNode);\r\n if (textCondition) {\r\n nodeXpath1 = isSvg(domNode)\r\n ? `*[local-name()='${domNode.tagName}' and ${textCondition}]`\r\n : `${domNode.tagName}[${textCondition}]`;\r\n xpaths1.push({ key: \"getReferenceElementsXpath\", value: nodeXpath1 });\r\n }\r\n } else {\r\n const textContent = getTextContent(domNode);\r\n const containerTextCondition = getContainerTextCondition(\r\n domNode,\r\n textContent\r\n );\r\n const textCondition = containerTextCondition\r\n ? containerTextCondition\r\n : /\\s/.test(textContent.trim())\r\n ? `normalize-space(.)=${escapeCharacters(\r\n replaceWhiteSpaces(textContent)\r\n )}`\r\n : `.=${escapeCharacters(textContent)}`;\r\n nodeXpath1 = isSvg(domNode)\r\n ? `*[local-name()='${domNode.tagName}' and ${textCondition}]`\r\n : `${domNode.tagName}[${textCondition}]`;\r\n if (nodeXpath1) {\r\n xpaths1.push({ key: \"getReferenceElementsXpath\", value: nodeXpath1 });\r\n }\r\n }\r\n }\r\n\r\n if (domNode.attributes) {\r\n const attributes =\r\n domNode.tagName === \"IMG\"\r\n ? Array.from(domNode.attributes).sort((left, right) => {\r\n if (left.name === \"alt\") return -1;\r\n if (right.name === \"alt\") return 1;\r\n return 0;\r\n })\r\n : Array.from(domNode.attributes);\r\n\r\n for (const attrName of attributes) {\r\n if (checkBlockedAttributes(attrName, domNode, isTarget)) {\r\n let attrValue = attrName.nodeValue;\r\n if (attrValue) {\r\n attrValue = sanitizeAttributeValue(attrName.name, attrValue);\r\n const elementName = attrName.name;\r\n // Strict numeric-attribute validation for direct callers that bypass\r\n // checkBlockedAttributes. Class is tokenized below, so only numeric\r\n // class tokens are skipped by getClassTokenCondition.\r\n if (elementName !== \"class\" && hasNumericAttributeValue(attrValue)) {\r\n continue;\r\n }\r\n\r\n if (elementName === \"class\") {\r\n const classConditions = getClassTokenConditions(\r\n domNode,\r\n attrValue,\r\n docmt\r\n );\r\n\r\n if (!classConditions.length) {\r\n continue;\r\n }\r\n\r\n for (const classCondition of classConditions) {\r\n nodeXpath1 = isSvg(domNode)\r\n ? `*[local-name()='${domNode.tagName}' and ${classCondition}]`\r\n : `${domNode.tagName}[${classCondition}]`;\r\n\r\n xpaths1.push({\r\n key: \"getReferenceElementsXpath\",\r\n value: nodeXpath1\r\n });\r\n }\r\n\r\n continue;\r\n } else {\r\n nodeXpath1 = isSvg(domNode)\r\n ? `*[local-name()='${\r\n domNode.tagName\r\n }' and @${elementName}=${escapeCharacters(attrValue)}]`\r\n : `${domNode.tagName}[@${elementName}=${escapeCharacters(\r\n attrValue\r\n )}]`;\r\n }\r\n\r\n if (nodeXpath1) {\r\n xpaths1.push({\r\n key: \"getReferenceElementsXpath\",\r\n value: nodeXpath1\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n const attributesArray = Array.prototype.slice.call(domNode.attributes);\r\n if (attributesArray?.length > 1) {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n domNode,\r\n docmt,\r\n Array.prototype.slice.call(domNode.attributes),\r\n isTarget\r\n );\r\n if (combinationXpath) {\r\n xpaths1.push({\r\n key: \"getReferenceElementsXpath\",\r\n value: combinationXpath\r\n });\r\n }\r\n }\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n const combinePattern = [];\r\n let pattern;\r\n const tag = domNode.tagName;\r\n if (domNode.textContent && isTarget && isNumberExist(domNode.textContent)) {\r\n const targetText = replaceWhiteSpaces(getTextContent(domNode)).trim();\r\n if (targetText?.length > 1) {\r\n combinePattern.push(`contains(text(),${escapeCharacters(targetText)})`);\r\n }\r\n\r\n if (combinePattern?.length) {\r\n if (isSvg(domNode)) {\r\n pattern = `*[local-name()='${tag}' and ${combinePattern.join(\r\n \" and \"\r\n )}]`;\r\n } else {\r\n pattern = `${tag}[${combinePattern.join(\" and \")}]`;\r\n }\r\n\r\n if (pattern)\r\n xpaths1.push({ key: \"getReferenceElementsXpath\", value: pattern });\r\n }\r\n }\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n const xpaths = addAttributeSplitCombineXpaths(\r\n domNode.attributes,\r\n domNode,\r\n docmt,\r\n isTarget\r\n );\r\n if (xpaths?.length) {\r\n xpaths1.concat(xpaths);\r\n }\r\n }\r\n\r\n return xpaths1;\r\n};\r\n\r\nexport const parseXml = (\r\n xmlStr: string,\r\n type: DOMParserSupportedType\r\n): Document | null => {\r\n if (window.DOMParser) {\r\n return new window.DOMParser().parseFromString(xmlStr, type);\r\n }\r\n\r\n return null;\r\n};\r\n\r\nexport const normalizeXPath = (xpath: string): string => {\r\n // Replace text() = \"value\" or text()='value'\r\n xpath = xpath.replace(\r\n /text\\(\\)\\s*=\\s*(['\"])(.*?)\\1/g,\r\n \"normalize-space(.)=$1$2$1\"\r\n );\r\n\r\n // Replace . = \"value\" or .='value'\r\n xpath = xpath.replace(/\\.\\s*=\\s*(['\"])(.*?)\\1/g, \"normalize-space(.)=$1$2$1\");\r\n\r\n return xpath;\r\n};\r\n\r\nexport const findMatchingParenthesis = (\r\n text: string,\r\n openPos: number\r\n): number => {\r\n let closePos = openPos;\r\n let counter = 1;\r\n while (counter > 0) {\r\n const c = text[++closePos];\r\n if (c == \"(\") {\r\n counter++;\r\n } else if (c == \")\") {\r\n counter--;\r\n }\r\n }\r\n return closePos;\r\n};\r\n\r\nexport function canonicalizeXPath(xpath: string): string {\r\n return (\r\n xpath\r\n .toLowerCase()\r\n // replace quoted values\r\n .replace(/'[^']*'/g, \"?\")\r\n .replace(/\"[^\"]*\"/g, \"?\")\r\n // replace numbers in predicates\r\n .replace(/\\[\\d+\\]/g, \"[?]\")\r\n // normalize node names\r\n .replace(/\\/\\/[a-z0-9_-]+/g, \"//node\")\r\n .replace(/\\/[a-z0-9_-]+/g, \"/node\")\r\n );\r\n}\r\n\r\nexport function extractXPathSignatureParts(xpath: string) {\r\n const xp = xpath.toLowerCase();\r\n\r\n const axisMatch = xp.match(\r\n /(ancestor-or-self|ancestor|descendant-or-self|descendant|following-sibling|preceding-sibling|following|preceding|parent|child|self)::/\r\n );\r\n const axis = axisMatch?.[1] ?? \"none\";\r\n\r\n const attrMatch = xp.match(/@([a-z0-9:-]+)/);\r\n const attribute = attrMatch?.[1] ?? \"none\";\r\n\r\n const usesNormalize = xp.includes(\"normalize-space\");\r\n\r\n return { axis, attribute, usesNormalize };\r\n}\r\n\r\nexport function getXPathPattern(xpath: string): string {\r\n const canonical = canonicalizeXPath(xpath);\r\n const parts = extractXPathSignatureParts(xpath);\r\n\r\n return [\r\n \"XPATH\",\r\n `axis:${parts.axis}`,\r\n `attr:${parts.attribute}`,\r\n `normalize:${parts.usesNormalize}`,\r\n `shape:${canonical}`\r\n ].join(\"|\");\r\n}\r\n\r\nexport function escapeAttrValue(value: string): string {\r\n return value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"').replace(/ /g, \"\\\\ \");\r\n}\r\n\r\nexport function shouldUseSnapshot(xpath: string): boolean {\r\n return /\\[(?:\\s*\\.|\\s*contains\\s*\\(\\s*\\.|\\s*normalize-space\\s*\\(\\s*\\.)/.test(\r\n xpath\r\n );\r\n}\r\n\r\nexport function isUniqueInDOM(\r\n docmt: Document,\r\n name: string,\r\n value: string,\r\n element?: Element | null\r\n): boolean {\r\n const root = (element?.getRootNode?.() as ParentNode | null) ?? docmt;\r\n const queryAll = (selector: string): Element[] => {\r\n try {\r\n return Array.from(root.querySelectorAll(selector));\r\n } catch {\r\n return [];\r\n }\r\n };\r\n\r\n try {\r\n switch (name) {\r\n case \"id\":\r\n return queryAll(`#${escapeAttrValue(value)}`).length === 1;\r\n\r\n case \"name\":\r\n return queryAll(`[name=\"${escapeAttrValue(value)}\"]`).length === 1;\r\n\r\n case \"className\":\r\n return queryAll(`.${value}`).length === 1;\r\n\r\n case \"tagName\":\r\n return queryAll(value).length === 1;\r\n\r\n case \"linkText\":\r\n return (\r\n queryAll(\"a\").filter((a) => a.textContent?.trim() === value)\r\n .length === 1\r\n );\r\n case \"partialLinkText\":\r\n return (\r\n queryAll(\"a\").filter((a) => a.textContent?.includes(value)).length ===\r\n 1\r\n );\r\n case \"cssSelector\":\r\n return queryAll(value).length === 1;\r\n default:\r\n return false;\r\n }\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport const xpathUtils = {\r\n parseXml,\r\n getReferenceElementsXpath,\r\n getAbsoluteXPath,\r\n getRelativeXPath,\r\n getCombinationXpath,\r\n getAttributeCombinationXpath,\r\n getElementFromXpath,\r\n isSvg,\r\n findXpathWithIndex,\r\n isNumberExist,\r\n getTextContent,\r\n getCountOfXPath,\r\n normalizeXPath,\r\n getShadowRoot,\r\n escapeCharacters,\r\n removeParenthesis,\r\n checkBlockedAttributes,\r\n getRelationship,\r\n findMatchingParenthesis,\r\n deleteGarbageFromInnerText,\r\n replaceTempAttributes,\r\n createObserver,\r\n startObserver,\r\n stopObserver,\r\n modifiedElementAttributes,\r\n cspEnabled,\r\n getXPathPattern,\r\n getNormalizedPropertyXPath,\r\n getStartsWithPropertyXPath,\r\n getContainsPropertyXPath,\r\n getOrAttributesXPath,\r\n getTagOnlyXPath,\r\n getFirstMatchedNode,\r\n isExactUniqueXpath,\r\n getAxisNodeTest,\r\n getUniqueNodeAnchorXpaths,\r\n escapeAttrValue,\r\n isUniqueInDOM,\r\n sanitizeAttributeValue,\r\n getClassTokenCondition,\r\n getClassTokenConditions,\r\n getXpathStrings,\r\n intermediateXpathSteps,\r\n getContainerTextCondition\r\n};\r\n","import {\r\n isNumberExist,\r\n getCountOfXPath,\r\n escapeCharacters,\r\n checkBlockedAttributes,\r\n replaceWhiteSpaces,\r\n getTextContent,\r\n getPropertyXPath,\r\n findXpathWithIndex,\r\n getFilteredText,\r\n intermediateXpathStep,\r\n intermediateXpathSteps,\r\n getAttributeCombinationXpath,\r\n getFilteredTextXPath,\r\n getNormalizedPropertyXPath,\r\n getStartsWithPropertyXPath,\r\n getContainsPropertyXPath,\r\n getOrAttributesXPath,\r\n getTagOnlyXPath,\r\n isExactUniqueXpath,\r\n getAxisNodeTest,\r\n getUniqueNodeAnchorXpaths,\r\n isSvg,\r\n getXpathStrings,\r\n reWhiteSpace,\r\n sanitizeAttributeValue,\r\n getContainerTextCondition,\r\n getStableTargetText,\r\n hasNumericAttributeValue\r\n // timeLog\r\n} from \"./xpathHelpers.ts\";\r\n\r\nlet xpathData: { key: string; value: string }[] = [];\r\nlet xpathDataWithIndex: { key: string; value: string; count: number }[] = [];\r\nlet referenceElementMode: boolean = false;\r\nlet xpathCache = new Map();\r\nlet cache = new Map();\r\n\r\nconst parentXpathCache = new Map(); // Cache for parent XPaths\r\n\r\nconst STRATEGY_MAP = {\r\n andConditions: \"and\",\r\n orConditions: \"or\",\r\n contains: \"contains\",\r\n startsWith: \"startsWith\",\r\n normalizeSpace: \"normalizeSpace\",\r\n axes: \"axes\",\r\n index: \"index\",\r\n hardCodedText: \"text\",\r\n tillTag: \"tag\"\r\n} as const;\r\n\r\nconst getStrategyName = (strategy: string) => {\r\n return STRATEGY_MAP[strategy as keyof typeof STRATEGY_MAP] || strategy;\r\n};\r\n\r\nconst withStrategyKey = (\r\n strategy: string,\r\n entries: { key: string; value: string }[]\r\n) => {\r\n return entries.map((entry) => ({\r\n ...entry,\r\n key: entry?.key?.includes(strategy)\r\n ? entry.key\r\n : `${strategy} ${entry.key}`.trim()\r\n }));\r\n};\r\n\r\nconst getUniqueXpathEntries = (entries: { key: string; value: string }[]) => {\r\n const seen = new Set<string>();\r\n\r\n return entries.filter((entry) => {\r\n if (!entry?.value || seen.has(entry.value)) {\r\n return false;\r\n }\r\n\r\n seen.add(entry.value);\r\n return true;\r\n });\r\n};\r\n\r\nconst hasPositionalIndex = (xpath: string) =>\r\n /(?:^|\\/)[^/\\[]+\\[\\d+\\](?=\\/|$)/.test(xpath) ||\r\n /^\\(.+\\)\\[\\d+\\]$/.test(xpath);\r\n\r\nconst removePositionalIndexXpaths = (\r\n entries: { key: string; value: string }[],\r\n isIndex: boolean\r\n) =>\r\n isIndex ? entries : entries.filter((entry) => !hasPositionalIndex(entry.value));\r\n\r\nconst getNormalizedText = (element: HTMLElement | Element) => {\r\n return element?.textContent?.replace(/\\s+/g, \" \")?.trim() || \"\";\r\n};\r\n\r\nconst buildTextStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n strategy: string\r\n) => {\r\n const text = getNormalizedText(element);\r\n\r\n if (!text) {\r\n return [];\r\n }\r\n\r\n if (strategy === \"text\") {\r\n const textXpath =\r\n getFilteredTextXPath(element, docmt) ||\r\n getTextXPath(element, docmt, false, false);\r\n\r\n return textXpath ? [{ key: \"xpath by text\", value: textXpath }] : [];\r\n }\r\n\r\n return [];\r\n};\r\n\r\nconst buildPropertyStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n isTarget: boolean,\r\n strategy: string\r\n) => {\r\n const xpaths: { key: string; value: string }[] = [];\r\n const attributes = Array.from(element.attributes || []).filter(\r\n (attribute) =>\r\n attribute?.value && checkBlockedAttributes(attribute, element, isTarget)\r\n );\r\n const text = getNormalizedText(element);\r\n const getStrategyXPath =\r\n strategy === \"contains\"\r\n ? getContainsPropertyXPath\r\n : strategy === \"startsWith\"\r\n ? getStartsWithPropertyXPath\r\n : strategy === \"normalizeSpace\"\r\n ? getNormalizedPropertyXPath\r\n : null;\r\n\r\n if (!getStrategyXPath) {\r\n return xpaths;\r\n }\r\n\r\n attributes.forEach((attribute) => {\r\n const xpath = getStrategyXPath(\r\n element,\r\n `@${attribute.name}`,\r\n attribute.value\r\n );\r\n\r\n if (xpath) {\r\n xpaths.push({\r\n key: `xpath by ${strategy} ${attribute.name}`,\r\n value: xpath\r\n });\r\n }\r\n });\r\n\r\n if (text) {\r\n const xpath = getStrategyXPath(element, \".\", text);\r\n\r\n if (xpath) {\r\n xpaths.push({\r\n key: `xpath by ${strategy} text`,\r\n value: xpath\r\n });\r\n }\r\n }\r\n\r\n return xpaths;\r\n};\r\n\r\nconst buildConditionStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n strategy: string\r\n) => {\r\n const attributes = Array.from(element.attributes || []).filter(\r\n (attribute) =>\r\n attribute?.value && checkBlockedAttributes(attribute, element, isTarget)\r\n );\r\n\r\n if (strategy === \"and\") {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n element,\r\n docmt,\r\n attributes,\r\n isTarget\r\n );\r\n\r\n return combinationXpath\r\n ? [{ key: \"xpath by combination\", value: combinationXpath }]\r\n : [];\r\n }\r\n\r\n if (strategy === \"or\" && attributes.length >= 1) {\r\n const xpath = getOrAttributesXPath(element, attributes);\r\n return xpath ? [{ key: \"xpath by or\", value: xpath }] : [];\r\n }\r\n\r\n return [];\r\n};\r\n\r\nconst collectSubtreeElements = (root: HTMLElement | Element) => {\r\n if (!root || !(root instanceof Element)) return [];\r\n\r\n const nodes: (HTMLElement | Element)[] = [];\r\n const queue = Array.from(root.children || []);\r\n\r\n while (queue.length) {\r\n const currentNode = queue.shift()!;\r\n\r\n if (currentNode.classList?.contains(\"flntooltip\")) {\r\n continue;\r\n }\r\n\r\n nodes.push(currentNode);\r\n queue.push(...Array.from(currentNode.children || []));\r\n }\r\n\r\n return nodes;\r\n};\r\n\r\nconst getSiblingNodes = (\r\n element: HTMLElement | Element,\r\n direction: \"previous\" | \"next\"\r\n) => {\r\n const nodes: (HTMLElement | Element)[] = [];\r\n let currentNode =\r\n direction === \"previous\"\r\n ? element.previousElementSibling\r\n : element.nextElementSibling;\r\n\r\n while (currentNode) {\r\n if (!currentNode.classList?.contains(\"flntooltip\")) {\r\n nodes.push(currentNode);\r\n }\r\n\r\n currentNode =\r\n direction === \"previous\"\r\n ? currentNode.previousElementSibling\r\n : currentNode.nextElementSibling;\r\n }\r\n\r\n return nodes;\r\n};\r\n\r\ntype AxisSeedNode =\r\n | Element\r\n | {\r\n node: Element;\r\n expand: () => Element[];\r\n };\r\n\r\nconst getDirectionalAxisSeedNodes = (\r\n element: HTMLElement | Element,\r\n direction: \"previous\" | \"next\"\r\n): AxisSeedNode[] => {\r\n const nodes: AxisSeedNode[] = [];\r\n\r\n for (\r\n let currentNode: HTMLElement | Element | null = element;\r\n currentNode?.parentElement;\r\n currentNode = currentNode.parentElement\r\n ) {\r\n let sibling =\r\n direction === \"previous\"\r\n ? currentNode.previousElementSibling\r\n : currentNode.nextElementSibling;\r\n\r\n while (sibling) {\r\n if (!sibling.classList?.contains(\"flntooltip\")) {\r\n nodes.push(sibling);\r\n\r\n nodes.push({\r\n node: sibling,\r\n expand: () => collectSubtreeElements(sibling as HTMLElement)\r\n });\r\n }\r\n\r\n sibling =\r\n direction === \"previous\"\r\n ? sibling.previousElementSibling\r\n : sibling.nextElementSibling;\r\n }\r\n }\r\n\r\n return nodes;\r\n};\r\n\r\nconst isLowQualityNode = (node: Element) => {\r\n if (!(node instanceof Element)) return true;\r\n const text = node.textContent?.trim();\r\n\r\n return (\r\n !node.id &&\r\n !node.className &&\r\n node.attributes.length === 0 &&\r\n (!text || text.length > 60) &&\r\n node.children.length > 2\r\n );\r\n};\r\n\r\nconst buildAxisXpathsForNodes = (\r\n nodes: any[],\r\n axis: string,\r\n targetElement: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n key: string,\r\n isIndex: boolean\r\n) => {\r\n const targetNodeTest = getAxisNodeTest(targetElement);\r\n const MAX_INDEX_TRY = 3;\r\n const MAX_CANDIDATES = 5;\r\n\r\n const candidates: { key: string; value: string }[] = [];\r\n\r\n let processed = 0;\r\n const MAX_PROCESS = axis.includes(\"descendant\") ? 10 : 20;\r\n\r\n for (const nodeItem of nodes) {\r\n if (processed++ > MAX_PROCESS) break;\r\n if (candidates.length >= MAX_CANDIDATES) break;\r\n\r\n const node = \"node\" in nodeItem ? nodeItem.node : nodeItem;\r\n\r\n if (!(node instanceof Element)) continue;\r\n if (isLowQualityNode(node)) continue;\r\n\r\n const anchorStages = [\r\n () => getUniqueNodeAnchorXpaths(node, docmt, isTarget),\r\n () => {\r\n const anchors: any[] = [];\r\n const attributes = Array.from(node.attributes || []).filter(\r\n (attr) =>\r\n attr?.value &&\r\n !/\\d/.test(attr.value) &&\r\n checkBlockedAttributes(attr, node, isTarget)\r\n );\r\n\r\n for (const attr of attributes) {\r\n const value = attr.value;\r\n if (!value) continue;\r\n\r\n const containsXpath = getContainsPropertyXPath(\r\n node,\r\n `@${attr.name}`,\r\n value\r\n );\r\n if (containsXpath) {\r\n anchors.push({ key: \"contains\", value: containsXpath });\r\n }\r\n\r\n const startsWithXpath = getStartsWithPropertyXPath(\r\n node,\r\n `@${attr.name}`,\r\n value\r\n );\r\n if (startsWithXpath) {\r\n anchors.push({ key: \"starts-with\", value: startsWithXpath });\r\n }\r\n }\r\n\r\n return anchors;\r\n },\r\n () => [{ key: \"tag\", value: getTagOnlyXPath(node, docmt) }]\r\n ];\r\n\r\n for (let stageIndex = 0; stageIndex < anchorStages.length; stageIndex++) {\r\n let anchors = anchorStages[stageIndex]();\r\n if (!anchors.length) continue;\r\n\r\n if (!isIndex) {\r\n anchors = anchors.filter((a) => !/\\[\\d+\\]/.test(a.value));\r\n }\r\n\r\n const seen = new Set<string>();\r\n anchors = anchors.filter((a) => {\r\n if (seen.has(a.value)) return false;\r\n seen.add(a.value);\r\n return true;\r\n });\r\n\r\n anchors = anchors.slice(0, 5);\r\n\r\n for (const anchor of anchors) {\r\n const xpath = `${anchor.value}/${axis}::${targetNodeTest}`;\r\n\r\n if (isExactUniqueXpath(xpath, targetElement, docmt)) {\r\n candidates.push({ key, value: xpath });\r\n\r\n if (candidates.length >= 2) {\r\n return candidates;\r\n }\r\n\r\n if (candidates.length >= MAX_CANDIDATES) {\r\n return candidates;\r\n }\r\n }\r\n }\r\n\r\n if (isIndex && stageIndex === anchorStages.length - 1) {\r\n for (const anchor of anchors) {\r\n const count = getCountOfXPath(anchor.value, node, docmt);\r\n\r\n for (let i = 1; i <= Math.min(count, MAX_INDEX_TRY); i++) {\r\n const xpath = `(${anchor.value})[${i}]/${axis}::${targetNodeTest}`;\r\n\r\n if (isExactUniqueXpath(xpath, targetElement, docmt)) {\r\n candidates.push({ key, value: xpath });\r\n\r\n if (candidates.length >= 2) {\r\n return candidates;\r\n }\r\n\r\n if (candidates.length >= MAX_CANDIDATES) {\r\n return candidates;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (\"expand\" in nodeItem && nodeItem.expand) {\r\n const expanded = nodeItem.expand();\r\n\r\n let childCount = 0;\r\n for (const child of expanded) {\r\n if (childCount++ > 15) break;\r\n if (candidates.length >= MAX_CANDIDATES) break;\r\n\r\n if (!(child instanceof Element)) continue;\r\n if (isLowQualityNode(child)) continue;\r\n\r\n const anchors = getUniqueNodeAnchorXpaths(child, docmt, isTarget);\r\n\r\n for (const anchor of anchors.slice(0, 5)) {\r\n const xpath = `${anchor.value}/${axis}::${targetNodeTest}`;\r\n\r\n if (isExactUniqueXpath(xpath, targetElement, docmt)) {\r\n candidates.push({ key, value: xpath });\r\n\r\n if (candidates.length >= 2) {\r\n return candidates;\r\n }\r\n\r\n if (candidates.length >= MAX_CANDIDATES) {\r\n return candidates;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return candidates;\r\n};\r\n\r\nconst buildAxesStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n isIndex: boolean\r\n) => {\r\n // const totalStart = performance.now();\r\n\r\n // let t = performance.now();\r\n\r\n const ancestors: (HTMLElement | Element)[] = [];\r\n\r\n for (\r\n let currentNode = element.parentElement;\r\n currentNode;\r\n currentNode = currentNode.parentElement\r\n ) {\r\n ancestors.push(currentNode);\r\n }\r\n // timeLog(\"ancestors collection\", t);\r\n // t = performance.now();\r\n const descendants = collectSubtreeElements(element);\r\n // timeLog(\"descendants collection\", t);\r\n // t = performance.now();\r\n const previousSiblings = getSiblingNodes(element, \"previous\");\r\n // timeLog(\"previous siblings collection\", t);\r\n\r\n const nextSiblings = getSiblingNodes(element, \"next\");\r\n // timeLog(\"next siblings collection\", t);\r\n\r\n const precedingSeeds = getDirectionalAxisSeedNodes(element, \"previous\");\r\n // timeLog(\"preceding seeds collection\", t);\r\n // t = performance.now();\r\n const followingSeeds = getDirectionalAxisSeedNodes(element, \"next\");\r\n // timeLog(\"following seeds collection\", t);\r\n // t = performance.now();\r\n const scoreNode = (node: Element) => {\r\n let score = 0;\r\n if (node.id) score += 100;\r\n if (node.getAttribute(\"data-testid\")) score += 90;\r\n if (node.className) score += 50;\r\n if (node.children.length === 0) score += 30;\r\n\r\n const text = node.textContent?.trim();\r\n if (text && text.length < 40) score += 40;\r\n\r\n return score;\r\n };\r\n\r\n const limitNodes = (nodes: any[], limit = 20) => {\r\n return nodes.length > limit ? nodes.slice(0, limit) : nodes;\r\n };\r\n\r\n const tiers = [\r\n [\r\n {\r\n nodes: limitNodes(nextSiblings),\r\n axis: \"preceding-sibling\",\r\n key: \"preceding-sibling\"\r\n },\r\n {\r\n nodes: limitNodes(previousSiblings),\r\n axis: \"following-sibling\",\r\n key: \"following-sibling\"\r\n }\r\n ],\r\n [\r\n { nodes: limitNodes(ancestors), axis: \"child\", key: \"child\" },\r\n {\r\n nodes: limitNodes(descendants, 15),\r\n axis: \"parent\",\r\n key: \"parent\"\r\n }\r\n ],\r\n [\r\n { nodes: limitNodes(ancestors), axis: \"descendant\", key: \"descendant\" },\r\n {\r\n nodes: limitNodes(ancestors),\r\n axis: \"descendant-or-self\",\r\n key: \"descendant-or-self\"\r\n },\r\n {\r\n nodes: limitNodes(descendants, 10),\r\n axis: \"ancestor\",\r\n key: \"ancestor\"\r\n },\r\n {\r\n nodes: limitNodes(descendants, 10),\r\n axis: \"ancestor-or-self\",\r\n key: \"ancestor-or-self\"\r\n }\r\n ],\r\n [\r\n {\r\n nodes: limitNodes(precedingSeeds),\r\n axis: \"following\",\r\n key: \"following\"\r\n },\r\n { nodes: limitNodes(followingSeeds), axis: \"preceding\", key: \"preceding\" }\r\n ]\r\n ];\r\n // timeLog(\"nodes sorting\", t);\r\n for (const tier of tiers) {\r\n for (const strategy of tier) {\r\n // const t = performance.now();\r\n\r\n const results = buildAxisXpathsForNodes(\r\n strategy.nodes,\r\n strategy.axis,\r\n element,\r\n docmt,\r\n isTarget,\r\n strategy.key,\r\n isIndex\r\n );\r\n\r\n // timeLog(`strategy ${strategy.key}`, t);\r\n if (results.length > 0) {\r\n // timeLog(\"TOTAL buildAxesStrategyXpaths\", totalStart);\r\n return results;\r\n }\r\n }\r\n }\r\n\r\n return [];\r\n};\r\n\r\nexport const generateIndexedXpaths = (element: Element, docmt: Document) => {\r\n const results = [];\r\n const tag = element.tagName.toLowerCase();\r\n\r\n const globalList = Array.from(docmt.querySelectorAll(tag));\r\n const idx = globalList.indexOf(element) + 1;\r\n\r\n if (idx <= 0) return [];\r\n\r\n // global must always exist)\r\n results.push({\r\n key: \"xpath by index\",\r\n value: `(//${tag})[${idx}]`\r\n });\r\n\r\n // Add at most one scoped/indexed XPath anchored by the nearest stable ancestor.\r\n let current: Element | null = element.parentElement;\r\n\r\n while (current && current !== docmt.body) {\r\n if (current.id || current.className) {\r\n const scopeXpaths = current.id\r\n ? getXpathStrings(current, \"id\", current.id)\r\n : getXpathStrings(current, \"class\", current.className.toString());\r\n\r\n // Scoped index anchors should also try every stable class token before\r\n // walking to a higher ancestor.\r\n for (const scopeXpath of scopeXpaths) {\r\n const scopedDescendants = Array.from(current.querySelectorAll(tag));\r\n const scopedIdx = scopedDescendants.indexOf(element) + 1;\r\n\r\n if (scopedIdx > 0) {\r\n results.push({\r\n key: \"xpath by index\",\r\n value: `(${scopeXpath}//${tag})[${scopedIdx}]`\r\n });\r\n break;\r\n }\r\n }\r\n\r\n if (results.length > 1) {\r\n break;\r\n }\r\n }\r\n\r\n current = current.parentElement;\r\n }\r\n\r\n return results;\r\n};\r\n\r\nconst buildStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n strategy: string,\r\n fallbackXpaths: { key: string; value: string }[]\r\n) => {\r\n const strategyName = getStrategyName(strategy);\r\n\r\n if (strategyName === \"text\") {\r\n return withStrategyKey(\r\n strategy,\r\n buildTextStrategyXpaths(element, docmt, strategyName)\r\n );\r\n }\r\n\r\n if ([\"contains\", \"startsWith\", \"normalizeSpace\"].includes(strategyName)) {\r\n return withStrategyKey(\r\n strategy,\r\n buildPropertyStrategyXpaths(element, isTarget, strategyName)\r\n );\r\n }\r\n\r\n if ([\"and\", \"or\"].includes(strategyName)) {\r\n return withStrategyKey(\r\n strategy,\r\n buildConditionStrategyXpaths(element, docmt, isTarget, strategyName)\r\n );\r\n }\r\n\r\n if (strategyName === \"axes\") {\r\n return withStrategyKey(\r\n strategy,\r\n buildAxesStrategyXpaths(element, docmt, isTarget, false)\r\n );\r\n }\r\n\r\n if (strategyName === \"index\") {\r\n return withStrategyKey(strategy, generateIndexedXpaths(element, docmt));\r\n }\r\n\r\n if (strategyName === \"tag\") {\r\n return withStrategyKey(strategy, [\r\n { key: \"xpath till tag\", value: getTagOnlyXPath(element, docmt) }\r\n ]);\r\n }\r\n\r\n return [];\r\n};\r\n\r\nconst checkRelativeXpathRelation = (\r\n nodeXpath1: string,\r\n nodeXpath2: string,\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n relationType: string\r\n) => {\r\n if (nodeXpath1 && !referenceElementMode) {\r\n let xpaths;\r\n\r\n if (relationType === \"parent\") {\r\n xpaths = [\r\n // `${nodeXpath1}/descendant::${nodeXpath2}`,\r\n `${nodeXpath1}/descendant-or-self::${nodeXpath2}`,\r\n `${nodeXpath1}/following::${nodeXpath2}`\r\n ];\r\n } else {\r\n xpaths = [\r\n // `${nodeXpath1}/descendant::${nodeXpath2}`,\r\n `${nodeXpath1}/ancestor-or-self::${nodeXpath2}`,\r\n `${nodeXpath1}/preceding::${nodeXpath2}`\r\n ];\r\n }\r\n\r\n // Iterate through XPath patterns\r\n for (const xpath of xpaths) {\r\n // Check if result is already cached to avoid recomputation\r\n if (!xpathCache?.get(xpath)) {\r\n // Compute and store result in cache\r\n xpathCache.set(xpath, getCountOfXPath(xpath, targetElemt, docmt));\r\n }\r\n\r\n const count = xpathCache?.get(xpath);\r\n\r\n // Short-circuit: Return the first valid XPath result found\r\n if (count === 1) {\r\n return xpath;\r\n }\r\n if (count > 1) {\r\n if (xpathDataWithIndex.length) {\r\n if (count < xpathDataWithIndex[0].count) {\r\n xpathDataWithIndex.pop();\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by unique parent ${isIndex ? \"index\" : \"\"}`,\r\n value: xpath,\r\n count\r\n });\r\n }\r\n } else {\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by unique parent ${isIndex ? \"index\" : \"\"}`,\r\n value: xpath,\r\n count\r\n });\r\n }\r\n }\r\n\r\n if (count > 1 && isIndex && !xpathData.length) {\r\n // Try finding XPath with index if count is greater than 1\r\n const indexedXpath = findXpathWithIndex(\r\n xpath,\r\n targetElemt,\r\n docmt,\r\n count\r\n );\r\n\r\n // Cache the indexed XPath result\r\n if (\r\n indexedXpath &&\r\n getCountOfXPath(indexedXpath, targetElemt, docmt) === 1\r\n ) {\r\n xpathData.push({\r\n key: `relative xpath by unique parent ${isIndex ? \"index\" : \"\"}`,\r\n value: indexedXpath\r\n });\r\n }\r\n }\r\n }\r\n }\r\n return null;\r\n};\r\n\r\nconst getUniqueParentXpath = (\r\n domNode: HTMLElement,\r\n docmt: Document,\r\n node: HTMLElement | Element,\r\n isTarget: boolean,\r\n nodeXpath: string,\r\n isIndex: boolean\r\n) => {\r\n try {\r\n if (parentXpathCache.has(domNode)) {\r\n return parentXpathCache.get(domNode);\r\n }\r\n\r\n // Direct XPath construction without loops\r\n const xpathParts = [];\r\n let currentNode = domNode;\r\n\r\n while (currentNode && currentNode.nodeType === 1) {\r\n const hasUniqueAttr = false;\r\n for (const attrName of Array.from(currentNode.attributes)) {\r\n if (checkBlockedAttributes(attrName, currentNode, isTarget)) {\r\n const attrValue = sanitizeAttributeValue(\r\n attrName.name,\r\n attrName.nodeValue\r\n );\r\n const elementName = attrName.name;\r\n\r\n for (const xpathe of getXpathStrings(currentNode, elementName, attrValue)) {\r\n let othersWithAttr;\r\n\r\n // If the XPath does not parse, move to the next unique attribute\r\n try {\r\n othersWithAttr = checkRelativeXpathRelation(\r\n xpathe,\r\n nodeXpath,\r\n node,\r\n docmt,\r\n isIndex,\r\n \"parent\"\r\n );\r\n } catch (ign) {\r\n continue;\r\n }\r\n\r\n // If the attribute isn't actually unique, get it's index too\r\n if (othersWithAttr) {\r\n return othersWithAttr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (currentNode.textContent && !currentNode.textContent) {\r\n if (\r\n !isTarget ||\r\n (isTarget && !isNumberExist(currentNode.textContent))\r\n ) {\r\n let xpathe;\r\n\r\n if (!reWhiteSpace.test(currentNode.textContent)) {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and normalize-space(.)=${escapeCharacters(\r\n getFilteredText(currentNode)\r\n )}]`\r\n : `//${\r\n currentNode.tagName || \"*\"\r\n }[normalize-space(.)=${escapeCharacters(\r\n getFilteredText(currentNode)\r\n )}]`;\r\n } else {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and .=${escapeCharacters(getFilteredText(currentNode))}]`\r\n : `//${currentNode.tagName || \"*\"}[.=${escapeCharacters(\r\n getFilteredText(currentNode)\r\n )}]`;\r\n }\r\n\r\n const othersWithAttr = checkRelativeXpathRelation(\r\n xpathe,\r\n nodeXpath,\r\n node,\r\n docmt,\r\n isIndex,\r\n \"parent\"\r\n );\r\n if (othersWithAttr) {\r\n return othersWithAttr;\r\n }\r\n } else {\r\n const combinePattern = [];\r\n const contentRes = [\r\n ...new Set(getFilteredText(currentNode).match(/([^0-9]+)/g))\r\n ];\r\n const reWhiteSpace = new RegExp(/^[\\S]+( [\\S]+)*$/gi);\r\n if (contentRes?.length) {\r\n for (let i = 0; i < contentRes?.length; i++) {\r\n if (contentRes[i] && replaceWhiteSpaces(contentRes[i].trim())) {\r\n if (!reWhiteSpace.test(contentRes[i])) {\r\n combinePattern.push(\r\n `contains(.,${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[i])\r\n ).trim()})`\r\n );\r\n } else {\r\n combinePattern.push(\r\n `contains(.,${escapeCharacters(\r\n contentRes[i].trim()\r\n ).trim()})`\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n const xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and ${combinePattern.join(\" and \")}]`\r\n : `//${currentNode.tagName || \"*\"}[${combinePattern.join(\r\n \" and \"\r\n )}]`;\r\n const othersWithAttr = checkRelativeXpathRelation(\r\n xpathe,\r\n nodeXpath,\r\n node,\r\n docmt,\r\n isIndex,\r\n \"parent\"\r\n );\r\n if (othersWithAttr) {\r\n return othersWithAttr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Construct the XPath based on the tag name\r\n if (!hasUniqueAttr) {\r\n const xpathe = isSvg(currentNode)\r\n ? `/*[local-name()='${currentNode.tagName}']`\r\n : `/${currentNode.tagName}`;\r\n\r\n xpathParts.unshift(xpathe);\r\n } else {\r\n break;\r\n }\r\n\r\n // Move to the parent node for the next iteration\r\n currentNode = currentNode.parentElement!;\r\n }\r\n\r\n // Final constructed XPath\r\n const finalXPath = xpathParts.join(\"\") + nodeXpath;\r\n let count = getCountOfXPath(finalXPath, domNode, docmt);\r\n if (count === 1) {\r\n parentXpathCache.set(domNode, finalXPath); // Cache final result\r\n return finalXPath;\r\n }\r\n } catch (error) {\r\n console.error(error);\r\n return null;\r\n }\r\n};\r\n\r\nconst getParentRelativeXpath = (\r\n domNode: HTMLElement,\r\n docmt: Document,\r\n node: HTMLElement | Element,\r\n isTarget: boolean\r\n) => {\r\n const cache = new Map(); // Cache to store computed results\r\n\r\n if (cache.has(domNode)) {\r\n return cache.get(domNode); // Return cached result if available\r\n }\r\n\r\n const xpathParts = []; // Initialize an array to hold parts of the XPath\r\n let currentNode = domNode; // Start with the provided DOM node\r\n\r\n try {\r\n while (currentNode && currentNode.nodeType === 1) {\r\n // BASE CASE #1: If this isn't an element, we're above the root, return empty string\r\n if (!currentNode.tagName) {\r\n return \"\";\r\n }\r\n\r\n // BASE CASE #2: Check for unique attributes\r\n let uniqueAttrFound = false;\r\n for (const attr of Array.from(currentNode.attributes)) {\r\n if (checkBlockedAttributes(attr, currentNode, isTarget)) {\r\n const attrValue = sanitizeAttributeValue(attr.name, attr.nodeValue);\r\n const elementName = attr.name;\r\n\r\n for (const xpathe of getXpathStrings(currentNode, elementName, attrValue)) {\r\n let othersWithAttr;\r\n\r\n // If the XPath does not parse, move to the next unique attribute\r\n try {\r\n othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n } catch (ign) {\r\n continue;\r\n }\r\n\r\n // If the attribute is unique, return its XPath\r\n if (othersWithAttr === 1) {\r\n xpathParts.unshift(xpathe);\r\n uniqueAttrFound = true; // Mark that we found at least one unique attribute\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (uniqueAttrFound) break;\r\n }\r\n\r\n // If no unique attributes, check for text content\r\n if (!uniqueAttrFound && currentNode.textContent && !node.textContent) {\r\n const textXPath = getFilteredTextXPath(currentNode, docmt);\r\n if (textXPath) {\r\n const othersWithAttr = getCountOfXPath(textXPath, currentNode, docmt);\r\n if (othersWithAttr === 1) {\r\n uniqueAttrFound = true; // Mark that we found at least one unique attribute\r\n xpathParts.unshift(textXPath);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!uniqueAttrFound) {\r\n // Construct the XPath based on the tag name\r\n const xpathe = isSvg(currentNode)\r\n ? `/*[local-name()='${currentNode.tagName}']`\r\n : `/${currentNode.tagName}`;\r\n\r\n // Prepend the current XPath part to the array\r\n xpathParts.unshift(xpathe);\r\n } else {\r\n break;\r\n }\r\n // Move to the parent node for the next iteration\r\n currentNode = currentNode.parentElement!;\r\n }\r\n\r\n // Combine all parts into the final XPath\r\n const finalXpath = xpathParts.join(\"\");\r\n cache.set(domNode, finalXpath); // Store result in cache\r\n return finalXpath;\r\n } catch (error) {\r\n console.log(error);\r\n return null;\r\n }\r\n};\r\n\r\nconst getChildRelativeXpath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n node: HTMLElement | Element\r\n) => {\r\n const xpathParts = []; // Initialize an array to hold parts of the XPath.\r\n let currentNode: HTMLElement | Element | null;\r\n\r\n const st = [];\r\n if (\r\n domNode.firstElementChild != null &&\r\n domNode.firstElementChild.classList.contains(\"flntooltip\")\r\n ) {\r\n st.unshift(domNode.firstElementChild);\r\n } else if (domNode.nextElementSibling != null)\r\n st.unshift(domNode.nextElementSibling);\r\n\r\n for (\r\n let m = domNode.parentElement;\r\n m != null && m.nodeType === 1;\r\n m = m.parentElement\r\n ) {\r\n if (m.nextElementSibling) st.unshift(m.nextElementSibling);\r\n }\r\n\r\n try {\r\n do {\r\n let uniqueAttrFound = false;\r\n for (currentNode = st.pop()!; currentNode !== null; ) {\r\n for (const attr of Array.from(currentNode.attributes)) {\r\n if (checkBlockedAttributes(attr, currentNode, true)) {\r\n const attrValue = sanitizeAttributeValue(attr.name, attr.nodeValue);\r\n const elementName = attr.name;\r\n\r\n for (const xpathe of getXpathStrings(currentNode, elementName, attrValue)) {\r\n let othersWithAttr;\r\n\r\n // If the XPath does not parse, move to the next unique attribute\r\n try {\r\n othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n } catch (ign) {\r\n continue;\r\n }\r\n\r\n // If the attribute is unique, return its XPath\r\n if (othersWithAttr === 1) {\r\n uniqueAttrFound = true; // Mark that we found at least one unique attribute\r\n xpathParts.push(xpathe);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (uniqueAttrFound) break;\r\n }\r\n\r\n // If no unique attributes, check for text content\r\n if (!uniqueAttrFound && currentNode.textContent && !node.textContent) {\r\n const textXPath = getFilteredTextXPath(currentNode, docmt);\r\n if (textXPath) {\r\n const othersWithAttr = getCountOfXPath(\r\n textXPath,\r\n currentNode,\r\n docmt\r\n );\r\n if (othersWithAttr === 1) {\r\n uniqueAttrFound = true; // Mark that we found at least one unique attribute\r\n xpathParts.push(textXPath);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!uniqueAttrFound) {\r\n // Construct the XPath based on the tag name\r\n const xpathe = isSvg(currentNode)\r\n ? `/*[local-name()='${currentNode.tagName}']`\r\n : `/${currentNode.tagName}`;\r\n\r\n // Prepend the current XPath part to the array\r\n xpathParts.push(xpathe);\r\n\r\n if (currentNode.firstElementChild != null) {\r\n st.push(currentNode.nextElementSibling);\r\n currentNode = currentNode.firstElementChild;\r\n } else {\r\n currentNode = currentNode.nextElementSibling;\r\n }\r\n } else {\r\n break;\r\n }\r\n }\r\n } while (st.length > 0);\r\n\r\n // Combine all parts into the final XPath\r\n const finalXpath = xpathParts.join(\"\");\r\n cache.set(domNode, finalXpath); // Store result in cache\r\n return finalXpath;\r\n } catch (error) {\r\n console.log(error);\r\n return null;\r\n }\r\n};\r\n\r\nconst getSiblingRelativeXPath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n nodeXpath: string\r\n) => {\r\n try {\r\n const markedSpan = document.querySelector(\".flntooltip\");\r\n\r\n for (\r\n let m = domNode.nextElementSibling;\r\n m !== null && m !== markedSpan;\r\n m = m.nextElementSibling\r\n ) {\r\n processSibling(\r\n m,\r\n domNode,\r\n docmt,\r\n nodeXpath,\r\n \"preceding-sibling\",\r\n isTarget\r\n );\r\n }\r\n\r\n for (\r\n let n = domNode.previousElementSibling;\r\n n !== null && n !== markedSpan;\r\n n = n.previousElementSibling\r\n ) {\r\n processSibling(\r\n n,\r\n domNode,\r\n docmt,\r\n nodeXpath,\r\n \"following-sibling\",\r\n isTarget\r\n );\r\n }\r\n } catch (error) {\r\n console.error(\"sibling error\", error);\r\n return null;\r\n }\r\n};\r\n\r\nconst processSibling = (\r\n sibling: Element,\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n nodeXpath: string,\r\n axis: string,\r\n isTarget: boolean\r\n) => {\r\n try {\r\n if (sibling.hasAttributes()) {\r\n for (const attr of Array.from(sibling.attributes)) {\r\n const xpaths = intermediateXpathSteps(\r\n sibling,\r\n {\r\n name: attr.name,\r\n value: attr.value\r\n },\r\n isTarget\r\n );\r\n\r\n for (let xpathe of xpaths) {\r\n xpathe += `/${axis}::${nodeXpath}`;\r\n\r\n const count = getCountOfXPath(xpathe, sibling, docmt);\r\n\r\n if (count === 1) {\r\n xpathData.push({\r\n key: `xpath by ${axis}`,\r\n value: xpathe\r\n });\r\n return;\r\n } else if (count > 1) {\r\n if (xpathDataWithIndex.length) {\r\n if (count < xpathDataWithIndex[0].count) {\r\n xpathDataWithIndex.pop();\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by ${axis}`,\r\n value: xpathe,\r\n count\r\n });\r\n }\r\n } else {\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by ${axis}`,\r\n value: xpathe,\r\n count\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (!isTarget) {\r\n let xpathe;\r\n xpathe = intermediateXpathStep(\r\n sibling,\r\n {\r\n name: \"text\",\r\n value: sibling.textContent\r\n },\r\n isTarget\r\n );\r\n\r\n if (xpathe) {\r\n const count = getCountOfXPath(xpathe, sibling, docmt);\r\n\r\n if (count === 1) {\r\n xpathData.push({\r\n key: `xpath by ${axis}`,\r\n value: xpathe\r\n });\r\n return;\r\n } else if (count > 1) {\r\n if (xpathDataWithIndex.length) {\r\n if (count < xpathDataWithIndex[0].count) {\r\n xpathDataWithIndex.pop();\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by ${axis}`,\r\n value: xpathe,\r\n count\r\n });\r\n }\r\n } else {\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by ${axis}`,\r\n value: xpathe,\r\n count\r\n });\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.log(`${axis} xpath-error`, error);\r\n }\r\n};\r\n\r\nfunction getXPathUsingAttributeAndText(\r\n attributes: Attr[],\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean\r\n) {\r\n const { tagName } = targetElemt;\r\n const textContent = targetElemt.textContent.trim();\r\n if (!textContent) {\r\n return;\r\n }\r\n const normalizedTextContent = replaceWhiteSpaces(textContent);\r\n const stableTargetText = getStableTargetText(normalizedTextContent);\r\n if (hasNumericAttributeValue(normalizedTextContent) && !stableTargetText) {\r\n return;\r\n }\r\n\r\n const textForPredicate = hasNumericAttributeValue(normalizedTextContent)\r\n ? stableTargetText\r\n : normalizedTextContent;\r\n const containerTextCondition = getContainerTextCondition(\r\n targetElemt,\r\n textForPredicate\r\n );\r\n for (const attrName of attributes) {\r\n if (checkBlockedAttributes(attrName, targetElemt, isTarget)) {\r\n let attrValue = sanitizeAttributeValue(attrName.name, attrName.nodeValue);\r\n const elementName = attrName.name;\r\n const textCondition = containerTextCondition\r\n ? containerTextCondition\r\n : hasNumericAttributeValue(normalizedTextContent)\r\n ? `contains(normalize-space(.),${escapeCharacters(textForPredicate)})`\r\n : /\\s/.test(textContent)\r\n ? `normalize-space(.)=${escapeCharacters(textForPredicate)}`\r\n : `text()=${escapeCharacters(textForPredicate)}`;\r\n const xpath = `//${tagName}[@${elementName}='${attrValue}' and ${textCondition}]`;\r\n if (xpath) {\r\n const count = getCountOfXPath(xpath, targetElemt, docmt);\r\n if (count == 1) {\r\n return xpath;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\nconst addRelativeXpaths = (\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean,\r\n attribute: Attr[]\r\n) => {\r\n try {\r\n let nodeXpath: string[] = [];\r\n let relativeXpath, relativeChildXpath;\r\n xpathData = [];\r\n\r\n console.log(attribute);\r\n if (attribute) {\r\n for (const attrName of attribute) {\r\n const expressions = intermediateXpathSteps(\r\n targetElemt,\r\n {\r\n name: attrName.name,\r\n value: attrName.value\r\n },\r\n isTarget\r\n );\r\n\r\n console.log(expressions[0] || \"\");\r\n for (const expression of expressions) {\r\n if (expression) {\r\n nodeXpath.push(expression);\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (targetElemt.textContent) {\r\n let expression = intermediateXpathStep(\r\n targetElemt,\r\n {\r\n name: \"text\",\r\n value: targetElemt.textContent\r\n },\r\n isTarget\r\n );\r\n\r\n console.log(expression);\r\n if (expression) {\r\n nodeXpath.push(expression);\r\n }\r\n }\r\n\r\n nodeXpath.push(targetElemt.tagName);\r\n\r\n if (nodeXpath?.length) {\r\n for (let i = 0; i < nodeXpath.length; i++) {\r\n if (!xpathData.length) {\r\n getSiblingRelativeXPath(targetElemt, docmt, isTarget, nodeXpath[i]);\r\n\r\n if (!xpathData.length) {\r\n if (!relativeXpath) {\r\n relativeXpath = getParentRelativeXpath(\r\n targetElemt.parentElement!,\r\n docmt,\r\n targetElemt,\r\n isTarget\r\n );\r\n }\r\n\r\n console.log(relativeXpath);\r\n\r\n if (\r\n relativeXpath &&\r\n (relativeXpath.includes(\"@\") ||\r\n relativeXpath.includes(\"text()\") ||\r\n relativeXpath.includes(\".=\")) &&\r\n relativeXpath.match(/\\//g)?.length - 2 < 5\r\n ) {\r\n const fullRelativeXpath = relativeXpath + `/${nodeXpath[i]}`;\r\n const count = getCountOfXPath(\r\n fullRelativeXpath,\r\n targetElemt,\r\n docmt\r\n );\r\n\r\n if (count === 1) {\r\n xpathData.push({\r\n key: \"relative xpath by relative parent\",\r\n value: fullRelativeXpath\r\n });\r\n } else if (count > 1 && isIndex) {\r\n const relativeXpathIndex = findXpathWithIndex(\r\n fullRelativeXpath,\r\n targetElemt,\r\n docmt,\r\n count\r\n );\r\n if (\r\n relativeXpathIndex &&\r\n getCountOfXPath(relativeXpathIndex, targetElemt, docmt) === 1\r\n ) {\r\n xpathData.push({\r\n key: `relative xpath by relative parent ${\r\n isIndex ? \"index\" : \"\"\r\n }`,\r\n value: relativeXpathIndex\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (!xpathData.length) {\r\n if (!relativeChildXpath) {\r\n relativeChildXpath = getChildRelativeXpath(\r\n targetElemt,\r\n docmt,\r\n targetElemt\r\n );\r\n }\r\n\r\n if (\r\n relativeChildXpath &&\r\n (relativeChildXpath.includes(\"@\") ||\r\n relativeChildXpath.includes(\"text()\") ||\r\n relativeChildXpath.includes(\".=\"))\r\n ) {\r\n const fullRelativeXpath = `/${\r\n nodeXpath[i] + relativeChildXpath.substring(1)\r\n }`;\r\n const count = getCountOfXPath(\r\n fullRelativeXpath,\r\n targetElemt,\r\n docmt\r\n );\r\n\r\n if (count === 1) {\r\n xpathData.push({\r\n key: \"relative xpath by relative child\",\r\n value: fullRelativeXpath\r\n });\r\n } else if (count > 1 && isIndex) {\r\n const relativeXpathIndex = findXpathWithIndex(\r\n fullRelativeXpath,\r\n targetElemt,\r\n docmt,\r\n count\r\n );\r\n if (\r\n relativeXpathIndex &&\r\n getCountOfXPath(relativeXpathIndex, targetElemt, docmt) === 1\r\n ) {\r\n xpathData.push({\r\n key: `relative xpath by relative parent ${\r\n isIndex ? \"index\" : \"\"\r\n }`,\r\n value: relativeXpathIndex\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (\r\n xpathData?.length === 1 &&\r\n xpathData?.[0]?.value?.match(/\\[([0-9]+)\\]/gm)?.length! > 3 &&\r\n !referenceElementMode\r\n ) {\r\n if (targetElemt.textContent) {\r\n const txtXpath = getTextXPath(targetElemt, docmt, isIndex, false);\r\n if (txtXpath) {\r\n xpathData.unshift({\r\n key: `xpath by text${isIndex ? \"index\" : \"\"}`,\r\n value: txtXpath\r\n });\r\n }\r\n }\r\n }\r\n\r\n if (!xpathData.length) {\r\n let tempRelativeXpath = getUniqueParentXpath(\r\n targetElemt.parentElement!,\r\n docmt,\r\n targetElemt,\r\n isTarget,\r\n nodeXpath[i],\r\n isIndex\r\n );\r\n\r\n if (tempRelativeXpath) {\r\n xpathData.push({\r\n key: \"xpath by unique parent\",\r\n value: tempRelativeXpath\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return xpathData;\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n};\r\n\r\nexport const attributesBasedXPath = (\r\n attr: Attr,\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n let attrName;\r\n\r\n attrName = attr.name;\r\n // Strict numeric-attribute validation for direct callers.\r\n if (!checkBlockedAttributes(attr, targetElemt, isTarget)) {\r\n return;\r\n }\r\n\r\n let xpath = getPropertyXPath(\r\n targetElemt,\r\n docmt,\r\n `@${attrName}`,\r\n attr.value,\r\n isIndex,\r\n isTarget\r\n );\r\n\r\n return xpath;\r\n};\r\n\r\nexport const getUniqueClassName = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n let value = element.className;\r\n if (typeof value !== \"string\") {\r\n value = \"\";\r\n }\r\n value = value?.replace(\"flndisabled\", \"disabled\");\r\n value = sanitizeAttributeValue(\"class\", value);\r\n value = value?.trim();\r\n\r\n if (value && checkBlockedAttributes({ name: \"class\", value }, element, isTarget)) {\r\n return getPropertyXPath(element, docmt, `@class`, value, isIndex, isTarget);\r\n }\r\n};\r\n\r\nexport const getTextXPath = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n if ((element.textContent ?? \"\").trim() != \"\") {\r\n const text = getTextContent(element);\r\n\r\n if (text) {\r\n return getPropertyXPath(element, docmt, \".\", text, isIndex, isTarget);\r\n }\r\n }\r\n};\r\n\r\nconst addAllXPathAttributes = (\r\n attributes: Attr[],\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n const attributesArray = attributes;\r\n try {\r\n attributesArray.map((attr) => {\r\n if (!(attr.name === \"className\" || attr.name === \"class\")) {\r\n // Strict numeric-attribute validation is enforced inside\r\n // checkBlockedAttributes before candidate XPath creation.\r\n if (checkBlockedAttributes(attr, targetElemt, isTarget)) {\r\n const xpth = attributesBasedXPath(\r\n attr,\r\n targetElemt,\r\n docmt,\r\n isIndex,\r\n isTarget\r\n );\r\n if (xpth) {\r\n xpathData.push({\r\n key: `xpath by ${attr.name}${isIndex ? \" index\" : \"\"}`,\r\n value: xpth\r\n });\r\n }\r\n }\r\n }\r\n });\r\n\r\n const txtXpath = getTextXPath(targetElemt, docmt, isIndex, isTarget);\r\n if (txtXpath) {\r\n xpathData.push({\r\n key: `xpath by text${isIndex ? \" index\" : \"\"}`,\r\n value: txtXpath\r\n });\r\n }\r\n\r\n if (\r\n attributesArray.find((element) => element.name === \"className\") &&\r\n checkBlockedAttributes(\r\n attributesArray?.find((element) => element.name === \"className\")!,\r\n targetElemt,\r\n isTarget\r\n )\r\n ) {\r\n let xpath = getUniqueClassName(targetElemt, docmt, isIndex, isTarget);\r\n if (xpath) {\r\n xpathData.push({\r\n key: \"xpath by class\",\r\n value: xpath\r\n });\r\n }\r\n }\r\n\r\n if (!xpathData.length && attributesArray.length > 1) {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n targetElemt,\r\n docmt,\r\n attributesArray,\r\n isTarget\r\n );\r\n if (combinationXpath)\r\n xpathData.push({\r\n key: \"xpath by combination\",\r\n value: combinationXpath\r\n });\r\n }\r\n\r\n if (!xpathData.length) {\r\n const textAttribute = getXPathUsingAttributeAndText(\r\n attributes,\r\n targetElemt,\r\n docmt,\r\n isTarget\r\n );\r\n if (textAttribute)\r\n xpathData.push({\r\n key: \"xpath by textAttribute\",\r\n value: textAttribute\r\n });\r\n }\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n};\r\n\r\nexport const parseDOM = (\r\n element: HTMLElement | Element,\r\n doc: Document,\r\n isIndex: boolean,\r\n isTarget: boolean,\r\n includedAttributes: Attr[] = [],\r\n strategies: string[] = []\r\n) => {\r\n xpathData = [];\r\n console.log(element);\r\n const targetElemt = element;\r\n const rootNode = targetElemt?.getRootNode?.();\r\n const isShadowScoped = rootNode?.nodeType === Node.DOCUMENT_FRAGMENT_NODE;\r\n const docmt = (\r\n isShadowScoped ? rootNode : targetElemt?.ownerDocument || doc\r\n ) as Document;\r\n const tag = targetElemt.tagName;\r\n const { attributes } = targetElemt;\r\n const attributesToUse =\r\n includedAttributes.length > 0 ? includedAttributes : Array.from(attributes);\r\n addAllXPathAttributes(attributesToUse, targetElemt, docmt, isIndex, isTarget);\r\n\r\n if (strategies.length) {\r\n const strategyXpaths = strategies.flatMap((strategy) =>\r\n buildStrategyXpaths(targetElemt, docmt, isTarget, strategy, xpathData)\r\n );\r\n\r\n xpathData = getUniqueXpathEntries(\r\n strategyXpaths.filter(\r\n (xpath) => getCountOfXPath(xpath.value, targetElemt, docmt) === 1\r\n )\r\n );\r\n\r\n return removePositionalIndexXpaths(xpathData, isIndex);\r\n }\r\n\r\n if (!referenceElementMode) {\r\n if (xpathData.length) {\r\n const len = xpathData.length;\r\n for (let i = 0; i < len; i++) {\r\n let xpth = xpathData[i].value;\r\n xpth = \"//*\" + xpth.substring(xpth.indexOf(\"//\") + 2 + tag.length);\r\n const count = getCountOfXPath(xpth, element, docmt);\r\n if (count === 1) {\r\n xpathData.push({\r\n key: `${xpathData[i].key} regex`,\r\n value: xpth\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (!xpathData.length && !isShadowScoped) {\r\n xpathData = buildAxesStrategyXpaths(targetElemt, docmt, isTarget, isIndex);\r\n }\r\n\r\n return removePositionalIndexXpaths(xpathData, isIndex);\r\n};\r\n\r\nconst xpath = {\r\n parseDOM,\r\n getTextXPath,\r\n getUniqueClassName,\r\n attributesBasedXPath,\r\n addAllXPathAttributes,\r\n addRelativeXpaths,\r\n getXPathUsingAttributeAndText,\r\n getSiblingRelativeXPath,\r\n getChildRelativeXpath,\r\n getParentRelativeXpath,\r\n getUniqueParentXpath,\r\n checkRelativeXpathRelation,\r\n buildAxesStrategyXpaths\r\n};\r\n\r\nexport default xpath;\r\n","import { parseDOM } from \"./xpath.ts\";\r\nimport {\r\n findXpathWithIndex,\r\n getShadowRoot,\r\n getTextContent,\r\n escapeCharacters,\r\n getCountOfXPath,\r\n checkBlockedAttributes,\r\n getAbsoluteXPath,\r\n isSvg,\r\n getCombinationXpath,\r\n getTextXpathFunction,\r\n replaceTempAttributes,\r\n replaceActualAttributes,\r\n getReferenceElementsXpath,\r\n getRelativeXPath,\r\n findMatchingParenthesis,\r\n removeParenthesis,\r\n sanitizeAttributeValue,\r\n replaceWhiteSpaces,\r\n getClassTokenConditions,\r\n getContainerTextCondition\r\n} from \"./xpathHelpers.ts\";\r\n\r\nlet xpathDataWithIndex: any[] = [];\r\nlet xpathData: { key: string; value: string }[] = [];\r\nconst reWhiteSpace = /^[\\S]+( [\\S]+)*$/gi;\r\n\r\nexport const findRelativeXpath = (\r\n element1: Element,\r\n element2: Element,\r\n docmt: Document,\r\n xpaths1: any[],\r\n xpaths2: any[],\r\n isIndex: boolean,\r\n multiElementReferenceMode: boolean = false,\r\n allowedRelations: string[] | null = null\r\n) => {\r\n let finalXpaths: any[] = [];\r\n\r\n const relations = allowedRelations || [];\r\n\r\n const tryRelation = (relation: string, useIndex: boolean) => {\r\n let rel_xpath: any[] = [];\r\n\r\n if (relation === \"descendant\" || relation === \"descendant-or-self\") {\r\n rel_xpath =\r\n getDescendantXpath(\r\n [element1, element2],\r\n docmt,\r\n xpaths1,\r\n xpaths2,\r\n relation as \"descendant\" | \"descendant-or-self\",\r\n useIndex,\r\n multiElementReferenceMode\r\n ) || [];\r\n } else {\r\n rel_xpath =\r\n getXpathRelationExpression(\r\n element1,\r\n element2,\r\n relation,\r\n xpaths1,\r\n xpaths2,\r\n useIndex,\r\n multiElementReferenceMode\r\n ) || [];\r\n }\r\n\r\n if (rel_xpath.length) {\r\n finalXpaths = finalXpaths.concat(rel_xpath);\r\n }\r\n };\r\n\r\n for (const relation of relations) {\r\n tryRelation(relation, isIndex);\r\n }\r\n\r\n return finalXpaths;\r\n};\r\n\r\nconst descendantExpression = (\r\n refExpectElement: Array<HTMLElement | Element>,\r\n xpath2: string,\r\n relation: string,\r\n docmt: Node,\r\n isIndex: any,\r\n expCommonParentXpathElements: string | any[],\r\n step4: string,\r\n refCommonParentXpathElementLength: number = 0,\r\n multiElementReferenceMode: boolean = false\r\n) => {\r\n let finalExpectedElementXpath: string | undefined = \"\";\r\n\r\n if (\r\n xpath2.split(/\\/(?=(?:[^']*\\'[^\\']*\\')*[^\\']*$)/g)?.length >=\r\n expCommonParentXpathElements.length\r\n ) {\r\n const xpaths2Els: string[] = [];\r\n const xpath2Elements = xpath2.split(/\\/(?=(?:[^']*\\'[^\\']*\\')*[^\\']*$)/g);\r\n for (let x = 1; x <= expCommonParentXpathElements.length; x++) {\r\n xpaths2Els.unshift(\r\n x === expCommonParentXpathElements.length\r\n ? expCommonParentXpathElements[\r\n expCommonParentXpathElements.length - x\r\n ]\r\n : xpath2Elements[xpath2Elements.length - x]\r\n );\r\n }\r\n const traverseXpath = getTraverseXpathExpression(\r\n `${\r\n step4 +\r\n (refCommonParentXpathElementLength\r\n ? \"]\".repeat(refCommonParentXpathElementLength)\r\n : \"\")\r\n }`,\r\n xpaths2Els,\r\n refExpectElement[refExpectElement.length - 1],\r\n refExpectElement,\r\n docmt,\r\n relation,\r\n isIndex,\r\n multiElementReferenceMode\r\n );\r\n if (traverseXpath) {\r\n return traverseXpath;\r\n }\r\n } else {\r\n finalExpectedElementXpath = `//${\r\n step4 +\r\n (refCommonParentXpathElementLength\r\n ? \"]\".repeat(refCommonParentXpathElementLength)\r\n : \"\")\r\n }/${relation}::${replaceActualAttributes(\r\n xpath2,\r\n refExpectElement[refExpectElement.length - 1]\r\n )}`;\r\n let rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt\r\n );\r\n if (rel_count === 1) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n if (rel_count > 1) {\r\n if (isIndex) {\r\n finalExpectedElementXpath = findXpathWithIndex(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt,\r\n rel_count\r\n );\r\n if (finalExpectedElementXpath) {\r\n rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt\r\n );\r\n if (rel_count === 1) {\r\n return [\r\n {\r\n key: `dynamic ${relation} ${isIndex ? \" index\" : \"\"}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n }\r\n }\r\n }\r\n }\r\n};\r\n\r\nconst getDescendantXpath = (\r\n refExpectElement: Array<HTMLElement | Element>,\r\n docmt: Document,\r\n xpaths1: { key: string; value: string }[],\r\n xpaths2: { key: string; value: string }[],\r\n relation: \"descendant\" | \"descendant-or-self\",\r\n isIndex: boolean = false,\r\n multiElementReferenceMode: boolean = false\r\n) => {\r\n const refElement: HTMLElement | Element =\r\n refExpectElement[refExpectElement.length - 2];\r\n const expElement: HTMLElement | Element =\r\n refExpectElement[refExpectElement.length - 1];\r\n const expElementDocmnt =\r\n getShadowRoot(expElement) ?? expElement.ownerDocument;\r\n\r\n const refAbsoluteXpath =\r\n xpaths1.find((x) => x?.key?.includes(\"absolute\"))?.value ||\r\n getAbsoluteXPath(refElement, refElement.ownerDocument);\r\n\r\n const refFullXpathElements: any[] = [];\r\n const refFullXpathElementsWithoutNumber: any[] = [];\r\n refAbsoluteXpath.split(\"/\").map((x) => refFullXpathElements.push(x));\r\n refFullXpathElements.map((x) =>\r\n refFullXpathElementsWithoutNumber.push(x.replace(/\\[([0-9]+)\\]/gm, \"\"))\r\n );\r\n\r\n const expAbsoluteXpath =\r\n xpaths2.find((x) => x?.key?.includes(\"absolute\"))?.value ||\r\n getAbsoluteXPath(expElement, expElement.ownerDocument);\r\n\r\n const expFullXpathElements: any[] = [];\r\n const expFullXpathElementsWithoutNumber: any[] = [];\r\n expAbsoluteXpath.split(\"/\").map((x) => expFullXpathElements.push(x));\r\n expFullXpathElements.map((x) =>\r\n expFullXpathElementsWithoutNumber.push(x.replace(/\\[([0-9]+)\\]/gm, \"\"))\r\n );\r\n\r\n for (\r\n var parentElementNumber = 0;\r\n parentElementNumber < refFullXpathElements.length;\r\n parentElementNumber++\r\n ) {\r\n if (\r\n refFullXpathElements[parentElementNumber] !=\r\n expFullXpathElements[parentElementNumber]\r\n ) {\r\n break;\r\n }\r\n }\r\n\r\n const refCommonParentXpathElements = [];\r\n for (let i = parentElementNumber - 1; i < refFullXpathElements.length; i++) {\r\n if (refFullXpathElements[i]) {\r\n refCommonParentXpathElements.push(refFullXpathElementsWithoutNumber[i]);\r\n }\r\n }\r\n\r\n const expCommonParentXpathElements: string[] = [];\r\n for (\r\n let j =\r\n relation === \"descendant\" ? parentElementNumber : parentElementNumber - 1;\r\n j < expFullXpathElements.length;\r\n j++\r\n ) {\r\n if (expFullXpathElements[j]) {\r\n if (expCommonParentXpathElements.length)\r\n expCommonParentXpathElements.push(expFullXpathElementsWithoutNumber[j]);\r\n else\r\n expCommonParentXpathElements.push(\r\n expFullXpathElementsWithoutNumber[j].replace(/\\[([0-9]+)\\]/gm, \"\")\r\n );\r\n }\r\n }\r\n\r\n xpathData = xpaths2;\r\n\r\n let nodeXpath2;\r\n if (refExpectElement[refExpectElement.length - 2].textContent) {\r\n if (\r\n !reWhiteSpace.test(\r\n refExpectElement[refExpectElement.length - 2].textContent\r\n )\r\n ) {\r\n nodeXpath2 = isSvg(refExpectElement[refExpectElement.length - 2])\r\n ? `*[local-name()='${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }' and ${getTextXpathFunction(\r\n refExpectElement[refExpectElement.length - 2]\r\n )})]`\r\n : `${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }[${getTextXpathFunction(\r\n refExpectElement[refExpectElement.length - 2]\r\n )}]`;\r\n } else {\r\n const referenceElement = refExpectElement[refExpectElement.length - 2];\r\n const referenceText = getTextContent(\r\n referenceElement\r\n );\r\n const containerTextCondition = getContainerTextCondition(\r\n referenceElement,\r\n referenceText\r\n );\r\n const referenceTextCondition = containerTextCondition\r\n ? containerTextCondition\r\n : /\\s/.test(referenceText.trim())\r\n ? `normalize-space(.)=${escapeCharacters(\r\n replaceWhiteSpaces(referenceText)\r\n )}`\r\n : `.=${escapeCharacters(referenceText)}`;\r\n nodeXpath2 = isSvg(refExpectElement[refExpectElement.length - 2])\r\n ? `*[local-name()='${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }' and ${referenceTextCondition}]`\r\n : `${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }[${referenceTextCondition}]`;\r\n }\r\n\r\n refCommonParentXpathElements[refCommonParentXpathElements.length - 1] =\r\n nodeXpath2;\r\n\r\n const refCommonParentXpath = refCommonParentXpathElements.join(\"[\");\r\n const refCommonParentXpathElementLength =\r\n refCommonParentXpathElements.length - 1;\r\n\r\n const step4 = refCommonParentXpath;\r\n\r\n for (let i = 0; i < xpathData.length; i++) {\r\n let xpath2;\r\n\r\n if (xpathData[i].value.startsWith(\"//\")) {\r\n xpath2 = xpathData[i].value.substring(\r\n xpathData[i].value.indexOf(\"//\") + 2\r\n );\r\n } else {\r\n xpath2 = xpathData[i].value; // No need to modify the value\r\n }\r\n if (xpath2) {\r\n const result = descendantExpression(\r\n refExpectElement,\r\n xpath2,\r\n relation,\r\n expElementDocmnt || docmt,\r\n isIndex,\r\n expCommonParentXpathElements,\r\n step4,\r\n refCommonParentXpathElementLength,\r\n multiElementReferenceMode\r\n );\r\n if (result?.length) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (refExpectElement[refExpectElement.length - 2].attributes) {\r\n for (const attrName of Array.from(\r\n refExpectElement[refExpectElement.length - 2].attributes\r\n )) {\r\n if (\r\n checkBlockedAttributes(\r\n attrName,\r\n refExpectElement[refExpectElement.length - 2],\r\n false\r\n )\r\n ) {\r\n let attrValue = attrName.nodeValue;\r\n if (attrValue) {\r\n attrValue = sanitizeAttributeValue(attrName.name, attrValue);\r\n const elementName = attrName.name;\r\n\r\n nodeXpath2 = isSvg(refExpectElement[refExpectElement.length - 2])\r\n ? `*[local-name()='${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }' and @${elementName}=${escapeCharacters(attrValue)}]`\r\n : `${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }[@${elementName}=${escapeCharacters(attrValue)}]`;\r\n\r\n refCommonParentXpathElements[\r\n refCommonParentXpathElements.length - 1\r\n ] = nodeXpath2;\r\n\r\n const refCommonParentXpath = refCommonParentXpathElements.join(\"[\");\r\n const refCommonParentXpathElementLength =\r\n refCommonParentXpathElements.length - 1;\r\n\r\n const step4 = refCommonParentXpath;\r\n\r\n for (let i = 0; i < xpathData.length; i++) {\r\n let xpath2;\r\n if (xpathData[i].value.startsWith(\"//\")) {\r\n xpath2 = xpathData[i].value.substring(\r\n xpathData[i].value.indexOf(\"//\") + 2\r\n );\r\n } else {\r\n xpath2 = xpathData[i].value; // No need to modify the value\r\n }\r\n\r\n const result = descendantExpression(\r\n refExpectElement,\r\n xpath2,\r\n relation,\r\n expElementDocmnt || docmt,\r\n isIndex,\r\n expCommonParentXpathElements,\r\n step4,\r\n refCommonParentXpathElementLength,\r\n multiElementReferenceMode\r\n );\r\n if (result?.length) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n for (const attrName of Array.from(\r\n refExpectElement[refExpectElement.length - 2].attributes\r\n )) {\r\n if (\r\n checkBlockedAttributes(\r\n attrName,\r\n refExpectElement[refExpectElement.length - 2],\r\n false\r\n )\r\n ) {\r\n let attrValue = attrName.nodeValue;\r\n if (attrValue) {\r\n attrValue = sanitizeAttributeValue(attrName.name, attrValue);\r\n const combinationXpath = getCombinationXpath(\r\n attrName,\r\n refExpectElement[refExpectElement.length - 2]\r\n );\r\n if (combinationXpath) {\r\n if (combinationXpath.startsWith(\"//\")) {\r\n nodeXpath2 = combinationXpath.substring(\r\n combinationXpath.indexOf(\"//\") + 2\r\n );\r\n } else {\r\n nodeXpath2 = combinationXpath; // No need to modify the value\r\n }\r\n\r\n refCommonParentXpathElements[\r\n refCommonParentXpathElements.length - 1\r\n ] = nodeXpath2;\r\n\r\n const refCommonParentXpath = refCommonParentXpathElements.join(\"[\");\r\n const refCommonParentXpathElementLength =\r\n refCommonParentXpathElements.length - 1;\r\n\r\n const step4 = refCommonParentXpath;\r\n\r\n for (let i = 0; i < xpathData.length; i++) {\r\n let xpath2;\r\n if (xpathData[i].value.startsWith(\"//\")) {\r\n xpath2 = xpathData[i].value.substring(\r\n xpathData[i].value.indexOf(\"//\") + 2\r\n );\r\n } else {\r\n xpath2 = xpathData[i].value; // No need to modify the value\r\n }\r\n\r\n const result = descendantExpression(\r\n refExpectElement,\r\n xpath2,\r\n relation,\r\n expElementDocmnt || docmt,\r\n isIndex,\r\n expCommonParentXpathElements,\r\n step4,\r\n refCommonParentXpathElementLength,\r\n multiElementReferenceMode\r\n );\r\n if (result?.length) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n const refCommonParentXpath = refCommonParentXpathElements.join(\"[\");\r\n const refCommonParentXpathElementLength =\r\n refCommonParentXpathElements.length - 1;\r\n const step4 = refCommonParentXpath;\r\n const traverseXpath = getTraverseXpathExpression(\r\n `${\r\n step4 +\r\n (refCommonParentXpathElementLength\r\n ? \"]\".repeat(refCommonParentXpathElementLength)\r\n : \"\")\r\n }`,\r\n expCommonParentXpathElements,\r\n refExpectElement[refExpectElement.length - 1],\r\n refExpectElement,\r\n docmt,\r\n relation,\r\n isIndex,\r\n multiElementReferenceMode\r\n );\r\n if (traverseXpath) {\r\n return traverseXpath;\r\n }\r\n};\r\n\r\nconst getXpathRelationExpression = (\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: string,\r\n xpath1: any[],\r\n xpath2: any[],\r\n isIndex: boolean,\r\n multiElementReferenceMode: boolean\r\n) => {\r\n let xpaths1;\r\n let xpaths2;\r\n console.log(\"getXpathRelationExpression\", relation);\r\n const finalXpaths: { key: string; value: any }[] = [];\r\n\r\n try {\r\n xpaths1 = xpath1\r\n .filter((x) => !x?.key?.includes(\"absolute\"))\r\n .filter((x) => doesReferenceXpathMatchElement(x.value, element1));\r\n\r\n xpaths2 = xpath2.filter((x) => !x?.key?.includes(\"absolute\"));\r\n\r\n if (relation === \"ancestor\" || relation === \"ancestor-or-self\") {\r\n const ancestorBridgeXpaths = getAncestorBridgeXpath(\r\n element1,\r\n element2,\r\n relation,\r\n xpaths1,\r\n xpaths2,\r\n isIndex\r\n );\r\n\r\n if (ancestorBridgeXpaths.length) {\r\n return ancestorBridgeXpaths;\r\n }\r\n }\r\n\r\n for (let i = 0; i < xpaths1.length; i++) {\r\n for (let j = 0; j < xpaths2.length; j++) {\r\n const targetXpathValue =\r\n xpaths2[j].value.indexOf(\"//\") !== 0\r\n ? xpaths2[j].value\r\n : xpaths2[j].value.substring(xpaths2[j].value.indexOf(\"//\") + 2);\r\n if (\r\n (relation === \"ancestor\" || relation === \"ancestor-or-self\") &&\r\n targetXpathValue.split(xpathStepSeparator).length > 1\r\n ) {\r\n // Ancestor bridge handles multi-step target paths; avoid producing ancestor::ARTICLE/SECTION[2]/... structural tails here.\r\n continue;\r\n }\r\n\r\n let rel_xpath: string | undefined = `//${\r\n xpaths1[i].value.indexOf(\"//\") !== 0\r\n ? replaceActualAttributes(xpaths1[i].value, element1)\r\n : replaceActualAttributes(\r\n xpaths1[i].value.substring(xpaths1[i].value.indexOf(\"//\") + 2),\r\n element1\r\n )\r\n }/${relation}::${replaceActualAttributes(targetXpathValue, element2)}`;\r\n console.log(\"getXpathRelationExpression\", rel_xpath);\r\n const rel_count = getCountOfXPath(\r\n rel_xpath,\r\n element2,\r\n element2.ownerDocument\r\n );\r\n if (rel_count > 1) {\r\n const referenceXpath =\r\n xpaths1[i].value.indexOf(\"//\") !== 0\r\n ? replaceActualAttributes(xpaths1[i].value, element1)\r\n : replaceActualAttributes(\r\n xpaths1[i].value.substring(\r\n xpaths1[i].value.indexOf(\"//\") + 2\r\n ),\r\n element1\r\n );\r\n const semanticTargetXpath = getDirectSemanticDescendantXpath(\r\n referenceXpath,\r\n relation,\r\n element2,\r\n xpaths2,\r\n element2.ownerDocument\r\n );\r\n\r\n if (semanticTargetXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(semanticTargetXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n if (isIndex) {\r\n rel_xpath = findXpathWithIndex(\r\n rel_xpath,\r\n element2,\r\n element2.ownerDocument,\r\n rel_count\r\n );\r\n if (rel_xpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation}${isIndex ? \" index\" : \"\"}`,\r\n value: replaceTempAttributes(rel_xpath)\r\n });\r\n return finalXpaths;\r\n }\r\n } else if (rel_count > 1) {\r\n if (xpathDataWithIndex.length) {\r\n if (rel_count < xpathDataWithIndex[0].count) {\r\n xpathDataWithIndex.pop();\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by relative child ${\r\n isIndex ? \"index\" : \"\"\r\n }`,\r\n value: rel_xpath,\r\n count: rel_count\r\n });\r\n }\r\n } else {\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by relative child ${\r\n isIndex ? \"index\" : \"\"\r\n }`,\r\n value: rel_xpath,\r\n count: rel_count\r\n });\r\n }\r\n }\r\n } else if (rel_count === 1) {\r\n if (\r\n relation === \"following\" &&\r\n targetXpathValue.split(xpathStepSeparator).length > 1\r\n ) {\r\n const referenceXpath =\r\n xpaths1[i].value.indexOf(\"//\") !== 0\r\n ? replaceActualAttributes(xpaths1[i].value, element1)\r\n : replaceActualAttributes(\r\n xpaths1[i].value.substring(\r\n xpaths1[i].value.indexOf(\"//\") + 2\r\n ),\r\n element1\r\n );\r\n const bridgeXpath = getDirectionalIntermediateBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n relation,\r\n xpaths2\r\n );\r\n\r\n if (bridgeXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(bridgeXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n\r\n finalXpaths.push({\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(rel_xpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n }\r\n if (!finalXpaths.length) {\r\n if (relation === \"following\") {\r\n for (let i = 0; i < xpaths1.length; i++) {\r\n const referenceXpath =\r\n xpaths1[i].value.indexOf(\"//\") !== 0\r\n ? replaceActualAttributes(xpaths1[i].value, element1)\r\n : replaceActualAttributes(\r\n xpaths1[i].value.substring(\r\n xpaths1[i].value.indexOf(\"//\") + 2\r\n ),\r\n element1\r\n );\r\n const bridgeXpath = getDirectionalIntermediateBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n relation,\r\n xpaths2\r\n );\r\n\r\n if (bridgeXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(bridgeXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n }\r\n\r\n for (let i = 0; i < xpaths1.length; i++) {\r\n for (let j = 0; j < xpaths2.length; j++) {\r\n const tempPath = `${\r\n xpaths2[j].value.indexOf(\"//\") !== 0\r\n ? xpaths2[j].value\r\n : xpaths2[j].value.substring(xpaths2[j].value.indexOf(\"//\") + 2)\r\n }`;\r\n const xpath2Elements: string[] = tempPath.split(\r\n /\\/(?=(?:[^']*\\'[^\\']*\\')*[^\\']*$)/g\r\n );\r\n if (xpath2Elements.length > 1) {\r\n const referenceXpath =\r\n xpaths1[i].value.indexOf(\"//\") !== 0\r\n ? replaceActualAttributes(xpaths1[i].value, element1)\r\n : replaceActualAttributes(\r\n xpaths1[i].value.substring(\r\n xpaths1[i].value.indexOf(\"//\") + 2\r\n ),\r\n element1\r\n );\r\n\r\n if (relation === \"following\") {\r\n const bridgeXpath = getDirectionalIntermediateBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n relation,\r\n xpaths2\r\n );\r\n\r\n if (bridgeXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(bridgeXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n\r\n const traverseXpath = getTraverseXpathExpression(\r\n referenceXpath,\r\n xpath2Elements,\r\n element2,\r\n [element1, element2],\r\n element2.ownerDocument,\r\n relation,\r\n isIndex,\r\n multiElementReferenceMode\r\n );\r\n\r\n console.log(\r\n \"getXpathRelationExpression traverseXpath\",\r\n traverseXpath\r\n );\r\n if (traverseXpath) {\r\n finalXpaths.push(...traverseXpath);\r\n return finalXpaths;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n\r\n return finalXpaths;\r\n};\r\n\r\nconst xpathStepSeparator = /\\/(?=(?:[^']*'[^']*')*[^']*$)/g;\r\n\r\nconst stripXpathPrefix = (xpath: string) =>\r\n xpath.indexOf(\"//\") === 0 ? xpath.substring(xpath.indexOf(\"//\") + 2) : xpath;\r\n\r\nconst getCommonAncestor = (\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element\r\n) => {\r\n let currentNode: Element | null = element1;\r\n\r\n while (currentNode) {\r\n if (currentNode.contains(element2)) {\r\n return currentNode;\r\n }\r\n\r\n currentNode = currentNode.parentElement;\r\n }\r\n\r\n return null;\r\n};\r\n\r\nconst getSingleStepXpath = (\r\n element: HTMLElement | Element,\r\n xpaths: { key: string; value: string }[]\r\n) => {\r\n return getSingleStepXpaths(element, xpaths)[0] || \"\";\r\n};\r\n\r\nconst getSingleStepXpaths = (\r\n element: HTMLElement | Element,\r\n xpaths: { key: string; value: string }[]\r\n) => {\r\n const candidates: string[] = [];\r\n let tagOnlyXpath = \"\";\r\n const addCandidate = (xpath: string) => {\r\n if (xpath && !candidates.includes(xpath)) {\r\n candidates.push(xpath);\r\n }\r\n };\r\n\r\n for (const xpath of xpaths) {\r\n const xpathValue = stripXpathPrefix(xpath.value);\r\n\r\n if (xpathValue && xpathValue.split(xpathStepSeparator).length === 1) {\r\n if (\r\n xpathValue === element.tagName ||\r\n xpathValue === element.tagName.toLowerCase()\r\n ) {\r\n tagOnlyXpath = xpathValue;\r\n continue;\r\n }\r\n\r\n addCandidate(replaceActualAttributes(xpathValue, element));\r\n }\r\n }\r\n\r\n for (const attributeName of semanticScopeAttributeNames) {\r\n const attributeValue = element.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getStableAttributeCondition(attributeName, attributeValue);\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n // A semantic target step is better than plain tag-only in reference mode; final relation scoping validates uniqueness.\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}' and ${condition}]`\r\n : `${element.tagName}[${condition}]`);\r\n }\r\n\r\n if (element.textContent) {\r\n const textXpath = getTextXpathFunction(element);\r\n\r\n if (textXpath) {\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}' and ${textXpath}]`\r\n : `${element.tagName}[${textXpath}]`);\r\n }\r\n }\r\n\r\n const classConditions = getClassTokenConditions(\r\n element,\r\n element.getAttribute(\"class\"),\r\n (element.getRootNode?.() as Document | ShadowRoot | null) ??\r\n element.ownerDocument,\r\n false\r\n );\r\n for (const classCondition of classConditions) {\r\n // Try every stable class token in reference mode; final relation\r\n // validation decides which token is actually unique.\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}' and ${classCondition}]`\r\n : `${element.tagName}[${classCondition}]`);\r\n }\r\n\r\n if (element.attributes) {\r\n for (const attrName of Array.from(element.attributes)) {\r\n if (attrName.name === \"class\") {\r\n // Class was already handled through getClassTokenConditions above.\r\n // Do not let the generic attribute fallback reintroduce numeric class\r\n // values such as css-1xc3v61-indicatorContainer.\r\n continue;\r\n }\r\n\r\n if (\r\n checkBlockedAttributes(attrName, element, false) &&\r\n attrName.nodeValue\r\n ) {\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}' and @${attrName.name}=${escapeCharacters(\r\n sanitizeAttributeValue(attrName.name, attrName.nodeValue)\r\n )}]`\r\n : `${element.tagName}[@${attrName.name}=${escapeCharacters(\r\n sanitizeAttributeValue(attrName.name, attrName.nodeValue)\r\n )}]`);\r\n }\r\n }\r\n }\r\n\r\n if (tagOnlyXpath) {\r\n addCandidate(tagOnlyXpath);\r\n }\r\n\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}']`\r\n : element.tagName);\r\n\r\n return candidates;\r\n};\r\n\r\nconst getRelativeXpathFromAncestor = (\r\n ancestorElement: Element,\r\n targetElement: HTMLElement | Element,\r\n targetXPaths: { key: string; value: string }[]\r\n) => {\r\n const steps: string[] = [];\r\n let currentNode: Element | null = targetElement;\r\n\r\n while (currentNode && currentNode !== ancestorElement) {\r\n const currentStep =\r\n currentNode === targetElement\r\n ? getSingleStepXpath(targetElement, targetXPaths)\r\n : isSvg(currentNode)\r\n ? `*[local-name()='${currentNode.tagName}']`\r\n : currentNode.tagName;\r\n\r\n steps.unshift(currentStep);\r\n currentNode = currentNode.parentElement;\r\n }\r\n\r\n return currentNode === ancestorElement ? steps.join(\"/\") : \"\";\r\n};\r\n\r\nconst semanticScopeAttributeNames = [\r\n \"aria-labelledby\",\r\n \"aria-label\",\r\n \"role\",\r\n \"name\",\r\n \"data-testid\",\r\n \"data-test\",\r\n \"data-qa\",\r\n \"data-id\",\r\n \"id\"\r\n];\r\n\r\nconst getStableAttributeCondition = (attributeName: string, value: string) => {\r\n const sanitizedValue = sanitizeAttributeValue(attributeName, value);\r\n\r\n if (!sanitizedValue) {\r\n return \"\";\r\n }\r\n\r\n if (/\\d/.test(sanitizedValue)) {\r\n // Strict numeric-attribute validation: relation/bridge strategies must not\r\n // split numeric attributes into contains/starts-with predicates.\r\n return \"\";\r\n }\r\n\r\n return `@${attributeName}=${escapeCharacters(sanitizedValue)}`;\r\n};\r\n\r\nconst getSemanticScopedBridgeXpath = (\r\n referenceXpath: string,\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n commonAncestor: Element,\r\n relation: \"ancestor\" | \"ancestor-or-self\",\r\n ancestorNodeTest: string,\r\n targetAxisXpath: string\r\n) => {\r\n let scopeElement = element2.parentElement;\r\n let checkedAncestors = 0;\r\n\r\n while (\r\n scopeElement &&\r\n scopeElement !== commonAncestor &&\r\n checkedAncestors < 6\r\n ) {\r\n checkedAncestors++;\r\n\r\n for (const attributeName of semanticScopeAttributeNames) {\r\n const attributeValue = scopeElement.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getStableAttributeCondition(\r\n attributeName,\r\n attributeValue\r\n );\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n const scopeNodeTest = isSvg(scopeElement)\r\n ? `*[local-name()='${scopeElement.tagName}' and ${condition}]`\r\n : `${scopeElement.tagName}[${condition}]`;\r\n // This bounded semantic scope avoids falling back to long DIV/DIV chains when a labelled group can uniquely scope the target.\r\n const scopedXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/descendant::${scopeNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n if (getCountOfXPath(scopedXpath, element2, element2.ownerDocument) === 1) {\r\n return scopedXpath;\r\n }\r\n }\r\n\r\n scopeElement = scopeElement.parentElement;\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\n// Semantic bridge for following only:\r\n// reference/following::target-ancestor/descendant::target.\r\nconst directionalIntermediateAttributeNames = [\r\n \"title\",\r\n ...semanticScopeAttributeNames\r\n];\r\n\r\nconst getDirectionalIntermediateBridgeXpath = (\r\n referenceXpath: string,\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: string,\r\n xpaths2: { key: string; value: string }[]\r\n) => {\r\n if (relation !== \"following\") {\r\n return \"\";\r\n }\r\n\r\n // Bridge only through target ancestors, so the second hop is safely scoped as descendant::target.\r\n const targetAxisXpaths = getSingleStepXpaths(element2, xpaths2);\r\n if (!targetAxisXpaths.length) {\r\n return \"\";\r\n }\r\n\r\n const resolvedReference = getFirstElementByXpath(\r\n `//${replaceActualAttributes(referenceXpath, element1)}`,\r\n element1.ownerDocument\r\n );\r\n const positionReference = resolvedReference || element1;\r\n let intermediate = element2.parentElement;\r\n let checkedAncestors = 0;\r\n\r\n while (intermediate && checkedAncestors < 6) {\r\n checkedAncestors++;\r\n\r\n const position = positionReference.compareDocumentPosition(intermediate);\r\n if (!(position & Node.DOCUMENT_POSITION_FOLLOWING)) {\r\n intermediate = intermediate.parentElement;\r\n continue;\r\n }\r\n\r\n for (const attributeName of directionalIntermediateAttributeNames) {\r\n const attributeValue = intermediate.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getStableAttributeCondition(\r\n attributeName,\r\n attributeValue\r\n );\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n const intermediateNodeTest = isSvg(intermediate)\r\n ? `*[local-name()='${intermediate.tagName}' and ${condition}]`\r\n : `${intermediate.tagName}[${condition}]`;\r\n for (const targetAxisXpath of targetAxisXpaths) {\r\n // Keep this as a fallback-only semantic bridge: following::ancestor/descendant::target, accepted only when unique.\r\n const bridgeXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${intermediateNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n if (\r\n getCountOfXPath(bridgeXpath, element2, element2.ownerDocument) === 1\r\n ) {\r\n return bridgeXpath;\r\n }\r\n }\r\n }\r\n\r\n intermediate = intermediate.parentElement;\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getSemanticAncestorNodeTest = (\r\n commonAncestor: Element,\r\n element2: HTMLElement | Element\r\n) => {\r\n let ancestorElement: Element | null = commonAncestor;\r\n let checkedAncestors = 0;\r\n const candidates: { nodeTest: string; score: number }[] = [];\r\n const semanticContainerTags = new Set([\r\n \"SECTION\",\r\n \"FIELDSET\",\r\n \"FORM\",\r\n \"ARTICLE\",\r\n \"MAIN\"\r\n ]);\r\n\r\n // Prefer a meaningful containing section/group over generic ancestor::DIV when it can still scope the target.\r\n while (ancestorElement && ancestorElement.contains(element2) && checkedAncestors < 6) {\r\n checkedAncestors++;\r\n\r\n for (const attributeName of semanticScopeAttributeNames) {\r\n const attributeValue = ancestorElement.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getStableAttributeCondition(\r\n attributeName,\r\n attributeValue\r\n );\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n const nodeTest = isSvg(ancestorElement)\r\n ? `*[local-name()='${ancestorElement.tagName}' and ${condition}]`\r\n : `${ancestorElement.tagName}[${condition}]`;\r\n const score =\r\n (semanticContainerTags.has(ancestorElement.tagName) ? 100 : 0) +\r\n (attributeName === \"data-testid\" ? 20 : 0) -\r\n checkedAncestors;\r\n\r\n candidates.push({ nodeTest, score });\r\n break;\r\n }\r\n\r\n ancestorElement = ancestorElement.parentElement;\r\n }\r\n\r\n return candidates.sort((left, right) => right.score - left.score)[0]\r\n ?.nodeTest || \"\";\r\n};\r\n\r\n// Semantic bridge for descendant and descendant-or-self only:\r\n// reference/descendant::semantic-scope/descendant::target.\r\nconst getDirectSemanticDescendantXpath = (\r\n referenceXpath: string,\r\n relation: string,\r\n element2: HTMLElement | Element,\r\n xpaths2: { key: string; value: string }[],\r\n docmt: Node\r\n) => {\r\n if (relation !== \"descendant\" && relation !== \"descendant-or-self\") {\r\n return \"\";\r\n }\r\n\r\n for (const xpath of xpaths2) {\r\n const targetXpath = stripXpathPrefix(xpath.value);\r\n\r\n if (\r\n !targetXpath ||\r\n targetXpath.split(xpathStepSeparator).length > 1 ||\r\n /\\[\\d+\\]/.test(targetXpath)\r\n ) {\r\n continue;\r\n }\r\n\r\n // Before index fallback, try meaningful single-step target candidates\r\n // such as IMG[@alt='...'] under the same descendant relation.\r\n const candidateXpath = `//${referenceXpath}/${relation}::${replaceActualAttributes(\r\n targetXpath,\r\n element2\r\n )}`;\r\n\r\n if (getCountOfXPath(candidateXpath, element2, docmt) === 1) {\r\n return candidateXpath;\r\n }\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getSemanticScopedDescendantXpath = (\r\n referenceXpath: string,\r\n relation: string,\r\n element2: HTMLElement | Element,\r\n docmt: Node\r\n) => {\r\n // This helper only belongs to descendant-style relations; other axes keep their existing flow.\r\n if (relation !== \"descendant\" && relation !== \"descendant-or-self\") {\r\n return \"\";\r\n }\r\n\r\n // Keep the target side as a single meaningful step so we do not rebuild the same DIV/DIV tail.\r\n const targetAxisXpath = getSingleStepXpath(\r\n element2,\r\n parseDOM(element2, element2.ownerDocument, false, false) || []\r\n );\r\n let scopeElement = element2.parentElement;\r\n let checkedAncestors = 0;\r\n\r\n // Walk only a few target ancestors to keep generation bounded and avoid broad DOM scanning.\r\n while (scopeElement && checkedAncestors < 6) {\r\n checkedAncestors++;\r\n\r\n // Use semantic attributes that describe a container/group before falling back to raw structure.\r\n for (const attributeName of semanticScopeAttributeNames) {\r\n const attributeValue = scopeElement.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n // Dynamic numeric values are converted to stable starts-with/contains checks or skipped.\r\n const condition = getStableAttributeCondition(\r\n attributeName,\r\n attributeValue\r\n );\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n const scopeNodeTest = isSvg(scopeElement)\r\n ? `*[local-name()='${scopeElement.tagName}' and ${condition}]`\r\n : `${scopeElement.tagName}[${condition}]`;\r\n // Prefer a labelled semantic descendant scope before accepting an indexed structural tail like DIV/DIV[2]/LABEL.\r\n const scopedXpath = `//${referenceXpath}/${relation}::${scopeNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n // Accept the semantic version only when it uniquely resolves to the same target.\r\n if (getCountOfXPath(scopedXpath, element2, docmt) === 1) {\r\n return scopedXpath;\r\n }\r\n }\r\n\r\n scopeElement = scopeElement.parentElement;\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getFirstElementByXpath = (xpath: string, docmt: Document) => {\r\n try {\r\n const result = docmt.evaluate(\r\n xpath,\r\n docmt,\r\n null,\r\n XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n ).singleNodeValue;\r\n\r\n return result instanceof Element ? result : null;\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\nconst doesReferenceXpathMatchElement = (\r\n xpathValue: string,\r\n element: HTMLElement | Element\r\n) => {\r\n const referenceXpath = stripXpathPrefix(xpathValue);\r\n if (!referenceXpath) {\r\n return false;\r\n }\r\n\r\n try {\r\n const result = element.ownerDocument.evaluate(\r\n `//${replaceActualAttributes(referenceXpath, element)}`,\r\n element.ownerDocument,\r\n null,\r\n XPathResult.ORDERED_NODE_ITERATOR_TYPE,\r\n null\r\n );\r\n let node = result.iterateNext();\r\n\r\n while (node) {\r\n if (node === element) {\r\n return true;\r\n }\r\n node = result.iterateNext();\r\n }\r\n } catch {\r\n return false;\r\n }\r\n\r\n return false;\r\n};\r\n\r\n// Semantic bridge for ancestor and ancestor-or-self icon targets only:\r\n// reference/ancestor::shared-scope/descendant::icon/ancestor::target-wrapper.\r\nconst getBridgeClassNodeTests = (element: Element) => {\r\n const classConditions = getClassTokenConditions(\r\n element,\r\n element.getAttribute(\"class\"),\r\n (element.getRootNode?.() as Document | ShadowRoot | null) ??\r\n element.ownerDocument\r\n );\r\n\r\n // Icon ancestor bridges also use the shared class-token ordering: numeric\r\n // tokens are blocked, while the remaining stable tokens are tried in order.\r\n return classConditions.map(\r\n (condition) => `${element.tagName.toLowerCase()}[${condition}]`\r\n );\r\n};\r\n\r\nconst getIconNodeTest = (iconElement: Element) => {\r\n const fill = iconElement.getAttribute(\"fill\");\r\n const stroke = iconElement.getAttribute(\"stroke\");\r\n if (/\\d/.test(fill || \"\") || /\\d/.test(stroke || \"\")) {\r\n // Strict numeric-attribute validation also applies to SVG icon attributes.\r\n return \"\";\r\n }\r\n\r\n const condition = fill\r\n ? `@fill=${escapeCharacters(fill)}`\r\n : stroke\r\n ? `@stroke=${escapeCharacters(stroke)}`\r\n : \"\";\r\n\r\n return condition\r\n ? `*[local-name()='${iconElement.tagName.toLowerCase()}' and ${condition}]`\r\n : \"\";\r\n};\r\n\r\nconst isUniqueIconAncestorBridge = (\r\n root: Element,\r\n iconElement: Element,\r\n targetElement: Element\r\n) => {\r\n const fill = iconElement.getAttribute(\"fill\");\r\n const stroke = iconElement.getAttribute(\"stroke\");\r\n const icons = Array.from(\r\n root.querySelectorAll(iconElement.tagName.toLowerCase())\r\n ).slice(0, 30);\r\n let matches = 0;\r\n\r\n for (const icon of icons) {\r\n if (\r\n (fill && icon.getAttribute(\"fill\") !== fill) ||\r\n (!fill && stroke && icon.getAttribute(\"stroke\") !== stroke)\r\n ) {\r\n continue;\r\n }\r\n\r\n const targetCandidate = icon.closest(targetElement.tagName.toLowerCase());\r\n if (targetCandidate) {\r\n matches++;\r\n if (targetCandidate !== targetElement || matches > 1) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n return matches === 1;\r\n};\r\n\r\nconst getIconAncestorBridgeXpath = (\r\n referenceXpath: string,\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n commonAncestor: Element,\r\n relation: \"ancestor\" | \"ancestor-or-self\"\r\n) => {\r\n const iconDescendants = Array.from(\r\n element2.querySelectorAll(\"path,use,circle,rect,polygon,polyline,line\")\r\n ).slice(0, 25);\r\n\r\n if (!iconDescendants.length) {\r\n return \"\";\r\n }\r\n\r\n const ancestorNodeTests = [\r\n ...getBridgeClassNodeTests(commonAncestor),\r\n commonAncestor.tagName\r\n ];\r\n\r\n for (const iconElement of iconDescendants) {\r\n const iconNodeTest = getIconNodeTest(iconElement);\r\n if (!iconNodeTest) {\r\n continue;\r\n }\r\n\r\n // Bounded icon-wrapper fallback: reference -> shared ancestor -> distinctive icon -> target wrapper.\r\n // This runs before structural/index fallbacks and avoids scanning outside the shared ancestor.\r\n if (!isUniqueIconAncestorBridge(commonAncestor, iconElement, element2)) {\r\n continue;\r\n }\r\n\r\n for (const ancestorNodeTest of ancestorNodeTests) {\r\n return `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/descendant::${iconNodeTest}/ancestor::${element2.tagName.toLowerCase()}`;\r\n }\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getAncestorBridgeXpath = (\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: \"ancestor\" | \"ancestor-or-self\",\r\n xpaths1: { key: string; value: string }[],\r\n xpaths2: { key: string; value: string }[],\r\n isIndex: boolean\r\n) => {\r\n const finalXpaths: { key: string; value: string }[] = [];\r\n const commonAncestor = getCommonAncestor(element1, element2);\r\n\r\n if (!commonAncestor || commonAncestor === element2) {\r\n return finalXpaths;\r\n }\r\n\r\n const ancestorNodeTest = isSvg(commonAncestor)\r\n ? `*[local-name()='${commonAncestor.tagName}']`\r\n : commonAncestor.tagName;\r\n // Build the old structural path from the nearest common ancestor to the target; kept as fallback.\r\n const targetRelativeXpath = getRelativeXpathFromAncestor(\r\n commonAncestor,\r\n element2,\r\n xpaths2\r\n );\r\n\r\n if (!targetRelativeXpath) {\r\n return finalXpaths;\r\n }\r\n\r\n const targetRelativeSteps = targetRelativeXpath.split(xpathStepSeparator);\r\n const shouldUseTargetAxis = targetRelativeSteps.length > 1;\r\n // When the target path has multiple steps, prefer a single target descriptor under a relational axis.\r\n const targetAxisXpath = shouldUseTargetAxis\r\n ? getSingleStepXpath(element2, xpaths2)\r\n : \"\";\r\n // This is now part of the normal flow: prefer semantic containers before generic ancestor::DIV.\r\n const semanticAncestorNodeTest = targetAxisXpath\r\n ? getSemanticAncestorNodeTest(commonAncestor, element2)\r\n : \"\";\r\n\r\n for (const xpath of xpaths1) {\r\n const referenceXpath = stripXpathPrefix(xpath.value);\r\n\r\n if (!referenceXpath) {\r\n continue;\r\n }\r\n\r\n if (semanticAncestorNodeTest) {\r\n // Try semantic ancestor first so a unique generic ancestor::DIV can become a readable section-scoped relation.\r\n const semanticAncestorXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${semanticAncestorNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n if (\r\n getCountOfXPath(semanticAncestorXpath, element2, element2.ownerDocument) ===\r\n 1\r\n ) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(semanticAncestorXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n\r\n // Fallback to the original common-ancestor bridge when no semantic ancestor uniquely resolves the target.\r\n let finalExpectedElementXpath: string | undefined =\r\n targetAxisXpath\r\n ? `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`\r\n : `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/${targetRelativeXpath}`;\r\n\t let rel_count = getCountOfXPath(\r\n\t finalExpectedElementXpath,\r\n\t element2,\r\n\t element2.ownerDocument\r\n\t );\r\n\t\r\n const iconBridgeXpath = getIconAncestorBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n commonAncestor,\r\n relation\r\n );\r\n\r\n if (iconBridgeXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} icon bridge`,\r\n value: replaceTempAttributes(iconBridgeXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n\t if (rel_count === 1) {\r\n\t finalXpaths.push({\r\n\t key: `dynamic ${relation} bridge`,\r\n\t value: replaceTempAttributes(finalExpectedElementXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n if (targetAxisXpath && rel_count > 1) {\r\n // Try a labelled/semantic descendant scope before structural fallback; this keeps XPath readable without returning a non-unique locator.\r\n const scopedXpath = getSemanticScopedBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n commonAncestor,\r\n relation,\r\n ancestorNodeTest,\r\n targetAxisXpath\r\n );\r\n\r\n if (scopedXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(scopedXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n // Last non-index bridge attempt: keep the original structural tail when the axis-only target was too broad.\r\n finalExpectedElementXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/${targetRelativeXpath}`;\r\n rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n element2,\r\n element2.ownerDocument\r\n );\r\n\r\n if (rel_count === 1) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n\r\n if (rel_count > 1 && isIndex) {\r\n finalExpectedElementXpath = findXpathWithIndex(\r\n finalExpectedElementXpath,\r\n element2,\r\n element2.ownerDocument,\r\n rel_count\r\n );\r\n rel_count = finalExpectedElementXpath\r\n ? getCountOfXPath(\r\n finalExpectedElementXpath,\r\n element2,\r\n element2.ownerDocument\r\n )\r\n : 0;\r\n\r\n if (finalExpectedElementXpath && rel_count === 1) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge index`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n }\r\n\r\n return finalXpaths;\r\n};\r\n\r\nconst getReferenceElementXpath = (element: HTMLElement | Element) => {\r\n let xpaths1: {\r\n key: string;\r\n value: string;\r\n }[] = [];\r\n\r\n xpaths1 = parseDOM(element, element.ownerDocument, false, false);\r\n\r\n const referenceElementXpaths = getReferenceElementsXpath(\r\n element,\r\n element.ownerDocument,\r\n false\r\n );\r\n if (referenceElementXpaths?.length) {\r\n xpaths1 = xpaths1?.length\r\n ? xpaths1.concat(referenceElementXpaths)\r\n : referenceElementXpaths;\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n xpaths1 = parseDOM(element, element.ownerDocument, true, false);\r\n xpaths1 = xpaths1?.map((x) =>\r\n x.value.charAt(0) == \"(\" &&\r\n findMatchingParenthesis(x.value, 0) + 1 === x.value.lastIndexOf(\"[\")\r\n ? { key: \"\", value: removeParenthesis(x.value) }\r\n : { key: \"\", value: x.value }\r\n );\r\n } else {\r\n let xpaths = parseDOM(element, element.ownerDocument, true, false);\r\n if (xpaths?.length) {\r\n xpaths = xpaths?.map((x) =>\r\n x.value.charAt(0) == \"(\" &&\r\n findMatchingParenthesis(x.value, 0) + 1 === x.value.lastIndexOf(\"[\")\r\n ? { key: \"\", value: removeParenthesis(x.value) }\r\n : { key: \"\", value: x.value }\r\n );\r\n xpaths1 = xpaths1.concat(xpaths);\r\n }\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n xpaths1 = [\r\n {\r\n key: \"\",\r\n value: getRelativeXPath(\r\n element,\r\n element.ownerDocument,\r\n false,\r\n false,\r\n Array.from(element.attributes)\r\n )\r\n }\r\n ];\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n xpaths1 = [\r\n {\r\n key: \"\",\r\n value: getRelativeXPath(\r\n element,\r\n element.ownerDocument,\r\n true,\r\n false,\r\n Array.from(element.attributes)\r\n )\r\n }\r\n ];\r\n xpaths1 = xpaths1?.map((x) =>\r\n x.value.charAt(0) == \"(\" &&\r\n findMatchingParenthesis(x.value, 0) + 1 === x.value.lastIndexOf(\"[\")\r\n ? { key: \"\", value: removeParenthesis(x.value) }\r\n : { key: \"\", value: x.value }\r\n );\r\n }\r\n\r\n const childAnchorXpaths = Array.from(element.children || [])\r\n .map((child) => {\r\n const childText = getTextContent(child)?.trim();\r\n\r\n if (!childText || childText !== getTextContent(element)?.trim()) {\r\n return null;\r\n }\r\n\r\n const containerTextCondition = getContainerTextCondition(child, childText);\r\n const childTextCondition = containerTextCondition\r\n ? containerTextCondition\r\n : /\\s/.test(childText)\r\n ? `normalize-space(.)=${escapeCharacters(replaceWhiteSpaces(childText))}`\r\n : `.=${escapeCharacters(childText)}`;\r\n\r\n return {\r\n key: \"reference child text\",\r\n value: `${child.tagName}[${childTextCondition}]`\r\n };\r\n })\r\n .filter((xpath): xpath is { key: string; value: string } => !!xpath);\r\n\r\n if (childAnchorXpaths.length) {\r\n xpaths1 = childAnchorXpaths.concat(xpaths1);\r\n }\r\n\r\n const referenceXpathElement = getAbsoluteXPath(\r\n element,\r\n element.ownerDocument\r\n );\r\n xpaths1 = xpaths1.filter((x) => x.value !== referenceXpathElement);\r\n\r\n xpaths1.push({\r\n key: \"absolute xpath\",\r\n value: referenceXpathElement.slice(1)\r\n });\r\n\r\n return xpaths1;\r\n};\r\n\r\nconst getTraverseXpathExpression = (\r\n xpathe1: string,\r\n absoluteXpathElements: string[],\r\n element2: HTMLElement | Element,\r\n refExpectElement: Array<HTMLElement | Element>,\r\n docmt: Node,\r\n relation: string,\r\n isIndex: boolean,\r\n multiElementReferenceMode: boolean\r\n) => {\r\n let finalExpectedElementXpath: string | undefined;\r\n if (!multiElementReferenceMode) {\r\n for (let x = 1; x <= absoluteXpathElements.length; x++) {\r\n const xpath2Candidates = replaceTrailingTargetClassWithTokenXpaths(\r\n absoluteXpathElements\r\n .slice(absoluteXpathElements.length - x, absoluteXpathElements.length)\r\n .join(\"/\"),\r\n element2\r\n );\r\n\r\n for (const xpath2 of xpath2Candidates) {\r\n finalExpectedElementXpath = `//${xpathe1}/${relation}::${replaceActualAttributes(\r\n xpath2,\r\n element2\r\n )}`;\r\n const rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n element2,\r\n docmt\r\n );\r\n if (rel_count === 1) {\r\n // A unique candidate can still be brittle if uniqueness came from an indexed/structural tail.\r\n const hasStructuralTail =\r\n xpath2.split(xpathStepSeparator).length > 1 ||\r\n /\\[\\d+\\]/.test(xpath2);\r\n if (hasStructuralTail) {\r\n // Descendant mode can otherwise return absolute-looking tails; try a semantic scope first when it stays unique.\r\n const scopedXpath = getSemanticScopedDescendantXpath(\r\n xpathe1,\r\n relation,\r\n element2,\r\n docmt\r\n );\r\n\r\n if (scopedXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(scopedXpath)\r\n }\r\n ];\r\n }\r\n }\r\n\r\n // No better semantic scope was found, so preserve the existing unique generated XPath.\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n if (rel_count > 1) {\r\n const semanticTargetXpath = getDirectSemanticDescendantXpath(\r\n xpathe1,\r\n relation,\r\n element2,\r\n parseDOM(element2, element2.ownerDocument, false, false) || [],\r\n docmt\r\n );\r\n\r\n if (semanticTargetXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(semanticTargetXpath)\r\n }\r\n ];\r\n }\r\n\r\n // Before adding an index, see whether a nearby semantic container can narrow the descendant target.\r\n const scopedXpath = getSemanticScopedDescendantXpath(\r\n xpathe1,\r\n relation,\r\n element2,\r\n docmt\r\n );\r\n\r\n if (scopedXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(scopedXpath)\r\n }\r\n ];\r\n }\r\n\r\n if (isIndex) {\r\n // Semantic scoping failed; continue with the existing index fallback behavior.\r\n finalExpectedElementXpath = findXpathWithIndex(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt,\r\n rel_count\r\n );\r\n if (finalExpectedElementXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}${isIndex ? \" index\" : \"\"}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } else {\r\n const xpath2 = absoluteXpathElements.join(\"/\");\r\n finalExpectedElementXpath = `//${xpathe1}/${relation}::${replaceActualAttributes(\r\n xpath2,\r\n element2\r\n )}`;\r\n const rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n element2,\r\n docmt\r\n );\r\n if (rel_count === 1) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n if (rel_count > 1) {\r\n if (isIndex) {\r\n finalExpectedElementXpath = findXpathWithIndex(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt,\r\n rel_count\r\n );\r\n if (finalExpectedElementXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}${isIndex ? \" index\" : \"\"}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n }\r\n }\r\n }\r\n};\r\n\r\nconst replaceTrailingTargetClassWithTokenXpaths = (\r\n xpath: string,\r\n element: HTMLElement | Element\r\n) => {\r\n const classValue = element.getAttribute(\"class\") || \"\";\r\n const classConditions = getClassTokenConditions(\r\n element,\r\n classValue,\r\n (element.getRootNode?.() as Document | ShadowRoot | null) ??\r\n element.ownerDocument\r\n );\r\n\r\n if (!classConditions.length) {\r\n return [xpath];\r\n }\r\n\r\n const exactClassStep = `${element.tagName}[@class=${escapeCharacters(\r\n classValue\r\n )}]`;\r\n\r\n if (!xpath.endsWith(exactClassStep)) {\r\n return [xpath];\r\n }\r\n\r\n // Structural tails are still allowed here, but the final target step should\r\n // follow the shared class rule and try every stable token before indexed\r\n // fallback is considered.\r\n return classConditions.map((classCondition) => {\r\n const replacementStep = `${element.tagName}[${classCondition}]`;\r\n return `${xpath.slice(0, -exactClassStep.length)}${replacementStep}`;\r\n });\r\n};\r\n\r\nexport const getSmartRelations = (\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element\r\n) => {\r\n const pos = element1.compareDocumentPosition(element2);\r\n\r\n const highPriority: string[] = [];\r\n const mediumPriority: string[] = [];\r\n const lowPriority: string[] = [];\r\n\r\n // Ancestor\r\n if (pos & Node.DOCUMENT_POSITION_CONTAINS) {\r\n highPriority.push(\"ancestor\", \"ancestor-or-self\", \"parent\");\r\n }\r\n\r\n // Descendant direct\r\n if (pos & Node.DOCUMENT_POSITION_CONTAINED_BY) {\r\n highPriority.push(\"child\");\r\n }\r\n\r\n // Siblings\r\n if (element1.parentElement === element2.parentElement) {\r\n highPriority.push(\"following-sibling\", \"preceding-sibling\");\r\n }\r\n\r\n // Directional\r\n if (pos & Node.DOCUMENT_POSITION_FOLLOWING) {\r\n mediumPriority.push(\"following\");\r\n }\r\n\r\n if (pos & Node.DOCUMENT_POSITION_PRECEDING) {\r\n mediumPriority.push(\"preceding\");\r\n }\r\n\r\n // always include fallback\r\n lowPriority.push(\"descendant\", \"descendant-or-self\");\r\n\r\n const relations = [...highPriority, ...mediumPriority, ...lowPriority];\r\n\r\n return [...new Set(relations)];\r\n};\r\nconst referenceXpath = {\r\n findRelativeXpath,\r\n getDescendantXpath,\r\n getAncestorBridgeXpath,\r\n getXpathRelationExpression,\r\n getTraverseXpathExpression,\r\n getReferenceElementXpath,\r\n getSmartRelations\r\n};\r\nexport default referenceXpath;\r\n","import { SelectorMode } from \"../types/locator.ts\";\r\nimport { isNumberExist } from \"./xpathHelpers.ts\";\r\n\r\nlet modifiedElementAttributes: [] = [];\r\n\r\nconst escapeCssAttributeValue = (value: string): string => {\r\n return String(value).replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\r\n};\r\n\r\nconst isCssSelectorUnique = (\r\n selector: string,\r\n el: Element,\r\n root: Document | ShadowRoot | ParentNode\r\n): boolean => {\r\n try {\r\n const matches = root.querySelectorAll(selector);\r\n return matches.length === 1 && matches[0] === el;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n\r\nexport const parseCssSelectors = (\r\n el: Element,\r\n mode: SelectorMode = \"single\"\r\n) => {\r\n const selectors: { key: string; value: string }[] = [];\r\n const root = el.getRootNode() as Document | ShadowRoot;\r\n\r\n try {\r\n const idPath = getIdCssPath(el);\r\n if (idPath && isCssSelectorUnique(idPath, el, root)) {\r\n selectors.push({ key: \"cssSelector by id\", value: idPath });\r\n if (mode === \"single\") return selectors;\r\n }\r\n const classPath = getClassCssPath(el);\r\n if (classPath && isCssSelectorUnique(classPath, el, root)) {\r\n selectors.push({ key: \"cssSelector by class\", value: classPath });\r\n }\r\n const namePath = getAttributeCssPath(el);\r\n if (namePath) {\r\n selectors.push({ key: \"cssSelector by name\", value: namePath });\r\n }\r\n // commented out absolute path strategy as it is not performing well and causing performance issues in large DOMs\r\n // const absPath = getAbsoluteCssPath(el);\r\n // if (absPath && isCssSelectorUnique(absPath, el, root)) {\r\n // selectors.push({ key: 'Absolute cssSelector', value: absPath });\r\n // }\r\n } catch (e) {\r\n console.error(e);\r\n }\r\n return selectors;\r\n};\r\n\r\nexport const getIdCssPath = (el: HTMLElement | Element) => {\r\n const view = el.ownerDocument?.defaultView;\r\n if (!view || !(el instanceof view.Element)) return;\r\n const tagName = el.tagName.toLowerCase();\r\n if (tagName.includes(\"style\") || tagName.includes(\"script\")) return;\r\n\r\n const path = [];\r\n while (el?.nodeType === Node.ELEMENT_NODE) {\r\n let selector = el.nodeName?.toLowerCase();\r\n if (el.id && !isNumberExist(el.id)) {\r\n selector += `#${CSS.escape(el.id)}`;\r\n path.unshift(selector);\r\n break;\r\n } else {\r\n let sib = el;\r\n let nth = 1;\r\n if (sib.previousElementSibling) {\r\n while ((sib = sib.previousElementSibling)) {\r\n if (sib.nodeName?.toLowerCase() === selector) nth++;\r\n }\r\n }\r\n\r\n if (nth !== 1) {\r\n selector += `:nth-of-type(${nth})`;\r\n }\r\n\r\n if (nth === 1 && sib?.parentElement?.childElementCount! > 1) {\r\n selector += `:nth-child(${nth})`;\r\n }\r\n }\r\n path.unshift(selector);\r\n el = el.parentElement!;\r\n }\r\n return path.join(\" > \");\r\n};\r\n\r\nconst EXCLUDED_ATTRS = new Set([\"id\", \"class\", \"style\"]);\r\nfunction getAttributeSelectors(el: Element): string[] {\r\n return Array.from(el.attributes)\r\n .filter(\r\n (attr) =>\r\n !EXCLUDED_ATTRS.has(attr?.name?.toLowerCase()) &&\r\n attr.value &&\r\n !isNumberExist(attr.value)\r\n )\r\n .map((attr) => `[${attr.name}=\"${escapeCssAttributeValue(attr.value)}\"]`);\r\n}\r\n\r\nexport const getAttributeCssPath = (el: Element): string | undefined => {\r\n const view = el.ownerDocument?.defaultView;\r\n if (!view || !(el instanceof view.Element)) return;\r\n\r\n const root = el.getRootNode() as ParentNode;\r\n const tag = el.tagName.toLowerCase();\r\n\r\n if (tag === \"style\" || tag === \"script\") return;\r\n\r\n const attrSelectors = getAttributeSelectors(el);\r\n\r\n for (const attrSelector of attrSelectors) {\r\n const candidate = `${tag}${attrSelector}`;\r\n\r\n if (isCssSelectorUnique(candidate, el, root)) {\r\n return candidate;\r\n }\r\n }\r\n return;\r\n};\r\n\r\nexport const getClassCssPath = (el: HTMLElement | Element) => {\r\n const view = el.ownerDocument?.defaultView;\r\n if (!view || !(el instanceof view.Element)) return;\r\n const tagName = el.tagName.toLowerCase();\r\n if (tagName.includes(\"style\") || tagName.includes(\"script\")) return;\r\n\r\n const path = [];\r\n while (el?.nodeType === Node.ELEMENT_NODE) {\r\n let selector = el.nodeName?.toLowerCase();\r\n\r\n if (\r\n typeof el.className === \"string\" &&\r\n el.className &&\r\n !isNumberExist(el.className) &&\r\n !modifiedElementAttributes?.find(\r\n (x: { element: HTMLElement | Element; attributeName: string }) =>\r\n x.element === el && x.attributeName === \"class\"\r\n )\r\n ) {\r\n el.classList.remove(\"marked-element-temp\");\r\n el.classList.remove(\"removePointers\");\r\n if (el.className) {\r\n selector += `.${el.className.trim().replace(/\\s+/g, \".\")}`;\r\n path.unshift(selector);\r\n break;\r\n }\r\n } else {\r\n let sib = el;\r\n let nth = 1;\r\n if (sib.previousElementSibling) {\r\n while ((sib = sib.previousElementSibling)) {\r\n if (sib.nodeName?.toLowerCase() === selector) nth++;\r\n }\r\n }\r\n\r\n if (nth !== 1) {\r\n selector += `:nth-of-type(${nth})`;\r\n }\r\n\r\n if (nth === 1 && sib?.parentElement?.childElementCount! > 1) {\r\n selector += `:nth-child(${nth})`;\r\n }\r\n }\r\n path.unshift(selector);\r\n el = el.parentElement!;\r\n }\r\n return path.join(\" > \");\r\n};\r\n\r\nexport const getAbsoluteCssPath = (el: Element) => {\r\n const view = el.ownerDocument?.defaultView;\r\n if (!view || !(el instanceof view.Element)) return;\r\n\r\n const path: string[] = [];\r\n\r\n while (el && el.nodeType === Node.ELEMENT_NODE) {\r\n const tagName = el.tagName.toLowerCase();\r\n\r\n if (tagName === \"style\" || tagName === \"script\") return;\r\n\r\n let selector = tagName;\r\n\r\n const parent = el.parentNode;\r\n\r\n if (parent) {\r\n const siblings = Array.from(parent.children).filter(\r\n (c) => c.tagName === el.tagName\r\n );\r\n\r\n if (siblings.length > 1) {\r\n selector += `:nth-of-type(${siblings.indexOf(el) + 1})`;\r\n }\r\n }\r\n\r\n path.unshift(selector);\r\n\r\n el = el.parentElement!;\r\n }\r\n\r\n return path.join(\" > \");\r\n};\r\n\r\nexport const cssSelectors = {\r\n parseCssSelectors,\r\n getIdCssPath,\r\n getAttributeCssPath,\r\n getClassCssPath,\r\n getAbsoluteCssPath\r\n};\r\n","import { ElementRecord, Locator } from \"../types/locator.ts\";\r\nimport { parseDOM } from \"./xpath.ts\";\r\nimport { parseCssSelectors } from \"./cssSelector.ts\";\r\nimport {\r\n isNumberExist,\r\n normalizeXPath,\r\n getXPathPattern,\r\n escapeAttrValue,\r\n isUniqueInDOM,\r\n shouldUseSnapshot\r\n} from \"./xpathHelpers.ts\";\r\n\r\nconst isSameXPathStillValid = (\r\n xpath: string,\r\n docmt: Document,\r\n target: Element\r\n): boolean => {\r\n const normalized = normalizeXPath(xpath);\r\n const found = getElementFromXPath(docmt, normalized);\r\n if (found === target) return true;\r\n\r\n if (shouldUseSnapshot(normalized)) {\r\n const result = docmt.evaluate(\r\n normalized,\r\n docmt,\r\n null,\r\n XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,\r\n null\r\n );\r\n\r\n for (let i = 0; i < result.snapshotLength; i++) {\r\n if (result.snapshotItem(i) === target) return true;\r\n }\r\n }\r\n\r\n return false;\r\n};\r\n\r\nconst getElementFromCssSelector = (\r\n docmt: Document,\r\n selector: string\r\n): Element | null => {\r\n try {\r\n const found = docmt.querySelector(selector);\r\n if (found) return found;\r\n } catch (error) {\r\n console.error(\"Invalid CSS selector:\", selector, error);\r\n return null;\r\n }\r\n\r\n return getElementFromShadowRoot(docmt.body, selector);\r\n};\r\n\r\nconst isSameCssSelectorStillValid = (\r\n selector: string,\r\n docmt: Document,\r\n target: Element\r\n): boolean => {\r\n return getElementFromCssSelector(docmt, selector) === target;\r\n};\r\n\r\nconst resolveIsSelfHealed = (\r\n locName: string,\r\n oldValue: string | null | undefined,\r\n newValue: string | null | undefined\r\n): \"Y\" | null => {\r\n if (!oldValue || !newValue) return \"Y\";\r\n return oldValue === newValue ? null : \"Y\";\r\n};\r\n\r\nconst isCssSelectorLocator = (locator: { name?: string | null }): boolean => {\r\n return locator.name?.toLowerCase().includes(\"cssselector\") ?? false;\r\n};\r\n\r\ntype ElementDetails = {\r\n id?: string | null;\r\n className?: string | null;\r\n xpathByText?: string | null;\r\n xpathById?: string | null;\r\n xpathByClass?: string | null;\r\n xpathAbsolute?: string | null;\r\n xpathByName?: string | null;\r\n xpathByPlaceholder?: string | null;\r\n xpathByType?: string | null;\r\n visibleText?: string | null;\r\n relativeXpath?: string | null;\r\n [key: string]: any;\r\n};\r\n\r\nconst getElementFromShadowRoot = (\r\n el: Element | ShadowRoot,\r\n selector: string\r\n): Element | null => {\r\n // const shadowRoot = (element as HTMLElement).shadowRoot;\r\n // if (shadowRoot && !selector.includes(\"dynamic\")) {\r\n // return shadowRoot.querySelector(selector);\r\n // }\r\n\r\n const elements = Array.from(el.querySelectorAll(\"*\"));\r\n\r\n try {\r\n for (let i = 0; i < elements.length; i++) {\r\n if (elements[i].shadowRoot) {\r\n const { shadowRoot } = elements[i];\r\n if (shadowRoot) {\r\n const nestedElement = getElementFromShadowRoot(shadowRoot, selector);\r\n if (nestedElement) {\r\n return nestedElement;\r\n }\r\n if (shadowRoot && !selector.includes(\"dynamic\")) {\r\n return shadowRoot.querySelector(selector);\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n return null;\r\n};\r\n\r\nconst getId = (element: Element | null): string | null => {\r\n return element?.id || null;\r\n};\r\n\r\nconst getClassName = (element: Element): string | null => {\r\n return (element as HTMLElement).className || null;\r\n};\r\n\r\nconst getVisibleText = (element: Element): string | null => {\r\n return element.textContent?.trim() || null;\r\n};\r\n\r\nconst getName = (element: Element): string | null => {\r\n const elementEl = element as HTMLElement;\r\n\r\n if (elementEl.hasAttribute(\"name\")) {\r\n const attrValue = elementEl.getAttribute(\"name\");\r\n const name = `${attrValue}`;\r\n return name || null;\r\n }\r\n return null;\r\n};\r\n\r\nconst relations: string[] = [\r\n \"/preceding-sibling\",\r\n \"/following-sibling\",\r\n \"/parent\",\r\n \"/descendant\",\r\n \"/ancestor\",\r\n \"/self\",\r\n \"/ancestor-or-self\",\r\n \"/child\",\r\n \"/preceding\",\r\n \"/following\"\r\n];\r\n\r\nfunction getElementFromXPath(docmt: Document, xpath: string): Element | null {\r\n const window = docmt.defaultView;\r\n if (!window) return null;\r\n\r\n const xpathEvaluator = new window.XPathEvaluator();\r\n const xpathResult = xpathEvaluator.evaluate(\r\n xpath,\r\n docmt,\r\n null,\r\n window.XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n return xpathResult.singleNodeValue as Element | null;\r\n}\r\n\r\nfunction checkReferenceElementIsValid(\r\n locator: string,\r\n relation: string,\r\n docmt: Document\r\n): string | null {\r\n if (locator.includes(relation)) {\r\n const locatotSplitArray: string[] = locator.split(relation);\r\n const sourceLoc = locatotSplitArray[0].trim();\r\n const window = docmt.defaultView;\r\n if (!window) return null;\r\n if (!locator.includes(\"dynamic\")) {\r\n const xpathEvaluator = new window.XPathEvaluator();\r\n const xpathResult = xpathEvaluator.evaluate(\r\n sourceLoc,\r\n docmt,\r\n null,\r\n window.XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n\r\n const sourceElement = xpathResult.singleNodeValue;\r\n if (sourceElement) {\r\n const xpathResultComplete = xpathEvaluator.evaluate(\r\n locator,\r\n docmt,\r\n null,\r\n window.XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n const completeElement = xpathResultComplete.singleNodeValue;\r\n let relativeXpath: string;\r\n if (completeElement) {\r\n relativeXpath = locator;\r\n return relativeXpath;\r\n } else {\r\n console.error(\"Complete Locator is Invalid:\", locator);\r\n relativeXpath = locator;\r\n return relativeXpath;\r\n }\r\n } else {\r\n console.error(\"Source Locator Not Found:\", sourceLoc);\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nconst getElementsFromHTML = (\r\n record: ElementRecord,\r\n docmt: Document\r\n): ElementDetails | null => {\r\n const elementsToRemove = docmt.querySelectorAll(\r\n \"script, style, link[rel='stylesheet'], meta, noscript, embed, object, param, source, svg\"\r\n );\r\n\r\n if (elementsToRemove) {\r\n elementsToRemove.forEach((tag) => {\r\n (tag as Element).remove();\r\n });\r\n }\r\n\r\n const finalLocatorsSet: Set<string> = new Set();\r\n let finalLocators: any[] = [];\r\n\r\n function createLocator(base: any, overrides: Partial<any> = {}) {\r\n const oldValue = base?.value;\r\n const newValue = overrides.value ?? base?.value;\r\n const newLocator: any = {\r\n name: overrides.name ?? base?.name,\r\n type: overrides.type ?? base?.type,\r\n value: overrides.value ?? base?.value,\r\n reference: overrides.reference ?? base?.reference,\r\n status: overrides.status ?? base?.status,\r\n isRecorded: overrides.isRecorded ?? base?.isRecorded\r\n };\r\n\r\n const previousSelfHealed = base?.isSelfHealed === \"Y\";\r\n\r\n newLocator.isSelfHealed = previousSelfHealed\r\n ? \"Y\"\r\n : overrides.hasOwnProperty(\"isSelfHealed\")\r\n ? overrides.isSelfHealed\r\n : resolveIsSelfHealed(newLocator.name, oldValue, newValue);\r\n\r\n pushUniqueLocator(newLocator);\r\n }\r\n\r\n function resolveElement(\r\n ctx: Document,\r\n locator: any,\r\n selector: string\r\n ): Element | null {\r\n if (isCssSelectorLocator(locator)) {\r\n return getElementFromCssSelector(ctx, selector);\r\n } else if (locator.name.includes(\"id\") || selector.startsWith(\"#\")) {\r\n return ctx.querySelector(\"#\" + escapeAttrValue(selector));\r\n } else if (locator.name.includes(\"className\") || selector.startsWith(\".\")) {\r\n return ctx.querySelector(\".\" + selector);\r\n } else if (locator.name === \"name\") {\r\n const safeName = escapeAttrValue(selector);\r\n return ctx.querySelector(`[name=\"${safeName}\"]`);\r\n } else if (locator.name === \"tagName\") {\r\n return ctx.querySelector(selector);\r\n } else if (locator.name === \"linkText\") {\r\n return (\r\n Array.from(ctx.querySelectorAll(\"a\")).find(\r\n (a) => a.textContent?.trim() === selector\r\n ) || null\r\n );\r\n } else if (locator.name === \"partialLinkText\") {\r\n return (\r\n Array.from(ctx.querySelectorAll(\"a\")).find((a) =>\r\n a.textContent?.includes(selector)\r\n ) || null\r\n );\r\n } else if (\r\n (locator.name.includes(\"xpath\") || selector.startsWith(\"//\")) &&\r\n !locator.type.match(\"dynamic\")\r\n ) {\r\n const normalizedXPath = normalizeXPath(selector);\r\n const el = getElementFromXPath(ctx, normalizedXPath);\r\n\r\n if (el) {\r\n createLocator(locator, {\r\n value: selector,\r\n isRecorded: String(locator.isRecorded).includes(\"N\") ? \"N\" : \"Y\"\r\n });\r\n }\r\n\r\n return el;\r\n } else {\r\n return ctx.querySelector(selector);\r\n }\r\n }\r\n\r\n function findInIframes(\r\n docmt: Document,\r\n locator: any,\r\n selector: string\r\n ): Element | null {\r\n const iframes = docmt.querySelectorAll(\"iframe\");\r\n\r\n for (const iframe of iframes) {\r\n try {\r\n const iframeDoc =\r\n iframe.contentDocument || iframe.contentWindow?.document;\r\n\r\n if (!iframeDoc) continue;\r\n\r\n const el = resolveElement(iframeDoc, locator, selector);\r\n if (el) return el;\r\n } catch {\r\n continue;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n function pushUniqueLocator(obj: any) {\r\n const key = `${obj.name}:${obj.value}`;\r\n if (!finalLocatorsSet.has(key)) {\r\n finalLocatorsSet.add(key);\r\n finalLocators.push(obj);\r\n }\r\n }\r\n\r\n /** Locator Value Cleaner (Handles Special Scenarios) **/\r\n const cleanLocatorValue = (\r\n val: string | null | undefined,\r\n type?: string,\r\n isRecorded?: string\r\n ): string | null => {\r\n if (!val) return null;\r\n\r\n let cleaned = val.trim();\r\n\r\n // Return null for empty or literal \"null\"\r\n if (!cleaned || cleaned.toLowerCase() === \"null\") return null;\r\n\r\n // Unescape any escaped quotes\r\n cleaned = cleaned.replace(/\\\\\"/g, '\"').replace(/\\\\'/g, \"'\");\r\n\r\n // Remove surrounding single or double quotes\r\n cleaned = cleaned.replace(/^['\"](.+?)['\"]$/, \"$1\");\r\n\r\n // Replace double single quotes with a single quote inside XPath\r\n cleaned = cleaned.replace(/''/g, \"'\");\r\n\r\n // Normalize double quotes in XPath attribute selectors [@id=\"\" -> [@id='']\r\n cleaned = cleaned.replace(\r\n /\\[@(id|name)=['\"]{2}(.+?)['\"]{2}\\]/g,\r\n \"[@$1='$2']\"\r\n );\r\n\r\n // For DOM selectors (id or name), remove ALL quotes\r\n if (type === \"id\" || type === \"name\") {\r\n cleaned = cleaned.replace(/['\"]/g, \"\").trim();\r\n }\r\n\r\n if (type === \"xpath\" && isRecorded === \"Y\" && !val.startsWith(\"//\"))\r\n return null;\r\n\r\n // Final check for empty strings\r\n if (!cleaned || /^['\"]{2}$/.test(cleaned)) return null;\r\n\r\n return cleaned;\r\n };\r\n\r\n locators: for (const locator of record.locators) {\r\n try {\r\n const isRecorded = String(locator.isRecorded || \"\");\r\n const recordedNLocators = record.locators.filter(\r\n (l) => l.isRecorded === \"N\"\r\n );\r\n\r\n if (recordedNLocators.length > 0) {\r\n for (const locator of recordedNLocators) {\r\n createLocator(locator);\r\n }\r\n }\r\n\r\n const isDynamic = String(locator.value || locator.type || \"\");\r\n if (\r\n isDynamic.includes(\"dynamic\") ||\r\n isDynamic.match(\"dynamic\") ||\r\n isDynamic.includes(\"{\") ||\r\n isDynamic.includes(\"}\")\r\n ) {\r\n createLocator(locator);\r\n continue;\r\n }\r\n\r\n if (record.isShared.includes(\"Y\")) {\r\n break locators;\r\n }\r\n\r\n try {\r\n let targetElement: Element | null = null;\r\n const selectors = locator.value.split(\">>>\");\r\n\r\n for (const selector of selectors) {\r\n if (!docmt) {\r\n console.error(\"Element not found at:\", selector);\r\n break;\r\n }\r\n\r\n const trimmedSelector = selector.trim();\r\n\r\n //normal DOM\r\n targetElement = resolveElement(docmt, locator, trimmedSelector);\r\n\r\n //iframe (if not found)\r\n if (!targetElement) {\r\n targetElement = findInIframes(docmt, locator, trimmedSelector);\r\n }\r\n\r\n //shadow DOM (if still not found)\r\n if (!targetElement) {\r\n targetElement = getElementFromShadowRoot(\r\n docmt.body,\r\n trimmedSelector\r\n );\r\n }\r\n\r\n if (!targetElement) {\r\n console.error(\"Element not found at:\", trimmedSelector);\r\n break;\r\n }\r\n }\r\n\r\n const locatorExists = (name: string, value: string): boolean => {\r\n const key = `${name}:${value}`;\r\n return finalLocatorsSet.has(key);\r\n };\r\n\r\n if (targetElement) {\r\n const payloadXPaths = record.locators.filter(\r\n (l) => l.name === \"xpath\" && l.value\r\n );\r\n const payloadCssSelectors = record.locators.filter(\r\n (l) => isCssSelectorLocator(l) && l.value\r\n );\r\n\r\n for (const px of payloadXPaths) {\r\n if (isSameXPathStillValid(px.value, docmt, targetElement))\r\n createLocator(px, {\r\n isSelfHealed: null\r\n });\r\n }\r\n\r\n for (const cssLocator of payloadCssSelectors) {\r\n if (\r\n isSameCssSelectorStillValid(\r\n cssLocator.value,\r\n docmt,\r\n targetElement\r\n )\r\n )\r\n createLocator(cssLocator, {\r\n isSelfHealed: null\r\n });\r\n }\r\n\r\n const existingXPaths = finalLocators.filter(\r\n (l) => l.name === \"xpath\" && l.value\r\n );\r\n\r\n // Track XPath patterns already used\r\n const usedXPathPatterns = new Set<string>(\r\n existingXPaths.map((x) => getXPathPattern(x.value))\r\n );\r\n\r\n const excludedAttributes: string[] = [];\r\n const idValue = getId(targetElement);\r\n if (\r\n idValue &&\r\n !locatorExists(\"id\", idValue) &&\r\n !isNumberExist(idValue)\r\n ) {\r\n const prevId = record.locators.find((l) => l.name === \"id\");\r\n if (isUniqueInDOM(docmt, \"id\", idValue, targetElement)) {\r\n excludedAttributes.push(\"id\");\r\n createLocator(prevId, {\r\n name: \"id\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: idValue\r\n });\r\n }\r\n }\r\n\r\n const tagName = targetElement.tagName;\r\n if (tagName && !locatorExists(\"tagName\", tagName)) {\r\n const prevTag = record.locators.find((l) => l.name === \"tagName\");\r\n if (isUniqueInDOM(docmt, \"tagName\", tagName, targetElement)) {\r\n excludedAttributes.push(\"tagName\");\r\n createLocator(prevTag, {\r\n name: \"tagName\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: tagName\r\n });\r\n }\r\n }\r\n\r\n const textValue = getVisibleText(targetElement);\r\n if (textValue && !isNumberExist(textValue)) {\r\n const prevLinkText = record.locators.find(\r\n (l) => l.name === \"linkText\"\r\n );\r\n if (isUniqueInDOM(docmt, \"linkText\", textValue, targetElement)) {\r\n excludedAttributes.push(\"linkText\");\r\n createLocator(prevLinkText, {\r\n name: \"linkText\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: textValue\r\n });\r\n }\r\n }\r\n\r\n const nameLocator = getName(targetElement);\r\n if (\r\n nameLocator &&\r\n !locatorExists(\"name\", nameLocator) &&\r\n !isNumberExist(nameLocator)\r\n ) {\r\n const prevName = record.locators.find((l) => l.name === \"name\");\r\n if (isUniqueInDOM(docmt, \"name\", nameLocator, targetElement)) {\r\n excludedAttributes.push(\"name\");\r\n createLocator(prevName, {\r\n name: \"name\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: nameLocator\r\n });\r\n }\r\n }\r\n\r\n const classValue = getClassName(targetElement);\r\n if (\r\n classValue &&\r\n classValue.trim() !== \"\" &&\r\n !classValue.includes(\" \") &&\r\n !locatorExists(\"className\", classValue) &&\r\n !isNumberExist(classValue)\r\n ) {\r\n const prevClassLocator = record.locators.find(\r\n (l) => l.name === \"className\"\r\n );\r\n if (isUniqueInDOM(docmt, \"className\", classValue, targetElement)) {\r\n excludedAttributes.push(\"className\");\r\n createLocator(prevClassLocator, {\r\n name: \"className\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: classValue\r\n });\r\n }\r\n }\r\n parseCssSelectors(targetElement, \"single\").forEach(\r\n (cssSelector) => {\r\n if (\r\n cssSelector.value &&\r\n !locatorExists(\"cssSelector\", cssSelector.value)\r\n ) {\r\n createLocator(undefined, {\r\n name: \"cssSelector\",\r\n value: cssSelector.value,\r\n type: \"static\",\r\n isRecorded: \"Y\"\r\n });\r\n }\r\n }\r\n );\r\n const allAttributes = Array.from(targetElement.attributes);\r\n const includedAttributes = allAttributes.filter(\r\n (attr) => !excludedAttributes.includes(attr.name)\r\n );\r\n\r\n //If any direct locator is broken then we consider it as broken xpath\r\n\r\n let xpathResults: any[] = [];\r\n try {\r\n xpathResults =\r\n parseDOM(targetElement, docmt, false, true, includedAttributes) ??\r\n [];\r\n } catch (error) {\r\n console.error(\"Error generating XPath candidates:\", error);\r\n }\r\n\r\n if (xpathResults?.length !== 0) {\r\n const brokenPayloadXPaths = payloadXPaths.filter(\r\n (px) => !isSameXPathStillValid(px.value, docmt, targetElement)\r\n );\r\n\r\n let xpathAdded = 0;\r\n\r\n for (const brokenPx of brokenPayloadXPaths) {\r\n if (xpathAdded >= brokenPayloadXPaths.length) break;\r\n\r\n const originalPattern = getXPathPattern(brokenPx.value);\r\n if (usedXPathPatterns.has(originalPattern)) continue;\r\n\r\n const match = xpathResults.find(\r\n (r) => r.value && getXPathPattern(r.value) === originalPattern\r\n );\r\n\r\n if (match?.value) {\r\n createLocator(brokenPx, {\r\n name: \"xpath\",\r\n value: match.value,\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n isSelfHealed: \"Y\"\r\n });\r\n\r\n usedXPathPatterns.add(originalPattern);\r\n xpathAdded++;\r\n }\r\n }\r\n if (xpathAdded < brokenPayloadXPaths.length) {\r\n for (const result of xpathResults) {\r\n if (xpathAdded >= brokenPayloadXPaths.length) break;\r\n if (!result.value) continue;\r\n\r\n const pattern = getXPathPattern(result.value);\r\n if (usedXPathPatterns.has(pattern)) continue;\r\n\r\n createLocator(result, {\r\n name: \"xpath\",\r\n value: result.value,\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n isSelfHealed: \"Y\"\r\n });\r\n\r\n usedXPathPatterns.add(pattern);\r\n xpathAdded++;\r\n }\r\n }\r\n }\r\n for (const locator of record.locators) {\r\n try {\r\n for (const loc of record.locators) {\r\n if (!loc.value) continue;\r\n\r\n for (const relation of relations) {\r\n if (loc.value.includes(relation)) {\r\n const relativeXpath = checkReferenceElementIsValid(\r\n loc.value,\r\n relation,\r\n docmt\r\n );\r\n if (relativeXpath) {\r\n createLocator(loc, {\r\n name: \"xpath\",\r\n value: relativeXpath,\r\n isRecorded:\r\n locator.isRecorded !== \"\" &&\r\n locator.isRecorded !== null\r\n ? locator.isRecorded\r\n : \"Y\"\r\n });\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.error(\"Error processing locator:\", locator, error);\r\n }\r\n }\r\n if (finalLocators.length < 5) {\r\n const fallbackCandidates = [\r\n { name: \"id\", value: getId(targetElement) },\r\n { name: \"name\", value: getName(targetElement) },\r\n { name: \"className\", value: getClassName(targetElement) },\r\n { name: \"tagName\", value: targetElement.tagName },\r\n { name: \"linkText\", value: getVisibleText(targetElement) }\r\n ];\r\n\r\n for (const candidate of fallbackCandidates) {\r\n if (finalLocators.length > 4) break;\r\n\r\n const { name, value } = candidate;\r\n if (!value) continue;\r\n if (isNumberExist(value)) continue;\r\n if (locatorExists(name, value)) continue;\r\n if (name === \"className\" && value.includes(\" \")) continue;\r\n if (isUniqueInDOM(docmt, name, value, targetElement)) {\r\n createLocator(undefined, {\r\n name,\r\n type: \"static\",\r\n value,\r\n isRecorded: \"Y\",\r\n isSelfHealed: \"Y\"\r\n });\r\n }\r\n }\r\n\r\n if (finalLocators.length < 5) {\r\n parseCssSelectors(targetElement, \"multiple\").forEach(\r\n (cssSelector) => {\r\n if (finalLocators.length > 4) return;\r\n if (!cssSelector.value) return;\r\n if (locatorExists(\"cssSelector\", cssSelector.value)) return;\r\n if (\r\n !isUniqueInDOM(\r\n docmt,\r\n \"cssSelector\",\r\n cssSelector.value,\r\n targetElement\r\n )\r\n ) {\r\n return;\r\n }\r\n\r\n createLocator(undefined, {\r\n name: \"cssSelector\",\r\n type: \"static\",\r\n value: cssSelector.value,\r\n isRecorded: \"Y\",\r\n isSelfHealed: \"Y\"\r\n });\r\n }\r\n );\r\n }\r\n }\r\n\r\n const finalAutoHealedLocators = finalLocators.map((obj) => ({\r\n ...obj,\r\n value: cleanLocatorValue(obj.value, obj.name, obj.isRecorded)\r\n }));\r\n\r\n const jsonResult = [\r\n {\r\n name: `${record.name}`,\r\n desc: `${record.desc}`,\r\n type: `${record.type}`,\r\n locators: finalAutoHealedLocators.filter(\r\n (locator) => locator?.value != null && locator.value !== \"\"\r\n ),\r\n isShared: `${record.isShared}`,\r\n projectId: `${record.projectId}`,\r\n projectType: `${record.projectType}`,\r\n isRecorded: `${record.isRecorded}`,\r\n folder: `${record.folder}`,\r\n parentId: `${record.parentId}`,\r\n parentName: `${record.parentName}`,\r\n platform: `${record.platform}`,\r\n licenseId: `${record.licenseId}`,\r\n licenseType: `${record.licenseType}`,\r\n userId: `${record.userId}`\r\n }\r\n ];\r\n\r\n return jsonResult;\r\n }\r\n } catch (error) {\r\n console.error(\"Error processing locator:\", locator, error);\r\n continue;\r\n }\r\n } catch (error) {\r\n console.error(\"Error processing locator:\", locator, error);\r\n continue;\r\n }\r\n }\r\n return null;\r\n};\r\n\r\nexport { getElementsFromHTML };\r\n","import { isNumberExist, getCountOfXPath } from \"./xpathHelpers\";\r\nfunction getOptimalClassChain(\r\n doc: Document,\r\n domNode: HTMLElement | Element | null,\r\n uniqueAttributes: Attr[]\r\n): string | null {\r\n\r\n try {\r\n\r\n if (\r\n !domNode ||\r\n domNode.nodeType !== 1 ||\r\n !domNode.tagName ||\r\n domNode.tagName === \"XCUIElementTypeApplication\"\r\n ) {\r\n return \"\";\r\n }\r\n\r\n const tag = domNode.tagName;\r\n\r\n // Priority attributes\r\n const priorityAttrs = [\"name\", \"label\", \"value\"];\r\n\r\n // ---------- STEP 1 : TRY GOOD ATTRIBUTES ----------\r\n for (const attrName of priorityAttrs) {\r\n\r\n const attr = uniqueAttributes.find(a => a.name === attrName);\r\n if (!attr) continue;\r\n\r\n let attrValue = attr.value;\r\n if (!attrValue) continue;\r\n\r\n attrValue = attrValue.trim().replace(/\\s+/g, \" \");\r\n\r\n if (isNumberExist(attrValue)) continue;\r\n\r\n const xpath = `//${tag}[@${attrName}=\"${attrValue}\"]`;\r\n\r\n let count = 0;\r\n\r\n try {\r\n count = getCountOfXPath(xpath, domNode, doc);\r\n } catch (err) {\r\n console.log(err);\r\n continue;\r\n }\r\n\r\n const hasSpace = /\\s/.test(attrValue);\r\n\r\n if (count === 1) {\r\n\r\n if (hasSpace) {\r\n return `/${tag}[\\`${attrName} CONTAINS \"${attrValue}\"\\`]`;\r\n }\r\n\r\n return `/${tag}[\\`${attrName} == \"${attrValue}\"\\`]`;\r\n }\r\n\r\n if (count > 1 && domNode.parentElement) {\r\n\r\n const siblings = Array.from(domNode.parentElement.children)\r\n .filter(el => el.tagName === tag);\r\n\r\n const index = siblings.indexOf(domNode) + 1;\r\n\r\n if (hasSpace) {\r\n return `/${tag}[\\`${attrName} CONTAINS \"${attrValue}\"\\`][${index}]`;\r\n }\r\n\r\n return `/${tag}[\\`${attrName} == \"${attrValue}\"\\`][${index}]`;\r\n }\r\n }\r\n\r\n // ---------- STEP 2 : FALLBACK USING TAG INDEX ----------\r\n let classChain = `/${tag}`;\r\n\r\n if (domNode.parentElement) {\r\n\r\n const siblings = Array.from(domNode.parentElement.children)\r\n .filter(el => el.tagName === tag);\r\n\r\n if (siblings.length > 1) {\r\n\r\n const index = siblings.indexOf(domNode) + 1;\r\n\r\n classChain += `[${index}]`;\r\n }\r\n }\r\n\r\n const parentChain = getOptimalClassChain(\r\n doc,\r\n domNode.parentElement,\r\n uniqueAttributes\r\n );\r\n\r\n return parentChain + classChain;\r\n\r\n } catch (error) {\r\n\r\n console.log(\r\n `Unable to generate optimal -ios class chain : ${JSON.stringify(error)}`\r\n );\r\n\r\n return null;\r\n }\r\n}\r\nfunction getOptimalPredicateString(\r\n doc: Document,\r\n domNode: HTMLElement | Element | null,\r\n uniqueAttributes: Attr[]\r\n) {\r\n try {\r\n // BASE CASE #1: If this isn't an element, we're above the root, or this is `XCUIElementTypeApplication`,\r\n // which is not an official XCUITest element, return empty string\r\n if (\r\n !domNode?.tagName ||\r\n domNode?.nodeType !== 1 ||\r\n domNode?.tagName === 'XCUIElementTypeApplication'\r\n ) {\r\n return '';\r\n }\r\n\r\n // BASE CASE #2: Check all attributes and try to find the best way\r\n let xpathAttributes: string[] = [];\r\n let predicateString: string[] = [];\r\n\r\n for (let attr of uniqueAttributes) {\r\n const attrValue = attr.value;\r\n const attrName = attr.name;\r\n\r\n if (attrValue.length === 0) {\r\n continue;\r\n }\r\n if (attrValue && !isNumberExist(attrValue)) {\r\n xpathAttributes.push(`@${attrName}=\"${attrValue}\"`);\r\n const xpathe = `//*[${xpathAttributes.join(' and ')}]`;\r\n predicateString.push(`${attrName} == \"${attrValue}\"`);\r\n let othersWithAttr;\r\n\r\n // If the XPath does not parse, move to the next unique attribute\r\n try {\r\n othersWithAttr = getCountOfXPath(\r\n xpathe,\r\n domNode,\r\n doc\r\n );\r\n } catch (ign) {\r\n console.log(ign);\r\n continue;\r\n }\r\n\r\n // If the attribute isn't actually unique, get it's index too\r\n if (othersWithAttr === 1) {\r\n return predicateString.join(' AND ');\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n // If there's an unexpected exception, abort and don't get an XPath\r\n console.log(\r\n `The most optimal '-ios predicate string' could not be determined because an error was thrown: '${JSON.stringify(\r\n error,\r\n null,\r\n 2\r\n )}'`\r\n );\r\n }\r\n return null;\r\n}\r\n\r\nexport const iosSelectors = {\r\n getOptimalClassChain,\r\n getOptimalPredicateString\r\n};","import xpath from '../utils/xpath.ts';\r\nimport referenceXpaths from '../utils/referenceXpath.ts';\r\nimport { xpathUtils } from '../utils/xpathHelpers.ts';\r\nimport { getElementsFromHTML } from '../utils/getElementsFromHTML.ts';\r\nimport { cssSelectors } from '../utils/cssSelector.ts';\r\nimport { iosSelectors } from '../utils/iosSelector.ts';\r\n\r\nexport const createXPathAPI = () => ({\r\n xpath,\r\n referenceXpaths,\r\n xpathUtils,\r\n getElementsFromHTML,\r\n cssSelectors,\r\n iosSelectors\r\n});\r\n\r\nexport default createXPathAPI;"],"names":["reWhiteSpace","xpathEvalCache","WeakMap","clearXPathEvalCache","node","contexts","addContext","candidate","includes","push","rootNode","getRootNode","Document","ShadowRoot","nodeType","Node","DOCUMENT_NODE","ownerDocument","getMutationCacheContexts","forEach","contextNode","delete","evaluateXPathOnce","xpath","docmt","owner","document","getXPathContext","nodeCache","get","Map","set","cached","result","evaluate","XPathResult","ORDERED_NODE_ITERATOR_TYPE","evalResult","first","iterateNext","second","mutationObserver","relativeXPathCache","modifiedElementAttributes","INTERNAL_CLASS_TOKENS","Set","normalizeClassTokens","classValue","split","map","token","trim","filter","has","sort","hasNumericAttributeValue","value","test","getClassTokenConditions","element","allowNumericToken","allClassTokens","classTokens","length","escapeCharacters","buildPattern","isSvg","tagName","toLowerCase","count","getTagOnlyXpathCandidateCount","left","right","TEST_ID_ATTRIBUTE_NAMES","sanitizeAttributeValue","attributeName","attributeValue","join","replace","isInternalClassOnlyMutation","mutation","type","target","Element","oldValue","classList","previousTokens","currentTokens","getAttribute","isNumberExist","str","pattern","getTextContent","targetElement","textContent","getFilteredText","childNodes","nodeValue","getCountOfXPath","multiElementReferenceMode","Array","isArray","matchCount","error","console","text","indexOf","removeParenthesis","charArr","indexArray","reverse","finalStr","i","endBracketLength","firstpart","slice","startsWith","endsWith","findXpathWithIndex","val","index","nodes","ANY_TYPE","nodex","isSameNode","log","deleteGarbageFromInnerText","a","deleteLineGap","reduce","b","c","replaceWhiteSpaces","getContainerTextCondition","normalizedText","children","fragment","getStableTargetTextCandidates","prefix","part","getStableTargetText","getShadowRoot","el","root","host","createShadowEvaluationContext","tempDoc","implementation","createHTMLDocument","wrapper","createElement","innerHTML","body","appendChild","cloneForElement","defaultView","path","current","parentElement","parent","unshift","from","parentNode","getElementPathFromRoot","container","next","item","getElementAtPath","cloneElements","Boolean","cloneElement","checkBlockedAttributes","attribute","isTarget","sanitizedValue","name","some","x","isModified","find","doc","hasGeneratedNumericSegment","SVGElement","replaceTempAttributes","getPropertyXPath","prop","isIndex","combinePattern","mergePattern","isAttributeProp","isTextProp","normalizedTextProp","hasTextSpacing","stableTargetText","textValueForPredicate","containerTextCondition","classCondition","splitText","contentRes","match","endIndex","startIndexString","endIndexString","getAbsoluteXPath","domNode","xpathe","prototype","call","childNode","HTMLElement","offsetParent","getRelativeXPath","attributesArray","xpathParts","currentNode","hasUniqueAttr","attributes","attrName","attrValue","elementName","xpathCandidate","getXpathStrings","othersWithAttr","RegExp","filteredText","tagBasedXPath","siblings","finalXPath","getCombinationXpath","classConditions","getAttributeCombinationXpath","uniqueAttributes","candidateAttributes","attr","buildAttributeConditions","getTextConditions","rawText","conditions","add","generateAttributeCombinations","combinationSize","results","build","startIndex","currentGroup","pop","buildXPath","tryAttributeOnlyCombinations","attributeGroups","attributeGroup","xpathConditions","attributeConditions","attributeOnlyXpath","textConditions","textCondition","JSON","stringify","intermediateXpathStep","targetElemt","intermediateXpathSteps","isSvgElement","expression","getFilteredTextXPath","textForPredicate","getNormalizedPropertyXPath","getStartsWithPropertyXPath","stableText","getContainsPropertyXPath","getOrAttributesXPath","flatMap","buildTextCondition","_error","getAncestorAnchorCandidates","anchors","seen","priorityAttrs","orderedAttributes","pushAnchor","isExactUniqueXpath","textXpath","combinationXpath","getStructuralPathFromAncestor","ancestor","steps","getAxisNodeTest","getTagOnlyXPath","fallbackXpath","ancestorAnchors","ancestorXpath","descendantXpath","getFirstMatchedNode","structuralPath","parentChainXpath","parentChainCount","fallbackCount","DOCUMENT_FRAGMENT_NODE","FIRST_ORDERED_NODE_TYPE","singleNodeValue","getUniqueNodeAnchorXpaths","key","tagXpath","getTextXpathFunction","trimmedText","undefined","condition","replaceActualAttributes","getReferenceElementsXpath","nodeXpath1","xpaths1","tag","targetText","xpaths","xpth","addAttributeSplitCombineXpaths","concat","normalizeXPath","findMatchingParenthesis","openPos","closePos","counter","getXPathPattern","canonical","canonicalizeXPath","parts","xp","axisMatch","axis","attrMatch","usesNormalize","extractXPathSignatureParts","escapeAttrValue","isUniqueInDOM","queryAll","selector","querySelectorAll","xpathUtils","parseXml","xmlStr","window","DOMParser","parseFromString","getElementFromXpath","multi","getRelationship","pos","compareDocumentPosition","createObserver","addedNodeCallBack","MutationObserver","mutations","addedNodes","url","baseURI","startObserver","options","observe","stopObserver","disconnect","cspEnabled","getClassTokenCondition","xpathData","xpathDataWithIndex","xpathCache","cache","parentXpathCache","STRATEGY_MAP","andConditions","orConditions","contains","normalizeSpace","axes","hardCodedText","tillTag","withStrategyKey","strategy","entries","entry","removePositionalIndexXpaths","hasPositionalIndex","getNormalizedText","collectSubtreeElements","queue","shift","getSiblingNodes","direction","previousElementSibling","nextElementSibling","getDirectionalAxisSeedNodes","sibling","expand","isLowQualityNode","id","className","buildAxisXpathsForNodes","targetNodeTest","candidates","processed","MAX_PROCESS","nodeItem","anchorStages","containsXpath","startsWithXpath","stageIndex","anchor","Math","min","expanded","childCount","child","buildAxesStrategyXpaths","ancestors","descendants","previousSiblings","nextSiblings","precedingSeeds","followingSeeds","limitNodes","limit","tiers","tier","buildStrategyXpaths","fallbackXpaths","strategyName","getStrategyName","getTextXPath","buildTextStrategyXpaths","getStrategyXPath","buildPropertyStrategyXpaths","buildConditionStrategyXpaths","idx","scopeXpaths","toString","scopeXpath","scopedIdx","generateIndexedXpaths","checkRelativeXpathRelation","nodeXpath2","relationType","indexedXpath","getUniqueParentXpath","nodeXpath","ign","getParentRelativeXpath","uniqueAttrFound","textXPath","finalXpath","getChildRelativeXpath","st","firstElementChild","m","getSiblingRelativeXPath","markedSpan","querySelector","processSibling","n","hasAttributes","getXPathUsingAttributeAndText","normalizedTextContent","attributesBasedXPath","getUniqueClassName","addAllXPathAttributes","txtXpath","textAttribute","parseDOM","includedAttributes","strategies","isShadowScoped","attributesToUse","strategyXpaths","getUniqueXpathEntries","len","substring","addRelativeXpaths","relativeXpath","relativeChildXpath","expressions","fullRelativeXpath","relativeXpathIndex","tempRelativeXpath","descendantExpression","refExpectElement","xpath2","relation","expCommonParentXpathElements","step4","refCommonParentXpathElementLength","finalExpectedElementXpath","xpaths2Els","xpath2Elements","traverseXpath","getTraverseXpathExpression","repeat","rel_count","getDescendantXpath","xpaths2","refElement","expElement","expElementDocmnt","refAbsoluteXpath","refFullXpathElements","refFullXpathElementsWithoutNumber","expAbsoluteXpath","expFullXpathElements","expFullXpathElementsWithoutNumber","parentElementNumber","refCommonParentXpathElements","j","referenceElement","referenceText","referenceTextCondition","refCommonParentXpath","getXpathRelationExpression","element1","element2","xpath1","finalXpaths","doesReferenceXpathMatchElement","ancestorBridgeXpaths","getAncestorBridgeXpath","targetXpathValue","xpathStepSeparator","rel_xpath","referenceXpath","semanticTargetXpath","getDirectSemanticDescendantXpath","bridgeXpath","getDirectionalIntermediateBridgeXpath","stripXpathPrefix","getSingleStepXpath","getSingleStepXpaths","tagOnlyXpath","addCandidate","xpathValue","semanticScopeAttributeNames","getStableAttributeCondition","getSemanticScopedBridgeXpath","commonAncestor","ancestorNodeTest","targetAxisXpath","scopeElement","checkedAncestors","scopeNodeTest","scopedXpath","directionalIntermediateAttributeNames","targetAxisXpaths","positionReference","getFirstElementByXpath","intermediate","DOCUMENT_POSITION_FOLLOWING","intermediateNodeTest","targetXpath","candidateXpath","getSemanticScopedDescendantXpath","getIconNodeTest","iconElement","fill","stroke","isUniqueIconAncestorBridge","icons","matches","icon","targetCandidate","closest","getIconAncestorBridgeXpath","iconDescendants","ancestorNodeTests","iconNodeTest","getCommonAncestor","targetRelativeXpath","ancestorElement","targetXPaths","currentStep","getRelativeXpathFromAncestor","semanticAncestorNodeTest","semanticContainerTags","nodeTest","score","getSemanticAncestorNodeTest","semanticAncestorXpath","iconBridgeXpath","xpathe1","absoluteXpathElements","xpath2Candidates","replaceTrailingTargetClassWithTokenXpaths","exactClassStep","replacementStep","findRelativeXpath","allowedRelations","relations","tryRelation","useIndex","getReferenceElementXpath","referenceElementXpaths","charAt","lastIndexOf","childAnchorXpaths","childText","childTextCondition","referenceXpathElement","getSmartRelations","highPriority","mediumPriority","lowPriority","DOCUMENT_POSITION_CONTAINS","DOCUMENT_POSITION_CONTAINED_BY","DOCUMENT_POSITION_PRECEDING","isCssSelectorUnique","parseCssSelectors","mode","selectors","idPath","getIdCssPath","classPath","getClassCssPath","namePath","getAttributeCssPath","e","view","ELEMENT_NODE","nodeName","CSS","escape","sib","nth","childElementCount","EXCLUDED_ATTRS","getAttributeSelectors","String","attrSelectors","attrSelector","remove","cssSelectors","getAbsoluteCssPath","isSameXPathStillValid","normalized","getElementFromXPath","shouldUseSnapshot","ORDERED_NODE_SNAPSHOT_TYPE","snapshotLength","snapshotItem","getElementFromCssSelector","found","getElementFromShadowRoot","isSameCssSelectorStillValid","isCssSelectorLocator","locator","elements","shadowRoot","nestedElement","getId","getClassName","getVisibleText","getName","elementEl","hasAttribute","XPathEvaluator","checkReferenceElementIsValid","sourceLoc","xpathEvaluator","getElementsFromHTML","record","elementsToRemove","finalLocatorsSet","finalLocators","createLocator","base","overrides","newValue","newLocator","reference","status","isRecorded","previousSelfHealed","isSelfHealed","hasOwnProperty","locName","resolveIsSelfHealed","obj","pushUniqueLocator","resolveElement","ctx","safeName","findInIframes","iframes","iframe","iframeDoc","contentDocument","contentWindow","cleanLocatorValue","cleaned","locators","recordedNLocators","l","isDynamic","isShared","trimmedSelector","locatorExists","payloadXPaths","payloadCssSelectors","px","cssLocator","existingXPaths","usedXPathPatterns","excludedAttributes","idValue","prevId","prevTag","textValue","prevLinkText","nameLocator","prevName","prevClassLocator","cssSelector","xpathResults","brokenPayloadXPaths","xpathAdded","brokenPx","originalPattern","r","loc","fallbackCandidates","finalAutoHealedLocators","jsonResult","desc","projectId","projectType","folder","parentId","parentName","platform","licenseId","licenseType","userId","iosSelectors","getOptimalClassChain","err","hasSpace","classChain","getOptimalPredicateString","xpathAttributes","predicateString","createXPathAPI","referenceXpaths"],"mappings":"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"}
1
+ {"version":3,"file":"index.browser.cjs","sources":["../src/utils/xpathHelpers.ts","../src/utils/xpath.ts","../src/utils/referenceXpath.ts","../src/utils/cssSelector.ts","../src/utils/getElementsFromHTML.ts","../src/utils/iosSelector.ts","../src/browser/xpath.ts"],"sourcesContent":["export const reWhiteSpace = /^[\\S]+( [\\S]+)*$/i;\r\nexport let cspEnabled: boolean = false;\r\nconst xpathCache: { [x: string]: number } = {};\r\n\r\nexport const timeLog = (label: string, start: number) => {\r\n const duration = performance.now() - start;\r\n console.log(`⏱️ ${label}: ${duration.toFixed(2)}ms time`);\r\n};\r\n\r\ntype EvalResult = {\r\n first: Node | null;\r\n second: Node | null;\r\n};\r\n\r\n// cache per context node → avoids cross-context pollution\r\nlet xpathEvalCache = new WeakMap<Node, Map<string, EvalResult>>();\r\n\r\nconst getXPathContext = (docmt: Node) => {\r\n const owner: Document =\r\n docmt.nodeType === 9\r\n ? (docmt as Document)\r\n : docmt.ownerDocument || document;\r\n\r\n // valid XPath context nodes: Element(1), Document(9), DocumentFragment/ShadowRoot(11)\r\n const contextNode: Node =\r\n docmt.nodeType === 1 || docmt.nodeType === 9 || docmt.nodeType === 11\r\n ? docmt\r\n : owner;\r\n\r\n return { owner, contextNode };\r\n};\r\n\r\nconst getMutationCacheContexts = (node: Node): Node[] => {\r\n const contexts: Node[] = [];\r\n const addContext = (candidate: Node | null | undefined) => {\r\n if (!candidate || contexts.includes(candidate)) return;\r\n contexts.push(candidate);\r\n };\r\n\r\n addContext(node);\r\n\r\n const rootNode = node.getRootNode?.();\r\n if (rootNode instanceof Document || rootNode instanceof ShadowRoot) {\r\n addContext(rootNode);\r\n }\r\n\r\n const ownerDocument =\r\n node.nodeType === Node.DOCUMENT_NODE\r\n ? (node as Document)\r\n : node.ownerDocument;\r\n addContext(ownerDocument);\r\n\r\n return contexts;\r\n};\r\n\r\nexport const clearXPathEvalCache = (node?: Node | null) => {\r\n if (!node) {\r\n xpathEvalCache = new WeakMap<Node, Map<string, EvalResult>>();\r\n return;\r\n }\r\n\r\n getMutationCacheContexts(node).forEach((contextNode) => {\r\n xpathEvalCache.delete(contextNode);\r\n });\r\n};\r\n\r\nexport const evaluateXPathOnce = (xpath: string, docmt: Node): EvalResult => {\r\n const { owner, contextNode } = getXPathContext(docmt);\r\n\r\n // get or create cache for this context node\r\n let nodeCache = xpathEvalCache.get(contextNode);\r\n if (!nodeCache) {\r\n nodeCache = new Map<string, EvalResult>();\r\n xpathEvalCache.set(contextNode, nodeCache);\r\n }\r\n\r\n // cache hit\r\n const cached = nodeCache.get(xpath);\r\n if (cached) return cached;\r\n\r\n // evaluate once, stop after 2 nodes\r\n const result = owner.evaluate(\r\n xpath,\r\n contextNode,\r\n null,\r\n XPathResult.ORDERED_NODE_ITERATOR_TYPE,\r\n null\r\n );\r\n\r\n const first = result.iterateNext();\r\n const second = result.iterateNext();\r\n\r\n const evalResult: EvalResult = { first, second };\r\n nodeCache.set(xpath, evalResult);\r\n\r\n return evalResult;\r\n};\r\nlet relativeXPathCache = new Map();\r\nexport let modifiedElementAttributes: {\r\n url: string | null;\r\n attributeName: string | null;\r\n element: HTMLElement | Element;\r\n doc: Document;\r\n}[] = [];\r\nlet mutationObserver: MutationObserver;\r\nconst INTERNAL_CLASS_TOKENS = new Set([\r\n \"marked-element-temp\",\r\n \"removePointers\"\r\n]);\r\n\r\nconst normalizeClassTokens = (\r\n classValue: string | null | undefined\r\n): string[] =>\r\n (classValue || \"\")\r\n .split(/\\s+/)\r\n .map((token) => token.trim())\r\n .filter((token) => token && !INTERNAL_CLASS_TOKENS.has(token))\r\n .sort();\r\n\r\nexport const hasNumericAttributeValue = (value: string | null | undefined) =>\r\n /\\d/.test(value || \"\");\r\n\r\nexport const getClassTokenConditions = (\r\n element: HTMLElement | Element,\r\n classValue: string | null | undefined,\r\n docmt: Document | ShadowRoot,\r\n allowNumericToken = false\r\n): string[] => {\r\n // Class is tokenized: numeric-looking tokens are unstable, but stable\r\n // non-numeric tokens in the same class attribute should all be tried.\r\n const allClassTokens = normalizeClassTokens(classValue);\r\n const classTokens = allClassTokens.filter((token) =>\r\n allowNumericToken ? true : !hasNumericAttributeValue(token)\r\n );\r\n\r\n if (!classTokens.length) return [];\r\n\r\n if (allClassTokens.length === 1 && classTokens.length === 1) {\r\n // Single class value: exact class is more precise and not affected by\r\n // class-token ordering because there is no competing token.\r\n return [`@class=${escapeCharacters(classTokens[0])}`];\r\n }\r\n\r\n return classTokens\r\n .map((token) => {\r\n const xpath = buildPattern(\r\n `contains(@class,${escapeCharacters(token)})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n\r\n return {\r\n token,\r\n count: getTagOnlyXpathCandidateCount(xpath, element, docmt)\r\n };\r\n })\r\n .sort((left, right) => {\r\n // Multi-token class value: prefer the shortest stable token; uniqueness\r\n // is still validated by the caller/final XPath count.\r\n if (left.token.length !== right.token.length) {\r\n return left.token.length - right.token.length;\r\n }\r\n\r\n return left.count - right.count;\r\n })\r\n .map(({ token }) => `contains(@class,${escapeCharacters(token)})`);\r\n};\r\n\r\nexport const getClassTokenCondition = (\r\n element: HTMLElement | Element,\r\n classValue: string | null | undefined,\r\n docmt: Document | ShadowRoot,\r\n allowNumericToken = false\r\n): string | null => {\r\n return (\r\n getClassTokenConditions(element, classValue, docmt, allowNumericToken)[0] ||\r\n null\r\n );\r\n};\r\n\r\nconst TEST_ID_ATTRIBUTE_NAMES = new Set([\r\n \"data-testid\",\r\n \"data-test-id\",\r\n \"data-test\",\r\n \"data-cy\",\r\n \"testid\"\r\n]);\r\n\r\nconst hasGeneratedNumericSegment = (attributeValue: string): boolean =>\r\n /(?:^|[-_:])\\d{4,}(?:$|[-_:])/.test(attributeValue);\r\n\r\nconst isGeneratedTestIdAttribute = (\r\n attributeName: string,\r\n attributeValue: string\r\n): boolean =>\r\n TEST_ID_ATTRIBUTE_NAMES.has(attributeName.toLowerCase()) &&\r\n hasGeneratedNumericSegment(attributeValue);\r\n\r\nexport const sanitizeAttributeValue = (\r\n attributeName: string,\r\n attributeValue: string | null | undefined\r\n): string => {\r\n if (!attributeValue) {\r\n return \"\";\r\n }\r\n\r\n if (attributeName === \"class\" || attributeName === \"className\") {\r\n return normalizeClassTokens(attributeValue).join(\" \");\r\n }\r\n\r\n return attributeValue.replace(\"removePointers\", \"\").trim();\r\n};\r\n\r\nconst isInternalClassOnlyMutation = (mutation: MutationRecord): boolean => {\r\n if (\r\n mutation.type !== \"attributes\" ||\r\n mutation.attributeName !== \"class\" ||\r\n !(mutation.target instanceof Element)\r\n ) {\r\n return false;\r\n }\r\n\r\n if (\r\n isSvg(mutation.target) &&\r\n mutation.oldValue?.trim() === mutation.target.classList.value?.trim()\r\n ) {\r\n return true;\r\n }\r\n\r\n const previousTokens = normalizeClassTokens(mutation.oldValue);\r\n const currentTokens = normalizeClassTokens(\r\n mutation.target.getAttribute(\"class\")\r\n );\r\n\r\n return previousTokens.join(\" \") === currentTokens.join(\" \");\r\n};\r\n\r\nexport const createObserver = (addedNodeCallBack: Function) => {\r\n mutationObserver = new MutationObserver((mutations) => {\r\n mutations.forEach((mutation) => {\r\n const shouldInvalidateXPathCache =\r\n mutation.type === \"childList\" ||\r\n mutation.type === \"characterData\" ||\r\n (mutation.type === \"attributes\" &&\r\n mutation.attributeName !== \"flndisabled\" &&\r\n !isInternalClassOnlyMutation(mutation));\r\n\r\n if (shouldInvalidateXPathCache) {\r\n clearXPathEvalCache(mutation.target);\r\n }\r\n\r\n if (mutation?.addedNodes?.length) {\r\n addedNodeCallBack(mutation?.addedNodes);\r\n }\r\n\r\n if (mutation.target instanceof HTMLElement) {\r\n if (isInternalClassOnlyMutation(mutation)) {\r\n } else if (\r\n mutation?.type === \"attributes\" &&\r\n ![\"flndisabled\"].includes(mutation.attributeName!)\r\n ) {\r\n modifiedElementAttributes.push({\r\n url: mutation.target.baseURI,\r\n attributeName: mutation.attributeName,\r\n element: mutation.target,\r\n doc: mutation.target.ownerDocument\r\n });\r\n }\r\n }\r\n });\r\n });\r\n};\r\nexport const startObserver = (\r\n target: Node,\r\n options: MutationObserverInit | undefined\r\n) => {\r\n mutationObserver?.observe(target, options);\r\n};\r\n\r\nexport const stopObserver = () => {\r\n mutationObserver?.disconnect();\r\n};\r\n\r\nexport const isNumberExist = (str: string): boolean => {\r\n const hasNumber = /\\d/;\r\n return hasNumber.test(str);\r\n};\r\n\r\nexport const buildPattern = (\r\n pattern: string,\r\n isSvg: boolean,\r\n tagName: string\r\n): string => {\r\n return isSvg\r\n ? `//*[local-name()='${tagName}' and ${pattern}]`\r\n : `//${tagName}[${pattern}]`;\r\n};\r\n\r\nexport const getTextContent = (\r\n targetElement: HTMLElement | Element\r\n): string => {\r\n const textContent = targetElement?.textContent;\r\n if (cspEnabled) {\r\n if (textContent) {\r\n const tooltip = document.querySelector(\".flntooltip\") as HTMLElement;\r\n if (tooltip) {\r\n const lastIndex = textContent.lastIndexOf(tooltip.innerText);\r\n if (\r\n lastIndex &&\r\n textContent.length === lastIndex + tooltip.innerText.length\r\n ) {\r\n return textContent.substring(0, lastIndex);\r\n }\r\n } else {\r\n return textContent;\r\n }\r\n }\r\n } else {\r\n return textContent;\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nexport const getFilteredText = (element: Node): string => {\r\n return element?.childNodes[0]?.nodeValue || \"\";\r\n};\r\n\r\nexport const getCountOfXPath = (\r\n xpath: string,\r\n element: HTMLElement | Element,\r\n docmt: Node,\r\n multiElementReferenceMode: boolean = false\r\n): number => {\r\n try {\r\n if (isShadowRootNode(docmt)) {\r\n // XPath cannot evaluate directly against ShadowRoot/DocumentFragment, so\r\n // count against the cloned evaluation context used for shadow DOM.\r\n const { owner, contextNode, cloneElement, cloneElements } =\r\n createShadowEvaluationContext(docmt, element);\r\n const result = owner.evaluate(\r\n xpath,\r\n contextNode,\r\n null,\r\n XPathResult.ORDERED_NODE_ITERATOR_TYPE,\r\n null\r\n );\r\n const first = result.iterateNext();\r\n const second = result.iterateNext();\r\n\r\n if (!first) return 0;\r\n\r\n if (!second) {\r\n return first === cloneElement ? 1 : 0;\r\n }\r\n\r\n if (multiElementReferenceMode && Array.isArray(element)) {\r\n let matchCount = 0;\r\n\r\n if (cloneElements.includes(first as Element)) matchCount++;\r\n if (cloneElements.includes(second as Element)) matchCount++;\r\n\r\n if (matchCount === 2) return 2;\r\n\r\n let node: Node | null;\r\n while ((node = result.iterateNext())) {\r\n if (cloneElements.includes(node as Element)) {\r\n matchCount++;\r\n if (matchCount === 2) return 2;\r\n }\r\n }\r\n\r\n return 0;\r\n }\r\n\r\n return 2;\r\n }\r\n\r\n const { first, second } = evaluateXPathOnce(xpath, docmt);\r\n\r\n if (!first) return 0;\r\n\r\n // exactly one match\r\n if (!second) {\r\n return first === element ? 1 : 0;\r\n }\r\n\r\n // multiple matches\r\n if (multiElementReferenceMode && Array.isArray(element)) {\r\n let matchCount = 0;\r\n\r\n if (element.includes(first)) matchCount++;\r\n if (element.includes(second)) matchCount++;\r\n\r\n if (matchCount === 2) return 2;\r\n const owner =\r\n docmt.nodeType === 9 ? (docmt as Document) : docmt.ownerDocument!;\r\n\r\n const result = owner.evaluate(\r\n xpath,\r\n docmt,\r\n null,\r\n XPathResult.ORDERED_NODE_ITERATOR_TYPE,\r\n null\r\n );\r\n\r\n let node: Node | null;\r\n while ((node = result.iterateNext())) {\r\n if (element.includes(node)) {\r\n matchCount++;\r\n if (matchCount === 2) return 2;\r\n }\r\n }\r\n\r\n return 0;\r\n }\r\n\r\n return 2;\r\n } catch (error) {\r\n console.error(`Error evaluating XPath: ${xpath}`, error);\r\n return 0;\r\n }\r\n};\r\n\r\nexport const escapeCharacters = (text: string): string => {\r\n if (text) {\r\n if (!(text.indexOf('\"') === -1)) {\r\n return `'${text}'`;\r\n }\r\n if (!(text.indexOf(\"'\") === -1)) {\r\n return `\"${text}\"`;\r\n }\r\n }\r\n return `'${text}'`;\r\n};\r\n\r\nexport const removeParenthesis = (xpath: string): string => {\r\n const charArr = xpath.split(\"\");\r\n\r\n let count = charArr.length;\r\n const indexArray = [];\r\n\r\n while (charArr[count - 2] !== \"[\") {\r\n indexArray.push(charArr[count - 2]);\r\n count--;\r\n }\r\n\r\n indexArray.reverse();\r\n let finalStr = \"\";\r\n for (let i = 0; i < indexArray.length; i++) {\r\n finalStr += indexArray[i];\r\n }\r\n\r\n const endBracketLength = finalStr.length + 2;\r\n let firstpart = xpath.slice(0, xpath.length - endBracketLength);\r\n\r\n if (firstpart.startsWith(\"(\") && firstpart.endsWith(\")\")) {\r\n firstpart = firstpart.slice(1, -1);\r\n } else {\r\n firstpart = xpath;\r\n }\r\n\r\n return firstpart;\r\n};\r\n\r\nexport const findXpathWithIndex = (\r\n val: string,\r\n node: HTMLElement | Element,\r\n docmt: Node,\r\n count: number\r\n) => {\r\n try {\r\n const owner =\r\n docmt.nodeType === 9 // DOCUMENT_NODE\r\n ? (docmt as Document)\r\n : docmt.ownerDocument!;\r\n\r\n let index = 0;\r\n if (count) {\r\n if (getCountOfXPath(`${val}[${count}]`, node, docmt) === 1) {\r\n return `${val}[${count}]`;\r\n }\r\n\r\n if (getCountOfXPath(`(${val})[${count}]`, node, docmt) === 1) {\r\n return `(${val})[${count}]`;\r\n }\r\n }\r\n\r\n const nodes = owner.evaluate(val, docmt, null, XPathResult.ANY_TYPE, null);\r\n let nodex: Node | null = null;\r\n while ((nodex = nodes.iterateNext())) {\r\n index++;\r\n if (nodex.isSameNode(node)) {\r\n if (getCountOfXPath(`${val}[${index}]`, node, docmt) === 1) {\r\n return `${val}[${index}]`;\r\n }\r\n if (getCountOfXPath(`(${val})[${index}]`, node, docmt) === 1) {\r\n return `(${val})[${index}]`;\r\n }\r\n return;\r\n }\r\n }\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n};\r\n\r\nconst deleteLineGap = (a: string): string => {\r\n a &&= a.split(\"\\n\")[0].length > 0 ? a.split(\"\\n\")[0] : a.split(\"\\n\")[1];\r\n return a;\r\n};\r\n\r\nconst deleteGarbageFromInnerText = (a: string): string => {\r\n a = deleteLineGap(a);\r\n a = a\r\n .split(/[^\\u0000-\\u00ff]/)\r\n .reduce((b, c) => {\r\n return b.length > c.length ? b : c;\r\n }, \"\")\r\n .trim();\r\n return (a = a.split(\"/\")[0].trim());\r\n};\r\n\r\nexport const replaceWhiteSpaces = (str: string): string => {\r\n if (str) {\r\n return str.replace(/\\s\\s+/g, \" \").trim();\r\n }\r\n\r\n return str;\r\n};\r\n\r\nexport const getContainerTextCondition = (\r\n element: HTMLElement | Element,\r\n text: string | null | undefined\r\n): string => {\r\n const normalizedText = replaceWhiteSpaces((text || \"\").trim());\r\n\r\n if (!element.children.length || normalizedText.length <= 50) {\r\n return \"\";\r\n }\r\n\r\n const fragment = normalizedText.split(/\\s+/).slice(0, 3).join(\" \");\r\n\r\n // Long container text is usually flattened descendant text. Use a short\r\n // visible fragment instead of exact matching the whole menu/header content.\r\n return fragment.length > 2\r\n ? `contains(normalize-space(.),${escapeCharacters(fragment)})`\r\n : \"\";\r\n};\r\n\r\nexport const getStableTargetTextCandidates = (\r\n text: string | null | undefined\r\n): { prefix: string; fragment: string } => {\r\n const normalizedText = replaceWhiteSpaces((text || \"\").trim());\r\n\r\n if (!normalizedText || !hasNumericAttributeValue(normalizedText)) {\r\n return { prefix: normalizedText, fragment: normalizedText };\r\n }\r\n\r\n const prefix = normalizedText\r\n .split(/[0-9]/)[0]\r\n .replace(/[₹$€£¥₫₽₩₦₱₲₴₵₡₭₮₺฿៛]+/g, \"\")\r\n .trim();\r\n const fragment = prefix\r\n .split(/[^a-zA-Z]+/)\r\n .map((part) => replaceWhiteSpaces(part).trim())\r\n .filter((part) => part.length > 2 && /[a-zA-Z]/.test(part))\r\n .join(\" \")\r\n .trim();\r\n\r\n // Target text containing numbers is dynamic. Keep only a meaningful\r\n // non-numeric prefix/fragment, so price/count text never becomes exact XPath.\r\n return {\r\n prefix: prefix.length > 2 && /[a-zA-Z]/.test(prefix) ? prefix : \"\",\r\n fragment: fragment.length > 2 ? fragment : \"\"\r\n };\r\n};\r\n\r\nexport const getStableTargetText = (\r\n text: string | null | undefined\r\n): string => getStableTargetTextCandidates(text).fragment;\r\n\r\nexport const getShadowRoot = (el: HTMLElement | Element): Element | null => {\r\n if (!el || !el?.getRootNode) return null;\r\n\r\n const root = el.getRootNode() as ShadowRoot;\r\n return root && root?.host ? (root as unknown as Element) : null;\r\n};\r\n\r\nconst isShadowRootNode = (node: Node): node is ShadowRoot => {\r\n return node?.nodeType === Node.DOCUMENT_FRAGMENT_NODE && \"host\" in node;\r\n};\r\n\r\nconst getElementPathFromRoot = (\r\n root: ShadowRoot,\r\n element: Element\r\n): number[] | null => {\r\n const path: number[] = [];\r\n let current: Element | null = element;\r\n\r\n while (current && current.parentElement) {\r\n const parent: Element = current.parentElement as Element;\r\n path.unshift(Array.from(parent.children).indexOf(current));\r\n current = parent;\r\n }\r\n\r\n if (!current || current.parentNode !== root) {\r\n return null;\r\n }\r\n\r\n path.unshift(Array.from(root.children).indexOf(current));\r\n return path;\r\n};\r\n\r\nconst getElementAtPath = (\r\n container: ParentNode & { children: HTMLCollection },\r\n path: number[]\r\n): Element | null => {\r\n let current: (ParentNode & { children: HTMLCollection }) | Element =\r\n container;\r\n\r\n for (const index of path) {\r\n const next: Element | null = current.children.item(index) as Element | null;\r\n if (!next) {\r\n return null;\r\n }\r\n\r\n current = next;\r\n }\r\n\r\n return current as Element | null;\r\n};\r\n\r\nexport const createShadowEvaluationContext = (\r\n root: ShadowRoot,\r\n element?: HTMLElement | Element | (HTMLElement | Element)[]\r\n) => {\r\n const tempDoc =\r\n root.ownerDocument.implementation.createHTMLDocument(\"shadow-xpath\");\r\n const wrapper = tempDoc.createElement(\"div\");\r\n wrapper.innerHTML = root.innerHTML;\r\n tempDoc.body.appendChild(wrapper);\r\n\r\n const cloneForElement = (candidate?: HTMLElement | Element | null) => {\r\n if (\r\n !candidate ||\r\n !(candidate instanceof root.ownerDocument.defaultView!.Element)\r\n ) {\r\n return null;\r\n }\r\n\r\n const path = getElementPathFromRoot(root, candidate);\r\n return path ? getElementAtPath(wrapper, path) : null;\r\n };\r\n\r\n const cloneElements = Array.isArray(element)\r\n ? element.map((candidate) => cloneForElement(candidate)).filter(Boolean)\r\n : [];\r\n\r\n const cloneElement = Array.isArray(element)\r\n ? null\r\n : cloneForElement(element ?? null);\r\n\r\n return {\r\n owner: tempDoc,\r\n contextNode: wrapper,\r\n cloneElement,\r\n cloneElements\r\n };\r\n};\r\n\r\nexport const checkBlockedAttributes = (\r\n attribute: {\r\n name: string;\r\n value: string;\r\n },\r\n targetElement: HTMLElement | Element,\r\n isTarget: boolean\r\n): boolean => {\r\n const sanitizedValue = sanitizeAttributeValue(\r\n attribute.name,\r\n attribute.value\r\n );\r\n\r\n if (!sanitizedValue || typeof attribute?.value === \"boolean\") {\r\n return false;\r\n }\r\n const blockedValues = [\r\n \"true\",\r\n \"false\",\r\n \"on\",\r\n \"off\",\r\n \"flntooltip\",\r\n \"flutter-highlight-overlay\"\r\n ];\r\n if (blockedValues.some((x) => x === sanitizedValue)) {\r\n return false;\r\n }\r\n const blockedNames = [\"style\", \"locator-data-tooltip\", \"value\"];\r\n if (blockedNames.some((x) => x === attribute.name)) {\r\n return false;\r\n }\r\n\r\n const isModified = modifiedElementAttributes?.find(\r\n (x) =>\r\n x.doc === targetElement.ownerDocument &&\r\n x.element === targetElement &&\r\n x.attributeName === attribute.name\r\n );\r\n if (isModified) {\r\n return false;\r\n }\r\n\r\n if (attribute?.name?.indexOf(\"on\") === 0 && attribute?.name?.length > 3) {\r\n return false;\r\n }\r\n\r\n if (typeof attribute.value === \"function\") {\r\n return false;\r\n }\r\n\r\n if (isGeneratedTestIdAttribute(attribute.name, sanitizedValue)) {\r\n return false;\r\n }\r\n\r\n // Strict numeric-attribute validation: numeric attribute values are treated\r\n // as unstable before candidate creation. Class is handled token-by-token by\r\n // getClassTokenCondition, so only numeric class tokens are rejected there.\r\n if (attribute.name !== \"class\" && hasNumericAttributeValue(sanitizedValue)) {\r\n return false;\r\n }\r\n\r\n return true;\r\n};\r\n\r\nexport const getRelationship = (a: HTMLElement, b: HTMLElement): string => {\r\n let pos = a.compareDocumentPosition(b);\r\n return pos === 2\r\n ? \"preceding\"\r\n : pos === 4\r\n ? \"following\"\r\n : pos === 8\r\n ? \"ancestor\"\r\n : pos === 16\r\n ? \"descendant\"\r\n : pos === 32\r\n ? \"self\"\r\n : \"\";\r\n};\r\n\r\nexport const isSvg = (element: HTMLElement | Element) => {\r\n return element instanceof SVGElement;\r\n};\r\n\r\nexport const replaceTempAttributes = (str: string): string => {\r\n if (!str) return str;\r\n\r\n return str.replace(/\\b[a-zA-Z_]*disabled\\b/gi, \"disabled\");\r\n};\r\n\r\nconst getElementFromXpath = (xpath: string, docmt: Node, multi = false) => {\r\n let contextNode: Node = docmt;\r\n\r\n // XPath does NOT support DocumentFragment / ShadowRoot\r\n if (docmt.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\r\n contextNode = (docmt as ShadowRoot).host ?? docmt;\r\n }\r\n\r\n const owner =\r\n contextNode.nodeType === Node.DOCUMENT_NODE\r\n ? (contextNode as Document)\r\n : contextNode.ownerDocument!;\r\n\r\n if (multi) {\r\n return owner.evaluate(xpath, contextNode, null, XPathResult.ANY_TYPE, null);\r\n }\r\n\r\n return owner.evaluate(\r\n xpath,\r\n contextNode,\r\n null,\r\n XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n ).singleNodeValue;\r\n};\r\n\r\nexport const getPropertyXPath = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n prop: string,\r\n value: string,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n if (value) {\r\n const { tagName } = element;\r\n let count;\r\n let combinePattern = \"\";\r\n const mergePattern = [];\r\n let pattern;\r\n\r\n const isAttributeProp = prop.startsWith(\"@\");\r\n const isTextProp = prop === \".\" || prop === \"text()\";\r\n const normalizedTextProp = isTextProp ? \".\" : prop;\r\n const hasTextSpacing = isTextProp && /\\s/.test(value.trim());\r\n const stableTargetText = isTextProp ? getStableTargetText(value) : value;\r\n const textValueForPredicate =\r\n isTextProp && hasNumericAttributeValue(value) ? stableTargetText : value;\r\n const containerTextCondition = isTextProp\r\n ? getContainerTextCondition(element, textValueForPredicate)\r\n : \"\";\r\n\r\n if (prop === \"@class\") {\r\n for (const classCondition of getClassTokenConditions(\r\n element,\r\n value,\r\n docmt\r\n )) {\r\n // Single-mode class generation tries every stable token and lets the\r\n // normal uniqueness check choose the first usable XPath.\r\n pattern = buildPattern(\r\n classCondition,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n if (isTextProp && hasNumericAttributeValue(value) && !stableTargetText) {\r\n // Target text with only dynamic numeric content should not produce a\r\n // text XPath. Other attribute/relative fallbacks can still run.\r\n return;\r\n }\r\n\r\n if (value && (!isAttributeProp || !isNumberExist(value))) {\r\n if (containerTextCondition) {\r\n pattern = buildPattern(\r\n containerTextCondition,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n } else if (hasTextSpacing) {\r\n pattern = buildPattern(\r\n `normalize-space(${normalizedTextProp})=${escapeCharacters(\r\n replaceWhiteSpaces(textValueForPredicate)\r\n ).trim()}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n } else if (!reWhiteSpace.test(value)) {\r\n pattern = buildPattern(\r\n `normalize-space(${prop})=${escapeCharacters(\r\n replaceWhiteSpaces(textValueForPredicate)\r\n ).trim()}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n } else {\r\n pattern = `//${tagName}[${prop}=${escapeCharacters(\r\n textValueForPredicate\r\n )}]`;\r\n }\r\n\r\n count = getCountOfXPath(pattern, element, docmt);\r\n\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n\r\n if (isAttributeProp && hasNumericAttributeValue(value)) {\r\n // Strict numeric-attribute validation: do not split numeric attribute\r\n // values into starts-with/contains fallbacks.\r\n return;\r\n }\r\n\r\n if (value && isTarget) {\r\n const splitText = value.split(\" \");\r\n if (splitText?.length) {\r\n if (splitText.length === 1) {\r\n const contentRes = [...new Set(splitText[0].match(/([^0-9]+)/g))];\r\n if (contentRes?.length >= 1) {\r\n if (\r\n contentRes[0] &&\r\n replaceWhiteSpaces(contentRes[0].trim())?.length > 1\r\n ) {\r\n if (value.startsWith(contentRes[0])) {\r\n if (!reWhiteSpace.test(contentRes[0])) {\r\n combinePattern = `starts-with(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[0])\r\n ).trim()})`;\r\n } else {\r\n combinePattern = `starts-with(${prop},${escapeCharacters(\r\n contentRes[0]\r\n ).trim()})`;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (contentRes?.length > 1) {\r\n if (\r\n contentRes[contentRes.length - 1] &&\r\n replaceWhiteSpaces(contentRes[contentRes.length - 1].trim())\r\n ?.length > 1\r\n ) {\r\n if (value.endsWith(contentRes[contentRes.length - 1])) {\r\n if (!reWhiteSpace.test(contentRes[contentRes.length - 1])) {\r\n combinePattern = `ends-with(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[contentRes.length - 1])\r\n ).trim()})`;\r\n } else {\r\n combinePattern = `ends-with(${prop},${escapeCharacters(\r\n contentRes[contentRes.length - 1]\r\n ).trim()})`;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and ${combinePattern}]`;\r\n } else {\r\n pattern = `//${tagName}[${combinePattern}]`;\r\n }\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n } else {\r\n const endIndex =\r\n splitText.length % 2 === 0\r\n ? splitText.length / 2\r\n : splitText.length % 2;\r\n const startIndexString = splitText.slice(0, endIndex).join(\" \");\r\n let contentRes = [...new Set(startIndexString.match(/([^0-9]+)/g))];\r\n if (contentRes?.length) {\r\n if (\r\n contentRes[0] &&\r\n replaceWhiteSpaces(contentRes[0].trim())?.length\r\n ) {\r\n if (value.startsWith(contentRes[0])) {\r\n if (!reWhiteSpace.test(contentRes[0])) {\r\n combinePattern = `starts-with(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[0])\r\n ).trim()})`;\r\n } else {\r\n combinePattern = `starts-with(${prop},${escapeCharacters(\r\n contentRes[0]\r\n ).trim()})`;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and ${combinePattern}]`;\r\n } else {\r\n pattern = `//${tagName}[${combinePattern}]`;\r\n }\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n\r\n const endIndexString = splitText\r\n .slice(endIndex, splitText.length - 1)\r\n .join(\" \");\r\n contentRes = [...new Set(endIndexString.match(/([^0-9]+)/g))];\r\n if (contentRes?.length) {\r\n if (\r\n contentRes[0] &&\r\n replaceWhiteSpaces(contentRes[0].trim())?.length > 3\r\n ) {\r\n if (value.endsWith(contentRes[0])) {\r\n if (!reWhiteSpace.test(contentRes[0])) {\r\n combinePattern = `ends-with(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[0])\r\n ).trim()})`;\r\n } else {\r\n combinePattern = `ends-with(${prop},${escapeCharacters(\r\n contentRes[0]\r\n ).trim()})`;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and ${combinePattern}]`;\r\n } else {\r\n pattern = `//${tagName}[${combinePattern}]`;\r\n }\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (value && isTarget && isNumberExist(value)) {\r\n const contentRes = [...new Set(value.match(/([^0-9]+)/g))];\r\n if (contentRes?.length) {\r\n for (let i = 0; i < contentRes?.length; i++) {\r\n if (\r\n contentRes[i] &&\r\n replaceWhiteSpaces(contentRes[i].trim())?.length > 1\r\n ) {\r\n if (!reWhiteSpace.test(contentRes[i])) {\r\n mergePattern.push(\r\n `contains(${prop},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[i])\r\n ).trim()})`\r\n );\r\n } else {\r\n mergePattern.push(\r\n `contains(${prop},${escapeCharacters(\r\n contentRes[i].trim()\r\n ).trim()})`\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (mergePattern?.length) {\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and ${mergePattern.join(\r\n \" and \"\r\n )}]`;\r\n } else {\r\n pattern = `//${tagName}[${mergePattern.join(\" and \")}]`;\r\n }\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n }\r\n\r\n if (isSvg(element)) {\r\n pattern = `//*[local-name()='${tagName}' and text()]`;\r\n } else {\r\n pattern = `//${tagName}[text()]`;\r\n }\r\n\r\n count = getCountOfXPath(pattern, element, docmt);\r\n if (count === 1 && !isIndex) {\r\n return pattern;\r\n }\r\n }\r\n};\r\n\r\nexport const getAbsoluteXPath = (\r\n domNode: HTMLElement | Element | null,\r\n docmt: Document\r\n): string => {\r\n try {\r\n if (!domNode) {\r\n return \"\";\r\n }\r\n\r\n let xpathe = isSvg(domNode)\r\n ? `/*[local-name()='${domNode.tagName}']`\r\n : `/${domNode.tagName}`;\r\n\r\n // // If this node has siblings of the same tagName, get the index of this node\r\n if (domNode.parentElement) {\r\n // Get the siblings\r\n const childNodes = Array.prototype.slice\r\n .call(domNode.parentElement.children, 0)\r\n .filter(\r\n (childNode: HTMLElement) => childNode.tagName === domNode.tagName\r\n );\r\n\r\n // // If there's more than one sibling, append the index\r\n if (childNodes.length > 1) {\r\n const index = childNodes.indexOf(domNode);\r\n xpathe += `[${index + 1}]`;\r\n }\r\n } else if (domNode instanceof HTMLElement) {\r\n if (domNode.offsetParent) {\r\n const childNodes = Array.prototype.slice\r\n .call(domNode.offsetParent.children, 0)\r\n .filter(\r\n (childNode: HTMLElement) => childNode.tagName === domNode.tagName\r\n );\r\n\r\n // // If there's more than one sibling, append the index\r\n if (childNodes.length > 1) {\r\n const index = childNodes.indexOf(domNode);\r\n xpathe += `[${index + 1}]`;\r\n }\r\n }\r\n }\r\n\r\n // // Make a recursive call to this nodes parents and prepend it to this xpath\r\n return getAbsoluteXPath(domNode?.parentElement, docmt) + xpathe;\r\n } catch (error) {\r\n // If there's an unexpected exception, abort and don't get an XPath\r\n console.log(\"xpath\", error);\r\n\r\n return \"\";\r\n }\r\n};\r\n\r\nexport const getRelativeXPath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean = false,\r\n attributesArray: Attr[]\r\n) => {\r\n try {\r\n // Generate a cache key based on the node's identifier, index, and target flag\r\n // Check if the result for this node is already cached\r\n if (relativeXPathCache.has(domNode)) {\r\n return relativeXPathCache.get(domNode);\r\n }\r\n\r\n // Initialize an array to hold parts of the XPath\r\n const xpathParts = [];\r\n let currentNode = domNode;\r\n\r\n // Traverse up the DOM tree iteratively instead of using recursion\r\n while (currentNode) {\r\n let xpathe: string | undefined = \"\";\r\n let hasUniqueAttr = false;\r\n let attributes =\r\n domNode === currentNode\r\n ? (attributesArray ?? currentNode.attributes)\r\n : currentNode.attributes;\r\n\r\n // Loop through attributes to check for unique identifiers\r\n for (const attrName of Array.from(attributes)) {\r\n if (checkBlockedAttributes(attrName, currentNode, isTarget)) {\r\n const attrValue = sanitizeAttributeValue(\r\n attrName.name,\r\n attrName.nodeValue\r\n );\r\n\r\n const elementName = attrName.name;\r\n\r\n // Class can produce multiple stable token candidates; try each\r\n // before moving to text/index fallbacks.\r\n for (const xpathCandidate of getXpathStrings(\r\n currentNode,\r\n elementName,\r\n attrValue\r\n )) {\r\n xpathe = xpathCandidate;\r\n let othersWithAttr: number = 0;\r\n othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n if (othersWithAttr === 1) {\r\n xpathParts.unshift(replaceTempAttributes(xpathe));\r\n hasUniqueAttr = true;\r\n break;\r\n }\r\n\r\n if (othersWithAttr > 1 && isIndex) {\r\n xpathe = findXpathWithIndex(\r\n xpathe,\r\n currentNode,\r\n docmt,\r\n othersWithAttr\r\n );\r\n if (xpathe) {\r\n xpathParts.unshift(replaceTempAttributes(xpathe));\r\n hasUniqueAttr = true;\r\n break;\r\n }\r\n // return replaceTempAttributes(xpathe);\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (currentNode.textContent) {\r\n if (\r\n !isTarget ||\r\n (isTarget && !isNumberExist(currentNode.textContent))\r\n ) {\r\n let reWhiteSpace = new RegExp(/^[\\S]+( [\\S]+)*$/gi);\r\n const filteredText = getFilteredText(currentNode);\r\n const containerTextCondition = getContainerTextCondition(\r\n currentNode,\r\n filteredText\r\n );\r\n\r\n if (containerTextCondition) {\r\n xpathe = buildPattern(\r\n containerTextCondition,\r\n isSvg(currentNode),\r\n currentNode.tagName || \"*\"\r\n );\r\n } else if (!reWhiteSpace.test(currentNode.textContent)) {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and normalize-space(.)=${escapeCharacters(\r\n filteredText\r\n )}]`\r\n : `//${\r\n currentNode.tagName || \"*\"\r\n }[normalize-space(.)=${escapeCharacters(\r\n filteredText\r\n )}]`;\r\n } else {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and .=${escapeCharacters(filteredText)}]`\r\n : `//${currentNode.tagName || \"*\"}[.=${escapeCharacters(\r\n filteredText\r\n )}]`;\r\n }\r\n\r\n let othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n if (othersWithAttr === 1) {\r\n return xpathe;\r\n }\r\n\r\n if (othersWithAttr > 1 && isIndex) {\r\n xpathe = findXpathWithIndex(\r\n xpathe,\r\n currentNode,\r\n docmt,\r\n othersWithAttr\r\n );\r\n return xpathe;\r\n }\r\n } else {\r\n let combinePattern: string[] = [];\r\n const contentRes = [\r\n ...new Set(getFilteredText(currentNode).match(/([^0-9]+)/g))\r\n ];\r\n let reWhiteSpace = new RegExp(/^[\\S]+( [\\S]+)*$/gi);\r\n if (contentRes?.length) {\r\n for (let i = 0; i < contentRes?.length; i++) {\r\n if (\r\n contentRes[i] &&\r\n replaceWhiteSpaces((contentRes[i] as string).trim())\r\n ) {\r\n if (!reWhiteSpace.test(contentRes[i] as string)) {\r\n combinePattern.push(\r\n `contains(.,${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[i])\r\n ).trim()})`\r\n );\r\n } else {\r\n combinePattern.push(\r\n `contains(.,${escapeCharacters(\r\n (contentRes[i] as string).trim()\r\n ).trim()})`\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and ${combinePattern.join(\" and \")}]`\r\n : `//${currentNode.tagName || \"*\"}[${combinePattern.join(\r\n \" and \"\r\n )}]`;\r\n let othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n if (othersWithAttr === 1) {\r\n return xpathe;\r\n }\r\n\r\n if (othersWithAttr > 1 && isIndex) {\r\n xpathe = findXpathWithIndex(\r\n xpathe,\r\n currentNode,\r\n docmt,\r\n othersWithAttr\r\n );\r\n return xpathe;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // If no unique attribute was found, construct XPath by tag name\r\n if (!hasUniqueAttr) {\r\n let tagBasedXPath = isSvg(currentNode)\r\n ? `/*[local-name()='${currentNode.tagName}']`\r\n : `/${currentNode.tagName}`;\r\n\r\n // Handle sibling nodes\r\n if (currentNode.parentElement) {\r\n const siblings = Array.from(\r\n currentNode.parentElement.children\r\n ).filter((childNode) => childNode.tagName === currentNode.tagName);\r\n\r\n // Append index to distinguish between siblings\r\n if (siblings.length > 1) {\r\n const index = siblings.indexOf(currentNode);\r\n tagBasedXPath += `[${index + 1}]`;\r\n }\r\n }\r\n\r\n // Add the constructed tag-based XPath to the parts array\r\n xpathParts.unshift(tagBasedXPath);\r\n } else {\r\n break;\r\n }\r\n\r\n // Move up to the parent node for the next iteration\r\n currentNode = currentNode.parentElement!;\r\n }\r\n\r\n // Combine all parts into the final XPath\r\n const finalXPath = `${xpathParts.join(\"\")}`;\r\n\r\n // Cache the final XPath for this node\r\n relativeXPathCache.set(domNode, finalXPath);\r\n return finalXPath;\r\n } catch (error) {\r\n console.log(error);\r\n return null;\r\n }\r\n};\r\n\r\nexport const getCombinationXpath = (\r\n attribute: Attr,\r\n domNode: HTMLElement | Element\r\n) => {\r\n const combinePattern = [];\r\n let pattern: string = \"\";\r\n\r\n if (\r\n attribute &&\r\n typeof attribute.nodeValue !== \"function\" // &&\r\n // !modifiedElementAttributes?.find(\r\n // (x) => x.element === domNode && x.attributeName === attribute.name\r\n // )\r\n ) {\r\n if (attribute.name === \"class\") {\r\n const docmt =\r\n (domNode.getRootNode?.() as Document | ShadowRoot | null) ??\r\n domNode.ownerDocument;\r\n const classConditions = getClassTokenConditions(\r\n domNode,\r\n attribute.value,\r\n docmt\r\n );\r\n\r\n // Class values are handled token-by-token so numeric tokens are blocked\r\n // without throwing away the other stable class tokens.\r\n for (const classCondition of classConditions) {\r\n pattern = isSvg(domNode)\r\n ? `//*[local-name()='${domNode.tagName}' and ${classCondition}]`\r\n : `//${domNode.tagName}[${classCondition}]`;\r\n\r\n if (pattern) {\r\n return pattern;\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n if (isNumberExist(attribute.value)) {\r\n return;\r\n }\r\n\r\n const contentRes = [...new Set(attribute.value.match(/([^0-9]+)/g))];\r\n if (contentRes?.length) {\r\n for (let i = 0; i < contentRes?.length; i++) {\r\n if (\r\n contentRes[i] &&\r\n replaceWhiteSpaces(contentRes[i].trim())?.length > 2\r\n ) {\r\n if (!reWhiteSpace.test(contentRes[i])) {\r\n combinePattern.push(\r\n `contains(@${attribute.name},${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[i])\r\n ).trim()})`\r\n );\r\n } else {\r\n combinePattern.push(\r\n `contains(@${attribute.name},${escapeCharacters(\r\n contentRes[i].trim()\r\n )})`\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n pattern = isSvg(domNode)\r\n ? `//*[local-name()='${domNode.tagName}' and ${combinePattern.join(\r\n \" and \"\r\n )}]`\r\n : `//${domNode.tagName}[${combinePattern.join(\" and \")}]`;\r\n return pattern;\r\n }\r\n }\r\n};\r\n\r\nexport const getAttributeCombinationXpath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document | ShadowRoot,\r\n uniqueAttributes: Attr[],\r\n isTarget: boolean\r\n): string | undefined => {\r\n try {\r\n const candidateAttributes = uniqueAttributes.filter((attr) =>\r\n checkBlockedAttributes(attr, domNode, isTarget)\r\n );\r\n\r\n const buildAttributeConditions = (attribute: Attr): string[] => {\r\n const attrValue = sanitizeAttributeValue(\r\n attribute.name,\r\n attribute.nodeValue\r\n );\r\n\r\n if (!attrValue) return [];\r\n\r\n if (attribute.name === \"class\") {\r\n return getClassTokenConditions(\r\n domNode,\r\n attrValue,\r\n docmt\r\n );\r\n }\r\n\r\n // Strict numeric-attribute validation for direct callers.\r\n if (hasNumericAttributeValue(attrValue)) return [];\r\n\r\n if (!reWhiteSpace.test(attrValue)) {\r\n return [`normalize-space(@${attribute.name})=\"${attrValue}\"`];\r\n }\r\n\r\n return [`@${attribute.name}=\"${attrValue}\"`];\r\n };\r\n\r\n const buildAttributeConditionAlternatives = (\r\n attribute: Attr\r\n ): string[][] => {\r\n const conditions = buildAttributeConditions(attribute);\r\n\r\n if (attribute.name === \"class\") {\r\n // Class tokens are alternatives; chaining every stable class token can\r\n // over-constrain generated combination XPath.\r\n return conditions.map((condition) => [condition]);\r\n }\r\n\r\n return conditions.length ? [conditions] : [];\r\n };\r\n\r\n const buildConditionGroups = (attributes: Attr[]): string[][] => {\r\n // Expand attribute alternatives into condition groups before uniqueness\r\n // checks, especially for class-token combinations.\r\n return attributes.reduce<string[][]>((groups, attribute) => {\r\n const alternatives = buildAttributeConditionAlternatives(attribute);\r\n\r\n if (!alternatives.length) return [];\r\n\r\n return groups.flatMap((group) =>\r\n alternatives.map((alternative) => [...group, ...alternative])\r\n );\r\n }, [[]]);\r\n };\r\n\r\n const getTextConditions = (): string[] => {\r\n const rawText = replaceWhiteSpaces(getTextContent(domNode)?.trim() || \"\");\r\n const stableTargetText = getStableTargetText(rawText);\r\n if (hasNumericAttributeValue(rawText)) {\r\n return stableTargetText\r\n ? [\r\n `contains(normalize-space(.),${escapeCharacters(\r\n stableTargetText\r\n )})`\r\n ]\r\n : [];\r\n }\r\n\r\n if (!rawText || rawText.length > 80 || /^\\d+$/.test(rawText)) {\r\n const containerTextCondition = getContainerTextCondition(\r\n domNode,\r\n rawText\r\n );\r\n return containerTextCondition ? [containerTextCondition] : [];\r\n }\r\n\r\n const conditions = new Set<string>();\r\n const containerTextCondition = getContainerTextCondition(\r\n domNode,\r\n rawText\r\n );\r\n\r\n if (containerTextCondition) {\r\n conditions.add(containerTextCondition);\r\n return Array.from(conditions);\r\n }\r\n\r\n if (reWhiteSpace.test(rawText) && rawText.length <= 40 && !rawText.includes(\" \")) {\r\n conditions.add(`text()=${escapeCharacters(rawText)}`);\r\n }\r\n\r\n if (rawText.includes(\" \")) {\r\n conditions.add(\r\n `normalize-space(.)=${escapeCharacters(replaceWhiteSpaces(rawText))}`\r\n );\r\n }\r\n\r\n conditions.add(`contains(text(),${escapeCharacters(rawText)})`);\r\n\r\n return Array.from(conditions);\r\n };\r\n\r\n const generateAttributeCombinations = (\r\n attributes: Attr[],\r\n combinationSize: number\r\n ): Attr[][] => {\r\n const results: Attr[][] = [];\r\n\r\n const build = (startIndex: number, currentGroup: Attr[]) => {\r\n if (currentGroup.length === combinationSize) {\r\n results.push([...currentGroup]);\r\n return;\r\n }\r\n\r\n for (let i = startIndex; i < attributes.length; i++) {\r\n currentGroup.push(attributes[i]);\r\n build(i + 1, currentGroup);\r\n currentGroup.pop();\r\n }\r\n };\r\n\r\n build(0, []);\r\n return results;\r\n };\r\n\r\n const buildXPath = (conditions: string[]) =>\r\n isSvg(domNode)\r\n ? `//*[local-name()='${domNode.tagName}' and ${conditions.join(\" and \")}]`\r\n : `//${domNode.tagName}[${conditions.join(\" and \")}]`;\r\n\r\n const tryAttributeOnlyCombinations = () => {\r\n if (candidateAttributes.length < 2) {\r\n return undefined;\r\n }\r\n\r\n for (\r\n let combinationSize = 2;\r\n combinationSize <= candidateAttributes.length;\r\n combinationSize++\r\n ) {\r\n const attributeGroups = generateAttributeCombinations(\r\n candidateAttributes,\r\n combinationSize\r\n );\r\n\r\n for (const attributeGroup of attributeGroups) {\r\n const conditionGroups = buildConditionGroups(attributeGroup);\r\n\r\n for (const xpathConditions of conditionGroups) {\r\n if (xpathConditions.length < 2) continue;\r\n\r\n const xpath = buildXPath(xpathConditions);\r\n\r\n let matchCount: number;\r\n\r\n try {\r\n matchCount = getCountOfXPath(xpath, domNode, docmt);\r\n } catch {\r\n continue;\r\n }\r\n\r\n if (matchCount === 1) {\r\n return xpath;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return undefined;\r\n };\r\n\r\n const attributeOnlyXpath = tryAttributeOnlyCombinations();\r\n if (attributeOnlyXpath) {\r\n return attributeOnlyXpath;\r\n }\r\n\r\n const textConditions = getTextConditions();\r\n if (!textConditions.length || !candidateAttributes.length) {\r\n return;\r\n }\r\n\r\n for (\r\n let combinationSize = 1;\r\n combinationSize <= candidateAttributes.length;\r\n combinationSize++\r\n ) {\r\n const attributeGroups = generateAttributeCombinations(\r\n candidateAttributes,\r\n combinationSize\r\n );\r\n\r\n for (const attributeGroup of attributeGroups) {\r\n const conditionGroups = buildConditionGroups(attributeGroup);\r\n\r\n for (const attributeConditions of conditionGroups) {\r\n if (!attributeConditions.length) {\r\n continue;\r\n }\r\n\r\n for (const textCondition of textConditions) {\r\n const xpathConditions = [...attributeConditions, textCondition];\r\n const xpath = buildXPath(xpathConditions);\r\n\r\n try {\r\n if (getCountOfXPath(xpath, domNode, docmt) === 1) {\r\n return xpath;\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.log(`XPath generation error: ${JSON.stringify(error, null, 2)}`);\r\n }\r\n};\r\n\r\nexport const intermediateXpathStep = (\r\n targetElemt: HTMLElement | Element,\r\n attr: { name: string; value: string },\r\n isTarget: boolean\r\n): string => {\r\n return intermediateXpathSteps(targetElemt, attr, isTarget)[0] || \"\";\r\n};\r\n\r\nexport const intermediateXpathSteps = (\r\n targetElemt: HTMLElement | Element,\r\n attr: { name: string; value: string },\r\n isTarget: boolean\r\n): string[] => {\r\n let isSvgElement = isSvg(targetElemt);\r\n let expression: string = \"\";\r\n\r\n if (checkBlockedAttributes(attr, targetElemt, isTarget)) {\r\n let attrValue = sanitizeAttributeValue(attr.name, attr.value);\r\n const elementName = attr.name;\r\n\r\n if (elementName === \"class\") {\r\n const docmt =\r\n (targetElemt.getRootNode?.() as Document | ShadowRoot | null) ??\r\n targetElemt.ownerDocument;\r\n\r\n // Relative child/parent steps follow the same class-token rule as direct\r\n // XPath candidates: try every stable token, never numeric tokens.\r\n return getClassTokenConditions(targetElemt, attrValue, docmt).map(\r\n (classCondition) =>\r\n isSvgElement\r\n ? `*[local-name()='${targetElemt.tagName}' and ${classCondition}]`\r\n : `${targetElemt.tagName || \"*\"}[${classCondition}]`\r\n );\r\n }\r\n\r\n // Strict numeric-attribute validation for direct callers.\r\n if (hasNumericAttributeValue(attrValue)) {\r\n return [];\r\n }\r\n\r\n if (!reWhiteSpace.test(attrValue)) {\r\n expression = isSvgElement\r\n ? `*[local-name()='${\r\n targetElemt.tagName\r\n }' and normalize-space(@${elementName})=${escapeCharacters(\r\n attrValue\r\n )}]`\r\n : `${\r\n targetElemt.tagName || \"*\"\r\n }[normalize-space(@${elementName})=${escapeCharacters(attrValue)}]`;\r\n } else {\r\n expression = isSvgElement\r\n ? `*[local-name()='${\r\n targetElemt.tagName\r\n }' and @${elementName}=${escapeCharacters(attrValue)}]`\r\n : `${targetElemt.tagName || \"*\"}[@${elementName}=${escapeCharacters(\r\n attrValue\r\n )}]`;\r\n }\r\n }\r\n\r\n return expression ? [expression] : [];\r\n};\r\n\r\nexport const getFilteredTextXPath = (\r\n node: HTMLElement | Element,\r\n docmt: Document | ShadowRoot\r\n): string => {\r\n if (!node.textContent) return \"\";\r\n\r\n const filteredText = getFilteredText(node);\r\n const stableTargetText = getStableTargetText(filteredText);\r\n if (hasNumericAttributeValue(filteredText) && !stableTargetText) {\r\n // Do not build text XPath from purely numeric/dynamic target text.\r\n return \"\";\r\n }\r\n\r\n const textForPredicate =\r\n hasNumericAttributeValue(filteredText) ? stableTargetText : filteredText;\r\n const containerTextCondition = getContainerTextCondition(\r\n node,\r\n textForPredicate\r\n );\r\n\r\n let xpathe;\r\n\r\n if (containerTextCondition) {\r\n xpathe = buildPattern(\r\n containerTextCondition,\r\n isSvg(node),\r\n node.tagName || \"*\"\r\n );\r\n } else if (hasNumericAttributeValue(filteredText)) {\r\n xpathe = buildPattern(\r\n `contains(normalize-space(.),${escapeCharacters(textForPredicate)})`,\r\n isSvg(node),\r\n node.tagName || \"*\"\r\n );\r\n } else if (!reWhiteSpace.test(filteredText) || /\\s/.test(filteredText.trim())) {\r\n xpathe = buildPattern(\r\n `normalize-space(.)=${escapeCharacters(textForPredicate)}`,\r\n isSvg(node),\r\n node.tagName || \"*\"\r\n );\r\n } else {\r\n xpathe = isSvg(node)\r\n ? `//*[local-name()='${node.tagName}' and .=${escapeCharacters(\r\n textForPredicate\r\n )}]`\r\n : `//${node.tagName || \"*\"}[.=${escapeCharacters(textForPredicate)}]`;\r\n }\r\n\r\n return xpathe;\r\n};\r\n\r\nexport const getNormalizedPropertyXPath = (\r\n element: HTMLElement | Element,\r\n prop: string,\r\n value: string\r\n): string => {\r\n if ((prop === \".\" || prop === \"text()\") && hasNumericAttributeValue(value)) {\r\n const { fragment } = getStableTargetTextCandidates(value);\r\n\r\n return fragment\r\n ? buildPattern(\r\n `contains(normalize-space(.),${escapeCharacters(fragment)})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n )\r\n : \"\";\r\n }\r\n\r\n return buildPattern(\r\n `normalize-space(${prop})=${escapeCharacters(replaceWhiteSpaces(value)).trim()}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n};\r\n\r\nexport const getStartsWithPropertyXPath = (\r\n element: HTMLElement | Element,\r\n prop: string,\r\n value: string\r\n): string => {\r\n if ((prop === \".\" || prop === \"text()\") && hasNumericAttributeValue(value)) {\r\n const { prefix, fragment } = getStableTargetTextCandidates(value);\r\n const stableText = prefix || fragment;\r\n\r\n return stableText\r\n ? buildPattern(\r\n `starts-with(normalize-space(.),${escapeCharacters(stableText)})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n )\r\n : \"\";\r\n }\r\n\r\n return buildPattern(\r\n `starts-with(${prop},${escapeCharacters(replaceWhiteSpaces(value)).trim()})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n};\r\n\r\nexport const getContainsPropertyXPath = (\r\n element: HTMLElement | Element,\r\n prop: string,\r\n value: string\r\n): string => {\r\n if ((prop === \".\" || prop === \"text()\") && hasNumericAttributeValue(value)) {\r\n const { fragment } = getStableTargetTextCandidates(value);\r\n\r\n return fragment\r\n ? buildPattern(\r\n `contains(normalize-space(.),${escapeCharacters(fragment)})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n )\r\n : \"\";\r\n }\r\n\r\n return buildPattern(\r\n `contains(${prop},${escapeCharacters(replaceWhiteSpaces(value)).trim()})`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n};\r\n\r\nexport const getOrAttributesXPath = (\r\n element: HTMLElement | Element,\r\n attributes: Attr[]\r\n): string => {\r\n const buildAttributeConditions = (attribute: Attr): string[] => {\r\n const attrValue = sanitizeAttributeValue(attribute.name, attribute.value);\r\n\r\n if (!attrValue) {\r\n return [];\r\n }\r\n\r\n if (attribute.name === \"class\") {\r\n const docmt =\r\n (element.getRootNode?.() as Document | ShadowRoot | null) ??\r\n element.ownerDocument;\r\n\r\n return getClassTokenConditions(element, attrValue, docmt);\r\n }\r\n\r\n // Strict numeric-attribute validation for direct callers.\r\n if (hasNumericAttributeValue(attrValue)) return [];\r\n\r\n if (!reWhiteSpace.test(attrValue)) {\r\n return [\r\n `normalize-space(@${attribute.name})=${escapeCharacters(attrValue)}`\r\n ];\r\n }\r\n\r\n return [`@${attribute.name}=${escapeCharacters(attrValue)}`];\r\n };\r\n\r\n const buildTextCondition = (): string | null => {\r\n const rawText = replaceWhiteSpaces(getTextContent(element)?.trim() || \"\");\r\n const stableTargetText = getStableTargetText(rawText);\r\n if (hasNumericAttributeValue(rawText)) {\r\n // OR conditions must not reintroduce full dynamic numeric target text.\r\n return stableTargetText\r\n ? `contains(normalize-space(.),${escapeCharacters(stableTargetText)})`\r\n : null;\r\n }\r\n\r\n const containerTextCondition = getContainerTextCondition(element, rawText);\r\n\r\n if (containerTextCondition) {\r\n return containerTextCondition;\r\n }\r\n\r\n if (!rawText || rawText.length > 80 || /^\\d+$/.test(rawText)) {\r\n return null;\r\n }\r\n\r\n if (reWhiteSpace.test(rawText) && rawText.length <= 40 && !rawText.includes(\" \")) {\r\n return `text()=${escapeCharacters(rawText)}`;\r\n }\r\n\r\n if (rawText.includes(\" \")) {\r\n return `normalize-space(.)=${escapeCharacters(rawText)}`;\r\n }\r\n\r\n return `contains(text(),${escapeCharacters(rawText)})`;\r\n };\r\n\r\n const attributeConditions = attributes\r\n .flatMap((attribute) => buildAttributeConditions(attribute))\r\n .filter(Boolean);\r\n\r\n if (attributeConditions.length >= 2) {\r\n return buildPattern(\r\n `${attributeConditions[0]} or ${attributeConditions[1]}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n }\r\n\r\n const textCondition = buildTextCondition();\r\n if (attributeConditions.length === 1 && textCondition) {\r\n return buildPattern(\r\n `${attributeConditions[0]} or ${textCondition}`,\r\n isSvg(element),\r\n element.tagName.toLowerCase()\r\n );\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getTagOnlyXpathCandidateCount = (\r\n xpath: string,\r\n element: HTMLElement | Element,\r\n docmt: Document | ShadowRoot\r\n) => {\r\n try {\r\n return getCountOfXPath(xpath, element, docmt);\r\n } catch (_error) {\r\n return 0;\r\n }\r\n};\r\n\r\nconst getAncestorAnchorCandidates = (\r\n node: HTMLElement | Element,\r\n docmt: Document | ShadowRoot\r\n): string[] => {\r\n const anchors: string[] = [];\r\n const seen = new Set<string>();\r\n const attributes = Array.from(node.attributes || []);\r\n const priorityAttrs = [\r\n \"id\",\r\n \"data-testid\",\r\n \"data-test\",\r\n \"data-qa\",\r\n \"name\",\r\n \"aria-label\",\r\n \"role\"\r\n ];\r\n const orderedAttributes = [\r\n ...priorityAttrs\r\n .map((attrName) => attributes.find((attr) => attr.name === attrName))\r\n .filter(Boolean),\r\n ...attributes.filter((attr) => !priorityAttrs.includes(attr.name))\r\n ] as Attr[];\r\n\r\n const pushAnchor = (xpath: string) => {\r\n if (!xpath || seen.has(xpath)) return;\r\n if (isExactUniqueXpath(xpath, node, docmt)) {\r\n seen.add(xpath);\r\n anchors.push(xpath);\r\n }\r\n };\r\n\r\n orderedAttributes.forEach((attr) => {\r\n if (!checkBlockedAttributes(attr, node, false)) return;\r\n\r\n for (const xpath of getXpathStrings(node, attr.name, attr.value)) {\r\n pushAnchor(xpath);\r\n }\r\n });\r\n\r\n const text = node.textContent?.trim();\r\n if (text && text.length < 40 && node.children.length === 0) {\r\n const textXpath = getFilteredTextXPath(node, docmt);\r\n if (textXpath) {\r\n pushAnchor(textXpath);\r\n }\r\n }\r\n\r\n if (attributes.length > 1) {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n node,\r\n docmt,\r\n attributes,\r\n false\r\n );\r\n if (combinationXpath) {\r\n pushAnchor(combinationXpath);\r\n }\r\n }\r\n\r\n return anchors;\r\n};\r\n\r\nconst getStructuralPathFromAncestor = (\r\n ancestor: HTMLElement | Element,\r\n element: HTMLElement | Element\r\n): string => {\r\n const steps: string[] = [];\r\n let current: Element | null = element;\r\n\r\n while (current && current !== ancestor) {\r\n steps.unshift(getAxisNodeTest(current));\r\n current = current.parentElement;\r\n }\r\n\r\n return current === ancestor ? steps.join(\"/\") : \"\";\r\n};\r\n\r\nexport const getTagOnlyXPath = (\r\n element: HTMLElement | Element,\r\n docmt?: Document | ShadowRoot\r\n): string => {\r\n const root =\r\n docmt ??\r\n ((element.getRootNode?.() as Document | ShadowRoot) ||\r\n element.ownerDocument);\r\n const tagName = getAxisNodeTest(element);\r\n const fallbackXpath = isSvg(element)\r\n ? `//*[local-name()='${element.tagName.toLowerCase()}']`\r\n : `//${element.tagName.toLowerCase()}`;\r\n\r\n for (\r\n let ancestor = element.parentElement;\r\n ancestor;\r\n ancestor = ancestor.parentElement\r\n ) {\r\n const ancestorAnchors = getAncestorAnchorCandidates(ancestor, root);\r\n\r\n for (const ancestorXpath of ancestorAnchors) {\r\n console.log(`Trying ancestor XPath: ${ancestorXpath}`);\r\n\r\n const descendantXpath = `${ancestorXpath}/descendant::${tagName}`;\r\n console.log(`Trying descendant XPath: ${descendantXpath}`);\r\n\r\n const count = getTagOnlyXpathCandidateCount(\r\n descendantXpath,\r\n element,\r\n root\r\n );\r\n console.log(`Match count: ${count}`);\r\n\r\n if (\r\n count === 1 &&\r\n getFirstMatchedNode(descendantXpath, root) === element\r\n ) {\r\n console.log(`Selected XPath: ${descendantXpath}`);\r\n return descendantXpath;\r\n }\r\n\r\n const structuralPath = getStructuralPathFromAncestor(ancestor, element);\r\n if (structuralPath) {\r\n const parentChainXpath = `${ancestorXpath}/${structuralPath}`;\r\n console.log(`Trying descendant XPath: ${parentChainXpath}`);\r\n\r\n const parentChainCount = getTagOnlyXpathCandidateCount(\r\n parentChainXpath,\r\n element,\r\n root\r\n );\r\n console.log(`Match count: ${parentChainCount}`);\r\n\r\n if (\r\n parentChainCount === 1 &&\r\n getFirstMatchedNode(parentChainXpath, root) === element\r\n ) {\r\n console.log(`Selected XPath: ${parentChainXpath}`);\r\n return parentChainXpath;\r\n }\r\n }\r\n }\r\n }\r\n\r\n console.log(`Trying descendant XPath: ${fallbackXpath}`);\r\n const fallbackCount = getTagOnlyXpathCandidateCount(\r\n fallbackXpath,\r\n element,\r\n root\r\n );\r\n console.log(`Match count: ${fallbackCount}`);\r\n\r\n if (\r\n fallbackCount === 1 &&\r\n getFirstMatchedNode(fallbackXpath, root) === element\r\n ) {\r\n console.log(`Selected XPath: ${fallbackXpath}`);\r\n return fallbackXpath;\r\n }\r\n\r\n console.log(\"Selected XPath: \");\r\n return \"\";\r\n};\r\n\r\nexport const getFirstMatchedNode = (\r\n xpath: string,\r\n docmt: Document | ShadowRoot\r\n): HTMLElement | Element | null => {\r\n try {\r\n if (isShadowRootNode(docmt)) {\r\n const { owner, contextNode, cloneElement } =\r\n createShadowEvaluationContext(docmt);\r\n const result = owner.evaluate(\r\n xpath,\r\n contextNode,\r\n null,\r\n XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n\r\n return (result.singleNodeValue || cloneElement) as\r\n | HTMLElement\r\n | Element\r\n | null;\r\n }\r\n\r\n const result = docmt.evaluate(\r\n xpath,\r\n docmt,\r\n null,\r\n docmt.defaultView!.XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n\r\n return result.singleNodeValue as HTMLElement | Element | null;\r\n } catch (_error) {\r\n return null;\r\n }\r\n};\r\n\r\nexport const isExactUniqueXpath = (\r\n xpath: string,\r\n element: HTMLElement | Element,\r\n docmt: Document | ShadowRoot\r\n): boolean => {\r\n try {\r\n const { first, second } = evaluateXPathOnce(xpath, docmt);\r\n\r\n return !!first && !second && first === element;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n\r\nexport const getAxisNodeTest = (element: HTMLElement | Element): string => {\r\n return isSvg(element)\r\n ? `*[local-name()='${element.tagName.toLowerCase()}']`\r\n : element.tagName.toLowerCase();\r\n};\r\n\r\nconst hasAnyNumber = (value: string) => /\\d/.test(value);\r\n\r\nexport const getUniqueNodeAnchorXpaths = (\r\n node: HTMLElement | Element,\r\n docmt: Document | ShadowRoot,\r\n isTarget: boolean\r\n): { key: string; value: string }[] => {\r\n if (!(node instanceof Element)) return [];\r\n const seen = new Set<string>();\r\n const anchors: { key: string; value: string }[] = [];\r\n\r\n const attributes = Array.from(node.attributes || []).filter(\r\n (attribute) =>\r\n attribute?.value &&\r\n !hasAnyNumber(attribute.value) &&\r\n checkBlockedAttributes(attribute, node, isTarget)\r\n );\r\n\r\n const pushAnchor = (key: string, value: string) => {\r\n if (!value || seen.has(value)) return;\r\n seen.add(value);\r\n anchors.push({ key, value });\r\n };\r\n\r\n // Priority attributes\r\n const priorityAttrs = [\r\n \"id\",\r\n \"data-testid\",\r\n \"data-test\",\r\n \"data-qa\",\r\n \"name\",\r\n \"aria-label\",\r\n \"role\"\r\n ];\r\n\r\n priorityAttrs.forEach((attrName) => {\r\n const attr = attributes.find((a) => a.name === attrName);\r\n if (!attr) return;\r\n\r\n for (const xpath of getXpathStrings(node, attr.name, attr.value)) {\r\n if (xpath && isExactUniqueXpath(xpath, node, docmt)) {\r\n pushAnchor(`anchor by ${attr.name}`, xpath);\r\n }\r\n }\r\n });\r\n\r\n // Other attributes\r\n attributes.forEach((attribute) => {\r\n if (priorityAttrs.includes(attribute.name)) return;\r\n\r\n for (const xpath of getXpathStrings(node, attribute.name, attribute.value)) {\r\n if (xpath && isExactUniqueXpath(xpath, node, docmt)) {\r\n pushAnchor(`anchor by ${attribute.name}`, xpath);\r\n }\r\n }\r\n });\r\n\r\n // Text (controlled)\r\n const text = node.textContent?.trim();\r\n if (text && text.length < 40 && node.children.length === 0) {\r\n const textXpath = getFilteredTextXPath(node, docmt);\r\n if (textXpath && isExactUniqueXpath(textXpath, node, docmt)) {\r\n pushAnchor(\"anchor by text\", textXpath);\r\n }\r\n }\r\n\r\n // Combination\r\n if (attributes.length > 1) {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n node,\r\n docmt,\r\n attributes,\r\n isTarget\r\n );\r\n\r\n if (combinationXpath && isExactUniqueXpath(combinationXpath, node, docmt)) {\r\n pushAnchor(\"anchor by combination\", combinationXpath);\r\n }\r\n }\r\n\r\n // Tag (last fallback)\r\n const tagXpath = getTagOnlyXPath(node, docmt);\r\n if (tagXpath && isExactUniqueXpath(tagXpath, node, docmt)) {\r\n pushAnchor(\"anchor by tag\", tagXpath);\r\n }\r\n\r\n return anchors;\r\n};\r\n\r\nexport const getTextXpathFunction = (\r\n domNode: HTMLElement | Element\r\n): string | undefined => {\r\n const trimmedText = getTextContent(domNode)?.trim();\r\n const stableTargetText = getStableTargetText(trimmedText);\r\n if (trimmedText && hasNumericAttributeValue(trimmedText)) {\r\n return stableTargetText\r\n ? `contains(normalize-space(.),${escapeCharacters(stableTargetText)})`\r\n : undefined;\r\n }\r\n\r\n const containerTextCondition = getContainerTextCondition(\r\n domNode,\r\n trimmedText\r\n );\r\n\r\n if (containerTextCondition) {\r\n return containerTextCondition;\r\n }\r\n\r\n const filteredText = trimmedText\r\n ? escapeCharacters(deleteGarbageFromInnerText(trimmedText))\r\n : trimmedText;\r\n if (filteredText) {\r\n if (filteredText !== `'${trimmedText}'`) {\r\n return `contains(.,${filteredText})`;\r\n }\r\n if (/\\s/.test(trimmedText)) {\r\n return `normalize-space(.)='${replaceWhiteSpaces(trimmedText)}'`;\r\n }\r\n return `normalize-space(.)='${trimmedText}'`;\r\n }\r\n};\r\n\r\nexport const getXpathString = (\r\n node: HTMLElement | Element,\r\n attrName: string,\r\n attrValue: string\r\n): string => {\r\n return getXpathStrings(node, attrName, attrValue)[0] || \"\";\r\n};\r\n\r\nexport const getXpathStrings = (\r\n node: HTMLElement | Element,\r\n attrName: string,\r\n attrValue: string\r\n): string[] => {\r\n const reWhiteSpace = new RegExp(/^[\\S]+( [\\S]+)*$/gi);\r\n let xpathe: string = \"\";\r\n attrValue = sanitizeAttributeValue(attrName, attrValue);\r\n\r\n if (attrValue) {\r\n if (attrName === \"class\") {\r\n const docmt =\r\n (node.getRootNode?.() as Document | ShadowRoot | null) ??\r\n node.ownerDocument;\r\n // Try every stable class token; numeric tokens are filtered by the\r\n // shared class helper before any XPath candidate is created.\r\n return getClassTokenConditions(node, attrValue, docmt).map((condition) =>\r\n isSvg(node)\r\n ? `//*[local-name()='${node.tagName}' and ${condition}]`\r\n : `//${node.tagName || \"*\"}[${condition}]`\r\n );\r\n }\r\n\r\n // Strict numeric-attribute validation: do not derive contains/starts-with\r\n // predicates from numeric attributes.\r\n if (hasNumericAttributeValue(attrValue)) return [];\r\n\r\n if (!reWhiteSpace.test(attrValue)) {\r\n xpathe = isSvg(node)\r\n ? `//*[local-name()='${\r\n node.tagName\r\n }' and contains(@${attrName},${escapeCharacters(attrValue)})]`\r\n : `//${node.tagName || \"*\"}[contains(@${attrName},${escapeCharacters(\r\n attrValue\r\n )})]`;\r\n } else {\r\n xpathe = isSvg(node)\r\n ? `//*[local-name()='${\r\n node.tagName\r\n }' and @${attrName}=${escapeCharacters(attrValue)}]`\r\n : `//${node.tagName || \"*\"}[@${attrName}=${escapeCharacters(\r\n attrValue\r\n )}]`;\r\n }\r\n }\r\n\r\n return xpathe ? [xpathe] : [];\r\n};\r\n\r\nexport const replaceActualAttributes = (\r\n str: string,\r\n element: { attributes: any }\r\n): string => {\r\n if (str) {\r\n return str.replace(/\\bdisabled\\b/gi, \"flndisabled\");\r\n }\r\n return str;\r\n};\r\n\r\nconst addAttributeSplitCombineXpaths = (\r\n attributes: NamedNodeMap,\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean\r\n): { key: string; value: string }[] => {\r\n const attributesArray = Array.prototype.slice.call(attributes);\r\n const xpaths: { key: string; value: string }[] = [];\r\n try {\r\n attributesArray.map((element) => {\r\n if (checkBlockedAttributes(element, targetElemt, isTarget)) {\r\n const xpth = getCombinationXpath(element, targetElemt);\r\n if (xpth) {\r\n xpaths.push({\r\n key: `split xpath by ${element.name}`,\r\n value: xpth\r\n });\r\n }\r\n }\r\n });\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n\r\n return xpaths;\r\n};\r\n\r\nconst trimAttributePart = (value: string): string =>\r\n value.replace(/^[-_:\\s.]+|[-_:\\s.]+$/g, \"\").trim();\r\n\r\nconst getStableAttributePart = (attributeValue: string): string => {\r\n const value = attributeValue.trim();\r\n const prefix = trimAttributePart(value.split(/\\d/)[0] || \"\");\r\n const prefixParts = prefix\r\n .split(/[-_:\\s.]+/)\r\n .filter(Boolean);\r\n\r\n if (prefixParts.length > 1 && prefixParts[prefixParts.length - 1].length <= 2) {\r\n prefixParts.pop();\r\n }\r\n\r\n const stablePrefix = prefixParts.join(\"-\");\r\n if (stablePrefix.length > 2 && /[a-zA-Z]/.test(stablePrefix)) {\r\n return stablePrefix;\r\n }\r\n\r\n const parts = value\r\n .split(/[\\d\\s\\-_:./\\\\]+/)\r\n .map((part) => trimAttributePart(part))\r\n .filter((part) => part.length > 2 && /[a-zA-Z]/.test(part));\r\n\r\n return parts?.sort((left, right) => right.length - left.length)[0] || \"\";\r\n};\r\n\r\nconst getNumericSafeAttributeCondition = (\r\n attributeName: string,\r\n attributeValue: string\r\n): string => {\r\n // Strict numeric-attribute validation: numeric attributes must not be\r\n // converted into \"safe\" attribute predicates.\r\n return \"\";\r\n};\r\n\r\nconst getNumericSafeAttributeXpath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n attributeName: string,\r\n attributeValue: string\r\n): string => {\r\n // Strict numeric-attribute validation: all numeric attribute XPath fallbacks\r\n // are disabled; callers should continue to text/context strategies.\r\n return \"\";\r\n};\r\n\r\nexport const getReferenceElementsXpath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean\r\n): { key: string; value: string }[] => {\r\n let nodeXpath1;\r\n const xpaths1 = [];\r\n if (domNode.textContent && isTarget && isNumberExist(domNode.textContent)) {\r\n // Numeric target text can still yield stable starts-with/contains text\r\n // candidates, e.g. SPRING SUMMER 26 -> SPRING SUMMER.\r\n const { prefix, fragment } = getStableTargetTextCandidates(\r\n getTextContent(domNode)\r\n );\r\n const textConditions = [\r\n prefix\r\n ? `starts-with(normalize-space(.),${escapeCharacters(prefix)})`\r\n : \"\",\r\n fragment\r\n ? `contains(normalize-space(.),${escapeCharacters(fragment)})`\r\n : \"\"\r\n ].filter((condition, index, conditions) =>\r\n condition && conditions.indexOf(condition) === index\r\n );\r\n\r\n for (const textCondition of textConditions) {\r\n nodeXpath1 = isSvg(domNode)\r\n ? `*[local-name()='${domNode.tagName}' and ${textCondition}]`\r\n : `${domNode.tagName}[${textCondition}]`;\r\n xpaths1.push({ key: \"getReferenceElementsXpath\", value: nodeXpath1 });\r\n }\r\n }\r\n\r\n if (\r\n domNode.textContent &&\r\n (!isTarget || (isTarget && !isNumberExist(domNode.textContent)))\r\n ) {\r\n if (!reWhiteSpace.test(domNode.textContent)) {\r\n const textCondition = getTextXpathFunction(domNode);\r\n if (textCondition) {\r\n nodeXpath1 = isSvg(domNode)\r\n ? `*[local-name()='${domNode.tagName}' and ${textCondition}]`\r\n : `${domNode.tagName}[${textCondition}]`;\r\n xpaths1.push({ key: \"getReferenceElementsXpath\", value: nodeXpath1 });\r\n }\r\n } else {\r\n const textContent = getTextContent(domNode);\r\n const containerTextCondition = getContainerTextCondition(\r\n domNode,\r\n textContent\r\n );\r\n const textCondition = containerTextCondition\r\n ? containerTextCondition\r\n : /\\s/.test(textContent.trim())\r\n ? `normalize-space(.)=${escapeCharacters(\r\n replaceWhiteSpaces(textContent)\r\n )}`\r\n : `.=${escapeCharacters(textContent)}`;\r\n nodeXpath1 = isSvg(domNode)\r\n ? `*[local-name()='${domNode.tagName}' and ${textCondition}]`\r\n : `${domNode.tagName}[${textCondition}]`;\r\n if (nodeXpath1) {\r\n xpaths1.push({ key: \"getReferenceElementsXpath\", value: nodeXpath1 });\r\n }\r\n }\r\n }\r\n\r\n if (domNode.attributes) {\r\n const attributes =\r\n domNode.tagName === \"IMG\"\r\n ? Array.from(domNode.attributes).sort((left, right) => {\r\n if (left.name === \"alt\") return -1;\r\n if (right.name === \"alt\") return 1;\r\n return 0;\r\n })\r\n : Array.from(domNode.attributes);\r\n\r\n for (const attrName of attributes) {\r\n if (checkBlockedAttributes(attrName, domNode, isTarget)) {\r\n let attrValue = attrName.nodeValue;\r\n if (attrValue) {\r\n attrValue = sanitizeAttributeValue(attrName.name, attrValue);\r\n const elementName = attrName.name;\r\n // Strict numeric-attribute validation for direct callers that bypass\r\n // checkBlockedAttributes. Class is tokenized below, so only numeric\r\n // class tokens are skipped by getClassTokenCondition.\r\n if (elementName !== \"class\" && hasNumericAttributeValue(attrValue)) {\r\n continue;\r\n }\r\n\r\n if (elementName === \"class\") {\r\n const classConditions = getClassTokenConditions(\r\n domNode,\r\n attrValue,\r\n docmt\r\n );\r\n\r\n if (!classConditions.length) {\r\n continue;\r\n }\r\n\r\n for (const classCondition of classConditions) {\r\n nodeXpath1 = isSvg(domNode)\r\n ? `*[local-name()='${domNode.tagName}' and ${classCondition}]`\r\n : `${domNode.tagName}[${classCondition}]`;\r\n\r\n xpaths1.push({\r\n key: \"getReferenceElementsXpath\",\r\n value: nodeXpath1\r\n });\r\n }\r\n\r\n continue;\r\n } else {\r\n nodeXpath1 = isSvg(domNode)\r\n ? `*[local-name()='${\r\n domNode.tagName\r\n }' and @${elementName}=${escapeCharacters(attrValue)}]`\r\n : `${domNode.tagName}[@${elementName}=${escapeCharacters(\r\n attrValue\r\n )}]`;\r\n }\r\n\r\n if (nodeXpath1) {\r\n xpaths1.push({\r\n key: \"getReferenceElementsXpath\",\r\n value: nodeXpath1\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n const attributesArray = Array.prototype.slice.call(domNode.attributes);\r\n if (attributesArray?.length > 1) {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n domNode,\r\n docmt,\r\n Array.prototype.slice.call(domNode.attributes),\r\n isTarget\r\n );\r\n if (combinationXpath) {\r\n xpaths1.push({\r\n key: \"getReferenceElementsXpath\",\r\n value: combinationXpath\r\n });\r\n }\r\n }\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n const combinePattern = [];\r\n let pattern;\r\n const tag = domNode.tagName;\r\n if (domNode.textContent && isTarget && isNumberExist(domNode.textContent)) {\r\n const targetText = replaceWhiteSpaces(getTextContent(domNode)).trim();\r\n if (targetText?.length > 1) {\r\n combinePattern.push(`contains(text(),${escapeCharacters(targetText)})`);\r\n }\r\n\r\n if (combinePattern?.length) {\r\n if (isSvg(domNode)) {\r\n pattern = `*[local-name()='${tag}' and ${combinePattern.join(\r\n \" and \"\r\n )}]`;\r\n } else {\r\n pattern = `${tag}[${combinePattern.join(\" and \")}]`;\r\n }\r\n\r\n if (pattern)\r\n xpaths1.push({ key: \"getReferenceElementsXpath\", value: pattern });\r\n }\r\n }\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n const xpaths = addAttributeSplitCombineXpaths(\r\n domNode.attributes,\r\n domNode,\r\n docmt,\r\n isTarget\r\n );\r\n if (xpaths?.length) {\r\n xpaths1.concat(xpaths);\r\n }\r\n }\r\n\r\n return xpaths1;\r\n};\r\n\r\nexport const parseXml = (\r\n xmlStr: string,\r\n type: DOMParserSupportedType\r\n): Document | null => {\r\n if (window.DOMParser) {\r\n return new window.DOMParser().parseFromString(xmlStr, type);\r\n }\r\n\r\n return null;\r\n};\r\n\r\nexport const normalizeXPath = (xpath: string): string => {\r\n // Replace text() = \"value\" or text()='value'\r\n xpath = xpath.replace(\r\n /text\\(\\)\\s*=\\s*(['\"])(.*?)\\1/g,\r\n \"normalize-space(.)=$1$2$1\"\r\n );\r\n\r\n // Replace . = \"value\" or .='value'\r\n xpath = xpath.replace(/\\.\\s*=\\s*(['\"])(.*?)\\1/g, \"normalize-space(.)=$1$2$1\");\r\n\r\n return xpath;\r\n};\r\n\r\nexport const findMatchingParenthesis = (\r\n text: string,\r\n openPos: number\r\n): number => {\r\n let closePos = openPos;\r\n let counter = 1;\r\n while (counter > 0) {\r\n const c = text[++closePos];\r\n if (c == \"(\") {\r\n counter++;\r\n } else if (c == \")\") {\r\n counter--;\r\n }\r\n }\r\n return closePos;\r\n};\r\n\r\nexport function canonicalizeXPath(xpath: string): string {\r\n return (\r\n xpath\r\n .toLowerCase()\r\n // replace quoted values\r\n .replace(/'[^']*'/g, \"?\")\r\n .replace(/\"[^\"]*\"/g, \"?\")\r\n // replace numbers in predicates\r\n .replace(/\\[\\d+\\]/g, \"[?]\")\r\n // normalize node names\r\n .replace(/\\/\\/[a-z0-9_-]+/g, \"//node\")\r\n .replace(/\\/[a-z0-9_-]+/g, \"/node\")\r\n );\r\n}\r\n\r\nexport function extractXPathSignatureParts(xpath: string) {\r\n const xp = xpath.toLowerCase();\r\n\r\n const axisMatch = xp.match(\r\n /(ancestor-or-self|ancestor|descendant-or-self|descendant|following-sibling|preceding-sibling|following|preceding|parent|child|self)::/\r\n );\r\n const axis = axisMatch?.[1] ?? \"none\";\r\n\r\n const attrMatch = xp.match(/@([a-z0-9:-]+)/);\r\n const attribute = attrMatch?.[1] ?? \"none\";\r\n\r\n const usesNormalize = xp.includes(\"normalize-space\");\r\n\r\n return { axis, attribute, usesNormalize };\r\n}\r\n\r\nexport function getXPathPattern(xpath: string): string {\r\n const canonical = canonicalizeXPath(xpath);\r\n const parts = extractXPathSignatureParts(xpath);\r\n\r\n return [\r\n \"XPATH\",\r\n `axis:${parts.axis}`,\r\n `attr:${parts.attribute}`,\r\n `normalize:${parts.usesNormalize}`,\r\n `shape:${canonical}`\r\n ].join(\"|\");\r\n}\r\n\r\nexport function escapeAttrValue(value: string): string {\r\n return value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"').replace(/ /g, \"\\\\ \");\r\n}\r\n\r\nexport function shouldUseSnapshot(xpath: string): boolean {\r\n return /\\[(?:\\s*\\.|\\s*contains\\s*\\(\\s*\\.|\\s*normalize-space\\s*\\(\\s*\\.)/.test(\r\n xpath\r\n );\r\n}\r\n\r\nexport function isUniqueInDOM(\r\n docmt: Document,\r\n name: string,\r\n value: string,\r\n element?: Element | null\r\n): boolean {\r\n const root = (element?.getRootNode?.() as ParentNode | null) ?? docmt;\r\n const queryAll = (selector: string): Element[] => {\r\n try {\r\n return Array.from(root.querySelectorAll(selector));\r\n } catch {\r\n return [];\r\n }\r\n };\r\n\r\n try {\r\n switch (name) {\r\n case \"id\":\r\n return queryAll(`#${escapeAttrValue(value)}`).length === 1;\r\n\r\n case \"name\":\r\n return queryAll(`[name=\"${escapeAttrValue(value)}\"]`).length === 1;\r\n\r\n case \"className\":\r\n return queryAll(`.${value}`).length === 1;\r\n\r\n case \"tagName\":\r\n return queryAll(value).length === 1;\r\n\r\n case \"linkText\":\r\n return (\r\n queryAll(\"a\").filter((a) => a.textContent?.trim() === value)\r\n .length === 1\r\n );\r\n case \"partialLinkText\":\r\n return (\r\n queryAll(\"a\").filter((a) => a.textContent?.includes(value)).length ===\r\n 1\r\n );\r\n case \"cssSelector\":\r\n return queryAll(value).length === 1;\r\n default:\r\n return false;\r\n }\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport const xpathUtils = {\r\n parseXml,\r\n getReferenceElementsXpath,\r\n getAbsoluteXPath,\r\n getRelativeXPath,\r\n getCombinationXpath,\r\n getAttributeCombinationXpath,\r\n getElementFromXpath,\r\n isSvg,\r\n findXpathWithIndex,\r\n isNumberExist,\r\n getTextContent,\r\n getCountOfXPath,\r\n normalizeXPath,\r\n getShadowRoot,\r\n escapeCharacters,\r\n removeParenthesis,\r\n checkBlockedAttributes,\r\n getRelationship,\r\n findMatchingParenthesis,\r\n deleteGarbageFromInnerText,\r\n replaceTempAttributes,\r\n createObserver,\r\n startObserver,\r\n stopObserver,\r\n modifiedElementAttributes,\r\n cspEnabled,\r\n getXPathPattern,\r\n getNormalizedPropertyXPath,\r\n getStartsWithPropertyXPath,\r\n getContainsPropertyXPath,\r\n getOrAttributesXPath,\r\n getTagOnlyXPath,\r\n getFirstMatchedNode,\r\n isExactUniqueXpath,\r\n getAxisNodeTest,\r\n getUniqueNodeAnchorXpaths,\r\n escapeAttrValue,\r\n isUniqueInDOM,\r\n sanitizeAttributeValue,\r\n getClassTokenCondition,\r\n getClassTokenConditions,\r\n getXpathStrings,\r\n intermediateXpathSteps,\r\n getContainerTextCondition\r\n};\r\n","import {\r\n isNumberExist,\r\n getCountOfXPath,\r\n escapeCharacters,\r\n checkBlockedAttributes,\r\n replaceWhiteSpaces,\r\n getTextContent,\r\n getPropertyXPath,\r\n findXpathWithIndex,\r\n getFilteredText,\r\n intermediateXpathStep,\r\n intermediateXpathSteps,\r\n getAttributeCombinationXpath,\r\n getFilteredTextXPath,\r\n getNormalizedPropertyXPath,\r\n getStartsWithPropertyXPath,\r\n getContainsPropertyXPath,\r\n getOrAttributesXPath,\r\n getTagOnlyXPath,\r\n isExactUniqueXpath,\r\n getAxisNodeTest,\r\n getUniqueNodeAnchorXpaths,\r\n isSvg,\r\n getXpathStrings,\r\n reWhiteSpace,\r\n sanitizeAttributeValue,\r\n getContainerTextCondition,\r\n getStableTargetText,\r\n hasNumericAttributeValue\r\n // timeLog\r\n} from \"./xpathHelpers.ts\";\r\n\r\nlet xpathData: { key: string; value: string }[] = [];\r\nlet xpathDataWithIndex: { key: string; value: string; count: number }[] = [];\r\nlet referenceElementMode: boolean = false;\r\nlet xpathCache = new Map();\r\nlet cache = new Map();\r\n\r\nconst parentXpathCache = new Map(); // Cache for parent XPaths\r\n\r\nconst STRATEGY_MAP = {\r\n andConditions: \"and\",\r\n orConditions: \"or\",\r\n contains: \"contains\",\r\n startsWith: \"startsWith\",\r\n normalizeSpace: \"normalizeSpace\",\r\n axes: \"axes\",\r\n index: \"index\",\r\n hardCodedText: \"text\",\r\n tillTag: \"tag\"\r\n} as const;\r\n\r\nconst getStrategyName = (strategy: string) => {\r\n return STRATEGY_MAP[strategy as keyof typeof STRATEGY_MAP] || strategy;\r\n};\r\n\r\nconst includesIndexStrategy = (strategies: string[] = []) =>\r\n strategies.some((strategy) => getStrategyName(strategy) === \"index\");\r\n\r\nconst withStrategyKey = (\r\n strategy: string,\r\n entries: { key: string; value: string }[]\r\n) => {\r\n return entries.map((entry) => ({\r\n ...entry,\r\n key: entry?.key?.includes(strategy)\r\n ? entry.key\r\n : `${strategy} ${entry.key}`.trim()\r\n }));\r\n};\r\n\r\nconst getUniqueXpathEntries = (entries: { key: string; value: string }[]) => {\r\n const seen = new Set<string>();\r\n\r\n return entries.filter((entry) => {\r\n if (!entry?.value || seen.has(entry.value)) {\r\n return false;\r\n }\r\n\r\n seen.add(entry.value);\r\n return true;\r\n });\r\n};\r\n\r\nconst hasPositionalIndex = (xpath: string) => {\r\n // Ignore numeric text inside quotes; only bare [n] predicates are indexes.\r\n let quote: string | null = null;\r\n\r\n for (let i = 0; i < xpath.length; i++) {\r\n const char = xpath[i];\r\n\r\n if (quote) {\r\n if (char === quote) {\r\n quote = null;\r\n }\r\n continue;\r\n }\r\n\r\n if (char === \"'\" || char === '\"') {\r\n quote = char;\r\n continue;\r\n }\r\n\r\n if (char !== \"[\") {\r\n continue;\r\n }\r\n\r\n const endIndex = xpath.indexOf(\"]\", i + 1);\r\n if (endIndex === -1) {\r\n return false;\r\n }\r\n\r\n if (/^\\s*\\d+\\s*$/.test(xpath.slice(i + 1, endIndex))) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n};\r\n\r\nconst removePositionalIndexXpaths = (\r\n entries: { key: string; value: string }[],\r\n isIndex: boolean\r\n) =>\r\n isIndex ? entries : entries.filter((entry) => !hasPositionalIndex(entry.value));\r\n\r\nconst getNormalizedText = (element: HTMLElement | Element) => {\r\n return element?.textContent?.replace(/\\s+/g, \" \")?.trim() || \"\";\r\n};\r\n\r\nconst buildTextStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n strategy: string\r\n) => {\r\n const text = getNormalizedText(element);\r\n\r\n if (!text) {\r\n return [];\r\n }\r\n\r\n if (strategy === \"text\") {\r\n const textXpath =\r\n getFilteredTextXPath(element, docmt) ||\r\n getTextXPath(element, docmt, false, false);\r\n\r\n return textXpath ? [{ key: \"xpath by text\", value: textXpath }] : [];\r\n }\r\n\r\n return [];\r\n};\r\n\r\nconst buildPropertyStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n isTarget: boolean,\r\n strategy: string\r\n) => {\r\n const xpaths: { key: string; value: string }[] = [];\r\n const attributes = Array.from(element.attributes || []).filter(\r\n (attribute) =>\r\n attribute?.value && checkBlockedAttributes(attribute, element, isTarget)\r\n );\r\n const text = getNormalizedText(element);\r\n const getStrategyXPath =\r\n strategy === \"contains\"\r\n ? getContainsPropertyXPath\r\n : strategy === \"startsWith\"\r\n ? getStartsWithPropertyXPath\r\n : strategy === \"normalizeSpace\"\r\n ? getNormalizedPropertyXPath\r\n : null;\r\n\r\n if (!getStrategyXPath) {\r\n return xpaths;\r\n }\r\n\r\n attributes.forEach((attribute) => {\r\n const xpath = getStrategyXPath(\r\n element,\r\n `@${attribute.name}`,\r\n attribute.value\r\n );\r\n\r\n if (xpath) {\r\n xpaths.push({\r\n key: `xpath by ${strategy} ${attribute.name}`,\r\n value: xpath\r\n });\r\n }\r\n });\r\n\r\n if (text) {\r\n const xpath = getStrategyXPath(element, \".\", text);\r\n\r\n if (xpath) {\r\n xpaths.push({\r\n key: `xpath by ${strategy} text`,\r\n value: xpath\r\n });\r\n }\r\n }\r\n\r\n return xpaths;\r\n};\r\n\r\nconst buildConditionStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n strategy: string\r\n) => {\r\n const attributes = Array.from(element.attributes || []).filter(\r\n (attribute) =>\r\n attribute?.value && checkBlockedAttributes(attribute, element, isTarget)\r\n );\r\n\r\n if (strategy === \"and\") {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n element,\r\n docmt,\r\n attributes,\r\n isTarget\r\n );\r\n\r\n return combinationXpath\r\n ? [{ key: \"xpath by combination\", value: combinationXpath }]\r\n : [];\r\n }\r\n\r\n if (strategy === \"or\" && attributes.length >= 1) {\r\n const xpath = getOrAttributesXPath(element, attributes);\r\n return xpath ? [{ key: \"xpath by or\", value: xpath }] : [];\r\n }\r\n\r\n return [];\r\n};\r\n\r\nconst collectSubtreeElements = (root: HTMLElement | Element) => {\r\n if (!root || !(root instanceof Element)) return [];\r\n\r\n const nodes: (HTMLElement | Element)[] = [];\r\n const queue = Array.from(root.children || []);\r\n\r\n while (queue.length) {\r\n const currentNode = queue.shift()!;\r\n\r\n if (currentNode.classList?.contains(\"flntooltip\")) {\r\n continue;\r\n }\r\n\r\n nodes.push(currentNode);\r\n queue.push(...Array.from(currentNode.children || []));\r\n }\r\n\r\n return nodes;\r\n};\r\n\r\nconst getSiblingNodes = (\r\n element: HTMLElement | Element,\r\n direction: \"previous\" | \"next\"\r\n) => {\r\n const nodes: (HTMLElement | Element)[] = [];\r\n let currentNode =\r\n direction === \"previous\"\r\n ? element.previousElementSibling\r\n : element.nextElementSibling;\r\n\r\n while (currentNode) {\r\n if (!currentNode.classList?.contains(\"flntooltip\")) {\r\n nodes.push(currentNode);\r\n }\r\n\r\n currentNode =\r\n direction === \"previous\"\r\n ? currentNode.previousElementSibling\r\n : currentNode.nextElementSibling;\r\n }\r\n\r\n return nodes;\r\n};\r\n\r\ntype AxisSeedNode =\r\n | Element\r\n | {\r\n node: Element;\r\n expand: () => Element[];\r\n };\r\n\r\nconst getDirectionalAxisSeedNodes = (\r\n element: HTMLElement | Element,\r\n direction: \"previous\" | \"next\"\r\n): AxisSeedNode[] => {\r\n const nodes: AxisSeedNode[] = [];\r\n\r\n for (\r\n let currentNode: HTMLElement | Element | null = element;\r\n currentNode?.parentElement;\r\n currentNode = currentNode.parentElement\r\n ) {\r\n let sibling =\r\n direction === \"previous\"\r\n ? currentNode.previousElementSibling\r\n : currentNode.nextElementSibling;\r\n\r\n while (sibling) {\r\n if (!sibling.classList?.contains(\"flntooltip\")) {\r\n nodes.push(sibling);\r\n\r\n nodes.push({\r\n node: sibling,\r\n expand: () => collectSubtreeElements(sibling as HTMLElement)\r\n });\r\n }\r\n\r\n sibling =\r\n direction === \"previous\"\r\n ? sibling.previousElementSibling\r\n : sibling.nextElementSibling;\r\n }\r\n }\r\n\r\n return nodes;\r\n};\r\n\r\nconst isLowQualityNode = (node: Element) => {\r\n if (!(node instanceof Element)) return true;\r\n const text = node.textContent?.trim();\r\n\r\n return (\r\n !node.id &&\r\n !node.className &&\r\n node.attributes.length === 0 &&\r\n (!text || text.length > 60) &&\r\n node.children.length > 2\r\n );\r\n};\r\n\r\nconst scoreNode = (node: Element) => {\r\n // Prefer stable/readable nearby anchors when building chained axes fallbacks.\r\n let score = 0;\r\n if (node.id) score += 100;\r\n if (node.getAttribute(\"data-testid\")) score += 90;\r\n if (node.className) score += 50;\r\n if (node.children.length === 0) score += 30;\r\n\r\n const text = node.textContent?.trim();\r\n if (text && text.length < 40) score += 40;\r\n\r\n return score;\r\n};\r\n\r\nconst buildAxisXpathsForNodes = (\r\n nodes: any[],\r\n axis: string,\r\n targetElement: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n key: string,\r\n isIndex: boolean\r\n) => {\r\n const targetNodeTest = getAxisNodeTest(targetElement);\r\n const MAX_INDEX_TRY = 3;\r\n const MAX_CANDIDATES = 5;\r\n\r\n const candidates: { key: string; value: string }[] = [];\r\n\r\n let processed = 0;\r\n const MAX_PROCESS = axis.includes(\"descendant\") ? 10 : 20;\r\n\r\n for (const nodeItem of nodes) {\r\n if (processed++ > MAX_PROCESS) break;\r\n if (candidates.length >= MAX_CANDIDATES) break;\r\n\r\n const node = \"node\" in nodeItem ? nodeItem.node : nodeItem;\r\n\r\n if (!(node instanceof Element)) continue;\r\n if (isLowQualityNode(node)) continue;\r\n\r\n const anchorStages = [\r\n () => getUniqueNodeAnchorXpaths(node, docmt, isTarget),\r\n () => {\r\n const anchors: any[] = [];\r\n const attributes = Array.from(node.attributes || []).filter(\r\n (attr) =>\r\n attr?.value &&\r\n !/\\d/.test(attr.value) &&\r\n checkBlockedAttributes(attr, node, isTarget)\r\n );\r\n\r\n for (const attr of attributes) {\r\n const value = attr.value;\r\n if (!value) continue;\r\n\r\n const containsXpath = getContainsPropertyXPath(\r\n node,\r\n `@${attr.name}`,\r\n value\r\n );\r\n if (containsXpath) {\r\n anchors.push({ key: \"contains\", value: containsXpath });\r\n }\r\n\r\n const startsWithXpath = getStartsWithPropertyXPath(\r\n node,\r\n `@${attr.name}`,\r\n value\r\n );\r\n if (startsWithXpath) {\r\n anchors.push({ key: \"starts-with\", value: startsWithXpath });\r\n }\r\n }\r\n\r\n return anchors;\r\n },\r\n () => [{ key: \"tag\", value: getTagOnlyXPath(node, docmt) }]\r\n ];\r\n\r\n for (let stageIndex = 0; stageIndex < anchorStages.length; stageIndex++) {\r\n let anchors = anchorStages[stageIndex]();\r\n if (!anchors.length) continue;\r\n\r\n if (!isIndex) {\r\n anchors = anchors.filter((a) => !/\\[\\d+\\]/.test(a.value));\r\n }\r\n\r\n const seen = new Set<string>();\r\n anchors = anchors.filter((a) => {\r\n if (seen.has(a.value)) return false;\r\n seen.add(a.value);\r\n return true;\r\n });\r\n\r\n anchors = anchors.slice(0, 5);\r\n\r\n for (const anchor of anchors) {\r\n const xpath = `${anchor.value}/${axis}::${targetNodeTest}`;\r\n\r\n if (isExactUniqueXpath(xpath, targetElement, docmt)) {\r\n candidates.push({ key, value: xpath });\r\n\r\n if (candidates.length >= 2) {\r\n return candidates;\r\n }\r\n\r\n if (candidates.length >= MAX_CANDIDATES) {\r\n return candidates;\r\n }\r\n }\r\n }\r\n\r\n if (isIndex && stageIndex === anchorStages.length - 1) {\r\n for (const anchor of anchors) {\r\n const count = getCountOfXPath(anchor.value, node, docmt);\r\n\r\n for (let i = 1; i <= Math.min(count, MAX_INDEX_TRY); i++) {\r\n const xpath = `(${anchor.value})[${i}]/${axis}::${targetNodeTest}`;\r\n\r\n if (isExactUniqueXpath(xpath, targetElement, docmt)) {\r\n candidates.push({ key, value: xpath });\r\n\r\n if (candidates.length >= 2) {\r\n return candidates;\r\n }\r\n\r\n if (candidates.length >= MAX_CANDIDATES) {\r\n return candidates;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (\"expand\" in nodeItem && nodeItem.expand) {\r\n const expanded = nodeItem.expand();\r\n\r\n let childCount = 0;\r\n for (const child of expanded) {\r\n if (childCount++ > 15) break;\r\n if (candidates.length >= MAX_CANDIDATES) break;\r\n\r\n if (!(child instanceof Element)) continue;\r\n if (isLowQualityNode(child)) continue;\r\n\r\n const anchors = getUniqueNodeAnchorXpaths(child, docmt, isTarget);\r\n\r\n for (const anchor of anchors.slice(0, 5)) {\r\n const xpath = `${anchor.value}/${axis}::${targetNodeTest}`;\r\n\r\n if (isExactUniqueXpath(xpath, targetElement, docmt)) {\r\n candidates.push({ key, value: xpath });\r\n\r\n if (candidates.length >= 2) {\r\n return candidates;\r\n }\r\n\r\n if (candidates.length >= MAX_CANDIDATES) {\r\n return candidates;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return candidates;\r\n};\r\n\r\nconst getLimitedAncestors = (node: Element | null, limit: number) => {\r\n // Keep fallback scope search bounded.\r\n const ancestors: Element[] = [];\r\n let currentNode = node;\r\n\r\n while (currentNode && ancestors.length < limit) {\r\n ancestors.push(currentNode);\r\n currentNode = currentNode.parentElement;\r\n }\r\n\r\n return ancestors;\r\n};\r\n\r\nconst getSiblingAxis = (from: Element, to: Element) => {\r\n for (let node = from.nextElementSibling; node; node = node.nextElementSibling) {\r\n if (node === to) return \"following-sibling\";\r\n }\r\n\r\n for (\r\n let node = from.previousElementSibling;\r\n node;\r\n node = node.previousElementSibling\r\n ) {\r\n if (node === to) return \"preceding-sibling\";\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getParentAxisPath = (from: Element, to: Element) => {\r\n const parts: string[] = [];\r\n\r\n for (let node = from; node && node !== to; node = node.parentElement!) {\r\n const parent = node.parentElement;\r\n if (!parent) return \"\";\r\n\r\n parts.push(`/parent::${getAxisNodeTest(parent)}`);\r\n }\r\n\r\n return parts.join(\"\");\r\n};\r\n\r\nconst getTargetPathFromScope = (\r\n scope: Element,\r\n targetElement: HTMLElement | Element\r\n) => {\r\n const targetNodeTest = getAxisNodeTest(targetElement);\r\n\r\n return targetElement.parentElement === scope\r\n ? [`/${targetNodeTest}`, `/descendant::${targetNodeTest}`]\r\n : [`/descendant::${targetNodeTest}`];\r\n};\r\n\r\nconst collectChainedAxisAnchorNodes = (element: HTMLElement | Element) => {\r\n // Collect nearby sibling-side anchors for cases where direct axes cannot\r\n // reach the target cleanly.\r\n const anchors: Element[] = [];\r\n const seen = new Set<Element>();\r\n const MAX_SCOPE_DEPTH = 4;\r\n const MAX_SIBLINGS_PER_SCOPE = 4;\r\n const MAX_DESCENDANTS_PER_SIBLING = 8;\r\n const MAX_ANCHORS = 20;\r\n\r\n const push = (node: Element | null) => {\r\n if (!node || node === element || seen.has(node)) return;\r\n if (node.contains(element) || element.contains(node)) return;\r\n\r\n seen.add(node);\r\n anchors.push(node);\r\n };\r\n\r\n for (\r\n let scope: Element | null = element.parentElement, depth = 0;\r\n scope && depth < MAX_SCOPE_DEPTH && anchors.length < MAX_ANCHORS;\r\n scope = scope.parentElement, depth++\r\n ) {\r\n const siblingGroups = [\r\n getSiblingNodes(scope, \"previous\").slice(0, MAX_SIBLINGS_PER_SCOPE),\r\n getSiblingNodes(scope, \"next\").slice(0, MAX_SIBLINGS_PER_SCOPE)\r\n ];\r\n\r\n for (const siblings of siblingGroups) {\r\n for (const sibling of siblings) {\r\n push(sibling);\r\n\r\n let descendantCount = 0;\r\n for (const descendant of collectSubtreeElements(sibling).sort(\r\n (left, right) => scoreNode(right) - scoreNode(left)\r\n )) {\r\n if (descendantCount++ >= MAX_DESCENDANTS_PER_SIBLING) break;\r\n push(descendant);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return anchors\r\n .sort((left, right) => scoreNode(right) - scoreNode(left))\r\n .slice(0, MAX_ANCHORS);\r\n};\r\n\r\nconst buildChainedAxesFallbackXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean\r\n) => {\r\n // Last axes fallback: anchor on a nearby node, hop to a sibling scope, then\r\n // descend to the target.\r\n const candidates: { key: string; value: string }[] = [];\r\n const seen = new Set<string>();\r\n const anchorNodes = collectChainedAxisAnchorNodes(element);\r\n const targetScopes = getLimitedAncestors(element.parentElement, 3);\r\n\r\n for (const anchorNode of anchorNodes) {\r\n const anchorXpaths = getUniqueNodeAnchorXpaths(anchorNode, docmt, isTarget)\r\n .filter((anchor) => anchor.key !== \"anchor by tag\")\r\n .slice(0, 2);\r\n\r\n if (!anchorXpaths.length) continue;\r\n\r\n const anchorScopes = getLimitedAncestors(anchorNode, 3);\r\n\r\n for (const anchorXpath of anchorXpaths) {\r\n for (const anchorScope of anchorScopes) {\r\n const anchorToScopePath = getParentAxisPath(anchorNode, anchorScope);\r\n if (anchorScope !== anchorNode && !anchorToScopePath) continue;\r\n\r\n for (const targetScope of targetScopes) {\r\n if (!targetScope || !targetScope.contains(element)) continue;\r\n\r\n const siblingAxis = getSiblingAxis(anchorScope, targetScope);\r\n if (!siblingAxis) continue;\r\n\r\n const siblingStep = `/${siblingAxis}::${getAxisNodeTest(targetScope)}`;\r\n\r\n for (const targetPath of getTargetPathFromScope(targetScope, element)) {\r\n const xpath = `${anchorXpath.value}${anchorToScopePath}${siblingStep}${targetPath}`;\r\n\r\n if (seen.has(xpath)) continue;\r\n seen.add(xpath);\r\n\r\n if (isExactUniqueXpath(xpath, element, docmt)) {\r\n candidates.push({\r\n key: \"chained axes fallback\",\r\n value: xpath\r\n });\r\n\r\n if (candidates.length >= 2) {\r\n return candidates;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return candidates;\r\n};\r\n\r\nconst getChildAxisPathFromAncestor = (\r\n ancestor: Element,\r\n element: HTMLElement | Element\r\n) => {\r\n // Build the child-axis tail from an anchored ancestor down to the target.\r\n const steps: string[] = [];\r\n\r\n for (\r\n let currentNode: HTMLElement | Element | null = element;\r\n currentNode && currentNode !== ancestor;\r\n currentNode = currentNode.parentElement\r\n ) {\r\n steps.unshift(getAxisNodeTest(currentNode));\r\n }\r\n\r\n if (!steps.length) return \"\";\r\n\r\n const finalStep = steps.pop();\r\n const intermediatePath = steps.length ? `/${steps.join(\"/\")}` : \"\";\r\n\r\n return `${intermediatePath}/child::${finalStep}`;\r\n};\r\n\r\nconst getStableAxisAttributeValue = (attributeValue: string) => {\r\n // Single-mode axis anchors may use a stable prefix before a numeric suffix.\r\n const valueBeforeNumber = attributeValue.split(/\\d/)[0] || \"\";\r\n const stableValue = valueBeforeNumber.replace(/[-_:\\s.]+$/g, \"\").trim();\r\n\r\n return stableValue.length > 2 && /[a-zA-Z]/.test(stableValue)\r\n ? stableValue\r\n : \"\";\r\n};\r\n\r\nconst canUseStableAxisAttribute = (attribute: Attr) => {\r\n const blockedNames = [\"style\", \"locator-data-tooltip\", \"value\"];\r\n\r\n return (\r\n !!attribute?.value &&\r\n !blockedNames.includes(attribute.name) &&\r\n !(attribute.name.indexOf(\"on\") === 0 && attribute.name.length > 3)\r\n );\r\n};\r\n\r\nconst getChildChainAnchorXpaths = (\r\n ancestor: Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n isIndex: boolean\r\n) => {\r\n // Use normal unique anchors plus stable numeric-prefix anchors for child\r\n // chain generation.\r\n const seen = new Set<string>();\r\n const anchors: { key: string; value: string }[] = [];\r\n const addAnchor = (key: string, value: string) => {\r\n if (!value || seen.has(value)) return;\r\n if (!isIndex && /\\[\\d+\\]/.test(value)) return;\r\n\r\n seen.add(value);\r\n anchors.push({ key, value });\r\n };\r\n\r\n getUniqueNodeAnchorXpaths(ancestor, docmt, isTarget)\r\n .filter((anchor) => anchor.key !== \"anchor by tag\")\r\n .forEach((anchor) => addAnchor(anchor.key, anchor.value));\r\n\r\n Array.from(ancestor.attributes || []).forEach((attribute) => {\r\n if (\r\n !canUseStableAxisAttribute(attribute) ||\r\n !hasNumericAttributeValue(attribute.value) ||\r\n attribute.name === \"class\"\r\n ) {\r\n return;\r\n }\r\n\r\n const stableValue = getStableAxisAttributeValue(attribute.value);\r\n if (!stableValue) return;\r\n\r\n const xpath = getContainsPropertyXPath(\r\n ancestor,\r\n `@${attribute.name}`,\r\n stableValue\r\n );\r\n addAnchor(`anchor by stable ${attribute.name}`, xpath);\r\n });\r\n\r\n return anchors;\r\n};\r\n\r\nconst buildAnchoredChildChainAxesXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n isIndex: boolean\r\n) => {\r\n // Prefer direct anchored child-chain paths before broader chained axes.\r\n const candidates: { key: string; value: string }[] = [];\r\n const seen = new Set<string>();\r\n const MAX_ANCESTORS = 8;\r\n\r\n for (\r\n let ancestor = element.parentElement, depth = 0;\r\n ancestor && depth < MAX_ANCESTORS;\r\n ancestor = ancestor.parentElement, depth++\r\n ) {\r\n const childAxisPath = getChildAxisPathFromAncestor(ancestor, element);\r\n if (!childAxisPath) continue;\r\n\r\n const anchors = getChildChainAnchorXpaths(\r\n ancestor,\r\n docmt,\r\n isTarget,\r\n isIndex\r\n );\r\n\r\n for (const anchor of anchors.slice(0, 3)) {\r\n const xpath = `${anchor.value}${childAxisPath}`;\r\n\r\n if (seen.has(xpath)) continue;\r\n seen.add(xpath);\r\n\r\n if (isExactUniqueXpath(xpath, element, docmt)) {\r\n candidates.push({\r\n key: \"child chain\",\r\n value: xpath\r\n });\r\n\r\n if (candidates.length >= 2) {\r\n return candidates;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return candidates;\r\n};\r\n\r\nconst buildAxesStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n isIndex: boolean\r\n) => {\r\n // const totalStart = performance.now();\r\n\r\n // let t = performance.now();\r\n\r\n const ancestors: (HTMLElement | Element)[] = [];\r\n\r\n for (\r\n let currentNode = element.parentElement;\r\n currentNode;\r\n currentNode = currentNode.parentElement\r\n ) {\r\n ancestors.push(currentNode);\r\n }\r\n // timeLog(\"ancestors collection\", t);\r\n // t = performance.now();\r\n const descendants = collectSubtreeElements(element);\r\n // timeLog(\"descendants collection\", t);\r\n // t = performance.now();\r\n const previousSiblings = getSiblingNodes(element, \"previous\");\r\n // timeLog(\"previous siblings collection\", t);\r\n\r\n const nextSiblings = getSiblingNodes(element, \"next\");\r\n // timeLog(\"next siblings collection\", t);\r\n\r\n const precedingSeeds = getDirectionalAxisSeedNodes(element, \"previous\");\r\n // timeLog(\"preceding seeds collection\", t);\r\n // t = performance.now();\r\n const followingSeeds = getDirectionalAxisSeedNodes(element, \"next\");\r\n // timeLog(\"following seeds collection\", t);\r\n // t = performance.now();\r\n const limitNodes = (nodes: any[], limit = 20) => {\r\n return nodes.length > limit ? nodes.slice(0, limit) : nodes;\r\n };\r\n\r\n const tiers = [\r\n [\r\n {\r\n nodes: limitNodes(nextSiblings),\r\n axis: \"preceding-sibling\",\r\n key: \"preceding-sibling\"\r\n },\r\n {\r\n nodes: limitNodes(previousSiblings),\r\n axis: \"following-sibling\",\r\n key: \"following-sibling\"\r\n }\r\n ],\r\n [\r\n { nodes: limitNodes(ancestors), axis: \"child\", key: \"child\" },\r\n {\r\n nodes: limitNodes(descendants, 15),\r\n axis: \"parent\",\r\n key: \"parent\"\r\n }\r\n ],\r\n [\r\n { nodes: limitNodes(ancestors), axis: \"descendant\", key: \"descendant\" },\r\n {\r\n nodes: limitNodes(ancestors),\r\n axis: \"descendant-or-self\",\r\n key: \"descendant-or-self\"\r\n },\r\n {\r\n nodes: limitNodes(descendants, 10),\r\n axis: \"ancestor\",\r\n key: \"ancestor\"\r\n },\r\n {\r\n nodes: limitNodes(descendants, 10),\r\n axis: \"ancestor-or-self\",\r\n key: \"ancestor-or-self\"\r\n }\r\n ],\r\n [\r\n {\r\n nodes: limitNodes(precedingSeeds),\r\n axis: \"following\",\r\n key: \"following\"\r\n },\r\n { nodes: limitNodes(followingSeeds), axis: \"preceding\", key: \"preceding\" }\r\n ]\r\n ];\r\n // timeLog(\"nodes sorting\", t);\r\n const childChainResults = buildAnchoredChildChainAxesXpaths(\r\n element,\r\n docmt,\r\n isTarget,\r\n isIndex\r\n );\r\n if (childChainResults.length) {\r\n return childChainResults;\r\n }\r\n\r\n for (const tier of tiers) {\r\n for (const strategy of tier) {\r\n // const t = performance.now();\r\n\r\n const results = buildAxisXpathsForNodes(\r\n strategy.nodes,\r\n strategy.axis,\r\n element,\r\n docmt,\r\n isTarget,\r\n strategy.key,\r\n isIndex\r\n );\r\n\r\n // timeLog(`strategy ${strategy.key}`, t);\r\n if (results.length > 0) {\r\n // timeLog(\"TOTAL buildAxesStrategyXpaths\", totalStart);\r\n return results;\r\n }\r\n }\r\n }\r\n\r\n return buildChainedAxesFallbackXpaths(element, docmt, isTarget) || [];\r\n};\r\n\r\nexport const generateIndexedXpaths = (element: Element, docmt: Document) => {\r\n const results = [];\r\n const tag = element.tagName.toLowerCase();\r\n\r\n const globalList = Array.from(docmt.querySelectorAll(tag));\r\n const idx = globalList.indexOf(element) + 1;\r\n\r\n if (idx <= 0) return [];\r\n\r\n // global must always exist)\r\n results.push({\r\n key: \"xpath by index\",\r\n value: `(//${tag})[${idx}]`\r\n });\r\n\r\n // Add at most one scoped/indexed XPath anchored by the nearest stable ancestor.\r\n let current: Element | null = element.parentElement;\r\n\r\n while (current && current !== docmt.body) {\r\n if (current.id || current.className) {\r\n const scopeXpaths = current.id\r\n ? getXpathStrings(current, \"id\", current.id)\r\n : getXpathStrings(current, \"class\", current.className.toString());\r\n\r\n // Scoped index anchors should also try every stable class token before\r\n // walking to a higher ancestor.\r\n for (const scopeXpath of scopeXpaths) {\r\n const scopedDescendants = Array.from(current.querySelectorAll(tag));\r\n const scopedIdx = scopedDescendants.indexOf(element) + 1;\r\n\r\n if (scopedIdx > 0) {\r\n results.push({\r\n key: \"xpath by index\",\r\n value: `(${scopeXpath}//${tag})[${scopedIdx}]`\r\n });\r\n break;\r\n }\r\n }\r\n\r\n if (results.length > 1) {\r\n break;\r\n }\r\n }\r\n\r\n current = current.parentElement;\r\n }\r\n\r\n return results;\r\n};\r\n\r\nconst buildStrategyXpaths = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n strategy: string,\r\n fallbackXpaths: { key: string; value: string }[]\r\n) => {\r\n const strategyName = getStrategyName(strategy);\r\n\r\n if (strategyName === \"text\") {\r\n return withStrategyKey(\r\n strategy,\r\n buildTextStrategyXpaths(element, docmt, strategyName)\r\n );\r\n }\r\n\r\n if ([\"contains\", \"startsWith\", \"normalizeSpace\"].includes(strategyName)) {\r\n return withStrategyKey(\r\n strategy,\r\n buildPropertyStrategyXpaths(element, isTarget, strategyName)\r\n );\r\n }\r\n\r\n if ([\"and\", \"or\"].includes(strategyName)) {\r\n return withStrategyKey(\r\n strategy,\r\n buildConditionStrategyXpaths(element, docmt, isTarget, strategyName)\r\n );\r\n }\r\n\r\n if (strategyName === \"axes\") {\r\n return withStrategyKey(\r\n strategy,\r\n buildAxesStrategyXpaths(element, docmt, isTarget, false)\r\n );\r\n }\r\n\r\n if (strategyName === \"index\") {\r\n return withStrategyKey(strategy, generateIndexedXpaths(element, docmt));\r\n }\r\n\r\n if (strategyName === \"tag\") {\r\n return withStrategyKey(strategy, [\r\n { key: \"xpath till tag\", value: getTagOnlyXPath(element, docmt) }\r\n ]);\r\n }\r\n\r\n return [];\r\n};\r\n\r\nconst checkRelativeXpathRelation = (\r\n nodeXpath1: string,\r\n nodeXpath2: string,\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n relationType: string\r\n) => {\r\n if (nodeXpath1 && !referenceElementMode) {\r\n let xpaths;\r\n\r\n if (relationType === \"parent\") {\r\n xpaths = [\r\n // `${nodeXpath1}/descendant::${nodeXpath2}`,\r\n `${nodeXpath1}/descendant-or-self::${nodeXpath2}`,\r\n `${nodeXpath1}/following::${nodeXpath2}`\r\n ];\r\n } else {\r\n xpaths = [\r\n // `${nodeXpath1}/descendant::${nodeXpath2}`,\r\n `${nodeXpath1}/ancestor-or-self::${nodeXpath2}`,\r\n `${nodeXpath1}/preceding::${nodeXpath2}`\r\n ];\r\n }\r\n\r\n // Iterate through XPath patterns\r\n for (const xpath of xpaths) {\r\n // Check if result is already cached to avoid recomputation\r\n if (!xpathCache?.get(xpath)) {\r\n // Compute and store result in cache\r\n xpathCache.set(xpath, getCountOfXPath(xpath, targetElemt, docmt));\r\n }\r\n\r\n const count = xpathCache?.get(xpath);\r\n\r\n // Short-circuit: Return the first valid XPath result found\r\n if (count === 1) {\r\n return xpath;\r\n }\r\n if (count > 1) {\r\n if (xpathDataWithIndex.length) {\r\n if (count < xpathDataWithIndex[0].count) {\r\n xpathDataWithIndex.pop();\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by unique parent ${isIndex ? \"index\" : \"\"}`,\r\n value: xpath,\r\n count\r\n });\r\n }\r\n } else {\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by unique parent ${isIndex ? \"index\" : \"\"}`,\r\n value: xpath,\r\n count\r\n });\r\n }\r\n }\r\n\r\n if (count > 1 && isIndex && !xpathData.length) {\r\n // Try finding XPath with index if count is greater than 1\r\n const indexedXpath = findXpathWithIndex(\r\n xpath,\r\n targetElemt,\r\n docmt,\r\n count\r\n );\r\n\r\n // Cache the indexed XPath result\r\n if (\r\n indexedXpath &&\r\n getCountOfXPath(indexedXpath, targetElemt, docmt) === 1\r\n ) {\r\n xpathData.push({\r\n key: `relative xpath by unique parent ${isIndex ? \"index\" : \"\"}`,\r\n value: indexedXpath\r\n });\r\n }\r\n }\r\n }\r\n }\r\n return null;\r\n};\r\n\r\nconst getUniqueParentXpath = (\r\n domNode: HTMLElement,\r\n docmt: Document,\r\n node: HTMLElement | Element,\r\n isTarget: boolean,\r\n nodeXpath: string,\r\n isIndex: boolean\r\n) => {\r\n try {\r\n if (parentXpathCache.has(domNode)) {\r\n return parentXpathCache.get(domNode);\r\n }\r\n\r\n // Direct XPath construction without loops\r\n const xpathParts = [];\r\n let currentNode = domNode;\r\n\r\n while (currentNode && currentNode.nodeType === 1) {\r\n const hasUniqueAttr = false;\r\n for (const attrName of Array.from(currentNode.attributes)) {\r\n if (checkBlockedAttributes(attrName, currentNode, isTarget)) {\r\n const attrValue = sanitizeAttributeValue(\r\n attrName.name,\r\n attrName.nodeValue\r\n );\r\n const elementName = attrName.name;\r\n\r\n for (const xpathe of getXpathStrings(currentNode, elementName, attrValue)) {\r\n let othersWithAttr;\r\n\r\n // If the XPath does not parse, move to the next unique attribute\r\n try {\r\n othersWithAttr = checkRelativeXpathRelation(\r\n xpathe,\r\n nodeXpath,\r\n node,\r\n docmt,\r\n isIndex,\r\n \"parent\"\r\n );\r\n } catch (ign) {\r\n continue;\r\n }\r\n\r\n // If the attribute isn't actually unique, get it's index too\r\n if (othersWithAttr) {\r\n return othersWithAttr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (currentNode.textContent && !currentNode.textContent) {\r\n if (\r\n !isTarget ||\r\n (isTarget && !isNumberExist(currentNode.textContent))\r\n ) {\r\n let xpathe;\r\n\r\n if (!reWhiteSpace.test(currentNode.textContent)) {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and normalize-space(.)=${escapeCharacters(\r\n getFilteredText(currentNode)\r\n )}]`\r\n : `//${\r\n currentNode.tagName || \"*\"\r\n }[normalize-space(.)=${escapeCharacters(\r\n getFilteredText(currentNode)\r\n )}]`;\r\n } else {\r\n xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and .=${escapeCharacters(getFilteredText(currentNode))}]`\r\n : `//${currentNode.tagName || \"*\"}[.=${escapeCharacters(\r\n getFilteredText(currentNode)\r\n )}]`;\r\n }\r\n\r\n const othersWithAttr = checkRelativeXpathRelation(\r\n xpathe,\r\n nodeXpath,\r\n node,\r\n docmt,\r\n isIndex,\r\n \"parent\"\r\n );\r\n if (othersWithAttr) {\r\n return othersWithAttr;\r\n }\r\n } else {\r\n const combinePattern = [];\r\n const contentRes = [\r\n ...new Set(getFilteredText(currentNode).match(/([^0-9]+)/g))\r\n ];\r\n const reWhiteSpace = new RegExp(/^[\\S]+( [\\S]+)*$/gi);\r\n if (contentRes?.length) {\r\n for (let i = 0; i < contentRes?.length; i++) {\r\n if (contentRes[i] && replaceWhiteSpaces(contentRes[i].trim())) {\r\n if (!reWhiteSpace.test(contentRes[i])) {\r\n combinePattern.push(\r\n `contains(.,${escapeCharacters(\r\n replaceWhiteSpaces(contentRes[i])\r\n ).trim()})`\r\n );\r\n } else {\r\n combinePattern.push(\r\n `contains(.,${escapeCharacters(\r\n contentRes[i].trim()\r\n ).trim()})`\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (combinePattern?.length) {\r\n const xpathe = isSvg(currentNode)\r\n ? `//*[local-name()='${\r\n currentNode.tagName\r\n }' and ${combinePattern.join(\" and \")}]`\r\n : `//${currentNode.tagName || \"*\"}[${combinePattern.join(\r\n \" and \"\r\n )}]`;\r\n const othersWithAttr = checkRelativeXpathRelation(\r\n xpathe,\r\n nodeXpath,\r\n node,\r\n docmt,\r\n isIndex,\r\n \"parent\"\r\n );\r\n if (othersWithAttr) {\r\n return othersWithAttr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Construct the XPath based on the tag name\r\n if (!hasUniqueAttr) {\r\n const xpathe = isSvg(currentNode)\r\n ? `/*[local-name()='${currentNode.tagName}']`\r\n : `/${currentNode.tagName}`;\r\n\r\n xpathParts.unshift(xpathe);\r\n } else {\r\n break;\r\n }\r\n\r\n // Move to the parent node for the next iteration\r\n currentNode = currentNode.parentElement!;\r\n }\r\n\r\n // Final constructed XPath\r\n const finalXPath = xpathParts.join(\"\") + nodeXpath;\r\n let count = getCountOfXPath(finalXPath, domNode, docmt);\r\n if (count === 1) {\r\n parentXpathCache.set(domNode, finalXPath); // Cache final result\r\n return finalXPath;\r\n }\r\n } catch (error) {\r\n console.error(error);\r\n return null;\r\n }\r\n};\r\n\r\nconst getParentRelativeXpath = (\r\n domNode: HTMLElement,\r\n docmt: Document,\r\n node: HTMLElement | Element,\r\n isTarget: boolean\r\n) => {\r\n const cache = new Map(); // Cache to store computed results\r\n\r\n if (cache.has(domNode)) {\r\n return cache.get(domNode); // Return cached result if available\r\n }\r\n\r\n const xpathParts = []; // Initialize an array to hold parts of the XPath\r\n let currentNode = domNode; // Start with the provided DOM node\r\n\r\n try {\r\n while (currentNode && currentNode.nodeType === 1) {\r\n // BASE CASE #1: If this isn't an element, we're above the root, return empty string\r\n if (!currentNode.tagName) {\r\n return \"\";\r\n }\r\n\r\n // BASE CASE #2: Check for unique attributes\r\n let uniqueAttrFound = false;\r\n for (const attr of Array.from(currentNode.attributes)) {\r\n if (checkBlockedAttributes(attr, currentNode, isTarget)) {\r\n const attrValue = sanitizeAttributeValue(attr.name, attr.nodeValue);\r\n const elementName = attr.name;\r\n\r\n for (const xpathe of getXpathStrings(currentNode, elementName, attrValue)) {\r\n let othersWithAttr;\r\n\r\n // If the XPath does not parse, move to the next unique attribute\r\n try {\r\n othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n } catch (ign) {\r\n continue;\r\n }\r\n\r\n // If the attribute is unique, return its XPath\r\n if (othersWithAttr === 1) {\r\n xpathParts.unshift(xpathe);\r\n uniqueAttrFound = true; // Mark that we found at least one unique attribute\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (uniqueAttrFound) break;\r\n }\r\n\r\n // If no unique attributes, check for text content\r\n if (!uniqueAttrFound && currentNode.textContent && !node.textContent) {\r\n const textXPath = getFilteredTextXPath(currentNode, docmt);\r\n if (textXPath) {\r\n const othersWithAttr = getCountOfXPath(textXPath, currentNode, docmt);\r\n if (othersWithAttr === 1) {\r\n uniqueAttrFound = true; // Mark that we found at least one unique attribute\r\n xpathParts.unshift(textXPath);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!uniqueAttrFound) {\r\n // Construct the XPath based on the tag name\r\n const xpathe = isSvg(currentNode)\r\n ? `/*[local-name()='${currentNode.tagName}']`\r\n : `/${currentNode.tagName}`;\r\n\r\n // Prepend the current XPath part to the array\r\n xpathParts.unshift(xpathe);\r\n } else {\r\n break;\r\n }\r\n // Move to the parent node for the next iteration\r\n currentNode = currentNode.parentElement!;\r\n }\r\n\r\n // Combine all parts into the final XPath\r\n const finalXpath = xpathParts.join(\"\");\r\n cache.set(domNode, finalXpath); // Store result in cache\r\n return finalXpath;\r\n } catch (error) {\r\n console.log(error);\r\n return null;\r\n }\r\n};\r\n\r\nconst getChildRelativeXpath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n node: HTMLElement | Element\r\n) => {\r\n const xpathParts = []; // Initialize an array to hold parts of the XPath.\r\n let currentNode: HTMLElement | Element | null;\r\n\r\n const st = [];\r\n if (\r\n domNode.firstElementChild != null &&\r\n domNode.firstElementChild.classList.contains(\"flntooltip\")\r\n ) {\r\n st.unshift(domNode.firstElementChild);\r\n } else if (domNode.nextElementSibling != null)\r\n st.unshift(domNode.nextElementSibling);\r\n\r\n for (\r\n let m = domNode.parentElement;\r\n m != null && m.nodeType === 1;\r\n m = m.parentElement\r\n ) {\r\n if (m.nextElementSibling) st.unshift(m.nextElementSibling);\r\n }\r\n\r\n try {\r\n do {\r\n let uniqueAttrFound = false;\r\n for (currentNode = st.pop()!; currentNode !== null; ) {\r\n for (const attr of Array.from(currentNode.attributes)) {\r\n if (checkBlockedAttributes(attr, currentNode, true)) {\r\n const attrValue = sanitizeAttributeValue(attr.name, attr.nodeValue);\r\n const elementName = attr.name;\r\n\r\n for (const xpathe of getXpathStrings(currentNode, elementName, attrValue)) {\r\n let othersWithAttr;\r\n\r\n // If the XPath does not parse, move to the next unique attribute\r\n try {\r\n othersWithAttr = getCountOfXPath(xpathe, currentNode, docmt);\r\n } catch (ign) {\r\n continue;\r\n }\r\n\r\n // If the attribute is unique, return its XPath\r\n if (othersWithAttr === 1) {\r\n uniqueAttrFound = true; // Mark that we found at least one unique attribute\r\n xpathParts.push(xpathe);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (uniqueAttrFound) break;\r\n }\r\n\r\n // If no unique attributes, check for text content\r\n if (!uniqueAttrFound && currentNode.textContent && !node.textContent) {\r\n const textXPath = getFilteredTextXPath(currentNode, docmt);\r\n if (textXPath) {\r\n const othersWithAttr = getCountOfXPath(\r\n textXPath,\r\n currentNode,\r\n docmt\r\n );\r\n if (othersWithAttr === 1) {\r\n uniqueAttrFound = true; // Mark that we found at least one unique attribute\r\n xpathParts.push(textXPath);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!uniqueAttrFound) {\r\n // Construct the XPath based on the tag name\r\n const xpathe = isSvg(currentNode)\r\n ? `/*[local-name()='${currentNode.tagName}']`\r\n : `/${currentNode.tagName}`;\r\n\r\n // Prepend the current XPath part to the array\r\n xpathParts.push(xpathe);\r\n\r\n if (currentNode.firstElementChild != null) {\r\n st.push(currentNode.nextElementSibling);\r\n currentNode = currentNode.firstElementChild;\r\n } else {\r\n currentNode = currentNode.nextElementSibling;\r\n }\r\n } else {\r\n break;\r\n }\r\n }\r\n } while (st.length > 0);\r\n\r\n // Combine all parts into the final XPath\r\n const finalXpath = xpathParts.join(\"\");\r\n cache.set(domNode, finalXpath); // Store result in cache\r\n return finalXpath;\r\n } catch (error) {\r\n console.log(error);\r\n return null;\r\n }\r\n};\r\n\r\nconst getSiblingRelativeXPath = (\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean,\r\n nodeXpath: string\r\n) => {\r\n try {\r\n const markedSpan = document.querySelector(\".flntooltip\");\r\n\r\n for (\r\n let m = domNode.nextElementSibling;\r\n m !== null && m !== markedSpan;\r\n m = m.nextElementSibling\r\n ) {\r\n processSibling(\r\n m,\r\n domNode,\r\n docmt,\r\n nodeXpath,\r\n \"preceding-sibling\",\r\n isTarget\r\n );\r\n }\r\n\r\n for (\r\n let n = domNode.previousElementSibling;\r\n n !== null && n !== markedSpan;\r\n n = n.previousElementSibling\r\n ) {\r\n processSibling(\r\n n,\r\n domNode,\r\n docmt,\r\n nodeXpath,\r\n \"following-sibling\",\r\n isTarget\r\n );\r\n }\r\n } catch (error) {\r\n console.error(\"sibling error\", error);\r\n return null;\r\n }\r\n};\r\n\r\nconst processSibling = (\r\n sibling: Element,\r\n domNode: HTMLElement | Element,\r\n docmt: Document,\r\n nodeXpath: string,\r\n axis: string,\r\n isTarget: boolean\r\n) => {\r\n try {\r\n if (sibling.hasAttributes()) {\r\n for (const attr of Array.from(sibling.attributes)) {\r\n const xpaths = intermediateXpathSteps(\r\n sibling,\r\n {\r\n name: attr.name,\r\n value: attr.value\r\n },\r\n isTarget\r\n );\r\n\r\n for (let xpathe of xpaths) {\r\n xpathe += `/${axis}::${nodeXpath}`;\r\n\r\n const count = getCountOfXPath(xpathe, sibling, docmt);\r\n\r\n if (count === 1) {\r\n xpathData.push({\r\n key: `xpath by ${axis}`,\r\n value: xpathe\r\n });\r\n return;\r\n } else if (count > 1) {\r\n if (xpathDataWithIndex.length) {\r\n if (count < xpathDataWithIndex[0].count) {\r\n xpathDataWithIndex.pop();\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by ${axis}`,\r\n value: xpathe,\r\n count\r\n });\r\n }\r\n } else {\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by ${axis}`,\r\n value: xpathe,\r\n count\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (!isTarget) {\r\n let xpathe;\r\n xpathe = intermediateXpathStep(\r\n sibling,\r\n {\r\n name: \"text\",\r\n value: sibling.textContent\r\n },\r\n isTarget\r\n );\r\n\r\n if (xpathe) {\r\n const count = getCountOfXPath(xpathe, sibling, docmt);\r\n\r\n if (count === 1) {\r\n xpathData.push({\r\n key: `xpath by ${axis}`,\r\n value: xpathe\r\n });\r\n return;\r\n } else if (count > 1) {\r\n if (xpathDataWithIndex.length) {\r\n if (count < xpathDataWithIndex[0].count) {\r\n xpathDataWithIndex.pop();\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by ${axis}`,\r\n value: xpathe,\r\n count\r\n });\r\n }\r\n } else {\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by ${axis}`,\r\n value: xpathe,\r\n count\r\n });\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.log(`${axis} xpath-error`, error);\r\n }\r\n};\r\n\r\nfunction getXPathUsingAttributeAndText(\r\n attributes: Attr[],\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isTarget: boolean\r\n) {\r\n const { tagName } = targetElemt;\r\n const textContent = targetElemt.textContent.trim();\r\n if (!textContent) {\r\n return;\r\n }\r\n const normalizedTextContent = replaceWhiteSpaces(textContent);\r\n const stableTargetText = getStableTargetText(normalizedTextContent);\r\n if (hasNumericAttributeValue(normalizedTextContent) && !stableTargetText) {\r\n return;\r\n }\r\n\r\n const textForPredicate = hasNumericAttributeValue(normalizedTextContent)\r\n ? stableTargetText\r\n : normalizedTextContent;\r\n const containerTextCondition = getContainerTextCondition(\r\n targetElemt,\r\n textForPredicate\r\n );\r\n for (const attrName of attributes) {\r\n if (checkBlockedAttributes(attrName, targetElemt, isTarget)) {\r\n let attrValue = sanitizeAttributeValue(attrName.name, attrName.nodeValue);\r\n const elementName = attrName.name;\r\n const textCondition = containerTextCondition\r\n ? containerTextCondition\r\n : hasNumericAttributeValue(normalizedTextContent)\r\n ? `contains(normalize-space(.),${escapeCharacters(textForPredicate)})`\r\n : /\\s/.test(textContent)\r\n ? `normalize-space(.)=${escapeCharacters(textForPredicate)}`\r\n : `text()=${escapeCharacters(textForPredicate)}`;\r\n const xpath = `//${tagName}[@${elementName}='${attrValue}' and ${textCondition}]`;\r\n if (xpath) {\r\n const count = getCountOfXPath(xpath, targetElemt, docmt);\r\n if (count == 1) {\r\n return xpath;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\nconst addRelativeXpaths = (\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean,\r\n attribute: Attr[]\r\n) => {\r\n try {\r\n let nodeXpath: string[] = [];\r\n let relativeXpath, relativeChildXpath;\r\n xpathData = [];\r\n\r\n console.log(attribute);\r\n if (attribute) {\r\n for (const attrName of attribute) {\r\n const expressions = intermediateXpathSteps(\r\n targetElemt,\r\n {\r\n name: attrName.name,\r\n value: attrName.value\r\n },\r\n isTarget\r\n );\r\n\r\n console.log(expressions[0] || \"\");\r\n for (const expression of expressions) {\r\n if (expression) {\r\n nodeXpath.push(expression);\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (targetElemt.textContent) {\r\n let expression = intermediateXpathStep(\r\n targetElemt,\r\n {\r\n name: \"text\",\r\n value: targetElemt.textContent\r\n },\r\n isTarget\r\n );\r\n\r\n console.log(expression);\r\n if (expression) {\r\n nodeXpath.push(expression);\r\n }\r\n }\r\n\r\n nodeXpath.push(targetElemt.tagName);\r\n\r\n if (nodeXpath?.length) {\r\n for (let i = 0; i < nodeXpath.length; i++) {\r\n if (!xpathData.length) {\r\n getSiblingRelativeXPath(targetElemt, docmt, isTarget, nodeXpath[i]);\r\n\r\n if (!xpathData.length) {\r\n if (!relativeXpath) {\r\n relativeXpath = getParentRelativeXpath(\r\n targetElemt.parentElement!,\r\n docmt,\r\n targetElemt,\r\n isTarget\r\n );\r\n }\r\n\r\n console.log(relativeXpath);\r\n\r\n if (\r\n relativeXpath &&\r\n (relativeXpath.includes(\"@\") ||\r\n relativeXpath.includes(\"text()\") ||\r\n relativeXpath.includes(\".=\")) &&\r\n relativeXpath.match(/\\//g)?.length - 2 < 5\r\n ) {\r\n const fullRelativeXpath = relativeXpath + `/${nodeXpath[i]}`;\r\n const count = getCountOfXPath(\r\n fullRelativeXpath,\r\n targetElemt,\r\n docmt\r\n );\r\n\r\n if (count === 1) {\r\n xpathData.push({\r\n key: \"relative xpath by relative parent\",\r\n value: fullRelativeXpath\r\n });\r\n } else if (count > 1 && isIndex) {\r\n const relativeXpathIndex = findXpathWithIndex(\r\n fullRelativeXpath,\r\n targetElemt,\r\n docmt,\r\n count\r\n );\r\n if (\r\n relativeXpathIndex &&\r\n getCountOfXPath(relativeXpathIndex, targetElemt, docmt) === 1\r\n ) {\r\n xpathData.push({\r\n key: `relative xpath by relative parent ${\r\n isIndex ? \"index\" : \"\"\r\n }`,\r\n value: relativeXpathIndex\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (!xpathData.length) {\r\n if (!relativeChildXpath) {\r\n relativeChildXpath = getChildRelativeXpath(\r\n targetElemt,\r\n docmt,\r\n targetElemt\r\n );\r\n }\r\n\r\n if (\r\n relativeChildXpath &&\r\n (relativeChildXpath.includes(\"@\") ||\r\n relativeChildXpath.includes(\"text()\") ||\r\n relativeChildXpath.includes(\".=\"))\r\n ) {\r\n // Preserve the step separator between the target descriptor and child tail.\r\n const childRelativeXpath = relativeChildXpath.replace(/^\\/+/, \"\");\r\n const fullRelativeXpath = `/${nodeXpath[i]}/${childRelativeXpath}`;\r\n const count = getCountOfXPath(\r\n fullRelativeXpath,\r\n targetElemt,\r\n docmt\r\n );\r\n\r\n if (count === 1) {\r\n xpathData.push({\r\n key: \"relative xpath by relative child\",\r\n value: fullRelativeXpath\r\n });\r\n } else if (count > 1 && isIndex) {\r\n const relativeXpathIndex = findXpathWithIndex(\r\n fullRelativeXpath,\r\n targetElemt,\r\n docmt,\r\n count\r\n );\r\n if (\r\n relativeXpathIndex &&\r\n getCountOfXPath(relativeXpathIndex, targetElemt, docmt) === 1\r\n ) {\r\n xpathData.push({\r\n key: `relative xpath by relative parent ${\r\n isIndex ? \"index\" : \"\"\r\n }`,\r\n value: relativeXpathIndex\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (\r\n xpathData?.length === 1 &&\r\n xpathData?.[0]?.value?.match(/\\[([0-9]+)\\]/gm)?.length! > 3 &&\r\n !referenceElementMode\r\n ) {\r\n if (targetElemt.textContent) {\r\n const txtXpath = getTextXPath(targetElemt, docmt, isIndex, false);\r\n if (txtXpath) {\r\n xpathData.unshift({\r\n key: `xpath by text${isIndex ? \"index\" : \"\"}`,\r\n value: txtXpath\r\n });\r\n }\r\n }\r\n }\r\n\r\n if (!xpathData.length) {\r\n let tempRelativeXpath = getUniqueParentXpath(\r\n targetElemt.parentElement!,\r\n docmt,\r\n targetElemt,\r\n isTarget,\r\n nodeXpath[i],\r\n isIndex\r\n );\r\n\r\n if (tempRelativeXpath) {\r\n xpathData.push({\r\n key: \"xpath by unique parent\",\r\n value: tempRelativeXpath\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return xpathData;\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n};\r\n\r\nexport const attributesBasedXPath = (\r\n attr: Attr,\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n let attrName;\r\n\r\n attrName = attr.name;\r\n // Strict numeric-attribute validation for direct callers.\r\n if (!checkBlockedAttributes(attr, targetElemt, isTarget)) {\r\n return;\r\n }\r\n\r\n let xpath = getPropertyXPath(\r\n targetElemt,\r\n docmt,\r\n `@${attrName}`,\r\n attr.value,\r\n isIndex,\r\n isTarget\r\n );\r\n\r\n return xpath;\r\n};\r\n\r\nexport const getUniqueClassName = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n let value = element.className;\r\n if (typeof value !== \"string\") {\r\n value = \"\";\r\n }\r\n value = value?.replace(\"flndisabled\", \"disabled\");\r\n value = sanitizeAttributeValue(\"class\", value);\r\n value = value?.trim();\r\n\r\n if (value && checkBlockedAttributes({ name: \"class\", value }, element, isTarget)) {\r\n return getPropertyXPath(element, docmt, `@class`, value, isIndex, isTarget);\r\n }\r\n};\r\n\r\nexport const getTextXPath = (\r\n element: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n if ((element.textContent ?? \"\").trim() != \"\") {\r\n const text = getTextContent(element);\r\n\r\n if (text) {\r\n return getPropertyXPath(element, docmt, \".\", text, isIndex, isTarget);\r\n }\r\n }\r\n};\r\n\r\nconst addAllXPathAttributes = (\r\n attributes: Attr[],\r\n targetElemt: HTMLElement | Element,\r\n docmt: Document,\r\n isIndex: boolean,\r\n isTarget: boolean\r\n) => {\r\n const attributesArray = attributes;\r\n try {\r\n attributesArray.map((attr) => {\r\n if (!(attr.name === \"className\" || attr.name === \"class\")) {\r\n // Strict numeric-attribute validation is enforced inside\r\n // checkBlockedAttributes before candidate XPath creation.\r\n if (checkBlockedAttributes(attr, targetElemt, isTarget)) {\r\n const xpth = attributesBasedXPath(\r\n attr,\r\n targetElemt,\r\n docmt,\r\n isIndex,\r\n isTarget\r\n );\r\n if (xpth) {\r\n xpathData.push({\r\n key: `xpath by ${attr.name}${isIndex ? \" index\" : \"\"}`,\r\n value: xpth\r\n });\r\n }\r\n }\r\n }\r\n });\r\n\r\n const txtXpath = getTextXPath(targetElemt, docmt, isIndex, isTarget);\r\n if (txtXpath) {\r\n xpathData.push({\r\n key: `xpath by text${isIndex ? \" index\" : \"\"}`,\r\n value: txtXpath\r\n });\r\n }\r\n\r\n if (\r\n attributesArray.find((element) => element.name === \"className\") &&\r\n checkBlockedAttributes(\r\n attributesArray?.find((element) => element.name === \"className\")!,\r\n targetElemt,\r\n isTarget\r\n )\r\n ) {\r\n let xpath = getUniqueClassName(targetElemt, docmt, isIndex, isTarget);\r\n if (xpath) {\r\n xpathData.push({\r\n key: \"xpath by class\",\r\n value: xpath\r\n });\r\n }\r\n }\r\n\r\n if (!xpathData.length && attributesArray.length > 1) {\r\n const combinationXpath = getAttributeCombinationXpath(\r\n targetElemt,\r\n docmt,\r\n attributesArray,\r\n isTarget\r\n );\r\n if (combinationXpath)\r\n xpathData.push({\r\n key: \"xpath by combination\",\r\n value: combinationXpath\r\n });\r\n }\r\n\r\n if (!xpathData.length) {\r\n const textAttribute = getXPathUsingAttributeAndText(\r\n attributes,\r\n targetElemt,\r\n docmt,\r\n isTarget\r\n );\r\n if (textAttribute)\r\n xpathData.push({\r\n key: \"xpath by textAttribute\",\r\n value: textAttribute\r\n });\r\n }\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n};\r\n\r\nexport const parseDOM = (\r\n element: HTMLElement | Element,\r\n doc: Document,\r\n isIndex: boolean,\r\n isTarget: boolean,\r\n includedAttributes: Attr[] = [],\r\n strategies: string[] = []\r\n) => {\r\n xpathData = [];\r\n console.log(element);\r\n const targetElemt = element;\r\n const rootNode = targetElemt?.getRootNode?.();\r\n const isShadowScoped = rootNode?.nodeType === Node.DOCUMENT_FRAGMENT_NODE;\r\n const docmt = (\r\n isShadowScoped ? rootNode : targetElemt?.ownerDocument || doc\r\n ) as Document;\r\n const tag = targetElemt.tagName;\r\n const { attributes } = targetElemt;\r\n const attributesToUse =\r\n includedAttributes.length > 0 ? includedAttributes : Array.from(attributes);\r\n addAllXPathAttributes(attributesToUse, targetElemt, docmt, isIndex, isTarget);\r\n\r\n if (strategies.length) {\r\n // Explicit index strategy should preserve positional candidates even when\r\n // isIndex is false.\r\n const allowPositionalIndex = isIndex || includesIndexStrategy(strategies);\r\n const strategyXpaths = strategies.flatMap((strategy) =>\r\n buildStrategyXpaths(targetElemt, docmt, isTarget, strategy, xpathData)\r\n );\r\n\r\n xpathData = getUniqueXpathEntries(\r\n strategyXpaths.filter(\r\n (xpath) => getCountOfXPath(xpath.value, targetElemt, docmt) === 1\r\n )\r\n );\r\n\r\n return removePositionalIndexXpaths(xpathData, allowPositionalIndex);\r\n }\r\n\r\n if (!referenceElementMode) {\r\n if (xpathData.length) {\r\n const len = xpathData.length;\r\n for (let i = 0; i < len; i++) {\r\n let xpth = xpathData[i].value;\r\n xpth = \"//*\" + xpth.substring(xpth.indexOf(\"//\") + 2 + tag.length);\r\n const count = getCountOfXPath(xpth, element, docmt);\r\n if (count === 1) {\r\n xpathData.push({\r\n key: `${xpathData[i].key} regex`,\r\n value: xpth\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (!xpathData.length && !isShadowScoped) {\r\n xpathData = buildAxesStrategyXpaths(targetElemt, docmt, isTarget, isIndex);\r\n }\r\n\r\n return removePositionalIndexXpaths(xpathData, isIndex);\r\n};\r\n\r\nconst xpath = {\r\n parseDOM,\r\n getTextXPath,\r\n getUniqueClassName,\r\n attributesBasedXPath,\r\n addAllXPathAttributes,\r\n addRelativeXpaths,\r\n getXPathUsingAttributeAndText,\r\n getSiblingRelativeXPath,\r\n getChildRelativeXpath,\r\n getParentRelativeXpath,\r\n getUniqueParentXpath,\r\n checkRelativeXpathRelation,\r\n buildAxesStrategyXpaths\r\n};\r\n\r\nexport default xpath;\r\n","import { parseDOM } from \"./xpath.ts\";\r\nimport {\r\n findXpathWithIndex,\r\n getShadowRoot,\r\n getTextContent,\r\n escapeCharacters,\r\n getCountOfXPath,\r\n checkBlockedAttributes,\r\n getAbsoluteXPath,\r\n isSvg,\r\n getCombinationXpath,\r\n getTextXpathFunction,\r\n replaceTempAttributes,\r\n replaceActualAttributes,\r\n getReferenceElementsXpath,\r\n getRelativeXPath,\r\n findMatchingParenthesis,\r\n removeParenthesis,\r\n sanitizeAttributeValue,\r\n replaceWhiteSpaces,\r\n getClassTokenConditions,\r\n getContainerTextCondition\r\n} from \"./xpathHelpers.ts\";\r\n\r\nlet xpathDataWithIndex: any[] = [];\r\nlet xpathData: { key: string; value: string }[] = [];\r\nconst reWhiteSpace = /^[\\S]+( [\\S]+)*$/gi;\r\n\r\nexport const findRelativeXpath = (\r\n element1: Element,\r\n element2: Element,\r\n docmt: Document,\r\n xpaths1: any[],\r\n xpaths2: any[],\r\n isIndex: boolean,\r\n multiElementReferenceMode: boolean = false,\r\n allowedRelations: string[] | null = null\r\n) => {\r\n let finalXpaths: any[] = [];\r\n\r\n const relations = allowedRelations || [];\r\n\r\n const tryRelation = (relation: string, useIndex: boolean) => {\r\n let rel_xpath: any[] = [];\r\n\r\n if (relation === \"descendant\" || relation === \"descendant-or-self\") {\r\n rel_xpath =\r\n getDescendantXpath(\r\n [element1, element2],\r\n docmt,\r\n xpaths1,\r\n xpaths2,\r\n relation as \"descendant\" | \"descendant-or-self\",\r\n useIndex,\r\n multiElementReferenceMode\r\n ) || [];\r\n } else {\r\n rel_xpath =\r\n getXpathRelationExpression(\r\n element1,\r\n element2,\r\n relation,\r\n xpaths1,\r\n xpaths2,\r\n useIndex,\r\n multiElementReferenceMode\r\n ) || [];\r\n }\r\n\r\n if (rel_xpath.length) {\r\n finalXpaths = finalXpaths.concat(rel_xpath);\r\n }\r\n };\r\n\r\n for (const relation of relations) {\r\n tryRelation(relation, isIndex);\r\n }\r\n\r\n return finalXpaths;\r\n};\r\n\r\nconst descendantExpression = (\r\n refExpectElement: Array<HTMLElement | Element>,\r\n xpath2: string,\r\n relation: string,\r\n docmt: Node,\r\n isIndex: any,\r\n expCommonParentXpathElements: string | any[],\r\n step4: string,\r\n refCommonParentXpathElementLength: number = 0,\r\n multiElementReferenceMode: boolean = false\r\n) => {\r\n let finalExpectedElementXpath: string | undefined = \"\";\r\n\r\n if (\r\n xpath2.split(/\\/(?=(?:[^']*\\'[^\\']*\\')*[^\\']*$)/g)?.length >=\r\n expCommonParentXpathElements.length\r\n ) {\r\n const xpaths2Els: string[] = [];\r\n const xpath2Elements = xpath2.split(/\\/(?=(?:[^']*\\'[^\\']*\\')*[^\\']*$)/g);\r\n for (let x = 1; x <= expCommonParentXpathElements.length; x++) {\r\n xpaths2Els.unshift(\r\n x === expCommonParentXpathElements.length\r\n ? expCommonParentXpathElements[\r\n expCommonParentXpathElements.length - x\r\n ]\r\n : xpath2Elements[xpath2Elements.length - x]\r\n );\r\n }\r\n const traverseXpath = getTraverseXpathExpression(\r\n `${\r\n step4 +\r\n (refCommonParentXpathElementLength\r\n ? \"]\".repeat(refCommonParentXpathElementLength)\r\n : \"\")\r\n }`,\r\n xpaths2Els,\r\n refExpectElement[refExpectElement.length - 1],\r\n refExpectElement,\r\n docmt,\r\n relation,\r\n isIndex,\r\n multiElementReferenceMode\r\n );\r\n if (traverseXpath) {\r\n return traverseXpath;\r\n }\r\n } else {\r\n finalExpectedElementXpath = `//${\r\n step4 +\r\n (refCommonParentXpathElementLength\r\n ? \"]\".repeat(refCommonParentXpathElementLength)\r\n : \"\")\r\n }/${relation}::${replaceActualAttributes(\r\n xpath2,\r\n refExpectElement[refExpectElement.length - 1]\r\n )}`;\r\n let rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt\r\n );\r\n if (rel_count === 1) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n if (rel_count > 1) {\r\n if (isIndex) {\r\n finalExpectedElementXpath = findXpathWithIndex(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt,\r\n rel_count\r\n );\r\n if (finalExpectedElementXpath) {\r\n rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt\r\n );\r\n if (rel_count === 1) {\r\n return [\r\n {\r\n key: `dynamic ${relation} ${isIndex ? \" index\" : \"\"}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n }\r\n }\r\n }\r\n }\r\n};\r\n\r\nconst prioritizeTextBasedXpaths = (\r\n xpaths: { key: string; value: string }[]\r\n) => {\r\n // Reference mode should prefer readable text-only target steps before mixing\r\n // them with attributes or structural tails.\r\n const getPriority = (xpath: { value: string }) => {\r\n const value = xpath.value || \"\";\r\n const hasTextPredicate =\r\n /(?:contains\\s*\\(\\s*normalize-space\\s*\\(\\s*\\.\\s*\\)|normalize-space\\s*\\(\\s*\\.\\s*\\)|contains\\s*\\(\\s*text\\s*\\(\\s*\\)|text\\s*\\(\\s*\\)|\\.\\s*=)/.test(\r\n value\r\n );\r\n const hasAttributePredicate = /@/.test(value);\r\n\r\n if (hasTextPredicate && !hasAttributePredicate) {\r\n return 0;\r\n }\r\n\r\n if (hasTextPredicate) {\r\n return 1;\r\n }\r\n\r\n return 2;\r\n };\r\n\r\n return [...xpaths].sort((left, right) => getPriority(left) - getPriority(right));\r\n};\r\n\r\nconst getDescendantXpath = (\r\n refExpectElement: Array<HTMLElement | Element>,\r\n docmt: Document,\r\n xpaths1: { key: string; value: string }[],\r\n xpaths2: { key: string; value: string }[],\r\n relation: \"descendant\" | \"descendant-or-self\",\r\n isIndex: boolean = false,\r\n multiElementReferenceMode: boolean = false\r\n) => {\r\n const refElement: HTMLElement | Element =\r\n refExpectElement[refExpectElement.length - 2];\r\n const expElement: HTMLElement | Element =\r\n refExpectElement[refExpectElement.length - 1];\r\n const expElementDocmnt =\r\n getShadowRoot(expElement) ?? expElement.ownerDocument;\r\n\r\n const refAbsoluteXpath =\r\n xpaths1.find((x) => x?.key?.includes(\"absolute\"))?.value ||\r\n getAbsoluteXPath(refElement, refElement.ownerDocument);\r\n\r\n const refFullXpathElements: any[] = [];\r\n const refFullXpathElementsWithoutNumber: any[] = [];\r\n refAbsoluteXpath.split(\"/\").map((x) => refFullXpathElements.push(x));\r\n refFullXpathElements.map((x) =>\r\n refFullXpathElementsWithoutNumber.push(x.replace(/\\[([0-9]+)\\]/gm, \"\"))\r\n );\r\n\r\n const expAbsoluteXpath =\r\n xpaths2.find((x) => x?.key?.includes(\"absolute\"))?.value ||\r\n getAbsoluteXPath(expElement, expElement.ownerDocument);\r\n\r\n const expFullXpathElements: any[] = [];\r\n const expFullXpathElementsWithoutNumber: any[] = [];\r\n expAbsoluteXpath.split(\"/\").map((x) => expFullXpathElements.push(x));\r\n expFullXpathElements.map((x) =>\r\n expFullXpathElementsWithoutNumber.push(x.replace(/\\[([0-9]+)\\]/gm, \"\"))\r\n );\r\n\r\n for (\r\n var parentElementNumber = 0;\r\n parentElementNumber < refFullXpathElements.length;\r\n parentElementNumber++\r\n ) {\r\n if (\r\n refFullXpathElements[parentElementNumber] !=\r\n expFullXpathElements[parentElementNumber]\r\n ) {\r\n break;\r\n }\r\n }\r\n\r\n const refCommonParentXpathElements = [];\r\n for (let i = parentElementNumber - 1; i < refFullXpathElements.length; i++) {\r\n if (refFullXpathElements[i]) {\r\n refCommonParentXpathElements.push(refFullXpathElementsWithoutNumber[i]);\r\n }\r\n }\r\n\r\n const expCommonParentXpathElements: string[] = [];\r\n for (\r\n let j =\r\n relation === \"descendant\" ? parentElementNumber : parentElementNumber - 1;\r\n j < expFullXpathElements.length;\r\n j++\r\n ) {\r\n if (expFullXpathElements[j]) {\r\n if (expCommonParentXpathElements.length)\r\n expCommonParentXpathElements.push(expFullXpathElementsWithoutNumber[j]);\r\n else\r\n expCommonParentXpathElements.push(\r\n expFullXpathElementsWithoutNumber[j].replace(/\\[([0-9]+)\\]/gm, \"\")\r\n );\r\n }\r\n }\r\n\r\n // Descendant generation consumes xpathData in order, so keep text candidates\r\n // ahead of heavier combination candidates.\r\n xpathData = prioritizeTextBasedXpaths(xpaths2);\r\n\r\n let nodeXpath2;\r\n if (refExpectElement[refExpectElement.length - 2].textContent) {\r\n if (\r\n !reWhiteSpace.test(\r\n refExpectElement[refExpectElement.length - 2].textContent\r\n )\r\n ) {\r\n nodeXpath2 = isSvg(refExpectElement[refExpectElement.length - 2])\r\n ? `*[local-name()='${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }' and ${getTextXpathFunction(\r\n refExpectElement[refExpectElement.length - 2]\r\n )})]`\r\n : `${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }[${getTextXpathFunction(\r\n refExpectElement[refExpectElement.length - 2]\r\n )}]`;\r\n } else {\r\n const referenceElement = refExpectElement[refExpectElement.length - 2];\r\n const referenceText = getTextContent(\r\n referenceElement\r\n );\r\n const containerTextCondition = getContainerTextCondition(\r\n referenceElement,\r\n referenceText\r\n );\r\n const referenceTextCondition = containerTextCondition\r\n ? containerTextCondition\r\n : /\\s/.test(referenceText.trim())\r\n ? `normalize-space(.)=${escapeCharacters(\r\n replaceWhiteSpaces(referenceText)\r\n )}`\r\n : `.=${escapeCharacters(referenceText)}`;\r\n nodeXpath2 = isSvg(refExpectElement[refExpectElement.length - 2])\r\n ? `*[local-name()='${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }' and ${referenceTextCondition}]`\r\n : `${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }[${referenceTextCondition}]`;\r\n }\r\n\r\n refCommonParentXpathElements[refCommonParentXpathElements.length - 1] =\r\n nodeXpath2;\r\n\r\n const refCommonParentXpath = refCommonParentXpathElements.join(\"[\");\r\n const refCommonParentXpathElementLength =\r\n refCommonParentXpathElements.length - 1;\r\n\r\n const step4 = refCommonParentXpath;\r\n\r\n for (let i = 0; i < xpathData.length; i++) {\r\n let xpath2;\r\n\r\n if (xpathData[i].value.startsWith(\"//\")) {\r\n xpath2 = xpathData[i].value.substring(\r\n xpathData[i].value.indexOf(\"//\") + 2\r\n );\r\n } else {\r\n xpath2 = xpathData[i].value; // No need to modify the value\r\n }\r\n if (xpath2) {\r\n const result = descendantExpression(\r\n refExpectElement,\r\n xpath2,\r\n relation,\r\n expElementDocmnt || docmt,\r\n isIndex,\r\n expCommonParentXpathElements,\r\n step4,\r\n refCommonParentXpathElementLength,\r\n multiElementReferenceMode\r\n );\r\n if (result?.length) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (refExpectElement[refExpectElement.length - 2].attributes) {\r\n for (const attrName of Array.from(\r\n refExpectElement[refExpectElement.length - 2].attributes\r\n )) {\r\n if (\r\n checkBlockedAttributes(\r\n attrName,\r\n refExpectElement[refExpectElement.length - 2],\r\n false\r\n )\r\n ) {\r\n let attrValue = attrName.nodeValue;\r\n if (attrValue) {\r\n attrValue = sanitizeAttributeValue(attrName.name, attrValue);\r\n const elementName = attrName.name;\r\n\r\n nodeXpath2 = isSvg(refExpectElement[refExpectElement.length - 2])\r\n ? `*[local-name()='${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }' and @${elementName}=${escapeCharacters(attrValue)}]`\r\n : `${\r\n refExpectElement[refExpectElement.length - 2].tagName\r\n }[@${elementName}=${escapeCharacters(attrValue)}]`;\r\n\r\n refCommonParentXpathElements[\r\n refCommonParentXpathElements.length - 1\r\n ] = nodeXpath2;\r\n\r\n const refCommonParentXpath = refCommonParentXpathElements.join(\"[\");\r\n const refCommonParentXpathElementLength =\r\n refCommonParentXpathElements.length - 1;\r\n\r\n const step4 = refCommonParentXpath;\r\n\r\n for (let i = 0; i < xpathData.length; i++) {\r\n let xpath2;\r\n if (xpathData[i].value.startsWith(\"//\")) {\r\n xpath2 = xpathData[i].value.substring(\r\n xpathData[i].value.indexOf(\"//\") + 2\r\n );\r\n } else {\r\n xpath2 = xpathData[i].value; // No need to modify the value\r\n }\r\n\r\n const result = descendantExpression(\r\n refExpectElement,\r\n xpath2,\r\n relation,\r\n expElementDocmnt || docmt,\r\n isIndex,\r\n expCommonParentXpathElements,\r\n step4,\r\n refCommonParentXpathElementLength,\r\n multiElementReferenceMode\r\n );\r\n if (result?.length) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n for (const attrName of Array.from(\r\n refExpectElement[refExpectElement.length - 2].attributes\r\n )) {\r\n if (\r\n checkBlockedAttributes(\r\n attrName,\r\n refExpectElement[refExpectElement.length - 2],\r\n false\r\n )\r\n ) {\r\n let attrValue = attrName.nodeValue;\r\n if (attrValue) {\r\n attrValue = sanitizeAttributeValue(attrName.name, attrValue);\r\n const combinationXpath = getCombinationXpath(\r\n attrName,\r\n refExpectElement[refExpectElement.length - 2]\r\n );\r\n if (combinationXpath) {\r\n if (combinationXpath.startsWith(\"//\")) {\r\n nodeXpath2 = combinationXpath.substring(\r\n combinationXpath.indexOf(\"//\") + 2\r\n );\r\n } else {\r\n nodeXpath2 = combinationXpath; // No need to modify the value\r\n }\r\n\r\n refCommonParentXpathElements[\r\n refCommonParentXpathElements.length - 1\r\n ] = nodeXpath2;\r\n\r\n const refCommonParentXpath = refCommonParentXpathElements.join(\"[\");\r\n const refCommonParentXpathElementLength =\r\n refCommonParentXpathElements.length - 1;\r\n\r\n const step4 = refCommonParentXpath;\r\n\r\n for (let i = 0; i < xpathData.length; i++) {\r\n let xpath2;\r\n if (xpathData[i].value.startsWith(\"//\")) {\r\n xpath2 = xpathData[i].value.substring(\r\n xpathData[i].value.indexOf(\"//\") + 2\r\n );\r\n } else {\r\n xpath2 = xpathData[i].value; // No need to modify the value\r\n }\r\n\r\n const result = descendantExpression(\r\n refExpectElement,\r\n xpath2,\r\n relation,\r\n expElementDocmnt || docmt,\r\n isIndex,\r\n expCommonParentXpathElements,\r\n step4,\r\n refCommonParentXpathElementLength,\r\n multiElementReferenceMode\r\n );\r\n if (result?.length) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n const refCommonParentXpath = refCommonParentXpathElements.join(\"[\");\r\n const refCommonParentXpathElementLength =\r\n refCommonParentXpathElements.length - 1;\r\n const step4 = refCommonParentXpath;\r\n const traverseXpath = getTraverseXpathExpression(\r\n `${\r\n step4 +\r\n (refCommonParentXpathElementLength\r\n ? \"]\".repeat(refCommonParentXpathElementLength)\r\n : \"\")\r\n }`,\r\n expCommonParentXpathElements,\r\n refExpectElement[refExpectElement.length - 1],\r\n refExpectElement,\r\n docmt,\r\n relation,\r\n isIndex,\r\n multiElementReferenceMode\r\n );\r\n if (traverseXpath) {\r\n return traverseXpath;\r\n }\r\n};\r\n\r\nconst getXpathRelationExpression = (\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: string,\r\n xpath1: any[],\r\n xpath2: any[],\r\n isIndex: boolean,\r\n multiElementReferenceMode: boolean\r\n) => {\r\n let xpaths1;\r\n let xpaths2;\r\n console.log(\"getXpathRelationExpression\", relation);\r\n const finalXpaths: { key: string; value: any }[] = [];\r\n\r\n try {\r\n xpaths1 = xpath1\r\n .filter((x) => !x?.key?.includes(\"absolute\"))\r\n .filter((x) => doesReferenceXpathMatchElement(x.value, element1));\r\n\r\n xpaths2 = xpath2.filter((x) => !x?.key?.includes(\"absolute\"));\r\n\r\n for (let i = 0; i < xpaths1.length; i++) {\r\n for (let j = 0; j < xpaths2.length; j++) {\r\n const targetXpathValue =\r\n xpaths2[j].value.indexOf(\"//\") !== 0\r\n ? xpaths2[j].value\r\n : xpaths2[j].value.substring(xpaths2[j].value.indexOf(\"//\") + 2);\r\n\r\n const referenceXpath = getReferenceXpathValue(xpaths1[i].value, element1);\r\n let rel_xpath: string | undefined = `//${referenceXpath}/${relation}::${replaceActualAttributes(targetXpathValue, element2)}`;\r\n console.log(\"getXpathRelationExpression\", rel_xpath);\r\n const rel_count = getCountOfXPath(\r\n rel_xpath,\r\n element2,\r\n element2.ownerDocument\r\n );\r\n if (rel_count > 1) {\r\n // Non-unique normal relation: try semantic bridge before index.\r\n const ancestorBridgeXpaths = getAncestorSemanticBridgeXpaths(\r\n element1,\r\n element2,\r\n relation,\r\n xpaths1,\r\n xpaths2\r\n );\r\n\r\n if (ancestorBridgeXpaths.length) {\r\n finalXpaths.push(...ancestorBridgeXpaths);\r\n return finalXpaths;\r\n }\r\n\r\n const semanticBridgeXpath = getSemanticRelationBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n relation,\r\n xpaths2\r\n );\r\n\r\n if (semanticBridgeXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(semanticBridgeXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n const semanticTargetXpath = getDirectSemanticDescendantXpath(\r\n referenceXpath,\r\n relation,\r\n element2,\r\n xpaths2,\r\n element2.ownerDocument\r\n );\r\n\r\n if (semanticTargetXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(semanticTargetXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n if (isIndex) {\r\n rel_xpath = findXpathWithIndex(\r\n rel_xpath,\r\n element2,\r\n element2.ownerDocument,\r\n rel_count\r\n );\r\n if (rel_xpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation}${isIndex ? \" index\" : \"\"}`,\r\n value: replaceTempAttributes(rel_xpath)\r\n });\r\n return finalXpaths;\r\n }\r\n } else if (rel_count > 1) {\r\n if (xpathDataWithIndex.length) {\r\n if (rel_count < xpathDataWithIndex[0].count) {\r\n xpathDataWithIndex.pop();\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by relative child ${\r\n isIndex ? \"index\" : \"\"\r\n }`,\r\n value: rel_xpath,\r\n count: rel_count\r\n });\r\n }\r\n } else {\r\n xpathDataWithIndex.push({\r\n key: `relative xpath by relative child ${\r\n isIndex ? \"index\" : \"\"\r\n }`,\r\n value: rel_xpath,\r\n count: rel_count\r\n });\r\n }\r\n }\r\n } else if (rel_count === 1) {\r\n if (hasStructuralRelationTail(targetXpathValue)) {\r\n // Unique but long/structural: try semantic bridge, but keep this\r\n // original unique XPath if no bridge can safely replace it.\r\n const ancestorBridgeXpaths = getAncestorSemanticBridgeXpaths(\r\n element1,\r\n element2,\r\n relation,\r\n xpaths1,\r\n xpaths2\r\n );\r\n\r\n if (ancestorBridgeXpaths.length) {\r\n finalXpaths.push(...ancestorBridgeXpaths);\r\n return finalXpaths;\r\n }\r\n\r\n const bridgeXpath = getSemanticRelationBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n relation,\r\n xpaths2\r\n );\r\n\r\n if (bridgeXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(bridgeXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n\r\n finalXpaths.push({\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(rel_xpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n }\r\n if (!finalXpaths.length) {\r\n // No normal relation resolved; give semantic bridge one bounded attempt\r\n // before the existing traverse/index fallbacks run.\r\n const ancestorBridgeXpaths = getAncestorSemanticBridgeXpaths(\r\n element1,\r\n element2,\r\n relation,\r\n xpaths1,\r\n xpaths2\r\n );\r\n\r\n if (ancestorBridgeXpaths.length) {\r\n finalXpaths.push(...ancestorBridgeXpaths);\r\n return finalXpaths;\r\n }\r\n\r\n for (let i = 0; i < xpaths1.length; i++) {\r\n const referenceXpath = getReferenceXpathValue(xpaths1[i].value, element1);\r\n const bridgeXpath = getSemanticRelationBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n relation,\r\n xpaths2\r\n );\r\n\r\n if (bridgeXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(bridgeXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n\r\n for (let i = 0; i < xpaths1.length; i++) {\r\n for (let j = 0; j < xpaths2.length; j++) {\r\n const tempPath = `${\r\n xpaths2[j].value.indexOf(\"//\") !== 0\r\n ? xpaths2[j].value\r\n : xpaths2[j].value.substring(xpaths2[j].value.indexOf(\"//\") + 2)\r\n }`;\r\n const xpath2Elements: string[] = tempPath.split(\r\n /\\/(?=(?:[^']*\\'[^\\']*\\')*[^\\']*$)/g\r\n );\r\n if (xpath2Elements.length > 1) {\r\n const referenceXpath = getReferenceXpathValue(\r\n xpaths1[i].value,\r\n element1\r\n );\r\n\r\n const bridgeXpath = getSemanticRelationBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n relation,\r\n xpaths2\r\n );\r\n\r\n if (bridgeXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(bridgeXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n const traverseXpath = getTraverseXpathExpression(\r\n referenceXpath,\r\n xpath2Elements,\r\n element2,\r\n [element1, element2],\r\n element2.ownerDocument,\r\n relation,\r\n isIndex,\r\n multiElementReferenceMode\r\n );\r\n\r\n console.log(\r\n \"getXpathRelationExpression traverseXpath\",\r\n traverseXpath\r\n );\r\n if (traverseXpath) {\r\n finalXpaths.push(...traverseXpath);\r\n return finalXpaths;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n\r\n return finalXpaths;\r\n};\r\n\r\nconst xpathStepSeparator = /\\/(?=(?:[^']*'[^']*')*[^']*$)/g;\r\n\r\nconst stripXpathPrefix = (xpath: string) =>\r\n xpath.indexOf(\"//\") === 0 ? xpath.substring(xpath.indexOf(\"//\") + 2) : xpath;\r\n\r\nconst getCommonAncestor = (\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element\r\n) => {\r\n let currentNode: Element | null = element1;\r\n\r\n while (currentNode) {\r\n if (currentNode.contains(element2)) {\r\n return currentNode;\r\n }\r\n\r\n currentNode = currentNode.parentElement;\r\n }\r\n\r\n return null;\r\n};\r\n\r\nconst getSingleStepXpath = (\r\n element: HTMLElement | Element,\r\n xpaths: { key: string; value: string }[]\r\n) => {\r\n return getSingleStepXpaths(element, xpaths)[0] || \"\";\r\n};\r\n\r\nconst getSingleStepXpaths = (\r\n element: HTMLElement | Element,\r\n xpaths: { key: string; value: string }[]\r\n) => {\r\n const candidates: string[] = [];\r\n let tagOnlyXpath = \"\";\r\n const addCandidate = (xpath: string) => {\r\n if (xpath && !candidates.includes(xpath)) {\r\n candidates.push(xpath);\r\n }\r\n };\r\n\r\n for (const xpath of xpaths) {\r\n const xpathValue = stripXpathPrefix(xpath.value);\r\n\r\n if (xpathValue && xpathValue.split(xpathStepSeparator).length === 1) {\r\n if (\r\n xpathValue === element.tagName ||\r\n xpathValue === element.tagName.toLowerCase()\r\n ) {\r\n tagOnlyXpath = xpathValue;\r\n continue;\r\n }\r\n\r\n addCandidate(replaceActualAttributes(xpathValue, element));\r\n }\r\n }\r\n\r\n for (const attributeName of semanticScopeAttributeNames) {\r\n const attributeValue = element.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getStableAttributeCondition(attributeName, attributeValue);\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n // A semantic target step is better than plain tag-only in reference mode; final relation scoping validates uniqueness.\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}' and ${condition}]`\r\n : `${element.tagName}[${condition}]`);\r\n }\r\n\r\n if (element.textContent) {\r\n const textXpath = getTextXpathFunction(element);\r\n\r\n if (textXpath) {\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}' and ${textXpath}]`\r\n : `${element.tagName}[${textXpath}]`);\r\n }\r\n }\r\n\r\n const classConditions = getClassTokenConditions(\r\n element,\r\n element.getAttribute(\"class\"),\r\n (element.getRootNode?.() as Document | ShadowRoot | null) ??\r\n element.ownerDocument,\r\n false\r\n );\r\n for (const classCondition of classConditions) {\r\n // Try every stable class token in reference mode; final relation\r\n // validation decides which token is actually unique.\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}' and ${classCondition}]`\r\n : `${element.tagName}[${classCondition}]`);\r\n }\r\n\r\n if (element.attributes) {\r\n for (const attrName of Array.from(element.attributes)) {\r\n if (attrName.name === \"class\") {\r\n // Class was already handled through getClassTokenConditions above.\r\n // Do not let the generic attribute fallback reintroduce numeric class\r\n // values such as css-1xc3v61-indicatorContainer.\r\n continue;\r\n }\r\n\r\n if (\r\n checkBlockedAttributes(attrName, element, false) &&\r\n attrName.nodeValue\r\n ) {\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}' and @${attrName.name}=${escapeCharacters(\r\n sanitizeAttributeValue(attrName.name, attrName.nodeValue)\r\n )}]`\r\n : `${element.tagName}[@${attrName.name}=${escapeCharacters(\r\n sanitizeAttributeValue(attrName.name, attrName.nodeValue)\r\n )}]`);\r\n }\r\n }\r\n }\r\n\r\n if (tagOnlyXpath) {\r\n addCandidate(tagOnlyXpath);\r\n }\r\n\r\n addCandidate(isSvg(element)\r\n ? `*[local-name()='${element.tagName}']`\r\n : element.tagName);\r\n\r\n return candidates;\r\n};\r\n\r\nconst getRelativeXpathFromAncestor = (\r\n ancestorElement: Element,\r\n targetElement: HTMLElement | Element,\r\n targetXPaths: { key: string; value: string }[]\r\n) => {\r\n const steps: string[] = [];\r\n let currentNode: Element | null = targetElement;\r\n\r\n while (currentNode && currentNode !== ancestorElement) {\r\n const currentStep =\r\n currentNode === targetElement\r\n ? getSingleStepXpath(targetElement, targetXPaths)\r\n : isSvg(currentNode)\r\n ? `*[local-name()='${currentNode.tagName}']`\r\n : currentNode.tagName;\r\n\r\n steps.unshift(currentStep);\r\n currentNode = currentNode.parentElement;\r\n }\r\n\r\n return currentNode === ancestorElement ? steps.join(\"/\") : \"\";\r\n};\r\n\r\nconst semanticScopeAttributeNames = [\r\n \"aria-labelledby\",\r\n \"aria-label\",\r\n \"role\",\r\n \"name\",\r\n \"data-testid\",\r\n \"data-test\",\r\n \"data-qa\",\r\n \"data-id\",\r\n \"id\"\r\n];\r\n\r\nconst getStableAttributeCondition = (attributeName: string, value: string) => {\r\n const sanitizedValue = sanitizeAttributeValue(attributeName, value);\r\n\r\n if (!sanitizedValue) {\r\n return \"\";\r\n }\r\n\r\n if (/\\d/.test(sanitizedValue)) {\r\n // Strict numeric-attribute validation: relation/bridge strategies must not\r\n // split numeric attributes into contains/starts-with predicates.\r\n return \"\";\r\n }\r\n\r\n return `@${attributeName}=${escapeCharacters(sanitizedValue)}`;\r\n};\r\n\r\nconst hasStructuralRelationTail = (xpath: string) =>\r\n xpath.split(xpathStepSeparator).length > 1 || /\\[\\d+\\]/.test(xpath);\r\n\r\n// Normalize candidate reference XPath once so relation builders do not repeat\r\n// prefix stripping and temp-attribute replacement.\r\nconst getReferenceXpathValue = (\r\n xpathValue: string,\r\n element: HTMLElement | Element\r\n) =>\r\n xpathValue.indexOf(\"//\") !== 0\r\n ? replaceActualAttributes(xpathValue, element)\r\n : replaceActualAttributes(\r\n xpathValue.substring(xpathValue.indexOf(\"//\") + 2),\r\n element\r\n );\r\n\r\nconst getSemanticNodeTests = (element: Element) => {\r\n const nodeTests: string[] = [];\r\n\r\n // Use only stable semantic attributes for bridge scopes; numeric values are\r\n // rejected by getStableAttributeCondition.\r\n for (const attributeName of semanticScopeAttributeNames) {\r\n const attributeValue = element.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getStableAttributeCondition(attributeName, attributeValue);\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n nodeTests.push(\r\n isSvg(element)\r\n ? `*[local-name()='${element.tagName}' and ${condition}]`\r\n : `${element.tagName}[${condition}]`\r\n );\r\n break;\r\n }\r\n\r\n return nodeTests;\r\n};\r\n\r\nconst getLimitedSelfAndAncestors = (element: Element | null, limit = 6) => {\r\n const elements: Element[] = [];\r\n let currentElement = element;\r\n\r\n while (currentElement && elements.length < limit) {\r\n elements.push(currentElement);\r\n currentElement = currentElement.parentElement;\r\n }\r\n\r\n return elements;\r\n};\r\n\r\nconst getDescendantScopeAttributeCondition = (\r\n attributeName: string,\r\n value: string\r\n) => {\r\n // Descendant scoping is allowed one narrow UUID-prefix exception; other\r\n // semantic bridges keep numeric attributes blocked.\r\n const condition = getStableAttributeCondition(attributeName, value);\r\n if (condition) {\r\n return condition;\r\n }\r\n\r\n const sanitizedValue = sanitizeAttributeValue(attributeName, value);\r\n if (attributeName !== \"id\" || !sanitizedValue) {\r\n return \"\";\r\n }\r\n\r\n const uuidSuffixPattern =\r\n /^(.+?)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\r\n const match = sanitizedValue.match(uuidSuffixPattern);\r\n const stablePrefix = match?.[1]?.trim();\r\n\r\n if (!stablePrefix || stablePrefix.length <= 2 || !/[a-zA-Z]/.test(stablePrefix)) {\r\n return \"\";\r\n }\r\n\r\n return `contains(@${attributeName},${escapeCharacters(stablePrefix)})`;\r\n};\r\n\r\nconst getSemanticScopedBridgeXpath = (\r\n referenceXpath: string,\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n commonAncestor: Element,\r\n relation: \"ancestor\" | \"ancestor-or-self\",\r\n ancestorNodeTest: string,\r\n targetAxisXpath: string\r\n) => {\r\n let scopeElement = element2.parentElement;\r\n let checkedAncestors = 0;\r\n\r\n while (\r\n scopeElement &&\r\n scopeElement !== commonAncestor &&\r\n checkedAncestors < 6\r\n ) {\r\n checkedAncestors++;\r\n\r\n for (const attributeName of semanticScopeAttributeNames) {\r\n const attributeValue = scopeElement.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getStableAttributeCondition(\r\n attributeName,\r\n attributeValue\r\n );\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n const scopeNodeTest = isSvg(scopeElement)\r\n ? `*[local-name()='${scopeElement.tagName}' and ${condition}]`\r\n : `${scopeElement.tagName}[${condition}]`;\r\n // This bounded semantic scope avoids falling back to long DIV/DIV chains when a labelled group can uniquely scope the target.\r\n const scopedXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/descendant::${scopeNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n if (getCountOfXPath(scopedXpath, element2, element2.ownerDocument) === 1) {\r\n return scopedXpath;\r\n }\r\n }\r\n\r\n scopeElement = scopeElement.parentElement;\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\n// Semantic bridge for broad directional axes:\r\n// reference/following::target-ancestor/descendant::target.\r\n// reference/preceding::target-ancestor/descendant::target.\r\nconst directionalIntermediateAttributeNames = [\r\n \"title\",\r\n ...semanticScopeAttributeNames\r\n];\r\n\r\nconst getDirectionalIntermediateBridgeXpath = (\r\n referenceXpath: string,\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: string,\r\n xpaths2: { key: string; value: string }[]\r\n) => {\r\n if (relation !== \"following\" && relation !== \"preceding\") {\r\n return \"\";\r\n }\r\n\r\n // Bridge only through target ancestors, so the second hop is safely scoped as descendant::target.\r\n const targetAxisXpaths = getSingleStepXpaths(element2, xpaths2);\r\n if (!targetAxisXpaths.length) {\r\n return \"\";\r\n }\r\n\r\n const resolvedReference = getFirstElementByXpath(\r\n `//${replaceActualAttributes(referenceXpath, element1)}`,\r\n element1.ownerDocument\r\n );\r\n const positionReference = resolvedReference || element1;\r\n let intermediate = element2.parentElement;\r\n let checkedAncestors = 0;\r\n\r\n while (intermediate && checkedAncestors < 6) {\r\n checkedAncestors++;\r\n\r\n const position = positionReference.compareDocumentPosition(intermediate);\r\n const expectedPosition =\r\n relation === \"following\"\r\n ? Node.DOCUMENT_POSITION_FOLLOWING\r\n : Node.DOCUMENT_POSITION_PRECEDING;\r\n if (!(position & expectedPosition)) {\r\n intermediate = intermediate.parentElement;\r\n continue;\r\n }\r\n\r\n for (const attributeName of directionalIntermediateAttributeNames) {\r\n const attributeValue = intermediate.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getStableAttributeCondition(\r\n attributeName,\r\n attributeValue\r\n );\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n const intermediateNodeTest = isSvg(intermediate)\r\n ? `*[local-name()='${intermediate.tagName}' and ${condition}]`\r\n : `${intermediate.tagName}[${condition}]`;\r\n for (const targetAxisXpath of targetAxisXpaths) {\r\n // Keep this as a fallback-only semantic bridge: following::ancestor/descendant::target, accepted only when unique.\r\n const bridgeXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${intermediateNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n if (\r\n getCountOfXPath(bridgeXpath, element2, element2.ownerDocument) === 1\r\n ) {\r\n return bridgeXpath;\r\n }\r\n }\r\n }\r\n\r\n intermediate = intermediate.parentElement;\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getSemanticSiblingBridgeXpath = (\r\n referenceXpath: string,\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: string,\r\n xpaths2: { key: string; value: string }[]\r\n) => {\r\n if (relation !== \"following-sibling\" && relation !== \"preceding-sibling\") {\r\n return \"\";\r\n }\r\n\r\n const targetAxisXpaths = getSingleStepXpaths(element2, xpaths2);\r\n if (!targetAxisXpaths.length) {\r\n return \"\";\r\n }\r\n\r\n // Sibling bridges climb both sides to semantic sibling containers, e.g.\r\n // A -> ancestor LI -> following-sibling LI -> descendant target.\r\n const referenceScopes = getLimitedSelfAndAncestors(element1);\r\n const targetScopes = getLimitedSelfAndAncestors(element2);\r\n\r\n for (const referenceScope of referenceScopes) {\r\n const referenceScopeTests = getSemanticNodeTests(referenceScope);\r\n if (!referenceScopeTests.length) {\r\n continue;\r\n }\r\n\r\n for (const targetScope of targetScopes) {\r\n const targetScopeTests = getSemanticNodeTests(targetScope);\r\n if (!targetScopeTests.length) {\r\n continue;\r\n }\r\n\r\n const isSibling =\r\n relation === \"following-sibling\"\r\n ? referenceScope.nextElementSibling === targetScope ||\r\n Array.from(referenceScope.parentElement?.children || []).indexOf(\r\n targetScope\r\n ) >\r\n Array.from(referenceScope.parentElement?.children || []).indexOf(\r\n referenceScope\r\n )\r\n : referenceScope.previousElementSibling === targetScope ||\r\n Array.from(referenceScope.parentElement?.children || []).indexOf(\r\n targetScope\r\n ) <\r\n Array.from(referenceScope.parentElement?.children || []).indexOf(\r\n referenceScope\r\n );\r\n\r\n if (\r\n !referenceScope.parentElement ||\r\n referenceScope.parentElement !== targetScope.parentElement ||\r\n !isSibling\r\n ) {\r\n continue;\r\n }\r\n\r\n for (const referenceScopeTest of referenceScopeTests) {\r\n for (const targetScopeTest of targetScopeTests) {\r\n for (const targetAxisXpath of targetAxisXpaths) {\r\n const bridgeXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/ancestor-or-self::${referenceScopeTest}/${relation}::${targetScopeTest}/descendant-or-self::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n if (\r\n getCountOfXPath(bridgeXpath, element2, element2.ownerDocument) === 1\r\n ) {\r\n return bridgeXpath;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getSemanticChildBridgeXpath = (\r\n referenceXpath: string,\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: string,\r\n xpaths2: { key: string; value: string }[]\r\n) => {\r\n if (relation !== \"child\") {\r\n return \"\";\r\n }\r\n\r\n const targetAxisXpaths = getSingleStepXpaths(element2, xpaths2);\r\n if (!targetAxisXpaths.length) {\r\n return \"\";\r\n }\r\n\r\n const targetScopes = getLimitedSelfAndAncestors(element2).filter(\r\n (scope) => scope.parentElement === element1\r\n );\r\n\r\n // Child bridge intentionally only uses direct child scopes of the reference;\r\n // intermediate wrappers remain part of the normal fallback flow.\r\n for (const targetScope of targetScopes) {\r\n const targetScopeTests = getSemanticNodeTests(targetScope);\r\n if (!targetScopeTests.length) {\r\n continue;\r\n }\r\n\r\n for (const targetScopeTest of targetScopeTests) {\r\n for (const targetAxisXpath of targetAxisXpaths) {\r\n const bridgeXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/child::${targetScopeTest}/descendant-or-self::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n if (getCountOfXPath(bridgeXpath, element2, element2.ownerDocument) === 1) {\r\n return bridgeXpath;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getSemanticRelationBridgeXpath = (\r\n referenceXpath: string,\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: string,\r\n xpaths2: { key: string; value: string }[]\r\n) =>\r\n // Shared dispatcher keeps the relation-level flow simple: ask for a bridge,\r\n // and each helper silently ignores axes it does not support.\r\n getDirectionalIntermediateBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n relation,\r\n xpaths2\r\n ) ||\r\n getSemanticSiblingBridgeXpath(referenceXpath, element1, element2, relation, xpaths2) ||\r\n getSemanticChildBridgeXpath(referenceXpath, element1, element2, relation, xpaths2);\r\n\r\nconst getAncestorSemanticBridgeXpaths = (\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: string,\r\n xpaths1: { key: string; value: string }[],\r\n xpaths2: { key: string; value: string }[]\r\n) => {\r\n if (relation !== \"ancestor\" && relation !== \"ancestor-or-self\") {\r\n return [];\r\n }\r\n\r\n // Ancestor bridge is called with index disabled so index remains the final\r\n // fallback in getXpathRelationExpression.\r\n return getAncestorBridgeXpath(\r\n element1,\r\n element2,\r\n relation,\r\n xpaths1,\r\n xpaths2,\r\n false\r\n );\r\n};\r\n\r\nconst getSemanticAncestorNodeTest = (\r\n commonAncestor: Element,\r\n element2: HTMLElement | Element\r\n) => {\r\n let ancestorElement: Element | null = commonAncestor;\r\n let checkedAncestors = 0;\r\n const candidates: { nodeTest: string; score: number }[] = [];\r\n const semanticContainerTags = new Set([\r\n \"SECTION\",\r\n \"FIELDSET\",\r\n \"FORM\",\r\n \"ARTICLE\",\r\n \"MAIN\"\r\n ]);\r\n\r\n // Prefer a meaningful containing section/group over generic ancestor::DIV when it can still scope the target.\r\n while (ancestorElement && ancestorElement.contains(element2) && checkedAncestors < 6) {\r\n checkedAncestors++;\r\n\r\n for (const attributeName of semanticScopeAttributeNames) {\r\n const attributeValue = ancestorElement.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getStableAttributeCondition(\r\n attributeName,\r\n attributeValue\r\n );\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n const nodeTest = isSvg(ancestorElement)\r\n ? `*[local-name()='${ancestorElement.tagName}' and ${condition}]`\r\n : `${ancestorElement.tagName}[${condition}]`;\r\n const score =\r\n (semanticContainerTags.has(ancestorElement.tagName) ? 100 : 0) +\r\n (attributeName === \"data-testid\" ? 20 : 0) -\r\n checkedAncestors;\r\n\r\n candidates.push({ nodeTest, score });\r\n break;\r\n }\r\n\r\n ancestorElement = ancestorElement.parentElement;\r\n }\r\n\r\n return candidates.sort((left, right) => right.score - left.score)[0]\r\n ?.nodeTest || \"\";\r\n};\r\n\r\n// Semantic bridge for descendant and descendant-or-self only:\r\n// reference/descendant::semantic-scope/descendant::target.\r\nconst getDirectSemanticDescendantXpath = (\r\n referenceXpath: string,\r\n relation: string,\r\n element2: HTMLElement | Element,\r\n xpaths2: { key: string; value: string }[],\r\n docmt: Node\r\n) => {\r\n if (relation !== \"descendant\" && relation !== \"descendant-or-self\") {\r\n return \"\";\r\n }\r\n\r\n for (const xpath of xpaths2) {\r\n const targetXpath = stripXpathPrefix(xpath.value);\r\n\r\n if (\r\n !targetXpath ||\r\n targetXpath.split(xpathStepSeparator).length > 1 ||\r\n /\\[\\d+\\]/.test(targetXpath)\r\n ) {\r\n continue;\r\n }\r\n\r\n // Before index fallback, try meaningful single-step target candidates\r\n // such as IMG[@alt='...'] under the same descendant relation.\r\n const candidateXpath = `//${referenceXpath}/${relation}::${replaceActualAttributes(\r\n targetXpath,\r\n element2\r\n )}`;\r\n\r\n if (getCountOfXPath(candidateXpath, element2, docmt) === 1) {\r\n return candidateXpath;\r\n }\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getSemanticScopedDescendantXpath = (\r\n referenceXpath: string,\r\n relation: string,\r\n element2: HTMLElement | Element,\r\n docmt: Node\r\n) => {\r\n // This helper only belongs to descendant-style relations; other axes keep their existing flow.\r\n if (relation !== \"descendant\" && relation !== \"descendant-or-self\") {\r\n return \"\";\r\n }\r\n\r\n // Keep the target side as a single meaningful step so we do not rebuild the same DIV/DIV tail.\r\n const targetAxisXpaths = getSingleStepXpaths(element2, [\r\n ...(parseDOM(element2, element2.ownerDocument, false, false) || []),\r\n ...(getReferenceElementsXpath(element2, element2.ownerDocument, true) || []),\r\n { key: \"tag\", value: element2.tagName }\r\n ]);\r\n if (!targetAxisXpaths.length) {\r\n return \"\";\r\n }\r\n\r\n let scopeElement = element2.parentElement;\r\n let checkedAncestors = 0;\r\n\r\n // Walk a bounded set of target ancestors to cover table/card wrappers without broad DOM scanning.\r\n while (scopeElement && checkedAncestors < 10) {\r\n checkedAncestors++;\r\n\r\n // Use semantic attributes that describe a container/group before falling back to raw structure.\r\n for (const attributeName of semanticScopeAttributeNames) {\r\n const attributeValue = scopeElement.getAttribute(attributeName);\r\n if (!attributeValue) {\r\n continue;\r\n }\r\n\r\n const condition = getDescendantScopeAttributeCondition(\r\n attributeName,\r\n attributeValue\r\n );\r\n if (!condition) {\r\n continue;\r\n }\r\n\r\n const scopeNodeTest = isSvg(scopeElement)\r\n ? `*[local-name()='${scopeElement.tagName}' and ${condition}]`\r\n : `${scopeElement.tagName}[${condition}]`;\r\n for (const targetAxisXpath of targetAxisXpaths) {\r\n // Prefer a labelled semantic descendant scope before accepting an indexed structural tail like DIV/DIV[2]/LABEL.\r\n const scopedXpath = `//${referenceXpath}/${relation}::${scopeNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n // Accept the semantic version only when it uniquely resolves to the same target.\r\n if (getCountOfXPath(scopedXpath, element2, docmt) === 1) {\r\n return scopedXpath;\r\n }\r\n }\r\n }\r\n\r\n scopeElement = scopeElement.parentElement;\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getFirstElementByXpath = (xpath: string, docmt: Document) => {\r\n try {\r\n const result = docmt.evaluate(\r\n xpath,\r\n docmt,\r\n null,\r\n XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n ).singleNodeValue;\r\n\r\n return result instanceof Element ? result : null;\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\nconst doesReferenceXpathMatchElement = (\r\n xpathValue: string,\r\n element: HTMLElement | Element\r\n) => {\r\n const referenceXpath = stripXpathPrefix(xpathValue);\r\n if (!referenceXpath) {\r\n return false;\r\n }\r\n\r\n try {\r\n const result = element.ownerDocument.evaluate(\r\n `//${replaceActualAttributes(referenceXpath, element)}`,\r\n element.ownerDocument,\r\n null,\r\n XPathResult.ORDERED_NODE_ITERATOR_TYPE,\r\n null\r\n );\r\n let node = result.iterateNext();\r\n\r\n while (node) {\r\n if (node === element) {\r\n return true;\r\n }\r\n node = result.iterateNext();\r\n }\r\n } catch {\r\n return false;\r\n }\r\n\r\n return false;\r\n};\r\n\r\n// Semantic bridge for ancestor and ancestor-or-self icon targets only:\r\n// reference/ancestor::shared-scope/descendant::icon/ancestor::target-wrapper.\r\nconst getBridgeClassNodeTests = (element: Element) => {\r\n const classConditions = getClassTokenConditions(\r\n element,\r\n element.getAttribute(\"class\"),\r\n (element.getRootNode?.() as Document | ShadowRoot | null) ??\r\n element.ownerDocument\r\n );\r\n\r\n // Icon ancestor bridges also use the shared class-token ordering: numeric\r\n // tokens are blocked, while the remaining stable tokens are tried in order.\r\n return classConditions.map(\r\n (condition) => `${element.tagName.toLowerCase()}[${condition}]`\r\n );\r\n};\r\n\r\nconst getIconNodeTest = (iconElement: Element) => {\r\n const fill = iconElement.getAttribute(\"fill\");\r\n const stroke = iconElement.getAttribute(\"stroke\");\r\n if (/\\d/.test(fill || \"\") || /\\d/.test(stroke || \"\")) {\r\n // Strict numeric-attribute validation also applies to SVG icon attributes.\r\n return \"\";\r\n }\r\n\r\n const condition = fill\r\n ? `@fill=${escapeCharacters(fill)}`\r\n : stroke\r\n ? `@stroke=${escapeCharacters(stroke)}`\r\n : \"\";\r\n\r\n return condition\r\n ? `*[local-name()='${iconElement.tagName.toLowerCase()}' and ${condition}]`\r\n : \"\";\r\n};\r\n\r\nconst isUniqueIconAncestorBridge = (\r\n root: Element,\r\n iconElement: Element,\r\n targetElement: Element\r\n) => {\r\n const fill = iconElement.getAttribute(\"fill\");\r\n const stroke = iconElement.getAttribute(\"stroke\");\r\n const icons = Array.from(\r\n root.querySelectorAll(iconElement.tagName.toLowerCase())\r\n ).slice(0, 30);\r\n let matches = 0;\r\n\r\n for (const icon of icons) {\r\n if (\r\n (fill && icon.getAttribute(\"fill\") !== fill) ||\r\n (!fill && stroke && icon.getAttribute(\"stroke\") !== stroke)\r\n ) {\r\n continue;\r\n }\r\n\r\n const targetCandidate = icon.closest(targetElement.tagName.toLowerCase());\r\n if (targetCandidate) {\r\n matches++;\r\n if (targetCandidate !== targetElement || matches > 1) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n return matches === 1;\r\n};\r\n\r\nconst getIconAncestorBridgeXpath = (\r\n referenceXpath: string,\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n commonAncestor: Element,\r\n relation: \"ancestor\" | \"ancestor-or-self\"\r\n) => {\r\n const iconDescendants = Array.from(\r\n element2.querySelectorAll(\"path,use,circle,rect,polygon,polyline,line\")\r\n ).slice(0, 25);\r\n\r\n if (!iconDescendants.length) {\r\n return \"\";\r\n }\r\n\r\n const ancestorNodeTests = [\r\n ...getBridgeClassNodeTests(commonAncestor),\r\n commonAncestor.tagName\r\n ];\r\n\r\n for (const iconElement of iconDescendants) {\r\n const iconNodeTest = getIconNodeTest(iconElement);\r\n if (!iconNodeTest) {\r\n continue;\r\n }\r\n\r\n // Bounded icon-wrapper fallback: reference -> shared ancestor -> distinctive icon -> target wrapper.\r\n // This runs before structural/index fallbacks and avoids scanning outside the shared ancestor.\r\n if (!isUniqueIconAncestorBridge(commonAncestor, iconElement, element2)) {\r\n continue;\r\n }\r\n\r\n for (const ancestorNodeTest of ancestorNodeTests) {\r\n return `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/descendant::${iconNodeTest}/ancestor::${element2.tagName.toLowerCase()}`;\r\n }\r\n }\r\n\r\n return \"\";\r\n};\r\n\r\nconst getAncestorBridgeXpath = (\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element,\r\n relation: \"ancestor\" | \"ancestor-or-self\",\r\n xpaths1: { key: string; value: string }[],\r\n xpaths2: { key: string; value: string }[],\r\n isIndex: boolean\r\n) => {\r\n const finalXpaths: { key: string; value: string }[] = [];\r\n const commonAncestor = getCommonAncestor(element1, element2);\r\n\r\n if (!commonAncestor || commonAncestor === element2) {\r\n return finalXpaths;\r\n }\r\n\r\n const ancestorNodeTest = isSvg(commonAncestor)\r\n ? `*[local-name()='${commonAncestor.tagName}']`\r\n : commonAncestor.tagName;\r\n // Build the old structural path from the nearest common ancestor to the target; kept as fallback.\r\n const targetRelativeXpath = getRelativeXpathFromAncestor(\r\n commonAncestor,\r\n element2,\r\n xpaths2\r\n );\r\n\r\n if (!targetRelativeXpath) {\r\n return finalXpaths;\r\n }\r\n\r\n const targetRelativeSteps = targetRelativeXpath.split(xpathStepSeparator);\r\n const shouldUseTargetAxis = targetRelativeSteps.length > 1;\r\n // When the target path has multiple steps, prefer a single target descriptor under a relational axis.\r\n const targetAxisXpath = shouldUseTargetAxis\r\n ? getSingleStepXpath(element2, xpaths2)\r\n : \"\";\r\n // This is now part of the normal flow: prefer semantic containers before generic ancestor::DIV.\r\n const semanticAncestorNodeTest = targetAxisXpath\r\n ? getSemanticAncestorNodeTest(commonAncestor, element2)\r\n : \"\";\r\n\r\n for (const xpath of xpaths1) {\r\n const referenceXpath = stripXpathPrefix(xpath.value);\r\n\r\n if (!referenceXpath) {\r\n continue;\r\n }\r\n\r\n if (semanticAncestorNodeTest) {\r\n // Try semantic ancestor first so a unique generic ancestor::DIV can become a readable section-scoped relation.\r\n const semanticAncestorXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${semanticAncestorNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`;\r\n\r\n if (\r\n getCountOfXPath(semanticAncestorXpath, element2, element2.ownerDocument) ===\r\n 1\r\n ) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(semanticAncestorXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n\r\n // Fallback to the original common-ancestor bridge when no semantic ancestor uniquely resolves the target.\r\n let finalExpectedElementXpath: string | undefined =\r\n targetAxisXpath\r\n ? `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/descendant::${replaceActualAttributes(\r\n targetAxisXpath,\r\n element2\r\n )}`\r\n : `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/${targetRelativeXpath}`;\r\n\t let rel_count = getCountOfXPath(\r\n\t finalExpectedElementXpath,\r\n\t element2,\r\n\t element2.ownerDocument\r\n\t );\r\n\t\r\n const iconBridgeXpath = getIconAncestorBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n commonAncestor,\r\n relation\r\n );\r\n\r\n if (iconBridgeXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} icon bridge`,\r\n value: replaceTempAttributes(iconBridgeXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n\t if (rel_count === 1) {\r\n\t finalXpaths.push({\r\n\t key: `dynamic ${relation} bridge`,\r\n\t value: replaceTempAttributes(finalExpectedElementXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n if (targetAxisXpath && rel_count > 1) {\r\n // Try a labelled/semantic descendant scope before structural fallback; this keeps XPath readable without returning a non-unique locator.\r\n const scopedXpath = getSemanticScopedBridgeXpath(\r\n referenceXpath,\r\n element1,\r\n element2,\r\n commonAncestor,\r\n relation,\r\n ancestorNodeTest,\r\n targetAxisXpath\r\n );\r\n\r\n if (scopedXpath) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(scopedXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n\r\n // Last non-index bridge attempt: keep the original structural tail when the axis-only target was too broad.\r\n finalExpectedElementXpath = `//${replaceActualAttributes(\r\n referenceXpath,\r\n element1\r\n )}/${relation}::${ancestorNodeTest}/${targetRelativeXpath}`;\r\n rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n element2,\r\n element2.ownerDocument\r\n );\r\n\r\n if (rel_count === 1) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n\r\n if (rel_count > 1 && isIndex) {\r\n finalExpectedElementXpath = findXpathWithIndex(\r\n finalExpectedElementXpath,\r\n element2,\r\n element2.ownerDocument,\r\n rel_count\r\n );\r\n rel_count = finalExpectedElementXpath\r\n ? getCountOfXPath(\r\n finalExpectedElementXpath,\r\n element2,\r\n element2.ownerDocument\r\n )\r\n : 0;\r\n\r\n if (finalExpectedElementXpath && rel_count === 1) {\r\n finalXpaths.push({\r\n key: `dynamic ${relation} bridge index`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n });\r\n return finalXpaths;\r\n }\r\n }\r\n }\r\n\r\n return finalXpaths;\r\n};\r\n\r\nconst getReferenceElementXpath = (element: HTMLElement | Element) => {\r\n let xpaths1: {\r\n key: string;\r\n value: string;\r\n }[] = [];\r\n\r\n xpaths1 = parseDOM(element, element.ownerDocument, false, false);\r\n\r\n const referenceElementXpaths = getReferenceElementsXpath(\r\n element,\r\n element.ownerDocument,\r\n false\r\n );\r\n if (referenceElementXpaths?.length) {\r\n xpaths1 = xpaths1?.length\r\n ? xpaths1.concat(referenceElementXpaths)\r\n : referenceElementXpaths;\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n xpaths1 = parseDOM(element, element.ownerDocument, true, false);\r\n xpaths1 = xpaths1?.map((x) =>\r\n x.value.charAt(0) == \"(\" &&\r\n findMatchingParenthesis(x.value, 0) + 1 === x.value.lastIndexOf(\"[\")\r\n ? { key: \"\", value: removeParenthesis(x.value) }\r\n : { key: \"\", value: x.value }\r\n );\r\n } else {\r\n let xpaths = parseDOM(element, element.ownerDocument, true, false);\r\n if (xpaths?.length) {\r\n xpaths = xpaths?.map((x) =>\r\n x.value.charAt(0) == \"(\" &&\r\n findMatchingParenthesis(x.value, 0) + 1 === x.value.lastIndexOf(\"[\")\r\n ? { key: \"\", value: removeParenthesis(x.value) }\r\n : { key: \"\", value: x.value }\r\n );\r\n xpaths1 = xpaths1.concat(xpaths);\r\n }\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n xpaths1 = [\r\n {\r\n key: \"\",\r\n value: getRelativeXPath(\r\n element,\r\n element.ownerDocument,\r\n false,\r\n false,\r\n Array.from(element.attributes)\r\n )\r\n }\r\n ];\r\n }\r\n\r\n if (!xpaths1?.length) {\r\n xpaths1 = [\r\n {\r\n key: \"\",\r\n value: getRelativeXPath(\r\n element,\r\n element.ownerDocument,\r\n true,\r\n false,\r\n Array.from(element.attributes)\r\n )\r\n }\r\n ];\r\n xpaths1 = xpaths1?.map((x) =>\r\n x.value.charAt(0) == \"(\" &&\r\n findMatchingParenthesis(x.value, 0) + 1 === x.value.lastIndexOf(\"[\")\r\n ? { key: \"\", value: removeParenthesis(x.value) }\r\n : { key: \"\", value: x.value }\r\n );\r\n }\r\n\r\n const childAnchorXpaths = Array.from(element.children || [])\r\n .map((child) => {\r\n const childText = getTextContent(child)?.trim();\r\n\r\n if (!childText || childText !== getTextContent(element)?.trim()) {\r\n return null;\r\n }\r\n\r\n const containerTextCondition = getContainerTextCondition(child, childText);\r\n const childTextCondition = containerTextCondition\r\n ? containerTextCondition\r\n : /\\s/.test(childText)\r\n ? `normalize-space(.)=${escapeCharacters(replaceWhiteSpaces(childText))}`\r\n : `.=${escapeCharacters(childText)}`;\r\n\r\n return {\r\n key: \"reference child text\",\r\n value: `${child.tagName}[${childTextCondition}]`\r\n };\r\n })\r\n .filter((xpath): xpath is { key: string; value: string } => !!xpath);\r\n\r\n if (childAnchorXpaths.length) {\r\n xpaths1 = childAnchorXpaths.concat(xpaths1);\r\n }\r\n\r\n const referenceXpathElement = getAbsoluteXPath(\r\n element,\r\n element.ownerDocument\r\n );\r\n xpaths1 = xpaths1.filter((x) => x.value !== referenceXpathElement);\r\n\r\n xpaths1.push({\r\n key: \"absolute xpath\",\r\n value: referenceXpathElement.slice(1)\r\n });\r\n\r\n return xpaths1;\r\n};\r\n\r\nconst getTraverseXpathExpression = (\r\n xpathe1: string,\r\n absoluteXpathElements: string[],\r\n element2: HTMLElement | Element,\r\n refExpectElement: Array<HTMLElement | Element>,\r\n docmt: Node,\r\n relation: string,\r\n isIndex: boolean,\r\n multiElementReferenceMode: boolean\r\n) => {\r\n let finalExpectedElementXpath: string | undefined;\r\n if (!multiElementReferenceMode) {\r\n for (let x = 1; x <= absoluteXpathElements.length; x++) {\r\n const xpath2Candidates = replaceTrailingTargetClassWithTokenXpaths(\r\n absoluteXpathElements\r\n .slice(absoluteXpathElements.length - x, absoluteXpathElements.length)\r\n .join(\"/\"),\r\n element2\r\n );\r\n\r\n for (const xpath2 of xpath2Candidates) {\r\n finalExpectedElementXpath = `//${xpathe1}/${relation}::${replaceActualAttributes(\r\n xpath2,\r\n element2\r\n )}`;\r\n const rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n element2,\r\n docmt\r\n );\r\n if (rel_count === 1) {\r\n // A unique candidate can still be brittle if uniqueness came from an indexed/structural tail.\r\n const hasStructuralTail =\r\n xpath2.split(xpathStepSeparator).length > 1 ||\r\n /\\[\\d+\\]/.test(xpath2);\r\n if (hasStructuralTail) {\r\n // Descendant mode can otherwise return absolute-looking tails; try a semantic scope first when it stays unique.\r\n const scopedXpath = getSemanticScopedDescendantXpath(\r\n xpathe1,\r\n relation,\r\n element2,\r\n docmt\r\n );\r\n\r\n if (scopedXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(scopedXpath)\r\n }\r\n ];\r\n }\r\n }\r\n\r\n // No better semantic scope was found, so preserve the existing unique generated XPath.\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n if (rel_count > 1) {\r\n const semanticTargetXpath = getDirectSemanticDescendantXpath(\r\n xpathe1,\r\n relation,\r\n element2,\r\n parseDOM(element2, element2.ownerDocument, false, false) || [],\r\n docmt\r\n );\r\n\r\n if (semanticTargetXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(semanticTargetXpath)\r\n }\r\n ];\r\n }\r\n\r\n // Before adding an index, see whether a nearby semantic container can narrow the descendant target.\r\n const scopedXpath = getSemanticScopedDescendantXpath(\r\n xpathe1,\r\n relation,\r\n element2,\r\n docmt\r\n );\r\n\r\n if (scopedXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(scopedXpath)\r\n }\r\n ];\r\n }\r\n\r\n if (isIndex) {\r\n // Semantic scoping failed; continue with the existing index fallback behavior.\r\n finalExpectedElementXpath = findXpathWithIndex(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt,\r\n rel_count\r\n );\r\n if (finalExpectedElementXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}${isIndex ? \" index\" : \"\"}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } else {\r\n const xpath2 = absoluteXpathElements.join(\"/\");\r\n finalExpectedElementXpath = `//${xpathe1}/${relation}::${replaceActualAttributes(\r\n xpath2,\r\n element2\r\n )}`;\r\n const rel_count = getCountOfXPath(\r\n finalExpectedElementXpath,\r\n element2,\r\n docmt\r\n );\r\n if (rel_count === 1) {\r\n return [\r\n {\r\n key: `dynamic ${relation}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n if (rel_count > 1) {\r\n if (isIndex) {\r\n finalExpectedElementXpath = findXpathWithIndex(\r\n finalExpectedElementXpath,\r\n refExpectElement[refExpectElement.length - 1],\r\n docmt,\r\n rel_count\r\n );\r\n if (finalExpectedElementXpath) {\r\n return [\r\n {\r\n key: `dynamic ${relation}${isIndex ? \" index\" : \"\"}`,\r\n value: replaceTempAttributes(finalExpectedElementXpath)\r\n }\r\n ];\r\n }\r\n }\r\n }\r\n }\r\n};\r\n\r\nconst replaceTrailingTargetClassWithTokenXpaths = (\r\n xpath: string,\r\n element: HTMLElement | Element\r\n) => {\r\n const classValue = element.getAttribute(\"class\") || \"\";\r\n const classConditions = getClassTokenConditions(\r\n element,\r\n classValue,\r\n (element.getRootNode?.() as Document | ShadowRoot | null) ??\r\n element.ownerDocument\r\n );\r\n\r\n if (!classConditions.length) {\r\n return [xpath];\r\n }\r\n\r\n const exactClassStep = `${element.tagName}[@class=${escapeCharacters(\r\n classValue\r\n )}]`;\r\n\r\n if (!xpath.endsWith(exactClassStep)) {\r\n return [xpath];\r\n }\r\n\r\n // Structural tails are still allowed here, but the final target step should\r\n // follow the shared class rule and try every stable token before indexed\r\n // fallback is considered.\r\n return classConditions.map((classCondition) => {\r\n const replacementStep = `${element.tagName}[${classCondition}]`;\r\n return `${xpath.slice(0, -exactClassStep.length)}${replacementStep}`;\r\n });\r\n};\r\n\r\nexport const getSmartRelations = (\r\n element1: HTMLElement | Element,\r\n element2: HTMLElement | Element\r\n) => {\r\n const pos = element1.compareDocumentPosition(element2);\r\n\r\n const highPriority: string[] = [];\r\n const mediumPriority: string[] = [];\r\n const lowPriority: string[] = [];\r\n\r\n // Ancestor\r\n if (pos & Node.DOCUMENT_POSITION_CONTAINS) {\r\n highPriority.push(\"ancestor\", \"ancestor-or-self\", \"parent\");\r\n }\r\n\r\n // Descendant direct\r\n if (pos & Node.DOCUMENT_POSITION_CONTAINED_BY) {\r\n highPriority.push(\"child\");\r\n }\r\n\r\n // Siblings\r\n if (element1.parentElement === element2.parentElement) {\r\n highPriority.push(\"following-sibling\", \"preceding-sibling\");\r\n }\r\n\r\n // Directional\r\n if (pos & Node.DOCUMENT_POSITION_FOLLOWING) {\r\n mediumPriority.push(\"following\");\r\n }\r\n\r\n if (pos & Node.DOCUMENT_POSITION_PRECEDING) {\r\n mediumPriority.push(\"preceding\");\r\n }\r\n\r\n // always include fallback\r\n lowPriority.push(\"descendant\", \"descendant-or-self\");\r\n\r\n const relations = [...highPriority, ...mediumPriority, ...lowPriority];\r\n\r\n return [...new Set(relations)];\r\n};\r\nconst referenceXpath = {\r\n findRelativeXpath,\r\n getDescendantXpath,\r\n getAncestorBridgeXpath,\r\n getXpathRelationExpression,\r\n getTraverseXpathExpression,\r\n getReferenceElementXpath,\r\n getSmartRelations\r\n};\r\nexport default referenceXpath;\r\n","import { SelectorMode } from \"../types/locator.ts\";\r\nimport { isNumberExist } from \"./xpathHelpers.ts\";\r\n\r\nlet modifiedElementAttributes: [] = [];\r\n\r\nconst escapeCssAttributeValue = (value: string): string => {\r\n return String(value).replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\r\n};\r\n\r\nconst isCssSelectorUnique = (\r\n selector: string,\r\n el: Element,\r\n root: Document | ShadowRoot | ParentNode\r\n): boolean => {\r\n try {\r\n const matches = root.querySelectorAll(selector);\r\n return matches.length === 1 && matches[0] === el;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n\r\nexport const parseCssSelectors = (\r\n el: Element,\r\n mode: SelectorMode = \"single\"\r\n) => {\r\n const selectors: { key: string; value: string }[] = [];\r\n const root = el.getRootNode() as Document | ShadowRoot;\r\n\r\n try {\r\n const idPath = getIdCssPath(el);\r\n if (idPath && isCssSelectorUnique(idPath, el, root)) {\r\n selectors.push({ key: \"cssSelector by id\", value: idPath });\r\n if (mode === \"single\") return selectors;\r\n }\r\n const classPath = getClassCssPath(el);\r\n if (classPath && isCssSelectorUnique(classPath, el, root)) {\r\n selectors.push({ key: \"cssSelector by class\", value: classPath });\r\n }\r\n const namePath = getAttributeCssPath(el);\r\n if (namePath) {\r\n selectors.push({ key: \"cssSelector by name\", value: namePath });\r\n }\r\n // commented out absolute path strategy as it is not performing well and causing performance issues in large DOMs\r\n // const absPath = getAbsoluteCssPath(el);\r\n // if (absPath && isCssSelectorUnique(absPath, el, root)) {\r\n // selectors.push({ key: 'Absolute cssSelector', value: absPath });\r\n // }\r\n } catch (e) {\r\n console.error(e);\r\n }\r\n return selectors;\r\n};\r\n\r\nexport const getIdCssPath = (el: HTMLElement | Element) => {\r\n const view = el.ownerDocument?.defaultView;\r\n if (!view || !(el instanceof view.Element)) return;\r\n const tagName = el.tagName.toLowerCase();\r\n if (tagName.includes(\"style\") || tagName.includes(\"script\")) return;\r\n\r\n const path = [];\r\n while (el?.nodeType === Node.ELEMENT_NODE) {\r\n let selector = el.nodeName?.toLowerCase();\r\n if (el.id && !isNumberExist(el.id)) {\r\n selector += `#${CSS.escape(el.id)}`;\r\n path.unshift(selector);\r\n break;\r\n } else {\r\n let sib = el;\r\n let nth = 1;\r\n if (sib.previousElementSibling) {\r\n while ((sib = sib.previousElementSibling)) {\r\n if (sib.nodeName?.toLowerCase() === selector) nth++;\r\n }\r\n }\r\n\r\n if (nth !== 1) {\r\n selector += `:nth-of-type(${nth})`;\r\n }\r\n\r\n if (nth === 1 && sib?.parentElement?.childElementCount! > 1) {\r\n selector += `:nth-child(${nth})`;\r\n }\r\n }\r\n path.unshift(selector);\r\n el = el.parentElement!;\r\n }\r\n return path.join(\" > \");\r\n};\r\n\r\nconst EXCLUDED_ATTRS = new Set([\"id\", \"class\", \"style\"]);\r\nfunction getAttributeSelectors(el: Element): string[] {\r\n return Array.from(el.attributes)\r\n .filter(\r\n (attr) =>\r\n !EXCLUDED_ATTRS.has(attr?.name?.toLowerCase()) &&\r\n attr.value &&\r\n !isNumberExist(attr.value)\r\n )\r\n .map((attr) => `[${attr.name}=\"${escapeCssAttributeValue(attr.value)}\"]`);\r\n}\r\n\r\nexport const getAttributeCssPath = (el: Element): string | undefined => {\r\n const view = el.ownerDocument?.defaultView;\r\n if (!view || !(el instanceof view.Element)) return;\r\n\r\n const root = el.getRootNode() as ParentNode;\r\n const tag = el.tagName.toLowerCase();\r\n\r\n if (tag === \"style\" || tag === \"script\") return;\r\n\r\n const attrSelectors = getAttributeSelectors(el);\r\n\r\n for (const attrSelector of attrSelectors) {\r\n const candidate = `${tag}${attrSelector}`;\r\n\r\n if (isCssSelectorUnique(candidate, el, root)) {\r\n return candidate;\r\n }\r\n }\r\n return;\r\n};\r\n\r\nexport const getClassCssPath = (el: HTMLElement | Element) => {\r\n const view = el.ownerDocument?.defaultView;\r\n if (!view || !(el instanceof view.Element)) return;\r\n const tagName = el.tagName.toLowerCase();\r\n if (tagName.includes(\"style\") || tagName.includes(\"script\")) return;\r\n\r\n const path = [];\r\n while (el?.nodeType === Node.ELEMENT_NODE) {\r\n let selector = el.nodeName?.toLowerCase();\r\n\r\n if (\r\n typeof el.className === \"string\" &&\r\n el.className &&\r\n !isNumberExist(el.className) &&\r\n !modifiedElementAttributes?.find(\r\n (x: { element: HTMLElement | Element; attributeName: string }) =>\r\n x.element === el && x.attributeName === \"class\"\r\n )\r\n ) {\r\n el.classList.remove(\"marked-element-temp\");\r\n el.classList.remove(\"removePointers\");\r\n if (el.className) {\r\n selector += `.${el.className.trim().replace(/\\s+/g, \".\")}`;\r\n path.unshift(selector);\r\n break;\r\n }\r\n } else {\r\n let sib = el;\r\n let nth = 1;\r\n if (sib.previousElementSibling) {\r\n while ((sib = sib.previousElementSibling)) {\r\n if (sib.nodeName?.toLowerCase() === selector) nth++;\r\n }\r\n }\r\n\r\n if (nth !== 1) {\r\n selector += `:nth-of-type(${nth})`;\r\n }\r\n\r\n if (nth === 1 && sib?.parentElement?.childElementCount! > 1) {\r\n selector += `:nth-child(${nth})`;\r\n }\r\n }\r\n path.unshift(selector);\r\n el = el.parentElement!;\r\n }\r\n return path.join(\" > \");\r\n};\r\n\r\nexport const getAbsoluteCssPath = (el: Element) => {\r\n const view = el.ownerDocument?.defaultView;\r\n if (!view || !(el instanceof view.Element)) return;\r\n\r\n const path: string[] = [];\r\n\r\n while (el && el.nodeType === Node.ELEMENT_NODE) {\r\n const tagName = el.tagName.toLowerCase();\r\n\r\n if (tagName === \"style\" || tagName === \"script\") return;\r\n\r\n let selector = tagName;\r\n\r\n const parent = el.parentNode;\r\n\r\n if (parent) {\r\n const siblings = Array.from(parent.children).filter(\r\n (c) => c.tagName === el.tagName\r\n );\r\n\r\n if (siblings.length > 1) {\r\n selector += `:nth-of-type(${siblings.indexOf(el) + 1})`;\r\n }\r\n }\r\n\r\n path.unshift(selector);\r\n\r\n el = el.parentElement!;\r\n }\r\n\r\n return path.join(\" > \");\r\n};\r\n\r\nexport const cssSelectors = {\r\n parseCssSelectors,\r\n getIdCssPath,\r\n getAttributeCssPath,\r\n getClassCssPath,\r\n getAbsoluteCssPath\r\n};\r\n","import { ElementRecord, Locator } from \"../types/locator.ts\";\r\nimport { parseDOM } from \"./xpath.ts\";\r\nimport { parseCssSelectors } from \"./cssSelector.ts\";\r\nimport {\r\n isNumberExist,\r\n normalizeXPath,\r\n getXPathPattern,\r\n escapeAttrValue,\r\n isUniqueInDOM,\r\n shouldUseSnapshot\r\n} from \"./xpathHelpers.ts\";\r\n\r\nconst isSameXPathStillValid = (\r\n xpath: string,\r\n docmt: Document,\r\n target: Element\r\n): boolean => {\r\n const normalized = normalizeXPath(xpath);\r\n const found = getElementFromXPath(docmt, normalized);\r\n if (found === target) return true;\r\n\r\n if (shouldUseSnapshot(normalized)) {\r\n const result = docmt.evaluate(\r\n normalized,\r\n docmt,\r\n null,\r\n XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,\r\n null\r\n );\r\n\r\n for (let i = 0; i < result.snapshotLength; i++) {\r\n if (result.snapshotItem(i) === target) return true;\r\n }\r\n }\r\n\r\n return false;\r\n};\r\n\r\nconst getElementFromCssSelector = (\r\n docmt: Document,\r\n selector: string\r\n): Element | null => {\r\n try {\r\n const found = docmt.querySelector(selector);\r\n if (found) return found;\r\n } catch (error) {\r\n console.error(\"Invalid CSS selector:\", selector, error);\r\n return null;\r\n }\r\n\r\n return getElementFromShadowRoot(docmt.body, selector);\r\n};\r\n\r\nconst isSameCssSelectorStillValid = (\r\n selector: string,\r\n docmt: Document,\r\n target: Element\r\n): boolean => {\r\n return getElementFromCssSelector(docmt, selector) === target;\r\n};\r\n\r\nconst resolveIsSelfHealed = (\r\n locName: string,\r\n oldValue: string | null | undefined,\r\n newValue: string | null | undefined\r\n): \"Y\" | null => {\r\n if (!oldValue || !newValue) return \"Y\";\r\n return oldValue === newValue ? null : \"Y\";\r\n};\r\n\r\nconst isCssSelectorLocator = (locator: { name?: string | null }): boolean => {\r\n return locator.name?.toLowerCase().includes(\"cssselector\") ?? false;\r\n};\r\n\r\ntype ElementDetails = {\r\n id?: string | null;\r\n className?: string | null;\r\n xpathByText?: string | null;\r\n xpathById?: string | null;\r\n xpathByClass?: string | null;\r\n xpathAbsolute?: string | null;\r\n xpathByName?: string | null;\r\n xpathByPlaceholder?: string | null;\r\n xpathByType?: string | null;\r\n visibleText?: string | null;\r\n relativeXpath?: string | null;\r\n [key: string]: any;\r\n};\r\n\r\nconst getElementFromShadowRoot = (\r\n el: Element | ShadowRoot,\r\n selector: string\r\n): Element | null => {\r\n // const shadowRoot = (element as HTMLElement).shadowRoot;\r\n // if (shadowRoot && !selector.includes(\"dynamic\")) {\r\n // return shadowRoot.querySelector(selector);\r\n // }\r\n\r\n const elements = Array.from(el.querySelectorAll(\"*\"));\r\n\r\n try {\r\n for (let i = 0; i < elements.length; i++) {\r\n if (elements[i].shadowRoot) {\r\n const { shadowRoot } = elements[i];\r\n if (shadowRoot) {\r\n const nestedElement = getElementFromShadowRoot(shadowRoot, selector);\r\n if (nestedElement) {\r\n return nestedElement;\r\n }\r\n if (shadowRoot && !selector.includes(\"dynamic\")) {\r\n return shadowRoot.querySelector(selector);\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n return null;\r\n};\r\n\r\nconst getId = (element: Element | null): string | null => {\r\n return element?.id || null;\r\n};\r\n\r\nconst getClassName = (element: Element): string | null => {\r\n return (element as HTMLElement).className || null;\r\n};\r\n\r\nconst getVisibleText = (element: Element): string | null => {\r\n return element.textContent?.trim() || null;\r\n};\r\n\r\nconst getName = (element: Element): string | null => {\r\n const elementEl = element as HTMLElement;\r\n\r\n if (elementEl.hasAttribute(\"name\")) {\r\n const attrValue = elementEl.getAttribute(\"name\");\r\n const name = `${attrValue}`;\r\n return name || null;\r\n }\r\n return null;\r\n};\r\n\r\nconst relations: string[] = [\r\n \"/preceding-sibling\",\r\n \"/following-sibling\",\r\n \"/parent\",\r\n \"/descendant\",\r\n \"/ancestor\",\r\n \"/self\",\r\n \"/ancestor-or-self\",\r\n \"/child\",\r\n \"/preceding\",\r\n \"/following\"\r\n];\r\n\r\nfunction getElementFromXPath(docmt: Document, xpath: string): Element | null {\r\n const window = docmt.defaultView;\r\n if (!window) return null;\r\n\r\n const xpathEvaluator = new window.XPathEvaluator();\r\n const xpathResult = xpathEvaluator.evaluate(\r\n xpath,\r\n docmt,\r\n null,\r\n window.XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n return xpathResult.singleNodeValue as Element | null;\r\n}\r\n\r\nfunction checkReferenceElementIsValid(\r\n locator: string,\r\n relation: string,\r\n docmt: Document\r\n): string | null {\r\n if (locator.includes(relation)) {\r\n const locatotSplitArray: string[] = locator.split(relation);\r\n const sourceLoc = locatotSplitArray[0].trim();\r\n const window = docmt.defaultView;\r\n if (!window) return null;\r\n if (!locator.includes(\"dynamic\")) {\r\n const xpathEvaluator = new window.XPathEvaluator();\r\n const xpathResult = xpathEvaluator.evaluate(\r\n sourceLoc,\r\n docmt,\r\n null,\r\n window.XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n\r\n const sourceElement = xpathResult.singleNodeValue;\r\n if (sourceElement) {\r\n const xpathResultComplete = xpathEvaluator.evaluate(\r\n locator,\r\n docmt,\r\n null,\r\n window.XPathResult.FIRST_ORDERED_NODE_TYPE,\r\n null\r\n );\r\n const completeElement = xpathResultComplete.singleNodeValue;\r\n let relativeXpath: string;\r\n if (completeElement) {\r\n relativeXpath = locator;\r\n return relativeXpath;\r\n } else {\r\n console.error(\"Complete Locator is Invalid:\", locator);\r\n relativeXpath = locator;\r\n return relativeXpath;\r\n }\r\n } else {\r\n console.error(\"Source Locator Not Found:\", sourceLoc);\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nconst getElementsFromHTML = (\r\n record: ElementRecord,\r\n docmt: Document\r\n): ElementDetails | null => {\r\n const elementsToRemove = docmt.querySelectorAll(\r\n \"script, style, link[rel='stylesheet'], meta, noscript, embed, object, param, source, svg\"\r\n );\r\n\r\n if (elementsToRemove) {\r\n elementsToRemove.forEach((tag) => {\r\n (tag as Element).remove();\r\n });\r\n }\r\n\r\n const finalLocatorsSet: Set<string> = new Set();\r\n let finalLocators: any[] = [];\r\n\r\n function createLocator(base: any, overrides: Partial<any> = {}) {\r\n const oldValue = base?.value;\r\n const newValue = overrides.value ?? base?.value;\r\n const newLocator: any = {\r\n name: overrides.name ?? base?.name,\r\n type: overrides.type ?? base?.type,\r\n value: overrides.value ?? base?.value,\r\n reference: overrides.reference ?? base?.reference,\r\n status: overrides.status ?? base?.status,\r\n isRecorded: overrides.isRecorded ?? base?.isRecorded\r\n };\r\n\r\n const previousSelfHealed = base?.isSelfHealed === \"Y\";\r\n\r\n newLocator.isSelfHealed = previousSelfHealed\r\n ? \"Y\"\r\n : overrides.hasOwnProperty(\"isSelfHealed\")\r\n ? overrides.isSelfHealed\r\n : resolveIsSelfHealed(newLocator.name, oldValue, newValue);\r\n\r\n pushUniqueLocator(newLocator);\r\n }\r\n\r\n function resolveElement(\r\n ctx: Document,\r\n locator: any,\r\n selector: string\r\n ): Element | null {\r\n if (isCssSelectorLocator(locator)) {\r\n return getElementFromCssSelector(ctx, selector);\r\n } else if (locator.name.includes(\"id\") || selector.startsWith(\"#\")) {\r\n return ctx.querySelector(\"#\" + escapeAttrValue(selector));\r\n } else if (locator.name.includes(\"className\") || selector.startsWith(\".\")) {\r\n return ctx.querySelector(\".\" + selector);\r\n } else if (locator.name === \"name\") {\r\n const safeName = escapeAttrValue(selector);\r\n return ctx.querySelector(`[name=\"${safeName}\"]`);\r\n } else if (locator.name === \"tagName\") {\r\n return ctx.querySelector(selector);\r\n } else if (locator.name === \"linkText\") {\r\n return (\r\n Array.from(ctx.querySelectorAll(\"a\")).find(\r\n (a) => a.textContent?.trim() === selector\r\n ) || null\r\n );\r\n } else if (locator.name === \"partialLinkText\") {\r\n return (\r\n Array.from(ctx.querySelectorAll(\"a\")).find((a) =>\r\n a.textContent?.includes(selector)\r\n ) || null\r\n );\r\n } else if (\r\n (locator.name.includes(\"xpath\") || selector.startsWith(\"//\")) &&\r\n !locator.type.match(\"dynamic\")\r\n ) {\r\n const normalizedXPath = normalizeXPath(selector);\r\n const el = getElementFromXPath(ctx, normalizedXPath);\r\n\r\n if (el) {\r\n createLocator(locator, {\r\n value: selector,\r\n isRecorded: String(locator.isRecorded).includes(\"N\") ? \"N\" : \"Y\"\r\n });\r\n }\r\n\r\n return el;\r\n } else {\r\n return ctx.querySelector(selector);\r\n }\r\n }\r\n\r\n function findInIframes(\r\n docmt: Document,\r\n locator: any,\r\n selector: string\r\n ): Element | null {\r\n const iframes = docmt.querySelectorAll(\"iframe\");\r\n\r\n for (const iframe of iframes) {\r\n try {\r\n const iframeDoc =\r\n iframe.contentDocument || iframe.contentWindow?.document;\r\n\r\n if (!iframeDoc) continue;\r\n\r\n const el = resolveElement(iframeDoc, locator, selector);\r\n if (el) return el;\r\n } catch {\r\n continue;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n function pushUniqueLocator(obj: any) {\r\n const key = `${obj.name}:${obj.value}`;\r\n if (!finalLocatorsSet.has(key)) {\r\n finalLocatorsSet.add(key);\r\n finalLocators.push(obj);\r\n }\r\n }\r\n\r\n /** Locator Value Cleaner (Handles Special Scenarios) **/\r\n const cleanLocatorValue = (\r\n val: string | null | undefined,\r\n type?: string,\r\n isRecorded?: string\r\n ): string | null => {\r\n if (!val) return null;\r\n\r\n let cleaned = val.trim();\r\n\r\n // Return null for empty or literal \"null\"\r\n if (!cleaned || cleaned.toLowerCase() === \"null\") return null;\r\n\r\n // Unescape any escaped quotes\r\n cleaned = cleaned.replace(/\\\\\"/g, '\"').replace(/\\\\'/g, \"'\");\r\n\r\n // Remove surrounding single or double quotes\r\n cleaned = cleaned.replace(/^['\"](.+?)['\"]$/, \"$1\");\r\n\r\n // Replace double single quotes with a single quote inside XPath\r\n cleaned = cleaned.replace(/''/g, \"'\");\r\n\r\n // Normalize double quotes in XPath attribute selectors [@id=\"\" -> [@id='']\r\n cleaned = cleaned.replace(\r\n /\\[@(id|name)=['\"]{2}(.+?)['\"]{2}\\]/g,\r\n \"[@$1='$2']\"\r\n );\r\n\r\n // For DOM selectors (id or name), remove ALL quotes\r\n if (type === \"id\" || type === \"name\") {\r\n cleaned = cleaned.replace(/['\"]/g, \"\").trim();\r\n }\r\n\r\n if (type === \"xpath\" && isRecorded === \"Y\" && !val.startsWith(\"//\"))\r\n return null;\r\n\r\n // Final check for empty strings\r\n if (!cleaned || /^['\"]{2}$/.test(cleaned)) return null;\r\n\r\n return cleaned;\r\n };\r\n\r\n locators: for (const locator of record.locators) {\r\n try {\r\n const isRecorded = String(locator.isRecorded || \"\");\r\n const recordedNLocators = record.locators.filter(\r\n (l) => l.isRecorded === \"N\"\r\n );\r\n\r\n if (recordedNLocators.length > 0) {\r\n for (const locator of recordedNLocators) {\r\n createLocator(locator);\r\n }\r\n }\r\n\r\n const isDynamic = String(locator.value || locator.type || \"\");\r\n if (\r\n isDynamic.includes(\"dynamic\") ||\r\n isDynamic.match(\"dynamic\") ||\r\n isDynamic.includes(\"{\") ||\r\n isDynamic.includes(\"}\")\r\n ) {\r\n createLocator(locator);\r\n continue;\r\n }\r\n\r\n if (record.isShared.includes(\"Y\")) {\r\n break locators;\r\n }\r\n\r\n try {\r\n let targetElement: Element | null = null;\r\n const selectors = locator.value.split(\">>>\");\r\n\r\n for (const selector of selectors) {\r\n if (!docmt) {\r\n console.error(\"Element not found at:\", selector);\r\n break;\r\n }\r\n\r\n const trimmedSelector = selector.trim();\r\n\r\n //normal DOM\r\n targetElement = resolveElement(docmt, locator, trimmedSelector);\r\n\r\n //iframe (if not found)\r\n if (!targetElement) {\r\n targetElement = findInIframes(docmt, locator, trimmedSelector);\r\n }\r\n\r\n //shadow DOM (if still not found)\r\n if (!targetElement) {\r\n targetElement = getElementFromShadowRoot(\r\n docmt.body,\r\n trimmedSelector\r\n );\r\n }\r\n\r\n if (!targetElement) {\r\n console.error(\"Element not found at:\", trimmedSelector);\r\n break;\r\n }\r\n }\r\n\r\n const locatorExists = (name: string, value: string): boolean => {\r\n const key = `${name}:${value}`;\r\n return finalLocatorsSet.has(key);\r\n };\r\n\r\n if (targetElement) {\r\n const payloadXPaths = record.locators.filter(\r\n (l) => l.name === \"xpath\" && l.value\r\n );\r\n const payloadCssSelectors = record.locators.filter(\r\n (l) => isCssSelectorLocator(l) && l.value\r\n );\r\n\r\n for (const px of payloadXPaths) {\r\n if (isSameXPathStillValid(px.value, docmt, targetElement))\r\n createLocator(px, {\r\n isSelfHealed: null\r\n });\r\n }\r\n\r\n for (const cssLocator of payloadCssSelectors) {\r\n if (\r\n isSameCssSelectorStillValid(\r\n cssLocator.value,\r\n docmt,\r\n targetElement\r\n )\r\n )\r\n createLocator(cssLocator, {\r\n isSelfHealed: null\r\n });\r\n }\r\n\r\n const existingXPaths = finalLocators.filter(\r\n (l) => l.name === \"xpath\" && l.value\r\n );\r\n\r\n // Track XPath patterns already used\r\n const usedXPathPatterns = new Set<string>(\r\n existingXPaths.map((x) => getXPathPattern(x.value))\r\n );\r\n\r\n const excludedAttributes: string[] = [];\r\n const idValue = getId(targetElement);\r\n if (\r\n idValue &&\r\n !locatorExists(\"id\", idValue) &&\r\n !isNumberExist(idValue)\r\n ) {\r\n const prevId = record.locators.find((l) => l.name === \"id\");\r\n if (isUniqueInDOM(docmt, \"id\", idValue, targetElement)) {\r\n excludedAttributes.push(\"id\");\r\n createLocator(prevId, {\r\n name: \"id\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: idValue\r\n });\r\n }\r\n }\r\n\r\n const tagName = targetElement.tagName;\r\n if (tagName && !locatorExists(\"tagName\", tagName)) {\r\n const prevTag = record.locators.find((l) => l.name === \"tagName\");\r\n if (isUniqueInDOM(docmt, \"tagName\", tagName, targetElement)) {\r\n excludedAttributes.push(\"tagName\");\r\n createLocator(prevTag, {\r\n name: \"tagName\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: tagName\r\n });\r\n }\r\n }\r\n\r\n const textValue = getVisibleText(targetElement);\r\n if (textValue && !isNumberExist(textValue)) {\r\n const prevLinkText = record.locators.find(\r\n (l) => l.name === \"linkText\"\r\n );\r\n if (isUniqueInDOM(docmt, \"linkText\", textValue, targetElement)) {\r\n excludedAttributes.push(\"linkText\");\r\n createLocator(prevLinkText, {\r\n name: \"linkText\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: textValue\r\n });\r\n }\r\n }\r\n\r\n const nameLocator = getName(targetElement);\r\n if (\r\n nameLocator &&\r\n !locatorExists(\"name\", nameLocator) &&\r\n !isNumberExist(nameLocator)\r\n ) {\r\n const prevName = record.locators.find((l) => l.name === \"name\");\r\n if (isUniqueInDOM(docmt, \"name\", nameLocator, targetElement)) {\r\n excludedAttributes.push(\"name\");\r\n createLocator(prevName, {\r\n name: \"name\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: nameLocator\r\n });\r\n }\r\n }\r\n\r\n const classValue = getClassName(targetElement);\r\n if (\r\n classValue &&\r\n classValue.trim() !== \"\" &&\r\n !classValue.includes(\" \") &&\r\n !locatorExists(\"className\", classValue) &&\r\n !isNumberExist(classValue)\r\n ) {\r\n const prevClassLocator = record.locators.find(\r\n (l) => l.name === \"className\"\r\n );\r\n if (isUniqueInDOM(docmt, \"className\", classValue, targetElement)) {\r\n excludedAttributes.push(\"className\");\r\n createLocator(prevClassLocator, {\r\n name: \"className\",\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n value: classValue\r\n });\r\n }\r\n }\r\n parseCssSelectors(targetElement, \"single\").forEach(\r\n (cssSelector) => {\r\n if (\r\n cssSelector.value &&\r\n !locatorExists(\"cssSelector\", cssSelector.value)\r\n ) {\r\n createLocator(undefined, {\r\n name: \"cssSelector\",\r\n value: cssSelector.value,\r\n type: \"static\",\r\n isRecorded: \"Y\"\r\n });\r\n }\r\n }\r\n );\r\n const allAttributes = Array.from(targetElement.attributes);\r\n const includedAttributes = allAttributes.filter(\r\n (attr) => !excludedAttributes.includes(attr.name)\r\n );\r\n\r\n //If any direct locator is broken then we consider it as broken xpath\r\n\r\n let xpathResults: any[] = [];\r\n try {\r\n xpathResults =\r\n parseDOM(targetElement, docmt, false, true, includedAttributes) ??\r\n [];\r\n } catch (error) {\r\n console.error(\"Error generating XPath candidates:\", error);\r\n }\r\n\r\n if (xpathResults?.length !== 0) {\r\n const brokenPayloadXPaths = payloadXPaths.filter(\r\n (px) => !isSameXPathStillValid(px.value, docmt, targetElement)\r\n );\r\n\r\n let xpathAdded = 0;\r\n\r\n for (const brokenPx of brokenPayloadXPaths) {\r\n if (xpathAdded >= brokenPayloadXPaths.length) break;\r\n\r\n const originalPattern = getXPathPattern(brokenPx.value);\r\n if (usedXPathPatterns.has(originalPattern)) continue;\r\n\r\n const match = xpathResults.find(\r\n (r) => r.value && getXPathPattern(r.value) === originalPattern\r\n );\r\n\r\n if (match?.value) {\r\n createLocator(brokenPx, {\r\n name: \"xpath\",\r\n value: match.value,\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n isSelfHealed: \"Y\"\r\n });\r\n\r\n usedXPathPatterns.add(originalPattern);\r\n xpathAdded++;\r\n }\r\n }\r\n if (xpathAdded < brokenPayloadXPaths.length) {\r\n for (const result of xpathResults) {\r\n if (xpathAdded >= brokenPayloadXPaths.length) break;\r\n if (!result.value) continue;\r\n\r\n const pattern = getXPathPattern(result.value);\r\n if (usedXPathPatterns.has(pattern)) continue;\r\n\r\n createLocator(result, {\r\n name: \"xpath\",\r\n value: result.value,\r\n type: \"static\",\r\n isRecorded: \"Y\",\r\n isSelfHealed: \"Y\"\r\n });\r\n\r\n usedXPathPatterns.add(pattern);\r\n xpathAdded++;\r\n }\r\n }\r\n }\r\n for (const locator of record.locators) {\r\n try {\r\n for (const loc of record.locators) {\r\n if (!loc.value) continue;\r\n\r\n for (const relation of relations) {\r\n if (loc.value.includes(relation)) {\r\n const relativeXpath = checkReferenceElementIsValid(\r\n loc.value,\r\n relation,\r\n docmt\r\n );\r\n if (relativeXpath) {\r\n createLocator(loc, {\r\n name: \"xpath\",\r\n value: relativeXpath,\r\n isRecorded:\r\n locator.isRecorded !== \"\" &&\r\n locator.isRecorded !== null\r\n ? locator.isRecorded\r\n : \"Y\"\r\n });\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.error(\"Error processing locator:\", locator, error);\r\n }\r\n }\r\n if (finalLocators.length < 5) {\r\n const fallbackCandidates = [\r\n { name: \"id\", value: getId(targetElement) },\r\n { name: \"name\", value: getName(targetElement) },\r\n { name: \"className\", value: getClassName(targetElement) },\r\n { name: \"tagName\", value: targetElement.tagName },\r\n { name: \"linkText\", value: getVisibleText(targetElement) }\r\n ];\r\n\r\n for (const candidate of fallbackCandidates) {\r\n if (finalLocators.length > 4) break;\r\n\r\n const { name, value } = candidate;\r\n if (!value) continue;\r\n if (isNumberExist(value)) continue;\r\n if (locatorExists(name, value)) continue;\r\n if (name === \"className\" && value.includes(\" \")) continue;\r\n if (isUniqueInDOM(docmt, name, value, targetElement)) {\r\n createLocator(undefined, {\r\n name,\r\n type: \"static\",\r\n value,\r\n isRecorded: \"Y\",\r\n isSelfHealed: \"Y\"\r\n });\r\n }\r\n }\r\n\r\n if (finalLocators.length < 5) {\r\n parseCssSelectors(targetElement, \"multiple\").forEach(\r\n (cssSelector) => {\r\n if (finalLocators.length > 4) return;\r\n if (!cssSelector.value) return;\r\n if (locatorExists(\"cssSelector\", cssSelector.value)) return;\r\n if (\r\n !isUniqueInDOM(\r\n docmt,\r\n \"cssSelector\",\r\n cssSelector.value,\r\n targetElement\r\n )\r\n ) {\r\n return;\r\n }\r\n\r\n createLocator(undefined, {\r\n name: \"cssSelector\",\r\n type: \"static\",\r\n value: cssSelector.value,\r\n isRecorded: \"Y\",\r\n isSelfHealed: \"Y\"\r\n });\r\n }\r\n );\r\n }\r\n }\r\n\r\n const finalAutoHealedLocators = finalLocators.map((obj) => ({\r\n ...obj,\r\n value: cleanLocatorValue(obj.value, obj.name, obj.isRecorded)\r\n }));\r\n\r\n const jsonResult = [\r\n {\r\n name: `${record.name}`,\r\n desc: `${record.desc}`,\r\n type: `${record.type}`,\r\n locators: finalAutoHealedLocators.filter(\r\n (locator) => locator?.value != null && locator.value !== \"\"\r\n ),\r\n isShared: `${record.isShared}`,\r\n projectId: `${record.projectId}`,\r\n projectType: `${record.projectType}`,\r\n isRecorded: `${record.isRecorded}`,\r\n folder: `${record.folder}`,\r\n parentId: `${record.parentId}`,\r\n parentName: `${record.parentName}`,\r\n platform: `${record.platform}`,\r\n licenseId: `${record.licenseId}`,\r\n licenseType: `${record.licenseType}`,\r\n userId: `${record.userId}`\r\n }\r\n ];\r\n\r\n return jsonResult;\r\n }\r\n } catch (error) {\r\n console.error(\"Error processing locator:\", locator, error);\r\n continue;\r\n }\r\n } catch (error) {\r\n console.error(\"Error processing locator:\", locator, error);\r\n continue;\r\n }\r\n }\r\n return null;\r\n};\r\n\r\nexport { getElementsFromHTML };\r\n","import { isNumberExist, getCountOfXPath } from \"./xpathHelpers\";\r\nfunction getOptimalClassChain(\r\n doc: Document,\r\n domNode: HTMLElement | Element | null,\r\n uniqueAttributes: Attr[]\r\n): string | null {\r\n\r\n try {\r\n\r\n if (\r\n !domNode ||\r\n domNode.nodeType !== 1 ||\r\n !domNode.tagName ||\r\n domNode.tagName === \"XCUIElementTypeApplication\"\r\n ) {\r\n return \"\";\r\n }\r\n\r\n const tag = domNode.tagName;\r\n\r\n // Priority attributes\r\n const priorityAttrs = [\"name\", \"label\", \"value\"];\r\n\r\n // ---------- STEP 1 : TRY GOOD ATTRIBUTES ----------\r\n for (const attrName of priorityAttrs) {\r\n\r\n const attr = uniqueAttributes.find(a => a.name === attrName);\r\n if (!attr) continue;\r\n\r\n let attrValue = attr.value;\r\n if (!attrValue) continue;\r\n\r\n attrValue = attrValue.trim().replace(/\\s+/g, \" \");\r\n\r\n if (isNumberExist(attrValue)) continue;\r\n\r\n const xpath = `//${tag}[@${attrName}=\"${attrValue}\"]`;\r\n\r\n let count = 0;\r\n\r\n try {\r\n count = getCountOfXPath(xpath, domNode, doc);\r\n } catch (err) {\r\n console.log(err);\r\n continue;\r\n }\r\n\r\n const hasSpace = /\\s/.test(attrValue);\r\n\r\n if (count === 1) {\r\n\r\n if (hasSpace) {\r\n return `/${tag}[\\`${attrName} CONTAINS \"${attrValue}\"\\`]`;\r\n }\r\n\r\n return `/${tag}[\\`${attrName} == \"${attrValue}\"\\`]`;\r\n }\r\n\r\n if (count > 1 && domNode.parentElement) {\r\n\r\n const siblings = Array.from(domNode.parentElement.children)\r\n .filter(el => el.tagName === tag);\r\n\r\n const index = siblings.indexOf(domNode) + 1;\r\n\r\n if (hasSpace) {\r\n return `/${tag}[\\`${attrName} CONTAINS \"${attrValue}\"\\`][${index}]`;\r\n }\r\n\r\n return `/${tag}[\\`${attrName} == \"${attrValue}\"\\`][${index}]`;\r\n }\r\n }\r\n\r\n // ---------- STEP 2 : FALLBACK USING TAG INDEX ----------\r\n let classChain = `/${tag}`;\r\n\r\n if (domNode.parentElement) {\r\n\r\n const siblings = Array.from(domNode.parentElement.children)\r\n .filter(el => el.tagName === tag);\r\n\r\n if (siblings.length > 1) {\r\n\r\n const index = siblings.indexOf(domNode) + 1;\r\n\r\n classChain += `[${index}]`;\r\n }\r\n }\r\n\r\n const parentChain = getOptimalClassChain(\r\n doc,\r\n domNode.parentElement,\r\n uniqueAttributes\r\n );\r\n\r\n return parentChain + classChain;\r\n\r\n } catch (error) {\r\n\r\n console.log(\r\n `Unable to generate optimal -ios class chain : ${JSON.stringify(error)}`\r\n );\r\n\r\n return null;\r\n }\r\n}\r\nfunction getOptimalPredicateString(\r\n doc: Document,\r\n domNode: HTMLElement | Element | null,\r\n uniqueAttributes: Attr[]\r\n) {\r\n try {\r\n // BASE CASE #1: If this isn't an element, we're above the root, or this is `XCUIElementTypeApplication`,\r\n // which is not an official XCUITest element, return empty string\r\n if (\r\n !domNode?.tagName ||\r\n domNode?.nodeType !== 1 ||\r\n domNode?.tagName === 'XCUIElementTypeApplication'\r\n ) {\r\n return '';\r\n }\r\n\r\n // BASE CASE #2: Check all attributes and try to find the best way\r\n let xpathAttributes: string[] = [];\r\n let predicateString: string[] = [];\r\n\r\n for (let attr of uniqueAttributes) {\r\n const attrValue = attr.value;\r\n const attrName = attr.name;\r\n\r\n if (attrValue.length === 0) {\r\n continue;\r\n }\r\n if (attrValue && !isNumberExist(attrValue)) {\r\n xpathAttributes.push(`@${attrName}=\"${attrValue}\"`);\r\n const xpathe = `//*[${xpathAttributes.join(' and ')}]`;\r\n predicateString.push(`${attrName} == \"${attrValue}\"`);\r\n let othersWithAttr;\r\n\r\n // If the XPath does not parse, move to the next unique attribute\r\n try {\r\n othersWithAttr = getCountOfXPath(\r\n xpathe,\r\n domNode,\r\n doc\r\n );\r\n } catch (ign) {\r\n console.log(ign);\r\n continue;\r\n }\r\n\r\n // If the attribute isn't actually unique, get it's index too\r\n if (othersWithAttr === 1) {\r\n return predicateString.join(' AND ');\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n // If there's an unexpected exception, abort and don't get an XPath\r\n console.log(\r\n `The most optimal '-ios predicate string' could not be determined because an error was thrown: '${JSON.stringify(\r\n error,\r\n null,\r\n 2\r\n )}'`\r\n );\r\n }\r\n return null;\r\n}\r\n\r\nexport const iosSelectors = {\r\n getOptimalClassChain,\r\n getOptimalPredicateString\r\n};","import xpath from '../utils/xpath.ts';\r\nimport referenceXpaths from '../utils/referenceXpath.ts';\r\nimport { xpathUtils } from '../utils/xpathHelpers.ts';\r\nimport { getElementsFromHTML } from '../utils/getElementsFromHTML.ts';\r\nimport { cssSelectors } from '../utils/cssSelector.ts';\r\nimport { iosSelectors } from '../utils/iosSelector.ts';\r\n\r\nexport const createXPathAPI = () => ({\r\n xpath,\r\n referenceXpaths,\r\n xpathUtils,\r\n getElementsFromHTML,\r\n cssSelectors,\r\n iosSelectors\r\n});\r\n\r\nexport default createXPathAPI;"],"names":["reWhiteSpace","xpathEvalCache","WeakMap","clearXPathEvalCache","node","contexts","addContext","candidate","includes","push","rootNode","getRootNode","Document","ShadowRoot","nodeType","Node","DOCUMENT_NODE","ownerDocument","getMutationCacheContexts","forEach","contextNode","delete","evaluateXPathOnce","xpath","docmt","owner","document","getXPathContext","nodeCache","get","Map","set","cached","result","evaluate","XPathResult","ORDERED_NODE_ITERATOR_TYPE","evalResult","first","iterateNext","second","mutationObserver","relativeXPathCache","modifiedElementAttributes","INTERNAL_CLASS_TOKENS","Set","normalizeClassTokens","classValue","split","map","token","trim","filter","has","sort","hasNumericAttributeValue","value","test","getClassTokenConditions","element","allowNumericToken","allClassTokens","classTokens","length","escapeCharacters","buildPattern","isSvg","tagName","toLowerCase","count","getTagOnlyXpathCandidateCount","left","right","TEST_ID_ATTRIBUTE_NAMES","sanitizeAttributeValue","attributeName","attributeValue","join","replace","isInternalClassOnlyMutation","mutation","type","target","Element","oldValue","classList","previousTokens","currentTokens","getAttribute","isNumberExist","str","pattern","getTextContent","targetElement","textContent","getFilteredText","childNodes","nodeValue","getCountOfXPath","multiElementReferenceMode","isShadowRootNode","cloneElement","cloneElements","createShadowEvaluationContext","Array","isArray","matchCount","error","console","text","indexOf","removeParenthesis","charArr","indexArray","reverse","finalStr","i","endBracketLength","firstpart","slice","startsWith","endsWith","findXpathWithIndex","val","index","nodes","ANY_TYPE","nodex","isSameNode","log","deleteGarbageFromInnerText","a","deleteLineGap","reduce","b","c","replaceWhiteSpaces","getContainerTextCondition","normalizedText","children","fragment","getStableTargetTextCandidates","prefix","part","getStableTargetText","getShadowRoot","el","root","host","DOCUMENT_FRAGMENT_NODE","tempDoc","implementation","createHTMLDocument","wrapper","createElement","innerHTML","body","appendChild","cloneForElement","defaultView","path","current","parentElement","parent","unshift","from","parentNode","getElementPathFromRoot","container","next","item","getElementAtPath","Boolean","checkBlockedAttributes","attribute","isTarget","sanitizedValue","name","some","x","isModified","find","doc","hasGeneratedNumericSegment","SVGElement","replaceTempAttributes","getPropertyXPath","prop","isIndex","combinePattern","mergePattern","isAttributeProp","isTextProp","normalizedTextProp","hasTextSpacing","stableTargetText","textValueForPredicate","containerTextCondition","classCondition","splitText","contentRes","match","endIndex","startIndexString","endIndexString","getAbsoluteXPath","domNode","xpathe","prototype","call","childNode","HTMLElement","offsetParent","getRelativeXPath","attributesArray","xpathParts","currentNode","hasUniqueAttr","attributes","attrName","attrValue","elementName","xpathCandidate","getXpathStrings","othersWithAttr","RegExp","filteredText","tagBasedXPath","siblings","finalXPath","getCombinationXpath","classConditions","getAttributeCombinationXpath","uniqueAttributes","candidateAttributes","attr","buildAttributeConditions","buildAttributeConditionAlternatives","conditions","condition","buildConditionGroups","groups","alternatives","flatMap","group","alternative","getTextConditions","rawText","add","generateAttributeCombinations","combinationSize","results","build","startIndex","currentGroup","pop","buildXPath","tryAttributeOnlyCombinations","attributeGroups","attributeGroup","conditionGroups","xpathConditions","attributeOnlyXpath","textConditions","attributeConditions","textCondition","JSON","stringify","intermediateXpathStep","targetElemt","intermediateXpathSteps","isSvgElement","expression","getFilteredTextXPath","textForPredicate","getNormalizedPropertyXPath","getStartsWithPropertyXPath","stableText","getContainsPropertyXPath","getOrAttributesXPath","buildTextCondition","_error","getAncestorAnchorCandidates","anchors","seen","priorityAttrs","orderedAttributes","pushAnchor","isExactUniqueXpath","textXpath","combinationXpath","getStructuralPathFromAncestor","ancestor","steps","getAxisNodeTest","getTagOnlyXPath","fallbackXpath","ancestorAnchors","ancestorXpath","descendantXpath","getFirstMatchedNode","structuralPath","parentChainXpath","parentChainCount","fallbackCount","FIRST_ORDERED_NODE_TYPE","singleNodeValue","getUniqueNodeAnchorXpaths","key","tagXpath","getTextXpathFunction","trimmedText","undefined","replaceActualAttributes","getReferenceElementsXpath","nodeXpath1","xpaths1","tag","targetText","xpaths","xpth","addAttributeSplitCombineXpaths","concat","normalizeXPath","findMatchingParenthesis","openPos","closePos","counter","getXPathPattern","canonical","canonicalizeXPath","parts","xp","axisMatch","axis","attrMatch","usesNormalize","extractXPathSignatureParts","escapeAttrValue","isUniqueInDOM","queryAll","selector","querySelectorAll","xpathUtils","parseXml","xmlStr","window","DOMParser","parseFromString","getElementFromXpath","multi","getRelationship","pos","compareDocumentPosition","createObserver","addedNodeCallBack","MutationObserver","mutations","addedNodes","url","baseURI","startObserver","options","observe","stopObserver","disconnect","cspEnabled","getClassTokenCondition","xpathData","xpathDataWithIndex","xpathCache","cache","parentXpathCache","STRATEGY_MAP","andConditions","orConditions","contains","normalizeSpace","axes","hardCodedText","tillTag","getStrategyName","strategy","withStrategyKey","entries","entry","removePositionalIndexXpaths","quote","char","hasPositionalIndex","getNormalizedText","collectSubtreeElements","queue","shift","getSiblingNodes","direction","previousElementSibling","nextElementSibling","getDirectionalAxisSeedNodes","sibling","expand","isLowQualityNode","id","className","scoreNode","score","buildAxisXpathsForNodes","targetNodeTest","candidates","processed","MAX_PROCESS","nodeItem","anchorStages","containsXpath","startsWithXpath","stageIndex","anchor","Math","min","expanded","childCount","child","getLimitedAncestors","limit","ancestors","getSiblingAxis","to","getParentAxisPath","getTargetPathFromScope","scope","buildChainedAxesFallbackXpaths","anchorNodes","depth","siblingGroups","descendantCount","descendant","collectChainedAxisAnchorNodes","targetScopes","anchorNode","anchorXpaths","anchorScopes","anchorXpath","anchorScope","anchorToScopePath","targetScope","siblingAxis","siblingStep","targetPath","getChildAxisPathFromAncestor","finalStep","getChildChainAnchorXpaths","addAnchor","canUseStableAxisAttribute","stableValue","getStableAxisAttributeValue","buildAxesStrategyXpaths","descendants","previousSiblings","nextSiblings","precedingSeeds","followingSeeds","limitNodes","tiers","childChainResults","childAxisPath","buildAnchoredChildChainAxesXpaths","tier","buildStrategyXpaths","fallbackXpaths","strategyName","getTextXPath","buildTextStrategyXpaths","getStrategyXPath","buildPropertyStrategyXpaths","buildConditionStrategyXpaths","idx","scopeXpaths","toString","scopeXpath","scopedIdx","generateIndexedXpaths","checkRelativeXpathRelation","nodeXpath2","relationType","indexedXpath","getUniqueParentXpath","nodeXpath","ign","getParentRelativeXpath","uniqueAttrFound","textXPath","finalXpath","getChildRelativeXpath","st","firstElementChild","m","getSiblingRelativeXPath","markedSpan","querySelector","processSibling","n","hasAttributes","getXPathUsingAttributeAndText","normalizedTextContent","attributesBasedXPath","getUniqueClassName","addAllXPathAttributes","txtXpath","textAttribute","parseDOM","includedAttributes","strategies","isShadowScoped","attributesToUse","allowPositionalIndex","includesIndexStrategy","strategyXpaths","getUniqueXpathEntries","len","substring","addRelativeXpaths","relativeXpath","relativeChildXpath","expressions","fullRelativeXpath","relativeXpathIndex","childRelativeXpath","tempRelativeXpath","descendantExpression","refExpectElement","xpath2","relation","expCommonParentXpathElements","step4","refCommonParentXpathElementLength","finalExpectedElementXpath","xpaths2Els","xpath2Elements","traverseXpath","getTraverseXpathExpression","repeat","rel_count","getDescendantXpath","xpaths2","refElement","expElement","expElementDocmnt","refAbsoluteXpath","refFullXpathElements","refFullXpathElementsWithoutNumber","expAbsoluteXpath","expFullXpathElements","expFullXpathElementsWithoutNumber","parentElementNumber","refCommonParentXpathElements","j","getPriority","hasTextPredicate","hasAttributePredicate","prioritizeTextBasedXpaths","referenceElement","referenceText","referenceTextCondition","refCommonParentXpath","getXpathRelationExpression","element1","element2","xpath1","finalXpaths","doesReferenceXpathMatchElement","targetXpathValue","referenceXpath","getReferenceXpathValue","rel_xpath","ancestorBridgeXpaths","getAncestorSemanticBridgeXpaths","semanticBridgeXpath","getSemanticRelationBridgeXpath","semanticTargetXpath","getDirectSemanticDescendantXpath","hasStructuralRelationTail","bridgeXpath","xpathStepSeparator","stripXpathPrefix","getSingleStepXpath","getSingleStepXpaths","tagOnlyXpath","addCandidate","xpathValue","semanticScopeAttributeNames","getStableAttributeCondition","getSemanticNodeTests","nodeTests","getLimitedSelfAndAncestors","elements","currentElement","getDescendantScopeAttributeCondition","stablePrefix","getSemanticScopedBridgeXpath","commonAncestor","ancestorNodeTest","targetAxisXpath","scopeElement","checkedAncestors","scopeNodeTest","scopedXpath","directionalIntermediateAttributeNames","targetAxisXpaths","positionReference","getFirstElementByXpath","intermediate","DOCUMENT_POSITION_FOLLOWING","DOCUMENT_POSITION_PRECEDING","intermediateNodeTest","getDirectionalIntermediateBridgeXpath","referenceScopes","referenceScope","referenceScopeTests","targetScopeTests","isSibling","referenceScopeTest","targetScopeTest","getSemanticSiblingBridgeXpath","getSemanticChildBridgeXpath","getAncestorBridgeXpath","targetXpath","candidateXpath","getSemanticScopedDescendantXpath","getIconNodeTest","iconElement","fill","stroke","isUniqueIconAncestorBridge","icons","matches","icon","targetCandidate","closest","getIconAncestorBridgeXpath","iconDescendants","ancestorNodeTests","iconNodeTest","getCommonAncestor","targetRelativeXpath","ancestorElement","targetXPaths","currentStep","getRelativeXpathFromAncestor","semanticAncestorNodeTest","semanticContainerTags","nodeTest","getSemanticAncestorNodeTest","semanticAncestorXpath","iconBridgeXpath","xpathe1","absoluteXpathElements","xpath2Candidates","replaceTrailingTargetClassWithTokenXpaths","exactClassStep","replacementStep","findRelativeXpath","allowedRelations","relations","tryRelation","useIndex","getReferenceElementXpath","referenceElementXpaths","charAt","lastIndexOf","childAnchorXpaths","childText","childTextCondition","referenceXpathElement","getSmartRelations","highPriority","mediumPriority","lowPriority","DOCUMENT_POSITION_CONTAINS","DOCUMENT_POSITION_CONTAINED_BY","isCssSelectorUnique","parseCssSelectors","mode","selectors","idPath","getIdCssPath","classPath","getClassCssPath","namePath","getAttributeCssPath","e","view","ELEMENT_NODE","nodeName","CSS","escape","sib","nth","childElementCount","EXCLUDED_ATTRS","getAttributeSelectors","String","attrSelectors","attrSelector","remove","cssSelectors","getAbsoluteCssPath","isSameXPathStillValid","normalized","getElementFromXPath","shouldUseSnapshot","ORDERED_NODE_SNAPSHOT_TYPE","snapshotLength","snapshotItem","getElementFromCssSelector","found","getElementFromShadowRoot","isSameCssSelectorStillValid","isCssSelectorLocator","locator","shadowRoot","nestedElement","getId","getClassName","getVisibleText","getName","elementEl","hasAttribute","XPathEvaluator","checkReferenceElementIsValid","sourceLoc","xpathEvaluator","getElementsFromHTML","record","elementsToRemove","finalLocatorsSet","finalLocators","createLocator","base","overrides","newValue","newLocator","reference","status","isRecorded","previousSelfHealed","isSelfHealed","hasOwnProperty","locName","resolveIsSelfHealed","obj","pushUniqueLocator","resolveElement","ctx","safeName","findInIframes","iframes","iframe","iframeDoc","contentDocument","contentWindow","cleanLocatorValue","cleaned","locators","recordedNLocators","l","isDynamic","isShared","trimmedSelector","locatorExists","payloadXPaths","payloadCssSelectors","px","cssLocator","existingXPaths","usedXPathPatterns","excludedAttributes","idValue","prevId","prevTag","textValue","prevLinkText","nameLocator","prevName","prevClassLocator","cssSelector","xpathResults","brokenPayloadXPaths","xpathAdded","brokenPx","originalPattern","r","loc","fallbackCandidates","finalAutoHealedLocators","jsonResult","desc","projectId","projectType","folder","parentId","parentName","platform","licenseId","licenseType","userId","iosSelectors","getOptimalClassChain","err","hasSpace","classChain","getOptimalPredicateString","xpathAttributes","predicateString","createXPathAPI","referenceXpaths"],"mappings":"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"}