browser-debugger-cli 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/commands/dom/a11y.js +2 -1
- package/dist/commands/dom/formInteraction.js +56 -25
- package/dist/commands/dom/helpers/keyAttributes.d.ts +20 -0
- package/dist/commands/dom/helpers/keyAttributes.js +54 -0
- package/dist/commands/dom/helpers/query.d.ts +1 -1
- package/dist/commands/dom/helpers/query.js +66 -19
- package/dist/commands/dom/helpers/runElementCommand.js +4 -3
- package/dist/commands/dom/helpers/screenshot.js +85 -12
- package/dist/commands/dom/index.d.ts +1 -0
- package/dist/commands/dom/index.js +8 -3
- package/dist/commands/dom/inspect.d.ts +15 -0
- package/dist/commands/dom/inspect.js +82 -0
- package/dist/commands/dom/layout.js +2 -2
- package/dist/commands/dom/listeners.js +2 -2
- package/dist/commands/dom/semanticUtils.d.ts +14 -1
- package/dist/commands/dom/semanticUtils.js +44 -3
- package/dist/commands/network/list.js +13 -2
- package/dist/commands/optionBehaviors.js +48 -6
- package/dist/commands/page.d.ts +1 -1
- package/dist/commands/page.js +62 -3
- package/dist/commands/shared/commonOptions.d.ts +4 -0
- package/dist/commands/shared/commonOptions.js +9 -0
- package/dist/commands/shared/optionTypes.d.ts +21 -0
- package/dist/commands/shared/startHelpers.d.ts +66 -0
- package/dist/commands/shared/startHelpers.js +91 -10
- package/dist/commands/shared/validation.d.ts +11 -0
- package/dist/commands/shared/validation.js +16 -0
- package/dist/daemon/launcher.d.ts +8 -1
- package/dist/daemon/launcher.js +3 -1
- package/dist/daemon/session/Session.d.ts +7 -0
- package/dist/daemon/session/Session.js +23 -1
- package/dist/daemon/session/commandRegistry.d.ts +14 -1
- package/dist/daemon/session/commandRegistry.js +65 -9
- package/dist/daemon/session/interactions.d.ts +18 -5
- package/dist/daemon/session/interactions.js +22 -12
- package/dist/daemon.js +3565 -329
- package/dist/errors/messages.d.ts +69 -0
- package/dist/errors/messages.js +102 -1
- package/dist/index.js +2416 -1320
- package/dist/ipc/client.d.ts +9 -0
- package/dist/ipc/client.js +13 -0
- package/dist/ipc/protocol/commands.d.ts +56 -1
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +35 -2
- package/dist/ipc/protocol/inspectTypes.d.ts +388 -0
- package/dist/ipc/protocol/inspectTypes.js +10 -0
- package/dist/runtime/dom/actionEffects.d.ts +94 -15
- package/dist/runtime/dom/actionEffects.js +173 -27
- package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -14
- package/dist/runtime/dom/actionEffectsScripts.js +224 -32
- package/dist/runtime/dom/elementInfo.d.ts +26 -0
- package/dist/runtime/dom/elementInfo.js +65 -0
- package/dist/runtime/dom/eventListeners.js +14 -4
- package/dist/runtime/dom/formFillHelpers/fill.d.ts +3 -4
- package/dist/runtime/dom/formFillHelpers/fill.js +77 -28
- package/dist/runtime/dom/frameSelection.d.ts +11 -0
- package/dist/runtime/dom/frameSelection.js +20 -1
- package/dist/runtime/dom/frames.d.ts +38 -5
- package/dist/runtime/dom/frames.js +136 -21
- package/dist/runtime/dom/inspect.d.ts +28 -0
- package/dist/runtime/dom/inspect.js +557 -0
- package/dist/runtime/dom/inspectAllStyles.d.ts +62 -0
- package/dist/runtime/dom/inspectAllStyles.js +385 -0
- package/dist/runtime/dom/inspectCascade.d.ts +94 -0
- package/dist/runtime/dom/inspectCascade.js +371 -0
- package/dist/runtime/dom/inspectCascadeModel.d.ts +39 -0
- package/dist/runtime/dom/inspectCascadeModel.js +232 -0
- package/dist/runtime/dom/inspectHints.d.ts +62 -0
- package/dist/runtime/dom/inspectHints.js +305 -0
- package/dist/runtime/dom/inspectLayoutModel.d.ts +87 -0
- package/dist/runtime/dom/inspectLayoutModel.js +346 -0
- package/dist/runtime/dom/inspectModel.d.ts +74 -0
- package/dist/runtime/dom/inspectModel.js +184 -0
- package/dist/runtime/dom/inspectPaintModel.d.ts +157 -0
- package/dist/runtime/dom/inspectPaintModel.js +461 -0
- package/dist/runtime/dom/inspectRules.d.ts +37 -0
- package/dist/runtime/dom/inspectRules.js +101 -0
- package/dist/runtime/dom/inspectScripts.d.ts +132 -0
- package/dist/runtime/dom/inspectScripts.js +263 -0
- package/dist/runtime/dom/inspectTree.d.ts +40 -0
- package/dist/runtime/dom/inspectTree.js +134 -0
- package/dist/runtime/dom/inspectVariables.d.ts +33 -0
- package/dist/runtime/dom/inspectVariables.js +94 -0
- package/dist/runtime/dom/inspectWhyModel.d.ts +20 -0
- package/dist/runtime/dom/inspectWhyModel.js +134 -0
- package/dist/runtime/dom/layout.d.ts +5 -1
- package/dist/runtime/dom/layout.js +10 -3
- package/dist/runtime/dom/listenerPageScripts.d.ts +11 -5
- package/dist/runtime/dom/listenerPageScripts.js +95 -9
- package/dist/runtime/dom/listenerSummary.d.ts +4 -0
- package/dist/runtime/dom/listenerSummary.js +26 -9
- package/dist/runtime/dom/reactEventHelpers.d.ts +5 -0
- package/dist/runtime/dom/reactEventHelpers.js +12 -4
- package/dist/runtime/page/emulation.d.ts +20 -0
- package/dist/runtime/page/emulation.js +37 -0
- package/dist/telemetry/a11y.d.ts +10 -0
- package/dist/telemetry/a11y.js +78 -1
- package/dist/telemetry/console.d.ts +1 -0
- package/dist/telemetry/console.js +100 -5
- package/dist/telemetry/network.js +3 -1
- package/dist/types.d.ts +32 -0
- package/dist/ui/formatters/details.d.ts +8 -0
- package/dist/ui/formatters/details.js +59 -3
- package/dist/ui/formatters/dom.d.ts +2 -1
- package/dist/ui/formatters/dom.js +25 -9
- package/dist/ui/formatters/inspect.d.ts +39 -0
- package/dist/ui/formatters/inspect.js +596 -0
- package/dist/ui/formatters/keyAttributes.d.ts +19 -0
- package/dist/ui/formatters/keyAttributes.js +84 -0
- package/dist/ui/formatters/layout.js +2 -2
- package/dist/ui/formatters/networkHeaders.d.ts +13 -0
- package/dist/ui/formatters/networkHeaders.js +23 -3
- package/dist/ui/formatters/networkList.d.ts +29 -1
- package/dist/ui/formatters/networkList.js +86 -20
- package/dist/ui/formatters/status.js +1 -1
- package/dist/ui/formatting.d.ts +9 -0
- package/dist/ui/formatting.js +6 -3
- package/dist/ui/messages/commands.d.ts +123 -7
- package/dist/ui/messages/commands.js +181 -10
- package/dist/ui/messages/networkMessages.d.ts +14 -0
- package/dist/ui/messages/networkMessages.js +18 -0
- package/dist/ui/messages/session.d.ts +14 -0
- package/dist/ui/messages/session.js +20 -0
- package/dist/utils/async.d.ts +9 -0
- package/dist/utils/async.js +17 -0
- package/dist/utils/color.d.ts +84 -0
- package/dist/utils/color.js +376 -0
- package/dist/utils/cssValues.d.ts +109 -0
- package/dist/utils/cssValues.js +236 -0
- package/dist/utils/selectorFilters.d.ts +12 -0
- package/dist/utils/selectorFilters.js +29 -0
- package/package.json +1 -1
|
@@ -0,0 +1,371 @@
|
|
|
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
|
+
/**
|
|
17
|
+
* The four side longhands of a pattern.
|
|
18
|
+
*
|
|
19
|
+
* @param pattern - e.g. `border-{side}-width`
|
|
20
|
+
* @returns Top, right, bottom, left
|
|
21
|
+
*/
|
|
22
|
+
function sideLonghands(pattern) {
|
|
23
|
+
return ['top', 'right', 'bottom', 'left'].map((side) => pattern.replace('{side}', side));
|
|
24
|
+
}
|
|
25
|
+
/** Longhands of common shorthands, for values with `var()` (CDP leaves those unexpanded) */
|
|
26
|
+
const SHORTHANDS = {
|
|
27
|
+
margin: ['margin-top', 'margin-right', 'margin-bottom', 'margin-left'],
|
|
28
|
+
padding: ['padding-top', 'padding-right', 'padding-bottom', 'padding-left'],
|
|
29
|
+
inset: ['top', 'right', 'bottom', 'left'],
|
|
30
|
+
gap: ['row-gap', 'column-gap'],
|
|
31
|
+
overflow: ['overflow-x', 'overflow-y'],
|
|
32
|
+
'border-width': [
|
|
33
|
+
'border-top-width',
|
|
34
|
+
'border-right-width',
|
|
35
|
+
'border-bottom-width',
|
|
36
|
+
'border-left-width',
|
|
37
|
+
],
|
|
38
|
+
'border-style': [
|
|
39
|
+
'border-top-style',
|
|
40
|
+
'border-right-style',
|
|
41
|
+
'border-bottom-style',
|
|
42
|
+
'border-left-style',
|
|
43
|
+
],
|
|
44
|
+
'border-color': [
|
|
45
|
+
'border-top-color',
|
|
46
|
+
'border-right-color',
|
|
47
|
+
'border-bottom-color',
|
|
48
|
+
'border-left-color',
|
|
49
|
+
],
|
|
50
|
+
'border-radius': [
|
|
51
|
+
'border-top-left-radius',
|
|
52
|
+
'border-top-right-radius',
|
|
53
|
+
'border-bottom-right-radius',
|
|
54
|
+
'border-bottom-left-radius',
|
|
55
|
+
],
|
|
56
|
+
'margin-inline': ['margin-left', 'margin-right'],
|
|
57
|
+
'margin-block': ['margin-top', 'margin-bottom'],
|
|
58
|
+
'padding-inline': ['padding-left', 'padding-right'],
|
|
59
|
+
'padding-block': ['padding-top', 'padding-bottom'],
|
|
60
|
+
'inset-inline': ['left', 'right'],
|
|
61
|
+
'inset-block': ['top', 'bottom'],
|
|
62
|
+
border: ['width', 'style', 'color'].flatMap((part) => sideLonghands('border-{side}-' + part)),
|
|
63
|
+
...Object.fromEntries(['top', 'right', 'bottom', 'left'].map((side) => [
|
|
64
|
+
`border-${side}`,
|
|
65
|
+
['width', 'style', 'color'].map((part) => `border-${side}-${part}`),
|
|
66
|
+
])),
|
|
67
|
+
background: ['background-color', 'background-image'],
|
|
68
|
+
font: ['font-style', 'font-weight', 'font-size', 'line-height', 'font-family'],
|
|
69
|
+
flex: ['flex-grow', 'flex-shrink', 'flex-basis'],
|
|
70
|
+
'place-items': ['align-items', 'justify-items'],
|
|
71
|
+
'place-content': ['align-content', 'justify-content'],
|
|
72
|
+
'place-self': ['align-self', 'justify-self'],
|
|
73
|
+
};
|
|
74
|
+
/** Physical longhand of a logical one (horizontal-tb, ltr) */
|
|
75
|
+
const LOGICAL_TO_PHYSICAL = {
|
|
76
|
+
'inline-size': 'width',
|
|
77
|
+
'block-size': 'height',
|
|
78
|
+
'min-inline-size': 'min-width',
|
|
79
|
+
'min-block-size': 'min-height',
|
|
80
|
+
'max-inline-size': 'max-width',
|
|
81
|
+
'max-block-size': 'max-height',
|
|
82
|
+
'inset-block-start': 'top',
|
|
83
|
+
'inset-block-end': 'bottom',
|
|
84
|
+
'inset-inline-start': 'left',
|
|
85
|
+
'inset-inline-end': 'right',
|
|
86
|
+
};
|
|
87
|
+
/** Sides of the logical box properties (block-start → top, …) */
|
|
88
|
+
const LOGICAL_SIDES = {
|
|
89
|
+
'block-start': 'top',
|
|
90
|
+
'block-end': 'bottom',
|
|
91
|
+
'inline-start': 'left',
|
|
92
|
+
'inline-end': 'right',
|
|
93
|
+
};
|
|
94
|
+
/** Properties that inherit (those `dom inspect` reports) */
|
|
95
|
+
const INHERITED = new Set([
|
|
96
|
+
'color',
|
|
97
|
+
'font-family',
|
|
98
|
+
'font-size',
|
|
99
|
+
'font-style',
|
|
100
|
+
'font-weight',
|
|
101
|
+
'font-variant',
|
|
102
|
+
'font-feature-settings',
|
|
103
|
+
'font-variation-settings',
|
|
104
|
+
'line-height',
|
|
105
|
+
'letter-spacing',
|
|
106
|
+
'word-spacing',
|
|
107
|
+
'text-align',
|
|
108
|
+
'text-indent',
|
|
109
|
+
'text-transform',
|
|
110
|
+
'text-shadow',
|
|
111
|
+
'white-space-collapse',
|
|
112
|
+
'text-wrap-mode',
|
|
113
|
+
'visibility',
|
|
114
|
+
'cursor',
|
|
115
|
+
'direction',
|
|
116
|
+
'list-style-type',
|
|
117
|
+
'list-style-position',
|
|
118
|
+
'tab-size',
|
|
119
|
+
'pointer-events',
|
|
120
|
+
'user-select',
|
|
121
|
+
'-webkit-text-security',
|
|
122
|
+
]);
|
|
123
|
+
/**
|
|
124
|
+
* The longhands of a shorthand.
|
|
125
|
+
*
|
|
126
|
+
* @param name - Property name
|
|
127
|
+
* @returns Its longhands, or undefined when it is not a known shorthand
|
|
128
|
+
*/
|
|
129
|
+
export function shorthandLonghands(name) {
|
|
130
|
+
return Object.hasOwn(SHORTHANDS, name) ? SHORTHANDS[name] : undefined;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Whether a property inherits.
|
|
134
|
+
*
|
|
135
|
+
* @param property - Longhand
|
|
136
|
+
* @returns True for inherited properties (custom properties inherit)
|
|
137
|
+
*/
|
|
138
|
+
export function isInherited(property) {
|
|
139
|
+
return INHERITED.has(property) || property.startsWith('--');
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The physical longhand a logical property sets.
|
|
143
|
+
*
|
|
144
|
+
* @param name - Property as written
|
|
145
|
+
* @returns Physical name, or the name itself
|
|
146
|
+
*/
|
|
147
|
+
export function physicalName(name) {
|
|
148
|
+
const direct = LOGICAL_TO_PHYSICAL[name];
|
|
149
|
+
if (direct)
|
|
150
|
+
return direct;
|
|
151
|
+
const match = /^(margin|padding|border|scroll-margin|scroll-padding)-(block-start|block-end|inline-start|inline-end)(-(width|style|color))?$/.exec(name);
|
|
152
|
+
if (!match)
|
|
153
|
+
return name;
|
|
154
|
+
const side = LOGICAL_SIDES[match[2] ?? ''] ?? '';
|
|
155
|
+
return `${match[1]}-${side}${match[3] ?? ''}`;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The longhands one written property sets, with the value each gets.
|
|
159
|
+
*
|
|
160
|
+
* @param property - CDP property (with `longhandProperties` when Chrome expanded it)
|
|
161
|
+
* @returns Longhand names and values
|
|
162
|
+
*/
|
|
163
|
+
function longhandsOf(property) {
|
|
164
|
+
if (property.longhandProperties && property.longhandProperties.length > 0) {
|
|
165
|
+
return property.longhandProperties.map((longhand) => ({
|
|
166
|
+
name: physicalName(longhand.name),
|
|
167
|
+
value: longhand.value,
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
const expanded = SHORTHANDS[property.name];
|
|
171
|
+
if (expanded)
|
|
172
|
+
return expanded.map((name) => ({ name, value: property.value }));
|
|
173
|
+
return [{ name: physicalName(property.name), value: property.value }];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The declarations a CSS style block sets, longhand by longhand. Only
|
|
177
|
+
* declarations as written count (CDP adds unranged duplicates); disabled
|
|
178
|
+
* and invalid ones do not. A shorthand with `var()` gives each longhand the
|
|
179
|
+
* value as written: Chrome cannot expand it before substitution and reports
|
|
180
|
+
* the initial values (`currentcolor` for `border: 2px solid var(--c)`).
|
|
181
|
+
*
|
|
182
|
+
* @param style - CDP style
|
|
183
|
+
* @param source - Where the block comes from
|
|
184
|
+
* @returns Declarations
|
|
185
|
+
*/
|
|
186
|
+
function declarationsOf(style, source) {
|
|
187
|
+
if (!style)
|
|
188
|
+
return [];
|
|
189
|
+
return style.cssProperties
|
|
190
|
+
.filter((property) => property.range !== undefined ||
|
|
191
|
+
source.origin === 'user-agent' ||
|
|
192
|
+
source.kind === 'attribute')
|
|
193
|
+
.filter((property) => property.disabled !== true && property.parsedOk !== false)
|
|
194
|
+
.flatMap((property) => {
|
|
195
|
+
const written = property.value.replace(/\s*!important\s*$/, '');
|
|
196
|
+
return longhandsOf(property).map(({ name, value }) => ({
|
|
197
|
+
property: name,
|
|
198
|
+
value: property.longhandProperties && value !== '' && !written.includes('var(')
|
|
199
|
+
? value
|
|
200
|
+
: written,
|
|
201
|
+
...(name !== property.name && { via: property.name, written }),
|
|
202
|
+
important: property.important === true,
|
|
203
|
+
source: {
|
|
204
|
+
...source,
|
|
205
|
+
...(property.range && {
|
|
206
|
+
line: property.range.startLine,
|
|
207
|
+
column: property.range.startColumn,
|
|
208
|
+
}),
|
|
209
|
+
},
|
|
210
|
+
}));
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Source of a matched rule: its matching selector, origin, stylesheet,
|
|
215
|
+
* layer (nested ones as `outer.inner`), the media or container condition
|
|
216
|
+
* it is under (`not all and (…)`, as Chrome writes `not (…)`, shortened) and
|
|
217
|
+
* the selector's specificity.
|
|
218
|
+
*
|
|
219
|
+
* @param match - CDP rule match
|
|
220
|
+
* @returns Declaration source
|
|
221
|
+
*/
|
|
222
|
+
function ruleSource(match) {
|
|
223
|
+
const { rule } = match;
|
|
224
|
+
const matching = rule.selectorList.selectors[match.matchingSelectors[0] ?? 0];
|
|
225
|
+
const selector = matching?.text ?? rule.selectorList.text;
|
|
226
|
+
const layer = rule.layers?.map((l) => l.text || '(anonymous)').join('.');
|
|
227
|
+
const condition = [...(rule.media ?? []), ...(rule.containerQueries ?? [])]
|
|
228
|
+
.map((c) => c.text.replace(/^not all and /, 'not '))
|
|
229
|
+
.join(' and ');
|
|
230
|
+
const specificity = matching?.specificity;
|
|
231
|
+
return {
|
|
232
|
+
kind: 'rule',
|
|
233
|
+
selector,
|
|
234
|
+
origin: rule.origin,
|
|
235
|
+
...(specificity && { specificity: [specificity.a, specificity.b, specificity.c] }),
|
|
236
|
+
...(rule.styleSheetId && { styleSheetId: rule.styleSheetId }),
|
|
237
|
+
...(layer && { layer }),
|
|
238
|
+
...(condition && { condition }),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* The declarations of one element in ascending cascade order.
|
|
243
|
+
*
|
|
244
|
+
* @param entry - Inline style, presentational attributes and matched rules
|
|
245
|
+
* @returns Declarations, lowest precedence first
|
|
246
|
+
*/
|
|
247
|
+
function orderedDeclarations(entry) {
|
|
248
|
+
return [
|
|
249
|
+
...declarationsOf(entry.attributesStyle, { kind: 'attribute' }),
|
|
250
|
+
...(entry.matchedCSSRules ?? []).flatMap((match) => declarationsOf(match.rule.style, ruleSource(match))),
|
|
251
|
+
...declarationsOf(entry.inlineStyle, { kind: 'inline' }),
|
|
252
|
+
];
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Whether a declaration comes from the page's authors (not the browser's
|
|
256
|
+
* own stylesheet or an extension's).
|
|
257
|
+
*
|
|
258
|
+
* @param declaration - Declaration
|
|
259
|
+
* @returns True for author declarations
|
|
260
|
+
*/
|
|
261
|
+
function isAuthor(declaration) {
|
|
262
|
+
const { origin } = declaration.source;
|
|
263
|
+
return origin === undefined || origin === 'regular' || origin === 'inspector';
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Precedence of a declaration within one element's list. Normal: author over
|
|
267
|
+
* browser; then the style attribute; then by layer (presentational
|
|
268
|
+
* attributes below every layer, unlayered rules above); then by position.
|
|
269
|
+
* Important: browser over author; the style attribute; layers reversed
|
|
270
|
+
* (unlayered lowest); position.
|
|
271
|
+
*
|
|
272
|
+
* @param declaration - Declaration
|
|
273
|
+
* @param position - Its index in ascending order
|
|
274
|
+
* @param layers - Layer names in the order they first appear
|
|
275
|
+
* @returns Comparable tuple, higher wins
|
|
276
|
+
*/
|
|
277
|
+
function precedence(declaration, position, layers) {
|
|
278
|
+
const { layer, kind } = declaration.source;
|
|
279
|
+
const layerIndex = layer === undefined ? -1 : layers.indexOf(layer);
|
|
280
|
+
const author = isAuthor(declaration) ? 1 : 0;
|
|
281
|
+
const inline = kind === 'inline' ? 1 : 0;
|
|
282
|
+
if (!declaration.important) {
|
|
283
|
+
const layerRank = kind === 'attribute' ? -1 : layer === undefined ? layers.length : layerIndex;
|
|
284
|
+
return [0, author, inline, layerRank, position];
|
|
285
|
+
}
|
|
286
|
+
return [1, 1 - author, inline, layer === undefined ? -1 : layers.length - layerIndex, position];
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Compare two precedence tuples.
|
|
290
|
+
*
|
|
291
|
+
* @param a - Tuple
|
|
292
|
+
* @param b - Tuple
|
|
293
|
+
* @returns Positive when a wins
|
|
294
|
+
*/
|
|
295
|
+
function compare(a, b) {
|
|
296
|
+
for (let i = 0; i < a.length; i++) {
|
|
297
|
+
const diff = (a[i] ?? 0) - (b[i] ?? 0);
|
|
298
|
+
if (diff !== 0)
|
|
299
|
+
return diff;
|
|
300
|
+
}
|
|
301
|
+
return 0;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Sort one element's declarations of a property, winner first.
|
|
305
|
+
*
|
|
306
|
+
* @param declarations - Declarations in ascending order
|
|
307
|
+
* @returns Highest precedence first
|
|
308
|
+
*/
|
|
309
|
+
function byPrecedence(declarations) {
|
|
310
|
+
const layers = [
|
|
311
|
+
...new Set(declarations.flatMap((d) => (d.source.layer ? [d.source.layer] : []))),
|
|
312
|
+
];
|
|
313
|
+
return declarations
|
|
314
|
+
.map((declaration, position) => ({
|
|
315
|
+
declaration,
|
|
316
|
+
key: precedence(declaration, position, layers),
|
|
317
|
+
}))
|
|
318
|
+
.sort((a, b) => compare(b.key, a.key))
|
|
319
|
+
.map((entry) => entry.declaration);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* The longhands the element's own declarations set (what hints check).
|
|
323
|
+
*
|
|
324
|
+
* @param matched - `CSS.getMatchedStylesForNode` response
|
|
325
|
+
* @returns Longhands
|
|
326
|
+
*/
|
|
327
|
+
export function ownProperties(matched) {
|
|
328
|
+
return [...new Set(orderedDeclarations(matched).map((declaration) => declaration.property))];
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Resolve the cascade of the given properties for an element.
|
|
332
|
+
*
|
|
333
|
+
* @param matched - `CSS.getMatchedStylesForNode` response
|
|
334
|
+
* @param properties - Longhands to resolve
|
|
335
|
+
* @returns Resolution per property
|
|
336
|
+
*/
|
|
337
|
+
export function resolveCascade(matched, properties) {
|
|
338
|
+
const own = orderedDeclarations(matched);
|
|
339
|
+
const ancestors = (matched.inherited ?? []).map(orderedDeclarations);
|
|
340
|
+
const resolved = new Map();
|
|
341
|
+
for (const property of properties) {
|
|
342
|
+
const ranked = byPrecedence(own.filter((d) => d.property === property));
|
|
343
|
+
const [winner, ...overridden] = ranked;
|
|
344
|
+
if (winner) {
|
|
345
|
+
resolved.set(property, { winner, overridden });
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
resolved.set(property, inheritedWinner(property, ancestors));
|
|
349
|
+
}
|
|
350
|
+
return resolved;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* The nearest ancestor's winning declaration of an inherited property.
|
|
354
|
+
*
|
|
355
|
+
* @param property - Longhand
|
|
356
|
+
* @param ancestors - Declarations of each ancestor, nearest first
|
|
357
|
+
* @returns The winner and the declarations it beat on that ancestor (none for
|
|
358
|
+
* non-inherited properties or when no ancestor sets it)
|
|
359
|
+
*/
|
|
360
|
+
function inheritedWinner(property, ancestors) {
|
|
361
|
+
if (!isInherited(property))
|
|
362
|
+
return { overridden: [] };
|
|
363
|
+
for (const [depth, declarations] of ancestors.entries()) {
|
|
364
|
+
const ranked = byPrecedence(declarations.filter((d) => d.property === property)).map((declaration) => ({ ...declaration, ancestor: depth + 1 }));
|
|
365
|
+
const [winner, ...overridden] = ranked;
|
|
366
|
+
if (winner)
|
|
367
|
+
return { winner, overridden };
|
|
368
|
+
}
|
|
369
|
+
return { overridden: [] };
|
|
370
|
+
}
|
|
371
|
+
//# sourceMappingURL=inspectCascade.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dom inspect`'s cascade fields from the matched rules: hints (declarations
|
|
3
|
+
* that have no effect), `--rules` (which declaration sets each shown
|
|
4
|
+
* property, sides set by one declaration merged into the shorthand) and
|
|
5
|
+
* `--why` (every declaration of one property).
|
|
6
|
+
*/
|
|
7
|
+
import type { Protocol } from '../../connection/typed-cdp.js';
|
|
8
|
+
import type { InspectResult } from '../../ipc/protocol/inspectTypes.js';
|
|
9
|
+
import { type Declaration } from './inspectCascade.js';
|
|
10
|
+
import type { StyleMap } from './inspectLayoutModel.js';
|
|
11
|
+
/** Longhands reported together, so a shorthand can stand for its sides */
|
|
12
|
+
export interface PropertyGroup {
|
|
13
|
+
shorthand?: string;
|
|
14
|
+
longhands: string[];
|
|
15
|
+
}
|
|
16
|
+
/** What the cascade fields are built from */
|
|
17
|
+
export interface CascadeInput {
|
|
18
|
+
matched: Protocol.CSS.GetMatchedStylesForNodeResponse;
|
|
19
|
+
style: StyleMap;
|
|
20
|
+
parentStyle: StyleMap | undefined;
|
|
21
|
+
replaced: boolean;
|
|
22
|
+
/** Where a declaration comes from, for people */
|
|
23
|
+
label: (declaration: Declaration) => string;
|
|
24
|
+
rules?: boolean;
|
|
25
|
+
why?: string;
|
|
26
|
+
/** `--props` names: `--rules` then covers only these */
|
|
27
|
+
props?: string[];
|
|
28
|
+
/** Check for declarations that have no effect (default true) */
|
|
29
|
+
hints?: boolean;
|
|
30
|
+
formControl?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The cascade fields of the result.
|
|
34
|
+
*
|
|
35
|
+
* @param input - Matched rules, computed styles, options
|
|
36
|
+
* @returns `hints` (empty when checked and nothing found), `rules` and `why`
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildCascadeFields(input: CascadeInput): Partial<InspectResult>;
|
|
39
|
+
//# sourceMappingURL=inspectCascadeModel.d.ts.map
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dom inspect`'s cascade fields from the matched rules: hints (declarations
|
|
3
|
+
* that have no effect), `--rules` (which declaration sets each shown
|
|
4
|
+
* property, sides set by one declaration merged into the shorthand) and
|
|
5
|
+
* `--why` (every declaration of one property).
|
|
6
|
+
*/
|
|
7
|
+
import { normalizeProperty } from './inspectAllStyles.js';
|
|
8
|
+
import { physicalName, ownProperties, resolveCascade, shorthandLonghands, } from './inspectCascade.js';
|
|
9
|
+
import { formControlFontHints, inactiveHints, undefinedVariableHints, } from './inspectHints.js';
|
|
10
|
+
import { buildWhy } from './inspectWhyModel.js';
|
|
11
|
+
const SIDES = ['top', 'right', 'bottom', 'left'];
|
|
12
|
+
const sides = (pattern) => SIDES.map((side) => pattern.replace('{side}', side));
|
|
13
|
+
/** Properties `--rules` reports */
|
|
14
|
+
const RULE_GROUPS = [
|
|
15
|
+
{ longhands: ['display'] },
|
|
16
|
+
{ longhands: ['position'] },
|
|
17
|
+
{ shorthand: 'inset', longhands: sides('{side}') },
|
|
18
|
+
{ longhands: ['z-index'] },
|
|
19
|
+
{ longhands: ['width'] },
|
|
20
|
+
{ longhands: ['height'] },
|
|
21
|
+
{ longhands: ['min-width'] },
|
|
22
|
+
{ longhands: ['max-width'] },
|
|
23
|
+
{ longhands: ['min-height'] },
|
|
24
|
+
{ longhands: ['max-height'] },
|
|
25
|
+
{ shorthand: 'margin', longhands: sides('margin-{side}') },
|
|
26
|
+
{ shorthand: 'padding', longhands: sides('padding-{side}') },
|
|
27
|
+
{ shorthand: 'border-width', longhands: sides('border-{side}-width') },
|
|
28
|
+
{ shorthand: 'border-style', longhands: sides('border-{side}-style') },
|
|
29
|
+
{ shorthand: 'border-color', longhands: sides('border-{side}-color') },
|
|
30
|
+
{
|
|
31
|
+
shorthand: 'border-radius',
|
|
32
|
+
longhands: ['top-left', 'top-right', 'bottom-right', 'bottom-left'].map((c) => `border-${c}-radius`),
|
|
33
|
+
},
|
|
34
|
+
{ longhands: ['background-color'] },
|
|
35
|
+
{ longhands: ['background-image'] },
|
|
36
|
+
{ longhands: ['color'] },
|
|
37
|
+
{ longhands: ['font-family'] },
|
|
38
|
+
{ longhands: ['font-size'] },
|
|
39
|
+
{ longhands: ['font-weight'] },
|
|
40
|
+
{ longhands: ['line-height'] },
|
|
41
|
+
{ longhands: ['letter-spacing'] },
|
|
42
|
+
{ longhands: ['text-align'] },
|
|
43
|
+
{ longhands: ['text-transform'] },
|
|
44
|
+
{ longhands: ['opacity'] },
|
|
45
|
+
{ longhands: ['box-shadow'] },
|
|
46
|
+
{ longhands: ['transform'] },
|
|
47
|
+
{ longhands: ['flex-direction'] },
|
|
48
|
+
{ longhands: ['flex-wrap'] },
|
|
49
|
+
{ longhands: ['justify-content'] },
|
|
50
|
+
{ longhands: ['align-items'] },
|
|
51
|
+
{ shorthand: 'gap', longhands: ['row-gap', 'column-gap'] },
|
|
52
|
+
{ longhands: ['grid-template-columns'] },
|
|
53
|
+
{ longhands: ['grid-template-rows'] },
|
|
54
|
+
{ shorthand: 'flex', longhands: ['flex-grow', 'flex-shrink', 'flex-basis'] },
|
|
55
|
+
{ longhands: ['align-self'] },
|
|
56
|
+
{ shorthand: 'overflow', longhands: ['overflow-x', 'overflow-y'] },
|
|
57
|
+
{ longhands: ['cursor'] },
|
|
58
|
+
];
|
|
59
|
+
/**
|
|
60
|
+
* The cascade fields of the result.
|
|
61
|
+
*
|
|
62
|
+
* @param input - Matched rules, computed styles, options
|
|
63
|
+
* @returns `hints` (empty when checked and nothing found), `rules` and `why`
|
|
64
|
+
*/
|
|
65
|
+
export function buildCascadeFields(input) {
|
|
66
|
+
const ruleGroups = input.rules ? (input.props?.map(propertyGroup) ?? RULE_GROUPS) : [];
|
|
67
|
+
const whyGroup = input.why ? propertyGroup(input.why) : undefined;
|
|
68
|
+
const wanted = [
|
|
69
|
+
...new Set([
|
|
70
|
+
...ownProperties(input.matched),
|
|
71
|
+
...ruleGroups.flatMap((group) => group.longhands),
|
|
72
|
+
...(whyGroup?.longhands ?? []),
|
|
73
|
+
]),
|
|
74
|
+
];
|
|
75
|
+
const cascade = resolveCascade(input.matched, wanted);
|
|
76
|
+
const hints = input.hints === false ? undefined : buildHints(cascade, input);
|
|
77
|
+
const rules = buildRules(ruleGroups, cascade, input);
|
|
78
|
+
return {
|
|
79
|
+
...(hints && { hints }),
|
|
80
|
+
...(rules.length > 0 && { rules }),
|
|
81
|
+
...(whyGroup && { why: buildWhy(whyGroup, cascade, input) }),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The longhands a property name stands for.
|
|
86
|
+
*
|
|
87
|
+
* @param name - Shorthand, longhand, logical or custom property
|
|
88
|
+
* @returns Group (a shorthand with its longhands, or one physical longhand)
|
|
89
|
+
*/
|
|
90
|
+
function propertyGroup(name) {
|
|
91
|
+
const longhands = shorthandLonghands(name);
|
|
92
|
+
return longhands
|
|
93
|
+
? { shorthand: name, longhands: [...longhands] }
|
|
94
|
+
: { longhands: [physicalName(name)] };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Hints: declarations with no effect, and var() of unset custom properties;
|
|
98
|
+
* none without the computed style to check them against.
|
|
99
|
+
*
|
|
100
|
+
* @param cascade - Resolved properties
|
|
101
|
+
* @param input - Styles and the label function
|
|
102
|
+
* @returns Hints
|
|
103
|
+
*/
|
|
104
|
+
function buildHints(cascade, input) {
|
|
105
|
+
if (input.style['display'] === undefined)
|
|
106
|
+
return [];
|
|
107
|
+
const ctx = {
|
|
108
|
+
style: input.style,
|
|
109
|
+
parentStyle: input.parentStyle,
|
|
110
|
+
replaced: input.replaced,
|
|
111
|
+
formControl: input.formControl === true,
|
|
112
|
+
};
|
|
113
|
+
return [
|
|
114
|
+
...inactiveHints(cascade, ctx),
|
|
115
|
+
...undefinedVariableHints(cascade, input.style),
|
|
116
|
+
...formControlFontHints(cascade, ctx),
|
|
117
|
+
].map((hint) => ({
|
|
118
|
+
kind: hint.kind,
|
|
119
|
+
property: hint.property,
|
|
120
|
+
value: hint.value,
|
|
121
|
+
reason: hint.reason,
|
|
122
|
+
fix: hint.fix,
|
|
123
|
+
source: input.label(hint.declaration),
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* `--rules`: one row per property set by an author declaration; one row for
|
|
128
|
+
* a group (`padding`, `border-width`) when a single declaration sets all of
|
|
129
|
+
* it, and one for a shorthand Chrome could not expand (`var()`, such as
|
|
130
|
+
* `border: 2px solid var(--c)` or `background: var(--bg)`) however many
|
|
131
|
+
* properties it sets.
|
|
132
|
+
*
|
|
133
|
+
* @param groups - Properties to report
|
|
134
|
+
* @param cascade - Resolved properties
|
|
135
|
+
* @param input - Computed style and the label function
|
|
136
|
+
* @returns Rules
|
|
137
|
+
*/
|
|
138
|
+
function buildRules(groups, cascade, input) {
|
|
139
|
+
const rows = groups.flatMap((group) => {
|
|
140
|
+
const resolutions = group.longhands.map((longhand) => cascade.get(longhand));
|
|
141
|
+
const winners = resolutions.map((resolution) => resolution?.winner);
|
|
142
|
+
const grouped = group.shorthand !== undefined ? groupedRow(group.shorthand, winners) : undefined;
|
|
143
|
+
if (grouped)
|
|
144
|
+
return [toRule(grouped.property, grouped, resolutions[0], input)];
|
|
145
|
+
return group.longhands.flatMap((longhand, i) => {
|
|
146
|
+
const winner = winners[i];
|
|
147
|
+
if (!winner || winner.source.origin === 'user-agent')
|
|
148
|
+
return [];
|
|
149
|
+
const unexpanded = winner.via !== undefined && winner.value === winner.written;
|
|
150
|
+
return unexpanded && winner.via
|
|
151
|
+
? [toRule(winner.via, winner, resolutions[i], input)]
|
|
152
|
+
: [toRule(longhand, winner, resolutions[i], input)];
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
const seen = new Set();
|
|
156
|
+
return rows.filter((row) => {
|
|
157
|
+
const key = `${row.property}|${row.value}|${row.source}`;
|
|
158
|
+
if (seen.has(key))
|
|
159
|
+
return false;
|
|
160
|
+
seen.add(key);
|
|
161
|
+
return true;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* One row for a group of longhands that a single author declaration sets:
|
|
166
|
+
* the shorthand as written, or (set by a wider shorthand, like `border`
|
|
167
|
+
* for `border-width`) the values it gives the sides; a wider shorthand
|
|
168
|
+
* Chrome could not expand (`var()`) as written.
|
|
169
|
+
*
|
|
170
|
+
* @param shorthand - The group's shorthand
|
|
171
|
+
* @param winners - Winning declaration of each longhand
|
|
172
|
+
* @returns The row's declaration, or undefined when the sides differ in source
|
|
173
|
+
*/
|
|
174
|
+
function groupedRow(shorthand, winners) {
|
|
175
|
+
const [first] = winners;
|
|
176
|
+
if (!first?.via || first.source.origin === 'user-agent')
|
|
177
|
+
return undefined;
|
|
178
|
+
const same = winners.every((w) => w && w.via === first.via && sameSource(w, first));
|
|
179
|
+
if (!same)
|
|
180
|
+
return undefined;
|
|
181
|
+
const written = first.written ?? first.value;
|
|
182
|
+
if (first.via === shorthand || first.value === written) {
|
|
183
|
+
return { ...first, property: first.via, value: written };
|
|
184
|
+
}
|
|
185
|
+
const values = winners.map((w) => w?.value ?? '');
|
|
186
|
+
const value = values.every((v) => v === first.value) ? first.value : values.join(' ');
|
|
187
|
+
return { ...first, property: shorthand, value };
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Whether two declarations come from the same place.
|
|
191
|
+
*
|
|
192
|
+
* @param a - Declaration
|
|
193
|
+
* @param b - Declaration
|
|
194
|
+
* @returns True for the same declaration (same rule and position)
|
|
195
|
+
*/
|
|
196
|
+
function sameSource(a, b) {
|
|
197
|
+
return (a.source.kind === b.source.kind &&
|
|
198
|
+
a.source.selector === b.source.selector &&
|
|
199
|
+
a.source.styleSheetId === b.source.styleSheetId &&
|
|
200
|
+
a.source.line === b.source.line &&
|
|
201
|
+
a.source.column === b.source.column);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* A `--rules` row.
|
|
205
|
+
*
|
|
206
|
+
* @param property - Property shown
|
|
207
|
+
* @param winner - Winning declaration
|
|
208
|
+
* @param resolution - Its resolution (for what it overrides)
|
|
209
|
+
* @param input - Computed style and the label function
|
|
210
|
+
* @returns Rule
|
|
211
|
+
*/
|
|
212
|
+
function toRule(property, winner, resolution, input) {
|
|
213
|
+
const computed = input.style[property];
|
|
214
|
+
const overrides = [
|
|
215
|
+
...new Set((resolution?.overridden ?? [])
|
|
216
|
+
.filter((d) => d.source.origin !== 'user-agent')
|
|
217
|
+
.map((d) => d.source.selector ?? d.source.kind)),
|
|
218
|
+
];
|
|
219
|
+
return {
|
|
220
|
+
property,
|
|
221
|
+
value: winner.value,
|
|
222
|
+
...(winner.value.includes('var(') &&
|
|
223
|
+
computed !== undefined && { computed: normalizeProperty(property, computed) }),
|
|
224
|
+
source: input.label(winner),
|
|
225
|
+
...(overrides.length > 0 && { overrides }),
|
|
226
|
+
...(winner.ancestor !== undefined && { inherited: winner.ancestor }),
|
|
227
|
+
...(winner.important && { important: true }),
|
|
228
|
+
...(winner.source.layer && { layer: winner.source.layer }),
|
|
229
|
+
...(winner.source.condition && { condition: winner.source.condition }),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=inspectCascadeModel.js.map
|