browser-debugger-cli 0.8.0 → 0.10.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 (304) hide show
  1. package/README.md +7 -1
  2. package/dist/cdp/schema.d.ts +4 -1
  3. package/dist/cdp/schema.js +48 -7
  4. package/dist/commands/cdp.js +3 -2
  5. package/dist/commands/cleanup.d.ts +11 -0
  6. package/dist/commands/cleanup.js +161 -57
  7. package/dist/commands/console.d.ts +20 -1
  8. package/dist/commands/console.js +57 -17
  9. package/dist/commands/details.js +3 -2
  10. package/dist/commands/dom/DomElementResolver.d.ts +10 -3
  11. package/dist/commands/dom/DomElementResolver.js +35 -17
  12. package/dist/commands/dom/a11y.d.ts +10 -0
  13. package/dist/commands/dom/a11y.js +29 -6
  14. package/dist/commands/dom/eval.d.ts +3 -1
  15. package/dist/commands/dom/eval.js +29 -4
  16. package/dist/commands/dom/form.js +16 -62
  17. package/dist/commands/dom/formInteraction.js +189 -119
  18. package/dist/commands/dom/formSummary.d.ts +49 -0
  19. package/dist/commands/dom/formSummary.js +180 -0
  20. package/dist/commands/dom/frames.d.ts +2 -1
  21. package/dist/commands/dom/frames.js +17 -2
  22. package/dist/commands/dom/get.d.ts +6 -5
  23. package/dist/commands/dom/get.js +92 -82
  24. package/dist/commands/dom/helpers/index.d.ts +1 -1
  25. package/dist/commands/dom/helpers/index.js +1 -1
  26. package/dist/commands/dom/helpers/keyAttributes.d.ts +20 -0
  27. package/dist/commands/dom/helpers/keyAttributes.js +54 -0
  28. package/dist/commands/dom/helpers/query.d.ts +44 -17
  29. package/dist/commands/dom/helpers/query.js +300 -106
  30. package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
  31. package/dist/commands/dom/helpers/runElementCommand.js +98 -30
  32. package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
  33. package/dist/commands/dom/helpers/screenshot.js +239 -51
  34. package/dist/commands/dom/index.d.ts +4 -1
  35. package/dist/commands/dom/index.js +22 -7
  36. package/dist/commands/dom/inspect.d.ts +15 -0
  37. package/dist/commands/dom/inspect.js +82 -0
  38. package/dist/commands/dom/layout.d.ts +14 -0
  39. package/dist/commands/dom/layout.js +54 -0
  40. package/dist/commands/dom/listeners.d.ts +5 -1
  41. package/dist/commands/dom/listeners.js +15 -5
  42. package/dist/commands/dom/query.js +2 -3
  43. package/dist/commands/dom/screenshot.d.ts +12 -2
  44. package/dist/commands/dom/screenshot.js +27 -3
  45. package/dist/commands/dom/semanticUtils.d.ts +16 -10
  46. package/dist/commands/dom/semanticUtils.js +53 -16
  47. package/dist/commands/dom/wait.d.ts +13 -0
  48. package/dist/commands/dom/wait.js +83 -0
  49. package/dist/commands/helpJson.js +2 -2
  50. package/dist/commands/network/list.js +17 -13
  51. package/dist/commands/optionBehaviors.js +154 -21
  52. package/dist/commands/page.d.ts +3 -2
  53. package/dist/commands/page.js +100 -5
  54. package/dist/commands/peek.js +4 -11
  55. package/dist/commands/sessions.d.ts +8 -0
  56. package/dist/commands/sessions.js +19 -0
  57. package/dist/commands/shared/CommandRunner.js +4 -4
  58. package/dist/commands/shared/commonOptions.d.ts +4 -0
  59. package/dist/commands/shared/commonOptions.js +9 -0
  60. package/dist/commands/shared/dataFetcher.js +2 -2
  61. package/dist/commands/shared/followMode.d.ts +21 -1
  62. package/dist/commands/shared/followMode.js +29 -2
  63. package/dist/commands/shared/handleValidationError.d.ts +2 -2
  64. package/dist/commands/shared/handleValidationError.js +12 -3
  65. package/dist/commands/shared/optionTypes.d.ts +61 -5
  66. package/dist/commands/shared/startHelpers.d.ts +66 -0
  67. package/dist/commands/shared/startHelpers.js +103 -13
  68. package/dist/commands/shared/validation.d.ts +14 -2
  69. package/dist/commands/shared/validation.js +20 -3
  70. package/dist/commands/start.d.ts +63 -0
  71. package/dist/commands/start.js +115 -15
  72. package/dist/commands/status.js +29 -7
  73. package/dist/commands/stop.js +7 -6
  74. package/dist/commands/tail.js +4 -11
  75. package/dist/commands/types.d.ts +2 -0
  76. package/dist/commands.js +2 -0
  77. package/dist/connection/chromeIdentity.d.ts +65 -0
  78. package/dist/connection/chromeIdentity.js +143 -0
  79. package/dist/connection/launcher/profilePreferences.d.ts +47 -0
  80. package/dist/connection/launcher/profilePreferences.js +151 -0
  81. package/dist/connection/launcher.d.ts +21 -2
  82. package/dist/connection/launcher.js +42 -16
  83. package/dist/connection/portReservation.d.ts +14 -4
  84. package/dist/connection/portReservation.js +21 -6
  85. package/dist/connection/startupExit.d.ts +8 -0
  86. package/dist/connection/startupExit.js +15 -6
  87. package/dist/constants.d.ts +6 -2
  88. package/dist/constants.js +9 -2
  89. package/dist/daemon/SessionController.js +23 -7
  90. package/dist/daemon/errors.d.ts +1 -1
  91. package/dist/daemon/errors.js +1 -1
  92. package/dist/daemon/launcher.d.ts +10 -2
  93. package/dist/daemon/launcher.js +8 -7
  94. package/dist/daemon/server/SocketServer.js +1 -2
  95. package/dist/daemon/session/Session.d.ts +20 -0
  96. package/dist/daemon/session/Session.js +80 -9
  97. package/dist/daemon/session/chromeConnection.d.ts +9 -0
  98. package/dist/daemon/session/chromeConnection.js +45 -8
  99. package/dist/daemon/session/commandRegistry.d.ts +14 -1
  100. package/dist/daemon/session/commandRegistry.js +113 -67
  101. package/dist/daemon/session/interactions.d.ts +48 -9
  102. package/dist/daemon/session/interactions.js +46 -9
  103. package/dist/daemon/session/triggeredRequests.d.ts +67 -0
  104. package/dist/daemon/session/triggeredRequests.js +157 -0
  105. package/dist/daemon/session/types.d.ts +5 -1
  106. package/dist/daemon.js +10630 -3601
  107. package/dist/errors/messages.d.ts +456 -24
  108. package/dist/errors/messages.js +862 -67
  109. package/dist/index.js +6915 -3401
  110. package/dist/ipc/client.d.ts +21 -1
  111. package/dist/ipc/client.js +35 -3
  112. package/dist/ipc/protocol/commands.d.ts +145 -5
  113. package/dist/ipc/protocol/commands.js +4 -0
  114. package/dist/ipc/protocol/domTypes.d.ts +291 -7
  115. package/dist/ipc/protocol/inspectTypes.d.ts +388 -0
  116. package/dist/ipc/protocol/inspectTypes.js +10 -0
  117. package/dist/ipc/session/lifecycle.d.ts +8 -1
  118. package/dist/ipc/session/queries.d.ts +5 -1
  119. package/dist/ipc/session/types.d.ts +5 -0
  120. package/dist/ipc/transport/index.d.ts +2 -1
  121. package/dist/ipc/transport/index.js +2 -2
  122. package/dist/runtime/dom/actionEffects.d.ts +185 -0
  123. package/dist/runtime/dom/actionEffects.js +402 -0
  124. package/dist/runtime/dom/actionEffectsScripts.d.ts +90 -0
  125. package/dist/runtime/dom/actionEffectsScripts.js +426 -0
  126. package/dist/runtime/dom/elementGeometry.d.ts +170 -0
  127. package/dist/runtime/dom/elementGeometry.js +553 -0
  128. package/dist/runtime/dom/elementInfo.d.ts +103 -0
  129. package/dist/runtime/dom/elementInfo.js +256 -0
  130. package/dist/runtime/dom/evalHelpers.d.ts +51 -6
  131. package/dist/runtime/dom/evalHelpers.js +136 -26
  132. package/dist/runtime/dom/eventListeners.d.ts +2 -1
  133. package/dist/runtime/dom/eventListeners.js +184 -47
  134. package/dist/runtime/dom/formDiscovery.d.ts +1 -1
  135. package/dist/runtime/dom/formDiscovery.js +116 -16
  136. package/dist/runtime/dom/formFillHelpers/fill.d.ts +9 -0
  137. package/dist/runtime/dom/formFillHelpers/fill.js +178 -14
  138. package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
  139. package/dist/runtime/dom/formFillHelpers/index.js +2 -2
  140. package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
  141. package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
  142. package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
  143. package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
  144. package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
  145. package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
  146. package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
  147. package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
  148. package/dist/runtime/dom/formSubmitHelpers.js +89 -15
  149. package/dist/runtime/dom/frameLayout.d.ts +60 -0
  150. package/dist/runtime/dom/frameLayout.js +140 -0
  151. package/dist/runtime/dom/frameOrigin.d.ts +50 -0
  152. package/dist/runtime/dom/frameOrigin.js +62 -0
  153. package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
  154. package/dist/runtime/dom/frameScopedConnection.js +252 -0
  155. package/dist/runtime/dom/frameSelection.d.ts +12 -1
  156. package/dist/runtime/dom/frameSelection.js +22 -3
  157. package/dist/runtime/dom/frames.d.ts +61 -5
  158. package/dist/runtime/dom/frames.js +329 -75
  159. package/dist/runtime/dom/inspect.d.ts +28 -0
  160. package/dist/runtime/dom/inspect.js +557 -0
  161. package/dist/runtime/dom/inspectAllStyles.d.ts +62 -0
  162. package/dist/runtime/dom/inspectAllStyles.js +385 -0
  163. package/dist/runtime/dom/inspectCascade.d.ts +94 -0
  164. package/dist/runtime/dom/inspectCascade.js +371 -0
  165. package/dist/runtime/dom/inspectCascadeModel.d.ts +39 -0
  166. package/dist/runtime/dom/inspectCascadeModel.js +232 -0
  167. package/dist/runtime/dom/inspectHints.d.ts +62 -0
  168. package/dist/runtime/dom/inspectHints.js +305 -0
  169. package/dist/runtime/dom/inspectLayoutModel.d.ts +87 -0
  170. package/dist/runtime/dom/inspectLayoutModel.js +346 -0
  171. package/dist/runtime/dom/inspectModel.d.ts +74 -0
  172. package/dist/runtime/dom/inspectModel.js +184 -0
  173. package/dist/runtime/dom/inspectPaintModel.d.ts +157 -0
  174. package/dist/runtime/dom/inspectPaintModel.js +461 -0
  175. package/dist/runtime/dom/inspectRules.d.ts +37 -0
  176. package/dist/runtime/dom/inspectRules.js +101 -0
  177. package/dist/runtime/dom/inspectScripts.d.ts +132 -0
  178. package/dist/runtime/dom/inspectScripts.js +263 -0
  179. package/dist/runtime/dom/inspectTree.d.ts +40 -0
  180. package/dist/runtime/dom/inspectTree.js +134 -0
  181. package/dist/runtime/dom/inspectVariables.d.ts +33 -0
  182. package/dist/runtime/dom/inspectVariables.js +94 -0
  183. package/dist/runtime/dom/inspectWhyModel.d.ts +20 -0
  184. package/dist/runtime/dom/inspectWhyModel.js +134 -0
  185. package/dist/runtime/dom/layout.d.ts +71 -0
  186. package/dist/runtime/dom/layout.js +340 -0
  187. package/dist/runtime/dom/listenerPageScripts.d.ts +72 -0
  188. package/dist/runtime/dom/listenerPageScripts.js +365 -0
  189. package/dist/runtime/dom/listenerSummary.d.ts +136 -11
  190. package/dist/runtime/dom/listenerSummary.js +361 -22
  191. package/dist/runtime/dom/pageActivity.d.ts +41 -0
  192. package/dist/runtime/dom/pageActivity.js +123 -0
  193. package/dist/runtime/dom/reactEventHelpers.d.ts +63 -2
  194. package/dist/runtime/dom/reactEventHelpers.js +220 -41
  195. package/dist/runtime/dom/targetNode.d.ts +80 -27
  196. package/dist/runtime/dom/targetNode.js +249 -33
  197. package/dist/runtime/dom/wait.d.ts +25 -0
  198. package/dist/runtime/dom/wait.js +199 -0
  199. package/dist/runtime/dom/waitCondition.d.ts +71 -0
  200. package/dist/runtime/dom/waitCondition.js +75 -0
  201. package/dist/runtime/page/emulation.d.ts +71 -0
  202. package/dist/runtime/page/emulation.js +117 -0
  203. package/dist/runtime/page/loadingState.d.ts +36 -0
  204. package/dist/runtime/page/loadingState.js +86 -0
  205. package/dist/runtime/page/navigation.d.ts +46 -2
  206. package/dist/runtime/page/navigation.js +69 -33
  207. package/dist/session/QueryCacheManager.d.ts +11 -1
  208. package/dist/session/QueryCacheManager.js +25 -3
  209. package/dist/session/chromeOwners.d.ts +34 -0
  210. package/dist/session/chromeOwners.js +51 -0
  211. package/dist/session/cleanup/staleSession.d.ts +11 -1
  212. package/dist/session/cleanup/staleSession.js +17 -6
  213. package/dist/session/cleanup/userCommands.js +2 -4
  214. package/dist/session/metadata.d.ts +5 -1
  215. package/dist/session/metadata.js +2 -1
  216. package/dist/session/paths.d.ts +77 -3
  217. package/dist/session/paths.js +111 -5
  218. package/dist/session/port.d.ts +31 -7
  219. package/dist/session/port.js +50 -43
  220. package/dist/session/portClaims.d.ts +66 -0
  221. package/dist/session/portClaims.js +284 -0
  222. package/dist/session/sessionList.d.ts +58 -0
  223. package/dist/session/sessionList.js +199 -0
  224. package/dist/session/sessionName.d.ts +46 -0
  225. package/dist/session/sessionName.js +97 -0
  226. package/dist/telemetry/a11y.d.ts +18 -3
  227. package/dist/telemetry/a11y.js +170 -29
  228. package/dist/telemetry/console.d.ts +1 -0
  229. package/dist/telemetry/console.js +100 -5
  230. package/dist/telemetry/network.js +3 -1
  231. package/dist/telemetry/requestKinds.d.ts +32 -0
  232. package/dist/telemetry/requestKinds.js +61 -0
  233. package/dist/telemetry/requestState.d.ts +31 -0
  234. package/dist/telemetry/requestState.js +38 -0
  235. package/dist/types.d.ts +112 -3
  236. package/dist/ui/formatters/a11y.js +3 -0
  237. package/dist/ui/formatters/console/chronological.d.ts +8 -0
  238. package/dist/ui/formatters/console/chronological.js +17 -4
  239. package/dist/ui/formatters/console/json.js +3 -4
  240. package/dist/ui/formatters/console/shared.d.ts +12 -0
  241. package/dist/ui/formatters/console.d.ts +2 -2
  242. package/dist/ui/formatters/console.js +1 -1
  243. package/dist/ui/formatters/details.d.ts +8 -0
  244. package/dist/ui/formatters/details.js +61 -4
  245. package/dist/ui/formatters/dom.d.ts +27 -14
  246. package/dist/ui/formatters/dom.js +88 -59
  247. package/dist/ui/formatters/form.js +29 -18
  248. package/dist/ui/formatters/inspect.d.ts +39 -0
  249. package/dist/ui/formatters/inspect.js +596 -0
  250. package/dist/ui/formatters/keyAttributes.d.ts +19 -0
  251. package/dist/ui/formatters/keyAttributes.js +84 -0
  252. package/dist/ui/formatters/layout.d.ts +31 -0
  253. package/dist/ui/formatters/layout.js +53 -0
  254. package/dist/ui/formatters/listeners.d.ts +3 -2
  255. package/dist/ui/formatters/listeners.js +73 -9
  256. package/dist/ui/formatters/networkHeaders.d.ts +13 -0
  257. package/dist/ui/formatters/networkHeaders.js +36 -3
  258. package/dist/ui/formatters/networkList.d.ts +29 -1
  259. package/dist/ui/formatters/networkList.js +86 -20
  260. package/dist/ui/formatters/preview.js +2 -1
  261. package/dist/ui/formatters/requestStatus.d.ts +1 -17
  262. package/dist/ui/formatters/requestStatus.js +2 -30
  263. package/dist/ui/formatters/sessions.d.ts +12 -0
  264. package/dist/ui/formatters/sessions.js +40 -0
  265. package/dist/ui/formatters/status.d.ts +21 -2
  266. package/dist/ui/formatters/status.js +47 -10
  267. package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
  268. package/dist/ui/formatters/triggeredRequests.js +65 -0
  269. package/dist/ui/formatting.d.ts +19 -0
  270. package/dist/ui/formatting.js +31 -36
  271. package/dist/ui/messages/chrome.d.ts +9 -0
  272. package/dist/ui/messages/chrome.js +17 -5
  273. package/dist/ui/messages/commands.d.ts +504 -14
  274. package/dist/ui/messages/commands.js +835 -21
  275. package/dist/ui/messages/consoleMessages.d.ts +10 -0
  276. package/dist/ui/messages/consoleMessages.js +17 -0
  277. package/dist/ui/messages/hints.js +2 -1
  278. package/dist/ui/messages/networkMessages.d.ts +14 -0
  279. package/dist/ui/messages/networkMessages.js +18 -0
  280. package/dist/ui/messages/preview.js +5 -4
  281. package/dist/ui/messages/session.d.ts +30 -21
  282. package/dist/ui/messages/session.js +48 -26
  283. package/dist/ui/messages/sessionCommand.d.ts +43 -0
  284. package/dist/ui/messages/sessionCommand.js +52 -0
  285. package/dist/utils/async.d.ts +17 -0
  286. package/dist/utils/async.js +36 -0
  287. package/dist/utils/color.d.ts +84 -0
  288. package/dist/utils/color.js +376 -0
  289. package/dist/utils/cssValues.d.ts +109 -0
  290. package/dist/utils/cssValues.js +236 -0
  291. package/dist/utils/http.d.ts +22 -1
  292. package/dist/utils/http.js +28 -9
  293. package/dist/utils/selectorFilters.d.ts +48 -8
  294. package/dist/utils/selectorFilters.js +296 -53
  295. package/dist/utils/shellDetection.d.ts +8 -2
  296. package/dist/utils/shellDetection.js +120 -33
  297. package/dist/utils/suggestions.d.ts +26 -0
  298. package/dist/utils/suggestions.js +73 -0
  299. package/dist/utils/taskMappings.js +10 -0
  300. package/dist/utils/url.d.ts +12 -2
  301. package/dist/utils/url.js +69 -7
  302. package/package.json +1 -1
  303. package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
  304. package/dist/ui/formatters/sessionFormatters.js +0 -121
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Page-side descriptions of elements for DOM command output (`dom query`,
3
+ * `dom layout`, DOM context of console messages): their text as a user sees
4
+ * it and where they live (iframes, shadow roots).
5
+ */
6
+ /** Length of the text `dom get` shows for an element. */
7
+ export declare const ELEMENT_TEXT_LENGTH = 500;
8
+ /**
9
+ * Page-side removal of decorations from an element's text: close buttons
10
+ * (`.close`, `aria-label="Close"` or `"Dismiss"`, a button or link showing
11
+ * just `×`) and `aria-hidden` icons (text without letters or digits), so a
12
+ * flash message does not end in "×". `aria-hidden` text with words is kept:
13
+ * it is often the visible twin of a screen-reader text. Each decoration's
14
+ * text is removed once, from the end.
15
+ */
16
+ export declare const WITHOUT_DECORATIONS_JS = "(el, text) => {\n if (!text || typeof el.querySelectorAll !== 'function') return text;\n const glyph = /^\\s*[\u00D7\u2715\u2716\u2717\u2A2F]\\s*$/;\n const textOf = (node) => (typeof node.innerText === 'string' ? node.innerText : node.textContent || '').trim();\n const closer = '.close, [aria-label=\"close\" i], [aria-label=\"dismiss\" i]';\n const rendered = (node) => !node.checkVisibility || node.checkVisibility();\n const found = Array.from(el.querySelectorAll(closer + ', [aria-hidden=\"true\"]'))\n .filter((node) => rendered(node) && (node.matches(closer) || !/[\\p{L}\\p{N}]/u.test(textOf(node))));\n if (/[\u00D7\u2715\u2716\u2717\u2A2F]/.test(text)) {\n found.push(...Array.from(el.querySelectorAll('button, a, [role=\"button\"]')).filter((node) => glyph.test(node.textContent || '')));\n }\n const unique = Array.from(new Set(found));\n const outermost = unique.filter((node) => !unique.some((other) => other !== node && other.contains(node)));\n let result = text;\n for (const node of outermost) {\n const part = textOf(node);\n const at = part ? result.lastIndexOf(part) : -1;\n if (at >= 0) result = result.slice(0, at) + result.slice(at + part.length);\n }\n return result;\n}";
17
+ /**
18
+ * Page-side text of an element as a user sees it: `innerText` for a rendered
19
+ * element (CSS-hidden parts left out, inline elements not split apart), none
20
+ * for an element that is not rendered, `textContent` for SVG and other
21
+ * elements without `innerText` and for `display: contents` wrappers (no box
22
+ * of their own, but their children are shown), and the label of an
23
+ * `<option>` (which its `<select>` renders). For large containers (more
24
+ * than 2000 characters of text) only the start is read, from the text nodes
25
+ * whose parent is rendered, so a preview never lays out a whole page's text,
26
+ * unless `full` is set. Decorations are left out ({@link WITHOUT_DECORATIONS_JS}).
27
+ */
28
+ export declare const ELEMENT_TEXT_JS = "(el, full) => {\n const withoutDecorations = (el, text) => {\n if (!text || typeof el.querySelectorAll !== 'function') return text;\n const glyph = /^\\s*[\u00D7\u2715\u2716\u2717\u2A2F]\\s*$/;\n const textOf = (node) => (typeof node.innerText === 'string' ? node.innerText : node.textContent || '').trim();\n const closer = '.close, [aria-label=\"close\" i], [aria-label=\"dismiss\" i]';\n const rendered = (node) => !node.checkVisibility || node.checkVisibility();\n const found = Array.from(el.querySelectorAll(closer + ', [aria-hidden=\"true\"]'))\n .filter((node) => rendered(node) && (node.matches(closer) || !/[\\p{L}\\p{N}]/u.test(textOf(node))));\n if (/[\u00D7\u2715\u2716\u2717\u2A2F]/.test(text)) {\n found.push(...Array.from(el.querySelectorAll('button, a, [role=\"button\"]')).filter((node) => glyph.test(node.textContent || '')));\n }\n const unique = Array.from(new Set(found));\n const outermost = unique.filter((node) => !unique.some((other) => other !== node && other.contains(node)));\n let result = text;\n for (const node of outermost) {\n const part = textOf(node);\n const at = part ? result.lastIndexOf(part) : -1;\n if (at >= 0) result = result.slice(0, at) + result.slice(at + part.length);\n }\n return result;\n};\n const all = el.textContent || '';\n if (el.tagName === 'OPTION') return el.label;\n if (typeof el.innerText !== 'string') return full ? all : all.slice(0, 2000);\n const rendered = (node) => !node.checkVisibility || node.checkVisibility();\n if (!rendered(el)) {\n const boxless = el.ownerDocument.defaultView.getComputedStyle(el).display === 'contents';\n return boxless ? withoutDecorations(el, full ? all : all.slice(0, 2000)) : '';\n }\n if (full || all.length <= 2000) return withoutDecorations(el, el.innerText);\n const walker = el.ownerDocument.createTreeWalker(el, NodeFilter.SHOW_TEXT);\n let start = '';\n while (start.length < 1000 && walker.nextNode()) {\n const parent = walker.currentNode.parentElement;\n if (!parent || rendered(parent)) start += walker.currentNode.data;\n }\n return withoutDecorations(el, start);\n}";
29
+ /** Shown instead of a secret field value (the same for every length) */
30
+ export declare const MASKED_VALUE = "\u2022\u2022\u2022\u2022";
31
+ /**
32
+ * Page-side check whether a form control holds a secret whose value must
33
+ * never leave the page: a password field (live type or type attribute), a
34
+ * field shown masked by CSS (`-webkit-text-security` other than `none`),
35
+ * one whose `autocomplete` names a password, a payment card (`cc-*`) or a
36
+ * one-time code, or a field named like a password, one-time code or card code
37
+ * (`password`, `passwd`, `pwd`, `passcode`, `otp`, `cvv`, `cvc`), which
38
+ * covers a password field switched to text by a "show password" button.
39
+ */
40
+ export declare const SENSITIVE_FIELD_JS = "(el) => {\n const autocomplete = el.getAttribute('autocomplete') || '';\n if (/(^|\\s)(cc-[a-z-]+|one-time-code|current-password|new-password)(\\s|$)/i.test(autocomplete)) return true;\n if (el.type === 'password' || /^password$/i.test(el.getAttribute('type') || '')) return true;\n const names = [el.getAttribute('name'), el.id, autocomplete].join(' ');\n if (/passw|passwd|pwd|passcode|(^|[^a-z])otp([^a-z]|$)|cvv|cvc/i.test(names)) return true;\n try {\n const security = el.ownerDocument.defaultView.getComputedStyle(el).getPropertyValue('-webkit-text-security');\n return Boolean(security) && security !== 'none';\n } catch (e) {\n return false;\n }\n}";
41
+ /**
42
+ * Page-side live state of a form control, which its attributes do not show:
43
+ * the type and current value of an `<input>` (for checkboxes and radios
44
+ * `checked` and their `value` attribute, not the default "on"), the value of
45
+ * a `<textarea>`, the labels of a `<select>`'s selected options and the type
46
+ * of a `<button>` in a form (`submit` when it has none; outside a form only
47
+ * a type attribute is shown). Empty for other elements.
48
+ *
49
+ * Secrets never leave the page: a hidden input's value is left out, and the
50
+ * value (or selected option) of a sensitive field ({@link SENSITIVE_FIELD_JS})
51
+ * is replaced by {@link MASKED_VALUE}, whatever its length, with
52
+ * `sensitive: true`.
53
+ */
54
+ export declare const ELEMENT_STATE_JS = "(el) => {\n const isSensitive = (el) => {\n const autocomplete = el.getAttribute('autocomplete') || '';\n if (/(^|\\s)(cc-[a-z-]+|one-time-code|current-password|new-password)(\\s|$)/i.test(autocomplete)) return true;\n if (el.type === 'password' || /^password$/i.test(el.getAttribute('type') || '')) return true;\n const names = [el.getAttribute('name'), el.id, autocomplete].join(' ');\n if (/passw|passwd|pwd|passcode|(^|[^a-z])otp([^a-z]|$)|cvv|cvc/i.test(names)) return true;\n try {\n const security = el.ownerDocument.defaultView.getComputedStyle(el).getPropertyValue('-webkit-text-security');\n return Boolean(security) && security !== 'none';\n } catch (e) {\n return false;\n }\n};\n const mask = (value) => (value ? '\u2022\u2022\u2022\u2022' : '');\n const guarded = (state) => {\n if (!isSensitive(el)) return state;\n const result = { ...state, sensitive: true };\n if ('value' in result) result.value = mask(result.value);\n if ('selected' in result) result.selected = mask(result.selected);\n return result;\n };\n switch (el.localName) {\n case 'input':\n if (el.type === 'hidden') return { type: 'hidden' };\n return guarded(\n /^(checkbox|radio)$/.test(el.type)\n ? { type: el.type, checked: el.checked, value: el.getAttribute('value') || '' }\n : { type: el.type, value: el.value }\n );\n case 'textarea':\n return guarded({ value: el.value });\n case 'select':\n return guarded({ selected: Array.from(el.selectedOptions || [], (option) => option.label).join(', ') });\n case 'button':\n return el.form ? { type: el.type } : {};\n default:\n return {};\n }\n}";
55
+ /**
56
+ * Page-side short description of an element: tag, id and up to two classes,
57
+ * e.g. `button#save.primary.large`.
58
+ */
59
+ export declare const ELEMENT_DESCRIPTION_JS = "(node) => node.tagName.toLowerCase() +\n (node.id ? '#' + node.id : '') +\n (node.classList && node.classList.length ? '.' + Array.from(node.classList).slice(0, 2).join('.') : '')";
60
+ /**
61
+ * Page-side position of an element among its parent's children with the
62
+ * same short description ({@link ELEMENT_DESCRIPTION_JS}), e.g. `(2nd of 3)`;
63
+ * empty when it is the only one.
64
+ */
65
+ export declare const SIBLING_POSITION_JS = "(el) => {\n const describe = (node) => node.tagName.toLowerCase() +\n (node.id ? '#' + node.id : '') +\n (node.classList && node.classList.length ? '.' + Array.from(node.classList).slice(0, 2).join('.') : '');\n const parent = el.parentElement;\n if (!parent) return '';\n const own = describe(el);\n const same = Array.from(parent.children).filter((child) => describe(child) === own);\n if (same.length < 2) return '';\n const n = same.indexOf(el) + 1;\n const teen = n % 100 >= 11 && n % 100 <= 13;\n const suffix = teen ? 'th' : ({ 1: 'st', 2: 'nd', 3: 'rd' })[n % 10] || 'th';\n return '(' + n + suffix + ' of ' + same.length + ')';\n}";
66
+ /**
67
+ * Page-side identity of an element an action hit, so the output says which
68
+ * one it was, as one string: its short description
69
+ * ({@link ELEMENT_DESCRIPTION_JS}) and visible text (button value for button
70
+ * inputs, decorations left out), e.g. `button#add.btn "Add to cart"`. A
71
+ * `<select>` is named by its label, aria-label or name, else by its selected
72
+ * option, e.g. `select.sort "Sort products"`. An element without visible
73
+ * text is described by itself first: by its position among same-looking
74
+ * siblings ({@link SIBLING_POSITION_JS}), e.g. `div.figure (2nd of 3)`, with
75
+ * its aria-label, placeholder or title when it has one. Only an element
76
+ * without an id that is the only one of its kind is named by the nearest of
77
+ * three ancestors that has text, e.g.
78
+ * `input.toggle in div.view "Write report"` (rows of a list share their
79
+ * aria-label), leaving out the options
80
+ * of `<select>`s in it (read like `innerText`: CSS-hidden text is left out of
81
+ * a rendered ancestor; at most 500 text nodes; selects in shadow roots are
82
+ * not looked into), and never past an editable ancestor, whose text may be
83
+ * typed input; otherwise its aria-label, placeholder or title is used. Texts
84
+ * are cut at 40 characters. Contenteditable elements count as controls: what
85
+ * was typed into them is never echoed (nor their ancestors' text).
86
+ */
87
+ export declare const ELEMENT_IDENTITY_JS = "(el) => {\n const describe = (node) => node.tagName.toLowerCase() +\n (node.id ? '#' + node.id : '') +\n (node.classList && node.classList.length ? '.' + Array.from(node.classList).slice(0, 2).join('.') : '');\n const siblingPosition = (el) => {\n const describe = (node) => node.tagName.toLowerCase() +\n (node.id ? '#' + node.id : '') +\n (node.classList && node.classList.length ? '.' + Array.from(node.classList).slice(0, 2).join('.') : '');\n const parent = el.parentElement;\n if (!parent) return '';\n const own = describe(el);\n const same = Array.from(parent.children).filter((child) => describe(child) === own);\n if (same.length < 2) return '';\n const n = same.indexOf(el) + 1;\n const teen = n % 100 >= 11 && n % 100 <= 13;\n const suffix = teen ? 'th' : ({ 1: 'st', 2: 'nd', 3: 'rd' })[n % 10] || 'th';\n return '(' + n + suffix + ' of ' + same.length + ')';\n};\n const withoutDecorations = (el, text) => {\n if (!text || typeof el.querySelectorAll !== 'function') return text;\n const glyph = /^\\s*[\u00D7\u2715\u2716\u2717\u2A2F]\\s*$/;\n const textOf = (node) => (typeof node.innerText === 'string' ? node.innerText : node.textContent || '').trim();\n const closer = '.close, [aria-label=\"close\" i], [aria-label=\"dismiss\" i]';\n const rendered = (node) => !node.checkVisibility || node.checkVisibility();\n const found = Array.from(el.querySelectorAll(closer + ', [aria-hidden=\"true\"]'))\n .filter((node) => rendered(node) && (node.matches(closer) || !/[\\p{L}\\p{N}]/u.test(textOf(node))));\n if (/[\u00D7\u2715\u2716\u2717\u2A2F]/.test(text)) {\n found.push(...Array.from(el.querySelectorAll('button, a, [role=\"button\"]')).filter((node) => glyph.test(node.textContent || '')));\n }\n const unique = Array.from(new Set(found));\n const outermost = unique.filter((node) => !unique.some((other) => other !== node && other.contains(node)));\n let result = text;\n for (const node of outermost) {\n const part = textOf(node);\n const at = part ? result.lastIndexOf(part) : -1;\n if (at >= 0) result = result.slice(0, at) + result.slice(at + part.length);\n }\n return result;\n};\n const clean = (text) => (text || '').replace(/\\s+/g, ' ').trim();\n const cut = (text) => {\n const characters = Array.from(text);\n return characters.length > 40 ? characters.slice(0, 40).join('') + '\u2026' : text;\n };\n const isControl = (node) => /^(input|select|textarea)$/.test(node.localName) || node.isContentEditable;\n const shownText = (node) =>\n isControl(node) ? '' : clean(withoutDecorations(node, typeof node.innerText === 'string' ? node.innerText : node.textContent));\n const buttonValue = (node) => (node.localName === 'input' && /^(submit|button|reset)$/i.test(node.type) ? clean(node.value) : '');\n const attributeText = (node) =>\n clean(node.getAttribute('aria-label')) || clean(node.getAttribute('placeholder')) || clean(node.getAttribute('title'));\n const selectName = (node) =>\n clean(node.labels && node.labels[0] && node.labels[0].innerText) ||\n clean(node.getAttribute('aria-label')) ||\n clean(node.getAttribute('name')) ||\n clean(node.selectedOptions && node.selectedOptions[0] && node.selectedOptions[0].label);\n const shown = (node, options) => !node.checkVisibility || node.checkVisibility(options);\n const textOutsideSelects = (node) => {\n if (!node.querySelector('select')) return shownText(node);\n const hiddenLeftOut = shown(node);\n const walker = node.ownerDocument.createTreeWalker(node, NodeFilter.SHOW_TEXT);\n let text = '';\n for (let visited = 0; visited < 500 && text.length < 200 && walker.nextNode(); visited++) {\n const parent = walker.currentNode.parentElement;\n if (!parent || parent.closest('select, textarea')) continue;\n if (!hiddenLeftOut || shown(parent, { visibilityProperty: true })) text += ' ' + walker.currentNode.data;\n }\n return clean(text);\n };\n const quoted = (text) => (text ? ' \"' + cut(text) + '\"' : '');\n const visible = shownText(el) || buttonValue(el) || (el.localName === 'select' ? selectName(el) : '');\n if (visible) return describe(el) + quoted(visible);\n const attribute = attributeText(el);\n const position = siblingPosition(el);\n if (position) return describe(el) + ' ' + position + quoted(attribute);\n let ancestor = el.id || el.isContentEditable ? null : el.parentElement;\n for (let depth = 0; ancestor && depth < 3; depth++, ancestor = ancestor.parentElement) {\n if (isControl(ancestor)) break;\n const text = textOutsideSelects(ancestor);\n if (text) return describe(el) + ' in ' + describe(ancestor) + quoted(text);\n }\n return describe(el) + quoted(attribute);\n}";
88
+ /**
89
+ * Page-side location of an element: the iframes it is in (outermost first)
90
+ * and the shadow root holding it, e.g. `iframe#pay > shadow root of <x-card>`;
91
+ * empty for the main document.
92
+ */
93
+ export declare const ELEMENT_CONTEXT_JS = "(el) => {\n const describe = (node) => node.tagName.toLowerCase() + (node.id ? '#' + node.id : '');\n const parts = [];\n for (let doc = el.ownerDocument; doc && doc.defaultView && doc.defaultView.frameElement; ) {\n const frame = doc.defaultView.frameElement;\n parts.unshift(describe(frame));\n doc = frame.ownerDocument;\n }\n const root = el.getRootNode();\n if (root.host) parts.push('shadow root of <' + describe(root.host) + '>');\n return parts.join(' > ');\n}";
94
+ /**
95
+ * Short text preview of an element's text: whitespace collapsed, cut on a
96
+ * whole character (an emoji is never split, which would make JSON invalid).
97
+ *
98
+ * @param text - Element text as the page renders it
99
+ * @param length - Characters kept
100
+ * @returns Collapsed text, truncated to `length` characters (followed by `...`)
101
+ */
102
+ export declare function textPreview(text: string, length?: number): string;
103
+ //# sourceMappingURL=elementInfo.d.ts.map
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Page-side descriptions of elements for DOM command output (`dom query`,
3
+ * `dom layout`, DOM context of console messages): their text as a user sees
4
+ * it and where they live (iframes, shadow roots).
5
+ */
6
+ /** Length of the text preview shown for elements. */
7
+ const PREVIEW_LENGTH = 80;
8
+ /** Length of the text `dom get` shows for an element. */
9
+ export const ELEMENT_TEXT_LENGTH = 500;
10
+ /**
11
+ * Page-side removal of decorations from an element's text: close buttons
12
+ * (`.close`, `aria-label="Close"` or `"Dismiss"`, a button or link showing
13
+ * just `×`) and `aria-hidden` icons (text without letters or digits), so a
14
+ * flash message does not end in "×". `aria-hidden` text with words is kept:
15
+ * it is often the visible twin of a screen-reader text. Each decoration's
16
+ * text is removed once, from the end.
17
+ */
18
+ export const WITHOUT_DECORATIONS_JS = `(el, text) => {
19
+ if (!text || typeof el.querySelectorAll !== 'function') return text;
20
+ const glyph = /^\\s*[×✕✖✗⨯]\\s*$/;
21
+ const textOf = (node) => (typeof node.innerText === 'string' ? node.innerText : node.textContent || '').trim();
22
+ const closer = '.close, [aria-label="close" i], [aria-label="dismiss" i]';
23
+ const rendered = (node) => !node.checkVisibility || node.checkVisibility();
24
+ const found = Array.from(el.querySelectorAll(closer + ', [aria-hidden="true"]'))
25
+ .filter((node) => rendered(node) && (node.matches(closer) || !/[\\p{L}\\p{N}]/u.test(textOf(node))));
26
+ if (/[×✕✖✗⨯]/.test(text)) {
27
+ found.push(...Array.from(el.querySelectorAll('button, a, [role="button"]')).filter((node) => glyph.test(node.textContent || '')));
28
+ }
29
+ const unique = Array.from(new Set(found));
30
+ const outermost = unique.filter((node) => !unique.some((other) => other !== node && other.contains(node)));
31
+ let result = text;
32
+ for (const node of outermost) {
33
+ const part = textOf(node);
34
+ const at = part ? result.lastIndexOf(part) : -1;
35
+ if (at >= 0) result = result.slice(0, at) + result.slice(at + part.length);
36
+ }
37
+ return result;
38
+ }`;
39
+ /**
40
+ * Page-side text of an element as a user sees it: `innerText` for a rendered
41
+ * element (CSS-hidden parts left out, inline elements not split apart), none
42
+ * for an element that is not rendered, `textContent` for SVG and other
43
+ * elements without `innerText` and for `display: contents` wrappers (no box
44
+ * of their own, but their children are shown), and the label of an
45
+ * `<option>` (which its `<select>` renders). For large containers (more
46
+ * than 2000 characters of text) only the start is read, from the text nodes
47
+ * whose parent is rendered, so a preview never lays out a whole page's text,
48
+ * unless `full` is set. Decorations are left out ({@link WITHOUT_DECORATIONS_JS}).
49
+ */
50
+ export const ELEMENT_TEXT_JS = `(el, full) => {
51
+ const withoutDecorations = ${WITHOUT_DECORATIONS_JS};
52
+ const all = el.textContent || '';
53
+ if (el.tagName === 'OPTION') return el.label;
54
+ if (typeof el.innerText !== 'string') return full ? all : all.slice(0, 2000);
55
+ const rendered = (node) => !node.checkVisibility || node.checkVisibility();
56
+ if (!rendered(el)) {
57
+ const boxless = el.ownerDocument.defaultView.getComputedStyle(el).display === 'contents';
58
+ return boxless ? withoutDecorations(el, full ? all : all.slice(0, 2000)) : '';
59
+ }
60
+ if (full || all.length <= 2000) return withoutDecorations(el, el.innerText);
61
+ const walker = el.ownerDocument.createTreeWalker(el, NodeFilter.SHOW_TEXT);
62
+ let start = '';
63
+ while (start.length < 1000 && walker.nextNode()) {
64
+ const parent = walker.currentNode.parentElement;
65
+ if (!parent || rendered(parent)) start += walker.currentNode.data;
66
+ }
67
+ return withoutDecorations(el, start);
68
+ }`;
69
+ /** Shown instead of a secret field value (the same for every length) */
70
+ export const MASKED_VALUE = '••••';
71
+ /**
72
+ * Page-side check whether a form control holds a secret whose value must
73
+ * never leave the page: a password field (live type or type attribute), a
74
+ * field shown masked by CSS (`-webkit-text-security` other than `none`),
75
+ * one whose `autocomplete` names a password, a payment card (`cc-*`) or a
76
+ * one-time code, or a field named like a password, one-time code or card code
77
+ * (`password`, `passwd`, `pwd`, `passcode`, `otp`, `cvv`, `cvc`), which
78
+ * covers a password field switched to text by a "show password" button.
79
+ */
80
+ export const SENSITIVE_FIELD_JS = `(el) => {
81
+ const autocomplete = el.getAttribute('autocomplete') || '';
82
+ if (/(^|\\s)(cc-[a-z-]+|one-time-code|current-password|new-password)(\\s|$)/i.test(autocomplete)) return true;
83
+ if (el.type === 'password' || /^password$/i.test(el.getAttribute('type') || '')) return true;
84
+ const names = [el.getAttribute('name'), el.id, autocomplete].join(' ');
85
+ if (/passw|passwd|pwd|passcode|(^|[^a-z])otp([^a-z]|$)|cvv|cvc/i.test(names)) return true;
86
+ try {
87
+ const security = el.ownerDocument.defaultView.getComputedStyle(el).getPropertyValue('-webkit-text-security');
88
+ return Boolean(security) && security !== 'none';
89
+ } catch (e) {
90
+ return false;
91
+ }
92
+ }`;
93
+ /**
94
+ * Page-side live state of a form control, which its attributes do not show:
95
+ * the type and current value of an `<input>` (for checkboxes and radios
96
+ * `checked` and their `value` attribute, not the default "on"), the value of
97
+ * a `<textarea>`, the labels of a `<select>`'s selected options and the type
98
+ * of a `<button>` in a form (`submit` when it has none; outside a form only
99
+ * a type attribute is shown). Empty for other elements.
100
+ *
101
+ * Secrets never leave the page: a hidden input's value is left out, and the
102
+ * value (or selected option) of a sensitive field ({@link SENSITIVE_FIELD_JS})
103
+ * is replaced by {@link MASKED_VALUE}, whatever its length, with
104
+ * `sensitive: true`.
105
+ */
106
+ export const ELEMENT_STATE_JS = `(el) => {
107
+ const isSensitive = ${SENSITIVE_FIELD_JS};
108
+ const mask = (value) => (value ? '${MASKED_VALUE}' : '');
109
+ const guarded = (state) => {
110
+ if (!isSensitive(el)) return state;
111
+ const result = { ...state, sensitive: true };
112
+ if ('value' in result) result.value = mask(result.value);
113
+ if ('selected' in result) result.selected = mask(result.selected);
114
+ return result;
115
+ };
116
+ switch (el.localName) {
117
+ case 'input':
118
+ if (el.type === 'hidden') return { type: 'hidden' };
119
+ return guarded(
120
+ /^(checkbox|radio)$/.test(el.type)
121
+ ? { type: el.type, checked: el.checked, value: el.getAttribute('value') || '' }
122
+ : { type: el.type, value: el.value }
123
+ );
124
+ case 'textarea':
125
+ return guarded({ value: el.value });
126
+ case 'select':
127
+ return guarded({ selected: Array.from(el.selectedOptions || [], (option) => option.label).join(', ') });
128
+ case 'button':
129
+ return el.form ? { type: el.type } : {};
130
+ default:
131
+ return {};
132
+ }
133
+ }`;
134
+ /**
135
+ * Page-side short description of an element: tag, id and up to two classes,
136
+ * e.g. `button#save.primary.large`.
137
+ */
138
+ export const ELEMENT_DESCRIPTION_JS = `(node) => node.tagName.toLowerCase() +
139
+ (node.id ? '#' + node.id : '') +
140
+ (node.classList && node.classList.length ? '.' + Array.from(node.classList).slice(0, 2).join('.') : '')`;
141
+ /**
142
+ * Page-side position of an element among its parent's children with the
143
+ * same short description ({@link ELEMENT_DESCRIPTION_JS}), e.g. `(2nd of 3)`;
144
+ * empty when it is the only one.
145
+ */
146
+ export const SIBLING_POSITION_JS = `(el) => {
147
+ const describe = ${ELEMENT_DESCRIPTION_JS};
148
+ const parent = el.parentElement;
149
+ if (!parent) return '';
150
+ const own = describe(el);
151
+ const same = Array.from(parent.children).filter((child) => describe(child) === own);
152
+ if (same.length < 2) return '';
153
+ const n = same.indexOf(el) + 1;
154
+ const teen = n % 100 >= 11 && n % 100 <= 13;
155
+ const suffix = teen ? 'th' : ({ 1: 'st', 2: 'nd', 3: 'rd' })[n % 10] || 'th';
156
+ return '(' + n + suffix + ' of ' + same.length + ')';
157
+ }`;
158
+ /**
159
+ * Page-side identity of an element an action hit, so the output says which
160
+ * one it was, as one string: its short description
161
+ * ({@link ELEMENT_DESCRIPTION_JS}) and visible text (button value for button
162
+ * inputs, decorations left out), e.g. `button#add.btn "Add to cart"`. A
163
+ * `<select>` is named by its label, aria-label or name, else by its selected
164
+ * option, e.g. `select.sort "Sort products"`. An element without visible
165
+ * text is described by itself first: by its position among same-looking
166
+ * siblings ({@link SIBLING_POSITION_JS}), e.g. `div.figure (2nd of 3)`, with
167
+ * its aria-label, placeholder or title when it has one. Only an element
168
+ * without an id that is the only one of its kind is named by the nearest of
169
+ * three ancestors that has text, e.g.
170
+ * `input.toggle in div.view "Write report"` (rows of a list share their
171
+ * aria-label), leaving out the options
172
+ * of `<select>`s in it (read like `innerText`: CSS-hidden text is left out of
173
+ * a rendered ancestor; at most 500 text nodes; selects in shadow roots are
174
+ * not looked into), and never past an editable ancestor, whose text may be
175
+ * typed input; otherwise its aria-label, placeholder or title is used. Texts
176
+ * are cut at 40 characters. Contenteditable elements count as controls: what
177
+ * was typed into them is never echoed (nor their ancestors' text).
178
+ */
179
+ export const ELEMENT_IDENTITY_JS = `(el) => {
180
+ const describe = ${ELEMENT_DESCRIPTION_JS};
181
+ const siblingPosition = ${SIBLING_POSITION_JS};
182
+ const withoutDecorations = ${WITHOUT_DECORATIONS_JS};
183
+ const clean = (text) => (text || '').replace(/\\s+/g, ' ').trim();
184
+ const cut = (text) => {
185
+ const characters = Array.from(text);
186
+ return characters.length > 40 ? characters.slice(0, 40).join('') + '…' : text;
187
+ };
188
+ const isControl = (node) => /^(input|select|textarea)$/.test(node.localName) || node.isContentEditable;
189
+ const shownText = (node) =>
190
+ isControl(node) ? '' : clean(withoutDecorations(node, typeof node.innerText === 'string' ? node.innerText : node.textContent));
191
+ const buttonValue = (node) => (node.localName === 'input' && /^(submit|button|reset)$/i.test(node.type) ? clean(node.value) : '');
192
+ const attributeText = (node) =>
193
+ clean(node.getAttribute('aria-label')) || clean(node.getAttribute('placeholder')) || clean(node.getAttribute('title'));
194
+ const selectName = (node) =>
195
+ clean(node.labels && node.labels[0] && node.labels[0].innerText) ||
196
+ clean(node.getAttribute('aria-label')) ||
197
+ clean(node.getAttribute('name')) ||
198
+ clean(node.selectedOptions && node.selectedOptions[0] && node.selectedOptions[0].label);
199
+ const shown = (node, options) => !node.checkVisibility || node.checkVisibility(options);
200
+ const textOutsideSelects = (node) => {
201
+ if (!node.querySelector('select')) return shownText(node);
202
+ const hiddenLeftOut = shown(node);
203
+ const walker = node.ownerDocument.createTreeWalker(node, NodeFilter.SHOW_TEXT);
204
+ let text = '';
205
+ for (let visited = 0; visited < 500 && text.length < 200 && walker.nextNode(); visited++) {
206
+ const parent = walker.currentNode.parentElement;
207
+ if (!parent || parent.closest('select, textarea')) continue;
208
+ if (!hiddenLeftOut || shown(parent, { visibilityProperty: true })) text += ' ' + walker.currentNode.data;
209
+ }
210
+ return clean(text);
211
+ };
212
+ const quoted = (text) => (text ? ' "' + cut(text) + '"' : '');
213
+ const visible = shownText(el) || buttonValue(el) || (el.localName === 'select' ? selectName(el) : '');
214
+ if (visible) return describe(el) + quoted(visible);
215
+ const attribute = attributeText(el);
216
+ const position = siblingPosition(el);
217
+ if (position) return describe(el) + ' ' + position + quoted(attribute);
218
+ let ancestor = el.id || el.isContentEditable ? null : el.parentElement;
219
+ for (let depth = 0; ancestor && depth < 3; depth++, ancestor = ancestor.parentElement) {
220
+ if (isControl(ancestor)) break;
221
+ const text = textOutsideSelects(ancestor);
222
+ if (text) return describe(el) + ' in ' + describe(ancestor) + quoted(text);
223
+ }
224
+ return describe(el) + quoted(attribute);
225
+ }`;
226
+ /**
227
+ * Page-side location of an element: the iframes it is in (outermost first)
228
+ * and the shadow root holding it, e.g. `iframe#pay > shadow root of <x-card>`;
229
+ * empty for the main document.
230
+ */
231
+ export const ELEMENT_CONTEXT_JS = `(el) => {
232
+ const describe = (node) => node.tagName.toLowerCase() + (node.id ? '#' + node.id : '');
233
+ const parts = [];
234
+ for (let doc = el.ownerDocument; doc && doc.defaultView && doc.defaultView.frameElement; ) {
235
+ const frame = doc.defaultView.frameElement;
236
+ parts.unshift(describe(frame));
237
+ doc = frame.ownerDocument;
238
+ }
239
+ const root = el.getRootNode();
240
+ if (root.host) parts.push('shadow root of <' + describe(root.host) + '>');
241
+ return parts.join(' > ');
242
+ }`;
243
+ /**
244
+ * Short text preview of an element's text: whitespace collapsed, cut on a
245
+ * whole character (an emoji is never split, which would make JSON invalid).
246
+ *
247
+ * @param text - Element text as the page renders it
248
+ * @param length - Characters kept
249
+ * @returns Collapsed text, truncated to `length` characters (followed by `...`)
250
+ */
251
+ export function textPreview(text, length = PREVIEW_LENGTH) {
252
+ const collapsed = text.replace(/\s+/g, ' ').trim();
253
+ const characters = Array.from(collapsed);
254
+ return characters.length > length ? characters.slice(0, length).join('') + '...' : collapsed;
255
+ }
256
+ //# sourceMappingURL=elementInfo.js.map
@@ -31,6 +31,25 @@ export interface EvalResult {
31
31
  * throwing getter becomes `[Error: …]`.
32
32
  */
33
33
  export declare const JSON_SAFE_COPY_FUNCTION = "function () {\n const MAX_ITEMS = 1000;\n const ancestors = new Set();\n const kind = (value) => Object.prototype.toString.call(value).slice(8, -1);\n const isNode = (value) => typeof value.nodeType === 'number' && typeof value.nodeName === 'string';\n const describeNode = (node) => {\n if (node.nodeType !== 1) return node.nodeName.toLowerCase();\n return node.tagName.toLowerCase() + (node.id ? '#' + node.id : '') +\n (node.classList && node.classList.length ? '.' + Array.from(node.classList).join('.') : '');\n };\n const items = (list, next) => {\n const result = [];\n let count = 0;\n for (const item of list) {\n if (count++ === MAX_ITEMS) { result.push('\u2026'); break; }\n result.push(next(item));\n }\n return result;\n };\n const leaf = (value) => {\n if (value === undefined) return null;\n if (typeof value === 'number') {\n if (Number.isNaN(value) || !Number.isFinite(value)) return String(value);\n return Object.is(value, -0) ? '-0' : value;\n }\n if (typeof value === 'bigint') return value + 'n';\n if (typeof value === 'symbol') return value.toString();\n if (typeof value === 'function') return 'function ' + (value.name || '(anonymous)') + '()';\n return value;\n };\n const copy = (value, depth) => {\n if (value === null || typeof value !== 'object') return leaf(value);\n if (ancestors.has(value)) return '[Circular]';\n if (depth > 20) return '[\u2026]';\n const next = (item) => copy(item, depth + 1);\n const type = kind(value);\n if (isNode(value)) return describeNode(value);\n if (value.window === value) return 'Window';\n if (type === 'Date') return isNaN(value) ? 'Invalid Date' : value.toISOString();\n if (type === 'RegExp') return String(value);\n if (type === 'Error' || value instanceof Error) return value.name + ': ' + value.message;\n ancestors.add(value);\n try {\n if (type === 'Map') return items(value, ([k, v]) => [next(k), next(v)]);\n if (type === 'Set' || type === 'NodeList' || type === 'HTMLCollection') return items(value, next);\n if (ArrayBuffer.isView(value) && type !== 'DataView') return items(value, next);\n if (Array.isArray(value)) return items(value, next);\n const result = {};\n const keys = Object.keys(value);\n for (const key of keys.slice(0, MAX_ITEMS)) {\n try { result[key] = next(value[key]); } catch (e) { result[key] = '[Error: ' + (e && e.message) + ']'; }\n }\n if (keys.length > MAX_ITEMS) result['\u2026'] = (keys.length - MAX_ITEMS) + ' more keys';\n return result;\n } finally {\n ancestors.delete(value);\n }\n };\n return copy(this, 0);\n}";
34
+ /** What a busy target is called in messages: the page, or an iframe (`--frame`) */
35
+ export type BusyScope = 'page' | 'frame';
36
+ /** When {@link withBusyPageRecovery} checks the target, and what it calls it */
37
+ export interface BusyRecoveryOptions {
38
+ /** Time after which a command that has not answered gets the target checked */
39
+ busyAfterMs?: number;
40
+ /** How long the target gets to answer the check */
41
+ livenessMs?: number;
42
+ /** The page (default) or an iframe, for messages */
43
+ scope?: BusyScope;
44
+ }
45
+ /**
46
+ * Whether Chrome failed a command because the document it ran in went away
47
+ * (navigation, a removed iframe).
48
+ *
49
+ * @param error - Error thrown by a CDP command
50
+ * @returns True for a lost context
51
+ */
52
+ export declare function isContextLostError(error: unknown): boolean;
34
53
  /**
35
54
  * Run a CDP command on the page, recovering a page kept busy by its own
36
55
  * scripts. If the command has not answered when a script would have been
@@ -41,21 +60,45 @@ export declare const JSON_SAFE_COPY_FUNCTION = "function () {\n const MAX_ITEMS
41
60
  *
42
61
  * @param cdp - CDP connection
43
62
  * @param command - The pending command
44
- * @param limits - When to check the page, and how long it gets to answer
63
+ * @param options - When to check the page, how long it gets to answer, what to call it
45
64
  * @returns The command's result
46
65
  * @throws CommandError (102) when the page was busy
47
66
  */
48
- export declare function withBusyPageRecovery<T>(cdp: CDPSender, command: Promise<T>, limits?: {
49
- busyAfterMs: number;
50
- livenessMs: number;
51
- }): Promise<T>;
67
+ export declare function withBusyPageRecovery<T>(cdp: CDPSender, command: Promise<T>, options?: BusyRecoveryOptions): Promise<T>;
68
+ /**
69
+ * The work's value if it settles within `ms` (its rejection is passed on).
70
+ *
71
+ * @param work - Pending work
72
+ * @param ms - Time limit
73
+ * @returns `{ settled: true, value }`, or `{ settled: false }` when time ran out
74
+ */
75
+ export declare function settledWithin<T>(work: Promise<T>, ms: number): Promise<{
76
+ settled: true;
77
+ value: T;
78
+ } | {
79
+ settled: false;
80
+ }>;
52
81
  /** Where a `bdg dom eval` script runs (default: the page's main frame) */
53
82
  export interface EvalTarget {
54
83
  /** Session of an attached target (out-of-process iframe) */
55
84
  sessionId?: string;
85
+ /**
86
+ * Where to check and recover the target when it does not answer (default:
87
+ * the session itself); a session attached while the target was busy gets
88
+ * no answer at all
89
+ */
90
+ recovery?: CDPSender;
56
91
  /** Execution context of a frame (`ExecutionContextDescription.uniqueId`) */
57
92
  uniqueContextId?: string;
58
93
  }
94
+ /**
95
+ * Whether the page still answers. A page that does not answer in time is
96
+ * taken as open: commands wait while a navigation is pending.
97
+ *
98
+ * @param cdp - CDP connection of the page
99
+ * @returns False when the page (tab) was closed
100
+ */
101
+ export declare function pageStillOpen(cdp: CDPSender): Promise<boolean>;
59
102
  /**
60
103
  * Evaluate a `bdg dom eval` script.
61
104
  *
@@ -70,7 +113,9 @@ export interface EvalTarget {
70
113
  * @param script - JavaScript expression
71
114
  * @param target - Session and execution context to run in (default: the page)
72
115
  * @returns Value and type
73
- * @throws CommandError (102) when the script was terminated, (91) when it threw
116
+ * @throws CommandError (102) when the script was terminated or a promise did
117
+ * not settle, (91) when it threw, (83) when the page navigated while it ran
118
+ * (in a frame, Chrome's context-lost error is passed on for the caller to explain)
74
119
  */
75
120
  export declare function evaluateScript(cdp: CDPConnection, script: string, target?: EvalTarget): Promise<EvalResult>;
76
121
  //# sourceMappingURL=evalHelpers.d.ts.map