browser-debugger-cli 0.11.0 → 0.13.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 (222) hide show
  1. package/.claude/skills/bdg/SKILL.md +4 -4
  2. package/README.md +143 -79
  3. package/dist/commands/cdp.d.ts +22 -1
  4. package/dist/commands/cdp.js +100 -43
  5. package/dist/commands/console.d.ts +12 -0
  6. package/dist/commands/console.js +62 -12
  7. package/dist/commands/css.d.ts +13 -0
  8. package/dist/commands/css.js +53 -0
  9. package/dist/commands/dom/DomElementResolver.d.ts +3 -1
  10. package/dist/commands/dom/DomElementResolver.js +10 -3
  11. package/dist/commands/dom/a11y.js +3 -2
  12. package/dist/commands/dom/audit.d.ts +14 -0
  13. package/dist/commands/dom/audit.js +87 -0
  14. package/dist/commands/dom/eval.d.ts +3 -2
  15. package/dist/commands/dom/eval.js +11 -5
  16. package/dist/commands/dom/form.js +10 -9
  17. package/dist/commands/dom/formInteraction.js +42 -11
  18. package/dist/commands/dom/get.js +8 -8
  19. package/dist/commands/dom/helpers/index.d.ts +1 -1
  20. package/dist/commands/dom/helpers/index.js +1 -1
  21. package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
  22. package/dist/commands/dom/helpers/keyAttributes.js +6 -4
  23. package/dist/commands/dom/helpers/query.d.ts +27 -3
  24. package/dist/commands/dom/helpers/query.js +152 -64
  25. package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
  26. package/dist/commands/dom/helpers/screenshot.js +169 -49
  27. package/dist/commands/dom/index.js +7 -2
  28. package/dist/commands/dom/query.d.ts +19 -2
  29. package/dist/commands/dom/query.js +37 -6
  30. package/dist/commands/dom/screenshot.js +12 -7
  31. package/dist/commands/dom/semanticUtils.d.ts +3 -2
  32. package/dist/commands/dom/semanticUtils.js +40 -9
  33. package/dist/commands/dom/wait.js +5 -3
  34. package/dist/commands/helpJson.d.ts +82 -19
  35. package/dist/commands/helpJson.js +112 -41
  36. package/dist/commands/helpTopic.d.ts +16 -1
  37. package/dist/commands/helpTopic.js +59 -1
  38. package/dist/commands/installSkill.d.ts +15 -5
  39. package/dist/commands/installSkill.js +86 -16
  40. package/dist/commands/network/list.js +22 -12
  41. package/dist/commands/optionBehaviors.js +53 -16
  42. package/dist/commands/page.js +7 -4
  43. package/dist/commands/peek.d.ts +7 -0
  44. package/dist/commands/peek.js +65 -23
  45. package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
  46. package/dist/commands/shared/daemonErrorHandler.js +20 -9
  47. package/dist/commands/shared/dataFetcher.d.ts +12 -4
  48. package/dist/commands/shared/dataFetcher.js +12 -4
  49. package/dist/commands/shared/followMode.d.ts +9 -1
  50. package/dist/commands/shared/followMode.js +22 -4
  51. package/dist/commands/shared/optionTypes.d.ts +9 -2
  52. package/dist/commands/shared/outputFile.js +6 -1
  53. package/dist/commands/start.d.ts +20 -5
  54. package/dist/commands/start.js +84 -23
  55. package/dist/commands/stop.d.ts +11 -0
  56. package/dist/commands/stop.js +24 -1
  57. package/dist/commands/tail.d.ts +7 -1
  58. package/dist/commands/tail.js +13 -62
  59. package/dist/commands.js +2 -0
  60. package/dist/connection/cdp.d.ts +7 -0
  61. package/dist/connection/cdp.js +9 -0
  62. package/dist/connection/launcher.js +3 -2
  63. package/dist/daemon/SessionController.js +6 -1
  64. package/dist/daemon/launcher.d.ts +3 -2
  65. package/dist/daemon/launcher.js +47 -3
  66. package/dist/daemon/session/Session.d.ts +4 -1
  67. package/dist/daemon/session/Session.js +33 -2
  68. package/dist/daemon/session/TelemetryStore.d.ts +8 -1
  69. package/dist/daemon/session/TelemetryStore.js +13 -1
  70. package/dist/daemon/session/commandRegistry.js +36 -14
  71. package/dist/daemon/session/interactions.d.ts +2 -1
  72. package/dist/daemon/session/interactions.js +13 -1
  73. package/dist/daemon/session/plugins.js +19 -53
  74. package/dist/daemon/session/teardown.js +1 -1
  75. package/dist/daemon.js +9234 -7222
  76. package/dist/errors/messages.d.ts +88 -15
  77. package/dist/errors/messages.js +177 -27
  78. package/dist/index.js +19322 -13961
  79. package/dist/ipc/client.d.ts +22 -2
  80. package/dist/ipc/client.js +34 -5
  81. package/dist/ipc/protocol/auditTypes.d.ts +135 -0
  82. package/dist/ipc/protocol/auditTypes.js +6 -0
  83. package/dist/ipc/protocol/commands.d.ts +35 -0
  84. package/dist/ipc/protocol/commands.js +2 -0
  85. package/dist/ipc/protocol/domTypes.d.ts +16 -0
  86. package/dist/ipc/protocol/inspectTypes.d.ts +73 -8
  87. package/dist/ipc/session/types.d.ts +2 -0
  88. package/dist/runtime/css/search.d.ts +39 -0
  89. package/dist/runtime/css/search.js +122 -0
  90. package/dist/runtime/dom/actionEffects.d.ts +9 -2
  91. package/dist/runtime/dom/actionEffects.js +30 -14
  92. package/dist/runtime/dom/audit.d.ts +19 -0
  93. package/dist/runtime/dom/audit.js +37 -0
  94. package/dist/runtime/dom/auditModel.d.ts +45 -0
  95. package/dist/runtime/dom/auditModel.js +220 -0
  96. package/dist/runtime/dom/auditScripts.d.ts +113 -0
  97. package/dist/runtime/dom/auditScripts.js +148 -0
  98. package/dist/runtime/dom/elementGeometry.d.ts +16 -3
  99. package/dist/runtime/dom/elementGeometry.js +49 -10
  100. package/dist/runtime/dom/elementInfo.d.ts +74 -17
  101. package/dist/runtime/dom/elementInfo.js +187 -34
  102. package/dist/runtime/dom/evalHelpers.d.ts +12 -2
  103. package/dist/runtime/dom/evalHelpers.js +67 -7
  104. package/dist/runtime/dom/formDiscovery.d.ts +6 -2
  105. package/dist/runtime/dom/formDiscovery.js +20 -3
  106. package/dist/runtime/dom/formFillHelpers/fill.js +8 -12
  107. package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
  108. package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
  109. package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
  110. package/dist/runtime/dom/formSubmitHelpers.js +4 -3
  111. package/dist/runtime/dom/frameLayout.js +1 -0
  112. package/dist/runtime/dom/inspect.d.ts +7 -0
  113. package/dist/runtime/dom/inspect.js +92 -28
  114. package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
  115. package/dist/runtime/dom/inspectAllStyles.js +90 -7
  116. package/dist/runtime/dom/inspectCascade.d.ts +19 -2
  117. package/dist/runtime/dom/inspectCascade.js +214 -44
  118. package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
  119. package/dist/runtime/dom/inspectCascadeModel.js +108 -34
  120. package/dist/runtime/dom/inspectHints.d.ts +26 -3
  121. package/dist/runtime/dom/inspectHints.js +125 -9
  122. package/dist/runtime/dom/inspectModel.d.ts +5 -1
  123. package/dist/runtime/dom/inspectModel.js +37 -10
  124. package/dist/runtime/dom/inspectPaintModel.d.ts +50 -22
  125. package/dist/runtime/dom/inspectPaintModel.js +182 -68
  126. package/dist/runtime/dom/inspectRules.d.ts +19 -0
  127. package/dist/runtime/dom/inspectRules.js +21 -5
  128. package/dist/runtime/dom/inspectScripts.d.ts +112 -12
  129. package/dist/runtime/dom/inspectScripts.js +357 -32
  130. package/dist/runtime/dom/inspectTree.js +10 -2
  131. package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
  132. package/dist/runtime/dom/inspectWhyModel.js +52 -10
  133. package/dist/runtime/dom/layout.js +40 -16
  134. package/dist/runtime/dom/reactEventHelpers.d.ts +21 -4
  135. package/dist/runtime/dom/reactEventHelpers.js +90 -36
  136. package/dist/runtime/dom/targetNode.d.ts +18 -5
  137. package/dist/runtime/dom/targetNode.js +268 -8
  138. package/dist/runtime/dom/wait.js +2 -1
  139. package/dist/runtime/page/bdgWorld.d.ts +57 -0
  140. package/dist/runtime/page/bdgWorld.js +180 -0
  141. package/dist/runtime/page/emulation.d.ts +13 -4
  142. package/dist/runtime/page/emulation.js +69 -4
  143. package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
  144. package/dist/runtime/page/replacedBuiltins.js +136 -0
  145. package/dist/runtime/page/userAgent.d.ts +17 -0
  146. package/dist/runtime/page/userAgent.js +57 -0
  147. package/dist/session/QueryCacheManager.d.ts +4 -1
  148. package/dist/session/QueryCacheManager.js +5 -2
  149. package/dist/session/chrome.d.ts +4 -1
  150. package/dist/session/chrome.js +7 -1
  151. package/dist/session/cleanup/staleSession.d.ts +21 -4
  152. package/dist/session/cleanup/staleSession.js +79 -9
  153. package/dist/session/cleanup/userCommands.d.ts +4 -1
  154. package/dist/session/cleanup/userCommands.js +10 -5
  155. package/dist/session/daemonSocket.d.ts +10 -0
  156. package/dist/session/daemonSocket.js +22 -0
  157. package/dist/session/lastSession.d.ts +6 -3
  158. package/dist/session/lastSession.js +11 -5
  159. package/dist/session/paths.d.ts +3 -1
  160. package/dist/session/paths.js +5 -5
  161. package/dist/session/portClaims.js +4 -3
  162. package/dist/session/sessionList.d.ts +13 -5
  163. package/dist/session/sessionList.js +31 -7
  164. package/dist/telemetry/a11y.js +2 -2
  165. package/dist/telemetry/console.d.ts +2 -1
  166. package/dist/telemetry/console.js +30 -21
  167. package/dist/telemetry/pageCrash.d.ts +26 -0
  168. package/dist/telemetry/pageCrash.js +53 -0
  169. package/dist/types.d.ts +20 -0
  170. package/dist/ui/formatters/audit.d.ts +19 -0
  171. package/dist/ui/formatters/audit.js +115 -0
  172. package/dist/ui/formatters/cdp.d.ts +138 -0
  173. package/dist/ui/formatters/cdp.js +131 -0
  174. package/dist/ui/formatters/console/chronological.js +3 -1
  175. package/dist/ui/formatters/console/follow.d.ts +2 -1
  176. package/dist/ui/formatters/console/follow.js +2 -2
  177. package/dist/ui/formatters/console/json.d.ts +2 -2
  178. package/dist/ui/formatters/console/json.js +11 -5
  179. package/dist/ui/formatters/console/shared.d.ts +30 -0
  180. package/dist/ui/formatters/console/shared.js +16 -0
  181. package/dist/ui/formatters/console/summarize.d.ts +9 -2
  182. package/dist/ui/formatters/console/summarize.js +40 -9
  183. package/dist/ui/formatters/console.d.ts +2 -1
  184. package/dist/ui/formatters/console.js +7 -5
  185. package/dist/ui/formatters/details.js +3 -1
  186. package/dist/ui/formatters/dom.d.ts +2 -2
  187. package/dist/ui/formatters/dom.js +10 -8
  188. package/dist/ui/formatters/helpFormatters.js +1 -1
  189. package/dist/ui/formatters/inspect.js +50 -17
  190. package/dist/ui/formatters/installSkill.d.ts +9 -1
  191. package/dist/ui/formatters/installSkill.js +32 -6
  192. package/dist/ui/formatters/layout.js +2 -1
  193. package/dist/ui/formatters/networkList.d.ts +1 -1
  194. package/dist/ui/formatters/networkList.js +1 -2
  195. package/dist/ui/formatters/preview.d.ts +2 -0
  196. package/dist/ui/formatters/preview.js +17 -7
  197. package/dist/ui/formatters/sessions.d.ts +2 -2
  198. package/dist/ui/formatters/sessions.js +9 -2
  199. package/dist/ui/formatters/status.js +1 -1
  200. package/dist/ui/logging/logger.d.ts +1 -1
  201. package/dist/ui/messages/commands.d.ts +168 -11
  202. package/dist/ui/messages/commands.js +245 -18
  203. package/dist/ui/messages/consoleMessages.d.ts +24 -0
  204. package/dist/ui/messages/consoleMessages.js +32 -0
  205. package/dist/ui/messages/preview.d.ts +12 -0
  206. package/dist/ui/messages/preview.js +18 -2
  207. package/dist/ui/messages/session.d.ts +13 -2
  208. package/dist/ui/messages/session.js +22 -3
  209. package/dist/utils/cssValues.js +36 -4
  210. package/dist/utils/decisionTrees.js +0 -5
  211. package/dist/utils/directories.d.ts +34 -0
  212. package/dist/utils/directories.js +88 -0
  213. package/dist/utils/display.d.ts +16 -0
  214. package/dist/utils/display.js +42 -0
  215. package/dist/utils/exitCodes.d.ts +1 -0
  216. package/dist/utils/exitCodes.js +6 -0
  217. package/dist/utils/process.d.ts +12 -0
  218. package/dist/utils/process.js +25 -0
  219. package/dist/utils/suggestions.d.ts +4 -2
  220. package/dist/utils/suggestions.js +7 -5
  221. package/dist/utils/taskMappings.js +1 -1
  222. package/package.json +3 -2
@@ -26,6 +26,10 @@ export interface RawTreeNode {
26
26
  display: string;
27
27
  /** Text of an element without block-level children */
28
28
  text?: string;
29
+ /** Reached through a slot or a `display: contents` wrapper (`slot.label`, `div.row (contents)`) */
30
+ via?: string;
31
+ /** In the shadow root of its parent */
32
+ shadow?: boolean;
29
33
  children?: RawTreeNode[];
30
34
  /** Rendered element children (at the depth limit) */
31
35
  childCount?: number;
@@ -38,6 +42,15 @@ export interface RawBackground {
38
42
  color: string;
39
43
  /** Has a background image or gradient */
40
44
  image: boolean;
45
+ /** Its own opacity, below 1 (it fades its background and everything inside it) */
46
+ opacity?: number;
47
+ }
48
+ /** A rule that would set a property if its `@media`/`@supports` condition applied */
49
+ export interface InactiveRule {
50
+ selector: string;
51
+ /** e.g. `@media (max-width: 600px)` */
52
+ condition: string;
53
+ value: string;
41
54
  }
42
55
  /** What {@link INSPECT_PAGE_JS} returns */
43
56
  export interface RawInspect {
@@ -56,15 +69,31 @@ export interface RawInspect {
56
69
  style: string;
57
70
  weight: string;
58
71
  };
59
- /** Has text to describe: own text, only inline content with text, or a form control */
72
+ /**
73
+ * Has text to describe: a text field or select, its own text where most
74
+ * of its text is, or only inline content with text
75
+ */
60
76
  textual: boolean;
61
77
  formControl: boolean;
78
+ /**
79
+ * Label of the descendant that draws most of the text (`abbr`,
80
+ * `slot.button__label`) when it is not the element itself; its styles are
81
+ * the text's
82
+ */
83
+ textHolder?: string;
84
+ /** Its text (the element, or the descendant that draws it) has a box and is not `visibility: hidden` */
85
+ rendered: boolean;
86
+ /** Visible text is drawn in it (or it is a text field or select) */
87
+ hasText: boolean;
88
+ /**
89
+ * The first family of the text's `font-family` is a web font (`@font-face`)
90
+ * the page loaded: whatever name the font file gives, it is not a fallback
91
+ */
92
+ familyLoaded?: boolean;
62
93
  /** Replaced element (img, svg and its shapes, video, canvas, iframe, embed, object, form controls): sized by its content */
63
94
  replaced?: boolean;
64
95
  /** An SVG element (SVG properties are not noise for it) */
65
96
  svg?: boolean;
66
- /** A text node is a direct child (the rendered font is read from the element itself) */
67
- ownText: boolean;
68
97
  /** Computed (not resolved) width and height: `auto`, `200px`, `50%`, … */
69
98
  typed: {
70
99
  width: string;
@@ -86,6 +115,8 @@ export interface RawInspect {
86
115
  left?: number;
87
116
  right?: number;
88
117
  };
118
+ /** Its text is cut off: clipped by `overflow` (ellipsis or not) or by a line clamp, on it or its text holder */
119
+ truncated?: boolean;
89
120
  /** Content size when it overflows the box */
90
121
  scroll?: {
91
122
  w: number;
@@ -99,6 +130,12 @@ export interface RawInspect {
99
130
  canvasDark: boolean;
100
131
  /** Opacity of the element times that of its ancestors */
101
132
  opacity?: number;
133
+ /**
134
+ * What makes the text's contrast approximate: blend modes and filters on
135
+ * it or its ancestors, painted content behind it that is not an ancestor
136
+ * (a canvas, a positioned layer) or on top of it
137
+ */
138
+ paintRisks?: string[];
102
139
  tree?: RawTreeNode[];
103
140
  hiddenChildren: number;
104
141
  /** Children the walk did not reach ({@link TREE_NODE_CAP}) */
@@ -109,24 +146,87 @@ export interface RawInspect {
109
146
  * given per side, e.g. `top 1px solid … / right 0px none …`
110
147
  */
111
148
  props?: Record<string, string>;
149
+ /** Font size of the root element (px), for rem custom properties in `--props` */
150
+ rootFontSize?: number;
112
151
  /** `--props` names the browser does not know as CSS properties */
113
152
  unknownProps?: string[];
114
- /** Properties of running CSS transitions, and names of running animations */
153
+ /** The `--why` property is not a CSS property */
154
+ unknownWhy?: boolean;
155
+ /** Longhands of the `--why` property when it is a shorthand (as the browser expands it) */
156
+ whyLonghands?: string[];
157
+ /** Computed value of the `--why` shorthand (`getComputedStyle` writes it as one value) */
158
+ whyComputed?: string;
159
+ /** Rules for the element that set the `--why` property under a condition that does not apply now */
160
+ whyInactive?: InactiveRule[];
161
+ /** Properties of running CSS transitions, and names of running animations (time-based: scroll-driven ones do not change on their own) */
115
162
  animating: string[];
116
163
  }
164
+ /**
165
+ * Page-side flat-tree helpers: the element's computed style, its flat-tree
166
+ * parent, the parent that lays it out (skipping `display: contents`), its
167
+ * element children in the flat tree and whether an element is rendered.
168
+ */
169
+ export declare const FLAT_TREE_JS: string;
170
+ /**
171
+ * Page-side hit test that also sees elements with `pointer-events: none`
172
+ * (hero images, decorative layers and blended duplicates often have it, and
173
+ * `elementsFromPoint` skips them): for the duration of `test`, a constructed
174
+ * stylesheet makes every element of the given roots (documents and shadow
175
+ * roots) hittable. It is added and removed within one script turn, so nothing
176
+ * is painted with it and no DOM mutation is recorded. A root that already has
177
+ * it (an outer call covering a whole page walk) is left as it is, so nested
178
+ * calls cost no extra style recalculation.
179
+ */
180
+ export declare const HIT_EVERYTHING_JS = "(roots, test) => {\n const added = [];\n for (const root of roots) {\n if (!root || !root.adoptedStyleSheets) continue;\n const view = (root.ownerDocument || root).defaultView;\n try {\n if (!view.__bdgHitSheet) {\n view.__bdgHitSheet = new view.CSSStyleSheet();\n view.__bdgHitSheet.replaceSync('* { pointer-events: auto !important; }');\n }\n if (root.adoptedStyleSheets.includes(view.__bdgHitSheet)) continue;\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, view.__bdgHitSheet];\n added.push([root, view.__bdgHitSheet]);\n } catch (e) {\n continue;\n }\n }\n try {\n return test();\n } finally {\n for (const [root, sheet] of added) root.adoptedStyleSheets = root.adoptedStyleSheets.filter((s) => s !== sheet);\n }\n}";
181
+ /**
182
+ * Page-side reasons the contrast of an element's text is approximate: a
183
+ * blend mode or filter on it or an ancestor, and, hit-testing the middle of
184
+ * its first line of text (else of its first box; only in the viewport), the
185
+ * nearest element below it that is not an ancestor, above the first opaque
186
+ * background of its own chain, and
187
+ * paints (a canvas, video, image, background) and the nearest one on top of
188
+ * it that paints (an overlay).
189
+ */
190
+ export declare const PAINT_RISKS_JS = "(el, tree, textParent) => {\n const risks = [];\n const chain = [];\n for (let n = el; n && chain.length < 60; n = tree.flatParent(n)) chain.push(n);\n for (const n of chain) {\n const s = tree.style(n);\n if (s.mixBlendMode !== 'normal') risks.push('mix-blend-mode ' + s.mixBlendMode + ' on ' + tree.label(n));\n if (s.filter !== 'none') risks.push('filter on ' + tree.label(n));\n }\n const textNode = Array.from(textParent.childNodes).find((c) => c.nodeType === 3 && c.data.trim() !== '');\n const range = el.ownerDocument.createRange();\n if (textNode) range.selectNodeContents(textNode);\n const box = tree.style(el).display === 'contents' ? tree.layoutParent(el) : el;\n const rect = (textNode && range.getClientRects()[0]) || (box && box.getClientRects()[0]);\n const view = el.ownerDocument.defaultView;\n if (!rect) return risks;\n const x = rect.left + rect.width / 2;\n const y = rect.top + rect.height / 2;\n if (x < 0 || y < 0 || x >= view.innerWidth || y >= view.innerHeight) return risks;\n const root = el.getRootNode();\n const hits = ((roots, test) => {\n const added = [];\n for (const root of roots) {\n if (!root || !root.adoptedStyleSheets) continue;\n const view = (root.ownerDocument || root).defaultView;\n try {\n if (!view.__bdgHitSheet) {\n view.__bdgHitSheet = new view.CSSStyleSheet();\n view.__bdgHitSheet.replaceSync('* { pointer-events: auto !important; }');\n }\n if (root.adoptedStyleSheets.includes(view.__bdgHitSheet)) continue;\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, view.__bdgHitSheet];\n added.push([root, view.__bdgHitSheet]);\n } catch (e) {\n continue;\n }\n }\n try {\n return test();\n } finally {\n for (const [root, sheet] of added) root.adoptedStyleSheets = root.adoptedStyleSheets.filter((s) => s !== sheet);\n }\n})([el.ownerDocument, root], () => (root.elementsFromPoint ? root : el.ownerDocument).elementsFromPoint(x, y));\n const at = hits.findIndex((h) => chain.includes(h));\n if (at < 0) return risks;\n const clear = (color) => color === 'transparent' || /^rgba\\(.*,\\s*0\\)$/.test(color) || /\\/\\s*0\\)$/.test(color);\n const opaque = (n) => {\n const s = tree.style(n);\n return /^rgb\\(/.test(s.backgroundColor) && s.backgroundImage === 'none' && Number(s.opacity) === 1;\n };\n const paints = (n) => {\n const s = tree.style(n);\n return /^(canvas|video|img|iframe|embed|object|svg)$/.test(n.localName) || s.backgroundImage !== 'none' || !clear(s.backgroundColor);\n };\n let behind = null;\n for (const h of hits.slice(at)) {\n if (chain.includes(h)) {\n if (opaque(h)) break;\n } else if (paints(h)) {\n behind = h;\n break;\n }\n }\n if (behind) risks.push(tree.label(behind) + ' behind');\n const onTop = hits.slice(0, at).find((h) => !el.contains(h) && paints(h));\n if (onTop) risks.push(tree.label(onTop) + ' on top');\n return risks;\n}";
117
191
  /**
118
192
  * Page-side function run on the element (`this`), see {@link RawInspect}.
119
- * Arguments: tree depth, and the property names asked for with `--props`
120
- * (or null).
193
+ * Arguments: tree depth, the property names asked for with `--props` (or
194
+ * null) and the `--why` property (or null).
121
195
  */
122
- export declare const INSPECT_PAGE_JS = "function (depth, props) {\n const el = this;\n const view = el.ownerDocument.defaultView;\n const tree = ((view) => {\n const style = (n, pseudo) => view.getComputedStyle(n, pseudo);\n const skipped = /^(script|style|template|link|meta|noscript|title|head|base)$/;\n const flatParent = (n) => n.assignedSlot || n.parentElement || (n.parentNode && n.parentNode.host) || null;\n const layoutParent = (n) => {\n let p = flatParent(n);\n while (p && style(p).display === 'contents') p = flatParent(p);\n return p;\n };\n const children = (n) => {\n const out = [];\n const add = (c) => {\n if (skipped.test(c.localName)) return;\n if (c.localName === 'slot') {\n const assigned = c.assignedElements({ flatten: true });\n (assigned.length ? assigned : Array.from(c.children)).forEach(add);\n } else if (style(c).display === 'contents') {\n Array.from((c.shadowRoot || c).children).forEach(add);\n } else {\n out.push(c);\n }\n };\n Array.from((n.shadowRoot || n).children).forEach(add);\n return out;\n };\n const rendered = (n) => n.getClientRects().length > 0 &&\n (!n.checkVisibility || n.checkVisibility({ visibilityProperty: true }));\n const container = (n) => children(n).some((c) => rendered(c) && !/^inline/.test(style(c).display));\n return { style, flatParent, layoutParent, children, rendered, container };\n})(view);\n const textOf = (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 clean = (text) => String(text || '').replace(/\\s+/g, ' ').trim().slice(0, 200);\n if (el.localName === 'input' && el.type === 'hidden') return '';\n if (el.localName === 'input' || el.localName === 'textarea') {\n return el.value && isSensitive(el) ? '\u2022\u2022\u2022\u2022' : clean(el.value);\n }\n if (el.localName === 'select') {\n const chosen = clean(Array.from(el.selectedOptions || [], (o) => o.label).join(', '));\n return chosen && isSensitive(el) ? '\u2022\u2022\u2022\u2022' : chosen;\n }\n const outsideControls = () => {\n const parts = [];\n const walker = el.ownerDocument.createTreeWalker(el, NodeFilter.SHOW_TEXT);\n for (let n = walker.nextNode(); n && parts.length < 400; n = walker.nextNode()) {\n const holder = n.parentElement;\n if (!holder || holder.closest('select, textarea, script, style, template, noscript')) continue;\n if (holder.checkVisibility && !holder.checkVisibility({ visibilityProperty: true })) continue;\n parts.push(n.data);\n }\n return parts.join(' ');\n };\n const holdsControls = Boolean(el.querySelector && el.querySelector('select, textarea'));\n const raw = holdsControls ? outsideControls() : typeof el.innerText === 'string' ? el.innerText : el.textContent;\n const text = clean(raw);\n const view = el.ownerDocument.defaultView;\n const security = view ? view.getComputedStyle(el).getPropertyValue('-webkit-text-security') : '';\n return text && security && security !== 'none' ? '\u2022\u2022\u2022\u2022' : text;\n};\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 s = tree.style(el);\n const formControl = /^(input|textarea|select|button)$/.test(el.localName);\n const content = textOf(el);\n const parent = tree.layoutParent(el);\n const typedMap = el.computedStyleMap ? el.computedStyleMap() : null;\n const typed = (name) => { try { return typedMap ? String(typedMap.get(name)) : ''; } catch (e) { return ''; } };\n const result = {\n tag: el.localName,\n id: el.id || '',\n classes: el.classList ? Array.from(el.classList) : [],\n context: ((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})(el),\n content: content,\n textual: formControl || (content !== '' && !tree.container(el)),\n formControl: formControl,\n replaced: el instanceof SVGElement || /^(img|video|canvas|iframe|embed|object|input|textarea|select|button|meter|progress)$/.test(el.localName),\n svg: el.namespaceURI === 'http://www.w3.org/2000/svg',\n ownText: Array.from(el.childNodes).some((n) => n.nodeType === 3 && n.data.trim() !== ''),\n typed: { width: typed('width'), height: typed('height') },\n parent: parent ? describe(parent) : undefined,\n animating: el.getAnimations ? [...new Set(el.getAnimations().filter((a) => a.playState === 'running').map((a) => a.transitionProperty || a.animationName || 'animation'))] : []\n };\n if (/^(input|textarea)$/.test(el.localName) && el.placeholder && !el.value) {\n result.placeholder = el.placeholder.replace(/\\s+/g, ' ').trim();\n const placeholderStyle = tree.style(el, '::placeholder');\n result.placeholderColor = placeholderStyle.color;\n result.placeholderFont = { style: placeholderStyle.fontStyle, weight: placeholderStyle.fontWeight };\n }\n if (el.clientWidth > 0 && (el.scrollWidth > el.clientWidth + 1 || el.scrollHeight > el.clientHeight + 1)) {\n result.scroll = { w: el.scrollWidth, h: el.scrollHeight, clientW: el.clientWidth, clientH: el.clientHeight };\n }\n if (props) {\n const known = (name) => name.startsWith('--') || CSS.supports(name, 'inherit');\n const valueOf = (name) => {\n const value = s.getPropertyValue(name).trim();\n if (value !== '' || name.startsWith('--')) return value;\n const sides = ['top', 'right', 'bottom', 'left'].map((side) => name + '-' + side).filter(known);\n return sides.map((side) => side.slice(name.length + 1) + ' ' + s.getPropertyValue(side).trim()).join(' / ');\n };\n result.props = Object.fromEntries(props.filter(known).map((name) => [name, valueOf(name)]));\n result.unknownProps = props.filter((name) => !known(name));\n }\n return Object.assign(result,\n ((el, tree) => {\n const parent = tree.layoutParent(el);\n if (!parent || tree.style(el).position === 'fixed' || !tree.rendered(el)) return {};\n const r = el.getBoundingClientRect();\n const p = parent.getBoundingClientRect();\n const ps = tree.style(parent);\n const edge = (side) => parseFloat(ps['border-' + side + '-width']) + parseFloat(ps['padding-' + side]);\n const inParent = {\n left: r.left - (p.left + edge('left')),\n top: r.top - (p.top + edge('top')),\n right: (p.right - edge('right')) - r.right,\n bottom: (p.bottom - edge('bottom')) - r.bottom\n };\n const inFlow = (n) => n !== el && tree.rendered(n) && !/^(absolute|fixed)$/.test(tree.style(n).position);\n const siblings = tree.children(parent);\n const at = siblings.indexOf(el);\n const before = siblings.slice(0, Math.max(at, 0)).reverse().find(inFlow);\n const after = at < 0 ? undefined : siblings.slice(at + 1).find(inFlow);\n const gaps = {};\n for (const sibling of [before, after]) {\n if (!sibling) continue;\n const s = sibling.getBoundingClientRect();\n if (s.bottom <= r.top + 0.5) gaps.top = r.top - s.bottom;\n else if (s.top >= r.bottom - 0.5) gaps.bottom = s.top - r.bottom;\n else if (s.right <= r.left + 0.5) gaps.left = r.left - s.right;\n else if (s.left >= r.right - 0.5) gaps.right = s.left - r.right;\n }\n return { inParent: inParent, siblings: gaps };\n})(el, tree),\n ((el, tree, view) => {\n const backgrounds = [];\n let opacity = 1;\n for (let n = el; n && backgrounds.length < 60; n = tree.flatParent(n)) {\n const s = tree.style(n);\n backgrounds.push({ color: s.backgroundColor, image: s.backgroundImage !== 'none' });\n opacity *= Number(s.opacity) || 0;\n }\n const doc = el.ownerDocument;\n const meta = doc.querySelector('meta[name=\"color-scheme\"]');\n const rootScheme = tree.style(doc.documentElement).colorScheme;\n const scheme = rootScheme && rootScheme !== 'normal' ? rootScheme : (meta && meta.content) || '';\n const prefersDark = view.matchMedia('(prefers-color-scheme: dark)').matches;\n const canvasDark = /dark/.test(scheme) && (!/light/.test(scheme) || prefersDark);\n return { backgrounds: backgrounds, canvasDark: canvasDark, opacity: opacity };\n})(el, tree, view),\n ((el, tree, textOf, depth) => {\n let budget = 400;\n let skipped = 0;\n const labelOf = (n) => n.localName + (n.id ? '#' + n.id : n.classList && n.classList.length ? '.' + n.classList[0] : '');\n const walk = (kids, level, origin) => {\n const shown = kids.filter(tree.rendered);\n const nodes = [];\n for (const k of shown) {\n if (budget <= 0) { skipped++; continue; }\n budget--;\n nodes.push(nodeOf(k, level, origin));\n }\n return { nodes: nodes, hidden: kids.length - shown.length };\n };\n const nodeOf = (n, level, origin) => {\n const r = n.getBoundingClientRect();\n const node = { label: labelOf(n), x: r.left - origin.left, y: r.top - origin.top, w: r.width, h: r.height, display: tree.style(n).display };\n const kids = tree.children(n);\n if (!tree.container(n)) node.text = textOf(n).slice(0, 60);\n if (level >= depth) {\n node.childCount = kids.filter(tree.rendered).length;\n return node;\n }\n const sub = walk(kids, level + 1, r);\n node.children = sub.nodes;\n node.hidden = sub.hidden;\n return node;\n };\n if (depth <= 0) return { hiddenChildren: 0, treeSkipped: 0 };\n const top = walk(tree.children(el), 1, el.getBoundingClientRect());\n return { tree: top.nodes, hiddenChildren: top.hidden, treeSkipped: skipped };\n})(el, tree, textOf, depth));\n}";
196
+ export declare const INSPECT_PAGE_JS: string;
123
197
  /**
124
198
  * Page-side function run on the element (`this`) that returns another
125
199
  * element whose styles CDP reads: `"parent"`, the parent that lays it out
126
- * (`display: contents` skipped, through shadow roots and slots), or
127
- * `"textHolder"`, for an element whose text is in a descendant
128
- * (`<button><span>Buy</span></button>`), the first element holding text,
129
- * whose rendered font is the one shown. Null when there is none.
200
+ * (`display: contents` skipped, through shadow roots and slots),
201
+ * `"textHolder"`, the element whose styles draw most of its text
202
+ * ({@link TEXT_HOLDER_JS}; the element itself when that is its own text), or
203
+ * `"fontHolder"`, the parent of that text's nodes (for the rendered font: a
204
+ * slot's text nodes belong to the host's light DOM). Null when there is none.
205
+ */
206
+ export declare const RELATED_NODE_JS: string;
207
+ /** Where a custom property is set, as {@link VARIABLE_SETTERS_JS} finds it */
208
+ export interface VariableSetter {
209
+ /** Selector of the rule, or `@keyframes name` */
210
+ selector: string;
211
+ /** Value as written (`inherit`, `` for an empty one) */
212
+ value: string;
213
+ /** Set in a keyframe of this animation */
214
+ keyframes?: string;
215
+ /** The rule matches the element or an ancestor now (null: bdg cannot test its selector) */
216
+ matches: boolean | null;
217
+ /** The `@media` or `@supports` condition it is under that does not apply now */
218
+ condition?: string;
219
+ }
220
+ /**
221
+ * Page-side function run on the element (`this`): for each custom property
222
+ * name, a rule in the page's stylesheets (same-origin, `@import`ed,
223
+ * constructed and the element's shadow root's) that sets it, keyframes
224
+ * included: the first one that matches the element or an ancestor now
225
+ * (across shadow roots, so `:root` matches inside a component), else the
226
+ * first that would match without its state (`.btn:hover` for this `.btn`),
227
+ * else the first one, with the `@media`/`@supports` condition it is under
228
+ * when that does not apply. At most 20000 rules are read; cross-origin sheets are
229
+ * skipped.
130
230
  */
131
- export declare const RELATED_NODE_JS = "function (which) {\n const tree = ((view) => {\n const style = (n, pseudo) => view.getComputedStyle(n, pseudo);\n const skipped = /^(script|style|template|link|meta|noscript|title|head|base)$/;\n const flatParent = (n) => n.assignedSlot || n.parentElement || (n.parentNode && n.parentNode.host) || null;\n const layoutParent = (n) => {\n let p = flatParent(n);\n while (p && style(p).display === 'contents') p = flatParent(p);\n return p;\n };\n const children = (n) => {\n const out = [];\n const add = (c) => {\n if (skipped.test(c.localName)) return;\n if (c.localName === 'slot') {\n const assigned = c.assignedElements({ flatten: true });\n (assigned.length ? assigned : Array.from(c.children)).forEach(add);\n } else if (style(c).display === 'contents') {\n Array.from((c.shadowRoot || c).children).forEach(add);\n } else {\n out.push(c);\n }\n };\n Array.from((n.shadowRoot || n).children).forEach(add);\n return out;\n };\n const rendered = (n) => n.getClientRects().length > 0 &&\n (!n.checkVisibility || n.checkVisibility({ visibilityProperty: true }));\n const container = (n) => children(n).some((c) => rendered(c) && !/^inline/.test(style(c).display));\n return { style, flatParent, layoutParent, children, rendered, container };\n})(this.ownerDocument.defaultView);\n if (which === 'parent') return tree.layoutParent(this);\n const walker = this.ownerDocument.createTreeWalker(this, NodeFilter.SHOW_TEXT);\n while (walker.nextNode()) {\n if (walker.currentNode.data.trim() !== '') return walker.currentNode.parentElement;\n }\n return null;\n}";
231
+ export declare const VARIABLE_SETTERS_JS = "function (names) {\n const el = this;\n const view = el.ownerDocument.defaultView;\n const matching = {};\n const related = {};\n const other = {};\n let budget = 20000;\n const closestAcross = (selector) => {\n for (let n = el; n; n = n.getRootNode().host || null) {\n if (n.closest(selector)) return true;\n }\n return false;\n };\n const matches = (selector) => {\n try { return closestAcross(selector); } catch (e) { return null; }\n };\n const stateless = (selector) => selector.replace(/:(focus-visible|focus-within|focus|hover|active|visited|checked|target|open)(?![\\w-])/g, '');\n const applies = (rule) => {\n if (rule.media && rule.media.mediaText && !view.matchMedia(rule.media.mediaText).matches) return '@media ' + rule.media.mediaText;\n if (typeof CSSSupportsRule !== 'undefined' && rule instanceof CSSSupportsRule && !CSS.supports(rule.conditionText)) return '@supports ' + rule.conditionText;\n return null;\n };\n const record = (name, rule, keyframes, condition) => {\n const selector = keyframes ? '@keyframes ' + keyframes : rule.selectorText || '';\n const match = keyframes || condition ? false : matches(selector);\n const setter = Object.assign(\n { selector: selector, value: rule.style.getPropertyValue(name).trim(), matches: match },\n keyframes ? { keyframes: keyframes } : {},\n condition ? { condition: condition } : {}\n );\n if (match && !matching[name]) matching[name] = setter;\n else if (!match && !keyframes && !related[name] && matches(stateless(selector))) related[name] = setter;\n else if (!match && !other[name]) other[name] = setter;\n };\n const visit = (rules, keyframes, condition) => {\n for (const rule of Array.from(rules)) {\n if (budget-- <= 0 || names.every((name) => matching[name])) return;\n if (typeof CSSImportRule !== 'undefined' && rule instanceof CSSImportRule) {\n try { if (rule.styleSheet) visit(rule.styleSheet.cssRules, keyframes, condition); } catch (e) { continue; }\n continue;\n }\n if (typeof CSSKeyframesRule !== 'undefined' && rule instanceof CSSKeyframesRule) {\n visit(rule.cssRules, rule.name, condition);\n continue;\n }\n if (rule.style) {\n for (const name of names) {\n if (!matching[name] && Array.from(rule.style).includes(name)) record(name, rule, keyframes, condition);\n }\n }\n if (rule.cssRules) visit(rule.cssRules, keyframes, condition || applies(rule));\n }\n };\n const sheets = [];\n for (const scope of new Set([el.getRootNode(), el.ownerDocument])) {\n sheets.push(...Array.from(scope.styleSheets || []), ...Array.from(scope.adoptedStyleSheets || []));\n }\n for (const sheet of sheets) {\n try { visit(sheet.cssRules, null, null); } catch (e) { continue; }\n }\n return Object.assign({}, other, related, matching);\n}";
132
232
  //# sourceMappingURL=inspectScripts.d.ts.map