@midscene/shared 0.12.4 → 0.12.5-beta-20250306111616.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.
Files changed (107) hide show
  1. package/dist/es/{constants.js → constants/index.js} +4 -5
  2. package/dist/es/extractor/client-extractor.js +161 -0
  3. package/dist/es/extractor/constants.js +10 -0
  4. package/dist/es/extractor/debug.js +9 -0
  5. package/dist/es/extractor/dom-util.js +73 -0
  6. package/dist/es/extractor/index.js +14 -0
  7. package/dist/es/extractor/tree.js +126 -0
  8. package/dist/es/extractor/util.js +344 -0
  9. package/dist/es/extractor/web-extractor.js +317 -0
  10. package/dist/es/img/box-select.js +187 -0
  11. package/dist/es/img/draw-box.js +43 -0
  12. package/dist/es/img/get-jimp.js +11 -0
  13. package/dist/es/img/index.js +34 -0
  14. package/dist/es/img/info.js +50 -0
  15. package/dist/es/img/transform.js +128 -0
  16. package/dist/es/index.js +0 -1
  17. package/dist/es/{fs.js → node/fs.js} +22 -5
  18. package/dist/es/types/index.js +5 -0
  19. package/dist/es/us-keyboard-layout.js +10 -11
  20. package/dist/es/utils.js +10 -569
  21. package/dist/lib/constants/index.js +20 -0
  22. package/dist/lib/extractor/client-extractor.js +161 -0
  23. package/dist/lib/extractor/constants.js +10 -0
  24. package/dist/lib/extractor/debug.js +9 -0
  25. package/dist/lib/extractor/dom-util.js +73 -0
  26. package/dist/lib/extractor/index.js +14 -0
  27. package/dist/lib/extractor/tree.js +126 -0
  28. package/dist/lib/extractor/util.js +344 -0
  29. package/dist/lib/extractor/web-extractor.js +317 -0
  30. package/dist/lib/img/box-select.js +187 -0
  31. package/dist/lib/img/draw-box.js +43 -0
  32. package/dist/lib/img/get-jimp.js +11 -0
  33. package/dist/lib/img/index.js +34 -0
  34. package/dist/lib/img/info.js +50 -0
  35. package/dist/lib/img/transform.js +128 -0
  36. package/dist/lib/index.js +3 -25
  37. package/dist/lib/node/fs.js +62 -0
  38. package/dist/lib/types/index.js +5 -0
  39. package/dist/lib/us-keyboard-layout.js +12 -41
  40. package/dist/lib/utils.js +12 -578
  41. package/dist/types/constants/index.d.ts +12 -0
  42. package/dist/types/extractor/client-extractor.d.ts +2 -0
  43. package/dist/types/extractor/constants.d.ts +1 -0
  44. package/dist/types/extractor/debug.d.ts +1 -0
  45. package/dist/types/extractor/dom-util.d.ts +5 -0
  46. package/dist/types/extractor/index.d.ts +29 -0
  47. package/dist/types/extractor/tree.d.ts +9 -0
  48. package/dist/types/extractor/util.d.ts +40 -0
  49. package/dist/types/extractor/web-extractor.d.ts +14 -0
  50. package/dist/types/img/box-select.d.ts +31 -0
  51. package/dist/types/img/draw-box.d.ts +15 -0
  52. package/dist/types/img/get-jimp.d.ts +2 -0
  53. package/dist/types/img/index.d.ts +4 -0
  54. package/dist/types/img/info.d.ts +40 -0
  55. package/dist/types/img/transform.d.ts +68 -0
  56. package/dist/types/index.d.ts +1 -2
  57. package/dist/{lib → types/node}/fs.d.ts +4 -4
  58. package/dist/{lib/index-305e7a7e.d.ts → types/types/index.d.ts} +6 -9
  59. package/dist/types/us-keyboard-layout.d.ts +32 -0
  60. package/dist/types/utils.d.ts +11 -0
  61. package/package.json +39 -39
  62. package/src/img/box-select.ts +17 -11
  63. package/src/img/draw-box.ts +5 -5
  64. package/src/img/get-jimp.ts +3 -0
  65. package/src/{fs/index.ts → node/fs.ts} +20 -0
  66. package/src/utils.ts +13 -0
  67. package/dist/browser/constants.d.ts +0 -14
  68. package/dist/browser/constants.js +0 -42
  69. package/dist/browser/extractor-debug.d.ts +0 -2
  70. package/dist/browser/extractor-debug.js +0 -1269
  71. package/dist/browser/extractor.d.ts +0 -47
  72. package/dist/browser/extractor.js +0 -1557
  73. package/dist/browser/fs.d.ts +0 -14
  74. package/dist/browser/fs.js +0 -66
  75. package/dist/browser/img.d.ts +0 -152
  76. package/dist/browser/img.js +0 -483
  77. package/dist/browser/index-305e7a7e.d.ts +0 -32
  78. package/dist/browser/index.d.ts +0 -3
  79. package/dist/browser/index.js +0 -26
  80. package/dist/browser/us-keyboard-layout.d.ts +0 -34
  81. package/dist/browser/us-keyboard-layout.js +0 -456
  82. package/dist/browser/utils.d.ts +0 -5
  83. package/dist/browser/utils.js +0 -611
  84. package/dist/es/constants.d.ts +0 -14
  85. package/dist/es/extractor-debug.d.ts +0 -2
  86. package/dist/es/extractor-debug.js +0 -1267
  87. package/dist/es/extractor.d.ts +0 -47
  88. package/dist/es/extractor.js +0 -1546
  89. package/dist/es/fs.d.ts +0 -14
  90. package/dist/es/img.d.ts +0 -152
  91. package/dist/es/img.js +0 -451
  92. package/dist/es/index-305e7a7e.d.ts +0 -32
  93. package/dist/es/index.d.ts +0 -3
  94. package/dist/es/us-keyboard-layout.d.ts +0 -34
  95. package/dist/es/utils.d.ts +0 -5
  96. package/dist/lib/constants.d.ts +0 -14
  97. package/dist/lib/constants.js +0 -50
  98. package/dist/lib/extractor-debug.d.ts +0 -2
  99. package/dist/lib/extractor-debug.js +0 -1261
  100. package/dist/lib/extractor.d.ts +0 -47
  101. package/dist/lib/extractor.js +0 -1559
  102. package/dist/lib/fs.js +0 -71
  103. package/dist/lib/img.d.ts +0 -152
  104. package/dist/lib/img.js +0 -501
  105. package/dist/lib/index.d.ts +0 -3
  106. package/dist/lib/us-keyboard-layout.d.ts +0 -34
  107. package/dist/lib/utils.d.ts +0 -5
@@ -1,8 +1,7 @@
1
- // src/constants/index.ts
2
- var TEXT_SIZE_THRESHOLD = 9;
3
- var TEXT_MAX_SIZE = 40;
4
- var CONTAINER_MINI_HEIGHT = 3;
5
- var CONTAINER_MINI_WIDTH = 3;
1
+ const TEXT_SIZE_THRESHOLD = 9;
2
+ const TEXT_MAX_SIZE = 40;
3
+ const CONTAINER_MINI_HEIGHT = 3;
4
+ const CONTAINER_MINI_WIDTH = 3;
6
5
  var NodeType = /* @__PURE__ */ ((NodeType2) => {
7
6
  NodeType2["CONTAINER"] = "CONTAINER Node";
8
7
  NodeType2["FORM_ITEM"] = "FORM_ITEM Node";
@@ -0,0 +1,161 @@
1
+ import { NodeType } from "./constants";
2
+ import { midsceneGenerateHash } from "./util";
3
+ function getNodeAttributes(node) {
4
+ const attrs = {};
5
+ if (node && node.nodeType === 1) {
6
+ const element = node;
7
+ for (let i = 0; i < element.attributes.length; i++) {
8
+ const attr = element.attributes[i];
9
+ attrs[attr.nodeName] = attr.nodeValue ?? "";
10
+ }
11
+ }
12
+ return attrs;
13
+ }
14
+ function getRect(attributes) {
15
+ const x = Math.round(Number.parseFloat(attributes.x ?? "0"));
16
+ const y = Math.round(Number.parseFloat(attributes.y ?? "0"));
17
+ const width = Math.round(Number.parseFloat(attributes.width ?? "0"));
18
+ const height = Math.round(Number.parseFloat(attributes.height ?? "0"));
19
+ return {
20
+ left: Math.max(0, Math.floor(x)),
21
+ top: Math.max(0, Math.floor(y)),
22
+ width: Math.max(0, width),
23
+ height: Math.max(0, height)
24
+ };
25
+ }
26
+ function validTextNodeContent(node) {
27
+ if (node.nodeType === 3) {
28
+ return node.nodeValue?.trim() || "";
29
+ }
30
+ return "";
31
+ }
32
+ function getXPathForElement(element) {
33
+ if (element.nodeType !== 1) {
34
+ return "";
35
+ }
36
+ const getIndex = (sib, name) => {
37
+ let count = 1;
38
+ for (let cur = sib.previousSibling; cur; cur = cur.previousSibling) {
39
+ if (cur.nodeType === 1 && cur.nodeName === name) {
40
+ count++;
41
+ }
42
+ }
43
+ return count;
44
+ };
45
+ const buildAttributePart = (elem) => {
46
+ const attributes = ["id", "resource-id", "content-desc", "class"];
47
+ for (const attr of attributes) {
48
+ if (elem.hasAttribute(attr)) {
49
+ const value = elem.getAttribute(attr);
50
+ if (value && value.trim() !== "") {
51
+ return `[@${attr}="${value}"]`;
52
+ }
53
+ }
54
+ }
55
+ return "";
56
+ };
57
+ const getPath = (node, path = "") => {
58
+ if (node.parentNode) {
59
+ path = getPath(node.parentNode, path);
60
+ }
61
+ if (node.nodeType === 1) {
62
+ const elem = node;
63
+ const tagName = elem.nodeName.toLowerCase();
64
+ let part = `/${tagName}`;
65
+ const attributePart = buildAttributePart(elem);
66
+ if (attributePart) {
67
+ part += attributePart;
68
+ } else {
69
+ const index = getIndex(node, node.nodeName);
70
+ if (index > 1) {
71
+ part += `[${index}]`;
72
+ }
73
+ }
74
+ path += part;
75
+ }
76
+ return path;
77
+ };
78
+ return getPath(element);
79
+ }
80
+ function extractTextWithPosition(initNode) {
81
+ const elementInfoArray = [];
82
+ let nodeIndex = 1;
83
+ function dfs(node, parentNode = null) {
84
+ if (!node) {
85
+ return;
86
+ }
87
+ const currentNodeDes = { node, children: [] };
88
+ if (parentNode) {
89
+ parentNode.children.push(currentNodeDes);
90
+ }
91
+ collectElementInfo(node);
92
+ if (node.childNodes && node.childNodes.length > 0) {
93
+ for (let i = 0; i < node.childNodes.length; i++) {
94
+ dfs(node.childNodes[i], currentNodeDes);
95
+ }
96
+ }
97
+ }
98
+ function collectElementInfo(node) {
99
+ const attributes = getNodeAttributes(node);
100
+ const rect = getRect(attributes);
101
+ const nodeHashId = midsceneGenerateHash(null, attributes.placeholder, rect);
102
+ const text = validTextNodeContent(node);
103
+ let nodeType;
104
+ switch (node.nodeName.toUpperCase()) {
105
+ case "TEXT":
106
+ nodeType = NodeType.TEXT;
107
+ break;
108
+ case "IMAGE":
109
+ nodeType = NodeType.IMG;
110
+ break;
111
+ case "BUTTON":
112
+ nodeType = NodeType.BUTTON;
113
+ break;
114
+ case "SEARCHINPUT":
115
+ case "TEXTINPUT":
116
+ case "INPUT":
117
+ nodeType = NodeType.FORM_ITEM;
118
+ break;
119
+ case "NAV":
120
+ case "LIST":
121
+ case "CELL":
122
+ nodeType = NodeType.CONTAINER;
123
+ break;
124
+ default:
125
+ if (attributes.id === "android:id/input" || attributes.id === "android:id/inputArea") {
126
+ nodeType = NodeType.FORM_ITEM;
127
+ } else {
128
+ nodeType = NodeType.CONTAINER;
129
+ }
130
+ break;
131
+ }
132
+ const xpath = getXPathForElement(node);
133
+ const elementInfo = {
134
+ id: nodeHashId,
135
+ indexId: nodeIndex++,
136
+ nodeHashId,
137
+ locator: xpath,
138
+ attributes: {
139
+ nodeType,
140
+ ...attributes
141
+ },
142
+ content: text,
143
+ rect,
144
+ center: [
145
+ Math.round(rect.left + rect.width / 2),
146
+ Math.round(rect.top + rect.height / 2)
147
+ ],
148
+ nodeType
149
+ };
150
+ if (elementInfo.nodeType !== NodeType.CONTAINER) {
151
+ elementInfoArray.push(elementInfo);
152
+ }
153
+ }
154
+ const rootNode = initNode;
155
+ const rootDescriptor = { node: rootNode, children: [] };
156
+ dfs(rootNode, rootDescriptor);
157
+ return elementInfoArray;
158
+ }
159
+ export {
160
+ extractTextWithPosition
161
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ NodeType,
3
+ TEXT_MAX_SIZE,
4
+ TEXT_SIZE_THRESHOLD
5
+ } from "../constants";
6
+ export {
7
+ NodeType,
8
+ TEXT_MAX_SIZE,
9
+ TEXT_SIZE_THRESHOLD
10
+ };
@@ -0,0 +1,9 @@
1
+ import { webExtractTextWithPosition } from ".";
2
+ import {
3
+ setExtractTextWithPositionOnWindow,
4
+ setMidsceneVisibleRectOnWindow
5
+ } from "./util";
6
+ console.log(webExtractTextWithPosition(document.body, true));
7
+ console.log(JSON.stringify(webExtractTextWithPosition(document.body, true)));
8
+ setExtractTextWithPositionOnWindow();
9
+ setMidsceneVisibleRectOnWindow();
@@ -0,0 +1,73 @@
1
+ function isFormElement(node) {
2
+ return node instanceof HTMLElement && (node.tagName.toLowerCase() === "input" || node.tagName.toLowerCase() === "textarea" || node.tagName.toLowerCase() === "select" || node.tagName.toLowerCase() === "option");
3
+ }
4
+ function isButtonElement(node) {
5
+ return node instanceof HTMLElement && node.tagName.toLowerCase() === "button";
6
+ }
7
+ function isImgElement(node) {
8
+ if (!includeBaseElement(node) && node instanceof Element) {
9
+ const computedStyle = window.getComputedStyle(node);
10
+ const backgroundImage = computedStyle.getPropertyValue("background-image");
11
+ if (backgroundImage !== "none") {
12
+ return true;
13
+ }
14
+ }
15
+ if (isIconfont(node)) {
16
+ return true;
17
+ }
18
+ return node instanceof HTMLElement && node.tagName.toLowerCase() === "img" || node instanceof SVGElement && node.tagName.toLowerCase() === "svg";
19
+ }
20
+ function isIconfont(node) {
21
+ if (node instanceof Element) {
22
+ const computedStyle = window.getComputedStyle(node);
23
+ const fontFamilyValue = computedStyle.fontFamily || "";
24
+ return fontFamilyValue.toLowerCase().indexOf("iconfont") >= 0;
25
+ }
26
+ return false;
27
+ }
28
+ function isTextElement(node) {
29
+ return node.nodeName.toLowerCase() === "#text" && !isIconfont(node);
30
+ }
31
+ function isContainerElement(node) {
32
+ if (!(node instanceof HTMLElement))
33
+ return false;
34
+ if (includeBaseElement(node)) {
35
+ return false;
36
+ }
37
+ const computedStyle = window.getComputedStyle(node);
38
+ const backgroundColor = computedStyle.getPropertyValue("background-color");
39
+ if (backgroundColor) {
40
+ return true;
41
+ }
42
+ return false;
43
+ }
44
+ function includeBaseElement(node) {
45
+ if (!(node instanceof HTMLElement))
46
+ return false;
47
+ if (node.innerText) {
48
+ return true;
49
+ }
50
+ const includeList = [
51
+ "svg",
52
+ "button",
53
+ "input",
54
+ "textarea",
55
+ "select",
56
+ "option",
57
+ "img"
58
+ ];
59
+ for (const tagName of includeList) {
60
+ const element = node.querySelectorAll(tagName);
61
+ if (element.length > 0) {
62
+ return true;
63
+ }
64
+ }
65
+ return false;
66
+ }
67
+ export {
68
+ isButtonElement,
69
+ isContainerElement,
70
+ isFormElement,
71
+ isImgElement,
72
+ isTextElement
73
+ };
@@ -0,0 +1,14 @@
1
+ import { descriptionOfTree, traverseTree, treeToList } from "./tree";
2
+ import { extractTextWithPosition } from "./web-extractor";
3
+ import { extractTextWithPosition as extractTextWithPosition2 } from "./client-extractor";
4
+ import { extractTreeNode } from "./web-extractor";
5
+ import { extractTreeNodeAsString } from "./web-extractor";
6
+ export {
7
+ extractTextWithPosition2 as clientExtractTextWithPosition,
8
+ descriptionOfTree,
9
+ traverseTree,
10
+ treeToList,
11
+ extractTreeNode as webExtractNodeTree,
12
+ extractTreeNodeAsString as webExtractNodeTreeAsString,
13
+ extractTextWithPosition as webExtractTextWithPosition
14
+ };
@@ -0,0 +1,126 @@
1
+ function truncateText(text, maxLength = 150) {
2
+ if (typeof text === "undefined") {
3
+ return "";
4
+ }
5
+ if (typeof text === "object") {
6
+ text = JSON.stringify(text);
7
+ }
8
+ if (typeof text === "number") {
9
+ return text.toString();
10
+ }
11
+ if (typeof text === "string" && text.length > maxLength) {
12
+ return `${text.slice(0, maxLength)}...`;
13
+ }
14
+ if (typeof text === "string") {
15
+ return text.trim();
16
+ }
17
+ return "";
18
+ }
19
+ function trimAttributes(attributes, truncateTextLength) {
20
+ const tailorAttributes = Object.keys(attributes).reduce(
21
+ (res, currentKey) => {
22
+ const attributeVal = attributes[currentKey];
23
+ if (currentKey === "style" || currentKey === "src" || currentKey === "htmlTagName" || currentKey === "nodeType") {
24
+ return res;
25
+ }
26
+ res[currentKey] = truncateText(attributeVal, truncateTextLength);
27
+ return res;
28
+ },
29
+ {}
30
+ );
31
+ return tailorAttributes;
32
+ }
33
+ const nodeSizeThreshold = 4;
34
+ function descriptionOfTree(tree, truncateTextLength, filterNonTextContent = false) {
35
+ const attributesString = (kv) => {
36
+ return Object.entries(kv).map(
37
+ ([key, value]) => `${key}="${truncateText(value, truncateTextLength)}"`
38
+ ).join(" ");
39
+ };
40
+ function buildContentTree(node, indent = 0) {
41
+ let before = "";
42
+ let contentWithIndent = "";
43
+ let after = "";
44
+ let emptyNode = true;
45
+ const indentStr = " ".repeat(indent);
46
+ let children = "";
47
+ for (let i = 0; i < (node.children || []).length; i++) {
48
+ const childContent = buildContentTree(node.children[i], indent + 1);
49
+ if (childContent) {
50
+ children += `
51
+ ${childContent}`;
52
+ }
53
+ }
54
+ if (node.node && node.node.rect.width > nodeSizeThreshold && node.node.rect.height > nodeSizeThreshold && (!filterNonTextContent || filterNonTextContent && node.node.content)) {
55
+ emptyNode = false;
56
+ let nodeTypeString;
57
+ if (node.node.attributes?.htmlTagName) {
58
+ nodeTypeString = node.node.attributes.htmlTagName.replace(/[<>]/g, "");
59
+ } else {
60
+ nodeTypeString = node.node.attributes.nodeType.replace(/\sNode$/, "").toLowerCase();
61
+ }
62
+ const markerId = node.node.indexId;
63
+ const markerIdString = markerId ? `markerId="${markerId}"` : "";
64
+ const rectAttribute = node.node.rect ? {
65
+ left: node.node.rect.left,
66
+ top: node.node.rect.top,
67
+ width: node.node.rect.width,
68
+ height: node.node.rect.height
69
+ } : {};
70
+ before = `<${nodeTypeString} id="${node.node.id}" ${markerIdString} ${attributesString(trimAttributes(node.node.attributes || {}, truncateTextLength))} ${attributesString(rectAttribute)}>`;
71
+ const content = truncateText(node.node.content, truncateTextLength);
72
+ contentWithIndent = content ? `
73
+ ${indentStr} ${content}` : "";
74
+ after = `</${nodeTypeString}>`;
75
+ } else if (!filterNonTextContent) {
76
+ if (!children.trim().startsWith("<>")) {
77
+ before = "<>";
78
+ contentWithIndent = "";
79
+ after = "</>";
80
+ }
81
+ }
82
+ if (emptyNode && !children.trim()) {
83
+ return "";
84
+ }
85
+ const result2 = `${indentStr}${before}${contentWithIndent}${children}
86
+ ${indentStr}${after}`;
87
+ if (result2.trim()) {
88
+ return result2;
89
+ }
90
+ return "";
91
+ }
92
+ const result = buildContentTree(tree);
93
+ return result.replace(/^\s*\n/gm, "");
94
+ }
95
+ function treeToList(tree) {
96
+ const result = [];
97
+ function dfs(node) {
98
+ if (node.node) {
99
+ result.push(node.node);
100
+ }
101
+ for (const child of node.children) {
102
+ dfs(child);
103
+ }
104
+ }
105
+ dfs(tree);
106
+ return result;
107
+ }
108
+ function traverseTree(tree, onNode) {
109
+ function dfs(node) {
110
+ if (node.node) {
111
+ node.node = onNode(node.node);
112
+ }
113
+ for (const child of node.children) {
114
+ dfs(child);
115
+ }
116
+ }
117
+ dfs(tree);
118
+ return tree;
119
+ }
120
+ export {
121
+ descriptionOfTree,
122
+ traverseTree,
123
+ treeToList,
124
+ trimAttributes,
125
+ truncateText
126
+ };