browser-debugger-cli 0.11.0 → 0.12.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 (98) hide show
  1. package/README.md +142 -79
  2. package/dist/commands/css.d.ts +13 -0
  3. package/dist/commands/css.js +53 -0
  4. package/dist/commands/dom/audit.d.ts +14 -0
  5. package/dist/commands/dom/audit.js +87 -0
  6. package/dist/commands/dom/formInteraction.js +36 -6
  7. package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
  8. package/dist/commands/dom/helpers/keyAttributes.js +6 -4
  9. package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
  10. package/dist/commands/dom/helpers/screenshot.js +158 -38
  11. package/dist/commands/dom/index.js +4 -1
  12. package/dist/commands/dom/screenshot.js +10 -6
  13. package/dist/commands/dom/wait.js +5 -3
  14. package/dist/commands/helpJson.js +1 -1
  15. package/dist/commands/optionBehaviors.js +21 -6
  16. package/dist/commands/page.js +7 -4
  17. package/dist/commands/peek.d.ts +7 -0
  18. package/dist/commands/peek.js +65 -23
  19. package/dist/commands/shared/optionTypes.d.ts +5 -1
  20. package/dist/commands/start.d.ts +13 -0
  21. package/dist/commands/start.js +19 -2
  22. package/dist/commands/tail.d.ts +7 -1
  23. package/dist/commands/tail.js +13 -62
  24. package/dist/commands.js +2 -0
  25. package/dist/daemon/session/commandRegistry.js +7 -1
  26. package/dist/daemon/session/plugins.js +4 -52
  27. package/dist/daemon.js +7986 -6848
  28. package/dist/errors/messages.d.ts +34 -4
  29. package/dist/errors/messages.js +68 -5
  30. package/dist/index.js +610 -186
  31. package/dist/ipc/client.d.ts +4 -0
  32. package/dist/ipc/client.js +8 -0
  33. package/dist/ipc/protocol/auditTypes.d.ts +129 -0
  34. package/dist/ipc/protocol/auditTypes.js +6 -0
  35. package/dist/ipc/protocol/commands.d.ts +23 -0
  36. package/dist/ipc/protocol/commands.js +2 -0
  37. package/dist/ipc/protocol/domTypes.d.ts +4 -0
  38. package/dist/ipc/protocol/inspectTypes.d.ts +71 -8
  39. package/dist/runtime/css/search.d.ts +39 -0
  40. package/dist/runtime/css/search.js +122 -0
  41. package/dist/runtime/dom/actionEffects.d.ts +4 -1
  42. package/dist/runtime/dom/actionEffects.js +8 -4
  43. package/dist/runtime/dom/audit.d.ts +19 -0
  44. package/dist/runtime/dom/audit.js +36 -0
  45. package/dist/runtime/dom/auditModel.d.ts +45 -0
  46. package/dist/runtime/dom/auditModel.js +215 -0
  47. package/dist/runtime/dom/auditScripts.d.ts +107 -0
  48. package/dist/runtime/dom/auditScripts.js +112 -0
  49. package/dist/runtime/dom/elementGeometry.d.ts +8 -2
  50. package/dist/runtime/dom/elementGeometry.js +24 -8
  51. package/dist/runtime/dom/elementInfo.d.ts +3 -2
  52. package/dist/runtime/dom/elementInfo.js +8 -2
  53. package/dist/runtime/dom/formFillHelpers/fill.js +2 -2
  54. package/dist/runtime/dom/inspect.d.ts +7 -0
  55. package/dist/runtime/dom/inspect.js +88 -23
  56. package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
  57. package/dist/runtime/dom/inspectAllStyles.js +89 -7
  58. package/dist/runtime/dom/inspectCascade.d.ts +19 -2
  59. package/dist/runtime/dom/inspectCascade.js +214 -44
  60. package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
  61. package/dist/runtime/dom/inspectCascadeModel.js +108 -34
  62. package/dist/runtime/dom/inspectHints.d.ts +26 -3
  63. package/dist/runtime/dom/inspectHints.js +125 -9
  64. package/dist/runtime/dom/inspectModel.d.ts +3 -0
  65. package/dist/runtime/dom/inspectModel.js +30 -7
  66. package/dist/runtime/dom/inspectPaintModel.d.ts +48 -22
  67. package/dist/runtime/dom/inspectPaintModel.js +180 -68
  68. package/dist/runtime/dom/inspectRules.d.ts +19 -0
  69. package/dist/runtime/dom/inspectRules.js +21 -5
  70. package/dist/runtime/dom/inspectScripts.d.ts +85 -12
  71. package/dist/runtime/dom/inspectScripts.js +314 -28
  72. package/dist/runtime/dom/inspectTree.js +10 -2
  73. package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
  74. package/dist/runtime/dom/inspectWhyModel.js +52 -10
  75. package/dist/runtime/dom/layout.js +31 -9
  76. package/dist/runtime/dom/reactEventHelpers.d.ts +7 -0
  77. package/dist/runtime/dom/reactEventHelpers.js +27 -9
  78. package/dist/runtime/page/emulation.d.ts +13 -4
  79. package/dist/runtime/page/emulation.js +69 -4
  80. package/dist/runtime/page/userAgent.d.ts +17 -0
  81. package/dist/runtime/page/userAgent.js +57 -0
  82. package/dist/types.d.ts +4 -0
  83. package/dist/ui/formatters/audit.d.ts +19 -0
  84. package/dist/ui/formatters/audit.js +106 -0
  85. package/dist/ui/formatters/dom.d.ts +1 -1
  86. package/dist/ui/formatters/dom.js +6 -3
  87. package/dist/ui/formatters/inspect.js +42 -15
  88. package/dist/ui/formatters/status.js +1 -1
  89. package/dist/ui/messages/commands.d.ts +44 -7
  90. package/dist/ui/messages/commands.js +83 -11
  91. package/dist/ui/messages/preview.d.ts +6 -0
  92. package/dist/ui/messages/preview.js +9 -1
  93. package/dist/utils/cssValues.js +36 -4
  94. package/dist/utils/decisionTrees.js +0 -5
  95. package/dist/utils/suggestions.d.ts +4 -2
  96. package/dist/utils/suggestions.js +7 -5
  97. package/dist/utils/taskMappings.js +1 -1
  98. package/package.json +3 -2
@@ -8,7 +8,7 @@
8
8
  * canvas).
9
9
  */
10
10
  import { composite, contrastLevel, contrastRatio, hexColor, parseColor, toHex, } from '../../utils/color.js';
11
- import { cssLength, firstFontFamily, normalizeCssValue, parseShadows, pxNumber, readableTransform, shadowText, shortUrls, splitTopLevel, } from '../../utils/cssValues.js';
11
+ import { cssLength, firstFontFamily, normalizeCssValue, parseShadows, pxNumber, readableTransform, shadowText, shortUrls, sidesShorthand, splitTopLevel, } from '../../utils/cssValues.js';
12
12
  /** Background images and gradients are shown at most this long */
13
13
  const IMAGE_TEXT_LENGTH = 140;
14
14
  /** Page canvas colors (light and dark color-scheme) */
@@ -16,62 +16,125 @@ const CANVAS = {
16
16
  light: { r: 1, g: 1, b: 1, a: 1 },
17
17
  dark: { r: 0x12 / 255, g: 0x12 / 255, b: 0x12 / 255, a: 1 },
18
18
  };
19
+ /** CSS generic font families: the browser picks a font for them */
20
+ const GENERIC_FAMILIES = new Set([
21
+ 'serif',
22
+ 'sans-serif',
23
+ 'monospace',
24
+ 'cursive',
25
+ 'fantasy',
26
+ 'system-ui',
27
+ 'ui-serif',
28
+ 'ui-sans-serif',
29
+ 'ui-monospace',
30
+ 'ui-rounded',
31
+ 'math',
32
+ 'emoji',
33
+ 'fangsong',
34
+ '-apple-system',
35
+ 'blinkmacsystemfont',
36
+ ]);
19
37
  /**
20
- * The font the text was rendered with, when it is not a face of the first
21
- * family (a fallback: `DM Sans 9pt` is a face of `DM Sans`, `Liberation Sans`
22
- * is not one of `Arial`), and whether it is a web font. Names
23
- * that are not readable (sites that scramble a web font's internal name)
24
- * are left out.
38
+ * The font the text was rendered with and whether it is a web font. For a
39
+ * generic first family, the font it resolved to (`resolved`). Otherwise
40
+ * `rendered` only when it is a fallback: not a face of the first family
41
+ * (`DM Sans 9pt` is a face of `DM Sans`, `Liberation Sans` is not one of
42
+ * `Arial`), and the first family is not a web font the page loaded (whose
43
+ * file may give any internal name: `Copyright Klim Type Foundry`, or the
44
+ * local font a `src: local()` points at). Names that are not readable
45
+ * (sites that scramble a web font's internal name) are left out.
25
46
  *
26
47
  * @param family - First family of `font-family`
27
48
  * @param fonts - Platform fonts of the text
28
- * @returns `rendered` and `webfont` fields
49
+ * @param familyLoaded - The first family is a loaded web font
50
+ * @returns `rendered`, `resolved` and `webfont` fields
29
51
  */
30
- export function renderedFont(family, fonts) {
52
+ export function renderedFont(family, fonts, familyLoaded = false) {
31
53
  const primary = [...fonts].sort((a, b) => b.glyphCount - a.glyphCount)[0];
32
54
  if (!primary)
33
55
  return {};
56
+ const webfont = primary.isCustomFont ? { webfont: true } : {};
34
57
  const readable = /^[\p{L}\p{N}.][\p{L}\p{N} ._'-]+$/u.test(primary.familyName);
35
- const differs = readable && !primary.familyName.toLowerCase().startsWith(family.toLowerCase());
58
+ if (!readable || familyLoaded)
59
+ return webfont;
60
+ if (GENERIC_FAMILIES.has(family.toLowerCase())) {
61
+ return { resolved: primary.familyName, ...webfont };
62
+ }
63
+ const differs = !primary.familyName.toLowerCase().startsWith(family.toLowerCase());
64
+ return { ...(differs && { rendered: primary.familyName }), ...webfont };
65
+ }
66
+ /** Fully transparent */
67
+ const CLEAR = { r: 0, g: 0, b: 0, a: 0 };
68
+ /**
69
+ * Paint the text color and the background behind it the way the browser
70
+ * composites them: from the element up to the root, each element's content
71
+ * over its own background, the result faded by its opacity (a translucent
72
+ * ancestor fades its background along with the text), then over the page
73
+ * canvas.
74
+ *
75
+ * @param text - Text color (undefined: the background alone)
76
+ * @param backgrounds - Backgrounds with their opacity, the element's own first
77
+ * @param canvasDark - The page canvas is dark
78
+ * @returns The text pixel, the background pixel and whether a background
79
+ * image or gradient was in the way
80
+ */
81
+ function paintOver(text, backgrounds, canvasDark) {
82
+ let withText = text ?? CLEAR;
83
+ let without = CLEAR;
84
+ let overImage = false;
85
+ for (const layer of backgrounds) {
86
+ if (layer.image && without.a < 0.999)
87
+ overImage = true;
88
+ const color = parseColor(layer.color);
89
+ if (color && color.a > 0) {
90
+ withText = composite(withText, color);
91
+ without = composite(without, color);
92
+ }
93
+ const opacity = layer.opacity ?? 1;
94
+ withText = { ...withText, a: withText.a * opacity };
95
+ without = { ...without, a: without.a * opacity };
96
+ }
97
+ const canvas = CANVAS[canvasDark ? 'dark' : 'light'];
36
98
  return {
37
- ...(differs && { rendered: primary.familyName }),
38
- ...(primary.isCustomFont && { webfont: true }),
99
+ text: composite(withText, canvas),
100
+ background: composite(without, canvas),
101
+ overImage,
39
102
  };
40
103
  }
104
+ /**
105
+ * Whether the element's own background lets what is behind it through (the
106
+ * background behind its text comes from an ancestor or the canvas).
107
+ *
108
+ * @param backgrounds - Backgrounds, the element's own first
109
+ * @returns True when its own background is not opaque
110
+ */
111
+ function ownBackgroundTranslucent(backgrounds) {
112
+ const own = parseColor(backgrounds[0]?.color ?? '');
113
+ return !own || own.a < 0.999;
114
+ }
41
115
  /**
42
116
  * The background behind the element's text: its own and its ancestors'
43
- * backgrounds composited, from the nearest opaque one (or the page canvas).
117
+ * backgrounds composited with their opacity over the page canvas.
44
118
  *
45
119
  * @param backgrounds - Backgrounds, the element's own first
46
120
  * @param canvasDark - The page canvas is dark
47
121
  * @returns Opaque background, whether it came from an ancestor and whether an image was in the way
48
122
  */
49
123
  export function effectiveBackground(backgrounds, canvasDark) {
50
- const layers = [];
51
- let overImage = false;
52
- for (const background of backgrounds) {
53
- if (background.image)
54
- overImage = true;
55
- const color = parseColor(background.color);
56
- if (!color || color.a === 0)
57
- continue;
58
- layers.push(color);
59
- if (color.a >= 0.999)
60
- break;
61
- }
62
- const base = layers[layers.length - 1];
63
- let color = base && base.a >= 0.999 ? base : CANVAS[canvasDark ? 'dark' : 'light'];
64
- const translucent = base && base.a >= 0.999 ? layers.slice(0, -1) : layers;
65
- for (const layer of [...translucent].reverse())
66
- color = composite(layer, color);
67
- const own = parseColor(backgrounds[0]?.color ?? '');
68
- return { color, inherited: !own || own.a < 0.999, overImage };
124
+ const painted = paintOver(undefined, backgrounds, canvasDark);
125
+ return {
126
+ color: painted.background,
127
+ inherited: ownBackgroundTranslucent(backgrounds),
128
+ overImage: painted.overImage,
129
+ };
69
130
  }
70
131
  /**
71
- * Contrast of the text color with the background behind it.
132
+ * Contrast of the text color with the background behind it, both painted
133
+ * as the browser composites them ({@link paintOver}), with what makes the
134
+ * number approximate (blend modes, filters, content behind or on top).
72
135
  *
73
136
  * @param style - Computed styles (color, font size and weight)
74
- * @param raw - Backgrounds and the page canvas
137
+ * @param raw - Backgrounds, the page canvas, opacity and paint risks
75
138
  * @returns Ratio (rounded down to 2 decimals), level and background
76
139
  */
77
140
  export function textContrast(style, raw) {
@@ -79,18 +142,19 @@ export function textContrast(style, raw) {
79
142
  if (!color)
80
143
  return undefined;
81
144
  const opacity = raw.opacity ?? 1;
82
- const text = opacity < 1 ? { ...color, a: color.a * opacity } : color;
83
- const background = effectiveBackground(raw.backgrounds, raw.canvasDark);
84
- const ratio = Math.floor(contrastRatio(text, background.color) * 100) / 100;
145
+ const painted = paintOver(color, raw.backgrounds, raw.canvasDark);
146
+ const ratio = Math.floor(contrastRatio(painted.text, painted.background) * 100) / 100;
85
147
  const size = pxNumber(style['font-size']) ?? 16;
86
148
  const weight = Number(style['font-weight'] ?? 400);
149
+ const approximate = raw.paintRisks ?? [];
87
150
  return {
88
151
  ratio,
89
152
  level: contrastLevel(ratio, size, weight),
90
- background: toHex(background.color),
91
- ...(background.inherited && { inherited: true }),
92
- ...(background.overImage && { overImage: true }),
153
+ background: toHex(painted.background),
154
+ ...(ownBackgroundTranslucent(raw.backgrounds) && { inherited: true }),
155
+ ...(painted.overImage && { overImage: true }),
93
156
  ...(opacity < 1 && { opacity: Math.round(opacity * 100) / 100 }),
157
+ ...(approximate.length > 0 && { approximate }),
94
158
  };
95
159
  }
96
160
  /**
@@ -188,40 +252,56 @@ function fontFields(style) {
188
252
  };
189
253
  }
190
254
  /**
191
- * The text group. Elements with text (or form controls) get the full group:
192
- * font with the rendered font, size, color, alignment, contrast (not for
193
- * text no one can see: `opacity: 0` on it or an ancestor,
194
- * `visibility: hidden`) and the non-default extras. Containers get only what differs from
195
- * their parent, with the font their text was rendered in when the family
196
- * differs.
255
+ * The text group. Elements with text (or text fields) get the full group,
256
+ * read from whatever draws the text (the element, or the descendant with
257
+ * most of it, named in `holder`): font with the rendered font, size, color,
258
+ * alignment, contrast (not for text no one can see: not rendered,
259
+ * `opacity: 0` on it or an ancestor, `visibility: hidden`) and the
260
+ * non-default extras. Containers get only what differs from their parent,
261
+ * with the font their text was rendered in when that text has the
262
+ * container's family. Nothing for an element without text (an icon button,
263
+ * a checkbox).
197
264
  *
198
- * @param style - Computed styles
199
- * @param parentStyle - Computed styles of the layout parent
265
+ * @param styles - Computed styles of the element, its parent and its text holder
200
266
  * @param raw - Page-side measurements
201
267
  * @param fonts - Platform fonts of the text
202
268
  * @returns Text group, or undefined when there is nothing to say
203
269
  */
204
- export function buildText(style, parentStyle, raw, fonts) {
205
- const fields = fontFields(style);
270
+ export function buildText(styles, raw, fonts) {
271
+ const { style, parentStyle, holderStyle } = styles;
206
272
  if (raw.textual) {
207
- const seen = (raw.opacity ?? 1) > 0 && style['visibility'] !== 'hidden';
208
- const contrast = seen ? textContrast(style, raw) : undefined;
273
+ const textStyle = raw.textHolder && holderStyle ? holderStyle : style;
274
+ const fields = fontFields(textStyle);
275
+ const gradientFill = (textStyle['background-clip'] ?? '').includes('text') &&
276
+ (parseColor(textStyle['-webkit-text-fill-color'] ?? '')?.a ?? 1) === 0;
277
+ const seen = raw.rendered !== false &&
278
+ (raw.opacity ?? 1) > 0 &&
279
+ textStyle['visibility'] !== 'hidden' &&
280
+ !gradientFill;
281
+ const contrast = seen ? textContrast(textStyle, raw) : undefined;
209
282
  return {
283
+ ...(textStyle !== style && raw.textHolder && { holder: raw.textHolder }),
210
284
  ...fields,
211
- ...renderedFont(fields.family ?? '', fonts),
285
+ ...renderedFont(fields.family ?? '', fonts, raw.familyLoaded),
212
286
  ...(contrast && { contrast }),
213
- ...textExtras(style),
214
- align: alignOf(style),
287
+ ...textExtras(textStyle),
288
+ align: alignOf(textStyle),
289
+ ...(raw.truncated && { truncated: true }),
290
+ ...(gradientFill && { gradientFill: true }),
215
291
  };
216
292
  }
217
- if (!parentStyle)
293
+ if (!parentStyle || raw.hasText === false)
218
294
  return undefined;
295
+ const fields = fontFields(style);
219
296
  const parentFields = { ...fontFields(parentStyle), ...textExtras(parentStyle) };
220
297
  const own = { ...fields, ...textExtras(style) };
221
298
  const differing = Object.fromEntries(Object.entries(own).filter(([key, value]) => parentFields[key] !== value));
222
299
  if (Object.keys(differing).length === 0)
223
300
  return undefined;
224
- return differing.family ? { ...differing, ...renderedFont(differing.family, fonts) } : differing;
301
+ const sameFamily = !holderStyle || holderStyle['font-family'] === style['font-family'];
302
+ return differing.family && sameFamily
303
+ ? { ...differing, ...renderedFont(differing.family, fonts, raw.familyLoaded) }
304
+ : differing;
225
305
  }
226
306
  /**
227
307
  * Cut a long value.
@@ -233,7 +313,8 @@ function cut(text) {
233
313
  return text.length > IMAGE_TEXT_LENGTH ? `${text.slice(0, IMAGE_TEXT_LENGTH)}…` : text;
234
314
  }
235
315
  /**
236
- * Background layers: images and gradients (top first), then the color.
316
+ * Background layers: images and gradients (top first), each with its own
317
+ * size and position when they are not the defaults, then the color.
237
318
  *
238
319
  * @param style - Computed styles
239
320
  * @returns Fills
@@ -241,25 +322,46 @@ function cut(text) {
241
322
  export function buildFills(style) {
242
323
  const fills = [];
243
324
  const image = style['background-image'];
244
- const size = style['background-size'];
245
325
  if (image && image !== 'none') {
246
- for (const layer of splitTopLevel(image)) {
326
+ const sizes = splitTopLevel(style['background-size'] ?? 'auto');
327
+ const xs = splitTopLevel(style['background-position-x'] ?? '0%');
328
+ const ys = splitTopLevel(style['background-position-y'] ?? '0%');
329
+ const positions = xs.map((x, i) => `${x} ${ys[i % ys.length] ?? '0%'}`);
330
+ splitTopLevel(image).forEach((layer, i) => {
331
+ const size = sizes[i % sizes.length] ?? 'auto';
332
+ const position = positions[i % positions.length] ?? '0% 0%';
247
333
  const value = cut(normalizeCssValue(shortUrls(layer)));
248
- if (layer.includes('gradient('))
249
- fills.push({ type: 'gradient', value });
250
- else
251
- fills.push({
252
- type: 'image',
253
- value,
254
- ...(size && size !== 'auto' && { size: normalizeCssValue(size) }),
255
- });
256
- }
334
+ fills.push({
335
+ type: layer.includes('gradient(') ? 'gradient' : 'image',
336
+ value,
337
+ ...(size !== 'auto' && size !== 'auto auto' && { size: normalizeCssValue(size) }),
338
+ ...(position !== '0% 0%' && { position: normalizeCssValue(position) }),
339
+ });
340
+ });
257
341
  }
258
342
  const color = hexColor(style['background-color'] ?? 'transparent');
259
343
  if (color !== 'transparent')
260
344
  fills.push({ type: 'solid', color });
261
345
  return fills;
262
346
  }
347
+ /**
348
+ * How an SVG element is painted: its `fill` and `stroke` (with the width).
349
+ *
350
+ * @param style - Computed styles
351
+ * @param raw - Whether it is an SVG element
352
+ * @returns Paint, or undefined for an HTML element
353
+ */
354
+ export function buildSvgPaint(style, raw) {
355
+ if (!raw.svg)
356
+ return undefined;
357
+ const paint = (value) => normalizeCssValue(shortUrls(hexColor(value ?? 'none')));
358
+ const stroke = paint(style['stroke']);
359
+ return {
360
+ fill: paint(style['fill']),
361
+ stroke,
362
+ ...(stroke !== 'none' && { strokeWidth: cssLength(style['stroke-width'] ?? '1px') }),
363
+ };
364
+ }
263
365
  /**
264
366
  * Border sides that show (a style other than none/hidden and a width): one
265
367
  * `all` stroke when the four are equal.
@@ -421,6 +523,7 @@ export function buildGeneratedPseudo(pseudo, hostColor) {
421
523
  content: shortUrls(content),
422
524
  ...(display && display !== 'inline' && { display }),
423
525
  ...(position && position !== 'static' && { position }),
526
+ ...(position && position !== 'static' && { inset: insetOf(style) }),
424
527
  ...(pseudo.size && { size: pseudo.size }),
425
528
  ...(style['color'] && style['color'] !== hostColor && { color: hexColor(style['color']) }),
426
529
  ...(fills.length > 0 && { fills }),
@@ -430,6 +533,15 @@ export function buildGeneratedPseudo(pseudo, hostColor) {
430
533
  ...(opacity !== 1 && { opacity }),
431
534
  };
432
535
  }
536
+ /**
537
+ * Offsets of a positioned box, as one 1-4 value shorthand.
538
+ *
539
+ * @param style - Computed styles
540
+ * @returns e.g. `auto 50% -9 0`
541
+ */
542
+ function insetOf(style) {
543
+ return sidesShorthand(['top', 'right', 'bottom', 'left'].map((side) => normalizeCssValue(style[side] ?? 'auto')));
544
+ }
433
545
  /**
434
546
  * The pseudo group: generated `::before`/`::after` and the placeholder color.
435
547
  *
@@ -14,6 +14,14 @@ import type { Declaration } from './inspectCascade.js';
14
14
  * @param cdp - CDP connection
15
15
  */
16
16
  export declare function trackStyleSheets(cdp: CDPConnection): void;
17
+ /**
18
+ * The stylesheet headers seen on a connection (after {@link trackStyleSheets}
19
+ * and `CSS.enable`).
20
+ *
21
+ * @param cdp - CDP connection
22
+ * @returns Headers
23
+ */
24
+ export declare function styleSheetHeaders(cdp: CDPConnection): Iterable<Protocol.CSS.CSSStyleSheetHeader>;
17
25
  /**
18
26
  * The rules that match an element, with its inline style and what its
19
27
  * ancestors pass down, or why they are missing.
@@ -34,4 +42,15 @@ export declare function matchedStyles(cdp: CDPConnection, nodeId: number, budget
34
42
  * @returns e.g. `.btn-primary (bootstrap.min.css:5:52628)`, `style attribute`, `browser default`
35
43
  */
36
44
  export declare function sourceLabel(declaration: Declaration, cdp: CDPConnection): string;
45
+ /**
46
+ * A stylesheet position as `file:line[:column]`.
47
+ *
48
+ * @param header - Stylesheet header (unknown: just the line)
49
+ * @param line - 0-based line within the stylesheet
50
+ * @param column - 0-based column
51
+ * @returns e.g. `app.css:12`, `bootstrap.min.css:5:52628`, `<style> in index.html:40`,
52
+ * `constructed stylesheet`, `<style> added by a script` (a sheet a script created and
53
+ * filled with `insertRule`: its lines are not in any file)
54
+ */
55
+ export declare function stylesheetPositionLabel(header: Protocol.CSS.CSSStyleSheetHeader | undefined, line: number | undefined, column: number | undefined): string;
37
56
  //# sourceMappingURL=inspectRules.d.ts.map
@@ -27,6 +27,16 @@ export function trackStyleSheets(cdp) {
27
27
  headers.delete(styleSheetId);
28
28
  });
29
29
  }
30
+ /**
31
+ * The stylesheet headers seen on a connection (after {@link trackStyleSheets}
32
+ * and `CSS.enable`).
33
+ *
34
+ * @param cdp - CDP connection
35
+ * @returns Headers
36
+ */
37
+ export function styleSheetHeaders(cdp) {
38
+ return headersByConnection.get(cdp)?.values() ?? [];
39
+ }
30
40
  /**
31
41
  * The rules that match an element, with its inline style and what its
32
42
  * ancestors pass down, or why they are missing.
@@ -77,7 +87,7 @@ export function sourceLabel(declaration, cdp) {
77
87
  const header = source.styleSheetId
78
88
  ? headersByConnection.get(cdp)?.get(source.styleSheetId)
79
89
  : undefined;
80
- return `${source.selector ?? ''} (${fileLabel(header, source.line, source.column)})`;
90
+ return `${source.selector ?? ''} (${stylesheetPositionLabel(header, source.line, source.column)})`;
81
91
  }
82
92
  /**
83
93
  * A stylesheet position as `file:line[:column]`.
@@ -85,17 +95,23 @@ export function sourceLabel(declaration, cdp) {
85
95
  * @param header - Stylesheet header (unknown: just the line)
86
96
  * @param line - 0-based line within the stylesheet
87
97
  * @param column - 0-based column
88
- * @returns e.g. `app.css:12`, `bootstrap.min.css:5:52628`, `<style> in index.html:40`, `constructed stylesheet`
98
+ * @returns e.g. `app.css:12`, `bootstrap.min.css:5:52628`, `<style> in index.html:40`,
99
+ * `constructed stylesheet`, `<style> added by a script` (a sheet a script created and
100
+ * filled with `insertRule`: its lines are not in any file)
89
101
  */
90
- function fileLabel(header, line, column) {
102
+ export function stylesheetPositionLabel(header, line, column) {
91
103
  if (!header)
92
104
  return line === undefined ? 'stylesheet' : `stylesheet:${line + 1}`;
93
105
  if (header.isConstructed)
94
106
  return 'constructed stylesheet';
95
107
  const file = fileName(header.sourceURL) || 'page';
96
- const absoluteLine = (line ?? 0) + (header.isInline ? header.startLine : 0) + 1;
97
108
  const where = header.isInline ? `<style> in ${file}` : file;
109
+ if (header.isMutable && !header.sourceURL)
110
+ return `<style> added by a script`;
111
+ const absoluteLine = (line ?? 0) + (header.isInline ? header.startLine : 0) + 1;
112
+ const firstLine = header.isInline && (line ?? 0) === 0;
113
+ const absoluteColumn = (column ?? 0) + (firstLine ? header.startColumn : 0) + 1;
98
114
  const minified = header.endLine - header.startLine < 10 && (column ?? 0) > 200;
99
- return minified ? `${where}:${absoluteLine}:${(column ?? 0) + 1}` : `${where}:${absoluteLine}`;
115
+ return minified ? `${where}:${absoluteLine}:${absoluteColumn}` : `${where}:${absoluteLine}`;
100
116
  }
101
117
  //# sourceMappingURL=inspectRules.js.map