playwright-dompath
Version:
Retrieve xpath and css selector paths from ElementHandle and Locator objects in Playwright
269 lines • 9.85 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.xPath = exports.cssPath = void 0;
require("css.escape");
const cssPath = async function cssPath(elHandle, optimized) {
return (await elHandle.evaluate(async (node, optimized) => {
function nodeNameInCorrectCase(node) {
const shadowRoot = node.shadowRoot;
const shadowRootType = shadowRoot && shadowRoot.mode;
if (shadowRootType) {
return `#shadow-root (${shadowRootType})`;
}
if (!node.localName) {
return node.nodeName;
}
if (node.localName.length !== node.nodeName.length) {
return node.nodeName;
}
return node.localName;
}
class Step {
value;
optimized;
constructor(value, optimized) {
this.value = value;
this.optimized = optimized || false;
}
toString() {
return this.value;
}
}
const cssPathStep = function cssPathStep(node, optimized, isTargetNode) {
function idSelector(id) {
return `#${CSS.escape(id)}`;
}
if (node.nodeType !== Node.ELEMENT_NODE) {
return null;
}
const id = node.id;
if (optimized) {
if (id) {
return new Step(idSelector(id), true);
}
const nodeNameLower = node.nodeName.toLowerCase();
if (nodeNameLower === "body" ||
nodeNameLower === "head" ||
nodeNameLower === "html") {
return new Step(nodeNameInCorrectCase(node), true);
}
}
const nodeName = nodeNameInCorrectCase(node);
if (id) {
return new Step(nodeName + idSelector(id), true);
}
const parent = node.parentNode;
if (!parent || parent.nodeType === Node.DOCUMENT_NODE) {
return new Step(nodeName, true);
}
function prefixedElementClassNames(node) {
const classAttribute = node.className;
if (!classAttribute) {
return [];
}
return classAttribute
.split(/\s+/g)
.filter(Boolean)
.map((name) => `$${name}`);
}
const prefixedOwnClassNamesArray = prefixedElementClassNames(node);
let needsClassNames = false;
let needsNthChild = false;
let ownIndex = -1;
let elementIndex = -1;
const siblings = parent.childNodes;
for (let i = 0; siblings &&
(ownIndex === -1 || !needsNthChild) &&
i < siblings.length; ++i) {
const sibling = siblings[i];
if (sibling.nodeType !== Node.ELEMENT_NODE) {
continue;
}
elementIndex += 1;
if (sibling === node) {
ownIndex = elementIndex;
continue;
}
if (needsNthChild) {
continue;
}
if (nodeNameInCorrectCase(sibling) !== nodeName) {
continue;
}
needsClassNames = true;
const ownClassNames = new Set(prefixedOwnClassNamesArray);
if (!ownClassNames.size) {
needsNthChild = true;
continue;
}
const siblingClassNamesArray = prefixedElementClassNames(sibling);
for (let j = 0; j < siblingClassNamesArray.length; ++j) {
const siblingClass = siblingClassNamesArray[j];
if (!ownClassNames.has(siblingClass)) {
continue;
}
ownClassNames.delete(siblingClass);
if (!ownClassNames.size) {
needsNthChild = true;
break;
}
}
}
let result = nodeName;
if (isTargetNode &&
nodeName.toLowerCase() === "input" &&
node.getAttribute("type") &&
!node.id &&
!node.className) {
result += `[type=${CSS.escape(node.getAttribute("type") || "")}]`;
}
if (needsNthChild) {
result += `:nth-child(${ownIndex + 1})`;
}
else if (needsClassNames) {
for (const prefixedName of prefixedOwnClassNamesArray) {
result += `.${CSS.escape(prefixedName.slice(1))}`;
}
}
return new Step(result, false);
};
if (node.nodeType !== Node.ELEMENT_NODE) {
return "";
}
const steps = [];
let contextNode = node;
while (contextNode) {
const step = cssPathStep(contextNode, Boolean(optimized), contextNode === node);
if (!step) {
break;
}
steps.push(step);
if (step.optimized) {
break;
}
contextNode = contextNode.parentNode;
}
steps.reverse();
return steps.join(" > ");
}, optimized));
};
exports.cssPath = cssPath;
const xPath = async function xPath(elHandle, optimized) {
return (await elHandle.evaluate(async (node, optimized) => {
class Step {
value;
optimized;
constructor(value, optimized) {
this.value = value;
this.optimized = optimized || false;
}
toString() {
return this.value;
}
}
const xPathValue = function xPathValue(node, optimized) {
let ownValue;
const ownIndex = xPathIndex(node);
if (ownIndex === -1) {
return null;
}
switch (node.nodeType) {
case Node.ELEMENT_NODE:
if (optimized && node.id) {
return new Step(`//*[@id="${node.id}"]`, true);
}
ownValue = node.localName;
break;
case Node.ATTRIBUTE_NODE:
ownValue = `@${node.nodeName}`;
break;
case Node.TEXT_NODE:
case Node.CDATA_SECTION_NODE:
ownValue = "text()";
break;
case Node.PROCESSING_INSTRUCTION_NODE:
ownValue = "processing-instruction()";
break;
case Node.COMMENT_NODE:
ownValue = "comment()";
break;
case Node.DOCUMENT_NODE:
ownValue = "";
break;
default:
ownValue = "";
break;
}
if (ownIndex > 0) {
ownValue += `[${ownIndex}]`;
}
return new Step(ownValue, node.nodeType === Node.DOCUMENT_NODE);
};
const xPathIndex = function xPathIndex(node) {
function areNodesSimilar(left, right) {
if (left === right) {
return true;
}
if (left.nodeType === Node.ELEMENT_NODE &&
right.nodeType === Node.ELEMENT_NODE) {
return left.localName === right.localName;
}
if (left.nodeType === right.nodeType) {
return true;
}
const leftType = left.nodeType === Node.CDATA_SECTION_NODE
? Node.TEXT_NODE
: left.nodeType;
const rightType = right.nodeType === Node.CDATA_SECTION_NODE
? Node.TEXT_NODE
: right.nodeType;
return leftType === rightType;
}
const parentNode = node.parentNode;
const siblings = parentNode ? parentNode.children : null;
if (!siblings) {
return 0;
}
let hasSameNamedElements;
for (let i = 0; i < siblings.length; ++i) {
if (areNodesSimilar(node, siblings[i]) && !(siblings[i] === node)) {
hasSameNamedElements = true;
break;
}
}
if (!hasSameNamedElements) {
return 0;
}
let ownIndex = 1;
for (let i = 0; i < siblings.length; ++i) {
if (areNodesSimilar(node, siblings[i])) {
if (siblings[i] === node) {
return ownIndex;
}
++ownIndex;
}
}
return -1;
};
if (node.nodeType === Node.DOCUMENT_NODE) {
return "/";
}
const steps = [];
let contextNode = node;
while (contextNode) {
const step = xPathValue(contextNode, optimized);
if (!step) {
break;
}
steps.push(step);
if (step.optimized) {
break;
}
contextNode = contextNode.parentNode;
}
steps.reverse();
return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/");
}, optimized));
};
exports.xPath = xPath;
//# sourceMappingURL=DOMPath.js.map
;