ff-automationv2 2.2.29 → 2.2.30
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.
- package/dist/ai/llmcalls/llmAction.js +49 -13
- package/dist/ai/llmcalls/parseLlmOputput.js +5 -5
- package/dist/ai/llmprompts/promptRegistry.js +4 -0
- package/dist/ai/llmprompts/systemPrompts/actionExtractorPrompt.js +39 -11
- package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtactors.js +6 -6
- package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtractor_Mob.js +32 -0
- package/dist/ai/llmprompts/systemPrompts/mobileKeywordExtractor.js +17 -8
- package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.d.ts +1 -0
- package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.js +22 -0
- package/dist/ai/llmprompts/systemPrompts/verifyActionExtractorPrompt.js +3 -1
- package/dist/ai/llmprompts/systemPrompts/visionPrompt.js +14 -6
- package/dist/ai/llmprompts/systemPrompts/visionPromptMobile.js +3 -0
- package/dist/ai/llmprompts/userPrompts/userPrompt.js +1 -0
- package/dist/automation/actions/executor.d.ts +4 -0
- package/dist/automation/actions/executor.js +20 -0
- package/dist/automation/actions/interaction/clear/clear.js +1 -1
- package/dist/automation/actions/interaction/clear/clearAndEnter.js +1 -1
- package/dist/automation/actions/interaction/click/click.js +10 -3
- package/dist/automation/actions/interaction/click/clickNtimes.js +1 -1
- package/dist/automation/actions/interaction/click/doubleClick.js +1 -1
- package/dist/automation/actions/interaction/click/rightClick.js +1 -1
- package/dist/automation/actions/interaction/elementlessActions/getOtp.d.ts +2 -0
- package/dist/automation/actions/interaction/elementlessActions/getOtp.js +101 -0
- package/dist/automation/actions/interaction/enterActions/enterInput.js +11 -6
- package/dist/automation/actions/interaction/enterActions/enterInputAndPress.js +2 -2
- package/dist/automation/actions/interaction/enterActions/enterusingJs.js +2 -2
- package/dist/automation/actions/interaction/enterActions/waitAndEnter.js +1 -1
- package/dist/automation/actions/interaction/upload/uploadfile.js +1 -1
- package/dist/automation/actions/interaction/verify/VerifyNavigateURL.js +38 -11
- package/dist/automation/actions/interface/FireFlinkResponseSchema.d.ts +12 -0
- package/dist/automation/actions/interface/FireFlinkResponseSchema.js +19 -3
- package/dist/automation/actions/interface/getOtpInterface.d.ts +15 -0
- package/dist/automation/actions/interface/getOtpInterface.js +2 -0
- package/dist/automation/browserSession/initiateBrowserSession.d.ts +1 -1
- package/dist/automation/browserSession/initiateBrowserSession.js +15 -7
- package/dist/automation/driverState.d.ts +2 -0
- package/dist/automation/driverState.js +4 -0
- package/dist/automation/mobileSession/initiateMobileSession.d.ts +4 -5
- package/dist/automation/mobileSession/initiateMobileSession.js +83 -19
- package/dist/core/constants/allAction.js +5 -1
- package/dist/core/constants/supportedActions.js +5 -2
- package/dist/core/interfaces/actionInterface.d.ts +4 -0
- package/dist/core/interfaces/browserConfigurationInterface.d.ts +0 -4
- package/dist/core/interfaces/browserConfigurationInterface.js +0 -1
- package/dist/core/interfaces/executionDetails.d.ts +6 -3
- package/dist/core/interfaces/fireflinkScriptPayloadInterface.d.ts +22 -16
- package/dist/core/interfaces/llmResponseInterface.d.ts +1 -0
- package/dist/core/interfaces/promptInterface.d.ts +1 -0
- package/dist/core/main/SessionManager.d.ts +9 -0
- package/dist/core/main/SessionManager.js +23 -0
- package/dist/core/main/actionHandlerFactory.js +261 -64
- package/dist/core/main/executionContext.d.ts +7 -1
- package/dist/core/main/executionContext.js +93 -3
- package/dist/core/main/runAutomationScript.d.ts +1 -0
- package/dist/core/main/runAutomationScript.js +912 -304
- package/dist/core/main/stepProcessor.js +7 -2
- package/dist/core/types/browserType.d.ts +3 -3
- package/dist/core/types/browserType.js +2 -2
- package/dist/core/types/messageType.d.ts +13 -0
- package/dist/core/types/messageType.js +15 -0
- package/dist/core/types/promptType.d.ts +2 -1
- package/dist/core/types/promptType.js +1 -0
- package/dist/domAnalysis/searchBest.js +15 -16
- package/dist/domAnalysis/simplifyAndFlatten.js +6 -4
- package/dist/fireflinkData/fireflinkLocators/getListOfLocators.d.ts +3 -0
- package/dist/fireflinkData/fireflinkLocators/getListOfLocators.js +23 -15
- package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.d.ts +3 -3
- package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.js +134 -118
- package/dist/fireflinkData/fireflinkLocators/types/locator.d.ts +11 -1
- package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.d.ts +1 -1
- package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.js +35 -9
- package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.d.ts +10 -10
- package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.js +56 -59
- package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.d.ts +1 -1
- package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.js +53 -29
- package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.d.ts +8 -8
- package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.js +113 -190
- package/dist/fireflinkData/fireflinkLocators/utils/xpath.d.ts +17 -26
- package/dist/fireflinkData/fireflinkLocators/utils/xpath.js +314 -786
- package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.d.ts +68 -70
- package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.js +498 -517
- package/dist/fireflinkData/fireflinkScript/appendScriptData.d.ts +1 -1
- package/dist/fireflinkData/fireflinkScript/appendScriptData.js +5 -8
- package/dist/fireflinkData/fireflinkScript/scriptGenrationData.d.ts +2 -2
- package/dist/fireflinkData/fireflinkScript/scriptGenrationData.js +17 -27
- package/dist/llmConfig/llmConfiguration.js +13 -6
- package/dist/service/api/fireflinkApi.service.d.ts +1 -1
- package/dist/service/api/fireflinkApi.service.js +1 -2
- package/dist/service/fireflink.service.d.ts +3 -3
- package/dist/service/fireflink.service.js +23 -21
- package/dist/service/kafka/fireflinkKafka.service.d.ts +1 -2
- package/dist/service/kafka/fireflinkKafka.service.js +6 -4
- package/dist/tests/test12.d.ts +0 -1
- package/dist/tests/test12.js +65 -78
- package/dist/tests/testkaf.d.ts +0 -1
- package/dist/tests/testkaf.js +51 -55
- package/dist/utils/InstancesDetails/getInstancesInfo.js +1 -1
- package/dist/utils/browserCap/capability.d.ts +5 -1
- package/dist/utils/browserCap/capability.js +91 -15
- package/dist/utils/helpers/domSanitizer.d.ts +1 -0
- package/dist/utils/helpers/domSanitizer.js +9 -0
- package/dist/utils/helpers/enterActionHelper.js +23 -4
- package/dist/utils/helpers/xpathcreation.js +2 -2
- package/dist/utils/javascript/jsFindElement.d.ts +1 -1
- package/dist/utils/javascript/jsFindElement.js +2 -2
- package/dist/utils/newTab/newTabTracker.js +18 -6
- package/dist/utils/workers/LocatorWorkerInterface.d.ts +22 -0
- package/dist/utils/workers/LocatorWorkerInterface.js +2 -0
- package/dist/utils/workers/LocatorWorkerPool.d.ts +13 -0
- package/dist/utils/workers/LocatorWorkerPool.js +89 -0
- package/dist/utils/workers/locatorWorker.d.ts +1 -0
- package/dist/utils/workers/locatorWorker.js +44 -0
- package/package.json +3 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.xpathUtils = exports.
|
|
4
|
-
exports.
|
|
3
|
+
exports.xpathUtils = exports.findMatchingParenthesis = exports.normalizeXPath = exports.getReferenceElementsXpath = exports.replaceAiActualAttributes = exports.getAiXpathString = exports.getAiTextXpathFunction = exports.getAiUniqueNodeAnchorXpaths = exports.getAiAxisNodeTest = exports.isAiExactUniqueXpath = exports.getAiFirstMatchedNode = exports.getAiTagOnlyXPath = exports.getOrAttributesAiXPath = exports.getAiContainsPropertyXPath = exports.getAiStartsWithPropertyXPath = exports.getAiNormalizedPropertyXPath = exports.getAiFilteredTextXPath = exports.intermediateAiXpathStep = exports.getAiAttributeCombinationXpath = exports.getAiCombinationXpath = exports.getAIRelativeXPath = exports.getAiAbsoluteXPath = exports.getAiPropertyXPath = exports.replaceAiTempAttributes = exports.isAiSvg = exports.getAiRelationship = exports.checkAiBlockedAttributes = exports.createAIShadowEvaluationContext = exports.getAiShadowRoot = exports.aiReplaceWhiteSpaces = exports.findAiXpathWithIndex = exports.removeAiParenthesis = exports.escapeAiCharacters = exports.getAiCountOfXPath = exports.getAiFilteredText = exports.getAiTextContent = exports.buildAiPattern = exports.isAiNumberExist = exports.sanitizeAiAttributeValue = exports.modifiedElementAttributes = exports.evaluateAIXPathOnce = exports.clearAiXPathEvalCache = exports.timeLog = exports.cspEnabled = exports.reWhiteSpace = void 0;
|
|
4
|
+
exports.evaluateAiXPath = evaluateAiXPath;
|
|
5
5
|
exports.escapeAttrValue = escapeAttrValue;
|
|
6
|
-
exports.
|
|
6
|
+
exports.isAiUniqueInDOM = isAiUniqueInDOM;
|
|
7
7
|
const logData_1 = require("../../../utils/logger/logData");
|
|
8
8
|
exports.reWhiteSpace = /^[\S]+( [\S]+)*$/i;
|
|
9
9
|
exports.cspEnabled = false;
|
|
@@ -15,45 +15,57 @@ const timeLog = (label, start) => {
|
|
|
15
15
|
exports.timeLog = timeLog;
|
|
16
16
|
// cache per context node → avoids cross-context pollution
|
|
17
17
|
let xpathEvalCache = new WeakMap();
|
|
18
|
-
const
|
|
18
|
+
const XPathResultConst = {
|
|
19
|
+
ANY_TYPE: 0,
|
|
20
|
+
NUMBER_TYPE: 1,
|
|
21
|
+
STRING_TYPE: 2,
|
|
22
|
+
BOOLEAN_TYPE: 3,
|
|
23
|
+
UNORDERED_NODE_ITERATOR_TYPE: 4,
|
|
24
|
+
ORDERED_NODE_ITERATOR_TYPE: 5,
|
|
25
|
+
UNORDERED_NODE_SNAPSHOT_TYPE: 6,
|
|
26
|
+
ORDERED_NODE_SNAPSHOT_TYPE: 7,
|
|
27
|
+
ANY_UNORDERED_NODE_TYPE: 8,
|
|
28
|
+
FIRST_ORDERED_NODE_TYPE: 9
|
|
29
|
+
};
|
|
30
|
+
const getAiXPathContext = (docmt) => {
|
|
19
31
|
const owner = docmt.nodeType === 9
|
|
20
32
|
? docmt
|
|
21
|
-
: docmt.ownerDocument
|
|
33
|
+
: docmt.ownerDocument;
|
|
22
34
|
// valid XPath context nodes: Element(1), Document(9), DocumentFragment/ShadowRoot(11)
|
|
23
35
|
const contextNode = docmt.nodeType === 1 || docmt.nodeType === 9 || docmt.nodeType === 11
|
|
24
36
|
? docmt
|
|
25
37
|
: owner;
|
|
26
38
|
return contextNode;
|
|
27
39
|
};
|
|
28
|
-
const
|
|
40
|
+
const getAiMutationCacheContexts = (node) => {
|
|
29
41
|
const contexts = [];
|
|
30
|
-
const
|
|
42
|
+
const addAiContext = (candidate) => {
|
|
31
43
|
if (!candidate || contexts.includes(candidate))
|
|
32
44
|
return;
|
|
33
45
|
contexts.push(candidate);
|
|
34
46
|
};
|
|
35
|
-
|
|
47
|
+
addAiContext(node);
|
|
36
48
|
const rootNode = node.getRootNode?.();
|
|
37
|
-
if (rootNode
|
|
38
|
-
|
|
49
|
+
if (rootNode && (rootNode.nodeType === 9 || rootNode.nodeType === 11)) {
|
|
50
|
+
addAiContext(rootNode);
|
|
39
51
|
}
|
|
40
52
|
const ownerDocument = node.nodeType === 9
|
|
41
53
|
? node
|
|
42
54
|
: node.ownerDocument;
|
|
43
|
-
|
|
55
|
+
addAiContext(ownerDocument);
|
|
44
56
|
return contexts;
|
|
45
57
|
};
|
|
46
|
-
const
|
|
58
|
+
const clearAiXPathEvalCache = (node) => {
|
|
47
59
|
if (!node) {
|
|
48
60
|
xpathEvalCache = new WeakMap();
|
|
49
61
|
return;
|
|
50
62
|
}
|
|
51
|
-
|
|
63
|
+
getAiMutationCacheContexts(node).forEach((contextNode) => {
|
|
52
64
|
xpathEvalCache.delete(contextNode);
|
|
53
65
|
});
|
|
54
66
|
};
|
|
55
|
-
exports.
|
|
56
|
-
function
|
|
67
|
+
exports.clearAiXPathEvalCache = clearAiXPathEvalCache;
|
|
68
|
+
function svgAiXPathFallback(xpath, root) {
|
|
57
69
|
const tag = xpath.match(/local-name\(\)\s*=\s*['"]([^'"]+)['"]/)?.[1];
|
|
58
70
|
if (!tag)
|
|
59
71
|
return [];
|
|
@@ -78,26 +90,24 @@ function svgXPathFallback(xpath, root) {
|
|
|
78
90
|
}
|
|
79
91
|
return elements;
|
|
80
92
|
}
|
|
81
|
-
function
|
|
93
|
+
function evaluateAiXPath(xpath, contextNode, mode = "iterator") {
|
|
82
94
|
const owner = contextNode.nodeType === 9
|
|
83
95
|
? contextNode
|
|
84
96
|
: contextNode.ownerDocument;
|
|
85
97
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return owner.evaluate(xpath, contextNode, null, owner.defaultView.XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
|
|
93
|
-
}
|
|
98
|
+
const resultType = mode === "first"
|
|
99
|
+
? (owner.defaultView?.XPathResult?.FIRST_ORDERED_NODE_TYPE ?? XPathResultConst.FIRST_ORDERED_NODE_TYPE)
|
|
100
|
+
: mode === "snapshot"
|
|
101
|
+
? (owner.defaultView?.XPathResult?.ORDERED_NODE_SNAPSHOT_TYPE ?? XPathResultConst.ORDERED_NODE_SNAPSHOT_TYPE)
|
|
102
|
+
: (owner.defaultView?.XPathResult?.ORDERED_NODE_ITERATOR_TYPE ?? XPathResultConst.ORDERED_NODE_ITERATOR_TYPE);
|
|
103
|
+
return owner.evaluate(xpath, contextNode, null, resultType, null);
|
|
94
104
|
}
|
|
95
105
|
catch (e) {
|
|
96
106
|
logData_1.logger.error(` Error in evaluating xpath: ${e.message}`);
|
|
97
107
|
const root = contextNode.nodeType === 9
|
|
98
108
|
? contextNode
|
|
99
109
|
: contextNode.ownerDocument;
|
|
100
|
-
const nodes =
|
|
110
|
+
const nodes = svgAiXPathFallback(xpath, root);
|
|
101
111
|
if (mode === "first") {
|
|
102
112
|
return {
|
|
103
113
|
singleNodeValue: nodes[0] ?? null
|
|
@@ -115,67 +125,93 @@ function evaluateXPath(xpath, contextNode, mode = "iterator") {
|
|
|
115
125
|
};
|
|
116
126
|
}
|
|
117
127
|
}
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
128
|
+
const evaluateAIXPathOnce = (xpath, docmt) => {
|
|
129
|
+
try {
|
|
130
|
+
const contextNode = getAiXPathContext(docmt);
|
|
131
|
+
// get or create cache for this context node
|
|
132
|
+
let nodeCache = xpathEvalCache.get(contextNode);
|
|
133
|
+
if (!nodeCache) {
|
|
134
|
+
nodeCache = new Map();
|
|
135
|
+
xpathEvalCache.set(contextNode, nodeCache);
|
|
136
|
+
}
|
|
137
|
+
// cache hit
|
|
138
|
+
const cached = nodeCache.get(xpath);
|
|
139
|
+
if (cached)
|
|
140
|
+
return cached;
|
|
141
|
+
// evaluate once, stop after 2 nodes
|
|
142
|
+
// const result = owner.evaluate(
|
|
143
|
+
// xpath,
|
|
144
|
+
// contextNode,
|
|
145
|
+
// null,
|
|
146
|
+
// owner.defaultView!.XPathResult.ORDERED_NODE_ITERATOR_TYPE,
|
|
147
|
+
// null
|
|
148
|
+
// );
|
|
149
|
+
// const result = evaluateAiXPath(xpath, contextNode);
|
|
150
|
+
const owner = contextNode.nodeType === 9
|
|
151
|
+
? contextNode
|
|
152
|
+
: contextNode.ownerDocument;
|
|
153
|
+
// const result = owner.evaluate(
|
|
154
|
+
// xpath,
|
|
155
|
+
// contextNode,
|
|
156
|
+
// null,
|
|
157
|
+
// owner.defaultView!.XPathResult.ORDERED_NODE_ITERATOR_TYPE,
|
|
158
|
+
// null
|
|
159
|
+
// );
|
|
160
|
+
let result;
|
|
161
|
+
try {
|
|
162
|
+
const iteratorType = owner.defaultView?.XPathResult?.ORDERED_NODE_ITERATOR_TYPE ??
|
|
163
|
+
XPathResultConst.ORDERED_NODE_ITERATOR_TYPE;
|
|
164
|
+
result = owner.evaluate(xpath, contextNode, null, iteratorType, null);
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
logData_1.logger.error("evaluate exception", err);
|
|
168
|
+
return { first: null, second: null };
|
|
169
|
+
}
|
|
170
|
+
const first = result.iterateNext();
|
|
171
|
+
const second = result.iterateNext();
|
|
172
|
+
const evalResult = { first, second };
|
|
173
|
+
nodeCache.set(xpath, evalResult);
|
|
174
|
+
return evalResult;
|
|
175
|
+
}
|
|
176
|
+
catch (e) {
|
|
177
|
+
logData_1.logger.error(e);
|
|
178
|
+
return { first: null, second: null };
|
|
179
|
+
}
|
|
144
180
|
};
|
|
145
|
-
exports.
|
|
181
|
+
exports.evaluateAIXPathOnce = evaluateAIXPathOnce;
|
|
146
182
|
const relativeXPathCache = new Map();
|
|
147
183
|
exports.modifiedElementAttributes = [];
|
|
148
184
|
const INTERNAL_CLASS_TOKENS = new Set([
|
|
149
185
|
"marked-element-temp",
|
|
150
186
|
"removePointers"
|
|
151
187
|
]);
|
|
152
|
-
const
|
|
188
|
+
const normalizeAiClassTokens = (classValue) => (classValue || "")
|
|
153
189
|
.split(/\s+/)
|
|
154
190
|
.map((token) => token.trim())
|
|
155
191
|
.filter((token) => token && !INTERNAL_CLASS_TOKENS.has(token))
|
|
156
192
|
.sort();
|
|
157
|
-
const
|
|
193
|
+
const sanitizeAiAttributeValue = (attributeName, attributeValue) => {
|
|
158
194
|
if (!attributeValue) {
|
|
159
195
|
return "";
|
|
160
196
|
}
|
|
161
197
|
if (attributeName === "class" || attributeName === "className") {
|
|
162
|
-
return
|
|
198
|
+
return normalizeAiClassTokens(attributeValue).join(" ");
|
|
163
199
|
}
|
|
164
200
|
return attributeValue.replace("removePointers", "").trim();
|
|
165
201
|
};
|
|
166
|
-
exports.
|
|
167
|
-
const
|
|
202
|
+
exports.sanitizeAiAttributeValue = sanitizeAiAttributeValue;
|
|
203
|
+
const isAiNumberExist = (str) => {
|
|
168
204
|
const hasNumber = /\d/;
|
|
169
205
|
return hasNumber.test(str);
|
|
170
206
|
};
|
|
171
|
-
exports.
|
|
172
|
-
const
|
|
173
|
-
return
|
|
207
|
+
exports.isAiNumberExist = isAiNumberExist;
|
|
208
|
+
const buildAiPattern = (pattern, isAiSvg, tagName) => {
|
|
209
|
+
return isAiSvg
|
|
174
210
|
? `//*[local-name()='${tagName}' and ${pattern}]`
|
|
175
211
|
: `//${tagName}[${pattern}]`;
|
|
176
212
|
};
|
|
177
|
-
exports.
|
|
178
|
-
const
|
|
213
|
+
exports.buildAiPattern = buildAiPattern;
|
|
214
|
+
const getAiTextContent = (targetElement) => {
|
|
179
215
|
const textContent = targetElement?.textContent;
|
|
180
216
|
if (exports.cspEnabled) {
|
|
181
217
|
if (textContent) {
|
|
@@ -197,14 +233,14 @@ const getTextContent = (targetElement) => {
|
|
|
197
233
|
}
|
|
198
234
|
return "";
|
|
199
235
|
};
|
|
200
|
-
exports.
|
|
201
|
-
const
|
|
236
|
+
exports.getAiTextContent = getAiTextContent;
|
|
237
|
+
const getAiFilteredText = (element) => {
|
|
202
238
|
return element?.childNodes[0]?.nodeValue || "";
|
|
203
239
|
};
|
|
204
|
-
exports.
|
|
205
|
-
const
|
|
240
|
+
exports.getAiFilteredText = getAiFilteredText;
|
|
241
|
+
const getAiCountOfXPath = (xpath, element, docmt, multiElementReferenceMode = false) => {
|
|
206
242
|
try {
|
|
207
|
-
const { first, second } = (0, exports.
|
|
243
|
+
const { first, second } = (0, exports.evaluateAIXPathOnce)(xpath, docmt);
|
|
208
244
|
if (!first)
|
|
209
245
|
return 0;
|
|
210
246
|
// exactly one match
|
|
@@ -227,7 +263,7 @@ const getCountOfXPath = (xpath, element, docmt, multiElementReferenceMode = fals
|
|
|
227
263
|
// owner.defaultView!.XPathResult.ORDERED_NODE_ITERATOR_TYPE,
|
|
228
264
|
// null
|
|
229
265
|
// );
|
|
230
|
-
const result =
|
|
266
|
+
const result = evaluateAiXPath(xpath, docmt);
|
|
231
267
|
let node;
|
|
232
268
|
while ((node = result.iterateNext())) {
|
|
233
269
|
if (element.includes(node)) {
|
|
@@ -240,13 +276,12 @@ const getCountOfXPath = (xpath, element, docmt, multiElementReferenceMode = fals
|
|
|
240
276
|
}
|
|
241
277
|
return 2;
|
|
242
278
|
}
|
|
243
|
-
catch
|
|
244
|
-
console.error(`Error evaluating XPath: ${xpath}`, error);
|
|
279
|
+
catch {
|
|
245
280
|
return 0;
|
|
246
281
|
}
|
|
247
282
|
};
|
|
248
|
-
exports.
|
|
249
|
-
const
|
|
283
|
+
exports.getAiCountOfXPath = getAiCountOfXPath;
|
|
284
|
+
const escapeAiCharacters = (text) => {
|
|
250
285
|
if (text) {
|
|
251
286
|
if (!(text.indexOf('"') === -1)) {
|
|
252
287
|
return `'${text}'`;
|
|
@@ -257,8 +292,8 @@ const escapeCharacters = (text) => {
|
|
|
257
292
|
}
|
|
258
293
|
return `'${text}'`;
|
|
259
294
|
};
|
|
260
|
-
exports.
|
|
261
|
-
const
|
|
295
|
+
exports.escapeAiCharacters = escapeAiCharacters;
|
|
296
|
+
const removeAiParenthesis = (xpath) => {
|
|
262
297
|
const charArr = xpath.split("");
|
|
263
298
|
let count = charArr.length;
|
|
264
299
|
const indexArray = [];
|
|
@@ -281,28 +316,28 @@ const removeParenthesis = (xpath) => {
|
|
|
281
316
|
}
|
|
282
317
|
return firstpart;
|
|
283
318
|
};
|
|
284
|
-
exports.
|
|
285
|
-
const
|
|
319
|
+
exports.removeAiParenthesis = removeAiParenthesis;
|
|
320
|
+
const findAiXpathWithIndex = (val, node, docmt, count) => {
|
|
286
321
|
try {
|
|
287
322
|
let index = 0;
|
|
288
323
|
if (count) {
|
|
289
|
-
if ((0, exports.
|
|
324
|
+
if ((0, exports.getAiCountOfXPath)(`${val}[${count}]`, node, docmt) === 1) {
|
|
290
325
|
return `${val}[${count}]`;
|
|
291
326
|
}
|
|
292
|
-
if ((0, exports.
|
|
327
|
+
if ((0, exports.getAiCountOfXPath)(`(${val})[${count}]`, node, docmt) === 1) {
|
|
293
328
|
return `(${val})[${count}]`;
|
|
294
329
|
}
|
|
295
330
|
}
|
|
296
331
|
// const nodes = owner.evaluate(val, docmt, null, owner.defaultView!.XPathResult.ANY_TYPE, null);
|
|
297
|
-
const nodes =
|
|
332
|
+
const nodes = evaluateAiXPath(val, docmt);
|
|
298
333
|
let nodex = null;
|
|
299
334
|
while ((nodex = nodes.iterateNext())) {
|
|
300
335
|
index++;
|
|
301
336
|
if (nodex.isSameNode(node)) {
|
|
302
|
-
if ((0, exports.
|
|
337
|
+
if ((0, exports.getAiCountOfXPath)(`${val}[${index}]`, node, docmt) === 1) {
|
|
303
338
|
return `${val}[${index}]`;
|
|
304
339
|
}
|
|
305
|
-
if ((0, exports.
|
|
340
|
+
if ((0, exports.getAiCountOfXPath)(`(${val})[${index}]`, node, docmt) === 1) {
|
|
306
341
|
return `(${val})[${index}]`;
|
|
307
342
|
}
|
|
308
343
|
return;
|
|
@@ -313,13 +348,13 @@ const findXpathWithIndex = (val, node, docmt, count) => {
|
|
|
313
348
|
logData_1.logger.error(error);
|
|
314
349
|
}
|
|
315
350
|
};
|
|
316
|
-
exports.
|
|
317
|
-
const
|
|
351
|
+
exports.findAiXpathWithIndex = findAiXpathWithIndex;
|
|
352
|
+
const deleteAiLineGap = (a) => {
|
|
318
353
|
a && (a = a.split("\n")[0].length > 0 ? a.split("\n")[0] : a.split("\n")[1]);
|
|
319
354
|
return a;
|
|
320
355
|
};
|
|
321
|
-
const
|
|
322
|
-
a =
|
|
356
|
+
const deleteAiGarbageFromInnerText = (a) => {
|
|
357
|
+
a = deleteAiLineGap(a);
|
|
323
358
|
a = a
|
|
324
359
|
.split(/[^\p{ASCII}\u0080-\u00FF]/u)
|
|
325
360
|
.reduce((b, c) => {
|
|
@@ -328,24 +363,24 @@ const deleteGarbageFromInnerText = (a) => {
|
|
|
328
363
|
.trim();
|
|
329
364
|
return (a.split("/")[0].trim());
|
|
330
365
|
};
|
|
331
|
-
const
|
|
366
|
+
const aiReplaceWhiteSpaces = (str) => {
|
|
332
367
|
if (str) {
|
|
333
368
|
return str.replace(/\s\s+/g, " ").trim();
|
|
334
369
|
}
|
|
335
370
|
return str;
|
|
336
371
|
};
|
|
337
|
-
exports.
|
|
338
|
-
const
|
|
372
|
+
exports.aiReplaceWhiteSpaces = aiReplaceWhiteSpaces;
|
|
373
|
+
const getAiShadowRoot = (el) => {
|
|
339
374
|
if (!el || !el?.getRootNode)
|
|
340
375
|
return null;
|
|
341
376
|
const root = el.getRootNode();
|
|
342
377
|
return root && root?.host ? root : null;
|
|
343
378
|
};
|
|
344
|
-
exports.
|
|
345
|
-
const
|
|
379
|
+
exports.getAiShadowRoot = getAiShadowRoot;
|
|
380
|
+
const isAiShadowRootNode = (node) => {
|
|
346
381
|
return node?.nodeType === 11 && "host" in node;
|
|
347
382
|
};
|
|
348
|
-
const
|
|
383
|
+
const getAiElementPathFromRoot = (root, element) => {
|
|
349
384
|
const path = [];
|
|
350
385
|
let current = element;
|
|
351
386
|
while (current && current.parentElement) {
|
|
@@ -359,7 +394,7 @@ const getElementPathFromRoot = (root, element) => {
|
|
|
359
394
|
path.unshift(Array.from(root.children).indexOf(current));
|
|
360
395
|
return path;
|
|
361
396
|
};
|
|
362
|
-
const
|
|
397
|
+
const getAiElementAtPath = (container, path) => {
|
|
363
398
|
let current = container;
|
|
364
399
|
for (const index of path) {
|
|
365
400
|
const next = current.children.item(index);
|
|
@@ -370,34 +405,34 @@ const getElementAtPath = (container, path) => {
|
|
|
370
405
|
}
|
|
371
406
|
return current;
|
|
372
407
|
};
|
|
373
|
-
const
|
|
408
|
+
const createAIShadowEvaluationContext = (root, element) => {
|
|
374
409
|
const tempDoc = root.ownerDocument.implementation.createHTMLDocument("shadow-xpath");
|
|
375
410
|
const wrapper = tempDoc.createElement("div");
|
|
376
411
|
wrapper.innerHTML = root.innerHTML;
|
|
377
412
|
tempDoc.body.appendChild(wrapper);
|
|
378
|
-
const
|
|
413
|
+
const cloneAiForElement = (candidate) => {
|
|
379
414
|
if (!candidate ||
|
|
380
|
-
|
|
415
|
+
candidate.nodeType !== 1) {
|
|
381
416
|
return null;
|
|
382
417
|
}
|
|
383
|
-
const path =
|
|
384
|
-
return path ?
|
|
418
|
+
const path = getAiElementPathFromRoot(root, candidate);
|
|
419
|
+
return path ? getAiElementAtPath(wrapper, path) : null;
|
|
385
420
|
};
|
|
386
421
|
const cloneElements = Array.isArray(element)
|
|
387
|
-
? element.map((candidate) =>
|
|
422
|
+
? element.map((candidate) => cloneAiForElement(candidate)).filter(Boolean)
|
|
388
423
|
: [];
|
|
389
424
|
const cloneElement = Array.isArray(element)
|
|
390
425
|
? null
|
|
391
|
-
:
|
|
426
|
+
: cloneAiForElement(element ?? null);
|
|
392
427
|
return {
|
|
393
428
|
contextNode: wrapper,
|
|
394
429
|
cloneElement,
|
|
395
430
|
cloneElements
|
|
396
431
|
};
|
|
397
432
|
};
|
|
398
|
-
exports.
|
|
399
|
-
const
|
|
400
|
-
const sanitizedValue = (0, exports.
|
|
433
|
+
exports.createAIShadowEvaluationContext = createAIShadowEvaluationContext;
|
|
434
|
+
const checkAiBlockedAttributes = (attribute, targetElement, isTarget) => {
|
|
435
|
+
const sanitizedValue = (0, exports.sanitizeAiAttributeValue)(attribute.name, attribute.value);
|
|
401
436
|
if (!sanitizedValue || typeof attribute?.value === "boolean") {
|
|
402
437
|
return false;
|
|
403
438
|
}
|
|
@@ -435,13 +470,13 @@ const checkBlockedAttributes = (attribute, targetElement, isTarget) => {
|
|
|
435
470
|
if (typeof attribute.value === "function") {
|
|
436
471
|
return false;
|
|
437
472
|
}
|
|
438
|
-
if (isTarget && (0, exports.
|
|
473
|
+
if (isTarget && (0, exports.isAiNumberExist)(sanitizedValue)) {
|
|
439
474
|
return false;
|
|
440
475
|
}
|
|
441
476
|
return true;
|
|
442
477
|
};
|
|
443
|
-
exports.
|
|
444
|
-
const
|
|
478
|
+
exports.checkAiBlockedAttributes = checkAiBlockedAttributes;
|
|
479
|
+
const getAiRelationship = (a, b) => {
|
|
445
480
|
const pos = a.compareDocumentPosition(b);
|
|
446
481
|
return pos === 2
|
|
447
482
|
? "preceding"
|
|
@@ -455,18 +490,23 @@ const getRelationship = (a, b) => {
|
|
|
455
490
|
? "self"
|
|
456
491
|
: "";
|
|
457
492
|
};
|
|
458
|
-
exports.
|
|
459
|
-
const
|
|
460
|
-
|
|
493
|
+
exports.getAiRelationship = getAiRelationship;
|
|
494
|
+
const isAiSvg = (element) => {
|
|
495
|
+
if (!element || element.nodeType !== 1)
|
|
496
|
+
return false;
|
|
497
|
+
const svgClass = element.ownerDocument?.defaultView?.SVGElement;
|
|
498
|
+
if (svgClass && element instanceof svgClass)
|
|
499
|
+
return true;
|
|
500
|
+
return element.tagName?.toLowerCase() === "svg" || element.namespaceURI === "http://www.w3.org/2000/svg";
|
|
461
501
|
};
|
|
462
|
-
exports.
|
|
463
|
-
const
|
|
502
|
+
exports.isAiSvg = isAiSvg;
|
|
503
|
+
const replaceAiTempAttributes = (str) => {
|
|
464
504
|
if (!str)
|
|
465
505
|
return str;
|
|
466
506
|
return str.replace(/\b[a-zA-Z_]*disabled\b/gi, "disabled");
|
|
467
507
|
};
|
|
468
|
-
exports.
|
|
469
|
-
const
|
|
508
|
+
exports.replaceAiTempAttributes = replaceAiTempAttributes;
|
|
509
|
+
const getAiPropertyXPath = (element, docmt, prop, value, isTarget, platform) => {
|
|
470
510
|
if (value) {
|
|
471
511
|
const { tagName } = element;
|
|
472
512
|
let count;
|
|
@@ -474,18 +514,18 @@ const getPropertyXPath = (element, docmt, prop, value, isIndex, isTarget, platfo
|
|
|
474
514
|
const mergePattern = [];
|
|
475
515
|
let pattern;
|
|
476
516
|
let elementTagName = element.tagName;
|
|
477
|
-
if (value && (!isTarget || !(0, exports.
|
|
517
|
+
if (value && (!isTarget || !(0, exports.isAiNumberExist)(value))) {
|
|
478
518
|
if (!exports.reWhiteSpace.test(value)) {
|
|
479
519
|
if (platform == 'web') {
|
|
480
520
|
elementTagName = element.tagName.toLowerCase();
|
|
481
521
|
}
|
|
482
|
-
pattern = (0, exports.
|
|
522
|
+
pattern = (0, exports.buildAiPattern)(`normalize-space(${prop})=${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(value)).trim()}`, (0, exports.isAiSvg)(element), elementTagName);
|
|
483
523
|
}
|
|
484
524
|
else {
|
|
485
|
-
pattern = `//${elementTagName}[${prop}=${(0, exports.
|
|
525
|
+
pattern = `//${elementTagName}[${prop}=${(0, exports.escapeAiCharacters)(value)}]`;
|
|
486
526
|
}
|
|
487
|
-
count = (0, exports.
|
|
488
|
-
if (count === 1
|
|
527
|
+
count = (0, exports.getAiCountOfXPath)(pattern, element, docmt);
|
|
528
|
+
if (count === 1) {
|
|
489
529
|
return pattern;
|
|
490
530
|
}
|
|
491
531
|
}
|
|
@@ -496,40 +536,40 @@ const getPropertyXPath = (element, docmt, prop, value, isIndex, isTarget, platfo
|
|
|
496
536
|
const contentRes = [...new Set(splitText[0].match(/([^0-9]+)/g))];
|
|
497
537
|
if (contentRes?.length >= 1) {
|
|
498
538
|
if (contentRes[0] &&
|
|
499
|
-
(0, exports.
|
|
539
|
+
(0, exports.aiReplaceWhiteSpaces)(contentRes[0].trim())?.length > 1) {
|
|
500
540
|
if (value.startsWith(contentRes[0])) {
|
|
501
541
|
if (!exports.reWhiteSpace.test(contentRes[0])) {
|
|
502
|
-
combinePattern = `starts-with(${prop},${(0, exports.
|
|
542
|
+
combinePattern = `starts-with(${prop},${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(contentRes[0])).trim()})`;
|
|
503
543
|
}
|
|
504
544
|
else {
|
|
505
|
-
combinePattern = `starts-with(${prop},${(0, exports.
|
|
545
|
+
combinePattern = `starts-with(${prop},${(0, exports.escapeAiCharacters)(contentRes[0]).trim()})`;
|
|
506
546
|
}
|
|
507
547
|
}
|
|
508
548
|
}
|
|
509
549
|
}
|
|
510
550
|
if (contentRes?.length > 1) {
|
|
511
551
|
if (contentRes[contentRes.length - 1] &&
|
|
512
|
-
(0, exports.
|
|
552
|
+
(0, exports.aiReplaceWhiteSpaces)(contentRes[contentRes.length - 1].trim())
|
|
513
553
|
?.length > 1) {
|
|
514
554
|
if (value.endsWith(contentRes[contentRes.length - 1])) {
|
|
515
555
|
if (!exports.reWhiteSpace.test(contentRes[contentRes.length - 1])) {
|
|
516
|
-
combinePattern = `ends-with(${prop},${(0, exports.
|
|
556
|
+
combinePattern = `ends-with(${prop},${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(contentRes[contentRes.length - 1])).trim()})`;
|
|
517
557
|
}
|
|
518
558
|
else {
|
|
519
|
-
combinePattern = `ends-with(${prop},${(0, exports.
|
|
559
|
+
combinePattern = `ends-with(${prop},${(0, exports.escapeAiCharacters)(contentRes[contentRes.length - 1]).trim()})`;
|
|
520
560
|
}
|
|
521
561
|
}
|
|
522
562
|
}
|
|
523
563
|
}
|
|
524
564
|
if (combinePattern?.length) {
|
|
525
|
-
if ((0, exports.
|
|
565
|
+
if ((0, exports.isAiSvg)(element)) {
|
|
526
566
|
pattern = `//*[local-name()='${tagName}' and ${combinePattern}]`;
|
|
527
567
|
}
|
|
528
568
|
else {
|
|
529
569
|
pattern = `//${tagName}[${combinePattern}]`;
|
|
530
570
|
}
|
|
531
|
-
count = (0, exports.
|
|
532
|
-
if (count === 1
|
|
571
|
+
count = (0, exports.getAiCountOfXPath)(pattern, element, docmt);
|
|
572
|
+
if (count === 1) {
|
|
533
573
|
return pattern;
|
|
534
574
|
}
|
|
535
575
|
}
|
|
@@ -542,26 +582,26 @@ const getPropertyXPath = (element, docmt, prop, value, isIndex, isTarget, platfo
|
|
|
542
582
|
let contentRes = [...new Set(startIndexString.match(/([^0-9]+)/g))];
|
|
543
583
|
if (contentRes?.length) {
|
|
544
584
|
if (contentRes[0] &&
|
|
545
|
-
(0, exports.
|
|
585
|
+
(0, exports.aiReplaceWhiteSpaces)(contentRes[0].trim())?.length) {
|
|
546
586
|
if (value.startsWith(contentRes[0])) {
|
|
547
587
|
if (!exports.reWhiteSpace.test(contentRes[0])) {
|
|
548
|
-
combinePattern = `starts-with(${prop},${(0, exports.
|
|
588
|
+
combinePattern = `starts-with(${prop},${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(contentRes[0])).trim()})`;
|
|
549
589
|
}
|
|
550
590
|
else {
|
|
551
|
-
combinePattern = `starts-with(${prop},${(0, exports.
|
|
591
|
+
combinePattern = `starts-with(${prop},${(0, exports.escapeAiCharacters)(contentRes[0]).trim()})`;
|
|
552
592
|
}
|
|
553
593
|
}
|
|
554
594
|
}
|
|
555
595
|
}
|
|
556
596
|
if (combinePattern?.length) {
|
|
557
|
-
if ((0, exports.
|
|
597
|
+
if ((0, exports.isAiSvg)(element)) {
|
|
558
598
|
pattern = `//*[local-name()='${tagName}' and ${combinePattern}]`;
|
|
559
599
|
}
|
|
560
600
|
else {
|
|
561
601
|
pattern = `//${tagName}[${combinePattern}]`;
|
|
562
602
|
}
|
|
563
|
-
count = (0, exports.
|
|
564
|
-
if (count === 1
|
|
603
|
+
count = (0, exports.getAiCountOfXPath)(pattern, element, docmt);
|
|
604
|
+
if (count === 1) {
|
|
565
605
|
return pattern;
|
|
566
606
|
}
|
|
567
607
|
}
|
|
@@ -571,107 +611,100 @@ const getPropertyXPath = (element, docmt, prop, value, isIndex, isTarget, platfo
|
|
|
571
611
|
contentRes = [...new Set(endIndexString.match(/([^0-9]+)/g))];
|
|
572
612
|
if (contentRes?.length) {
|
|
573
613
|
if (contentRes[0] &&
|
|
574
|
-
(0, exports.
|
|
614
|
+
(0, exports.aiReplaceWhiteSpaces)(contentRes[0].trim())?.length > 3) {
|
|
575
615
|
if (value.endsWith(contentRes[0])) {
|
|
576
616
|
if (!exports.reWhiteSpace.test(contentRes[0])) {
|
|
577
|
-
combinePattern = `ends-with(${prop},${(0, exports.
|
|
617
|
+
combinePattern = `ends-with(${prop},${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(contentRes[0])).trim()})`;
|
|
578
618
|
}
|
|
579
619
|
else {
|
|
580
|
-
combinePattern = `ends-with(${prop},${(0, exports.
|
|
620
|
+
combinePattern = `ends-with(${prop},${(0, exports.escapeAiCharacters)(contentRes[0]).trim()})`;
|
|
581
621
|
}
|
|
582
622
|
}
|
|
583
623
|
}
|
|
584
624
|
}
|
|
585
625
|
if (combinePattern?.length) {
|
|
586
|
-
if ((0, exports.
|
|
626
|
+
if ((0, exports.isAiSvg)(element)) {
|
|
587
627
|
pattern = `//*[local-name()='${tagName}' and ${combinePattern}]`;
|
|
588
628
|
}
|
|
589
629
|
else {
|
|
590
630
|
pattern = `//${tagName}[${combinePattern}]`;
|
|
591
631
|
}
|
|
592
|
-
count = (0, exports.
|
|
593
|
-
if (count === 1
|
|
632
|
+
count = (0, exports.getAiCountOfXPath)(pattern, element, docmt);
|
|
633
|
+
if (count === 1) {
|
|
594
634
|
return pattern;
|
|
595
635
|
}
|
|
596
636
|
}
|
|
597
637
|
}
|
|
598
638
|
}
|
|
599
639
|
}
|
|
600
|
-
if (value && isTarget && (0, exports.
|
|
640
|
+
if (value && isTarget && (0, exports.isAiNumberExist)(value)) {
|
|
601
641
|
const contentRes = [...new Set(value.match(/([^0-9]+)/g))];
|
|
602
642
|
if (contentRes?.length) {
|
|
603
643
|
for (let i = 0; i < contentRes?.length; i++) {
|
|
604
644
|
if (contentRes[i] &&
|
|
605
|
-
(0, exports.
|
|
645
|
+
(0, exports.aiReplaceWhiteSpaces)(contentRes[i].trim())?.length > 1) {
|
|
606
646
|
if (!exports.reWhiteSpace.test(contentRes[i])) {
|
|
607
|
-
mergePattern.push(`contains(${prop},${(0, exports.
|
|
647
|
+
mergePattern.push(`contains(${prop},${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(contentRes[i])).trim()})`);
|
|
608
648
|
}
|
|
609
649
|
else {
|
|
610
|
-
mergePattern.push(`contains(${prop},${(0, exports.
|
|
650
|
+
mergePattern.push(`contains(${prop},${(0, exports.escapeAiCharacters)(contentRes[i].trim()).trim()})`);
|
|
611
651
|
}
|
|
612
652
|
}
|
|
613
653
|
}
|
|
614
654
|
}
|
|
615
655
|
if (mergePattern?.length) {
|
|
616
|
-
if ((0, exports.
|
|
656
|
+
if ((0, exports.isAiSvg)(element)) {
|
|
617
657
|
pattern = `//*[local-name()='${tagName}' and ${mergePattern.join(" and ")}]`;
|
|
618
658
|
}
|
|
619
659
|
else {
|
|
620
660
|
pattern = `//${tagName}[${mergePattern.join(" and ")}]`;
|
|
621
661
|
}
|
|
622
|
-
count = (0, exports.
|
|
623
|
-
if (count === 1
|
|
662
|
+
count = (0, exports.getAiCountOfXPath)(pattern, element, docmt);
|
|
663
|
+
if (count === 1) {
|
|
624
664
|
return pattern;
|
|
625
665
|
}
|
|
626
666
|
}
|
|
627
667
|
}
|
|
628
|
-
if ((0, exports.
|
|
668
|
+
if ((0, exports.isAiSvg)(element)) {
|
|
629
669
|
pattern = `//*[local-name()='${tagName}' and text()]`;
|
|
630
670
|
}
|
|
631
671
|
else {
|
|
632
672
|
pattern = `//${tagName}[text()]`;
|
|
633
673
|
}
|
|
634
|
-
count = (0, exports.
|
|
635
|
-
if (count === 1
|
|
674
|
+
count = (0, exports.getAiCountOfXPath)(pattern, element, docmt);
|
|
675
|
+
if (count === 1) {
|
|
636
676
|
return pattern;
|
|
637
677
|
}
|
|
638
678
|
}
|
|
639
679
|
};
|
|
640
|
-
exports.
|
|
641
|
-
const
|
|
680
|
+
exports.getAiPropertyXPath = getAiPropertyXPath;
|
|
681
|
+
const getAiAbsoluteXPath = (domNode, docmt) => {
|
|
642
682
|
try {
|
|
643
|
-
if (!domNode) {
|
|
683
|
+
if (!domNode || domNode.nodeType !== 1) {
|
|
644
684
|
return "";
|
|
645
685
|
}
|
|
646
|
-
let xpathe = (0, exports.
|
|
686
|
+
let xpathe = (0, exports.isAiSvg)(domNode)
|
|
647
687
|
? `/*[local-name()='${domNode.tagName}']`
|
|
648
688
|
: `/${domNode.tagName}`;
|
|
649
689
|
// // If this node has siblings of the same tagName, get the index of this node
|
|
650
|
-
|
|
690
|
+
const parent = domNode.parentElement || domNode.parentNode;
|
|
691
|
+
if (parent && parent.nodeType === 1) {
|
|
651
692
|
// Get the siblings
|
|
652
693
|
const childNodes = Array.prototype.slice
|
|
653
|
-
.call(
|
|
654
|
-
.filter((childNode) => childNode.tagName === domNode.tagName);
|
|
694
|
+
.call(parent.children || parent.childNodes, 0)
|
|
695
|
+
.filter((childNode) => childNode && childNode.nodeType === 1 && childNode.tagName === domNode.tagName);
|
|
655
696
|
// // If there's more than one sibling, append the index
|
|
656
697
|
if (childNodes.length > 1) {
|
|
657
698
|
const index = childNodes.indexOf(domNode);
|
|
658
699
|
xpathe += `[${index + 1}]`;
|
|
659
700
|
}
|
|
660
701
|
}
|
|
661
|
-
else if (domNode instanceof HTMLElement) {
|
|
662
|
-
if (domNode.offsetParent) {
|
|
663
|
-
const childNodes = Array.prototype.slice
|
|
664
|
-
.call(domNode.offsetParent.children, 0)
|
|
665
|
-
.filter((childNode) => childNode.tagName === domNode.tagName);
|
|
666
|
-
// // If there's more than one sibling, append the index
|
|
667
|
-
if (childNodes.length > 1) {
|
|
668
|
-
const index = childNodes.indexOf(domNode);
|
|
669
|
-
xpathe += `[${index + 1}]`;
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
702
|
// // Make a recursive call to this nodes parents and prepend it to this xpath
|
|
674
|
-
|
|
703
|
+
const parentNode = domNode.parentElement || domNode.parentNode;
|
|
704
|
+
if (parentNode && parentNode.nodeType === 1) {
|
|
705
|
+
return (0, exports.getAiAbsoluteXPath)(parentNode, docmt) + xpathe;
|
|
706
|
+
}
|
|
707
|
+
return xpathe;
|
|
675
708
|
}
|
|
676
709
|
catch (error) {
|
|
677
710
|
// If there's an unexpected exception, abort and don't get an XPath
|
|
@@ -679,10 +712,12 @@ const getAbsoluteXPath = (domNode, docmt) => {
|
|
|
679
712
|
return "";
|
|
680
713
|
}
|
|
681
714
|
};
|
|
682
|
-
exports.
|
|
683
|
-
const
|
|
715
|
+
exports.getAiAbsoluteXPath = getAiAbsoluteXPath;
|
|
716
|
+
const getAIRelativeXPath = (domNode, docmt, _isTarget = false, attributesArray, platform = "web") => {
|
|
684
717
|
try {
|
|
685
|
-
|
|
718
|
+
if (!domNode || domNode.nodeType !== 1) {
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
686
721
|
// Check if the result for this node is already cached
|
|
687
722
|
if (relativeXPathCache.has(domNode)) {
|
|
688
723
|
return relativeXPathCache.get(domNode);
|
|
@@ -690,137 +725,108 @@ const getRelativeXPath = (domNode, docmt, isIndex, isTarget = false, attributesA
|
|
|
690
725
|
// Initialize an array to hold parts of the XPath
|
|
691
726
|
const xpathParts = [];
|
|
692
727
|
let currentNode = domNode;
|
|
728
|
+
let hasUniqueAttr = false;
|
|
693
729
|
// Traverse up the DOM tree iteratively instead of using recursion
|
|
694
|
-
while (currentNode) {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
: currentNode.attributes;
|
|
730
|
+
while (currentNode && currentNode.nodeType === 1) {
|
|
731
|
+
const isTargetNode = domNode === currentNode;
|
|
732
|
+
const attributes = isTargetNode
|
|
733
|
+
? (attributesArray ?? Array.from(currentNode.attributes))
|
|
734
|
+
: Array.from(currentNode.attributes);
|
|
700
735
|
// Loop through attributes to check for unique identifiers
|
|
701
|
-
for (const attrName of
|
|
702
|
-
|
|
703
|
-
|
|
736
|
+
for (const attrName of attributes) {
|
|
737
|
+
const checkTarget = platform === "android" ? true : (isTargetNode ? _isTarget : false);
|
|
738
|
+
if ((0, exports.checkAiBlockedAttributes)(attrName, currentNode, checkTarget)) {
|
|
739
|
+
const attrValue = (0, exports.sanitizeAiAttributeValue)(attrName.name, attrName.nodeValue);
|
|
740
|
+
if (platform === "android" && attrValue && (0, exports.isAiNumberExist)(attrValue)) {
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
704
743
|
const elementName = attrName.name;
|
|
705
744
|
// Construct an XPath based on attribute
|
|
706
|
-
xpathe = (0, exports.
|
|
707
|
-
let othersWithAttr = 0;
|
|
745
|
+
const xpathe = (0, exports.getAiXpathString)(currentNode, elementName, attrValue);
|
|
708
746
|
if (xpathe) {
|
|
709
|
-
othersWithAttr = (0, exports.
|
|
747
|
+
const othersWithAttr = (0, exports.getAiCountOfXPath)(xpathe, currentNode, docmt);
|
|
710
748
|
if (othersWithAttr === 1) {
|
|
711
|
-
xpathParts.unshift((0, exports.
|
|
749
|
+
xpathParts.unshift((0, exports.replaceAiTempAttributes)(xpathe));
|
|
712
750
|
hasUniqueAttr = true;
|
|
713
751
|
break;
|
|
714
752
|
}
|
|
715
753
|
}
|
|
716
|
-
if (othersWithAttr > 1 && isIndex) {
|
|
717
|
-
xpathe = (0, exports.findXpathWithIndex)(xpathe, currentNode, docmt, othersWithAttr);
|
|
718
|
-
if (xpathe) {
|
|
719
|
-
xpathParts.unshift((0, exports.replaceTempAttributes)(xpathe));
|
|
720
|
-
hasUniqueAttr = true;
|
|
721
|
-
break;
|
|
722
|
-
}
|
|
723
|
-
// return replaceTempAttributes(xpathe);
|
|
724
|
-
}
|
|
725
754
|
}
|
|
726
755
|
}
|
|
756
|
+
if (hasUniqueAttr) {
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
727
759
|
if (currentNode.textContent) {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
xpathe = (0, exports.isSvg)(currentNode)
|
|
733
|
-
? `//*[local-name()='${currentNode.tagName}' and normalize-space(.)=${(0, exports.escapeCharacters)((0, exports.getFilteredText)(currentNode))}]`
|
|
734
|
-
: `//${currentNode.tagName || "*"}[normalize-space(.)=${(0, exports.escapeCharacters)((0, exports.getFilteredText)(currentNode))}]`;
|
|
735
|
-
}
|
|
736
|
-
else {
|
|
737
|
-
xpathe = (0, exports.isSvg)(currentNode)
|
|
738
|
-
? `//*[local-name()='${currentNode.tagName}' and .=${(0, exports.escapeCharacters)((0, exports.getFilteredText)(currentNode))}]`
|
|
739
|
-
: `//${currentNode.tagName || "*"}[.=${(0, exports.escapeCharacters)((0, exports.getFilteredText)(currentNode))}]`;
|
|
740
|
-
}
|
|
741
|
-
const othersWithAttr = (0, exports.getCountOfXPath)(xpathe, currentNode, docmt);
|
|
742
|
-
if (othersWithAttr === 1) {
|
|
743
|
-
return xpathe;
|
|
744
|
-
}
|
|
745
|
-
if (othersWithAttr > 1 && isIndex) {
|
|
746
|
-
xpathe = (0, exports.findXpathWithIndex)(xpathe, currentNode, docmt, othersWithAttr);
|
|
747
|
-
return xpathe;
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
else {
|
|
751
|
-
const combinePattern = [];
|
|
752
|
-
const contentRes = [
|
|
753
|
-
...new Set((0, exports.getFilteredText)(currentNode).match(/([^0-9]+)/g))
|
|
754
|
-
];
|
|
760
|
+
const canCheckText = platform === "android"
|
|
761
|
+
? !(0, exports.isAiNumberExist)(currentNode.textContent)
|
|
762
|
+
: (!isTargetNode || !_isTarget || !(0, exports.isAiNumberExist)(currentNode.textContent));
|
|
763
|
+
if (canCheckText) {
|
|
755
764
|
const reWhiteSpace = new RegExp(/^[\S]+( [\S]+)*$/gi);
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
}
|
|
763
|
-
else {
|
|
764
|
-
combinePattern.push(`contains(.,${(0, exports.escapeCharacters)(contentRes[i].trim()).trim()})`);
|
|
765
|
-
}
|
|
766
|
-
}
|
|
765
|
+
const filteredText = (0, exports.getAiFilteredText)(currentNode);
|
|
766
|
+
if (filteredText && (platform !== "android" || !(0, exports.isAiNumberExist)(filteredText))) {
|
|
767
|
+
let xpathe = "";
|
|
768
|
+
if (!reWhiteSpace.test(currentNode.textContent)) {
|
|
769
|
+
xpathe = (0, exports.isAiSvg)(currentNode)
|
|
770
|
+
? `//*[local-name()='${currentNode.tagName}' and normalize-space(.)=${(0, exports.escapeAiCharacters)(filteredText)}]`
|
|
771
|
+
: `//${currentNode.tagName || "*"}[normalize-space(.)=${(0, exports.escapeAiCharacters)(filteredText)}]`;
|
|
767
772
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
: `//${currentNode.tagName || "*"}[${combinePattern.join(" and ")}]`;
|
|
773
|
-
const othersWithAttr = (0, exports.getCountOfXPath)(xpathe, currentNode, docmt);
|
|
774
|
-
if (othersWithAttr === 1) {
|
|
775
|
-
return xpathe;
|
|
773
|
+
else {
|
|
774
|
+
xpathe = (0, exports.isAiSvg)(currentNode)
|
|
775
|
+
? `//*[local-name()='${currentNode.tagName}' and .=${(0, exports.escapeAiCharacters)(filteredText)}]`
|
|
776
|
+
: `//${currentNode.tagName || "*"}[.=${(0, exports.escapeAiCharacters)(filteredText)}]`;
|
|
776
777
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
778
|
+
const othersWithAttr = (0, exports.getAiCountOfXPath)(xpathe, currentNode, docmt);
|
|
779
|
+
if (othersWithAttr === 1) {
|
|
780
|
+
xpathParts.unshift((0, exports.replaceAiTempAttributes)(xpathe));
|
|
781
|
+
hasUniqueAttr = true;
|
|
782
|
+
break;
|
|
780
783
|
}
|
|
781
784
|
}
|
|
782
785
|
}
|
|
783
786
|
}
|
|
784
787
|
// If no unique attribute was found, construct XPath by tag name
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
788
|
+
const currentTag = currentNode.tagName;
|
|
789
|
+
const currentEl = currentNode;
|
|
790
|
+
let tagBasedXPath = (0, exports.isAiSvg)(currentNode)
|
|
791
|
+
? `/*[local-name()='${currentTag}']`
|
|
792
|
+
: `/${currentTag}`;
|
|
793
|
+
// Handle sibling nodes
|
|
794
|
+
const parent = currentNode.parentElement || currentNode.parentNode;
|
|
795
|
+
if (parent && parent.nodeType === 1) {
|
|
796
|
+
const siblings = Array.from(parent.children || parent.childNodes).filter((childNode) => childNode && childNode.nodeType === 1 && childNode.tagName === currentTag);
|
|
797
|
+
// Append index to distinguish between siblings
|
|
798
|
+
if (siblings.length > 1) {
|
|
799
|
+
const index = siblings.indexOf(currentEl);
|
|
800
|
+
tagBasedXPath += `[${index + 1}]`;
|
|
797
801
|
}
|
|
798
|
-
// Add the constructed tag-based XPath to the parts array
|
|
799
|
-
xpathParts.unshift(tagBasedXPath);
|
|
800
|
-
}
|
|
801
|
-
else {
|
|
802
|
-
break;
|
|
803
802
|
}
|
|
803
|
+
// Add the constructed tag-based XPath to the parts array
|
|
804
|
+
xpathParts.unshift(tagBasedXPath);
|
|
804
805
|
// Move up to the parent node for the next iteration
|
|
805
|
-
currentNode =
|
|
806
|
+
currentNode = parent;
|
|
806
807
|
}
|
|
807
808
|
// Combine all parts into the final XPath
|
|
808
|
-
const finalXPath =
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
809
|
+
const finalXPath = xpathParts.join("");
|
|
810
|
+
if (finalXPath && finalXPath.startsWith("//")) {
|
|
811
|
+
const count = (0, exports.getAiCountOfXPath)(finalXPath, domNode, docmt);
|
|
812
|
+
if (count === 1) {
|
|
813
|
+
relativeXPathCache.set(domNode, finalXPath);
|
|
814
|
+
return finalXPath;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return null;
|
|
812
818
|
}
|
|
813
819
|
catch (error) {
|
|
814
|
-
logData_1.logger.error(error);
|
|
820
|
+
logData_1.logger.error("error in getAIRelativeXPath", error);
|
|
815
821
|
return null;
|
|
816
822
|
}
|
|
817
823
|
};
|
|
818
|
-
exports.
|
|
819
|
-
const
|
|
824
|
+
exports.getAIRelativeXPath = getAIRelativeXPath;
|
|
825
|
+
const getAiCombinationXpath = (attribute, domNode) => {
|
|
820
826
|
const combinePattern = [];
|
|
821
827
|
let pattern;
|
|
822
828
|
if (attribute &&
|
|
823
|
-
!(0, exports.
|
|
829
|
+
!(0, exports.isAiNumberExist)(attribute.value) &&
|
|
824
830
|
typeof attribute.nodeValue !== "function" // &&
|
|
825
831
|
// !modifiedElementAttributes?.find(
|
|
826
832
|
// (x) => x.element === domNode && x.attributeName === attribute.name
|
|
@@ -830,30 +836,30 @@ const getCombinationXpath = (attribute, domNode) => {
|
|
|
830
836
|
if (contentRes?.length) {
|
|
831
837
|
for (let i = 0; i < contentRes?.length; i++) {
|
|
832
838
|
if (contentRes[i] &&
|
|
833
|
-
(0, exports.
|
|
839
|
+
(0, exports.aiReplaceWhiteSpaces)(contentRes[i].trim())?.length > 2) {
|
|
834
840
|
if (!exports.reWhiteSpace.test(contentRes[i])) {
|
|
835
|
-
combinePattern.push(`contains(@${attribute.name},${(0, exports.
|
|
841
|
+
combinePattern.push(`contains(@${attribute.name},${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(contentRes[i])).trim()})`);
|
|
836
842
|
}
|
|
837
843
|
else {
|
|
838
|
-
combinePattern.push(`contains(@${attribute.name},${(0, exports.
|
|
844
|
+
combinePattern.push(`contains(@${attribute.name},${(0, exports.escapeAiCharacters)(contentRes[i].trim())})`);
|
|
839
845
|
}
|
|
840
846
|
}
|
|
841
847
|
}
|
|
842
848
|
}
|
|
843
849
|
if (combinePattern?.length) {
|
|
844
|
-
pattern = (0, exports.
|
|
850
|
+
pattern = (0, exports.isAiSvg)(domNode)
|
|
845
851
|
? `//*[local-name()='${domNode.tagName}' and ${combinePattern.join(" and ")}]`
|
|
846
852
|
: `//${domNode.tagName}[${combinePattern.join(" and ")}]`;
|
|
847
853
|
return pattern;
|
|
848
854
|
}
|
|
849
855
|
}
|
|
850
856
|
};
|
|
851
|
-
exports.
|
|
852
|
-
const
|
|
857
|
+
exports.getAiCombinationXpath = getAiCombinationXpath;
|
|
858
|
+
const getAiAttributeCombinationXpath = (domNode, docmt, uniqueAttributes, isTarget, platform) => {
|
|
853
859
|
try {
|
|
854
|
-
const candidateAttributes = uniqueAttributes.filter((attr) => (0, exports.
|
|
855
|
-
const
|
|
856
|
-
const attrValue = (0, exports.
|
|
860
|
+
const candidateAttributes = uniqueAttributes.filter((attr) => (0, exports.checkAiBlockedAttributes)(attr, domNode, isTarget));
|
|
861
|
+
const buildAiAttributeConditions = (attribute) => {
|
|
862
|
+
const attrValue = (0, exports.sanitizeAiAttributeValue)(attribute.name, attribute.nodeValue);
|
|
857
863
|
if (!attrValue)
|
|
858
864
|
return [];
|
|
859
865
|
if (attribute.name === "class") {
|
|
@@ -865,10 +871,10 @@ const getAttributeCombinationXpath = (domNode, docmt, uniqueAttributes, isTarget
|
|
|
865
871
|
return [];
|
|
866
872
|
const rankedTokens = classTokens
|
|
867
873
|
.map((token) => {
|
|
868
|
-
const xpath = (0, exports.
|
|
874
|
+
const xpath = (0, exports.buildAiPattern)(`contains(@class,${(0, exports.escapeAiCharacters)(token)})`, (0, exports.isAiSvg)(domNode), platform === "web" ? domNode.tagName.toLowerCase() : domNode.localName);
|
|
869
875
|
return {
|
|
870
876
|
token,
|
|
871
|
-
count:
|
|
877
|
+
count: getAiTagOnlyXpathCandidateCount(xpath, domNode, docmt)
|
|
872
878
|
};
|
|
873
879
|
})
|
|
874
880
|
.sort((left, right) => {
|
|
@@ -878,7 +884,7 @@ const getAttributeCombinationXpath = (domNode, docmt, uniqueAttributes, isTarget
|
|
|
878
884
|
return right.token.length - left.token.length;
|
|
879
885
|
});
|
|
880
886
|
return rankedTokens[0]?.token
|
|
881
|
-
? [`contains(@class,${(0, exports.
|
|
887
|
+
? [`contains(@class,${(0, exports.escapeAiCharacters)(rankedTokens[0].token)})`]
|
|
882
888
|
: [];
|
|
883
889
|
}
|
|
884
890
|
if (!exports.reWhiteSpace.test(attrValue)) {
|
|
@@ -886,22 +892,22 @@ const getAttributeCombinationXpath = (domNode, docmt, uniqueAttributes, isTarget
|
|
|
886
892
|
}
|
|
887
893
|
return [`@${attribute.name}="${attrValue}"`];
|
|
888
894
|
};
|
|
889
|
-
const
|
|
890
|
-
const rawText = (0, exports.
|
|
895
|
+
const getAiTextConditions = () => {
|
|
896
|
+
const rawText = (0, exports.aiReplaceWhiteSpaces)((0, exports.getAiTextContent)(domNode)?.trim() || "");
|
|
891
897
|
if (!rawText || rawText.length > 80 || /^\d+$/.test(rawText)) {
|
|
892
898
|
return [];
|
|
893
899
|
}
|
|
894
900
|
const conditions = new Set();
|
|
895
901
|
if (exports.reWhiteSpace.test(rawText) && rawText.length <= 40) {
|
|
896
|
-
conditions.add(`text()=${(0, exports.
|
|
902
|
+
conditions.add(`text()=${(0, exports.escapeAiCharacters)(rawText)}`);
|
|
897
903
|
}
|
|
898
904
|
if (rawText.includes(" ")) {
|
|
899
|
-
conditions.add(`normalize-space(text())=${(0, exports.
|
|
905
|
+
conditions.add(`normalize-space(text())=${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(rawText))}`);
|
|
900
906
|
}
|
|
901
|
-
conditions.add(`contains(text(),${(0, exports.
|
|
907
|
+
conditions.add(`contains(text(),${(0, exports.escapeAiCharacters)(rawText)})`);
|
|
902
908
|
return Array.from(conditions);
|
|
903
909
|
};
|
|
904
|
-
const
|
|
910
|
+
const generateAiAttributeCombinations = (attributes, combinationSize) => {
|
|
905
911
|
const results = [];
|
|
906
912
|
const build = (startIndex, currentGroup) => {
|
|
907
913
|
if (currentGroup.length === combinationSize) {
|
|
@@ -917,29 +923,30 @@ const getAttributeCombinationXpath = (domNode, docmt, uniqueAttributes, isTarget
|
|
|
917
923
|
build(0, []);
|
|
918
924
|
return results;
|
|
919
925
|
};
|
|
920
|
-
const
|
|
926
|
+
const buildAiXPath = (conditions) => (0, exports.isAiSvg)(domNode)
|
|
921
927
|
? `//*[local-name()='${domNode.tagName}' and ${conditions.join(" and ")}]`
|
|
922
928
|
: `//${domNode.tagName}[${conditions.join(" and ")}]`;
|
|
923
|
-
const
|
|
929
|
+
const tryAiAttributeOnlyCombinations = () => {
|
|
924
930
|
if (candidateAttributes.length < 2) {
|
|
925
931
|
return undefined;
|
|
926
932
|
}
|
|
927
|
-
|
|
928
|
-
|
|
933
|
+
const maxCombinationSize = Math.min(2, candidateAttributes.length);
|
|
934
|
+
for (let combinationSize = 2; combinationSize <= maxCombinationSize; combinationSize++) {
|
|
935
|
+
const attributeGroups = generateAiAttributeCombinations(candidateAttributes, combinationSize);
|
|
929
936
|
for (const attributeGroup of attributeGroups) {
|
|
930
937
|
const xpathConditions = [];
|
|
931
938
|
for (const attribute of attributeGroup) {
|
|
932
|
-
const attributeConditions =
|
|
939
|
+
const attributeConditions = buildAiAttributeConditions(attribute);
|
|
933
940
|
if (!attributeConditions.length)
|
|
934
941
|
continue;
|
|
935
942
|
xpathConditions.push(...attributeConditions);
|
|
936
943
|
}
|
|
937
944
|
if (xpathConditions.length < 2)
|
|
938
945
|
continue;
|
|
939
|
-
const xpath =
|
|
946
|
+
const xpath = buildAiXPath(xpathConditions);
|
|
940
947
|
let matchCount;
|
|
941
948
|
try {
|
|
942
|
-
matchCount = (0, exports.
|
|
949
|
+
matchCount = (0, exports.getAiCountOfXPath)(xpath, domNode, docmt);
|
|
943
950
|
}
|
|
944
951
|
catch {
|
|
945
952
|
continue;
|
|
@@ -951,29 +958,30 @@ const getAttributeCombinationXpath = (domNode, docmt, uniqueAttributes, isTarget
|
|
|
951
958
|
}
|
|
952
959
|
return undefined;
|
|
953
960
|
};
|
|
954
|
-
const attributeOnlyXpath =
|
|
961
|
+
const attributeOnlyXpath = tryAiAttributeOnlyCombinations();
|
|
955
962
|
if (attributeOnlyXpath) {
|
|
956
963
|
return attributeOnlyXpath;
|
|
957
964
|
}
|
|
958
|
-
const textConditions =
|
|
965
|
+
const textConditions = getAiTextConditions();
|
|
959
966
|
if (!textConditions.length || !candidateAttributes.length) {
|
|
960
967
|
return;
|
|
961
968
|
}
|
|
962
|
-
|
|
963
|
-
|
|
969
|
+
const maxCombinationSize = Math.min(2, candidateAttributes.length);
|
|
970
|
+
for (let combinationSize = 1; combinationSize <= maxCombinationSize; combinationSize++) {
|
|
971
|
+
const attributeGroups = generateAiAttributeCombinations(candidateAttributes, combinationSize);
|
|
964
972
|
for (const attributeGroup of attributeGroups) {
|
|
965
973
|
const attributeConditions = [];
|
|
966
974
|
for (const attribute of attributeGroup) {
|
|
967
|
-
attributeConditions.push(...
|
|
975
|
+
attributeConditions.push(...buildAiAttributeConditions(attribute));
|
|
968
976
|
}
|
|
969
977
|
if (!attributeConditions.length) {
|
|
970
978
|
continue;
|
|
971
979
|
}
|
|
972
980
|
for (const textCondition of textConditions) {
|
|
973
981
|
const xpathConditions = [...attributeConditions, textCondition];
|
|
974
|
-
const xpath =
|
|
982
|
+
const xpath = buildAiXPath(xpathConditions);
|
|
975
983
|
try {
|
|
976
|
-
if ((0, exports.
|
|
984
|
+
if ((0, exports.getAiCountOfXPath)(xpath, domNode, docmt) === 1) {
|
|
977
985
|
return xpath;
|
|
978
986
|
}
|
|
979
987
|
}
|
|
@@ -988,70 +996,70 @@ const getAttributeCombinationXpath = (domNode, docmt, uniqueAttributes, isTarget
|
|
|
988
996
|
logData_1.logger.error(`XPath generation error: ${JSON.stringify(error, null, 2)}`);
|
|
989
997
|
}
|
|
990
998
|
};
|
|
991
|
-
exports.
|
|
992
|
-
const
|
|
993
|
-
const isSvgElement = (0, exports.
|
|
999
|
+
exports.getAiAttributeCombinationXpath = getAiAttributeCombinationXpath;
|
|
1000
|
+
const intermediateAiXpathStep = (targetElemt, attr, isTarget) => {
|
|
1001
|
+
const isSvgElement = (0, exports.isAiSvg)(targetElemt);
|
|
994
1002
|
let expression = "";
|
|
995
|
-
if ((0, exports.
|
|
996
|
-
const attrValue = (0, exports.
|
|
1003
|
+
if ((0, exports.checkAiBlockedAttributes)(attr, targetElemt, isTarget)) {
|
|
1004
|
+
const attrValue = (0, exports.sanitizeAiAttributeValue)(attr.name, attr.value);
|
|
997
1005
|
const elementName = attr.name;
|
|
998
1006
|
if (!exports.reWhiteSpace.test(attrValue)) {
|
|
999
1007
|
expression = isSvgElement
|
|
1000
|
-
? `*[local-name()='${targetElemt.tagName}' and normalize-space(@${elementName})=${(0, exports.
|
|
1001
|
-
: `${targetElemt.tagName || "*"}[normalize-space(@${elementName})=${(0, exports.
|
|
1008
|
+
? `*[local-name()='${targetElemt.tagName}' and normalize-space(@${elementName})=${(0, exports.escapeAiCharacters)(attrValue)}]`
|
|
1009
|
+
: `${targetElemt.tagName || "*"}[normalize-space(@${elementName})=${(0, exports.escapeAiCharacters)(attrValue)}]`;
|
|
1002
1010
|
}
|
|
1003
1011
|
else {
|
|
1004
1012
|
expression = isSvgElement
|
|
1005
|
-
? `*[local-name()='${targetElemt.tagName}' and @${elementName}=${(0, exports.
|
|
1006
|
-
: `${targetElemt.tagName || "*"}[@${elementName}=${(0, exports.
|
|
1013
|
+
? `*[local-name()='${targetElemt.tagName}' and @${elementName}=${(0, exports.escapeAiCharacters)(attrValue)}]`
|
|
1014
|
+
: `${targetElemt.tagName || "*"}[@${elementName}=${(0, exports.escapeAiCharacters)(attrValue)}]`;
|
|
1007
1015
|
}
|
|
1008
1016
|
}
|
|
1009
1017
|
return expression;
|
|
1010
1018
|
};
|
|
1011
|
-
exports.
|
|
1012
|
-
const
|
|
1019
|
+
exports.intermediateAiXpathStep = intermediateAiXpathStep;
|
|
1020
|
+
const getAiFilteredTextXPath = (node) => {
|
|
1013
1021
|
if (!node.textContent)
|
|
1014
1022
|
return "";
|
|
1015
|
-
const filteredText = (0, exports.
|
|
1023
|
+
const filteredText = (0, exports.getAiFilteredText)(node);
|
|
1016
1024
|
let xpathe;
|
|
1017
1025
|
if (!exports.reWhiteSpace.test(filteredText)) {
|
|
1018
|
-
xpathe = (0, exports.
|
|
1019
|
-
? `//*[local-name()='${node.tagName}' and normalize-space(.)=${(0, exports.
|
|
1020
|
-
: `//${node.tagName || "*"}[normalize-space(.)=${(0, exports.
|
|
1026
|
+
xpathe = (0, exports.isAiSvg)(node)
|
|
1027
|
+
? `//*[local-name()='${node.tagName}' and normalize-space(.)=${(0, exports.escapeAiCharacters)(filteredText)}]`
|
|
1028
|
+
: `//${node.tagName || "*"}[normalize-space(.)=${(0, exports.escapeAiCharacters)(filteredText)}]`;
|
|
1021
1029
|
}
|
|
1022
1030
|
else {
|
|
1023
|
-
xpathe = (0, exports.
|
|
1024
|
-
? `//*[local-name()='${node.tagName}' and .=${(0, exports.
|
|
1025
|
-
: `//${node.tagName || "*"}[.=${(0, exports.
|
|
1031
|
+
xpathe = (0, exports.isAiSvg)(node)
|
|
1032
|
+
? `//*[local-name()='${node.tagName}' and .=${(0, exports.escapeAiCharacters)(filteredText)}]`
|
|
1033
|
+
: `//${node.tagName || "*"}[.=${(0, exports.escapeAiCharacters)(filteredText)}]`;
|
|
1026
1034
|
}
|
|
1027
1035
|
return xpathe;
|
|
1028
1036
|
};
|
|
1029
|
-
exports.
|
|
1030
|
-
const
|
|
1037
|
+
exports.getAiFilteredTextXPath = getAiFilteredTextXPath;
|
|
1038
|
+
const getAiNormalizedPropertyXPath = (element, prop, value, platform) => {
|
|
1031
1039
|
const elementTagName = platform === "web" ? element.tagName.toLowerCase() : element.localName;
|
|
1032
|
-
const xpath = (0, exports.
|
|
1040
|
+
const xpath = (0, exports.buildAiPattern)(`normalize-space(${prop})=${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(value)).trim()}`, (0, exports.isAiSvg)(element), elementTagName);
|
|
1033
1041
|
// logger.info("normalizedPropertyXPath", xpath)
|
|
1034
1042
|
return xpath;
|
|
1035
1043
|
};
|
|
1036
|
-
exports.
|
|
1037
|
-
const
|
|
1044
|
+
exports.getAiNormalizedPropertyXPath = getAiNormalizedPropertyXPath;
|
|
1045
|
+
const getAiStartsWithPropertyXPath = (element, prop, value, platform) => {
|
|
1038
1046
|
const elementTagName = platform === "web" ? element.tagName.toLowerCase() : element.localName;
|
|
1039
|
-
const xpath = (0, exports.
|
|
1040
|
-
// logger.info("
|
|
1047
|
+
const xpath = (0, exports.buildAiPattern)(`starts-with(${prop},${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(value)).trim()})`, (0, exports.isAiSvg)(element), elementTagName);
|
|
1048
|
+
// logger.info("getAiStartsWithPropertyXPath", xpath)
|
|
1041
1049
|
return xpath;
|
|
1042
1050
|
};
|
|
1043
|
-
exports.
|
|
1044
|
-
const
|
|
1051
|
+
exports.getAiStartsWithPropertyXPath = getAiStartsWithPropertyXPath;
|
|
1052
|
+
const getAiContainsPropertyXPath = (element, prop, value, platform) => {
|
|
1045
1053
|
const elementTagName = platform === "web" ? element.tagName.toLowerCase() : element.localName;
|
|
1046
|
-
const xpath = (0, exports.
|
|
1047
|
-
// logger.info("
|
|
1054
|
+
const xpath = (0, exports.buildAiPattern)(`contains(${prop},${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(value)).trim()})`, (0, exports.isAiSvg)(element), elementTagName);
|
|
1055
|
+
// logger.info("getAiContainsPropertyXPath", xpath)
|
|
1048
1056
|
return xpath;
|
|
1049
1057
|
};
|
|
1050
|
-
exports.
|
|
1051
|
-
const
|
|
1058
|
+
exports.getAiContainsPropertyXPath = getAiContainsPropertyXPath;
|
|
1059
|
+
const getOrAttributesAiXPath = (element, attributes, platform) => {
|
|
1052
1060
|
const elementTagName = platform === "web" ? element.tagName.toLowerCase() : element.localName;
|
|
1053
|
-
const
|
|
1054
|
-
const attrValue = (0, exports.
|
|
1061
|
+
const buildAiAttributeCondition = (attribute) => {
|
|
1062
|
+
const attrValue = (0, exports.sanitizeAiAttributeValue)(attribute.name, attribute.value);
|
|
1055
1063
|
if (!attrValue) {
|
|
1056
1064
|
return null;
|
|
1057
1065
|
}
|
|
@@ -1064,10 +1072,10 @@ const getOrAttributesXPath = (element, attributes, platform) => {
|
|
|
1064
1072
|
element.ownerDocument;
|
|
1065
1073
|
const rankedToken = classTokens
|
|
1066
1074
|
.map((token) => {
|
|
1067
|
-
const xpath = (0, exports.
|
|
1075
|
+
const xpath = (0, exports.buildAiPattern)(`contains(@class,${(0, exports.escapeAiCharacters)(token)})`, (0, exports.isAiSvg)(element), elementTagName);
|
|
1068
1076
|
return {
|
|
1069
1077
|
token,
|
|
1070
|
-
count:
|
|
1078
|
+
count: getAiTagOnlyXpathCandidateCount(xpath, element, docmt)
|
|
1071
1079
|
};
|
|
1072
1080
|
})
|
|
1073
1081
|
.sort((left, right) => {
|
|
@@ -1077,46 +1085,46 @@ const getOrAttributesXPath = (element, attributes, platform) => {
|
|
|
1077
1085
|
return right.token.length - left.token.length;
|
|
1078
1086
|
})[0]?.token;
|
|
1079
1087
|
return rankedToken
|
|
1080
|
-
? `contains(@class,${(0, exports.
|
|
1088
|
+
? `contains(@class,${(0, exports.escapeAiCharacters)(rankedToken)})`
|
|
1081
1089
|
: null;
|
|
1082
1090
|
}
|
|
1083
1091
|
if (!exports.reWhiteSpace.test(attrValue)) {
|
|
1084
|
-
return `normalize-space(@${attribute.name})=${(0, exports.
|
|
1092
|
+
return `normalize-space(@${attribute.name})=${(0, exports.escapeAiCharacters)(attrValue)}`;
|
|
1085
1093
|
}
|
|
1086
|
-
return `@${attribute.name}=${(0, exports.
|
|
1094
|
+
return `@${attribute.name}=${(0, exports.escapeAiCharacters)(attrValue)}`;
|
|
1087
1095
|
};
|
|
1088
1096
|
const buildTextCondition = () => {
|
|
1089
|
-
const rawText = (0, exports.
|
|
1097
|
+
const rawText = (0, exports.aiReplaceWhiteSpaces)((0, exports.getAiTextContent)(element)?.trim() || "");
|
|
1090
1098
|
if (!rawText || rawText.length > 80 || /^\d+$/.test(rawText)) {
|
|
1091
1099
|
return null;
|
|
1092
1100
|
}
|
|
1093
1101
|
if (exports.reWhiteSpace.test(rawText) && rawText.length <= 40) {
|
|
1094
|
-
return `text()=${(0, exports.
|
|
1102
|
+
return `text()=${(0, exports.escapeAiCharacters)(rawText)}`;
|
|
1095
1103
|
}
|
|
1096
1104
|
if (rawText.includes(" ")) {
|
|
1097
|
-
return `normalize-space(text())=${(0, exports.
|
|
1105
|
+
return `normalize-space(text())=${(0, exports.escapeAiCharacters)(rawText)}`;
|
|
1098
1106
|
}
|
|
1099
|
-
return `contains(text(),${(0, exports.
|
|
1107
|
+
return `contains(text(),${(0, exports.escapeAiCharacters)(rawText)})`;
|
|
1100
1108
|
};
|
|
1101
1109
|
const attributeConditions = attributes
|
|
1102
|
-
.map((attribute) =>
|
|
1110
|
+
.map((attribute) => buildAiAttributeCondition(attribute))
|
|
1103
1111
|
.filter(Boolean);
|
|
1104
1112
|
if (attributeConditions.length >= 2) {
|
|
1105
|
-
return (0, exports.
|
|
1113
|
+
return (0, exports.buildAiPattern)(`${attributeConditions[0]} or ${attributeConditions[1]}`, (0, exports.isAiSvg)(element), elementTagName);
|
|
1106
1114
|
}
|
|
1107
1115
|
const textCondition = buildTextCondition();
|
|
1108
1116
|
if (attributeConditions.length === 1 && textCondition) {
|
|
1109
|
-
return (0, exports.
|
|
1117
|
+
return (0, exports.buildAiPattern)(`${attributeConditions[0]} or ${textCondition}`, (0, exports.isAiSvg)(element), elementTagName);
|
|
1110
1118
|
}
|
|
1111
1119
|
return "";
|
|
1112
1120
|
};
|
|
1113
|
-
exports.
|
|
1114
|
-
const
|
|
1121
|
+
exports.getOrAttributesAiXPath = getOrAttributesAiXPath;
|
|
1122
|
+
const getAiTagOnlyXpathCandidateCount = (xpath, element, docmt) => {
|
|
1115
1123
|
try {
|
|
1116
|
-
return (0, exports.
|
|
1124
|
+
return (0, exports.getAiCountOfXPath)(xpath, element, docmt);
|
|
1117
1125
|
}
|
|
1118
1126
|
catch (_error) {
|
|
1119
|
-
logData_1.logger.error(`error in
|
|
1127
|
+
logData_1.logger.error(`error in getAiTagOnlyXpathCandidateCount ${_error.message}`);
|
|
1120
1128
|
return 0;
|
|
1121
1129
|
}
|
|
1122
1130
|
};
|
|
@@ -1142,30 +1150,30 @@ const getAncestorAnchorCandidates = (node, docmt, platform) => {
|
|
|
1142
1150
|
const pushAnchor = (xpath) => {
|
|
1143
1151
|
if (!xpath || seen.has(xpath))
|
|
1144
1152
|
return;
|
|
1145
|
-
if ((0, exports.
|
|
1153
|
+
if ((0, exports.isAiExactUniqueXpath)(xpath, node, docmt)) {
|
|
1146
1154
|
seen.add(xpath);
|
|
1147
1155
|
anchors.push(xpath);
|
|
1148
1156
|
}
|
|
1149
1157
|
};
|
|
1150
1158
|
orderedAttributes.forEach((attr) => {
|
|
1151
|
-
if (!(0, exports.
|
|
1159
|
+
if (!(0, exports.checkAiBlockedAttributes)(attr, node, false))
|
|
1152
1160
|
return;
|
|
1153
1161
|
const xpath = attr.name === "id"
|
|
1154
|
-
? `//*[@id=${(0, exports.
|
|
1155
|
-
: (0, exports.
|
|
1162
|
+
? `//*[@id=${(0, exports.escapeAiCharacters)((0, exports.sanitizeAiAttributeValue)(attr.name, attr.value))}]`
|
|
1163
|
+
: (0, exports.getAiXpathString)(node, attr.name, attr.value);
|
|
1156
1164
|
if (xpath) {
|
|
1157
1165
|
pushAnchor(xpath);
|
|
1158
1166
|
}
|
|
1159
1167
|
});
|
|
1160
1168
|
const text = node.textContent?.trim();
|
|
1161
1169
|
if (text && text.length < 40 && node.children.length === 0) {
|
|
1162
|
-
const textXpath = (0, exports.
|
|
1170
|
+
const textXpath = (0, exports.getAiFilteredTextXPath)(node);
|
|
1163
1171
|
if (textXpath) {
|
|
1164
1172
|
pushAnchor(textXpath);
|
|
1165
1173
|
}
|
|
1166
1174
|
}
|
|
1167
1175
|
if (attributes.length > 1) {
|
|
1168
|
-
const combinationXpath = (0, exports.
|
|
1176
|
+
const combinationXpath = (0, exports.getAiAttributeCombinationXpath)(node, docmt, attributes, false, platform);
|
|
1169
1177
|
if (combinationXpath) {
|
|
1170
1178
|
pushAnchor(combinationXpath);
|
|
1171
1179
|
}
|
|
@@ -1176,62 +1184,55 @@ const getStructuralPathFromAncestor = (ancestor, element, platform) => {
|
|
|
1176
1184
|
const steps = [];
|
|
1177
1185
|
let current = element;
|
|
1178
1186
|
while (current && current !== ancestor) {
|
|
1179
|
-
steps.unshift((0, exports.
|
|
1187
|
+
steps.unshift((0, exports.getAiAxisNodeTest)(current, platform));
|
|
1180
1188
|
current = current.parentElement;
|
|
1181
1189
|
}
|
|
1182
1190
|
return current === ancestor ? steps.join("/") : "";
|
|
1183
1191
|
};
|
|
1184
|
-
const
|
|
1192
|
+
const getAiTagOnlyXPath = (element, platform, docmt) => {
|
|
1185
1193
|
const root = docmt ??
|
|
1186
1194
|
(element.getRootNode?.() ||
|
|
1187
1195
|
element.ownerDocument);
|
|
1188
|
-
const tagName = (0, exports.
|
|
1196
|
+
const tagName = (0, exports.getAiAxisNodeTest)(element, platform);
|
|
1189
1197
|
const elementTagName = platform === "web" ? element.tagName.toLowerCase() : element.localName;
|
|
1190
|
-
const fallbackXpath = (0, exports.
|
|
1198
|
+
const fallbackXpath = (0, exports.isAiSvg)(element)
|
|
1191
1199
|
? `//*[local-name()='${elementTagName}']`
|
|
1192
1200
|
: `//${elementTagName}`;
|
|
1193
|
-
|
|
1201
|
+
let depth = 0;
|
|
1202
|
+
for (let ancestor = element.parentElement; ancestor && depth < 5; ancestor = ancestor.parentElement,
|
|
1203
|
+
depth++) {
|
|
1194
1204
|
const ancestorAnchors = getAncestorAnchorCandidates(ancestor, root, platform);
|
|
1195
1205
|
for (const ancestorXpath of ancestorAnchors) {
|
|
1196
1206
|
// logger.info(`Trying ancestor XPath: ${ancestorXpath}`);
|
|
1197
1207
|
const descendantXpath = `${ancestorXpath}/descendant::${tagName}`;
|
|
1198
1208
|
// logger.info(`Trying descendant XPath: ${descendantXpath}`);
|
|
1199
|
-
const
|
|
1200
|
-
|
|
1201
|
-
if (count === 1 &&
|
|
1202
|
-
(0, exports.getFirstMatchedNode)(descendantXpath, root) === element) {
|
|
1203
|
-
// logger.info(`Selected XPath: ${descendantXpath}`);
|
|
1209
|
+
const { first, second } = (0, exports.evaluateAIXPathOnce)(descendantXpath, root);
|
|
1210
|
+
if (first === element && !second) {
|
|
1204
1211
|
return descendantXpath;
|
|
1205
1212
|
}
|
|
1206
1213
|
const structuralPath = getStructuralPathFromAncestor(ancestor, element, platform);
|
|
1207
1214
|
if (structuralPath) {
|
|
1208
1215
|
const parentChainXpath = `${ancestorXpath}/${structuralPath}`;
|
|
1209
1216
|
// logger.info(`Trying descendant XPath: ${parentChainXpath}`);
|
|
1210
|
-
const
|
|
1211
|
-
|
|
1212
|
-
if (parentChainCount === 1 &&
|
|
1213
|
-
(0, exports.getFirstMatchedNode)(parentChainXpath, root) === element) {
|
|
1214
|
-
// logger.info(`Selected XPath: ${parentChainXpath}`);
|
|
1217
|
+
const { first, second } = (0, exports.evaluateAIXPathOnce)(parentChainXpath, root);
|
|
1218
|
+
if (first === element && !second) {
|
|
1215
1219
|
return parentChainXpath;
|
|
1216
1220
|
}
|
|
1217
1221
|
}
|
|
1218
1222
|
}
|
|
1219
1223
|
}
|
|
1220
1224
|
// logger.info(`Trying descendant XPath: ${fallbackXpath}`);
|
|
1221
|
-
const
|
|
1222
|
-
|
|
1223
|
-
if (fallbackCount === 1 &&
|
|
1224
|
-
(0, exports.getFirstMatchedNode)(fallbackXpath, root) === element) {
|
|
1225
|
-
// logger.info(`Selected XPath: ${fallbackXpath}`);
|
|
1225
|
+
const { first, second } = (0, exports.evaluateAIXPathOnce)(fallbackXpath, root);
|
|
1226
|
+
if (first === element && !second) {
|
|
1226
1227
|
return fallbackXpath;
|
|
1227
1228
|
}
|
|
1228
1229
|
return "";
|
|
1229
1230
|
};
|
|
1230
|
-
exports.
|
|
1231
|
-
const
|
|
1231
|
+
exports.getAiTagOnlyXPath = getAiTagOnlyXPath;
|
|
1232
|
+
const getAiFirstMatchedNode = (xpath, docmt) => {
|
|
1232
1233
|
try {
|
|
1233
|
-
if (
|
|
1234
|
-
const { contextNode, cloneElement } = (0, exports.
|
|
1234
|
+
if (isAiShadowRootNode(docmt)) {
|
|
1235
|
+
const { contextNode, cloneElement } = (0, exports.createAIShadowEvaluationContext)(docmt);
|
|
1235
1236
|
// const result = owner.evaluate(
|
|
1236
1237
|
// xpath,
|
|
1237
1238
|
// contextNode,
|
|
@@ -1239,7 +1240,7 @@ const getFirstMatchedNode = (xpath, docmt) => {
|
|
|
1239
1240
|
// owner.defaultView!.XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
1240
1241
|
// null
|
|
1241
1242
|
// );
|
|
1242
|
-
const result =
|
|
1243
|
+
const result = evaluateAiXPath(xpath, contextNode, "first");
|
|
1243
1244
|
return (result.singleNodeValue || cloneElement);
|
|
1244
1245
|
}
|
|
1245
1246
|
// const result = docmt.evaluate(
|
|
@@ -1249,44 +1250,46 @@ const getFirstMatchedNode = (xpath, docmt) => {
|
|
|
1249
1250
|
// docmt.defaultView!.XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
1250
1251
|
// null
|
|
1251
1252
|
// );
|
|
1252
|
-
const result =
|
|
1253
|
+
const result = evaluateAiXPath(xpath, docmt, "first");
|
|
1253
1254
|
return result.singleNodeValue;
|
|
1254
1255
|
}
|
|
1255
1256
|
catch (_error) {
|
|
1256
|
-
logData_1.logger.error(`error in
|
|
1257
|
+
logData_1.logger.error(`error in getAiFirstMatchedNode ${_error.message}`);
|
|
1257
1258
|
return null;
|
|
1258
1259
|
}
|
|
1259
1260
|
};
|
|
1260
|
-
exports.
|
|
1261
|
-
const
|
|
1261
|
+
exports.getAiFirstMatchedNode = getAiFirstMatchedNode;
|
|
1262
|
+
const isAiExactUniqueXpath = (xpath, element, docmt) => {
|
|
1262
1263
|
try {
|
|
1263
|
-
const { first, second } = (0, exports.
|
|
1264
|
+
const { first, second } = (0, exports.evaluateAIXPathOnce)(xpath, docmt);
|
|
1264
1265
|
return !!first && !second && first === element;
|
|
1265
1266
|
}
|
|
1266
1267
|
catch {
|
|
1267
1268
|
return false;
|
|
1268
1269
|
}
|
|
1269
1270
|
};
|
|
1270
|
-
exports.
|
|
1271
|
-
const
|
|
1271
|
+
exports.isAiExactUniqueXpath = isAiExactUniqueXpath;
|
|
1272
|
+
const getAiAxisNodeTest = (element, platform) => {
|
|
1272
1273
|
const elementTagName = platform === "web" ? element.tagName.toLowerCase() : element.localName;
|
|
1273
|
-
return (0, exports.
|
|
1274
|
+
return (0, exports.isAiSvg)(element)
|
|
1274
1275
|
? `*[local-name()='${elementTagName}']`
|
|
1275
1276
|
: elementTagName;
|
|
1276
1277
|
};
|
|
1277
|
-
exports.
|
|
1278
|
+
exports.getAiAxisNodeTest = getAiAxisNodeTest;
|
|
1278
1279
|
const hasAnyNumber = (value) => /\d/.test(value);
|
|
1279
|
-
const
|
|
1280
|
-
if (!
|
|
1280
|
+
const getAiUniqueNodeAnchorXpaths = (node, docmt, isTarget, platform) => {
|
|
1281
|
+
if (!node || node.nodeType !== 1)
|
|
1281
1282
|
return [];
|
|
1282
1283
|
const seen = new Set();
|
|
1283
1284
|
const anchors = [];
|
|
1285
|
+
const MAX_ANCHORS = 3;
|
|
1284
1286
|
const attributes = Array.from(node.attributes || []).filter((attribute) => attribute?.value &&
|
|
1285
1287
|
!hasAnyNumber(attribute.value) &&
|
|
1286
|
-
(0, exports.
|
|
1288
|
+
(0, exports.checkAiBlockedAttributes)(attribute, node, isTarget));
|
|
1287
1289
|
const pushAnchor = (key, value) => {
|
|
1288
|
-
if (!value || seen.has(value))
|
|
1290
|
+
if (!value || seen.has(value) || anchors.length >= MAX_ANCHORS) {
|
|
1289
1291
|
return;
|
|
1292
|
+
}
|
|
1290
1293
|
seen.add(value);
|
|
1291
1294
|
anchors.push({ key, value });
|
|
1292
1295
|
};
|
|
@@ -1300,53 +1303,67 @@ const getUniqueNodeAnchorXpaths = (node, docmt, isTarget, platform) => {
|
|
|
1300
1303
|
"aria-label",
|
|
1301
1304
|
"role"
|
|
1302
1305
|
];
|
|
1303
|
-
|
|
1304
|
-
|
|
1306
|
+
const attributeMap = new Map(attributes.map(attr => [attr.name, attr]));
|
|
1307
|
+
const priorityAttrSet = new Set(priorityAttrs);
|
|
1308
|
+
for (const attrName of priorityAttrs) {
|
|
1309
|
+
if (anchors.length >= MAX_ANCHORS) {
|
|
1310
|
+
return anchors;
|
|
1311
|
+
}
|
|
1312
|
+
const attr = attributeMap.get(attrName);
|
|
1305
1313
|
if (!attr)
|
|
1306
|
-
|
|
1314
|
+
continue;
|
|
1307
1315
|
const xpath = attrName === "id"
|
|
1308
1316
|
? `//*[@id='${attr.value}']`
|
|
1309
|
-
: (0, exports.
|
|
1310
|
-
if (xpath && (0, exports.
|
|
1317
|
+
: (0, exports.getAiXpathString)(node, attr.name, attr.value);
|
|
1318
|
+
if (xpath && (0, exports.isAiExactUniqueXpath)(xpath, node, docmt)) {
|
|
1311
1319
|
pushAnchor(`anchor by ${attr.name}`, xpath);
|
|
1312
1320
|
}
|
|
1313
|
-
}
|
|
1321
|
+
}
|
|
1314
1322
|
// Other attributes
|
|
1315
|
-
|
|
1316
|
-
if (
|
|
1317
|
-
return;
|
|
1318
|
-
|
|
1319
|
-
if (
|
|
1323
|
+
for (const attribute of attributes) {
|
|
1324
|
+
if (anchors.length >= MAX_ANCHORS) {
|
|
1325
|
+
return anchors;
|
|
1326
|
+
}
|
|
1327
|
+
if (priorityAttrSet.has(attribute.name))
|
|
1328
|
+
continue;
|
|
1329
|
+
const xpath = (0, exports.getAiXpathString)(node, attribute.name, attribute.value);
|
|
1330
|
+
if (xpath && (0, exports.isAiExactUniqueXpath)(xpath, node, docmt)) {
|
|
1320
1331
|
pushAnchor(`anchor by ${attribute.name}`, xpath);
|
|
1321
1332
|
}
|
|
1322
|
-
}
|
|
1333
|
+
}
|
|
1323
1334
|
// Text (controlled)
|
|
1324
1335
|
const text = node.textContent?.trim();
|
|
1325
1336
|
if (text && text.length < 40 && node.children.length === 0) {
|
|
1326
|
-
const textXpath = (0, exports.
|
|
1327
|
-
if (textXpath && (0, exports.
|
|
1337
|
+
const textXpath = (0, exports.getAiFilteredTextXPath)(node);
|
|
1338
|
+
if (textXpath && (0, exports.isAiExactUniqueXpath)(textXpath, node, docmt)) {
|
|
1328
1339
|
pushAnchor("anchor by text", textXpath);
|
|
1329
1340
|
}
|
|
1330
1341
|
}
|
|
1342
|
+
if (anchors.length >= MAX_ANCHORS) {
|
|
1343
|
+
return anchors;
|
|
1344
|
+
}
|
|
1331
1345
|
// Combination
|
|
1332
1346
|
if (attributes.length > 1) {
|
|
1333
|
-
const combinationXpath = (0, exports.
|
|
1334
|
-
if (combinationXpath && (0, exports.
|
|
1347
|
+
const combinationXpath = (0, exports.getAiAttributeCombinationXpath)(node, docmt, attributes, isTarget, platform);
|
|
1348
|
+
if (combinationXpath && (0, exports.isAiExactUniqueXpath)(combinationXpath, node, docmt)) {
|
|
1335
1349
|
pushAnchor("anchor by combination", combinationXpath);
|
|
1336
1350
|
}
|
|
1337
1351
|
}
|
|
1352
|
+
if (anchors.length >= MAX_ANCHORS) {
|
|
1353
|
+
return anchors;
|
|
1354
|
+
}
|
|
1338
1355
|
// Tag (last fallback)
|
|
1339
|
-
const tagXpath = (0, exports.
|
|
1340
|
-
if (tagXpath && (0, exports.
|
|
1356
|
+
const tagXpath = (0, exports.getAiTagOnlyXPath)(node, platform, docmt);
|
|
1357
|
+
if (tagXpath && (0, exports.isAiExactUniqueXpath)(tagXpath, node, docmt)) {
|
|
1341
1358
|
pushAnchor("anchor by tag", tagXpath);
|
|
1342
1359
|
}
|
|
1343
1360
|
return anchors;
|
|
1344
1361
|
};
|
|
1345
|
-
exports.
|
|
1346
|
-
const
|
|
1347
|
-
const trimmedText = (0, exports.
|
|
1362
|
+
exports.getAiUniqueNodeAnchorXpaths = getAiUniqueNodeAnchorXpaths;
|
|
1363
|
+
const getAiTextXpathFunction = (domNode) => {
|
|
1364
|
+
const trimmedText = (0, exports.getAiTextContent)(domNode)?.trim();
|
|
1348
1365
|
const filteredText = trimmedText
|
|
1349
|
-
? (0, exports.
|
|
1366
|
+
? (0, exports.escapeAiCharacters)(deleteAiGarbageFromInnerText(trimmedText))
|
|
1350
1367
|
: trimmedText;
|
|
1351
1368
|
if (filteredText) {
|
|
1352
1369
|
if (filteredText !== `'${trimmedText}'`) {
|
|
@@ -1355,45 +1372,45 @@ const getTextXpathFunction = (domNode) => {
|
|
|
1355
1372
|
return `normalize-space(.)='${trimmedText}'`;
|
|
1356
1373
|
}
|
|
1357
1374
|
};
|
|
1358
|
-
exports.
|
|
1359
|
-
const
|
|
1375
|
+
exports.getAiTextXpathFunction = getAiTextXpathFunction;
|
|
1376
|
+
const getAiXpathString = (node, attrName, attrValue) => {
|
|
1360
1377
|
const reWhiteSpace = new RegExp(/^[\S]+( [\S]+)*$/gi);
|
|
1361
1378
|
let xpathe = "";
|
|
1362
|
-
attrValue = (0, exports.
|
|
1379
|
+
attrValue = (0, exports.sanitizeAiAttributeValue)(attrName, attrValue);
|
|
1363
1380
|
if (attrValue) {
|
|
1364
1381
|
if (!reWhiteSpace.test(attrValue)) {
|
|
1365
|
-
xpathe = (0, exports.
|
|
1366
|
-
? `//*[local-name()='${node.tagName}' and contains(@${attrName},${(0, exports.
|
|
1367
|
-
: `//${node.tagName || "*"}[contains(@${attrName},${(0, exports.
|
|
1382
|
+
xpathe = (0, exports.isAiSvg)(node)
|
|
1383
|
+
? `//*[local-name()='${node.tagName}' and contains(@${attrName},${(0, exports.escapeAiCharacters)(attrValue)})]`
|
|
1384
|
+
: `//${node.tagName || "*"}[contains(@${attrName},${(0, exports.escapeAiCharacters)(attrValue)})]`;
|
|
1368
1385
|
}
|
|
1369
1386
|
else if (attrName === "class") {
|
|
1370
|
-
xpathe = (0, exports.
|
|
1371
|
-
? `//*[local-name()='${node.tagName}' and contains(@${attrName},${(0, exports.
|
|
1372
|
-
: `//${node.tagName || "*"}[contains(@${attrName},${(0, exports.
|
|
1387
|
+
xpathe = (0, exports.isAiSvg)(node)
|
|
1388
|
+
? `//*[local-name()='${node.tagName}' and contains(@${attrName},${(0, exports.escapeAiCharacters)(attrValue)})]`
|
|
1389
|
+
: `//${node.tagName || "*"}[contains(@${attrName},${(0, exports.escapeAiCharacters)(attrValue)})]`;
|
|
1373
1390
|
}
|
|
1374
1391
|
else {
|
|
1375
|
-
xpathe = (0, exports.
|
|
1376
|
-
? `//*[local-name()='${node.tagName}' and @${attrName}=${(0, exports.
|
|
1377
|
-
: `//${node.tagName || "*"}[@${attrName}=${(0, exports.
|
|
1392
|
+
xpathe = (0, exports.isAiSvg)(node)
|
|
1393
|
+
? `//*[local-name()='${node.tagName}' and @${attrName}=${(0, exports.escapeAiCharacters)(attrValue)}]`
|
|
1394
|
+
: `//${node.tagName || "*"}[@${attrName}=${(0, exports.escapeAiCharacters)(attrValue)}]`;
|
|
1378
1395
|
}
|
|
1379
1396
|
}
|
|
1380
1397
|
return xpathe;
|
|
1381
1398
|
};
|
|
1382
|
-
exports.
|
|
1383
|
-
const
|
|
1399
|
+
exports.getAiXpathString = getAiXpathString;
|
|
1400
|
+
const replaceAiActualAttributes = (str) => {
|
|
1384
1401
|
if (str) {
|
|
1385
1402
|
return str.replace(/\bdisabled\b/gi, "flndisabled");
|
|
1386
1403
|
}
|
|
1387
1404
|
return str;
|
|
1388
1405
|
};
|
|
1389
|
-
exports.
|
|
1406
|
+
exports.replaceAiActualAttributes = replaceAiActualAttributes;
|
|
1390
1407
|
const addAttributeSplitCombineXpaths = (attributes, targetElemt, docmt, isTarget) => {
|
|
1391
1408
|
const attributesArray = Array.prototype.slice.call(attributes);
|
|
1392
1409
|
const xpaths = [];
|
|
1393
1410
|
try {
|
|
1394
1411
|
attributesArray.map((element) => {
|
|
1395
|
-
if ((0, exports.
|
|
1396
|
-
const xpth = (0, exports.
|
|
1412
|
+
if ((0, exports.checkAiBlockedAttributes)(element, targetElemt, isTarget)) {
|
|
1413
|
+
const xpth = (0, exports.getAiCombinationXpath)(element, targetElemt);
|
|
1397
1414
|
if (xpth) {
|
|
1398
1415
|
xpaths.push({
|
|
1399
1416
|
key: `split xpath by ${element.name}`,
|
|
@@ -1412,19 +1429,19 @@ const getReferenceElementsXpath = (domNode, docmt, isTarget, platform) => {
|
|
|
1412
1429
|
let nodeXpath1;
|
|
1413
1430
|
const xpaths1 = [];
|
|
1414
1431
|
if (domNode.textContent &&
|
|
1415
|
-
(!isTarget || (isTarget && !(0, exports.
|
|
1432
|
+
(!isTarget || (isTarget && !(0, exports.isAiNumberExist)(domNode.textContent)))) {
|
|
1416
1433
|
if (!exports.reWhiteSpace.test(domNode.textContent)) {
|
|
1417
|
-
nodeXpath1 = (0, exports.
|
|
1418
|
-
? `*[local-name()='${domNode.tagName}' and ${(0, exports.
|
|
1419
|
-
: `${domNode.tagName}[${(0, exports.
|
|
1434
|
+
nodeXpath1 = (0, exports.isAiSvg)(domNode)
|
|
1435
|
+
? `*[local-name()='${domNode.tagName}' and ${(0, exports.getAiTextXpathFunction)(domNode)})]`
|
|
1436
|
+
: `${domNode.tagName}[${(0, exports.getAiTextXpathFunction)(domNode)}]`;
|
|
1420
1437
|
if (nodeXpath1) {
|
|
1421
1438
|
xpaths1.push({ key: "getReferenceElementsXpath", value: nodeXpath1 });
|
|
1422
1439
|
}
|
|
1423
1440
|
}
|
|
1424
1441
|
else {
|
|
1425
|
-
nodeXpath1 = (0, exports.
|
|
1426
|
-
? `*[local-name()='${domNode.tagName}' and .=${(0, exports.
|
|
1427
|
-
: `${domNode.tagName}[.=${(0, exports.
|
|
1442
|
+
nodeXpath1 = (0, exports.isAiSvg)(domNode)
|
|
1443
|
+
? `*[local-name()='${domNode.tagName}' and .=${(0, exports.escapeAiCharacters)((0, exports.getAiTextContent)(domNode))}]`
|
|
1444
|
+
: `${domNode.tagName}[.=${(0, exports.escapeAiCharacters)((0, exports.getAiTextContent)(domNode))}]`;
|
|
1428
1445
|
if (nodeXpath1) {
|
|
1429
1446
|
xpaths1.push({ key: "getReferenceElementsXpath", value: nodeXpath1 });
|
|
1430
1447
|
}
|
|
@@ -1432,20 +1449,20 @@ const getReferenceElementsXpath = (domNode, docmt, isTarget, platform) => {
|
|
|
1432
1449
|
}
|
|
1433
1450
|
if (domNode.attributes) {
|
|
1434
1451
|
for (const attrName of Array.from(domNode.attributes)) {
|
|
1435
|
-
if ((0, exports.
|
|
1452
|
+
if ((0, exports.checkAiBlockedAttributes)(attrName, domNode, isTarget)) {
|
|
1436
1453
|
let attrValue = attrName.nodeValue;
|
|
1437
1454
|
if (attrValue) {
|
|
1438
|
-
attrValue = (0, exports.
|
|
1455
|
+
attrValue = (0, exports.sanitizeAiAttributeValue)(attrName.name, attrValue);
|
|
1439
1456
|
const elementName = attrName.name;
|
|
1440
1457
|
if (elementName === "class") {
|
|
1441
|
-
nodeXpath1 = (0, exports.
|
|
1442
|
-
? `*[local-name()='${domNode.tagName}' and contains(@${elementName},${(0, exports.
|
|
1443
|
-
: `${domNode.tagName}[contains(@${elementName},${(0, exports.
|
|
1458
|
+
nodeXpath1 = (0, exports.isAiSvg)(domNode)
|
|
1459
|
+
? `*[local-name()='${domNode.tagName}' and contains(@${elementName},${(0, exports.escapeAiCharacters)(attrValue)})]`
|
|
1460
|
+
: `${domNode.tagName}[contains(@${elementName},${(0, exports.escapeAiCharacters)(attrValue)})]`;
|
|
1444
1461
|
}
|
|
1445
1462
|
else {
|
|
1446
|
-
nodeXpath1 = (0, exports.
|
|
1447
|
-
? `*[local-name()='${domNode.tagName}' and @${elementName}=${(0, exports.
|
|
1448
|
-
: `${domNode.tagName}[@${elementName}=${(0, exports.
|
|
1463
|
+
nodeXpath1 = (0, exports.isAiSvg)(domNode)
|
|
1464
|
+
? `*[local-name()='${domNode.tagName}' and @${elementName}=${(0, exports.escapeAiCharacters)(attrValue)}]`
|
|
1465
|
+
: `${domNode.tagName}[@${elementName}=${(0, exports.escapeAiCharacters)(attrValue)}]`;
|
|
1449
1466
|
}
|
|
1450
1467
|
if (nodeXpath1) {
|
|
1451
1468
|
xpaths1.push({
|
|
@@ -1460,7 +1477,7 @@ const getReferenceElementsXpath = (domNode, docmt, isTarget, platform) => {
|
|
|
1460
1477
|
if (!xpaths1?.length) {
|
|
1461
1478
|
const attributesArray = Array.prototype.slice.call(domNode.attributes);
|
|
1462
1479
|
if (attributesArray?.length > 1) {
|
|
1463
|
-
const combinationXpath = (0, exports.
|
|
1480
|
+
const combinationXpath = (0, exports.getAiAttributeCombinationXpath)(domNode, docmt, Array.prototype.slice.call(domNode.attributes), isTarget, platform);
|
|
1464
1481
|
if (combinationXpath) {
|
|
1465
1482
|
xpaths1.push({
|
|
1466
1483
|
key: "getReferenceElementsXpath",
|
|
@@ -1472,18 +1489,18 @@ const getReferenceElementsXpath = (domNode, docmt, isTarget, platform) => {
|
|
|
1472
1489
|
if (!xpaths1?.length) {
|
|
1473
1490
|
const combinePattern = [];
|
|
1474
1491
|
let pattern;
|
|
1475
|
-
const tag = (0, exports.
|
|
1476
|
-
if (domNode.textContent && isTarget && (0, exports.
|
|
1492
|
+
const tag = (0, exports.isAiSvg)(domNode);
|
|
1493
|
+
if (domNode.textContent && isTarget && (0, exports.isAiNumberExist)(domNode.textContent)) {
|
|
1477
1494
|
const contentRes = [...new Set(domNode.textContent.match(/([^0-9]+)/g))];
|
|
1478
1495
|
if (contentRes?.length) {
|
|
1479
1496
|
for (let i = 0; i < contentRes?.length; i++) {
|
|
1480
1497
|
if (contentRes[i] &&
|
|
1481
|
-
(0, exports.
|
|
1498
|
+
(0, exports.aiReplaceWhiteSpaces)(contentRes[i].trim())?.length > 1) {
|
|
1482
1499
|
if (!exports.reWhiteSpace.test(contentRes[i])) {
|
|
1483
|
-
combinePattern.push(`contains(.,${(0, exports.
|
|
1500
|
+
combinePattern.push(`contains(.,${(0, exports.escapeAiCharacters)((0, exports.aiReplaceWhiteSpaces)(contentRes[i])).trim()})`);
|
|
1484
1501
|
}
|
|
1485
1502
|
else {
|
|
1486
|
-
combinePattern.push(`contains(.,${(0, exports.
|
|
1503
|
+
combinePattern.push(`contains(.,${(0, exports.escapeAiCharacters)(contentRes[i]).trim()})`);
|
|
1487
1504
|
}
|
|
1488
1505
|
}
|
|
1489
1506
|
}
|
|
@@ -1535,7 +1552,7 @@ exports.findMatchingParenthesis = findMatchingParenthesis;
|
|
|
1535
1552
|
function escapeAttrValue(value) {
|
|
1536
1553
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/ /g, "\\ ");
|
|
1537
1554
|
}
|
|
1538
|
-
function
|
|
1555
|
+
function isAiUniqueInDOM(docmt, name, value, element) {
|
|
1539
1556
|
const root = element?.getRootNode?.() ?? docmt;
|
|
1540
1557
|
const queryAll = (selector) => {
|
|
1541
1558
|
try {
|
|
@@ -1571,77 +1588,41 @@ function isUniqueInDOM(docmt, name, value, element) {
|
|
|
1571
1588
|
return false;
|
|
1572
1589
|
}
|
|
1573
1590
|
}
|
|
1574
|
-
const getPlatformFallbackXpath = (element, platform) => {
|
|
1575
|
-
const tag = element.tagName;
|
|
1576
|
-
if (platform === "android") {
|
|
1577
|
-
const bounds = element.getAttribute("bounds");
|
|
1578
|
-
const index = element.getAttribute("index");
|
|
1579
|
-
if (bounds) {
|
|
1580
|
-
return index
|
|
1581
|
-
? `//${tag}[@index="${index}" and @bounds="${bounds}"]`
|
|
1582
|
-
: `//${tag}[@bounds="${bounds}"]`;
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
if (platform === "ios") {
|
|
1586
|
-
const name = element.getAttribute("name");
|
|
1587
|
-
if (name) {
|
|
1588
|
-
return `//${tag}[@name="${name}"]`;
|
|
1589
|
-
}
|
|
1590
|
-
const label = element.getAttribute("label");
|
|
1591
|
-
if (label) {
|
|
1592
|
-
return `//${tag}[@label="${label}"]`;
|
|
1593
|
-
}
|
|
1594
|
-
const value = element.getAttribute("value");
|
|
1595
|
-
if (value) {
|
|
1596
|
-
return `//${tag}[@value="${value}"]`;
|
|
1597
|
-
}
|
|
1598
|
-
const x = element.getAttribute("x");
|
|
1599
|
-
const y = element.getAttribute("y");
|
|
1600
|
-
const width = element.getAttribute("width");
|
|
1601
|
-
const height = element.getAttribute("height");
|
|
1602
|
-
if (x && y && width && height) {
|
|
1603
|
-
return `//${tag}[@x="${x}" and @y="${y}" and @width="${width}" and @height="${height}"]`;
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
return null;
|
|
1607
|
-
};
|
|
1608
|
-
exports.getPlatformFallbackXpath = getPlatformFallbackXpath;
|
|
1609
1591
|
exports.xpathUtils = {
|
|
1610
1592
|
getReferenceElementsXpath: exports.getReferenceElementsXpath,
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
getCountOfXPath: exports.getCountOfXPath,
|
|
1593
|
+
getAiAbsoluteXPath: exports.getAiAbsoluteXPath,
|
|
1594
|
+
getAIRelativeXPath: exports.getAIRelativeXPath,
|
|
1595
|
+
getAiCombinationXpath: exports.getAiCombinationXpath,
|
|
1596
|
+
getAiAttributeCombinationXpath: exports.getAiAttributeCombinationXpath,
|
|
1597
|
+
isAiSvg: exports.isAiSvg,
|
|
1598
|
+
findAiXpathWithIndex: exports.findAiXpathWithIndex,
|
|
1599
|
+
isAiNumberExist: exports.isAiNumberExist,
|
|
1600
|
+
getAiTextContent: exports.getAiTextContent,
|
|
1601
|
+
getAiCountOfXPath: exports.getAiCountOfXPath,
|
|
1621
1602
|
normalizeXPath: exports.normalizeXPath,
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1603
|
+
getAiShadowRoot: exports.getAiShadowRoot,
|
|
1604
|
+
escapeAiCharacters: exports.escapeAiCharacters,
|
|
1605
|
+
removeAiParenthesis: exports.removeAiParenthesis,
|
|
1606
|
+
checkAiBlockedAttributes: exports.checkAiBlockedAttributes,
|
|
1607
|
+
getAiRelationship: exports.getAiRelationship,
|
|
1627
1608
|
findMatchingParenthesis: exports.findMatchingParenthesis,
|
|
1628
|
-
|
|
1629
|
-
|
|
1609
|
+
deleteAiGarbageFromInnerText,
|
|
1610
|
+
replaceAiTempAttributes: exports.replaceAiTempAttributes,
|
|
1630
1611
|
// createObserver,
|
|
1631
1612
|
// startObserver,
|
|
1632
1613
|
// stopObserver,
|
|
1633
1614
|
modifiedElementAttributes: exports.modifiedElementAttributes,
|
|
1634
1615
|
cspEnabled: exports.cspEnabled,
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1616
|
+
getAiNormalizedPropertyXPath: exports.getAiNormalizedPropertyXPath,
|
|
1617
|
+
getAiStartsWithPropertyXPath: exports.getAiStartsWithPropertyXPath,
|
|
1618
|
+
getAiContainsPropertyXPath: exports.getAiContainsPropertyXPath,
|
|
1619
|
+
getOrAttributesAiXPath: exports.getOrAttributesAiXPath,
|
|
1620
|
+
getAiTagOnlyXPath: exports.getAiTagOnlyXPath,
|
|
1621
|
+
getAiFirstMatchedNode: exports.getAiFirstMatchedNode,
|
|
1622
|
+
isAiExactUniqueXpath: exports.isAiExactUniqueXpath,
|
|
1623
|
+
getAiAxisNodeTest: exports.getAiAxisNodeTest,
|
|
1624
|
+
getAiUniqueNodeAnchorXpaths: exports.getAiUniqueNodeAnchorXpaths,
|
|
1644
1625
|
escapeAttrValue,
|
|
1645
|
-
|
|
1646
|
-
|
|
1626
|
+
isAiUniqueInDOM,
|
|
1627
|
+
sanitizeAiAttributeValue: exports.sanitizeAiAttributeValue
|
|
1647
1628
|
};
|