@midscene/shared 0.17.2 → 0.17.3-beta-20250526042111.0
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/es/common.d.ts +1 -2
- package/dist/es/common.js +1 -3
- package/dist/es/constants.d.ts +1 -0
- package/dist/es/constants.js +1 -0
- package/dist/es/extractor-debug.js +92 -7
- package/dist/es/extractor.js +98 -35
- package/dist/es/logger.js +4 -2
- package/dist/lib/common.d.ts +1 -2
- package/dist/lib/common.js +2 -5
- package/dist/lib/constants.d.ts +1 -0
- package/dist/lib/constants.js +1 -0
- package/dist/lib/extractor-debug.js +92 -7
- package/dist/lib/extractor.js +98 -35
- package/dist/lib/logger.js +4 -2
- package/dist/script/htmlElement.js +97 -35
- package/dist/script/htmlElementDebug.js +90 -7
- package/dist/types/common.d.ts +1 -2
- package/dist/types/constants.d.ts +1 -0
- package/package.json +1 -1
- package/src/common.ts +0 -2
- package/src/constants/index.ts +1 -0
- package/src/extractor/dom-util.ts +7 -0
- package/src/extractor/locator.ts +9 -46
- package/src/extractor/web-extractor.ts +94 -1
- package/src/logger.ts +5 -2
package/dist/lib/extractor.js
CHANGED
|
@@ -197,6 +197,9 @@ function isFormElement(node) {
|
|
|
197
197
|
function isButtonElement(node) {
|
|
198
198
|
return node instanceof HTMLElement && node.tagName.toLowerCase() === "button";
|
|
199
199
|
}
|
|
200
|
+
function isAElement(node) {
|
|
201
|
+
return node instanceof HTMLElement && node.tagName.toLowerCase() === "a";
|
|
202
|
+
}
|
|
200
203
|
function isImgElement(node) {
|
|
201
204
|
if (!includeBaseElement(node) && node instanceof Element) {
|
|
202
205
|
const computedStyle = window.getComputedStyle(node);
|
|
@@ -247,7 +250,8 @@ function includeBaseElement(node) {
|
|
|
247
250
|
"textarea",
|
|
248
251
|
"select",
|
|
249
252
|
"option",
|
|
250
|
-
"img"
|
|
253
|
+
"img",
|
|
254
|
+
"a"
|
|
251
255
|
];
|
|
252
256
|
for (const tagName of includeList) {
|
|
253
257
|
const element = node.querySelectorAll(tagName);
|
|
@@ -636,10 +640,20 @@ function collectElementInfo(node, currentWindow, currentDocument, baseZoom = 1,
|
|
|
636
640
|
return elementInfo;
|
|
637
641
|
}
|
|
638
642
|
if (isButtonElement(node)) {
|
|
643
|
+
const rect2 = mergeElementAndChildrenRects(
|
|
644
|
+
node,
|
|
645
|
+
currentWindow,
|
|
646
|
+
currentDocument,
|
|
647
|
+
baseZoom,
|
|
648
|
+
visibleOnly
|
|
649
|
+
);
|
|
650
|
+
if (!rect2) {
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
639
653
|
const attributes = getNodeAttributes(node, currentWindow);
|
|
640
654
|
const pseudo = getPseudoElementContent(node, currentWindow);
|
|
641
655
|
const content = node.innerText || pseudo.before || pseudo.after || "";
|
|
642
|
-
const nodeHashId = midsceneGenerateHash(node, content,
|
|
656
|
+
const nodeHashId = midsceneGenerateHash(node, content, rect2);
|
|
643
657
|
const selector = setDataForNode(node, nodeHashId, false, currentWindow);
|
|
644
658
|
const elementInfo = {
|
|
645
659
|
id: nodeHashId,
|
|
@@ -653,12 +667,12 @@ function collectElementInfo(node, currentWindow, currentDocument, baseZoom = 1,
|
|
|
653
667
|
nodeType: "BUTTON Node" /* BUTTON */
|
|
654
668
|
},
|
|
655
669
|
content,
|
|
656
|
-
rect,
|
|
670
|
+
rect: rect2,
|
|
657
671
|
center: [
|
|
658
|
-
Math.round(
|
|
659
|
-
Math.round(
|
|
672
|
+
Math.round(rect2.left + rect2.width / 2),
|
|
673
|
+
Math.round(rect2.top + rect2.height / 2)
|
|
660
674
|
],
|
|
661
|
-
zoom:
|
|
675
|
+
zoom: rect2.zoom
|
|
662
676
|
};
|
|
663
677
|
return elementInfo;
|
|
664
678
|
}
|
|
@@ -723,6 +737,33 @@ function collectElementInfo(node, currentWindow, currentDocument, baseZoom = 1,
|
|
|
723
737
|
};
|
|
724
738
|
return elementInfo;
|
|
725
739
|
}
|
|
740
|
+
if (isAElement(node)) {
|
|
741
|
+
const attributes = getNodeAttributes(node, currentWindow);
|
|
742
|
+
const pseudo = getPseudoElementContent(node, currentWindow);
|
|
743
|
+
const content = node.innerText || pseudo.before || pseudo.after || "";
|
|
744
|
+
const nodeHashId = midsceneGenerateHash(node, content, rect);
|
|
745
|
+
const selector = setDataForNode(node, nodeHashId, false, currentWindow);
|
|
746
|
+
const elementInfo = {
|
|
747
|
+
id: nodeHashId,
|
|
748
|
+
indexId: indexId++,
|
|
749
|
+
nodeHashId,
|
|
750
|
+
nodeType: "Anchor Node" /* A */,
|
|
751
|
+
locator: selector,
|
|
752
|
+
attributes: {
|
|
753
|
+
...attributes,
|
|
754
|
+
htmlTagName: tagNameOfNode(node),
|
|
755
|
+
nodeType: "Anchor Node" /* A */
|
|
756
|
+
},
|
|
757
|
+
content,
|
|
758
|
+
rect,
|
|
759
|
+
center: [
|
|
760
|
+
Math.round(rect.left + rect.width / 2),
|
|
761
|
+
Math.round(rect.top + rect.height / 2)
|
|
762
|
+
],
|
|
763
|
+
zoom: rect.zoom
|
|
764
|
+
};
|
|
765
|
+
return elementInfo;
|
|
766
|
+
}
|
|
726
767
|
if (isContainerElement(node)) {
|
|
727
768
|
const attributes = getNodeAttributes(node, currentWindow);
|
|
728
769
|
const nodeHashId = midsceneGenerateHash(node, "", rect);
|
|
@@ -797,7 +838,7 @@ function extractTreeNode(initNode, debugMode2 = false) {
|
|
|
797
838
|
node: elementInfo,
|
|
798
839
|
children: []
|
|
799
840
|
};
|
|
800
|
-
if (elementInfo?.nodeType === "BUTTON Node" /* BUTTON */ || elementInfo?.nodeType === "IMG Node" /* IMG */ || elementInfo?.nodeType === "TEXT Node" /* TEXT */ || elementInfo?.nodeType === "FORM_ITEM Node" /* FORM_ITEM */ || elementInfo?.nodeType === "CONTAINER Node" /* CONTAINER */) {
|
|
841
|
+
if (elementInfo?.nodeType === "BUTTON Node" /* BUTTON */ || elementInfo?.nodeType === "IMG Node" /* IMG */ || elementInfo?.nodeType === "TEXT Node" /* TEXT */ || elementInfo?.nodeType === "Anchor Node" /* A */ || elementInfo?.nodeType === "FORM_ITEM Node" /* FORM_ITEM */ || elementInfo?.nodeType === "CONTAINER Node" /* CONTAINER */) {
|
|
801
842
|
return nodeInfo;
|
|
802
843
|
}
|
|
803
844
|
const rect = getRect(node, baseZoom, currentWindow);
|
|
@@ -852,6 +893,50 @@ function extractTreeNode(initNode, debugMode2 = false) {
|
|
|
852
893
|
children: topChildren
|
|
853
894
|
};
|
|
854
895
|
}
|
|
896
|
+
function mergeElementAndChildrenRects(node, currentWindow, currentDocument, baseZoom = 1, visibleOnly = true) {
|
|
897
|
+
const selfRect = elementRect(
|
|
898
|
+
node,
|
|
899
|
+
currentWindow,
|
|
900
|
+
currentDocument,
|
|
901
|
+
baseZoom,
|
|
902
|
+
visibleOnly
|
|
903
|
+
);
|
|
904
|
+
if (!selfRect)
|
|
905
|
+
return null;
|
|
906
|
+
let minLeft = selfRect.left;
|
|
907
|
+
let minTop = selfRect.top;
|
|
908
|
+
let maxRight = selfRect.left + selfRect.width;
|
|
909
|
+
let maxBottom = selfRect.top + selfRect.height;
|
|
910
|
+
function traverse(child) {
|
|
911
|
+
for (let i = 0; i < child.childNodes.length; i++) {
|
|
912
|
+
const sub = child.childNodes[i];
|
|
913
|
+
if (sub.nodeType === 1) {
|
|
914
|
+
const rect = elementRect(
|
|
915
|
+
sub,
|
|
916
|
+
currentWindow,
|
|
917
|
+
currentDocument,
|
|
918
|
+
baseZoom,
|
|
919
|
+
visibleOnly
|
|
920
|
+
);
|
|
921
|
+
if (rect) {
|
|
922
|
+
minLeft = Math.min(minLeft, rect.left);
|
|
923
|
+
minTop = Math.min(minTop, rect.top);
|
|
924
|
+
maxRight = Math.max(maxRight, rect.left + rect.width);
|
|
925
|
+
maxBottom = Math.max(maxBottom, rect.top + rect.height);
|
|
926
|
+
}
|
|
927
|
+
traverse(sub);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
traverse(node);
|
|
932
|
+
return {
|
|
933
|
+
...selfRect,
|
|
934
|
+
left: minLeft,
|
|
935
|
+
top: minTop,
|
|
936
|
+
width: maxRight - minLeft,
|
|
937
|
+
height: maxBottom - minTop
|
|
938
|
+
};
|
|
939
|
+
}
|
|
855
940
|
|
|
856
941
|
// src/extractor/locator.ts
|
|
857
942
|
var getElementIndex = (element) => {
|
|
@@ -865,16 +950,6 @@ var getElementIndex = (element) => {
|
|
|
865
950
|
}
|
|
866
951
|
return index;
|
|
867
952
|
};
|
|
868
|
-
var findFirstAncestorWithId = (element) => {
|
|
869
|
-
let current = element;
|
|
870
|
-
while (current?.parentElement) {
|
|
871
|
-
if (current.id) {
|
|
872
|
-
return current;
|
|
873
|
-
}
|
|
874
|
-
current = current.parentElement;
|
|
875
|
-
}
|
|
876
|
-
return null;
|
|
877
|
-
};
|
|
878
953
|
var getTextNodeIndex = (textNode) => {
|
|
879
954
|
let index = 1;
|
|
880
955
|
let current = textNode.previousSibling;
|
|
@@ -892,6 +967,10 @@ var getElementXPath = (element) => {
|
|
|
892
967
|
if (parentNode && parentNode.nodeType === Node.ELEMENT_NODE) {
|
|
893
968
|
const parentXPath = getElementXPath(parentNode);
|
|
894
969
|
const textIndex = getTextNodeIndex(element);
|
|
970
|
+
const textContent = element.textContent?.trim();
|
|
971
|
+
if (textContent) {
|
|
972
|
+
return `${parentXPath}/text()[${textIndex}][normalize-space()="${textContent}"]`;
|
|
973
|
+
}
|
|
895
974
|
return `${parentXPath}/text()[${textIndex}]`;
|
|
896
975
|
}
|
|
897
976
|
return "";
|
|
@@ -905,22 +984,6 @@ var getElementXPath = (element) => {
|
|
|
905
984
|
if (el === document.body) {
|
|
906
985
|
return "/html/body";
|
|
907
986
|
}
|
|
908
|
-
if (el.id) {
|
|
909
|
-
return `//*[@id="${el.id}"]`;
|
|
910
|
-
}
|
|
911
|
-
const ancestorWithId = findFirstAncestorWithId(el);
|
|
912
|
-
if (ancestorWithId) {
|
|
913
|
-
const ancestorPath = `//*[@id="${ancestorWithId.id}"]`;
|
|
914
|
-
let current = el;
|
|
915
|
-
const pathParts = [];
|
|
916
|
-
while (current && current !== ancestorWithId) {
|
|
917
|
-
const index2 = getElementIndex(current);
|
|
918
|
-
const tagName2 = current.nodeName.toLowerCase();
|
|
919
|
-
pathParts.unshift(`${tagName2}[${index2}]`);
|
|
920
|
-
current = current.parentElement;
|
|
921
|
-
}
|
|
922
|
-
return pathParts.length > 0 ? `${ancestorPath}/${pathParts.join("/")}` : ancestorPath;
|
|
923
|
-
}
|
|
924
987
|
if (!el.parentNode) {
|
|
925
988
|
return `/${el.nodeName.toLowerCase()}`;
|
|
926
989
|
}
|
|
@@ -935,8 +998,8 @@ var getElementXPath = (element) => {
|
|
|
935
998
|
function generateXPaths(node) {
|
|
936
999
|
if (!node)
|
|
937
1000
|
return [];
|
|
938
|
-
const
|
|
939
|
-
return [
|
|
1001
|
+
const fullXPath = getElementXPath(node);
|
|
1002
|
+
return [fullXPath];
|
|
940
1003
|
}
|
|
941
1004
|
function getXpathsById(id) {
|
|
942
1005
|
const node = getNodeFromCacheList(id);
|
package/dist/lib/logger.js
CHANGED
|
@@ -171,7 +171,6 @@ var getMidsceneRunSubDir = (subdir) => {
|
|
|
171
171
|
}
|
|
172
172
|
return logPath;
|
|
173
173
|
};
|
|
174
|
-
var logDir = isNodeEnv ? getMidsceneRunSubDir("log") : "";
|
|
175
174
|
|
|
176
175
|
// src/logger.ts
|
|
177
176
|
var topicPrefix = "midscene";
|
|
@@ -179,7 +178,10 @@ var logStreams = /* @__PURE__ */ new Map();
|
|
|
179
178
|
function getLogStream(topic) {
|
|
180
179
|
const topicFileName = topic.replace(/:/g, "-");
|
|
181
180
|
if (!logStreams.has(topicFileName)) {
|
|
182
|
-
const logFile = import_node_path2.default.join(
|
|
181
|
+
const logFile = import_node_path2.default.join(
|
|
182
|
+
getMidsceneRunSubDir("log"),
|
|
183
|
+
`${topicFileName}.log`
|
|
184
|
+
);
|
|
183
185
|
const stream = import_node_fs2.default.createWriteStream(logFile, { flags: "a" });
|
|
184
186
|
logStreams.set(topicFileName, stream);
|
|
185
187
|
}
|
|
@@ -755,6 +755,9 @@ ${indentStr}${after}`;
|
|
|
755
755
|
function isButtonElement(node) {
|
|
756
756
|
return node instanceof HTMLElement && node.tagName.toLowerCase() === "button";
|
|
757
757
|
}
|
|
758
|
+
function isAElement(node) {
|
|
759
|
+
return node instanceof HTMLElement && node.tagName.toLowerCase() === "a";
|
|
760
|
+
}
|
|
758
761
|
function isImgElement(node) {
|
|
759
762
|
if (!includeBaseElement(node) && node instanceof Element) {
|
|
760
763
|
const computedStyle = window.getComputedStyle(node);
|
|
@@ -805,7 +808,8 @@ ${indentStr}${after}`;
|
|
|
805
808
|
"textarea",
|
|
806
809
|
"select",
|
|
807
810
|
"option",
|
|
808
|
-
"img"
|
|
811
|
+
"img",
|
|
812
|
+
"a"
|
|
809
813
|
];
|
|
810
814
|
for (const tagName of includeList) {
|
|
811
815
|
const element = node.querySelectorAll(tagName);
|
|
@@ -1196,10 +1200,20 @@ ${indentStr}${after}`;
|
|
|
1196
1200
|
return elementInfo;
|
|
1197
1201
|
}
|
|
1198
1202
|
if (isButtonElement(node)) {
|
|
1203
|
+
const rect2 = mergeElementAndChildrenRects(
|
|
1204
|
+
node,
|
|
1205
|
+
currentWindow,
|
|
1206
|
+
currentDocument,
|
|
1207
|
+
baseZoom,
|
|
1208
|
+
visibleOnly
|
|
1209
|
+
);
|
|
1210
|
+
if (!rect2) {
|
|
1211
|
+
return null;
|
|
1212
|
+
}
|
|
1199
1213
|
const attributes = getNodeAttributes(node, currentWindow);
|
|
1200
1214
|
const pseudo = getPseudoElementContent(node, currentWindow);
|
|
1201
1215
|
const content = node.innerText || pseudo.before || pseudo.after || "";
|
|
1202
|
-
const nodeHashId = midsceneGenerateHash(node, content,
|
|
1216
|
+
const nodeHashId = midsceneGenerateHash(node, content, rect2);
|
|
1203
1217
|
const selector = setDataForNode(node, nodeHashId, false, currentWindow);
|
|
1204
1218
|
const elementInfo = {
|
|
1205
1219
|
id: nodeHashId,
|
|
@@ -1212,12 +1226,12 @@ ${indentStr}${after}`;
|
|
|
1212
1226
|
nodeType: "BUTTON Node" /* BUTTON */
|
|
1213
1227
|
}),
|
|
1214
1228
|
content,
|
|
1215
|
-
rect,
|
|
1229
|
+
rect: rect2,
|
|
1216
1230
|
center: [
|
|
1217
|
-
Math.round(
|
|
1218
|
-
Math.round(
|
|
1231
|
+
Math.round(rect2.left + rect2.width / 2),
|
|
1232
|
+
Math.round(rect2.top + rect2.height / 2)
|
|
1219
1233
|
],
|
|
1220
|
-
zoom:
|
|
1234
|
+
zoom: rect2.zoom
|
|
1221
1235
|
};
|
|
1222
1236
|
return elementInfo;
|
|
1223
1237
|
}
|
|
@@ -1279,6 +1293,32 @@ ${indentStr}${after}`;
|
|
|
1279
1293
|
};
|
|
1280
1294
|
return elementInfo;
|
|
1281
1295
|
}
|
|
1296
|
+
if (isAElement(node)) {
|
|
1297
|
+
const attributes = getNodeAttributes(node, currentWindow);
|
|
1298
|
+
const pseudo = getPseudoElementContent(node, currentWindow);
|
|
1299
|
+
const content = node.innerText || pseudo.before || pseudo.after || "";
|
|
1300
|
+
const nodeHashId = midsceneGenerateHash(node, content, rect);
|
|
1301
|
+
const selector = setDataForNode(node, nodeHashId, false, currentWindow);
|
|
1302
|
+
const elementInfo = {
|
|
1303
|
+
id: nodeHashId,
|
|
1304
|
+
indexId: indexId++,
|
|
1305
|
+
nodeHashId,
|
|
1306
|
+
nodeType: "Anchor Node" /* A */,
|
|
1307
|
+
locator: selector,
|
|
1308
|
+
attributes: __spreadProps(__spreadValues({}, attributes), {
|
|
1309
|
+
htmlTagName: tagNameOfNode(node),
|
|
1310
|
+
nodeType: "Anchor Node" /* A */
|
|
1311
|
+
}),
|
|
1312
|
+
content,
|
|
1313
|
+
rect,
|
|
1314
|
+
center: [
|
|
1315
|
+
Math.round(rect.left + rect.width / 2),
|
|
1316
|
+
Math.round(rect.top + rect.height / 2)
|
|
1317
|
+
],
|
|
1318
|
+
zoom: rect.zoom
|
|
1319
|
+
};
|
|
1320
|
+
return elementInfo;
|
|
1321
|
+
}
|
|
1282
1322
|
if (isContainerElement(node)) {
|
|
1283
1323
|
const attributes = getNodeAttributes(node, currentWindow);
|
|
1284
1324
|
const nodeHashId = midsceneGenerateHash(node, "", rect);
|
|
@@ -1352,7 +1392,7 @@ ${indentStr}${after}`;
|
|
|
1352
1392
|
node: elementInfo,
|
|
1353
1393
|
children: []
|
|
1354
1394
|
};
|
|
1355
|
-
if ((elementInfo == null ? void 0 : elementInfo.nodeType) === "BUTTON Node" /* BUTTON */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "IMG Node" /* IMG */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "TEXT Node" /* TEXT */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "FORM_ITEM Node" /* FORM_ITEM */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "CONTAINER Node" /* CONTAINER */) {
|
|
1395
|
+
if ((elementInfo == null ? void 0 : elementInfo.nodeType) === "BUTTON Node" /* BUTTON */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "IMG Node" /* IMG */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "TEXT Node" /* TEXT */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "Anchor Node" /* A */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "FORM_ITEM Node" /* FORM_ITEM */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "CONTAINER Node" /* CONTAINER */) {
|
|
1356
1396
|
return nodeInfo;
|
|
1357
1397
|
}
|
|
1358
1398
|
const rect = getRect(node, baseZoom, currentWindow);
|
|
@@ -1407,6 +1447,49 @@ ${indentStr}${after}`;
|
|
|
1407
1447
|
children: topChildren
|
|
1408
1448
|
};
|
|
1409
1449
|
}
|
|
1450
|
+
function mergeElementAndChildrenRects(node, currentWindow, currentDocument, baseZoom = 1, visibleOnly = true) {
|
|
1451
|
+
const selfRect = elementRect(
|
|
1452
|
+
node,
|
|
1453
|
+
currentWindow,
|
|
1454
|
+
currentDocument,
|
|
1455
|
+
baseZoom,
|
|
1456
|
+
visibleOnly
|
|
1457
|
+
);
|
|
1458
|
+
if (!selfRect)
|
|
1459
|
+
return null;
|
|
1460
|
+
let minLeft = selfRect.left;
|
|
1461
|
+
let minTop = selfRect.top;
|
|
1462
|
+
let maxRight = selfRect.left + selfRect.width;
|
|
1463
|
+
let maxBottom = selfRect.top + selfRect.height;
|
|
1464
|
+
function traverse(child) {
|
|
1465
|
+
for (let i = 0; i < child.childNodes.length; i++) {
|
|
1466
|
+
const sub = child.childNodes[i];
|
|
1467
|
+
if (sub.nodeType === 1) {
|
|
1468
|
+
const rect = elementRect(
|
|
1469
|
+
sub,
|
|
1470
|
+
currentWindow,
|
|
1471
|
+
currentDocument,
|
|
1472
|
+
baseZoom,
|
|
1473
|
+
visibleOnly
|
|
1474
|
+
);
|
|
1475
|
+
if (rect) {
|
|
1476
|
+
minLeft = Math.min(minLeft, rect.left);
|
|
1477
|
+
minTop = Math.min(minTop, rect.top);
|
|
1478
|
+
maxRight = Math.max(maxRight, rect.left + rect.width);
|
|
1479
|
+
maxBottom = Math.max(maxBottom, rect.top + rect.height);
|
|
1480
|
+
}
|
|
1481
|
+
traverse(sub);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
traverse(node);
|
|
1486
|
+
return __spreadProps(__spreadValues({}, selfRect), {
|
|
1487
|
+
left: minLeft,
|
|
1488
|
+
top: minTop,
|
|
1489
|
+
width: maxRight - minLeft,
|
|
1490
|
+
height: maxBottom - minTop
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1410
1493
|
|
|
1411
1494
|
// src/extractor/locator.ts
|
|
1412
1495
|
var getElementIndex = (element) => {
|
|
@@ -1420,16 +1503,6 @@ ${indentStr}${after}`;
|
|
|
1420
1503
|
}
|
|
1421
1504
|
return index;
|
|
1422
1505
|
};
|
|
1423
|
-
var findFirstAncestorWithId = (element) => {
|
|
1424
|
-
let current = element;
|
|
1425
|
-
while (current == null ? void 0 : current.parentElement) {
|
|
1426
|
-
if (current.id) {
|
|
1427
|
-
return current;
|
|
1428
|
-
}
|
|
1429
|
-
current = current.parentElement;
|
|
1430
|
-
}
|
|
1431
|
-
return null;
|
|
1432
|
-
};
|
|
1433
1506
|
var getTextNodeIndex = (textNode) => {
|
|
1434
1507
|
let index = 1;
|
|
1435
1508
|
let current = textNode.previousSibling;
|
|
@@ -1442,11 +1515,16 @@ ${indentStr}${after}`;
|
|
|
1442
1515
|
return index;
|
|
1443
1516
|
};
|
|
1444
1517
|
var getElementXPath = (element) => {
|
|
1518
|
+
var _a;
|
|
1445
1519
|
if (element.nodeType === Node.TEXT_NODE) {
|
|
1446
1520
|
const parentNode = element.parentNode;
|
|
1447
1521
|
if (parentNode && parentNode.nodeType === Node.ELEMENT_NODE) {
|
|
1448
1522
|
const parentXPath = getElementXPath(parentNode);
|
|
1449
1523
|
const textIndex = getTextNodeIndex(element);
|
|
1524
|
+
const textContent = (_a = element.textContent) == null ? void 0 : _a.trim();
|
|
1525
|
+
if (textContent) {
|
|
1526
|
+
return `${parentXPath}/text()[${textIndex}][normalize-space()="${textContent}"]`;
|
|
1527
|
+
}
|
|
1450
1528
|
return `${parentXPath}/text()[${textIndex}]`;
|
|
1451
1529
|
}
|
|
1452
1530
|
return "";
|
|
@@ -1460,22 +1538,6 @@ ${indentStr}${after}`;
|
|
|
1460
1538
|
if (el === document.body) {
|
|
1461
1539
|
return "/html/body";
|
|
1462
1540
|
}
|
|
1463
|
-
if (el.id) {
|
|
1464
|
-
return `//*[@id="${el.id}"]`;
|
|
1465
|
-
}
|
|
1466
|
-
const ancestorWithId = findFirstAncestorWithId(el);
|
|
1467
|
-
if (ancestorWithId) {
|
|
1468
|
-
const ancestorPath = `//*[@id="${ancestorWithId.id}"]`;
|
|
1469
|
-
let current = el;
|
|
1470
|
-
const pathParts = [];
|
|
1471
|
-
while (current && current !== ancestorWithId) {
|
|
1472
|
-
const index2 = getElementIndex(current);
|
|
1473
|
-
const tagName2 = current.nodeName.toLowerCase();
|
|
1474
|
-
pathParts.unshift(`${tagName2}[${index2}]`);
|
|
1475
|
-
current = current.parentElement;
|
|
1476
|
-
}
|
|
1477
|
-
return pathParts.length > 0 ? `${ancestorPath}/${pathParts.join("/")}` : ancestorPath;
|
|
1478
|
-
}
|
|
1479
1541
|
if (!el.parentNode) {
|
|
1480
1542
|
return `/${el.nodeName.toLowerCase()}`;
|
|
1481
1543
|
}
|
|
@@ -1490,8 +1552,8 @@ ${indentStr}${after}`;
|
|
|
1490
1552
|
function generateXPaths(node) {
|
|
1491
1553
|
if (!node)
|
|
1492
1554
|
return [];
|
|
1493
|
-
const
|
|
1494
|
-
return [
|
|
1555
|
+
const fullXPath = getElementXPath(node);
|
|
1556
|
+
return [fullXPath];
|
|
1495
1557
|
}
|
|
1496
1558
|
function getXpathsById(id) {
|
|
1497
1559
|
const node = getNodeFromCacheList(id);
|
|
@@ -611,6 +611,9 @@ var midscene_element_inspector = (() => {
|
|
|
611
611
|
function isButtonElement(node) {
|
|
612
612
|
return node instanceof HTMLElement && node.tagName.toLowerCase() === "button";
|
|
613
613
|
}
|
|
614
|
+
function isAElement(node) {
|
|
615
|
+
return node instanceof HTMLElement && node.tagName.toLowerCase() === "a";
|
|
616
|
+
}
|
|
614
617
|
function isImgElement(node) {
|
|
615
618
|
if (!includeBaseElement(node) && node instanceof Element) {
|
|
616
619
|
const computedStyle = window.getComputedStyle(node);
|
|
@@ -661,7 +664,8 @@ var midscene_element_inspector = (() => {
|
|
|
661
664
|
"textarea",
|
|
662
665
|
"select",
|
|
663
666
|
"option",
|
|
664
|
-
"img"
|
|
667
|
+
"img",
|
|
668
|
+
"a"
|
|
665
669
|
];
|
|
666
670
|
for (const tagName of includeList) {
|
|
667
671
|
const element = node.querySelectorAll(tagName);
|
|
@@ -1045,10 +1049,20 @@ var midscene_element_inspector = (() => {
|
|
|
1045
1049
|
return elementInfo;
|
|
1046
1050
|
}
|
|
1047
1051
|
if (isButtonElement(node)) {
|
|
1052
|
+
const rect2 = mergeElementAndChildrenRects(
|
|
1053
|
+
node,
|
|
1054
|
+
currentWindow,
|
|
1055
|
+
currentDocument,
|
|
1056
|
+
baseZoom,
|
|
1057
|
+
visibleOnly
|
|
1058
|
+
);
|
|
1059
|
+
if (!rect2) {
|
|
1060
|
+
return null;
|
|
1061
|
+
}
|
|
1048
1062
|
const attributes = getNodeAttributes(node, currentWindow);
|
|
1049
1063
|
const pseudo = getPseudoElementContent(node, currentWindow);
|
|
1050
1064
|
const content = node.innerText || pseudo.before || pseudo.after || "";
|
|
1051
|
-
const nodeHashId = midsceneGenerateHash(node, content,
|
|
1065
|
+
const nodeHashId = midsceneGenerateHash(node, content, rect2);
|
|
1052
1066
|
const selector = setDataForNode(node, nodeHashId, false, currentWindow);
|
|
1053
1067
|
const elementInfo = {
|
|
1054
1068
|
id: nodeHashId,
|
|
@@ -1061,12 +1075,12 @@ var midscene_element_inspector = (() => {
|
|
|
1061
1075
|
nodeType: "BUTTON Node" /* BUTTON */
|
|
1062
1076
|
}),
|
|
1063
1077
|
content,
|
|
1064
|
-
rect,
|
|
1078
|
+
rect: rect2,
|
|
1065
1079
|
center: [
|
|
1066
|
-
Math.round(
|
|
1067
|
-
Math.round(
|
|
1080
|
+
Math.round(rect2.left + rect2.width / 2),
|
|
1081
|
+
Math.round(rect2.top + rect2.height / 2)
|
|
1068
1082
|
],
|
|
1069
|
-
zoom:
|
|
1083
|
+
zoom: rect2.zoom
|
|
1070
1084
|
};
|
|
1071
1085
|
return elementInfo;
|
|
1072
1086
|
}
|
|
@@ -1128,6 +1142,32 @@ var midscene_element_inspector = (() => {
|
|
|
1128
1142
|
};
|
|
1129
1143
|
return elementInfo;
|
|
1130
1144
|
}
|
|
1145
|
+
if (isAElement(node)) {
|
|
1146
|
+
const attributes = getNodeAttributes(node, currentWindow);
|
|
1147
|
+
const pseudo = getPseudoElementContent(node, currentWindow);
|
|
1148
|
+
const content = node.innerText || pseudo.before || pseudo.after || "";
|
|
1149
|
+
const nodeHashId = midsceneGenerateHash(node, content, rect);
|
|
1150
|
+
const selector = setDataForNode(node, nodeHashId, false, currentWindow);
|
|
1151
|
+
const elementInfo = {
|
|
1152
|
+
id: nodeHashId,
|
|
1153
|
+
indexId: indexId++,
|
|
1154
|
+
nodeHashId,
|
|
1155
|
+
nodeType: "Anchor Node" /* A */,
|
|
1156
|
+
locator: selector,
|
|
1157
|
+
attributes: __spreadProps(__spreadValues({}, attributes), {
|
|
1158
|
+
htmlTagName: tagNameOfNode(node),
|
|
1159
|
+
nodeType: "Anchor Node" /* A */
|
|
1160
|
+
}),
|
|
1161
|
+
content,
|
|
1162
|
+
rect,
|
|
1163
|
+
center: [
|
|
1164
|
+
Math.round(rect.left + rect.width / 2),
|
|
1165
|
+
Math.round(rect.top + rect.height / 2)
|
|
1166
|
+
],
|
|
1167
|
+
zoom: rect.zoom
|
|
1168
|
+
};
|
|
1169
|
+
return elementInfo;
|
|
1170
|
+
}
|
|
1131
1171
|
if (isContainerElement(node)) {
|
|
1132
1172
|
const attributes = getNodeAttributes(node, currentWindow);
|
|
1133
1173
|
const nodeHashId = midsceneGenerateHash(node, "", rect);
|
|
@@ -1197,7 +1237,7 @@ var midscene_element_inspector = (() => {
|
|
|
1197
1237
|
node: elementInfo,
|
|
1198
1238
|
children: []
|
|
1199
1239
|
};
|
|
1200
|
-
if ((elementInfo == null ? void 0 : elementInfo.nodeType) === "BUTTON Node" /* BUTTON */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "IMG Node" /* IMG */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "TEXT Node" /* TEXT */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "FORM_ITEM Node" /* FORM_ITEM */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "CONTAINER Node" /* CONTAINER */) {
|
|
1240
|
+
if ((elementInfo == null ? void 0 : elementInfo.nodeType) === "BUTTON Node" /* BUTTON */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "IMG Node" /* IMG */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "TEXT Node" /* TEXT */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "Anchor Node" /* A */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "FORM_ITEM Node" /* FORM_ITEM */ || (elementInfo == null ? void 0 : elementInfo.nodeType) === "CONTAINER Node" /* CONTAINER */) {
|
|
1201
1241
|
return nodeInfo;
|
|
1202
1242
|
}
|
|
1203
1243
|
const rect = getRect(node, baseZoom, currentWindow);
|
|
@@ -1252,6 +1292,49 @@ var midscene_element_inspector = (() => {
|
|
|
1252
1292
|
children: topChildren
|
|
1253
1293
|
};
|
|
1254
1294
|
}
|
|
1295
|
+
function mergeElementAndChildrenRects(node, currentWindow, currentDocument, baseZoom = 1, visibleOnly = true) {
|
|
1296
|
+
const selfRect = elementRect(
|
|
1297
|
+
node,
|
|
1298
|
+
currentWindow,
|
|
1299
|
+
currentDocument,
|
|
1300
|
+
baseZoom,
|
|
1301
|
+
visibleOnly
|
|
1302
|
+
);
|
|
1303
|
+
if (!selfRect)
|
|
1304
|
+
return null;
|
|
1305
|
+
let minLeft = selfRect.left;
|
|
1306
|
+
let minTop = selfRect.top;
|
|
1307
|
+
let maxRight = selfRect.left + selfRect.width;
|
|
1308
|
+
let maxBottom = selfRect.top + selfRect.height;
|
|
1309
|
+
function traverse(child) {
|
|
1310
|
+
for (let i = 0; i < child.childNodes.length; i++) {
|
|
1311
|
+
const sub = child.childNodes[i];
|
|
1312
|
+
if (sub.nodeType === 1) {
|
|
1313
|
+
const rect = elementRect(
|
|
1314
|
+
sub,
|
|
1315
|
+
currentWindow,
|
|
1316
|
+
currentDocument,
|
|
1317
|
+
baseZoom,
|
|
1318
|
+
visibleOnly
|
|
1319
|
+
);
|
|
1320
|
+
if (rect) {
|
|
1321
|
+
minLeft = Math.min(minLeft, rect.left);
|
|
1322
|
+
minTop = Math.min(minTop, rect.top);
|
|
1323
|
+
maxRight = Math.max(maxRight, rect.left + rect.width);
|
|
1324
|
+
maxBottom = Math.max(maxBottom, rect.top + rect.height);
|
|
1325
|
+
}
|
|
1326
|
+
traverse(sub);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
traverse(node);
|
|
1331
|
+
return __spreadProps(__spreadValues({}, selfRect), {
|
|
1332
|
+
left: minLeft,
|
|
1333
|
+
top: minTop,
|
|
1334
|
+
width: maxRight - minLeft,
|
|
1335
|
+
height: maxBottom - minTop
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1255
1338
|
|
|
1256
1339
|
// src/extractor/debug.ts
|
|
1257
1340
|
console.log(extractTextWithPosition(document.body, true));
|
package/dist/types/common.d.ts
CHANGED
|
@@ -10,6 +10,5 @@ declare const getMidsceneRunBaseDir: () => string;
|
|
|
10
10
|
* @returns The absolute path to the requested directory
|
|
11
11
|
*/
|
|
12
12
|
declare const getMidsceneRunSubDir: (subdir: "dump" | "cache" | "report" | "tmp" | "log" | "output") => string;
|
|
13
|
-
declare const logDir: string;
|
|
14
13
|
|
|
15
|
-
export { defaultRunDirName, getMidsceneRunBaseDir, getMidsceneRunDir, getMidsceneRunSubDir, isNodeEnv
|
|
14
|
+
export { defaultRunDirName, getMidsceneRunBaseDir, getMidsceneRunDir, getMidsceneRunSubDir, isNodeEnv };
|
package/package.json
CHANGED
package/src/common.ts
CHANGED
package/src/constants/index.ts
CHANGED
|
@@ -17,6 +17,12 @@ export function isButtonElement(
|
|
|
17
17
|
return node instanceof HTMLElement && node.tagName.toLowerCase() === 'button';
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
export function isAElement(
|
|
21
|
+
node: globalThis.Node,
|
|
22
|
+
): node is globalThis.HTMLButtonElement {
|
|
23
|
+
return node instanceof HTMLElement && node.tagName.toLowerCase() === 'a';
|
|
24
|
+
}
|
|
25
|
+
|
|
20
26
|
export function isImgElement(
|
|
21
27
|
node: globalThis.Node,
|
|
22
28
|
): node is globalThis.HTMLImageElement {
|
|
@@ -90,6 +96,7 @@ function includeBaseElement(node: globalThis.Node) {
|
|
|
90
96
|
'select',
|
|
91
97
|
'option',
|
|
92
98
|
'img',
|
|
99
|
+
'a',
|
|
93
100
|
];
|
|
94
101
|
|
|
95
102
|
for (const tagName of includeList) {
|