browser-debugger-cli 0.9.0 → 0.11.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 (139) hide show
  1. package/.claude/skills/bdg/SKILL.md +268 -0
  2. package/README.md +15 -1
  3. package/dist/commands/dom/a11y.js +2 -1
  4. package/dist/commands/dom/formInteraction.js +56 -25
  5. package/dist/commands/dom/helpers/keyAttributes.d.ts +20 -0
  6. package/dist/commands/dom/helpers/keyAttributes.js +54 -0
  7. package/dist/commands/dom/helpers/query.d.ts +1 -1
  8. package/dist/commands/dom/helpers/query.js +66 -19
  9. package/dist/commands/dom/helpers/runElementCommand.js +4 -3
  10. package/dist/commands/dom/helpers/screenshot.js +85 -12
  11. package/dist/commands/dom/index.d.ts +1 -0
  12. package/dist/commands/dom/index.js +8 -3
  13. package/dist/commands/dom/inspect.d.ts +15 -0
  14. package/dist/commands/dom/inspect.js +82 -0
  15. package/dist/commands/dom/layout.js +2 -2
  16. package/dist/commands/dom/listeners.js +2 -2
  17. package/dist/commands/dom/semanticUtils.d.ts +14 -1
  18. package/dist/commands/dom/semanticUtils.js +44 -3
  19. package/dist/commands/installSkill.d.ts +20 -0
  20. package/dist/commands/installSkill.js +87 -0
  21. package/dist/commands/network/list.js +13 -2
  22. package/dist/commands/optionBehaviors.js +48 -6
  23. package/dist/commands/page.d.ts +1 -1
  24. package/dist/commands/page.js +62 -3
  25. package/dist/commands/shared/commonOptions.d.ts +4 -0
  26. package/dist/commands/shared/commonOptions.js +9 -0
  27. package/dist/commands/shared/optionTypes.d.ts +21 -0
  28. package/dist/commands/shared/startHelpers.d.ts +66 -0
  29. package/dist/commands/shared/startHelpers.js +91 -10
  30. package/dist/commands/shared/validation.d.ts +11 -0
  31. package/dist/commands/shared/validation.js +16 -0
  32. package/dist/commands.js +3 -0
  33. package/dist/daemon/launcher.d.ts +8 -1
  34. package/dist/daemon/launcher.js +3 -1
  35. package/dist/daemon/session/Session.d.ts +7 -0
  36. package/dist/daemon/session/Session.js +23 -1
  37. package/dist/daemon/session/commandRegistry.d.ts +14 -1
  38. package/dist/daemon/session/commandRegistry.js +65 -9
  39. package/dist/daemon/session/interactions.d.ts +18 -5
  40. package/dist/daemon/session/interactions.js +22 -12
  41. package/dist/daemon.js +3565 -329
  42. package/dist/errors/messages.d.ts +85 -0
  43. package/dist/errors/messages.js +128 -1
  44. package/dist/index.js +2151 -960
  45. package/dist/ipc/client.d.ts +9 -0
  46. package/dist/ipc/client.js +13 -0
  47. package/dist/ipc/protocol/commands.d.ts +56 -1
  48. package/dist/ipc/protocol/commands.js +2 -0
  49. package/dist/ipc/protocol/domTypes.d.ts +35 -2
  50. package/dist/ipc/protocol/inspectTypes.d.ts +388 -0
  51. package/dist/ipc/protocol/inspectTypes.js +10 -0
  52. package/dist/runtime/dom/actionEffects.d.ts +94 -15
  53. package/dist/runtime/dom/actionEffects.js +173 -27
  54. package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -14
  55. package/dist/runtime/dom/actionEffectsScripts.js +224 -32
  56. package/dist/runtime/dom/elementInfo.d.ts +26 -0
  57. package/dist/runtime/dom/elementInfo.js +65 -0
  58. package/dist/runtime/dom/eventListeners.js +14 -4
  59. package/dist/runtime/dom/formFillHelpers/fill.d.ts +3 -4
  60. package/dist/runtime/dom/formFillHelpers/fill.js +77 -28
  61. package/dist/runtime/dom/frameSelection.d.ts +11 -0
  62. package/dist/runtime/dom/frameSelection.js +20 -1
  63. package/dist/runtime/dom/frames.d.ts +38 -5
  64. package/dist/runtime/dom/frames.js +136 -21
  65. package/dist/runtime/dom/inspect.d.ts +28 -0
  66. package/dist/runtime/dom/inspect.js +557 -0
  67. package/dist/runtime/dom/inspectAllStyles.d.ts +62 -0
  68. package/dist/runtime/dom/inspectAllStyles.js +385 -0
  69. package/dist/runtime/dom/inspectCascade.d.ts +94 -0
  70. package/dist/runtime/dom/inspectCascade.js +371 -0
  71. package/dist/runtime/dom/inspectCascadeModel.d.ts +39 -0
  72. package/dist/runtime/dom/inspectCascadeModel.js +232 -0
  73. package/dist/runtime/dom/inspectHints.d.ts +62 -0
  74. package/dist/runtime/dom/inspectHints.js +305 -0
  75. package/dist/runtime/dom/inspectLayoutModel.d.ts +87 -0
  76. package/dist/runtime/dom/inspectLayoutModel.js +346 -0
  77. package/dist/runtime/dom/inspectModel.d.ts +74 -0
  78. package/dist/runtime/dom/inspectModel.js +184 -0
  79. package/dist/runtime/dom/inspectPaintModel.d.ts +157 -0
  80. package/dist/runtime/dom/inspectPaintModel.js +461 -0
  81. package/dist/runtime/dom/inspectRules.d.ts +37 -0
  82. package/dist/runtime/dom/inspectRules.js +101 -0
  83. package/dist/runtime/dom/inspectScripts.d.ts +132 -0
  84. package/dist/runtime/dom/inspectScripts.js +263 -0
  85. package/dist/runtime/dom/inspectTree.d.ts +40 -0
  86. package/dist/runtime/dom/inspectTree.js +134 -0
  87. package/dist/runtime/dom/inspectVariables.d.ts +33 -0
  88. package/dist/runtime/dom/inspectVariables.js +94 -0
  89. package/dist/runtime/dom/inspectWhyModel.d.ts +20 -0
  90. package/dist/runtime/dom/inspectWhyModel.js +134 -0
  91. package/dist/runtime/dom/layout.d.ts +5 -1
  92. package/dist/runtime/dom/layout.js +10 -3
  93. package/dist/runtime/dom/listenerPageScripts.d.ts +11 -5
  94. package/dist/runtime/dom/listenerPageScripts.js +95 -9
  95. package/dist/runtime/dom/listenerSummary.d.ts +4 -0
  96. package/dist/runtime/dom/listenerSummary.js +26 -9
  97. package/dist/runtime/dom/reactEventHelpers.d.ts +5 -0
  98. package/dist/runtime/dom/reactEventHelpers.js +12 -4
  99. package/dist/runtime/page/emulation.d.ts +20 -0
  100. package/dist/runtime/page/emulation.js +37 -0
  101. package/dist/telemetry/a11y.d.ts +10 -0
  102. package/dist/telemetry/a11y.js +78 -1
  103. package/dist/telemetry/console.d.ts +1 -0
  104. package/dist/telemetry/console.js +100 -5
  105. package/dist/telemetry/network.js +3 -1
  106. package/dist/types.d.ts +40 -0
  107. package/dist/ui/formatters/details.d.ts +8 -0
  108. package/dist/ui/formatters/details.js +59 -3
  109. package/dist/ui/formatters/dom.d.ts +2 -1
  110. package/dist/ui/formatters/dom.js +25 -9
  111. package/dist/ui/formatters/inspect.d.ts +39 -0
  112. package/dist/ui/formatters/inspect.js +596 -0
  113. package/dist/ui/formatters/installSkill.d.ts +11 -0
  114. package/dist/ui/formatters/installSkill.js +31 -0
  115. package/dist/ui/formatters/keyAttributes.d.ts +19 -0
  116. package/dist/ui/formatters/keyAttributes.js +84 -0
  117. package/dist/ui/formatters/layout.js +2 -2
  118. package/dist/ui/formatters/networkHeaders.d.ts +13 -0
  119. package/dist/ui/formatters/networkHeaders.js +23 -3
  120. package/dist/ui/formatters/networkList.d.ts +29 -1
  121. package/dist/ui/formatters/networkList.js +86 -20
  122. package/dist/ui/formatters/status.js +1 -1
  123. package/dist/ui/formatting.d.ts +9 -0
  124. package/dist/ui/formatting.js +6 -3
  125. package/dist/ui/messages/commands.d.ts +123 -7
  126. package/dist/ui/messages/commands.js +181 -10
  127. package/dist/ui/messages/networkMessages.d.ts +14 -0
  128. package/dist/ui/messages/networkMessages.js +18 -0
  129. package/dist/ui/messages/session.d.ts +14 -0
  130. package/dist/ui/messages/session.js +20 -0
  131. package/dist/utils/async.d.ts +9 -0
  132. package/dist/utils/async.js +17 -0
  133. package/dist/utils/color.d.ts +84 -0
  134. package/dist/utils/color.js +376 -0
  135. package/dist/utils/cssValues.d.ts +109 -0
  136. package/dist/utils/cssValues.js +236 -0
  137. package/dist/utils/selectorFilters.d.ts +12 -0
  138. package/dist/utils/selectorFilters.js +29 -0
  139. package/package.json +2 -1
@@ -0,0 +1,385 @@
1
+ /**
2
+ * `bdg dom inspect --all` and `--props`.
3
+ *
4
+ * `--all` lists every computed longhand that is not noise and not its
5
+ * default, collapsed into shorthands (margin, padding, inset, border,
6
+ * radius, overflow, gap, flex, grid area, outline, animation). Defaults are
7
+ * the CSS initial values as Chrome computes them; the UA stylesheet's
8
+ * per-tag values (a `<p>`'s margins, a button's padding) are real values and
9
+ * are listed. Display, font, size, line height and color are always listed.
10
+ *
11
+ * Noise: custom properties, logical duplicates of physical properties,
12
+ * width/height (in the header), transitions, origins without a transform,
13
+ * colors that only repeat `color` (currentColor), properties of borders,
14
+ * outlines and rules that are not drawn, SVG paint properties on HTML
15
+ * elements, and vendor-prefixed internals.
16
+ */
17
+ import { hexColorsIn } from '../../utils/color.js';
18
+ import { normalizeCssValue, readableTransform, shortUrls, sidesShorthand, } from '../../utils/cssValues.js';
19
+ /** CSS initial values as Chrome computes them, by value */
20
+ const INITIAL_BY_VALUE = [
21
+ [
22
+ 'auto',
23
+ 'accent-color align-self animation-timeline aspect-ratio background-size bottom break-after break-before break-inside caret-animation caret-shape clip column-count column-height column-width column-wrap cursor flex-basis font-kerning font-optical-sizing font-synthesis-small-caps font-synthesis-style font-synthesis-weight forced-color-adjust grid-auto-columns grid-auto-rows grid-column-end grid-column-start grid-row-end grid-row-start hyphenate-character hyphenate-limit-chars image-rendering interactivity isolation justify-self left line-break mask-size offset-anchor overflow-anchor overscroll-behavior-x overscroll-behavior-y pointer-events quotes right ruby-overhang scroll-behavior scroll-padding-bottom scroll-padding-left scroll-padding-right scroll-padding-top scrollbar-color scrollbar-gutter scrollbar-width table-layout text-align-last text-box-edge text-decoration-skip-ink text-decoration-thickness text-justify text-rendering text-size-adjust text-underline-offset text-underline-position text-wrap-style top touch-action user-select view-timeline-inset will-change z-index',
24
+ ],
25
+ [
26
+ 'none',
27
+ 'anchor-name anchor-scope animation-fill-mode animation-name animation-trigger app-region appearance backdrop-filter background-image border-bottom-style border-image-source border-left-style border-right-style border-shape border-top-style box-shadow clear clip-path column-rule-style column-span contain contain-intrinsic-height contain-intrinsic-size contain-intrinsic-width container-name counter-increment counter-reset counter-set filter float font-size-adjust grid-template-areas grid-template-columns grid-template-rows list-style-image mask-image max-height max-width object-view-box offset-path outline-style overlay perspective position-area position-try-fallbacks resize rotate row-rule-style scale scroll-initial-target scroll-marker-group scroll-snap-align scroll-snap-type scroll-target-group scroll-timeline-name shape-outside text-box-trim text-combine-upright text-decoration text-decoration-line text-emphasis-style text-fit text-shadow text-transform timeline-scope transform translate trigger-scope view-timeline-name view-transition-class view-transition-name view-transition-scope window-drag -webkit-line-clamp -webkit-text-security',
28
+ ],
29
+ [
30
+ 'normal',
31
+ 'align-content align-items animation-direction animation-range-end animation-range-start background-blend-mode color-scheme column-gap container-type content font-feature-settings font-language-override font-palette font-style font-variant font-variant-alternates font-variant-caps font-variant-east-asian font-variant-emoji font-variant-ligatures font-variant-numeric font-variant-position font-variation-settings initial-letter interest-delay-end interest-delay-start justify-content justify-items letter-spacing line-height math-shift math-style mix-blend-mode offset-position overflow-wrap position-anchor position-try-order reading-flow row-gap scroll-snap-stop speak text-spacing-trim view-transition-group word-break',
32
+ ],
33
+ [
34
+ '0px',
35
+ 'border-bottom-left-radius border-bottom-right-radius border-bottom-width border-left-width border-right-width border-top-left-radius border-top-right-radius border-top-width margin-bottom margin-left margin-right margin-top min-height min-width offset-distance outline-offset overflow-clip-margin padding-bottom padding-left padding-right padding-top scroll-margin-bottom scroll-margin-left scroll-margin-right scroll-margin-top shape-margin text-indent word-spacing -webkit-text-stroke-width',
36
+ ],
37
+ ['1', 'animation-iteration-count border-image-width flex-line-count flex-shrink opacity zoom'],
38
+ ['0', 'border-image-outset flex-grow math-depth order reading-order shape-image-threshold'],
39
+ ['visible', 'backface-visibility content-visibility overflow-x overflow-y visibility'],
40
+ [
41
+ 'superellipse(1)',
42
+ 'corner-bottom-left-shape corner-bottom-right-shape corner-top-left-shape corner-top-right-shape',
43
+ ],
44
+ ['border-box', 'background-clip mask-clip mask-origin'],
45
+ ['3px', 'column-rule-width outline-width row-rule-width'],
46
+ ['block', 'scroll-timeline-axis view-timeline-axis'],
47
+ ['0s', 'animation-delay animation-duration'],
48
+ ['0% 0%', 'background-position mask-position'],
49
+ ['repeat', 'background-repeat mask-repeat'],
50
+ ['100%', 'border-image-slice font-stretch'],
51
+ ['row', 'flex-direction grid-auto-flow'],
52
+ ['0%', 'background-position-x background-position-y mask-position-x mask-position-y'],
53
+ ['2', 'orphans widows'],
54
+ ['over', 'ruby-position text-emphasis-position'],
55
+ ['start', 'text-align'],
56
+ ['replace', 'animation-composition'],
57
+ ['running', 'animation-play-state'],
58
+ ['ease', 'animation-timing-function'],
59
+ ['scroll', 'background-attachment'],
60
+ ['rgba(0, 0, 0, 0)', 'background-color'],
61
+ ['padding-box', 'background-origin'],
62
+ ['separate', 'border-collapse'],
63
+ ['stretch', 'border-image-repeat'],
64
+ ['slice', 'box-decoration-break'],
65
+ ['content-box', 'box-sizing'],
66
+ ['top', 'caption-side'],
67
+ ['balance', 'column-fill'],
68
+ ['ltr', 'direction'],
69
+ ['no-limit', 'dynamic-range-limit'],
70
+ ['show', 'empty-cells'],
71
+ ['fixed', 'field-sizing'],
72
+ ['nowrap', 'flex-wrap'],
73
+ ['manual', 'hyphens'],
74
+ ['from-image', 'image-orientation'],
75
+ ['numeric-only', 'interpolate-size'],
76
+ ['outside', 'list-style-position'],
77
+ ['disc', 'list-style-type'],
78
+ ['add', 'mask-composite'],
79
+ ['match-source', 'mask-mode'],
80
+ ['luminance', 'mask-type'],
81
+ ['fill', 'object-fit'],
82
+ ['50% 50%', 'object-position'],
83
+ ['auto 0deg', 'offset-rotate'],
84
+ ['static', 'position'],
85
+ ['anchors-visible', 'position-visibility'],
86
+ ['economy', 'print-color-adjust'],
87
+ ['space-around', 'ruby-align'],
88
+ ['row-over-column', 'rule-overlap'],
89
+ ['8', 'tab-size'],
90
+ ['no-autospace', 'text-autospace'],
91
+ ['solid', 'text-decoration-style'],
92
+ ['mixed', 'text-orientation'],
93
+ ['clip', 'text-overflow'],
94
+ ['wrap', 'text-wrap-mode'],
95
+ ['view-box', 'transform-box'],
96
+ ['flat', 'transform-style'],
97
+ ['baseline', 'vertical-align'],
98
+ ['collapse', 'white-space-collapse'],
99
+ ['horizontal-tb', 'writing-mode'],
100
+ ['isolate', 'unicode-bidi'],
101
+ ];
102
+ /** Initial value per property ({@link INITIAL_BY_VALUE}) */
103
+ const INITIAL_VALUES = new Map(INITIAL_BY_VALUE.flatMap(([value, names]) => names.split(' ').map((name) => [name, value])));
104
+ /** Defaults Chrome computes differently for some elements or versions */
105
+ const ALSO_DEFAULT = {
106
+ 'unicode-bidi': ['normal'],
107
+ 'text-align': ['left', '-webkit-auto'],
108
+ cursor: ['default'],
109
+ };
110
+ /**
111
+ * Values that are the default of properties the table does not know (new or
112
+ * experimental ones Chrome adds, e.g. `timeline-trigger-*`): their initial
113
+ * value is one of these keywords
114
+ */
115
+ const GENERIC_DEFAULTS = new Set(['', 'auto', 'none', 'normal', '0px', '0']);
116
+ /** Always listed, also with their default value */
117
+ const CORE = new Set([
118
+ 'display',
119
+ 'font-family',
120
+ 'font-size',
121
+ 'font-weight',
122
+ 'line-height',
123
+ 'color',
124
+ ]);
125
+ /** Noise by name */
126
+ const NOISE = new Set([
127
+ 'width',
128
+ 'height',
129
+ 'x',
130
+ 'y',
131
+ 'cx',
132
+ 'cy',
133
+ 'r',
134
+ 'rx',
135
+ 'ry',
136
+ 'd',
137
+ 'perspective-origin',
138
+ 'transform-origin',
139
+ 'caret-color',
140
+ 'flex-line-count',
141
+ 'speak',
142
+ ]);
143
+ /** Logical duplicates of physical properties */
144
+ const LOGICAL = /((^|-)block(-|$)|(^|-)inline(-|$)|^inset-|-start-start|-start-end|-end-end|-end-start)/;
145
+ /** Vendor-prefixed properties worth listing */
146
+ const PREFIXED_KEPT = new Set([
147
+ '-webkit-line-clamp',
148
+ '-webkit-text-stroke-width',
149
+ '-webkit-text-security',
150
+ ]);
151
+ /** SVG paint and geometry properties (noise on HTML elements) */
152
+ const SVG_ONLY = /^(fill|fill-opacity|fill-rule|stroke|stroke-.*|stop-.*|flood-.*|lighting-color|marker-.*|clip-rule|color-interpolation.*|color-rendering|shape-rendering|text-anchor|dominant-baseline|alignment-baseline|baseline-shift|vector-effect|buffered-rendering|paint-order|mask-type)$/;
153
+ /** Colors that repeat `color` when not set otherwise */
154
+ const CURRENT_COLOR_ECHOES = /^(border-(top|right|bottom|left)-color|outline-color|column-rule-color|row-rule-color|text-decoration-color|text-emphasis-color|-webkit-text-fill-color|-webkit-text-stroke-color)$/;
155
+ /**
156
+ * Whether a property is noise for `--all`.
157
+ *
158
+ * @param name - Property name
159
+ * @param style - All computed styles (for the conditions)
160
+ * @param svg - The element is an SVG element
161
+ * @returns True when it is left out
162
+ */
163
+ function isNoise(name, style, svg) {
164
+ if (name.startsWith('--') || NOISE.has(name) || name.startsWith('transition'))
165
+ return true;
166
+ if (LOGICAL.test(name) && !name.endsWith('-axis'))
167
+ return true;
168
+ if (name.startsWith('-webkit-') && !PREFIXED_KEPT.has(name))
169
+ return true;
170
+ if (!svg && SVG_ONLY.test(name))
171
+ return true;
172
+ if (CURRENT_COLOR_ECHOES.test(name) && style[name] === style['color'])
173
+ return true;
174
+ const side = /^border-(top|right|bottom|left)-(color|style|width)$/.exec(name)?.[1];
175
+ if (side && ['none', 'hidden'].includes(style[`border-${side}-style`] ?? 'none'))
176
+ return true;
177
+ const drawn = /^(outline|column-rule|row-rule)-/.exec(name)?.[1];
178
+ return drawn !== undefined && name !== `${drawn}-style` && style[`${drawn}-style`] === 'none';
179
+ }
180
+ /**
181
+ * Whether a computed value is its property's default.
182
+ *
183
+ * @param name - Property name
184
+ * @param value - Computed value
185
+ * @returns True for the initial value (or an equivalent), an empty value, and
186
+ * a generic default keyword for a property the table does not know
187
+ */
188
+ export function isDefaultValue(name, value) {
189
+ if (CORE.has(name))
190
+ return false;
191
+ if (value === '')
192
+ return true;
193
+ const initial = INITIAL_VALUES.get(name);
194
+ if (initial === undefined)
195
+ return GENERIC_DEFAULTS.has(value);
196
+ return initial === value || (ALSO_DEFAULT[name]?.includes(value) ?? false);
197
+ }
198
+ /**
199
+ * A computed value normalized: px as numbers, colors as hex, URLs as file
200
+ * names, matrices as transforms.
201
+ *
202
+ * @param name - Property name
203
+ * @param value - Computed value
204
+ * @returns Normalized value
205
+ */
206
+ export function normalizeProperty(name, value) {
207
+ if (name === 'transform')
208
+ return readableTransform(value);
209
+ return normalizeCssValue(shortUrls(hexColorsIn(value)));
210
+ }
211
+ const sideNames = (pattern) => ['top', 'right', 'bottom', 'left'].map((side) => pattern.replace('{side}', side));
212
+ const COLLAPSES = [
213
+ { shorthand: 'margin', longhands: sideNames('margin-{side}'), write: sidesShorthand },
214
+ { shorthand: 'padding', longhands: sideNames('padding-{side}'), write: sidesShorthand },
215
+ { shorthand: 'inset', longhands: sideNames('{side}'), write: sidesShorthand },
216
+ {
217
+ shorthand: 'scroll-margin',
218
+ longhands: sideNames('scroll-margin-{side}'),
219
+ write: sidesShorthand,
220
+ },
221
+ {
222
+ shorthand: 'scroll-padding',
223
+ longhands: sideNames('scroll-padding-{side}'),
224
+ write: sidesShorthand,
225
+ },
226
+ {
227
+ shorthand: 'border-radius',
228
+ longhands: ['top-left', 'top-right', 'bottom-right', 'bottom-left'].map((c) => `border-${c}-radius`),
229
+ write: sidesShorthand,
230
+ },
231
+ {
232
+ shorthand: 'overflow',
233
+ longhands: ['overflow-x', 'overflow-y'],
234
+ write: ([x, y]) => (x === y ? `${x}` : `${x} ${y}`),
235
+ },
236
+ {
237
+ shorthand: 'gap',
238
+ longhands: ['row-gap', 'column-gap'],
239
+ write: ([row, column]) => (row === column ? `${row}` : `${row} ${column}`),
240
+ },
241
+ {
242
+ shorthand: 'flex',
243
+ longhands: ['flex-grow', 'flex-shrink', 'flex-basis'],
244
+ write: (v) => v.join(' '),
245
+ },
246
+ {
247
+ shorthand: 'grid-area',
248
+ longhands: ['grid-row-start', 'grid-column-start', 'grid-row-end', 'grid-column-end'],
249
+ write: (v) => v.join(' / '),
250
+ },
251
+ {
252
+ shorthand: 'outline',
253
+ longhands: ['outline-width', 'outline-style', 'outline-color', 'outline-offset'],
254
+ write: ([width, style, color, offset]) => `${width} ${style} ${color}${offset === '0' ? '' : ` offset ${offset}`}`,
255
+ },
256
+ {
257
+ shorthand: 'animation',
258
+ longhands: [
259
+ 'animation-name',
260
+ 'animation-duration',
261
+ 'animation-timing-function',
262
+ 'animation-delay',
263
+ 'animation-iteration-count',
264
+ 'animation-direction',
265
+ 'animation-fill-mode',
266
+ ],
267
+ write: (v) => v.join(' '),
268
+ },
269
+ ];
270
+ /**
271
+ * Border longhands collapsed: one `border` when the four drawn sides are
272
+ * equal, else one entry per drawn side.
273
+ *
274
+ * @param style - All computed styles
275
+ * @returns Collapsed entries
276
+ */
277
+ function collapseBorders(style) {
278
+ const sides = ['top', 'right', 'bottom', 'left'].filter((side) => !['none', 'hidden'].includes(style[`border-${side}-style`] ?? 'none'));
279
+ const write = (side) => ['width', 'style', 'color']
280
+ .map((part) => normalizeProperty(`border-${side}-${part}`, style[`border-${side}-${part}`] ?? ''))
281
+ .join(' ');
282
+ const lines = sides.map((side) => [`border-${side}`, write(side)]);
283
+ const first = lines[0]?.[1];
284
+ if (lines.length === 4 && lines.every(([, line]) => line === first))
285
+ return [['border', first ?? '']];
286
+ return lines;
287
+ }
288
+ /**
289
+ * Replace collapsible longhands with their shorthands, each at the place of
290
+ * its first longhand.
291
+ *
292
+ * @param kept - Listed longhands with normalized values, in computed order
293
+ * @param style - All computed styles (values of the longhands that are defaults)
294
+ * @returns Listed properties
295
+ */
296
+ function collapse(kept, style) {
297
+ const result = [];
298
+ const done = new Set();
299
+ const borderPart = /^border-(top|right|bottom|left)-(width|style|color)$/;
300
+ for (const [name, value] of kept) {
301
+ if (done.has(name))
302
+ continue;
303
+ if (borderPart.test(name)) {
304
+ for (const key of kept.keys())
305
+ if (borderPart.test(key))
306
+ done.add(key);
307
+ result.push(...collapseBorders(style));
308
+ continue;
309
+ }
310
+ const group = COLLAPSES.find((entry) => entry.longhands.includes(name));
311
+ if (!group) {
312
+ result.push([name, value]);
313
+ continue;
314
+ }
315
+ group.longhands.forEach((longhand) => done.add(longhand));
316
+ const values = group.longhands.map((longhand) => kept.get(longhand) ?? normalizeProperty(longhand, style[longhand] ?? ''));
317
+ result.push([group.shorthand, group.write(values)]);
318
+ }
319
+ return Object.fromEntries(result);
320
+ }
321
+ /**
322
+ * Whether an inset side is only resolved, not set: Chrome computes `0px` for
323
+ * the sides of a `position: relative` element that sets none (and `auto`
324
+ * stays `auto` elsewhere).
325
+ *
326
+ * @param name - Property name
327
+ * @param value - Computed value
328
+ * @param style - All computed styles
329
+ * @returns True for a 0 offset of a relative element
330
+ */
331
+ function isUnsetOffset(name, value, style) {
332
+ return (/^(top|right|bottom|left)$/.test(name) && value === '0px' && style['position'] === 'relative');
333
+ }
334
+ /**
335
+ * Every computed longhand that is not noise and not a default, normalized
336
+ * and collapsed into shorthands.
337
+ *
338
+ * @param style - Computed styles
339
+ * @param svg - The element is an SVG element (SVG properties are listed)
340
+ * @returns Properties and values
341
+ */
342
+ export function allStyles(style, svg) {
343
+ const kept = new Map();
344
+ const transformed = (style['transform'] ?? 'none') !== 'none';
345
+ for (const [name, value] of Object.entries(style)) {
346
+ if (name === 'transform-origin' && transformed) {
347
+ kept.set(name, normalizeProperty(name, value));
348
+ continue;
349
+ }
350
+ if (isNoise(name, style, svg) || isDefaultValue(name, value))
351
+ continue;
352
+ if (isUnsetOffset(name, value, style))
353
+ continue;
354
+ kept.set(name, normalizeProperty(name, value));
355
+ }
356
+ return collapse(kept, style);
357
+ }
358
+ /**
359
+ * The properties asked for with `--props`, raw and normalized. CDP's
360
+ * computed longhands come first; shorthands and custom properties come from
361
+ * the page (`getComputedStyle`).
362
+ *
363
+ * @param names - Property names, lowercase
364
+ * @param style - Computed longhands (CDP)
365
+ * @param pageValues - Values the page read
366
+ * @param pageUnknown - Names the page does not know as CSS properties
367
+ * @returns Values by name (an unset custom property is empty), and the
368
+ * names that are not properties
369
+ */
370
+ export function selectedProps(names, style, pageValues, pageUnknown = []) {
371
+ const props = {};
372
+ const unknown = [];
373
+ for (const name of names) {
374
+ const computed = style[name] ?? pageValues?.[name] ?? '';
375
+ const known = name in style || (pageValues !== undefined && name in pageValues);
376
+ if (pageUnknown.includes(name) || (!known && computed === '' && !name.startsWith('--'))) {
377
+ unknown.push(name);
378
+ }
379
+ else {
380
+ props[name] = { computed, value: normalizeProperty(name, computed) };
381
+ }
382
+ }
383
+ return { props, unknown };
384
+ }
385
+ //# sourceMappingURL=inspectAllStyles.js.map
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Which declaration sets a property of an element: the CSS cascade computed
3
+ * from `CSS.getMatchedStylesForNode` (Chrome reports the matching rules, not
4
+ * which declaration wins).
5
+ *
6
+ * The rules come in ascending precedence (user-agent first, then layered
7
+ * rules in layer order, then unlayered rules by specificity and source
8
+ * order), between the presentational attributes and the style attribute.
9
+ * The last normal declaration wins unless an `!important` one exists; among
10
+ * important ones the style attribute wins, then layered ones (earlier layers
11
+ * first), then unlayered ones. Shorthands are expanded into their longhands
12
+ * and logical properties mapped to physical ones (horizontal, left-to-right
13
+ * writing). With no declaration of its own, an inherited property comes from
14
+ * the nearest ancestor that declares it.
15
+ */
16
+ import type { Protocol } from 'devtools-protocol';
17
+ /** Where a declaration comes from */
18
+ export interface DeclarationSource {
19
+ /** `rule` (a stylesheet rule), `inline` (style attribute), `attribute` (presentational HTML attribute) */
20
+ kind: 'rule' | 'inline' | 'attribute';
21
+ /** The matching selector of the rule */
22
+ selector?: string;
23
+ /** `regular`, `user-agent`, `injected`, `inspector` */
24
+ origin?: string;
25
+ styleSheetId?: string;
26
+ /** 0-based line and column in the stylesheet (as CDP reports them) */
27
+ line?: number;
28
+ column?: number;
29
+ /** Cascade layer, e.g. `utilities` */
30
+ layer?: string;
31
+ /** Media or container condition the rule is under, e.g. `(min-width: 80rem)` */
32
+ condition?: string;
33
+ /** Specificity of the matching selector (ids, classes, types) */
34
+ specificity?: [number, number, number];
35
+ }
36
+ /** One declaration of a longhand */
37
+ export interface Declaration {
38
+ /** Longhand it sets (a shorthand or logical property mapped to it) */
39
+ property: string;
40
+ /** Value this longhand gets (Chrome's expansion, or the written value when it has `var()`) */
41
+ value: string;
42
+ /** Property as written, when it is not the longhand (`padding`, `margin-inline-start`) */
43
+ via?: string;
44
+ /** Value as written, when set via another property (`4px 8px` for `padding`) */
45
+ written?: string;
46
+ important: boolean;
47
+ source: DeclarationSource;
48
+ /** How many ancestors up it was declared (absent: on the element) */
49
+ ancestor?: number;
50
+ }
51
+ /** The cascade of one property */
52
+ export interface Resolution {
53
+ /** The winning declaration, absent when nothing authored sets it (initial or inherited default) */
54
+ winner?: Declaration;
55
+ /** Declarations that lost (of the element, or of the ancestor it inherits from), highest precedence first */
56
+ overridden: Declaration[];
57
+ }
58
+ /**
59
+ * The longhands of a shorthand.
60
+ *
61
+ * @param name - Property name
62
+ * @returns Its longhands, or undefined when it is not a known shorthand
63
+ */
64
+ export declare function shorthandLonghands(name: string): readonly string[] | undefined;
65
+ /**
66
+ * Whether a property inherits.
67
+ *
68
+ * @param property - Longhand
69
+ * @returns True for inherited properties (custom properties inherit)
70
+ */
71
+ export declare function isInherited(property: string): boolean;
72
+ /**
73
+ * The physical longhand a logical property sets.
74
+ *
75
+ * @param name - Property as written
76
+ * @returns Physical name, or the name itself
77
+ */
78
+ export declare function physicalName(name: string): string;
79
+ /**
80
+ * The longhands the element's own declarations set (what hints check).
81
+ *
82
+ * @param matched - `CSS.getMatchedStylesForNode` response
83
+ * @returns Longhands
84
+ */
85
+ export declare function ownProperties(matched: Protocol.CSS.GetMatchedStylesForNodeResponse): string[];
86
+ /**
87
+ * Resolve the cascade of the given properties for an element.
88
+ *
89
+ * @param matched - `CSS.getMatchedStylesForNode` response
90
+ * @param properties - Longhands to resolve
91
+ * @returns Resolution per property
92
+ */
93
+ export declare function resolveCascade(matched: Protocol.CSS.GetMatchedStylesForNodeResponse, properties: readonly string[]): Map<string, Resolution>;
94
+ //# sourceMappingURL=inspectCascade.d.ts.map