browser-debugger-cli 0.8.0 → 0.9.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 (251) hide show
  1. package/README.md +4 -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 +27 -5
  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 +152 -113
  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/query.d.ts +44 -17
  27. package/dist/commands/dom/helpers/query.js +244 -97
  28. package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
  29. package/dist/commands/dom/helpers/runElementCommand.js +97 -30
  30. package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
  31. package/dist/commands/dom/helpers/screenshot.js +164 -49
  32. package/dist/commands/dom/index.d.ts +3 -1
  33. package/dist/commands/dom/index.js +16 -6
  34. package/dist/commands/dom/layout.d.ts +14 -0
  35. package/dist/commands/dom/layout.js +54 -0
  36. package/dist/commands/dom/listeners.d.ts +5 -1
  37. package/dist/commands/dom/listeners.js +13 -3
  38. package/dist/commands/dom/query.js +2 -3
  39. package/dist/commands/dom/screenshot.d.ts +12 -2
  40. package/dist/commands/dom/screenshot.js +27 -3
  41. package/dist/commands/dom/semanticUtils.d.ts +6 -13
  42. package/dist/commands/dom/semanticUtils.js +15 -19
  43. package/dist/commands/dom/wait.d.ts +13 -0
  44. package/dist/commands/dom/wait.js +83 -0
  45. package/dist/commands/helpJson.js +2 -2
  46. package/dist/commands/network/list.js +4 -11
  47. package/dist/commands/optionBehaviors.js +112 -21
  48. package/dist/commands/page.d.ts +2 -1
  49. package/dist/commands/page.js +41 -5
  50. package/dist/commands/peek.js +4 -11
  51. package/dist/commands/sessions.d.ts +8 -0
  52. package/dist/commands/sessions.js +19 -0
  53. package/dist/commands/shared/CommandRunner.js +4 -4
  54. package/dist/commands/shared/dataFetcher.js +2 -2
  55. package/dist/commands/shared/followMode.d.ts +21 -1
  56. package/dist/commands/shared/followMode.js +29 -2
  57. package/dist/commands/shared/handleValidationError.d.ts +2 -2
  58. package/dist/commands/shared/handleValidationError.js +12 -3
  59. package/dist/commands/shared/optionTypes.d.ts +40 -5
  60. package/dist/commands/shared/startHelpers.js +12 -3
  61. package/dist/commands/shared/validation.d.ts +3 -2
  62. package/dist/commands/shared/validation.js +4 -3
  63. package/dist/commands/start.d.ts +63 -0
  64. package/dist/commands/start.js +115 -15
  65. package/dist/commands/status.js +29 -7
  66. package/dist/commands/stop.js +7 -6
  67. package/dist/commands/tail.js +4 -11
  68. package/dist/commands/types.d.ts +2 -0
  69. package/dist/commands.js +2 -0
  70. package/dist/connection/chromeIdentity.d.ts +65 -0
  71. package/dist/connection/chromeIdentity.js +143 -0
  72. package/dist/connection/launcher/profilePreferences.d.ts +47 -0
  73. package/dist/connection/launcher/profilePreferences.js +151 -0
  74. package/dist/connection/launcher.d.ts +21 -2
  75. package/dist/connection/launcher.js +42 -16
  76. package/dist/connection/portReservation.d.ts +14 -4
  77. package/dist/connection/portReservation.js +21 -6
  78. package/dist/connection/startupExit.d.ts +8 -0
  79. package/dist/connection/startupExit.js +15 -6
  80. package/dist/constants.d.ts +6 -2
  81. package/dist/constants.js +9 -2
  82. package/dist/daemon/SessionController.js +23 -7
  83. package/dist/daemon/errors.d.ts +1 -1
  84. package/dist/daemon/errors.js +1 -1
  85. package/dist/daemon/launcher.d.ts +2 -1
  86. package/dist/daemon/launcher.js +5 -6
  87. package/dist/daemon/server/SocketServer.js +1 -2
  88. package/dist/daemon/session/Session.d.ts +13 -0
  89. package/dist/daemon/session/Session.js +57 -8
  90. package/dist/daemon/session/chromeConnection.d.ts +9 -0
  91. package/dist/daemon/session/chromeConnection.js +45 -8
  92. package/dist/daemon/session/commandRegistry.js +52 -62
  93. package/dist/daemon/session/interactions.d.ts +35 -9
  94. package/dist/daemon/session/interactions.js +36 -9
  95. package/dist/daemon/session/triggeredRequests.d.ts +67 -0
  96. package/dist/daemon/session/triggeredRequests.js +157 -0
  97. package/dist/daemon/session/types.d.ts +5 -1
  98. package/dist/daemon.js +5393 -1600
  99. package/dist/errors/messages.d.ts +387 -24
  100. package/dist/errors/messages.js +761 -67
  101. package/dist/index.js +3976 -1558
  102. package/dist/ipc/client.d.ts +12 -1
  103. package/dist/ipc/client.js +22 -3
  104. package/dist/ipc/protocol/commands.d.ts +89 -4
  105. package/dist/ipc/protocol/commands.js +2 -0
  106. package/dist/ipc/protocol/domTypes.d.ts +258 -7
  107. package/dist/ipc/session/lifecycle.d.ts +8 -1
  108. package/dist/ipc/session/queries.d.ts +5 -1
  109. package/dist/ipc/session/types.d.ts +5 -0
  110. package/dist/ipc/transport/index.d.ts +2 -1
  111. package/dist/ipc/transport/index.js +2 -2
  112. package/dist/runtime/dom/actionEffects.d.ts +106 -0
  113. package/dist/runtime/dom/actionEffects.js +256 -0
  114. package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -0
  115. package/dist/runtime/dom/actionEffectsScripts.js +234 -0
  116. package/dist/runtime/dom/elementGeometry.d.ts +170 -0
  117. package/dist/runtime/dom/elementGeometry.js +553 -0
  118. package/dist/runtime/dom/elementInfo.d.ts +77 -0
  119. package/dist/runtime/dom/elementInfo.js +191 -0
  120. package/dist/runtime/dom/evalHelpers.d.ts +51 -6
  121. package/dist/runtime/dom/evalHelpers.js +136 -26
  122. package/dist/runtime/dom/eventListeners.d.ts +2 -1
  123. package/dist/runtime/dom/eventListeners.js +174 -47
  124. package/dist/runtime/dom/formDiscovery.d.ts +1 -1
  125. package/dist/runtime/dom/formDiscovery.js +116 -16
  126. package/dist/runtime/dom/formFillHelpers/fill.d.ts +10 -0
  127. package/dist/runtime/dom/formFillHelpers/fill.js +125 -10
  128. package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
  129. package/dist/runtime/dom/formFillHelpers/index.js +2 -2
  130. package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
  131. package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
  132. package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
  133. package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
  134. package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
  135. package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
  136. package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
  137. package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
  138. package/dist/runtime/dom/formSubmitHelpers.js +89 -15
  139. package/dist/runtime/dom/frameLayout.d.ts +60 -0
  140. package/dist/runtime/dom/frameLayout.js +140 -0
  141. package/dist/runtime/dom/frameOrigin.d.ts +50 -0
  142. package/dist/runtime/dom/frameOrigin.js +62 -0
  143. package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
  144. package/dist/runtime/dom/frameScopedConnection.js +252 -0
  145. package/dist/runtime/dom/frameSelection.d.ts +1 -1
  146. package/dist/runtime/dom/frameSelection.js +2 -2
  147. package/dist/runtime/dom/frames.d.ts +25 -2
  148. package/dist/runtime/dom/frames.js +202 -63
  149. package/dist/runtime/dom/layout.d.ts +67 -0
  150. package/dist/runtime/dom/layout.js +333 -0
  151. package/dist/runtime/dom/listenerPageScripts.d.ts +66 -0
  152. package/dist/runtime/dom/listenerPageScripts.js +279 -0
  153. package/dist/runtime/dom/listenerSummary.d.ts +132 -11
  154. package/dist/runtime/dom/listenerSummary.js +344 -22
  155. package/dist/runtime/dom/pageActivity.d.ts +41 -0
  156. package/dist/runtime/dom/pageActivity.js +123 -0
  157. package/dist/runtime/dom/reactEventHelpers.d.ts +58 -2
  158. package/dist/runtime/dom/reactEventHelpers.js +212 -41
  159. package/dist/runtime/dom/targetNode.d.ts +80 -27
  160. package/dist/runtime/dom/targetNode.js +249 -33
  161. package/dist/runtime/dom/wait.d.ts +25 -0
  162. package/dist/runtime/dom/wait.js +199 -0
  163. package/dist/runtime/dom/waitCondition.d.ts +71 -0
  164. package/dist/runtime/dom/waitCondition.js +75 -0
  165. package/dist/runtime/page/emulation.d.ts +51 -0
  166. package/dist/runtime/page/emulation.js +80 -0
  167. package/dist/runtime/page/loadingState.d.ts +36 -0
  168. package/dist/runtime/page/loadingState.js +86 -0
  169. package/dist/runtime/page/navigation.d.ts +46 -2
  170. package/dist/runtime/page/navigation.js +69 -33
  171. package/dist/session/QueryCacheManager.d.ts +11 -1
  172. package/dist/session/QueryCacheManager.js +25 -3
  173. package/dist/session/chromeOwners.d.ts +34 -0
  174. package/dist/session/chromeOwners.js +51 -0
  175. package/dist/session/cleanup/staleSession.d.ts +11 -1
  176. package/dist/session/cleanup/staleSession.js +17 -6
  177. package/dist/session/cleanup/userCommands.js +2 -4
  178. package/dist/session/metadata.d.ts +5 -1
  179. package/dist/session/metadata.js +2 -1
  180. package/dist/session/paths.d.ts +77 -3
  181. package/dist/session/paths.js +111 -5
  182. package/dist/session/port.d.ts +31 -7
  183. package/dist/session/port.js +50 -43
  184. package/dist/session/portClaims.d.ts +66 -0
  185. package/dist/session/portClaims.js +284 -0
  186. package/dist/session/sessionList.d.ts +58 -0
  187. package/dist/session/sessionList.js +199 -0
  188. package/dist/session/sessionName.d.ts +46 -0
  189. package/dist/session/sessionName.js +97 -0
  190. package/dist/telemetry/a11y.d.ts +8 -3
  191. package/dist/telemetry/a11y.js +92 -28
  192. package/dist/telemetry/requestKinds.d.ts +32 -0
  193. package/dist/telemetry/requestKinds.js +61 -0
  194. package/dist/telemetry/requestState.d.ts +31 -0
  195. package/dist/telemetry/requestState.js +38 -0
  196. package/dist/types.d.ts +80 -3
  197. package/dist/ui/formatters/a11y.js +3 -0
  198. package/dist/ui/formatters/console/chronological.d.ts +8 -0
  199. package/dist/ui/formatters/console/chronological.js +17 -4
  200. package/dist/ui/formatters/console/json.js +3 -4
  201. package/dist/ui/formatters/console/shared.d.ts +12 -0
  202. package/dist/ui/formatters/console.d.ts +2 -2
  203. package/dist/ui/formatters/console.js +1 -1
  204. package/dist/ui/formatters/details.js +2 -1
  205. package/dist/ui/formatters/dom.d.ts +26 -14
  206. package/dist/ui/formatters/dom.js +65 -52
  207. package/dist/ui/formatters/form.js +29 -18
  208. package/dist/ui/formatters/layout.d.ts +31 -0
  209. package/dist/ui/formatters/layout.js +53 -0
  210. package/dist/ui/formatters/listeners.d.ts +3 -2
  211. package/dist/ui/formatters/listeners.js +73 -9
  212. package/dist/ui/formatters/networkHeaders.js +13 -0
  213. package/dist/ui/formatters/preview.js +2 -1
  214. package/dist/ui/formatters/requestStatus.d.ts +1 -17
  215. package/dist/ui/formatters/requestStatus.js +2 -30
  216. package/dist/ui/formatters/sessions.d.ts +12 -0
  217. package/dist/ui/formatters/sessions.js +40 -0
  218. package/dist/ui/formatters/status.d.ts +21 -2
  219. package/dist/ui/formatters/status.js +47 -10
  220. package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
  221. package/dist/ui/formatters/triggeredRequests.js +65 -0
  222. package/dist/ui/formatting.d.ts +10 -0
  223. package/dist/ui/formatting.js +28 -36
  224. package/dist/ui/messages/chrome.d.ts +9 -0
  225. package/dist/ui/messages/chrome.js +17 -5
  226. package/dist/ui/messages/commands.d.ts +388 -14
  227. package/dist/ui/messages/commands.js +664 -21
  228. package/dist/ui/messages/consoleMessages.d.ts +10 -0
  229. package/dist/ui/messages/consoleMessages.js +17 -0
  230. package/dist/ui/messages/hints.js +2 -1
  231. package/dist/ui/messages/preview.js +5 -4
  232. package/dist/ui/messages/session.d.ts +16 -21
  233. package/dist/ui/messages/session.js +28 -26
  234. package/dist/ui/messages/sessionCommand.d.ts +43 -0
  235. package/dist/ui/messages/sessionCommand.js +52 -0
  236. package/dist/utils/async.d.ts +8 -0
  237. package/dist/utils/async.js +19 -0
  238. package/dist/utils/http.d.ts +22 -1
  239. package/dist/utils/http.js +28 -9
  240. package/dist/utils/selectorFilters.d.ts +36 -8
  241. package/dist/utils/selectorFilters.js +267 -53
  242. package/dist/utils/shellDetection.d.ts +8 -2
  243. package/dist/utils/shellDetection.js +120 -33
  244. package/dist/utils/suggestions.d.ts +26 -0
  245. package/dist/utils/suggestions.js +73 -0
  246. package/dist/utils/taskMappings.js +10 -0
  247. package/dist/utils/url.d.ts +12 -2
  248. package/dist/utils/url.js +69 -7
  249. package/package.json +1 -1
  250. package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
  251. package/dist/ui/formatters/sessionFormatters.js +0 -121
@@ -0,0 +1,333 @@
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 hitTestable = (node) => node.ownerDocument.defaultView.getComputedStyle(node).pointerEvents !== 'none';
154
+ const coveredBy = (el, g) => {
155
+ const center = hitTestable(el) && visibleCenter(el, g);
156
+ if (!center) return null;
157
+ let x = center.x - g.offset.x;
158
+ let y = center.y - g.offset.y;
159
+ let cover = coverAt(el, x, y);
160
+ for (let view = el.ownerDocument.defaultView; !cover && view.frameElement; view = view.parent) {
161
+ if (!hitTestable(view.frameElement)) return null;
162
+ const offset = frameOffset(view.frameElement);
163
+ x += offset.x;
164
+ y += offset.y;
165
+ cover = coverAt(view.frameElement, x, y);
166
+ }
167
+ return cover ? describe(cover) : null;
168
+ };
169
+ const elements = picked.map(([i, el]) => {
170
+ const style = el.ownerDocument.defaultView.getComputedStyle(el);
171
+ const geometry = geometryOf(el);
172
+ return {
173
+ index: i,
174
+ tag: el.tagName.toLowerCase(),
175
+ element: describe(el),
176
+ text: String(textOf(el)).replace(/\\s+/g, ' ').trim().slice(0, 1000),
177
+ context: contextOf(el),
178
+ geometry: geometry,
179
+ coveredBy: geometry.hidden ? null : coveredBy(el, geometry),
180
+ computed: { display: style.display, visibility: style.visibility, position: style.position, opacity: style.opacity, zIndex: style.zIndex }
181
+ };
182
+ });
183
+ return { count: found.length, page: page, elements: elements, crossOriginFrame: top.parent !== top };
184
+ }`;
185
+ /** Distinguishes the object groups of concurrent calls */
186
+ let groupCounter = 0;
187
+ /**
188
+ * Measure the elements a selector (or cached index) refers to.
189
+ *
190
+ * @param cdp - CDP connection
191
+ * @param params - Selector (and index) or backend node id
192
+ * @returns Layout report
193
+ * @throws CommandError (83) no match, (81) index out of range or invalid
194
+ * selector, (87) the cached element left the page
195
+ */
196
+ export async function inspectLayout(cdp, params) {
197
+ const objectGroup = `bdg-layout-${++groupCounter}`;
198
+ try {
199
+ const raw = params.backendNodeId === undefined
200
+ ? await measureSelector(cdp, params)
201
+ : await measureNode(cdp, params.backendNodeId, objectGroup);
202
+ if (!raw.page || raw.elements.length === 0)
203
+ throw missingElementError(params, raw.count);
204
+ return buildLayoutResult({ ...raw, page: raw.page }, params);
205
+ }
206
+ finally {
207
+ void cdp
208
+ .send('Runtime.releaseObjectGroup', { objectGroup })
209
+ .catch((error) => log.debug(`Object group not released: ${getErrorMessage(error)}`));
210
+ }
211
+ }
212
+ /**
213
+ * Measure the matches of a selector (searching open shadow roots and
214
+ * same-origin frames) in one page evaluation.
215
+ *
216
+ * @param cdp - CDP connection
217
+ * @param params - Selector and optional index
218
+ * @returns Measurements
219
+ * @throws CommandError (81) invalid selector, (91) page script failure
220
+ */
221
+ async function measureSelector(cdp, params) {
222
+ const found = `(${DEEP_QUERY_JS})(${selectorArgsJS(params.selector)})`;
223
+ const response = (await cdp.send('Runtime.evaluate', {
224
+ expression: `(${LAYOUT_JS})(${found}, ${params.index ?? null}, ${LAYOUT_ELEMENT_LIMIT})`,
225
+ returnByValue: true,
226
+ }));
227
+ if (response.exceptionDetails) {
228
+ throwIfInvalidSelector(response.exceptionDetails, params.selector);
229
+ const err = operationFailedError('measure the elements', response.exceptionDetails.text);
230
+ throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.SCRIPT_ERROR);
231
+ }
232
+ return response.result.value;
233
+ }
234
+ /**
235
+ * Measure one exact element (from the query cache).
236
+ *
237
+ * @param cdp - CDP connection
238
+ * @param backendNodeId - Backend node id
239
+ * @param objectGroup - Object group for the handle
240
+ * @returns Measurements; no elements when the node left the page. An element
241
+ * of a cross-origin iframe (from an a11y query) is placed in the top-level
242
+ * viewport through the iframe's own measurements.
243
+ */
244
+ async function measureNode(cdp, backendNodeId, objectGroup) {
245
+ const resolved = (await cdp
246
+ .send('DOM.resolveNode', { backendNodeId, objectGroup })
247
+ .catch((error) => {
248
+ log.debug(`Node ${backendNodeId} not resolved: ${getErrorMessage(error)}`);
249
+ return {};
250
+ }));
251
+ const objectId = resolved.object?.objectId;
252
+ if (!objectId)
253
+ return { count: 0, elements: [] };
254
+ const response = (await cdp.send('Runtime.callFunctionOn', {
255
+ objectId,
256
+ functionDeclaration: `function () { return (${LAYOUT_JS})(this.isConnected ? [this] : [], null, 1); }`,
257
+ returnByValue: true,
258
+ }));
259
+ const raw = response.result.value ?? { count: 0, elements: [] };
260
+ if (!raw.crossOriginFrame)
261
+ return raw;
262
+ const owner = await findFrameOwner(cdp, objectId);
263
+ if (owner === undefined)
264
+ return raw;
265
+ const ownerLayout = await measureNode(cdp, owner, objectGroup);
266
+ return placeInOwnerFrame(raw, ownerLayout, await measureFrameMapping(cdp, objectId));
267
+ }
268
+ /**
269
+ * Turn page-side measurements into the layout report: rounded page and
270
+ * viewport coordinates, viewport position and text preview per element.
271
+ *
272
+ * @param raw - Measurements with at least one element
273
+ * @param params - Request (selector and index)
274
+ * @returns Layout report
275
+ */
276
+ export function buildLayoutResult(raw, params) {
277
+ const omitted = params.index === undefined ? raw.count - raw.elements.length : 0;
278
+ return {
279
+ success: true,
280
+ selector: params.selector,
281
+ count: raw.count,
282
+ page: roundPage(raw.page),
283
+ elements: raw.elements.map((element) => elementLayout(element, raw.page)),
284
+ ...(omitted > 0 && { omitted }),
285
+ };
286
+ }
287
+ /**
288
+ * Page layout with whole pixels.
289
+ *
290
+ * @param page - Measured page layout
291
+ * @returns Rounded page layout
292
+ */
293
+ function roundPage(page) {
294
+ return {
295
+ viewport: { width: Math.round(page.viewport.width), height: Math.round(page.viewport.height) },
296
+ scroll: { x: Math.round(page.scroll.x), y: Math.round(page.scroll.y) },
297
+ document: { width: Math.round(page.document.width), height: Math.round(page.document.height) },
298
+ ...(page.colorScheme && { colorScheme: page.colorScheme }),
299
+ };
300
+ }
301
+ /**
302
+ * Layout of one element.
303
+ *
304
+ * @param raw - Element measurements
305
+ * @param page - Page layout (viewport size and scroll position)
306
+ * @returns Element layout; `coveredBy` only for elements that are in view
307
+ */
308
+ function elementLayout(raw, page) {
309
+ const { rect } = raw.geometry;
310
+ const placement = classifyViewportPosition(raw.geometry, page.viewport);
311
+ const inView = placement.inViewport === 'visible' || placement.inViewport === 'partly';
312
+ const text = textPreview(raw.text);
313
+ return {
314
+ index: raw.index,
315
+ tag: raw.tag,
316
+ element: raw.element,
317
+ ...(text && { text }),
318
+ ...(raw.context && { context: raw.context }),
319
+ bounds: {
320
+ x: Math.round(rect.x + page.scroll.x),
321
+ y: Math.round(rect.y + page.scroll.y),
322
+ width: Math.round(rect.width),
323
+ height: Math.round(rect.height),
324
+ },
325
+ viewport: { x: Math.round(rect.x), y: Math.round(rect.y) },
326
+ ...placement,
327
+ ...(inView && raw.coveredBy && { coveredBy: raw.coveredBy }),
328
+ ...(raw.geometry.invisible && { invisible: raw.geometry.invisible }),
329
+ ...(raw.geometry.inert && { inert: true }),
330
+ computed: raw.computed,
331
+ };
332
+ }
333
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1,66 @@
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, React's `on…` props
5
+ * of the element and its ancestors, the element's iframe).
6
+ *
7
+ * Each piece is a function expression in a string, combined into
8
+ * {@link ELEMENT_INFO_JS}; every lookup of page globals is guarded, so a
9
+ * page with odd globals (a throwing `jQuery` getter) only loses that detail.
10
+ */
11
+ /** Most jQuery handlers resolved per call; the rest keep jQuery's dispatcher */
12
+ export declare const MAX_JQUERY_HANDLERS = 50;
13
+ /** Most React prop handlers resolved per call; the rest are counted */
14
+ export declare const MAX_REACT_HANDLERS = 50;
15
+ /**
16
+ * Page function, called on the element with the listeners (position in the
17
+ * chain and event type of each), the requested event types (null for all;
18
+ * React props are filtered before the limit), then the chain's objects, then each
19
+ * listener's handler, then the function each handler calls (a bound
20
+ * function's target, else null).
21
+ *
22
+ * Returns `[info, ...jQueryHandlers, ...reactHandlers]`. `info` has the
23
+ * iframe element holding the element's document (`frame`), a framework
24
+ * label per chain entry (`roots`), per listener the handler's name, the
25
+ * identity and name of the function it calls (equal identities are the same
26
+ * function object) and, for jQuery's dispatcher, the jQuery handlers that
27
+ * run for the element; then the React `on…` props that run for the
28
+ * element's events (`react`, see {@link REACT_HANDLERS_JS}). Their functions follow `info` in the same order.
29
+ * After {@link MAX_JQUERY_HANDLERS}, dispatchers stay unresolved and are
30
+ * counted in `jquerySkipped`; after {@link MAX_REACT_HANDLERS}, React props
31
+ * are counted in `reactSkipped`.
32
+ */
33
+ export declare const ELEMENT_INFO_JS: string;
34
+ /** What {@link ELEMENT_INFO_JS} reports, by value */
35
+ export interface ElementInfo {
36
+ frame: string | null;
37
+ roots: Array<string | null>;
38
+ listeners: Array<{
39
+ name: string | null;
40
+ identity: number | null;
41
+ targetName: string | null;
42
+ jquery?: Array<{
43
+ type: string;
44
+ selector: string | null;
45
+ name: string;
46
+ }>;
47
+ }>;
48
+ /** jQuery handlers left unresolved (over the limit) */
49
+ jquerySkipped: number;
50
+ /** React `on…` props that run for the element's events, nearest first */
51
+ react: Array<{
52
+ /** Position of the element the prop is on in the chain (0 = the inspected element); null outside it (a portal's React parent) */
53
+ position: number | null;
54
+ /** Description of that element when it is outside the chain */
55
+ node?: string;
56
+ /** Prop name, e.g. `onClickCapture` */
57
+ prop: string;
58
+ /** DOM event type, e.g. `click` */
59
+ type: string;
60
+ capture: boolean;
61
+ name: string;
62
+ }>;
63
+ /** React props left unresolved (over the limit) */
64
+ reactSkipped: number;
65
+ }
66
+ //# sourceMappingURL=listenerPageScripts.d.ts.map
@@ -0,0 +1,279 @@
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, React's `on…` props
5
+ * of the element and its ancestors, the element's iframe).
6
+ *
7
+ * Each piece is a function expression in a string, combined into
8
+ * {@link ELEMENT_INFO_JS}; every lookup of page globals is guarded, so a
9
+ * page with odd globals (a throwing `jQuery` getter) only loses that detail.
10
+ */
11
+ /** Most jQuery handlers resolved per call; the rest keep jQuery's dispatcher */
12
+ export const MAX_JQUERY_HANDLERS = 50;
13
+ /** Most React prop handlers resolved per call; the rest are counted */
14
+ export const MAX_REACT_HANDLERS = 50;
15
+ /** `(element, view) => string | null`: the iframe element holding the element's document */
16
+ const FRAME_OF_JS = `(element, view) => {
17
+ try {
18
+ const owner = view && view.frameElement;
19
+ return owner ? owner.tagName.toLowerCase() + (owner.id ? '#' + owner.id : '') : null;
20
+ } catch (e) { return null; }
21
+ }`;
22
+ /** `(node) => boolean`: whether the node is a React root container */
23
+ const REACT_ROOT_JS = `(node) => {
24
+ try {
25
+ return !!node && node.nodeType === 1 &&
26
+ ('_reactRootContainer' in node || Object.keys(node).some((key) => key.startsWith('__reactContainer$')));
27
+ } catch (e) { return false; }
28
+ }`;
29
+ /** `(view) => jQuery | undefined`: the page's jQuery, when it has one */
30
+ const JQUERY_OF_JS = `(view) => {
31
+ try {
32
+ if (!view) return undefined;
33
+ return [view.jQuery, view.$].find((c) => c && typeof c._data === 'function');
34
+ } catch (e) { return undefined; }
35
+ }`;
36
+ /**
37
+ * `(jq, element, node, type, handler) => handleObj[] | null`: the jQuery
38
+ * handlers that run for `element` when `handler` is jQuery's dispatcher on
39
+ * `node` (delegates only when the element, or an element between it and
40
+ * `node`, matches their selector); null when it is not the dispatcher.
41
+ */
42
+ const JQUERY_HANDLERS_JS = `(jq, element, node, type, handler) => {
43
+ try {
44
+ if (typeof handler !== 'function') return null;
45
+ const data = jq._data(node);
46
+ if (!data || data.handle !== handler || !data.events) return null;
47
+ const find = jq.find;
48
+ const matches = (el, selector) => {
49
+ try {
50
+ return find && typeof find.matchesSelector === 'function' ? find.matchesSelector(el, selector) : el.matches(selector);
51
+ } catch (e) { return false; }
52
+ };
53
+ const delegatedTo = (selector) => {
54
+ for (let el = element; el && el !== node; el = el.parentNode) {
55
+ if (el.nodeType === 1 && matches(el, selector)) return true;
56
+ }
57
+ return false;
58
+ };
59
+ return Array.from(data.events[type] || []).filter((h) => !h.selector || delegatedTo(h.selector));
60
+ } catch (e) { return null; }
61
+ }`;
62
+ /**
63
+ * `(object, key) => value`: an own data property, read without running a
64
+ * getter the page may have defined (undefined for accessors and on errors).
65
+ */
66
+ const OWN_VALUE_JS = `(object, key) => {
67
+ try {
68
+ const descriptor = object ? Object.getOwnPropertyDescriptor(object, key) : undefined;
69
+ return descriptor ? descriptor.value : undefined;
70
+ } catch (e) { return undefined; }
71
+ }`;
72
+ /**
73
+ * `(node, prefixes) => value`: the value of the node's own key starting with
74
+ * one of `prefixes` (React's keys end in a random suffix).
75
+ */
76
+ const REACT_KEY_JS = `(node, prefixes) => {
77
+ try {
78
+ const key = Object.keys(node).find((k) => prefixes.some((prefix) => k.startsWith(prefix)));
79
+ return key === undefined ? undefined : (${OWN_VALUE_JS})(node, key);
80
+ } catch (e) { return undefined; }
81
+ }`;
82
+ /** `(node) => fiber | undefined`: React's fiber of a DOM element */
83
+ const REACT_FIBER_JS = `(node) => (${REACT_KEY_JS})(node, ['__reactFiber$', '__reactInternalInstance$'])`;
84
+ /**
85
+ * `(node) => object | null`: the props React rendered on a DOM element:
86
+ * `__reactProps$…` (React 17-19), `__reactEventHandlers$…` (React 16), else
87
+ * the `memoizedProps` of its fiber.
88
+ */
89
+ const REACT_PROPS_JS = `(node) => {
90
+ if (!node || node.nodeType !== 1) return null;
91
+ const props = (${REACT_KEY_JS})(node, ['__reactProps$', '__reactEventHandlers$']);
92
+ if (props && typeof props === 'object') return props;
93
+ const memoized = (${OWN_VALUE_JS})((${REACT_FIBER_JS})(node), 'memoizedProps');
94
+ return memoized && typeof memoized === 'object' ? memoized : null;
95
+ }`;
96
+ /** Most fibers walked up from the element (guards against cycles) */
97
+ const MAX_FIBER_STEPS = 1000;
98
+ /**
99
+ * `(element, nodes) => Array<{ node, position }>`: the DOM elements whose
100
+ * React props run for events on the element, nearest first. With a fiber,
101
+ * the host components on its `.return` path (so a portal's React parents
102
+ * count and DOM parents outside the React path don't); `position` is the
103
+ * node's place in the chain, null outside it. Without one, the chain's elements.
104
+ */
105
+ const REACT_HOSTS_JS = `(element, nodes) => {
106
+ const own = ${OWN_VALUE_JS};
107
+ let fiber = (${REACT_FIBER_JS})(element);
108
+ if (!fiber) return nodes.flatMap((node, position) => (node && node.nodeType === 1 ? [{ node, position }] : []));
109
+ const hosts = [];
110
+ const seen = new Set();
111
+ for (let step = 0; fiber && typeof fiber === 'object' && !seen.has(fiber) && step < ${MAX_FIBER_STEPS}; step++) {
112
+ seen.add(fiber);
113
+ const node = own(fiber, 'stateNode');
114
+ if (typeof own(fiber, 'type') === 'string' && node && node.nodeType === 1) {
115
+ const position = nodes.indexOf(node);
116
+ hosts.push({ node, position: position === -1 ? null : position });
117
+ }
118
+ fiber = own(fiber, 'return');
119
+ }
120
+ return hosts;
121
+ }`;
122
+ /** `(node) => string`: CDP-like description of an element, e.g. `div#app.card` */
123
+ const DESCRIBE_NODE_JS = `(node) => {
124
+ try {
125
+ const classes = Array.from(node.classList || []).map((c) => '.' + c).join('');
126
+ return String(node.localName || 'element') + (node.id ? '#' + node.id : '') + classes;
127
+ } catch (e) { return 'element'; }
128
+ }`;
129
+ /**
130
+ * `(props) => Array<{ prop, handler, name }>`: the event handler props
131
+ * (`onClick`, `onKeyDownCapture`) among React props, read without
132
+ * running getters.
133
+ */
134
+ const REACT_HANDLER_PROPS_JS = `(props) => {
135
+ const own = ${OWN_VALUE_JS};
136
+ try {
137
+ return Object.keys(props).filter((prop) => /^on[A-Z]/.test(prop)).flatMap((prop) => {
138
+ const handler = own(props, prop);
139
+ if (typeof handler !== 'function') return [];
140
+ const name = own(handler, 'name');
141
+ return [{ prop, handler, name: typeof name === 'string' ? name : '' }];
142
+ });
143
+ } catch (e) { return []; }
144
+ }`;
145
+ /**
146
+ * `(prop) => { type, capture }`: the DOM event type and phase of a React
147
+ * handler prop: `onClick` → click, `onClickCapture` → click in the capture
148
+ * phase, `onDoubleClick` → dblclick, `onFocus`/`onBlur` → focusin/focusout
149
+ * (the events React listens for), `onGotPointerCapture` → gotpointercapture
150
+ * (and `onGotPointerCaptureCapture` its capture phase).
151
+ */
152
+ const REACT_EVENT_TYPE_JS = `(prop) => {
153
+ const base = prop.slice(2);
154
+ const capture = base.endsWith('Capture') && !/^(?:Got|Lost)PointerCapture$/.test(base);
155
+ const name = (capture ? base.slice(0, -7) : base).toLowerCase();
156
+ const types = { doubleclick: 'dblclick', focus: 'focusin', blur: 'focusout' };
157
+ return { type: types[name] || name, capture };
158
+ }`;
159
+ /**
160
+ * Event types React does not bubble to parents (their bubble-phase props on
161
+ * ancestors never run for the element): enter/leave, scroll (React 17+),
162
+ * and the events React listens for on the element itself (media, load, …).
163
+ */
164
+ const REACT_NON_BUBBLING_TYPES = [
165
+ 'mouseenter',
166
+ 'mouseleave',
167
+ 'pointerenter',
168
+ 'pointerleave',
169
+ 'scroll',
170
+ 'scrollend',
171
+ 'load',
172
+ 'error',
173
+ 'abort',
174
+ 'cancel',
175
+ 'close',
176
+ 'invalid',
177
+ 'toggle',
178
+ 'canplay',
179
+ 'canplaythrough',
180
+ 'durationchange',
181
+ 'emptied',
182
+ 'encrypted',
183
+ 'ended',
184
+ 'loadeddata',
185
+ 'loadedmetadata',
186
+ 'loadstart',
187
+ 'pause',
188
+ 'play',
189
+ 'playing',
190
+ 'progress',
191
+ 'ratechange',
192
+ 'seeked',
193
+ 'seeking',
194
+ 'stalled',
195
+ 'suspend',
196
+ 'timeupdate',
197
+ 'volumechange',
198
+ 'waiting',
199
+ ];
200
+ /**
201
+ * `(element, nodes, wanted, fns) => { react, reactSkipped }`: the React
202
+ * `on…` props that run for events on the element (its own, and bubbling or
203
+ * capture ones of its React parents), limited to the `wanted` types (all
204
+ * when null); their functions are pushed to `fns`.
205
+ */
206
+ const REACT_HANDLERS_JS = `(element, nodes, wanted, fns) => {
207
+ const nonBubbling = new Set(${JSON.stringify(REACT_NON_BUBBLING_TYPES)});
208
+ const react = [];
209
+ let reactSkipped = 0;
210
+ (${REACT_HOSTS_JS})(element, nodes).forEach(({ node, position }, depth) => {
211
+ const props = (${REACT_PROPS_JS})(node);
212
+ if (!props) return;
213
+ for (const { prop, handler, name } of (${REACT_HANDLER_PROPS_JS})(props)) {
214
+ const { type, capture } = (${REACT_EVENT_TYPE_JS})(prop);
215
+ if ((wanted && !wanted.has(type)) || (depth > 0 && !capture && nonBubbling.has(type))) continue;
216
+ if (react.length >= ${MAX_REACT_HANDLERS}) { reactSkipped++; continue; }
217
+ fns.push(handler);
218
+ react.push({ position, ...(position === null && { node: (${DESCRIBE_NODE_JS})(node) }), prop, type, capture, name });
219
+ }
220
+ });
221
+ return { react, reactSkipped };
222
+ }`;
223
+ /**
224
+ * Page function, called on the element with the listeners (position in the
225
+ * chain and event type of each), the requested event types (null for all;
226
+ * React props are filtered before the limit), then the chain's objects, then each
227
+ * listener's handler, then the function each handler calls (a bound
228
+ * function's target, else null).
229
+ *
230
+ * Returns `[info, ...jQueryHandlers, ...reactHandlers]`. `info` has the
231
+ * iframe element holding the element's document (`frame`), a framework
232
+ * label per chain entry (`roots`), per listener the handler's name, the
233
+ * identity and name of the function it calls (equal identities are the same
234
+ * function object) and, for jQuery's dispatcher, the jQuery handlers that
235
+ * run for the element; then the React `on…` props that run for the
236
+ * element's events (`react`, see {@link REACT_HANDLERS_JS}). Their functions follow `info` in the same order.
237
+ * After {@link MAX_JQUERY_HANDLERS}, dispatchers stay unresolved and are
238
+ * counted in `jquerySkipped`; after {@link MAX_REACT_HANDLERS}, React props
239
+ * are counted in `reactSkipped`.
240
+ */
241
+ export const ELEMENT_INFO_JS = `function (listeners, types, ...rest) {
242
+ const count = listeners.length;
243
+ const nodes = rest.slice(0, rest.length - 2 * count);
244
+ const handlers = rest.slice(nodes.length, nodes.length + count);
245
+ const targets = rest.slice(nodes.length + count);
246
+ const view = this.ownerDocument && this.ownerDocument.defaultView;
247
+ const jq = (${JQUERY_OF_JS})(view);
248
+ const ids = new Map();
249
+ const identity = (fn) => {
250
+ if (typeof fn !== 'function') return null;
251
+ if (!ids.has(fn)) ids.set(fn, ids.size);
252
+ return ids.get(fn);
253
+ };
254
+ const fns = [];
255
+ let jquerySkipped = 0;
256
+ const describeHandler = (h) => {
257
+ fns.push(h.handler);
258
+ return { type: h.origType || h.type, selector: h.selector || null,
259
+ name: typeof h.handler === 'function' ? h.handler.name : '' };
260
+ };
261
+ const info = listeners.map((listener, i) => {
262
+ const handler = handlers[i];
263
+ const target = typeof targets[i] === 'function' ? targets[i] : handler;
264
+ const entry = { name: typeof handler === 'function' ? handler.name : null, identity: identity(target),
265
+ targetName: typeof target === 'function' ? target.name : null };
266
+ const resolved = jq ? (${JQUERY_HANDLERS_JS})(jq, this, nodes[listener.position], listener.type, handler) : null;
267
+ if (!resolved) return entry;
268
+ if (fns.length + resolved.length > ${MAX_JQUERY_HANDLERS}) {
269
+ jquerySkipped += resolved.length;
270
+ return entry;
271
+ }
272
+ return { ...entry, jquery: resolved.map(describeHandler) };
273
+ });
274
+ const roots = nodes.map((node) => ((${REACT_ROOT_JS})(node) ? 'React root' : null));
275
+ const wanted = types && types.length > 0 ? new Set(types) : null;
276
+ const { react, reactSkipped } = (${REACT_HANDLERS_JS})(this, nodes, wanted, fns);
277
+ return [{ frame: (${FRAME_OF_JS})(this, view), roots, listeners: info, jquerySkipped, react, reactSkipped }, ...fns];
278
+ }`;
279
+ //# sourceMappingURL=listenerPageScripts.js.map