@xiuchang-midscene/shared 2.0.2 → 2.0.3

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 (166) hide show
  1. package/dist/es/oss/index.mjs +1 -1
  2. package/dist/lib/oss/index.js +1 -1
  3. package/package.json +1 -1
  4. package/src/oss/index.ts +1 -1
  5. package/dist/es/baseDB.mjs.bak +0 -109
  6. package/dist/es/build/copy-static.mjs.bak +0 -31
  7. package/dist/es/build/rspack-config.mjs.bak +0 -4
  8. package/dist/es/cli/cli-runner.mjs.bak +0 -140
  9. package/dist/es/cli/index.mjs.bak +0 -2
  10. package/dist/es/common.mjs.bak +0 -37
  11. package/dist/es/constants/example-code.mjs.bak +0 -223
  12. package/dist/es/constants/index.mjs.bak +0 -23
  13. package/dist/es/env/basic.mjs.bak +0 -6
  14. package/dist/es/env/constants.mjs.bak +0 -70
  15. package/dist/es/env/global-config-manager.mjs.bak +0 -94
  16. package/dist/es/env/helper.mjs.bak +0 -43
  17. package/dist/es/env/index.mjs.bak +0 -5
  18. package/dist/es/env/init-debug.mjs.bak +0 -18
  19. package/dist/es/env/model-config-manager.mjs.bak +0 -79
  20. package/dist/es/env/parse-model-config.mjs.bak +0 -132
  21. package/dist/es/env/types.mjs.bak +0 -220
  22. package/dist/es/env/utils.mjs.bak +0 -26
  23. package/dist/es/extractor/constants.mjs.bak +0 -2
  24. package/dist/es/extractor/debug.mjs.bak +0 -6
  25. package/dist/es/extractor/dom-util.mjs.bak +0 -92
  26. package/dist/es/extractor/index.mjs.bak +0 -5
  27. package/dist/es/extractor/locator.mjs.bak +0 -250
  28. package/dist/es/extractor/tree.mjs.bak +0 -78
  29. package/dist/es/extractor/util.mjs.bak +0 -245
  30. package/dist/es/extractor/web-extractor.mjs.bak +0 -303
  31. package/dist/es/img/box-select.mjs.bak +0 -824
  32. package/dist/es/img/canvas-fallback.mjs.bak +0 -238
  33. package/dist/es/img/get-photon.mjs.bak +0 -45
  34. package/dist/es/img/get-sharp.mjs.bak +0 -11
  35. package/dist/es/img/index.mjs.bak +0 -4
  36. package/dist/es/img/info.mjs.bak +0 -29
  37. package/dist/es/img/transform.mjs.bak +0 -295
  38. package/dist/es/index.mjs.bak +0 -4
  39. package/dist/es/logger.mjs.bak +0 -64
  40. package/dist/es/mcp/base-server.mjs.bak +0 -281
  41. package/dist/es/mcp/base-tools.mjs.bak +0 -91
  42. package/dist/es/mcp/chrome-path.mjs.bak +0 -35
  43. package/dist/es/mcp/index.mjs.bak +0 -7
  44. package/dist/es/mcp/inject-report-html-plugin.mjs.bak +0 -53
  45. package/dist/es/mcp/launcher-helper.mjs.bak +0 -52
  46. package/dist/es/mcp/tool-generator.mjs.bak +0 -297
  47. package/dist/es/mcp/types.mjs.bak +0 -3
  48. package/dist/es/node/fs.mjs.bak +0 -44
  49. package/dist/es/node/index.mjs.bak +0 -2
  50. package/dist/es/node/port.mjs.bak +0 -24
  51. package/dist/es/oss/demo.mjs.bak +0 -30
  52. package/dist/es/oss/index.mjs.bak +0 -90
  53. package/dist/es/polyfills/async-hooks.mjs.bak +0 -2
  54. package/dist/es/polyfills/index.mjs.bak +0 -1
  55. package/dist/es/types/index.mjs.bak +0 -3
  56. package/dist/es/us-keyboard-layout.mjs.bak +0 -1414
  57. package/dist/es/utils.mjs.bak +0 -72
  58. package/dist/es/zod-schema-utils.mjs.bak +0 -54
  59. package/dist/lib/baseDB.js.bak +0 -149
  60. package/dist/lib/build/copy-static.js.bak +0 -79
  61. package/dist/lib/build/rspack-config.js.bak +0 -38
  62. package/dist/lib/cli/cli-runner.js.bak +0 -196
  63. package/dist/lib/cli/index.js.bak +0 -48
  64. package/dist/lib/common.js.bak +0 -93
  65. package/dist/lib/constants/example-code.js.bak +0 -260
  66. package/dist/lib/constants/index.js.bak +0 -96
  67. package/dist/lib/env/basic.js.bak +0 -40
  68. package/dist/lib/env/constants.js.bak +0 -113
  69. package/dist/lib/env/global-config-manager.js.bak +0 -128
  70. package/dist/lib/env/helper.js.bak +0 -80
  71. package/dist/lib/env/index.js.bak +0 -90
  72. package/dist/lib/env/init-debug.js.bak +0 -52
  73. package/dist/lib/env/model-config-manager.js.bak +0 -113
  74. package/dist/lib/env/parse-model-config.js.bak +0 -178
  75. package/dist/lib/env/types.js.bak +0 -554
  76. package/dist/lib/env/utils.js.bak +0 -72
  77. package/dist/lib/extractor/constants.js.bak +0 -42
  78. package/dist/lib/extractor/debug.js.bak +0 -12
  79. package/dist/lib/extractor/dom-util.js.bak +0 -153
  80. package/dist/lib/extractor/index.js.bak +0 -81
  81. package/dist/lib/extractor/locator.js.bak +0 -296
  82. package/dist/lib/extractor/tree.js.bak +0 -124
  83. package/dist/lib/extractor/util.js.bak +0 -336
  84. package/dist/lib/extractor/web-extractor.js.bak +0 -349
  85. package/dist/lib/img/box-select.js.bak +0 -875
  86. package/dist/lib/img/canvas-fallback.js.bak +0 -305
  87. package/dist/lib/img/get-photon.js.bak +0 -82
  88. package/dist/lib/img/get-sharp.js.bak +0 -45
  89. package/dist/lib/img/index.js.bak +0 -95
  90. package/dist/lib/img/info.js.bak +0 -83
  91. package/dist/lib/img/transform.js.bak +0 -387
  92. package/dist/lib/index.js.bak +0 -47
  93. package/dist/lib/logger.js.bak +0 -114
  94. package/dist/lib/mcp/base-server.js.bak +0 -331
  95. package/dist/lib/mcp/base-tools.js.bak +0 -125
  96. package/dist/lib/mcp/chrome-path.js.bak +0 -72
  97. package/dist/lib/mcp/index.js.bak +0 -100
  98. package/dist/lib/mcp/inject-report-html-plugin.js.bak +0 -98
  99. package/dist/lib/mcp/launcher-helper.js.bak +0 -86
  100. package/dist/lib/mcp/tool-generator.js.bak +0 -334
  101. package/dist/lib/mcp/types.js.bak +0 -40
  102. package/dist/lib/node/fs.js.bak +0 -97
  103. package/dist/lib/node/index.js.bak +0 -65
  104. package/dist/lib/node/port.js.bak +0 -61
  105. package/dist/lib/oss/demo.js.bak +0 -36
  106. package/dist/lib/oss/index.js.bak +0 -138
  107. package/dist/lib/polyfills/async-hooks.js.bak +0 -36
  108. package/dist/lib/polyfills/index.js.bak +0 -58
  109. package/dist/lib/types/index.js.bak +0 -37
  110. package/dist/lib/us-keyboard-layout.js.bak +0 -1457
  111. package/dist/lib/utils.js.bak +0 -148
  112. package/dist/lib/zod-schema-utils.js.bak +0 -97
  113. package/dist/types/baseDB.d.ts.bak +0 -25
  114. package/dist/types/build/copy-static.d.ts.bak +0 -31
  115. package/dist/types/build/rspack-config.d.ts.bak +0 -8
  116. package/dist/types/cli/cli-runner.d.ts.bak +0 -14
  117. package/dist/types/cli/index.d.ts.bak +0 -2
  118. package/dist/types/common.d.ts.bak +0 -12
  119. package/dist/types/constants/example-code.d.ts.bak +0 -2
  120. package/dist/types/constants/index.d.ts.bak +0 -21
  121. package/dist/types/env/basic.d.ts.bak +0 -6
  122. package/dist/types/env/constants.d.ts.bak +0 -40
  123. package/dist/types/env/global-config-manager.d.ts.bak +0 -32
  124. package/dist/types/env/helper.d.ts.bak +0 -4
  125. package/dist/types/env/index.d.ts.bak +0 -4
  126. package/dist/types/env/init-debug.d.ts.bak +0 -1
  127. package/dist/types/env/model-config-manager.d.ts.bak +0 -25
  128. package/dist/types/env/parse-model-config.d.ts.bak +0 -31
  129. package/dist/types/env/types.d.ts.bak +0 -318
  130. package/dist/types/env/utils.d.ts.bak +0 -38
  131. package/dist/types/extractor/constants.d.ts.bak +0 -1
  132. package/dist/types/extractor/debug.d.ts.bak +0 -1
  133. package/dist/types/extractor/dom-util.d.ts.bak +0 -56
  134. package/dist/types/extractor/index.d.ts.bak +0 -32
  135. package/dist/types/extractor/locator.d.ts.bak +0 -9
  136. package/dist/types/extractor/tree.d.ts.bak +0 -6
  137. package/dist/types/extractor/util.d.ts.bak +0 -47
  138. package/dist/types/extractor/web-extractor.d.ts.bak +0 -19
  139. package/dist/types/img/box-select.d.ts.bak +0 -26
  140. package/dist/types/img/canvas-fallback.d.ts.bak +0 -105
  141. package/dist/types/img/get-photon.d.ts.bak +0 -19
  142. package/dist/types/img/get-sharp.d.ts.bak +0 -3
  143. package/dist/types/img/index.d.ts.bak +0 -3
  144. package/dist/types/img/info.d.ts.bak +0 -29
  145. package/dist/types/img/transform.d.ts.bak +0 -107
  146. package/dist/types/index.d.ts.bak +0 -4
  147. package/dist/types/logger.d.ts.bak +0 -5
  148. package/dist/types/mcp/base-server.d.ts.bak +0 -93
  149. package/dist/types/mcp/base-tools.d.ts.bak +0 -79
  150. package/dist/types/mcp/chrome-path.d.ts.bak +0 -2
  151. package/dist/types/mcp/index.d.ts.bak +0 -7
  152. package/dist/types/mcp/inject-report-html-plugin.d.ts.bak +0 -18
  153. package/dist/types/mcp/launcher-helper.d.ts.bak +0 -94
  154. package/dist/types/mcp/tool-generator.d.ts.bak +0 -10
  155. package/dist/types/mcp/types.d.ts.bak +0 -103
  156. package/dist/types/node/fs.d.ts.bak +0 -15
  157. package/dist/types/node/index.d.ts.bak +0 -2
  158. package/dist/types/node/port.d.ts.bak +0 -8
  159. package/dist/types/oss/demo.d.ts.bak +0 -1
  160. package/dist/types/oss/index.d.ts.bak +0 -34
  161. package/dist/types/polyfills/async-hooks.d.ts.bak +0 -6
  162. package/dist/types/polyfills/index.d.ts.bak +0 -4
  163. package/dist/types/types/index.d.ts.bak +0 -34
  164. package/dist/types/us-keyboard-layout.d.ts.bak +0 -32
  165. package/dist/types/utils.d.ts.bak +0 -34
  166. package/dist/types/zod-schema-utils.d.ts.bak +0 -23
@@ -1,26 +0,0 @@
1
- import { GlobalConfigManager } from "./global-config-manager.mjs";
2
- import { ModelConfigManager } from "./model-config-manager.mjs";
3
- import { MIDSCENE_PREFERRED_LANGUAGE } from "./types.mjs";
4
- const globalModelConfigManager = new ModelConfigManager();
5
- const globalConfigManager = new GlobalConfigManager();
6
- globalConfigManager.registerModelConfigManager(globalModelConfigManager);
7
- globalModelConfigManager.registerGlobalConfigManager(globalConfigManager);
8
- async function getCurrentTime(device, useDeviceTimestamp) {
9
- if (useDeviceTimestamp && device?.getTimestamp) try {
10
- return await device.getTimestamp();
11
- } catch (error) {
12
- console.warn(`Failed to get device time, falling back to system time: ${error}`);
13
- }
14
- return Date.now();
15
- }
16
- const getPreferredLanguage = ()=>{
17
- const prefer = globalConfigManager.getEnvConfigValue(MIDSCENE_PREFERRED_LANGUAGE);
18
- if (prefer) return prefer;
19
- const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
20
- const isChina = 'Asia/Shanghai' === timeZone;
21
- return isChina ? 'Chinese' : 'English';
22
- };
23
- const overrideAIConfig = (newConfig, extendMode = false)=>{
24
- globalConfigManager.overrideAIConfig(newConfig, extendMode);
25
- };
26
- export { getCurrentTime, getPreferredLanguage, globalConfigManager, globalModelConfigManager, overrideAIConfig };
@@ -1,2 +0,0 @@
1
- import { NodeType, TEXT_MAX_SIZE, TEXT_SIZE_THRESHOLD } from "../constants/index.mjs";
2
- export { NodeType, TEXT_MAX_SIZE, TEXT_SIZE_THRESHOLD };
@@ -1,6 +0,0 @@
1
- import { webExtractTextWithPosition } from "./index.mjs";
2
- import { setExtractTextWithPositionOnWindow, setMidsceneVisibleRectOnWindow } from "./util.mjs";
3
- console.log(webExtractTextWithPosition(document.body, true));
4
- console.log(JSON.stringify(webExtractTextWithPosition(document.body, true)));
5
- setExtractTextWithPositionOnWindow();
6
- setMidsceneVisibleRectOnWindow();
@@ -1,92 +0,0 @@
1
- function isFormElement(node) {
2
- return node instanceof HTMLElement && ('input' === node.tagName.toLowerCase() || 'textarea' === node.tagName.toLowerCase() || 'select' === node.tagName.toLowerCase() || 'option' === node.tagName.toLowerCase());
3
- }
4
- function isButtonElement(node) {
5
- return node instanceof HTMLElement && 'button' === node.tagName.toLowerCase();
6
- }
7
- function isAElement(node) {
8
- return node instanceof HTMLElement && 'a' === node.tagName.toLowerCase();
9
- }
10
- function isSvgElement(node) {
11
- return node instanceof SVGElement;
12
- }
13
- function isImgElement(node) {
14
- if (!includeBaseElement(node) && node instanceof Element) {
15
- const computedStyle = window.getComputedStyle(node);
16
- const backgroundImage = computedStyle.getPropertyValue('background-image');
17
- if ('none' !== backgroundImage) return true;
18
- }
19
- if (isIconfont(node)) return true;
20
- return node instanceof HTMLElement && 'img' === node.tagName.toLowerCase() || node instanceof SVGElement && 'svg' === node.tagName.toLowerCase();
21
- }
22
- function isIconfont(node) {
23
- if (node instanceof Element) {
24
- const computedStyle = window.getComputedStyle(node);
25
- const fontFamilyValue = computedStyle.fontFamily || '';
26
- return fontFamilyValue.toLowerCase().indexOf('iconfont') >= 0;
27
- }
28
- return false;
29
- }
30
- function isNotContainerElement(node) {
31
- return isTextElement(node) || isIconfont(node) || isImgElement(node) || isButtonElement(node) || isAElement(node) || isFormElement(node);
32
- }
33
- function isTextElement(node) {
34
- if (node instanceof Element) {
35
- if (node?.childNodes?.length === 1 && node?.childNodes[0] instanceof Text) return true;
36
- }
37
- return node.nodeName?.toLowerCase?.() === '#text' && !isIconfont(node);
38
- }
39
- function isContainerElement(node) {
40
- if (!(node instanceof HTMLElement)) return false;
41
- if (includeBaseElement(node)) return false;
42
- const computedStyle = window.getComputedStyle(node);
43
- const backgroundColor = computedStyle.getPropertyValue('background-color');
44
- if (backgroundColor) return true;
45
- return false;
46
- }
47
- function includeBaseElement(node) {
48
- if (!(node instanceof HTMLElement)) return false;
49
- if (node.innerText) return true;
50
- const includeList = [
51
- 'svg',
52
- 'button',
53
- 'input',
54
- 'textarea',
55
- 'select',
56
- 'option',
57
- 'img',
58
- 'a'
59
- ];
60
- for (const tagName of includeList){
61
- const element = node.querySelectorAll(tagName);
62
- if (element.length > 0) return true;
63
- }
64
- return false;
65
- }
66
- function generateElementByPoint(center, description, edgeSize = 8) {
67
- const [centerX, centerY] = center;
68
- const offset = Math.ceil(edgeSize / 2) - 1;
69
- const expandedRect = {
70
- left: Math.max(centerX - offset, 0),
71
- top: Math.max(centerY - offset, 0),
72
- width: edgeSize,
73
- height: edgeSize
74
- };
75
- return {
76
- rect: expandedRect,
77
- center: [
78
- centerX,
79
- centerY
80
- ],
81
- description: description || ''
82
- };
83
- }
84
- function generateElementByRect(sourceRect, description, edgeSize = 8) {
85
- const centerX = sourceRect.left + Math.floor((sourceRect.width - 1) / 2);
86
- const centerY = sourceRect.top + Math.floor((sourceRect.height - 1) / 2);
87
- return generateElementByPoint([
88
- centerX,
89
- centerY
90
- ], description, edgeSize);
91
- }
92
- export { generateElementByPoint, generateElementByRect, isAElement, isButtonElement, isContainerElement, isFormElement, isImgElement, isNotContainerElement, isSvgElement, isTextElement };
@@ -1,5 +0,0 @@
1
- import { descriptionOfTree, traverseTree, treeToList, trimAttributes, truncateText } from "./tree.mjs";
2
- import { extractTextWithPosition, extractTreeNode, extractTreeNodeAsString } from "./web-extractor.mjs";
3
- import { getElementInfoByXpath, getElementXpath, getNodeInfoByXpath, getXpathsById, getXpathsByPoint } from "./locator.mjs";
4
- import { generateElementByRect, isNotContainerElement } from "./dom-util.mjs";
5
- export { descriptionOfTree, generateElementByRect, getElementInfoByXpath, getElementXpath, getNodeInfoByXpath, getXpathsById, getXpathsByPoint, isNotContainerElement, traverseTree, treeToList, trimAttributes, truncateText, extractTreeNode as webExtractNodeTree, extractTreeNodeAsString as webExtractNodeTreeAsString, extractTextWithPosition as webExtractTextWithPosition };
@@ -1,250 +0,0 @@
1
- import { isSvgElement } from "./dom-util.mjs";
2
- import { getNodeFromCacheList, getRect, isElementPartiallyInViewport, logger } from "./util.mjs";
3
- import { collectElementInfo } from "./web-extractor.mjs";
4
- const SUB_XPATH_SEPARATOR = '|>>|';
5
- function parseCSSZoom(style) {
6
- return Number.parseFloat(style.zoom ?? '1') || 1;
7
- }
8
- function calculateIframeOffset(nodeOwnerDoc, rootDoc) {
9
- let leftOffset = 0;
10
- let topOffset = 0;
11
- let iterDoc = nodeOwnerDoc;
12
- while(iterDoc && iterDoc !== rootDoc)try {
13
- const frameElement = iterDoc.defaultView?.frameElement;
14
- if (!frameElement) break;
15
- const rect = frameElement.getBoundingClientRect();
16
- const parentWin = iterDoc.defaultView?.parent;
17
- let borderLeft = 0;
18
- let borderTop = 0;
19
- let zoom = 1;
20
- try {
21
- if (parentWin) {
22
- const style = parentWin.getComputedStyle(frameElement);
23
- borderLeft = Number.parseFloat(style.borderLeftWidth) || 0;
24
- borderTop = Number.parseFloat(style.borderTopWidth) || 0;
25
- zoom = parseCSSZoom(style);
26
- }
27
- } catch {}
28
- leftOffset = leftOffset / zoom + rect.left + borderLeft;
29
- topOffset = topOffset / zoom + rect.top + borderTop;
30
- iterDoc = frameElement.ownerDocument;
31
- } catch {
32
- break;
33
- }
34
- return {
35
- left: leftOffset,
36
- top: topOffset
37
- };
38
- }
39
- function translatePointToIframeCoordinates(point, iframeElement, parentWindow) {
40
- const rect = iframeElement.getBoundingClientRect();
41
- const style = parentWindow.getComputedStyle(iframeElement);
42
- const clientLeft = iframeElement.clientLeft;
43
- const clientTop = iframeElement.clientTop;
44
- const paddingLeft = Number.parseFloat(style.paddingLeft) || 0;
45
- const paddingTop = Number.parseFloat(style.paddingTop) || 0;
46
- const zoom = parseCSSZoom(style);
47
- return {
48
- left: (point.left - rect.left - clientLeft - paddingLeft) / zoom,
49
- top: (point.top - rect.top - clientTop - paddingTop) / zoom
50
- };
51
- }
52
- const getElementXpathIndex = (element)=>{
53
- let index = 1;
54
- let prev = element.previousElementSibling;
55
- while(prev){
56
- if (prev.nodeName.toLowerCase() === element.nodeName.toLowerCase()) index++;
57
- prev = prev.previousElementSibling;
58
- }
59
- return index;
60
- };
61
- const normalizeXpathText = (text)=>{
62
- if ('string' != typeof text) return '';
63
- return text.replace(/\s+/g, ' ').trim();
64
- };
65
- const buildCurrentElementXpath = (element, isOrderSensitive, isLeafElement, limitToCurrentDocument = false)=>{
66
- const parentPath = element.parentNode ? getElementXpath(element.parentNode, isOrderSensitive, false, limitToCurrentDocument) : '';
67
- const prefix = parentPath ? `${parentPath}/` : '/';
68
- const tagName = element.nodeName.toLowerCase();
69
- const textContent = element.textContent?.trim();
70
- const isSVGNamespace = 'http://www.w3.org/2000/svg' === element.namespaceURI;
71
- const tagSelector = isSVGNamespace ? `*[name()="${tagName}"]` : tagName;
72
- if (isOrderSensitive) {
73
- const index = getElementXpathIndex(element);
74
- return `${prefix}${tagSelector}[${index}]`;
75
- }
76
- if (isLeafElement && textContent) return `${prefix}${tagSelector}[normalize-space()="${normalizeXpathText(textContent)}"]`;
77
- const index = getElementXpathIndex(element);
78
- return `${prefix}${tagSelector}[${index}]`;
79
- };
80
- const getElementXpath = (element, isOrderSensitive = false, isLeafElement = false, limitToCurrentDocument = false)=>{
81
- if (element.nodeType === Node.TEXT_NODE) {
82
- const parentNode = element.parentNode;
83
- if (parentNode && parentNode.nodeType === Node.ELEMENT_NODE) {
84
- const parentXPath = getElementXpath(parentNode, isOrderSensitive, true, limitToCurrentDocument);
85
- const textContent = element.textContent?.trim();
86
- if (textContent) return `${parentXPath}/text()[normalize-space()="${normalizeXpathText(textContent)}"]`;
87
- return `${parentXPath}/text()`;
88
- }
89
- return '';
90
- }
91
- if (element.nodeType !== Node.ELEMENT_NODE) return '';
92
- const el = element;
93
- try {
94
- const nodeName = el.nodeName.toLowerCase();
95
- if (el === el.ownerDocument?.documentElement || 'html' === nodeName) {
96
- if (!limitToCurrentDocument) {
97
- const frameElement = el.ownerDocument?.defaultView?.frameElement;
98
- if (frameElement) {
99
- const framePath = getElementXpath(frameElement, isOrderSensitive, false, limitToCurrentDocument);
100
- return `${framePath}${SUB_XPATH_SEPARATOR}/html`;
101
- }
102
- }
103
- return '/html';
104
- }
105
- if (el === el.ownerDocument?.body || 'body' === nodeName) {
106
- if (!limitToCurrentDocument) {
107
- const frameElement = el.ownerDocument?.defaultView?.frameElement;
108
- if (frameElement) {
109
- const framePath = getElementXpath(frameElement, isOrderSensitive, false, limitToCurrentDocument);
110
- return `${framePath}${SUB_XPATH_SEPARATOR}/html/body`;
111
- }
112
- }
113
- return '/html/body';
114
- }
115
- } catch (error) {
116
- logger('[midscene:locator] ownerDocument access failed:', error);
117
- if ('html' === el.nodeName.toLowerCase()) return '/html';
118
- if ('body' === el.nodeName.toLowerCase()) return '/html/body';
119
- }
120
- if (isSvgElement(el)) {
121
- const tagName = el.nodeName.toLowerCase();
122
- if ('svg' === tagName) return buildCurrentElementXpath(el, isOrderSensitive, isLeafElement, limitToCurrentDocument);
123
- let parent = el.parentNode;
124
- while(parent && parent.nodeType === Node.ELEMENT_NODE){
125
- const parentEl = parent;
126
- if (!isSvgElement(parentEl)) return getElementXpath(parentEl, isOrderSensitive, isLeafElement, limitToCurrentDocument);
127
- const parentTag = parentEl.nodeName.toLowerCase();
128
- if ('svg' === parentTag) return getElementXpath(parentEl, isOrderSensitive, isLeafElement, limitToCurrentDocument);
129
- parent = parent.parentNode;
130
- }
131
- const fallbackParent = el.parentNode;
132
- if (fallbackParent && fallbackParent.nodeType === Node.ELEMENT_NODE) return getElementXpath(fallbackParent, isOrderSensitive, isLeafElement, limitToCurrentDocument);
133
- return '';
134
- }
135
- return buildCurrentElementXpath(el, isOrderSensitive, isLeafElement, limitToCurrentDocument);
136
- };
137
- function getXpathsById(id) {
138
- const node = getNodeFromCacheList(id);
139
- if (!node) return null;
140
- const fullXPath = getElementXpath(node, false, true, true);
141
- return [
142
- fullXPath
143
- ];
144
- }
145
- function getXpathsByPoint(point, isOrderSensitive) {
146
- let currentWindow = 'undefined' != typeof window ? window : void 0;
147
- let currentDocument = 'undefined' != typeof document ? document : void 0;
148
- let { left, top } = point;
149
- let depth = 0;
150
- const MAX_DEPTH = 10;
151
- let xpathPrefix = '';
152
- let lastFoundElement = null;
153
- while(depth < MAX_DEPTH){
154
- depth++;
155
- const element = currentDocument.elementFromPoint(left, top);
156
- if (!element) {
157
- if (lastFoundElement) {
158
- const fullXPath = getElementXpath(lastFoundElement, isOrderSensitive, true, true);
159
- return [
160
- xpathPrefix + fullXPath
161
- ];
162
- }
163
- return null;
164
- }
165
- lastFoundElement = element;
166
- const tag = element.tagName.toLowerCase();
167
- if ('iframe' === tag || 'frame' === tag) try {
168
- const contentWindow = element.contentWindow;
169
- const contentDocument = element.contentDocument;
170
- if (contentWindow && contentDocument) {
171
- const localPoint = translatePointToIframeCoordinates({
172
- left,
173
- top
174
- }, element, currentWindow);
175
- const currentIframeXpath = getElementXpath(element, isOrderSensitive, false, true);
176
- xpathPrefix += currentIframeXpath + SUB_XPATH_SEPARATOR;
177
- currentWindow = contentWindow;
178
- currentDocument = contentDocument;
179
- left = localPoint.left;
180
- top = localPoint.top;
181
- continue;
182
- }
183
- } catch (error) {
184
- logger('[midscene:locator] iframe penetration failed (cross-origin?):', error);
185
- }
186
- const fullXPath = getElementXpath(element, isOrderSensitive, true, true);
187
- return [
188
- xpathPrefix + fullXPath
189
- ];
190
- }
191
- if (lastFoundElement) {
192
- const fullXPath = getElementXpath(lastFoundElement, isOrderSensitive, true, true);
193
- return [
194
- xpathPrefix + fullXPath
195
- ];
196
- }
197
- return null;
198
- }
199
- function getNodeInfoByXpath(xpath) {
200
- const parts = xpath.split(SUB_XPATH_SEPARATOR).map((p)=>p.trim()).filter(Boolean);
201
- if (0 === parts.length) return null;
202
- let currentDocument = 'undefined' != typeof document ? document : void 0;
203
- let node = null;
204
- for(let i = 0; i < parts.length; i++){
205
- const currentXpath = parts[i];
206
- const xpathResult = currentDocument.evaluate(currentXpath, currentDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
207
- if (1 !== xpathResult.snapshotLength) {
208
- logger(`[midscene:locator] XPath "${currentXpath}" matched ${xpathResult.snapshotLength} elements (expected 1), discarding.`);
209
- return null;
210
- }
211
- node = xpathResult.snapshotItem(0);
212
- if (i < parts.length - 1) if (!node || node.nodeType !== Node.ELEMENT_NODE || 'iframe' !== node.tagName.toLowerCase()) return null;
213
- else try {
214
- const contentDocument = node.contentDocument;
215
- if (contentDocument) currentDocument = contentDocument;
216
- else {
217
- logger('[midscene:locator] iframe contentDocument is null (cross-origin?)');
218
- return null;
219
- }
220
- } catch (error) {
221
- logger('[midscene:locator] iframe contentDocument access failed:', error);
222
- return null;
223
- }
224
- }
225
- return node;
226
- }
227
- function getElementInfoByXpath(xpath) {
228
- const node = getNodeInfoByXpath(xpath);
229
- if (!node) return null;
230
- let targetWindow = 'undefined' != typeof window ? window : void 0;
231
- let targetDocument = 'undefined' != typeof document ? document : void 0;
232
- if (node.ownerDocument?.defaultView) {
233
- targetWindow = node.ownerDocument.defaultView;
234
- targetDocument = node.ownerDocument;
235
- }
236
- const rootDoc = 'undefined' != typeof document ? document : null;
237
- const iframeOffset = calculateIframeOffset(node.ownerDocument ?? null, rootDoc);
238
- const targetWin = targetWindow;
239
- const targetDoc = targetDocument;
240
- if (node instanceof targetWin.HTMLElement) {
241
- const rect = getRect(node, 1, targetWin);
242
- const isVisible = isElementPartiallyInViewport(rect, targetWin, targetDoc, 1);
243
- if (!isVisible) node.scrollIntoView({
244
- behavior: 'instant',
245
- block: 'center'
246
- });
247
- }
248
- return collectElementInfo(node, targetWin, targetDoc, 1, iframeOffset, true);
249
- }
250
- export { getElementInfoByXpath, getElementXpath, getNodeInfoByXpath, getXpathsById, getXpathsByPoint };
@@ -1,78 +0,0 @@
1
- function truncateText(text, maxLength = 150) {
2
- if (void 0 === text) return '';
3
- if ('object' == typeof text) text = JSON.stringify(text);
4
- if ('number' == typeof text) return text.toString();
5
- if ('string' == typeof text && text.length > maxLength) return `${text.slice(0, maxLength)}...`;
6
- if ('string' == typeof text) return text.trim();
7
- return '';
8
- }
9
- function trimAttributes(attributes, truncateTextLength) {
10
- const tailorAttributes = Object.keys(attributes).reduce((res, currentKey)=>{
11
- const attributeVal = attributes[currentKey];
12
- if ('style' === currentKey || 'htmlTagName' === currentKey || 'nodeType' === currentKey) return res;
13
- res[currentKey] = truncateText(attributeVal, truncateTextLength);
14
- return res;
15
- }, {});
16
- return tailorAttributes;
17
- }
18
- const nodeSizeThreshold = 4;
19
- function descriptionOfTree(tree, truncateTextLength, filterNonTextContent = false, visibleOnly = true) {
20
- const attributesString = (kv)=>Object.entries(kv).map(([key, value])=>`${key}="${truncateText(value, truncateTextLength)}"`).join(' ');
21
- function buildContentTree(node, indent = 0, visibleOnly = true) {
22
- let before = '';
23
- let contentWithIndent = '';
24
- let after = '';
25
- let emptyNode = true;
26
- const indentStr = ' '.repeat(indent);
27
- let children = '';
28
- for(let i = 0; i < (node.children || []).length; i++){
29
- const childContent = buildContentTree(node.children[i], indent + 1, visibleOnly);
30
- if (childContent) children += `\n${childContent}`;
31
- }
32
- if (node.node && node.node.rect.width > nodeSizeThreshold && node.node.rect.height > nodeSizeThreshold && (!filterNonTextContent || filterNonTextContent && node.node.content) && (!visibleOnly || visibleOnly && node.node.isVisible)) {
33
- emptyNode = false;
34
- let nodeTypeString;
35
- nodeTypeString = node.node.attributes?.htmlTagName ? node.node.attributes.htmlTagName.replace(/[<>]/g, '') : node.node.attributes.nodeType.replace(/\sNode$/, '').toLowerCase();
36
- const rectAttribute = node.node.rect ? {
37
- left: node.node.rect.left,
38
- top: node.node.rect.top,
39
- width: node.node.rect.width,
40
- height: node.node.rect.height
41
- } : {};
42
- before = `<${nodeTypeString} id="${node.node.id}" ${attributesString(trimAttributes(node.node.attributes || {}, truncateTextLength))} ${attributesString(rectAttribute)}>`;
43
- const content = truncateText(node.node.content, truncateTextLength);
44
- contentWithIndent = content ? `\n${indentStr} ${content}` : '';
45
- after = `</${nodeTypeString}>`;
46
- } else if (!filterNonTextContent) {
47
- if (!children.trim().startsWith('<>')) {
48
- before = '<>';
49
- contentWithIndent = '';
50
- after = '</>';
51
- }
52
- }
53
- if (emptyNode && !children.trim()) return '';
54
- const result = `${indentStr}${before}${contentWithIndent}${children}\n${indentStr}${after}`;
55
- if (result.trim()) return result;
56
- return '';
57
- }
58
- const result = buildContentTree(tree, 0, visibleOnly);
59
- return result.replace(/^\s*\n/gm, '');
60
- }
61
- function treeToList(tree) {
62
- const result = [];
63
- function dfs(node) {
64
- if (node.node) result.push(node.node);
65
- for (const child of node.children)dfs(child);
66
- }
67
- dfs(tree);
68
- return result;
69
- }
70
- function traverseTree(tree, onNode) {
71
- function dfs(node) {
72
- if (node.node) node.node = onNode(node.node);
73
- for (const child of node.children)dfs(child);
74
- }
75
- dfs(tree);
76
- return tree;
77
- }
78
- export { descriptionOfTree, traverseTree, treeToList, trimAttributes, truncateText };