зеркало из https://github.com/microsoft/appium.git
129 строки
3.5 KiB
JavaScript
129 строки
3.5 KiB
JavaScript
"use strict";
|
|
var au;
|
|
|
|
if (typeof au === "undefined") {
|
|
au = {};
|
|
}
|
|
|
|
au.getNodeIndex = function (seg) {
|
|
var index = /\[(\d+|last\(\))\]/;
|
|
var match = index.exec(seg);
|
|
if (match) {
|
|
|
|
if (match[1].indexOf("last") !== -1) {
|
|
return -1; // last() is internally an index of -1
|
|
}
|
|
|
|
// -1 is an invalid index when supplied by the user.
|
|
// set to 0 which is always invalid so parseXpath returns false
|
|
var idx = parseInt(match[1], 10);
|
|
if (idx < 1) {
|
|
idx = 0;
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
au.getXpathSearchMethod = function (pathSeg, root) {
|
|
if (typeof root === "undefined") {
|
|
root = false;
|
|
}
|
|
if (root && pathSeg[0] !== "/") {
|
|
return "desc";
|
|
}
|
|
if (pathSeg.substr(0, 2) === "//") {
|
|
return "desc";
|
|
}
|
|
return "child";
|
|
};
|
|
|
|
au.getXpathExtPath = function (matchedExt) {
|
|
var path = [];
|
|
if (matchedExt) {
|
|
// first split on '//'
|
|
matchedExt = matchedExt.replace(/\//g, "|/");
|
|
matchedExt = matchedExt.replace(/\|\/\|\//g, "|//");
|
|
var splits = matchedExt.split("|");
|
|
for (var i = 0; i < splits.length; i++) {
|
|
if (splits[i] !== "") {
|
|
path.push({
|
|
node: splits[i].replace(/\/+/, '').replace(/\[\d+\]/, '')
|
|
, search: au.getXpathSearchMethod(splits[i])
|
|
, index: au.getNodeIndex(splits[i])
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return path;
|
|
};
|
|
|
|
au.parseXpath = function (xpath) {
|
|
// e.g. "//button" or "button" or "/button"
|
|
var index = "(\\[(?:\\d+|last\\(\\))\\])?";
|
|
var root = "^(/?/?(?:[a-zA-Z.]+|\\*)" + index + ")";
|
|
var ext = "((//?[a-zA-Z.]+" + index + ")*)"; // e.g. "/text" or "/cell//button/text"
|
|
var attrEq = "(@[a-zA-Z0-9_]+=[^\\]]+)"; // e.g. [@name="foo"]
|
|
// e.g. [contains(@name, "foo")]
|
|
var attrContains = "(contains\\(@[a-zA-Z0-9_]+, ?[^\\]]+\\))";
|
|
var attr = "(\\[(" + attrEq + "|" + attrContains + ")\\])?$";
|
|
var xpathRe = new RegExp(root + ext + attr); // all together now
|
|
var match = xpathRe.exec(xpath);
|
|
if (match) {
|
|
var matchedRoot = match[1]
|
|
, matchedExt = match[3]
|
|
, matchedAttrEq = match[8]
|
|
, matchedContains = match[9]
|
|
, attrName = null
|
|
, attrConstraint = null
|
|
, substrMatch = false
|
|
, path = []
|
|
, rootSearch = au.getXpathSearchMethod(matchedRoot, true)
|
|
, parts = null;
|
|
path.push({
|
|
node: matchedRoot.replace(/\/+/, '').replace(/\[\d+\]/, '').replace(/\[last\(\)\]/, '')
|
|
, search: rootSearch
|
|
, index: au.getNodeIndex(matchedRoot)
|
|
});
|
|
path = path.concat(au.getXpathExtPath(matchedExt));
|
|
if (matchedAttrEq || matchedContains) {
|
|
if (matchedAttrEq) {
|
|
parts = matchedAttrEq.split("=");
|
|
attrName = parts[0].substr(1);
|
|
} else if (matchedContains) {
|
|
substrMatch = true;
|
|
parts = matchedContains.split(",");
|
|
attrName = parts[0].substr(10);
|
|
parts[1] = parts[1].substr(0, parts[1].length - 1);
|
|
parts[1] = parts[1].replace(/^ /, '');
|
|
}
|
|
if (parts[1][0] === "'" || parts[1][0] === '"') {
|
|
attrConstraint = parts[1].substr(1, parts[1].length - 2);
|
|
} else {
|
|
attrConstraint = parts[1];
|
|
}
|
|
}
|
|
|
|
// ensure we're using 1-indexing
|
|
for (var i = 0; i < path.length; i++) {
|
|
if (path[i].index !== null && path[i].index < 1 && path[i].index !== -1) {
|
|
return false;
|
|
}
|
|
}
|
|
var ret = {
|
|
path: path
|
|
, attr: attrName
|
|
, constraint: attrConstraint
|
|
, substr: substrMatch
|
|
};
|
|
return ret;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
if (typeof module !== "undefined") {
|
|
module.exports = au;
|
|
}
|