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,340 @@
1
+ /**
2
+ * Positions, sizes and visibility of elements (`bdg dom layout`).
3
+ *
4
+ * One page-side pass per command measures every match: its box in page and
5
+ * viewport coordinates (iframe offsets included), what clips it, whether it
6
+ * is rendered, what covers its center and the styles that decide how it
7
+ * shows. The measurements are classified outside the page
8
+ * ({@link classifyViewportPosition}).
9
+ */
10
+ import { CommandError } from '../../errors/index.js';
11
+ import { operationFailedError } from '../../errors/messages.js';
12
+ import { ELEMENT_GEOMETRY_JS, FRAME_OFFSET_JS, VIEWPORT_SIZE_JS, classifyViewportPosition, } from './elementGeometry.js';
13
+ import { ELEMENT_CONTEXT_JS, ELEMENT_DESCRIPTION_JS, ELEMENT_TEXT_JS, textPreview, } from './elementInfo.js';
14
+ import { throwIfInvalidSelector } from './formFillHelpers/shared.js';
15
+ import { findFrameOwner, placeInOwnerFrame } from './frameLayout.js';
16
+ import { measureFrameMapping } from './frameScopedConnection.js';
17
+ import { DEEP_QUERY_JS, missingElementError, selectorArgsJS } from './targetNode.js';
18
+ import { createLogger } from '../../ui/logging/index.js';
19
+ import { getErrorMessage } from '../../utils/errors.js';
20
+ import { EXIT_CODES } from '../../utils/exitCodes.js';
21
+ const log = createLogger('dom');
22
+ /** Matches measured per command (the rest are counted as omitted) */
23
+ export const LAYOUT_ELEMENT_LIMIT = 100;
24
+ /**
25
+ * Page-side end of a visible span kept clear of an overlay scrollbar along
26
+ * an edge (16 CSS px wide): overlay scrollbars (macOS, mobile) show for about a
27
+ * second after a scroll and catch hit tests, which then return the scroller.
28
+ * The span ends before the strip when it reaches into it and also shows
29
+ * outside it; without overlay scrollbars along the edge it is unchanged.
30
+ * Arguments: span start and end, the edge, whether overlay scrollbars show there.
31
+ */
32
+ export const CLEAR_OF_SCROLLBAR_JS = `(start, end, edge, overlay) =>
33
+ overlay && end > edge - 16 && edge - 16 > start ? edge - 16 : end`;
34
+ /**
35
+ * Page-side edges of the top-level viewport with overlay scrollbars: the page
36
+ * scrolls along an axis while its scrollbar takes no space (the window is as
37
+ * wide or tall as the viewport).
38
+ */
39
+ const VIEWPORT_OVERLAY_JS = `(view, viewport) => {
40
+ const scroller = view.document.scrollingElement || view.document.documentElement;
41
+ return {
42
+ right: scroller.scrollHeight > viewport.height && view.innerWidth - viewport.width < 1,
43
+ bottom: scroller.scrollWidth > viewport.width && view.innerHeight - viewport.height < 1
44
+ };
45
+ }`;
46
+ /** Elements a click on any of their content activates */
47
+ const CLICK_TARGET_SELECTOR = 'a[href], button, [role="button"], [role="link"], label, summary, input, select, textarea';
48
+ /**
49
+ * Page-side test of whether an element on top of another one is part of the
50
+ * same click target, so a click there does what a click on the element
51
+ * would: both are in the same link, button or label (an overlay span inside
52
+ * the card's link), or in links to the same URL (a card's overlay link next
53
+ * to its headline link), or the element is plain content (in no link or
54
+ * button) of a card covered by its "faux block link" (news sites): an
55
+ * absolutely positioned `<a href>` without visible text of its own (empty,
56
+ * or an aria-label only), directly in the card (not `<body>`) and spanning
57
+ * it. Dismiss buttons, promo links with text and `[role=button]` overlays
58
+ * still count as covers.
59
+ */
60
+ const SAME_CLICK_TARGET_JS = `(node, hit) => {
61
+ const parentOf = (n) => n.parentElement || (n.parentNode && n.parentNode.host) || null;
62
+ const targetOf = (n) => {
63
+ for (let p = n; p; p = parentOf(p)) {
64
+ if (p.matches && p.matches(${JSON.stringify(CLICK_TARGET_SELECTOR)})) return p;
65
+ }
66
+ return null;
67
+ };
68
+ const theirs = targetOf(hit);
69
+ if (!theirs) return false;
70
+ const mine = targetOf(node);
71
+ if (mine) return mine === theirs || (mine.localName === 'a' && theirs.localName === 'a' && mine.href === theirs.href);
72
+ const card = theirs.parentElement;
73
+ if (theirs.localName !== 'a' || theirs.hasAttribute('role')) return false;
74
+ if (!card || card === node.ownerDocument.body || !card.contains(node)) return false;
75
+ const style = theirs.ownerDocument.defaultView.getComputedStyle(theirs);
76
+ if (style.position !== 'absolute' || (theirs.innerText || '').trim() !== '') return false;
77
+ const outer = theirs.getBoundingClientRect();
78
+ const inner = card.getBoundingClientRect();
79
+ return outer.left <= inner.left + 1 && outer.top <= inner.top + 1 && outer.right >= inner.right - 1 && outer.bottom >= inner.bottom - 1;
80
+ }`;
81
+ /**
82
+ * Page function: layout of the matches in `found` (all up to `limit`, or the
83
+ * one at `index`) and of the top-level page. An element covers another when
84
+ * it is the topmost element at the center of the largest visible part of the
85
+ * other's boxes (a wrapped link has one per line; the strip where overlay
86
+ * scrollbars show is avoided when possible, {@link CLEAR_OF_SCROLLBAR_JS}) and does not lie inside it,
87
+ * nor part of the element's own click target ({@link SAME_CLICK_TARGET_JS}: the link, button
88
+ * or label it is in, or the overlay link of its card; a click there does the same). An
89
+ * ancestor covers it only when the ancestor is painted above it there (its
90
+ * `::before`/`::after` overlay, or its background over a negative
91
+ * `z-index`), as `dom click` finds: the element is in the hit-test stack below
92
+ * the ancestor. Hit-testing goes up through the iframes, so an overlay over
93
+ * an iframe covers the elements in it. Elements hit-testing skips
94
+ * (`pointer-events: none`, also through an iframe) get no cover.
95
+ */
96
+ const LAYOUT_JS = `function (found, index, limit) {
97
+ const geometryOf = ${ELEMENT_GEOMETRY_JS};
98
+ const viewportSize = ${VIEWPORT_SIZE_JS};
99
+ const frameOffset = ${FRAME_OFFSET_JS};
100
+ const describe = ${ELEMENT_DESCRIPTION_JS};
101
+ const contextOf = ${ELEMENT_CONTEXT_JS};
102
+ const textOf = ${ELEMENT_TEXT_JS};
103
+ const clearOfScrollbar = ${CLEAR_OF_SCROLLBAR_JS};
104
+ const viewportOverlay = ${VIEWPORT_OVERLAY_JS};
105
+ const picked = index === null
106
+ ? found.slice(0, limit).map((el, i) => [i, el])
107
+ : (found[index] ? [[index, found[index]]] : []);
108
+ if (picked.length === 0) return { count: found.length, elements: [] };
109
+ let top = picked[0][1].ownerDocument.defaultView;
110
+ while (top.frameElement) top = top.parent;
111
+ const scroller = top.document.scrollingElement || top.document.documentElement;
112
+ const page = {
113
+ viewport: viewportSize(top),
114
+ scroll: { x: top.scrollX, y: top.scrollY },
115
+ document: { width: scroller.scrollWidth, height: scroller.scrollHeight },
116
+ colorScheme: top.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
117
+ };
118
+ const pageOverlay = viewportOverlay(top, page.viewport);
119
+ const encloses = (outer, node) => {
120
+ for (let n = node; n; n = n.parentNode || n.host) if (n === outer) return true;
121
+ return false;
122
+ };
123
+ const sameTarget = ${SAME_CLICK_TARGET_JS};
124
+ const coverAt = (node, x, y) => {
125
+ const root = node.getRootNode();
126
+ const scope = typeof root.elementFromPoint === 'function' ? root : node.ownerDocument;
127
+ const hit = scope.elementFromPoint(x, y);
128
+ if (!hit || encloses(node, hit) || sameTarget(node, hit)) return null;
129
+ if (!encloses(hit, node)) return hit;
130
+ return scope.elementsFromPoint(x, y).indexOf(node) > 0 ? hit : null;
131
+ };
132
+ const visibleCenter = (el, g) => {
133
+ const bounds = [{ x: 0, y: 0, width: page.viewport.width, height: page.viewport.height }].concat(g.clip ? [g.clip] : []);
134
+ let best = null;
135
+ for (const r of Array.from(el.getClientRects())) {
136
+ const boxes = bounds.concat([{ x: r.left + g.offset.x, y: r.top + g.offset.y, width: r.width, height: r.height }]);
137
+ const left = Math.max(...boxes.map((b) => b.x));
138
+ const top = Math.max(...boxes.map((b) => b.y));
139
+ const right = Math.min(...boxes.map((b) => b.x + b.width));
140
+ const bottom = Math.min(...boxes.map((b) => b.y + b.height));
141
+ const area = (right - left) * (bottom - top);
142
+ if (!(right > left && bottom > top) || (best && area <= best.area)) continue;
143
+ let clearRight = clearOfScrollbar(left, right, page.viewport.width, pageOverlay.right);
144
+ let clearBottom = clearOfScrollbar(top, bottom, page.viewport.height, pageOverlay.bottom);
145
+ if (g.clip) {
146
+ clearRight = clearOfScrollbar(left, clearRight, g.clip.x + g.clip.width, g.clipOverlay.right);
147
+ clearBottom = clearOfScrollbar(top, clearBottom, g.clip.y + g.clip.height, g.clipOverlay.bottom);
148
+ }
149
+ best = { area: area, x: (left + clearRight) / 2, y: (top + clearBottom) / 2 };
150
+ }
151
+ return best;
152
+ };
153
+ const paintsNothing = (node) => {
154
+ const s = node.ownerDocument.defaultView.getComputedStyle(node);
155
+ const clearColor = (c) => c === 'transparent' || /^rgba\\(.*,\\s*0\\)$/.test(c);
156
+ const ownText = Array.from(node.childNodes).some((n) => n.nodeType === 3 && n.data.trim() !== '');
157
+ return clearColor(s.backgroundColor) && s.backgroundImage === 'none' && s.boxShadow === 'none' && !ownText;
158
+ };
159
+ const hitTestable = (node) => node.ownerDocument.defaultView.getComputedStyle(node).pointerEvents !== 'none';
160
+ const coveredBy = (el, g) => {
161
+ const center = hitTestable(el) && visibleCenter(el, g);
162
+ if (!center) return null;
163
+ let x = center.x - g.offset.x;
164
+ let y = center.y - g.offset.y;
165
+ let cover = coverAt(el, x, y);
166
+ for (let view = el.ownerDocument.defaultView; !cover && view.frameElement; view = view.parent) {
167
+ if (!hitTestable(view.frameElement)) return null;
168
+ const offset = frameOffset(view.frameElement);
169
+ x += offset.x;
170
+ y += offset.y;
171
+ cover = coverAt(view.frameElement, x, y);
172
+ }
173
+ return cover ? { element: describe(cover), transparent: paintsNothing(cover) } : null;
174
+ };
175
+ const elements = picked.map(([i, el]) => {
176
+ const style = el.ownerDocument.defaultView.getComputedStyle(el);
177
+ const geometry = geometryOf(el);
178
+ return {
179
+ index: i,
180
+ tag: el.tagName.toLowerCase(),
181
+ element: describe(el),
182
+ text: String(textOf(el)).replace(/\\s+/g, ' ').trim().slice(0, 1000),
183
+ context: contextOf(el),
184
+ geometry: geometry,
185
+ cover: geometry.hidden ? null : coveredBy(el, geometry),
186
+ computed: { display: style.display, visibility: style.visibility, position: style.position, opacity: style.opacity, zIndex: style.zIndex }
187
+ };
188
+ });
189
+ return { count: found.length, page: page, elements: elements, crossOriginFrame: top.parent !== top };
190
+ }`;
191
+ /** Distinguishes the object groups of concurrent calls */
192
+ let groupCounter = 0;
193
+ /**
194
+ * Measure the elements a selector (or cached index) refers to.
195
+ *
196
+ * @param cdp - CDP connection
197
+ * @param params - Selector (and index) or backend node id
198
+ * @returns Layout report
199
+ * @throws CommandError (83) no match, (81) index out of range or invalid
200
+ * selector, (87) the cached element left the page
201
+ */
202
+ export async function inspectLayout(cdp, params) {
203
+ const objectGroup = `bdg-layout-${++groupCounter}`;
204
+ try {
205
+ const raw = params.backendNodeId === undefined
206
+ ? await measureSelector(cdp, params)
207
+ : await measureNode(cdp, params.backendNodeId, objectGroup);
208
+ if (!raw.page || raw.elements.length === 0)
209
+ throw missingElementError(params, raw.count);
210
+ return buildLayoutResult({ ...raw, page: raw.page }, params);
211
+ }
212
+ finally {
213
+ void cdp
214
+ .send('Runtime.releaseObjectGroup', { objectGroup })
215
+ .catch((error) => log.debug(`Object group not released: ${getErrorMessage(error)}`));
216
+ }
217
+ }
218
+ /**
219
+ * Measure the matches of a selector (searching open shadow roots and
220
+ * same-origin frames) in one page evaluation.
221
+ *
222
+ * @param cdp - CDP connection
223
+ * @param params - Selector and optional index
224
+ * @returns Measurements
225
+ * @throws CommandError (81) invalid selector, (91) page script failure
226
+ */
227
+ async function measureSelector(cdp, params) {
228
+ const found = `(${DEEP_QUERY_JS})(${selectorArgsJS(params.selector)})`;
229
+ const response = (await cdp.send('Runtime.evaluate', {
230
+ expression: `(${LAYOUT_JS})(${found}, ${params.index ?? null}, ${LAYOUT_ELEMENT_LIMIT})`,
231
+ returnByValue: true,
232
+ }));
233
+ if (response.exceptionDetails) {
234
+ throwIfInvalidSelector(response.exceptionDetails, params.selector);
235
+ const err = operationFailedError('measure the elements', response.exceptionDetails.text);
236
+ throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.SCRIPT_ERROR);
237
+ }
238
+ return response.result.value;
239
+ }
240
+ /**
241
+ * Measure one exact element (from the query cache).
242
+ *
243
+ * @param cdp - CDP connection
244
+ * @param backendNodeId - Backend node id
245
+ * @param objectGroup - Object group for the handle
246
+ * @returns Measurements; no elements when the node left the page. An element
247
+ * of a cross-origin iframe (from an a11y query) is placed in the top-level
248
+ * viewport through the iframe's own measurements.
249
+ */
250
+ async function measureNode(cdp, backendNodeId, objectGroup) {
251
+ const resolved = (await cdp
252
+ .send('DOM.resolveNode', { backendNodeId, objectGroup })
253
+ .catch((error) => {
254
+ log.debug(`Node ${backendNodeId} not resolved: ${getErrorMessage(error)}`);
255
+ return {};
256
+ }));
257
+ const objectId = resolved.object?.objectId;
258
+ if (!objectId)
259
+ return { count: 0, elements: [] };
260
+ const response = (await cdp.send('Runtime.callFunctionOn', {
261
+ objectId,
262
+ functionDeclaration: `function () { return (${LAYOUT_JS})(this.isConnected ? [this] : [], null, 1); }`,
263
+ returnByValue: true,
264
+ }));
265
+ const raw = response.result.value ?? { count: 0, elements: [] };
266
+ if (!raw.crossOriginFrame)
267
+ return raw;
268
+ const owner = await findFrameOwner(cdp, objectId);
269
+ if (owner === undefined)
270
+ return raw;
271
+ const ownerLayout = await measureNode(cdp, owner, objectGroup);
272
+ return placeInOwnerFrame(raw, ownerLayout, await measureFrameMapping(cdp, objectId));
273
+ }
274
+ /**
275
+ * Turn page-side measurements into the layout report: rounded page and
276
+ * viewport coordinates, viewport position and text preview per element.
277
+ *
278
+ * @param raw - Measurements with at least one element
279
+ * @param params - Request (selector and index)
280
+ * @returns Layout report
281
+ */
282
+ export function buildLayoutResult(raw, params) {
283
+ const omitted = params.index === undefined ? raw.count - raw.elements.length : 0;
284
+ return {
285
+ success: true,
286
+ selector: params.selector,
287
+ count: raw.count,
288
+ page: roundPage(raw.page),
289
+ elements: raw.elements.map((element) => elementLayout(element, raw.page)),
290
+ ...(omitted > 0 && { omitted }),
291
+ };
292
+ }
293
+ /**
294
+ * Page layout with whole pixels.
295
+ *
296
+ * @param page - Measured page layout
297
+ * @returns Rounded page layout
298
+ */
299
+ function roundPage(page) {
300
+ return {
301
+ viewport: { width: Math.round(page.viewport.width), height: Math.round(page.viewport.height) },
302
+ scroll: { x: Math.round(page.scroll.x), y: Math.round(page.scroll.y) },
303
+ document: { width: Math.round(page.document.width), height: Math.round(page.document.height) },
304
+ ...(page.colorScheme && { colorScheme: page.colorScheme }),
305
+ };
306
+ }
307
+ /**
308
+ * Layout of one element.
309
+ *
310
+ * @param raw - Element measurements
311
+ * @param page - Page layout (viewport size and scroll position)
312
+ * @returns Element layout; `coveredBy` only for elements that are in view
313
+ */
314
+ function elementLayout(raw, page) {
315
+ const { rect } = raw.geometry;
316
+ const placement = classifyViewportPosition(raw.geometry, page.viewport);
317
+ const inView = placement.inViewport === 'visible' || placement.inViewport === 'partly';
318
+ const text = textPreview(raw.text);
319
+ return {
320
+ index: raw.index,
321
+ tag: raw.tag,
322
+ element: raw.element,
323
+ ...(text && { text }),
324
+ ...(raw.context && { context: raw.context }),
325
+ bounds: {
326
+ x: Math.round(rect.x + page.scroll.x),
327
+ y: Math.round(rect.y + page.scroll.y),
328
+ width: Math.round(rect.width),
329
+ height: Math.round(rect.height),
330
+ },
331
+ viewport: { x: Math.round(rect.x), y: Math.round(rect.y) },
332
+ ...placement,
333
+ ...(inView && raw.cover && { coveredBy: raw.cover.element }),
334
+ ...(inView && raw.cover?.transparent && { coverTransparent: true }),
335
+ ...(raw.geometry.invisible && { invisible: raw.geometry.invisible }),
336
+ ...(raw.geometry.inert && { inert: true }),
337
+ computed: raw.computed,
338
+ };
339
+ }
340
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Page-side functions of `bdg dom listeners`: what only the page can tell
3
+ * about an element's listeners (handler names and identities, React root
4
+ * containers, the handlers behind jQuery's dispatcher and Preact's event
5
+ * proxy, React's `on…` props of the element and its ancestors, the
6
+ * element's iframe).
7
+ *
8
+ * Each piece is a function expression in a string, combined into
9
+ * {@link ELEMENT_INFO_JS}; every lookup of page globals is guarded, so a
10
+ * page with odd globals (a throwing `jQuery` getter) only loses that detail.
11
+ */
12
+ /** Most jQuery handlers resolved per call; the rest keep jQuery's dispatcher */
13
+ export declare const MAX_JQUERY_HANDLERS = 50;
14
+ /** Most React prop handlers resolved per call; the rest are counted */
15
+ export declare const MAX_REACT_HANDLERS = 50;
16
+ /**
17
+ * Page function, called on the element with the listeners (position in the
18
+ * chain, event type and capture flag of each), the requested event types (null for all;
19
+ * React props are filtered before the limit), then the chain's objects, then each
20
+ * listener's handler, then the function each handler calls (a bound
21
+ * function's target, else null).
22
+ *
23
+ * Returns `[info, ...jQueryAndPreactHandlers, ...reactHandlers]`. `info` has the
24
+ * iframe element holding the element's document (`frame`), a framework
25
+ * label per chain entry (`roots`), per listener the handler's name, the
26
+ * identity and name of the function it calls (equal identities are the same
27
+ * function object) and, for jQuery's dispatcher, the jQuery handlers that
28
+ * run for the element, for Preact's event proxy the handler Preact runs
29
+ * (`preact`); then the React `on…` props that run for the
30
+ * element's events (`react`, see {@link REACT_HANDLERS_JS}). Their functions follow `info` in the same order.
31
+ * After {@link MAX_JQUERY_HANDLERS}, dispatchers stay unresolved and are
32
+ * counted in `jquerySkipped`; after {@link MAX_REACT_HANDLERS}, React props
33
+ * are counted in `reactSkipped`.
34
+ */
35
+ export declare const ELEMENT_INFO_JS: string;
36
+ /** What {@link ELEMENT_INFO_JS} reports, by value */
37
+ export interface ElementInfo {
38
+ frame: string | null;
39
+ roots: Array<string | null>;
40
+ listeners: Array<{
41
+ name: string | null;
42
+ identity: number | null;
43
+ targetName: string | null;
44
+ jquery?: Array<{
45
+ type: string;
46
+ selector: string | null;
47
+ name: string;
48
+ }>;
49
+ /** The handler Preact runs from this listener (set when it is Preact's event proxy) */
50
+ preact?: {
51
+ name: string;
52
+ };
53
+ }>;
54
+ /** jQuery handlers left unresolved (over the limit) */
55
+ jquerySkipped: number;
56
+ /** React `on…` props that run for the element's events, nearest first */
57
+ react: Array<{
58
+ /** Position of the element the prop is on in the chain (0 = the inspected element); null outside it (a portal's React parent) */
59
+ position: number | null;
60
+ /** Description of that element when it is outside the chain */
61
+ node?: string;
62
+ /** Prop name, e.g. `onClickCapture` */
63
+ prop: string;
64
+ /** DOM event type, e.g. `click` */
65
+ type: string;
66
+ capture: boolean;
67
+ name: string;
68
+ }>;
69
+ /** React props left unresolved (over the limit) */
70
+ reactSkipped: number;
71
+ }
72
+ //# sourceMappingURL=listenerPageScripts.d.ts.map