chrome-devtools-frontend 1.0.1033742 → 1.0.1034881

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.
@@ -377,4 +377,5 @@ export enum EnumeratedHistogram {
377
377
  RecordingToggled = 'DevTools.RecordingToggled',
378
378
  StyleTextCopied = 'DevTools.StyleTextCopied',
379
379
  ManifestSectionSelected = 'DevTools.ManifestSectionSelected',
380
+ CSSHintShown = 'DevTools.CSSHintShown',
380
381
  }
@@ -277,6 +277,11 @@ export class UserMetrics {
277
277
  InspectorFrontendHostInstance.recordEnumeratedHistogram(
278
278
  EnumeratedHistogram.ManifestSectionSelected, code, ManifestSectionCodes.MaxValue);
279
279
  }
280
+
281
+ cssHintShown(type: CSSHintType): void {
282
+ InspectorFrontendHostInstance.recordEnumeratedHistogram(
283
+ EnumeratedHistogram.CSSHintShown, type, CSSHintType.MaxValue);
284
+ }
280
285
  }
281
286
 
282
287
  /**
@@ -993,4 +998,22 @@ export enum ManifestSectionCodes {
993
998
  MaxValue = 5,
994
999
  }
995
1000
 
1001
+ // The names here match the CSSRuleValidator names in CSSRuleValidator.ts.
1002
+ // TODO(crbug.com/1167717): Make this a const enum again
1003
+ // eslint-disable-next-line rulesdir/const_enum
1004
+ export enum CSSHintType {
1005
+ Other = 0,
1006
+ AlignContent = 1,
1007
+ FlexItem = 2,
1008
+ FlexContainer = 3,
1009
+ GridContainer = 4,
1010
+ GridItem = 5,
1011
+ FlexGrid = 6,
1012
+ MulticolFlexGrid = 7,
1013
+ Padding = 8,
1014
+ Position = 9,
1015
+ ZIndex = 10,
1016
+ MaxValue = 11,
1017
+ }
1018
+
996
1019
  /* eslint-enable @typescript-eslint/naming-convention */
@@ -120,18 +120,21 @@ export class ExperimentsSupport {
120
120
  #enabledTransiently: Set<string>;
121
121
  readonly #enabledByDefault: Set<string>;
122
122
  readonly #serverEnabled: Set<string>;
123
+ // Experiments in this set won't be shown to the user
124
+ readonly #nonConfigurable: Set<string>;
123
125
  constructor() {
124
126
  this.#experiments = [];
125
127
  this.#experimentNames = new Set();
126
128
  this.#enabledTransiently = new Set();
127
129
  this.#enabledByDefault = new Set();
128
130
  this.#serverEnabled = new Set();
131
+ this.#nonConfigurable = new Set();
129
132
  }
130
133
 
131
134
  allConfigurableExperiments(): Experiment[] {
132
135
  const result = [];
133
136
  for (const experiment of this.#experiments) {
134
- if (!this.#enabledTransiently.has(experiment.name)) {
137
+ if (!this.#enabledTransiently.has(experiment.name) && !this.#nonConfigurable.has(experiment.name)) {
135
138
  result.push(experiment);
136
139
  }
137
140
  }
@@ -203,6 +206,13 @@ export class ExperimentsSupport {
203
206
  }
204
207
  }
205
208
 
209
+ setNonConfigurableExperiments(experimentNames: string[]): void {
210
+ for (const experiment of experimentNames) {
211
+ this.checkExperiment(experiment);
212
+ this.#nonConfigurable.add(experiment);
213
+ }
214
+ }
215
+
206
216
  enableForTest(experimentName: string): void {
207
217
  this.checkExperiment(experimentName);
208
218
  this.#enabledTransiently.add(experimentName);
@@ -465,10 +465,10 @@ export class NetworkDispatcher implements ProtocolProxyApi.NetworkDispatcher {
465
465
  networkRequest.setUrl(response.url as Platform.DevToolsPath.UrlString);
466
466
  }
467
467
  networkRequest.mimeType = (response.mimeType as MIME_TYPE);
468
- if (!networkRequest.statusCode) {
468
+ if (!networkRequest.statusCode || networkRequest.wasIntercepted()) {
469
469
  networkRequest.statusCode = response.status;
470
470
  }
471
- if (!networkRequest.statusText) {
471
+ if (!networkRequest.statusText || networkRequest.wasIntercepted()) {
472
472
  networkRequest.statusText = response.statusText;
473
473
  }
474
474
  if (!networkRequest.hasExtraResponseInfo() || networkRequest.wasIntercepted()) {
@@ -1170,6 +1170,10 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1170
1170
  return multiTargetNetworkManagerInstance;
1171
1171
  }
1172
1172
 
1173
+ static dispose(): void {
1174
+ multiTargetNetworkManagerInstance = null;
1175
+ }
1176
+
1173
1177
  static getChromeVersion(): string {
1174
1178
  const chromeRegex = /(?:^|\W)(?:Chrome|HeadlessChrome)\/(\S+)/;
1175
1179
  const chromeMatch = navigator.userAgent.match(chromeRegex);
@@ -1523,6 +1527,7 @@ export namespace MultitargetNetworkManager {
1523
1527
  InterceptorsChanged = 'InterceptorsChanged',
1524
1528
  AcceptedEncodingsChanged = 'AcceptedEncodingsChanged',
1525
1529
  RequestIntercepted = 'RequestIntercepted',
1530
+ RequestFulfilled = 'RequestFulfilled',
1526
1531
  }
1527
1532
 
1528
1533
  export type EventTypes = {
@@ -1532,6 +1537,7 @@ export namespace MultitargetNetworkManager {
1532
1537
  [Events.InterceptorsChanged]: void,
1533
1538
  [Events.AcceptedEncodingsChanged]: void,
1534
1539
  [Events.RequestIntercepted]: Platform.DevToolsPath.UrlString,
1540
+ [Events.RequestFulfilled]: Platform.DevToolsPath.UrlString,
1535
1541
  };
1536
1542
  }
1537
1543
 
@@ -1565,11 +1571,15 @@ export class InterceptedRequest {
1565
1571
  return this.#hasRespondedInternal;
1566
1572
  }
1567
1573
 
1568
- async continueRequestWithContent(contentBlob: Blob, encoded: boolean, responseHeaders: Protocol.Fetch.HeaderEntry[]):
1569
- Promise<void> {
1574
+ async continueRequestWithContent(
1575
+ contentBlob: Blob, encoded: boolean, responseHeaders: Protocol.Fetch.HeaderEntry[],
1576
+ isBodyOverridden: boolean): Promise<void> {
1570
1577
  this.#hasRespondedInternal = true;
1571
1578
  const body = encoded ? await contentBlob.text() : await blobToBase64(contentBlob);
1572
- void this.#fetchAgent.invoke_fulfillRequest({requestId: this.requestId, responseCode: 200, body, responseHeaders});
1579
+ const responseCode = isBodyOverridden ? 200 : (this.responseStatusCode || 200);
1580
+ void this.#fetchAgent.invoke_fulfillRequest({requestId: this.requestId, responseCode, body, responseHeaders});
1581
+ MultitargetNetworkManager.instance().dispatchEventToListeners(
1582
+ MultitargetNetworkManager.Events.RequestFulfilled, this.request.url as Platform.DevToolsPath.UrlString);
1573
1583
 
1574
1584
  async function blobToBase64(blob: Blob): Promise<string> {
1575
1585
  const reader = new FileReader();
@@ -1608,6 +1618,10 @@ export class InterceptedRequest {
1608
1618
  const error = response.getError() || null;
1609
1619
  return {error: error, content: error ? null : response.body, encoded: response.base64Encoded};
1610
1620
  }
1621
+
1622
+ isRedirect(): boolean {
1623
+ return this.responseStatusCode !== undefined && this.responseStatusCode >= 300 && this.responseStatusCode < 400;
1624
+ }
1611
1625
  }
1612
1626
 
1613
1627
  /**
@@ -125,7 +125,7 @@ async function invokeLH(action: string, args: any): Promise<unknown> {
125
125
  }
126
126
 
127
127
  // @ts-expect-error https://github.com/GoogleChrome/lighthouse/issues/11628
128
- const config = self.createConfig(args.categoryIDs, flags.emulatedFormFactor);
128
+ const config = args.config || self.createConfig(args.categoryIDs, flags.emulatedFormFactor);
129
129
  const url = args.url;
130
130
 
131
131
  // Handle legacy Lighthouse runner path.
@@ -222,25 +222,36 @@ async function fetchLocaleData(locales: string[]): Promise<string|void> {
222
222
  */
223
223
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
224
224
  function notifyFrontendViaWorkerMessage(action: string, args: any): void {
225
- self.postMessage(JSON.stringify({action, args}));
225
+ self.postMessage({action, args});
226
226
  }
227
227
 
228
228
  async function onFrontendMessage(event: MessageEvent): Promise<void> {
229
- const messageFromFrontend = JSON.parse(event.data);
229
+ const messageFromFrontend = event.data;
230
230
  switch (messageFromFrontend.action) {
231
231
  case 'startTimespan':
232
232
  case 'endTimespan':
233
233
  case 'snapshot':
234
234
  case 'navigation': {
235
235
  const result = await invokeLH(messageFromFrontend.action, messageFromFrontend.args);
236
- self.postMessage(JSON.stringify({id: messageFromFrontend.id, result}));
236
+ if (result && typeof result === 'object') {
237
+ // Report isn't used upstream.
238
+ if ('report' in result) {
239
+ // @ts-expect-error
240
+ delete result.report;
241
+ }
242
+
243
+ // Logger PerformanceTiming objects cannot be cloned by this worker's `postMessage` function.
244
+ if ('artifacts' in result) {
245
+ // @ts-expect-error
246
+ result.artifacts.Timing = JSON.parse(JSON.stringify(result.artifacts.Timing));
247
+ }
248
+ }
249
+ self.postMessage({id: messageFromFrontend.id, result});
237
250
  break;
238
251
  }
239
252
  case 'dispatchProtocolMessage': {
240
- cdpConnection?.onMessage?.(
241
- JSON.parse(messageFromFrontend.args.message),
242
- );
243
- legacyPort.onMessage?.(messageFromFrontend.args.message);
253
+ cdpConnection?.onMessage?.(messageFromFrontend.args.message);
254
+ legacyPort.onMessage?.(JSON.stringify(messageFromFrontend.args.message));
244
255
  break;
245
256
  }
246
257
  default: {
@@ -426,10 +426,14 @@ export class MainImpl {
426
426
  'reportingApiDebugging',
427
427
  Root.Runtime.ExperimentName.SYNC_SETTINGS,
428
428
  Root.Runtime.ExperimentName.CSS_LAYERS,
429
- Root.Runtime.ExperimentName.EYEDROPPER_COLOR_PICKER,
429
+ ...('EyeDropper' in window ? [Root.Runtime.ExperimentName.EYEDROPPER_COLOR_PICKER] : []),
430
430
  'lighthousePanelFR',
431
431
  ]);
432
432
 
433
+ Root.Runtime.experiments.setNonConfigurableExperiments([
434
+ ...(!('EyeDropper' in window) ? [Root.Runtime.ExperimentName.EYEDROPPER_COLOR_PICKER] : []),
435
+ ]);
436
+
433
437
  Root.Runtime.experiments.cleanUpStaleExperiments();
434
438
  const enabledExperiments = Root.Runtime.Runtime.queryParam('enabledExperiments');
435
439
  if (enabledExperiments) {
@@ -731,13 +731,17 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
731
731
  const blob = await project.requestFileBlob(fileSystemUISourceCode);
732
732
  if (blob) {
733
733
  void interceptedRequest.continueRequestWithContent(
734
- new Blob([blob], {type: mimeType}), /* encoded */ false, responseHeaders);
734
+ new Blob([blob], {type: mimeType}), /* encoded */ false, responseHeaders, /* isBodyOverridden */ true);
735
735
  }
736
+ } else if (interceptedRequest.isRedirect()) {
737
+ void interceptedRequest.continueRequestWithContent(
738
+ new Blob([], {type: mimeType}), /* encoded */ true, responseHeaders, /* isBodyOverridden */ false);
736
739
  } else {
737
740
  const responseBody = await interceptedRequest.responseBody();
738
741
  if (!responseBody.error && responseBody.content) {
739
742
  void interceptedRequest.continueRequestWithContent(
740
- new Blob([responseBody.content], {type: mimeType}), /* encoded */ true, responseHeaders);
743
+ new Blob([responseBody.content], {type: mimeType}), /* encoded */ true, responseHeaders,
744
+ /* isBodyOverridden */ false);
741
745
  }
742
746
  }
743
747
  }
@@ -2,11 +2,12 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
+ import * as Host from '../../core/host/host.js';
5
6
  import * as i18n from '../../core/i18n/i18n.js';
6
7
 
7
8
  import {
8
- buildStyledPropertyText,
9
- buildStyledRuleText,
9
+ buildPropertyDefinitionText,
10
+ buildPropertyText,
10
11
  isFlexContainer,
11
12
  isGridContainer,
12
13
  isMulticolContainer,
@@ -58,35 +59,34 @@ const UIStrings = {
58
59
  const str_ = i18n.i18n.registerUIStrings('panels/elements/CSSRuleValidator.ts', UIStrings);
59
60
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
60
61
 
61
- export const enum AuthoringHintType {
62
+ export const enum HintType {
62
63
  INACTIVE_PROPERTY = 'ruleValidation',
63
64
  DEPRECATED_PROPERTY = 'deprecatedProperty',
64
65
  }
65
66
 
66
- export class AuthoringHint {
67
- readonly #hintType: AuthoringHintType;
67
+ export class Hint {
68
+ readonly #hintType: HintType;
68
69
  readonly #hintMessage: string;
69
70
  readonly #possibleFixMessage: string|null;
70
71
  readonly #learnMoreLink: string|undefined;
71
72
 
72
- constructor(
73
- hintType: AuthoringHintType, hintMessage: string, possibleFixMessage: string|null, learnMoreLink?: string) {
73
+ constructor(hintType: HintType, hintMessage: string, possibleFixMessage: string|null, learnMoreLink?: string) {
74
74
  this.#hintType = hintType;
75
75
  this.#hintMessage = hintMessage;
76
76
  this.#possibleFixMessage = possibleFixMessage;
77
77
  this.#learnMoreLink = learnMoreLink;
78
78
  }
79
79
 
80
- getHintPrefix(): string {
80
+ getPrefix(): string {
81
81
  switch (this.#hintType) {
82
- case AuthoringHintType.INACTIVE_PROPERTY:
82
+ case HintType.INACTIVE_PROPERTY:
83
83
  return i18nString(UIStrings.inactivePropertyHintPrefix);
84
- case AuthoringHintType.DEPRECATED_PROPERTY:
84
+ case HintType.DEPRECATED_PROPERTY:
85
85
  return i18nString(UIStrings.deprecatedPropertyHintPrefix);
86
86
  }
87
87
  }
88
88
 
89
- getHintMessage(): string {
89
+ getMessage(): string {
90
90
  return this.#hintMessage;
91
91
  }
92
92
 
@@ -100,25 +100,23 @@ export class AuthoringHint {
100
100
  }
101
101
 
102
102
  export abstract class CSSRuleValidator {
103
+ getMetricType(): Host.UserMetrics.CSSHintType {
104
+ return Host.UserMetrics.CSSHintType.Other;
105
+ }
106
+
103
107
  readonly #affectedProperties: string[];
104
108
 
105
109
  constructor(affectedProperties: string[]) {
106
110
  this.#affectedProperties = affectedProperties;
107
111
  }
108
112
 
109
- /**
110
- * If `isRuleValid` returns false, it means there is a hint to be shown. The hint is retrieved by invoking `getAuthoringHint`.
111
- */
112
- abstract isRuleValid(computedStyles: Map<String, String>|null, parentsComputedStyles?: Map<String, String>|null):
113
- boolean;
114
-
115
- getAffectedProperties(): string[] {
113
+ getApplicableProperties(): string[] {
116
114
  return this.#affectedProperties;
117
115
  }
118
116
 
119
- abstract getAuthoringHint(
120
- propertyName: string, computedStyles: Map<String, String>|null,
121
- parentComputedStyles: Map<String, String>|null): AuthoringHint;
117
+ abstract getHint(
118
+ propertyName: string, computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): Hint
119
+ |undefined;
122
120
  }
123
121
 
124
122
  export class AlignContentValidator extends CSSRuleValidator {
@@ -126,7 +124,11 @@ export class AlignContentValidator extends CSSRuleValidator {
126
124
  super(['align-content']);
127
125
  }
128
126
 
129
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
127
+ getMetricType(): Host.UserMetrics.CSSHintType {
128
+ return Host.UserMetrics.CSSHintType.AlignContent;
129
+ }
130
+
131
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
130
132
  if (computedStyles === null || computedStyles === undefined) {
131
133
  return true;
132
134
  }
@@ -136,12 +138,15 @@ export class AlignContentValidator extends CSSRuleValidator {
136
138
  return computedStyles.get('flex-wrap') !== 'nowrap';
137
139
  }
138
140
 
139
- getAuthoringHint(): AuthoringHint {
140
- const reasonPropertyDeclaration = buildStyledPropertyText('flex-wrap');
141
- const affectedPropertyDeclarationCode = buildStyledPropertyText('align-content');
141
+ getHint(_propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
142
+ if (this.#isRuleValid(computedStyles)) {
143
+ return;
144
+ }
145
+ const reasonPropertyDeclaration = buildPropertyText('flex-wrap');
146
+ const affectedPropertyDeclarationCode = buildPropertyText('align-content');
142
147
 
143
- return new AuthoringHint(
144
- AuthoringHintType.INACTIVE_PROPERTY,
148
+ return new Hint(
149
+ HintType.INACTIVE_PROPERTY,
145
150
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
146
151
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
147
152
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -158,22 +163,28 @@ export class FlexItemValidator extends CSSRuleValidator {
158
163
  super(['flex', 'flex-basis', 'flex-grow', 'flex-shrink']);
159
164
  }
160
165
 
161
- isRuleValid(computedStyles: Map<String, String>|null, parentsComputedStyles: Map<String, String>|null): boolean {
162
- if (parentsComputedStyles === null) {
166
+ getMetricType(): Host.UserMetrics.CSSHintType {
167
+ return Host.UserMetrics.CSSHintType.FlexItem;
168
+ }
169
+
170
+ #isRuleValid(computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): boolean {
171
+ if (parentComputedStyles === null) {
163
172
  return true;
164
173
  }
165
- return isFlexContainer(parentsComputedStyles);
174
+ return isFlexContainer(parentComputedStyles);
166
175
  }
167
176
 
168
- getAuthoringHint(
169
- property: string, computedStyles: Map<String, String>|null,
170
- parentsComputedStyles: Map<String, String>|null): AuthoringHint {
171
- const reasonPropertyDeclaration = buildStyledRuleText('display', parentsComputedStyles?.get('display'));
172
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
173
- const targeParentPropertyDeclaration = buildStyledRuleText('display', 'flex');
177
+ getHint(propertyName: string, computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): Hint
178
+ |undefined {
179
+ if (this.#isRuleValid(computedStyles, parentComputedStyles)) {
180
+ return;
181
+ }
182
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', parentComputedStyles?.get('display'));
183
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
184
+ const targeParentPropertyDeclaration = buildPropertyDefinitionText('display', 'flex');
174
185
 
175
- return new AuthoringHint(
176
- AuthoringHintType.INACTIVE_PROPERTY,
186
+ return new Hint(
187
+ HintType.INACTIVE_PROPERTY,
177
188
  i18nString(UIStrings.ruleViolatedByParentElementRuleReason, {
178
189
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
179
190
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -191,20 +202,27 @@ export class FlexContainerValidator extends CSSRuleValidator {
191
202
  super(['flex-direction', 'flex-flow', 'flex-wrap', 'justify-content']);
192
203
  }
193
204
 
194
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
205
+ getMetricType(): Host.UserMetrics.CSSHintType {
206
+ return Host.UserMetrics.CSSHintType.FlexContainer;
207
+ }
208
+
209
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
195
210
  if (computedStyles === null) {
196
211
  return true;
197
212
  }
198
213
  return isFlexContainer(computedStyles);
199
214
  }
200
215
 
201
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
202
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
203
- const targetRuleCode = buildStyledRuleText('display', 'flex');
204
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
216
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
217
+ if (this.#isRuleValid(computedStyles)) {
218
+ return;
219
+ }
220
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
221
+ const targetRuleCode = buildPropertyDefinitionText('display', 'flex');
222
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
205
223
 
206
- return new AuthoringHint(
207
- AuthoringHintType.INACTIVE_PROPERTY,
224
+ return new Hint(
225
+ HintType.INACTIVE_PROPERTY,
208
226
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
209
227
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
210
228
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -231,20 +249,24 @@ export class GridContainerValidator extends CSSRuleValidator {
231
249
  ]);
232
250
  }
233
251
 
234
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
235
- if (computedStyles === null) {
236
- return true;
237
- }
252
+ getMetricType(): Host.UserMetrics.CSSHintType {
253
+ return Host.UserMetrics.CSSHintType.GridContainer;
254
+ }
255
+
256
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
238
257
  return isGridContainer(computedStyles);
239
258
  }
240
259
 
241
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
242
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
243
- const targetRuleCode = buildStyledRuleText('display', 'grid');
244
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
260
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
261
+ if (this.#isRuleValid(computedStyles)) {
262
+ return;
263
+ }
264
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
265
+ const targetRuleCode = buildPropertyDefinitionText('display', 'grid');
266
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
245
267
 
246
- return new AuthoringHint(
247
- AuthoringHintType.INACTIVE_PROPERTY,
268
+ return new Hint(
269
+ HintType.INACTIVE_PROPERTY,
248
270
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
249
271
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
250
272
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -268,22 +290,28 @@ export class GridItemValidator extends CSSRuleValidator {
268
290
  ]);
269
291
  }
270
292
 
271
- isRuleValid(computedStyles: Map<String, String>|null, parentComputedStyles: Map<String, String>|null): boolean {
272
- if (parentComputedStyles === null) {
293
+ getMetricType(): Host.UserMetrics.CSSHintType {
294
+ return Host.UserMetrics.CSSHintType.GridItem;
295
+ }
296
+
297
+ #isRuleValid(computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): boolean {
298
+ if (!parentComputedStyles) {
273
299
  return true;
274
300
  }
275
301
  return isGridContainer(parentComputedStyles);
276
302
  }
277
303
 
278
- getAuthoringHint(
279
- property: string, computedStyles: Map<String, String>|null,
280
- parentComputedStyles: Map<String, String>|null): AuthoringHint {
281
- const reasonPropertyDeclaration = buildStyledRuleText('display', parentComputedStyles?.get('display'));
282
- const targeParentPropertyDeclaration = buildStyledRuleText('display', 'grid');
283
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
304
+ getHint(propertyName: string, computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): Hint
305
+ |undefined {
306
+ if (this.#isRuleValid(computedStyles, parentComputedStyles)) {
307
+ return;
308
+ }
309
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', parentComputedStyles?.get('display'));
310
+ const targeParentPropertyDeclaration = buildPropertyDefinitionText('display', 'grid');
311
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
284
312
 
285
- return new AuthoringHint(
286
- AuthoringHintType.INACTIVE_PROPERTY,
313
+ return new Hint(
314
+ HintType.INACTIVE_PROPERTY,
287
315
  i18nString(UIStrings.ruleViolatedByParentElementRuleReason, {
288
316
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
289
317
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -306,19 +334,27 @@ export class FlexGridValidator extends CSSRuleValidator {
306
334
  ]);
307
335
  }
308
336
 
309
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
337
+ getMetricType(): Host.UserMetrics.CSSHintType {
338
+ return Host.UserMetrics.CSSHintType.FlexGrid;
339
+ }
340
+
341
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
310
342
  if (computedStyles === null) {
311
343
  return true;
312
344
  }
313
345
  return isFlexContainer(computedStyles) || isGridContainer(computedStyles);
314
346
  }
315
347
 
316
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
317
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
318
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
348
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
349
+ if (this.#isRuleValid(computedStyles)) {
350
+ return;
351
+ }
352
+
353
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
354
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
319
355
 
320
- return new AuthoringHint(
321
- AuthoringHintType.INACTIVE_PROPERTY,
356
+ return new Hint(
357
+ HintType.INACTIVE_PROPERTY,
322
358
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
323
359
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
324
360
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -343,19 +379,27 @@ export class MulticolFlexGridValidator extends CSSRuleValidator {
343
379
  ]);
344
380
  }
345
381
 
346
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
382
+ getMetricType(): Host.UserMetrics.CSSHintType {
383
+ return Host.UserMetrics.CSSHintType.MulticolFlexGrid;
384
+ }
385
+
386
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
347
387
  if (computedStyles === null) {
348
388
  return true;
349
389
  }
350
390
  return isMulticolContainer(computedStyles) || isFlexContainer(computedStyles) || isGridContainer(computedStyles);
351
391
  }
352
392
 
353
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
354
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
355
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
393
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
394
+ if (this.#isRuleValid(computedStyles)) {
395
+ return;
396
+ }
356
397
 
357
- return new AuthoringHint(
358
- AuthoringHintType.INACTIVE_PROPERTY,
398
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
399
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
400
+
401
+ return new Hint(
402
+ HintType.INACTIVE_PROPERTY,
359
403
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
360
404
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
361
405
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -378,7 +422,11 @@ export class PaddingValidator extends CSSRuleValidator {
378
422
  ]);
379
423
  }
380
424
 
381
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
425
+ getMetricType(): Host.UserMetrics.CSSHintType {
426
+ return Host.UserMetrics.CSSHintType.Padding;
427
+ }
428
+
429
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
382
430
  const display = computedStyles?.get('display');
383
431
  if (display === null || display === undefined) {
384
432
  return true;
@@ -388,12 +436,16 @@ export class PaddingValidator extends CSSRuleValidator {
388
436
  .includes(display as string);
389
437
  }
390
438
 
391
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
392
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
393
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
439
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
440
+ if (this.#isRuleValid(computedStyles)) {
441
+ return;
442
+ }
443
+
444
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
445
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
394
446
 
395
- return new AuthoringHint(
396
- AuthoringHintType.INACTIVE_PROPERTY,
447
+ return new Hint(
448
+ HintType.INACTIVE_PROPERTY,
397
449
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
398
450
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
399
451
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -415,7 +467,11 @@ export class PositionValidator extends CSSRuleValidator {
415
467
  ]);
416
468
  }
417
469
 
418
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
470
+ getMetricType(): Host.UserMetrics.CSSHintType {
471
+ return Host.UserMetrics.CSSHintType.Position;
472
+ }
473
+
474
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
419
475
  const position = computedStyles?.get('position');
420
476
  if (position === null || position === undefined) {
421
477
  return true;
@@ -423,12 +479,16 @@ export class PositionValidator extends CSSRuleValidator {
423
479
  return position !== 'static';
424
480
  }
425
481
 
426
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
427
- const reasonPropertyDeclaration = buildStyledRuleText('position', computedStyles?.get('position'));
428
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
482
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
483
+ if (this.#isRuleValid(computedStyles)) {
484
+ return;
485
+ }
429
486
 
430
- return new AuthoringHint(
431
- AuthoringHintType.INACTIVE_PROPERTY,
487
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('position', computedStyles?.get('position'));
488
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
489
+
490
+ return new Hint(
491
+ HintType.INACTIVE_PROPERTY,
432
492
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
433
493
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
434
494
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -447,21 +507,29 @@ export class ZIndexValidator extends CSSRuleValidator {
447
507
  ]);
448
508
  }
449
509
 
450
- isRuleValid(computedStyles: Map<String, String>|null, parentComputedStyles: Map<String, String>|null): boolean {
510
+ getMetricType(): Host.UserMetrics.CSSHintType {
511
+ return Host.UserMetrics.CSSHintType.ZIndex;
512
+ }
513
+
514
+ #isRuleValid(computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): boolean {
451
515
  const position = computedStyles?.get('position');
452
516
  if (position === null || position === undefined) {
453
517
  return true;
454
518
  }
455
- return ['absolute', 'relative', 'fixed', 'sticky'].includes(position as string) ||
456
- isFlexContainer(parentComputedStyles);
519
+ return ['absolute', 'relative', 'fixed', 'sticky'].includes(position) || isFlexContainer(parentComputedStyles);
457
520
  }
458
521
 
459
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
460
- const reasonPropertyDeclaration = buildStyledRuleText('position', computedStyles?.get('position'));
461
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
522
+ getHint(propertyName: string, computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): Hint
523
+ |undefined {
524
+ if (this.#isRuleValid(computedStyles, parentComputedStyles)) {
525
+ return;
526
+ }
527
+
528
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('position', computedStyles?.get('position'));
529
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
462
530
 
463
- return new AuthoringHint(
464
- AuthoringHintType.INACTIVE_PROPERTY,
531
+ return new Hint(
532
+ HintType.INACTIVE_PROPERTY,
465
533
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
466
534
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
467
535
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -486,11 +554,11 @@ const CSS_RULE_VALIDATORS = [
486
554
  ZIndexValidator,
487
555
  ];
488
556
 
489
- const setupCSSRulesValidators = (): Map<String, CSSRuleValidator[]> => {
490
- const validatorsMap = new Map<String, CSSRuleValidator[]>();
557
+ const setupCSSRulesValidators = (): Map<string, CSSRuleValidator[]> => {
558
+ const validatorsMap = new Map<string, CSSRuleValidator[]>();
491
559
  for (const validatorClass of CSS_RULE_VALIDATORS) {
492
560
  const validator = new validatorClass();
493
- const affectedProperties = validator.getAffectedProperties();
561
+ const affectedProperties = validator.getApplicableProperties();
494
562
 
495
563
  for (const affectedProperty of affectedProperties) {
496
564
  let propertyValidators = validatorsMap.get(affectedProperty);
@@ -505,4 +573,4 @@ const setupCSSRulesValidators = (): Map<String, CSSRuleValidator[]> => {
505
573
  return validatorsMap;
506
574
  };
507
575
 
508
- export const cssRuleValidatorsMap: Map<String, CSSRuleValidator[]> = setupCSSRulesValidators();
576
+ export const cssRuleValidatorsMap: Map<string, CSSRuleValidator[]> = setupCSSRulesValidators();
@@ -2,31 +2,37 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
- export const buildStyledRuleText = (property: String, value: String|undefined): string => {
5
+ export const buildPropertyDefinitionText = (property: string, value?: string): string => {
6
6
  if (value === undefined) {
7
- return buildStyledPropertyText(property);
7
+ return buildPropertyText(property);
8
8
  }
9
9
  return '<code class="unbreakable-text"><span class="property">' + property + '</span>: ' + value + '</code>';
10
10
  };
11
11
 
12
- export const buildStyledPropertyText = (property: String): string => {
12
+ export const buildPropertyText = (property: string): string => {
13
13
  return '<code class="unbreakable-text"><span class="property">' + property + '</span></code>';
14
14
  };
15
15
 
16
- export const isFlexContainer = (computedStyles: Map<String, String>|null): boolean => {
17
- if (computedStyles === null) {
16
+ export const isFlexContainer = (computedStyles?: Map<string, string>): boolean => {
17
+ if (!computedStyles) {
18
18
  return false;
19
19
  }
20
20
  const display = computedStyles.get('display');
21
21
  return display === 'flex' || display === 'inline-flex';
22
22
  };
23
23
 
24
- export const isGridContainer = (computedStyles: Map<String, String>): boolean => {
24
+ export const isGridContainer = (computedStyles?: Map<string, string>): boolean => {
25
+ if (!computedStyles) {
26
+ return false;
27
+ }
25
28
  const display = computedStyles.get('display');
26
29
  return display === 'grid' || display === 'inline-grid';
27
30
  };
28
31
 
29
- export const isMulticolContainer = (computedStyles: Map<String, String>): boolean => {
32
+ export const isMulticolContainer = (computedStyles?: Map<string, string>): boolean => {
33
+ if (!computedStyles) {
34
+ return false;
35
+ }
30
36
  const columnWidth = computedStyles.get('column-width');
31
37
  const columnCount = computedStyles.get('column-count');
32
38
 
@@ -290,6 +290,14 @@ export class StylePropertiesSection {
290
290
  this.onpopulate();
291
291
  }
292
292
 
293
+ setComputedStyles(computedStyles: Map<string, string>|null): void {
294
+ this.computedStyles = computedStyles;
295
+ }
296
+
297
+ setParentsComputedStyles(parentsComputedStyles: Map<string, string>|null): void {
298
+ this.parentsComputedStyles = parentsComputedStyles;
299
+ }
300
+
293
301
  setSectionIdx(sectionIdx: number): void {
294
302
  this.sectionIdx = sectionIdx;
295
303
  this.onpopulate();
@@ -21,12 +21,12 @@ import {StyleEditorWidget} from './StyleEditorWidget.js';
21
21
  import {type StylePropertiesSection} from './StylePropertiesSection.js';
22
22
  import {CSSPropertyPrompt, StylesSidebarPane, StylesSidebarPropertyRenderer} from './StylesSidebarPane.js';
23
23
  import {getCssDeclarationAsJavascriptProperty} from './StylePropertyUtils.js';
24
- import {cssRuleValidatorsMap, type AuthoringHint} from './CSSRuleValidator.js';
24
+ import {cssRuleValidatorsMap, type Hint} from './CSSRuleValidator.js';
25
25
 
26
26
  const FlexboxEditor = ElementsComponents.StylePropertyEditor.FlexboxEditor;
27
27
  const GridEditor = ElementsComponents.StylePropertyEditor.GridEditor;
28
28
 
29
- export const activeHints = new WeakMap<Element, AuthoringHint>();
29
+ export const activeHints = new WeakMap<Element, Hint>();
30
30
 
31
31
  const UIStrings = {
32
32
  /**
@@ -717,23 +717,16 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
717
717
  }
718
718
  }
719
719
 
720
- const authoringHint = this.getAuthoringHint(this.computedStyles, this.parentsComputedStyles);
721
- const showAuthoringHint = authoringHint !== null && this.property.parsedOk;
722
- if (showAuthoringHint) {
723
- const hintIcon = UI.Icon.Icon.create('mediumicon-info', 'hint');
724
- activeHints.set(hintIcon, authoringHint);
725
- this.listItemElement.append(hintIcon);
726
- }
727
-
728
- if (!this.property.parsedOk) {
720
+ if (this.property.parsedOk) {
721
+ void this.updateFontVariationSettingsWarning();
722
+ this.updateAuthoringHint();
723
+ } else {
729
724
  // Avoid having longhands under an invalid shorthand.
730
725
  this.listItemElement.classList.add('not-parsed-ok');
731
726
 
732
727
  // Add a separate exclamation mark IMG element with a tooltip.
733
728
  this.listItemElement.insertBefore(
734
729
  StylesSidebarPane.createExclamationMark(this.property, null), this.listItemElement.firstChild);
735
- } else {
736
- void this.updateFontVariationSettingsWarning();
737
730
  }
738
731
 
739
732
  if (!this.property.activeInStyle()) {
@@ -768,6 +761,35 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
768
761
  }
769
762
  }
770
763
 
764
+ private updateAuthoringHint(): void {
765
+ if (!Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.CSS_AUTHORING_HINTS)) {
766
+ return;
767
+ }
768
+
769
+ const existingElement = this.listItemElement.querySelector('.hint');
770
+ if (existingElement) {
771
+ activeHints.delete(existingElement);
772
+ existingElement.parentElement?.removeChild(existingElement);
773
+ }
774
+ const propertyName = this.property.name;
775
+
776
+ if (!cssRuleValidatorsMap.has(propertyName)) {
777
+ return;
778
+ }
779
+
780
+ for (const validator of cssRuleValidatorsMap.get(propertyName) || []) {
781
+ const hint =
782
+ validator.getHint(propertyName, this.computedStyles || undefined, this.parentsComputedStyles || undefined);
783
+ if (hint) {
784
+ Host.userMetrics.cssHintShown(validator.getMetricType());
785
+ const hintIcon = UI.Icon.Icon.create('mediumicon-info', 'hint');
786
+ activeHints.set(hintIcon, hint);
787
+ this.listItemElement.append(hintIcon);
788
+ break;
789
+ }
790
+ }
791
+ }
792
+
771
793
  private async updateFontVariationSettingsWarning(): Promise<void> {
772
794
  if (this.property.name !== 'font-variation-settings') {
773
795
  return;
@@ -816,24 +838,6 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
816
838
  StylesSidebarPane.createExclamationMark(this.property, warnings.join(' ')), this.listItemElement.firstChild);
817
839
  }
818
840
 
819
- private getAuthoringHint(computedStyles: Map<string, string>|null, parentComputedStyles: Map<string, string>|null):
820
- AuthoringHint|null {
821
- const propertyName = this.property.name;
822
-
823
- if (!Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.CSS_AUTHORING_HINTS) ||
824
- !cssRuleValidatorsMap.has(propertyName)) {
825
- return null;
826
- }
827
-
828
- for (const validator of cssRuleValidatorsMap.get(propertyName) || []) {
829
- if (!validator.isRuleValid(computedStyles, parentComputedStyles)) {
830
- return validator.getAuthoringHint(propertyName, this.computedStyles, this.parentsComputedStyles);
831
- }
832
- }
833
-
834
- return null;
835
- }
836
-
837
841
  private mouseUp(event: MouseEvent): void {
838
842
  const activeTreeElement = parentMap.get(this.parentPaneInternal);
839
843
  parentMap.delete(this.parentPaneInternal);
@@ -218,6 +218,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
218
218
  #urlToChangeTracker: Map<Platform.DevToolsPath.UrlString, ChangeTracker> = new Map();
219
219
  #copyChangesButton?: UI.Toolbar.ToolbarButton;
220
220
  #updateAbortController?: AbortController;
221
+ #updateComputedStylesAbortController?: AbortController;
221
222
 
222
223
  static instance(): StylesSidebarPane {
223
224
  if (!stylesSidebarPaneInstance) {
@@ -753,10 +754,12 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
753
754
  for (const section of this.allSections()) {
754
755
  section.styleSheetEdited(edit);
755
756
  }
757
+ void this.refreshComputedStyles();
756
758
  return;
757
759
  }
758
760
 
759
761
  if (this.userOperation || this.isEditingStyle) {
762
+ void this.refreshComputedStyles();
760
763
  return;
761
764
  }
762
765
 
@@ -764,6 +767,27 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
764
767
  this.update();
765
768
  }
766
769
 
770
+ async refreshComputedStyles(): Promise<void> {
771
+ this.#updateComputedStylesAbortController?.abort();
772
+ this.#updateAbortController = new AbortController();
773
+ const signal = this.#updateAbortController.signal;
774
+ const matchedStyles = await this.fetchMatchedCascade();
775
+ const nodeId = this.node()?.id;
776
+ const parentNodeId = matchedStyles?.getParentLayoutNodeId();
777
+
778
+ const [computedStyles, parentsComputedStyles] =
779
+ await Promise.all([this.fetchComputedStylesFor(nodeId), this.fetchComputedStylesFor(parentNodeId)]);
780
+
781
+ if (signal.aborted) {
782
+ return;
783
+ }
784
+
785
+ for (const section of this.allSections()) {
786
+ section.setComputedStyles(computedStyles);
787
+ section.setParentsComputedStyles(parentsComputedStyles);
788
+ }
789
+ }
790
+
767
791
  focusedSectionIndex(): number {
768
792
  let index = 0;
769
793
  for (const block of this.sectionBlocks) {
@@ -20,10 +20,10 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
20
20
  const {render, html, Directives} = LitHtml;
21
21
 
22
22
  interface Hint {
23
- getHintPrefix(): string;
24
- getHintMessage(): string;
25
- getPossibleFixMessage(): string|null;
26
- getLearnMoreLink(): string|undefined;
23
+ getPrefix(): string;
24
+ getMessage(): string;
25
+ getPossibleFixMessage(): string|null;
26
+ getLearnMoreLink(): string|undefined;
27
27
  }
28
28
 
29
29
  export class CSSHintDetailsView extends HTMLElement {
@@ -44,7 +44,7 @@ export class CSSHintDetailsView extends HTMLElement {
44
44
  render(html`
45
45
  <div class="hint-popup-wrapper">
46
46
  <div class="hint-popup-reason">
47
- <strong>${this.#authoringHint.getHintPrefix()}:</strong> ${Directives.unsafeHTML(this.#authoringHint.getHintMessage())}
47
+ <strong>${this.#authoringHint.getPrefix()}:</strong> ${Directives.unsafeHTML(this.#authoringHint.getMessage())}
48
48
  </div>
49
49
  ${this.#authoringHint.getPossibleFixMessage() ? html`
50
50
  <div class="hint-popup-possible-fix">
@@ -267,7 +267,7 @@ export class LayoutPane extends HTMLElement {
267
267
  } as NodeText.NodeText.NodeTextData}></${NodeText.NodeText.NodeText.litTagName}>
268
268
  </span>
269
269
  </label>
270
- <label @keyup=${onColorLabelKeyUp} @keydown=${onColorLabelKeyDown} tabindex="0" title=${i18nString(UIStrings.chooseElementOverlayColor)} class="color-picker-label" style="background: ${element.color};">
270
+ <label @keyup=${onColorLabelKeyUp} @keydown=${onColorLabelKeyDown} tabindex="0" title=${i18nString(UIStrings.chooseElementOverlayColor)} aria-label=${i18nString(UIStrings.chooseElementOverlayColor)} class="color-picker-label" style="background: ${element.color};">
271
271
  <input @change=${onColorChange} @input=${onColorChange} tabindex="-1" class="color-picker" type="color" value=${element.color} />
272
272
  </label>
273
273
  <button tabindex="0" @click=${onElementClick} title=${i18nString(UIStrings.showElementInTheElementsPanel)} class="show-element"></button>
@@ -63,6 +63,7 @@ export class ProtocolService {
63
63
  private parallelConnection?: ProtocolClient.InspectorBackend.Connection;
64
64
  private lighthouseWorkerPromise?: Promise<Worker>;
65
65
  private lighthouseMessageUpdateCallback?: ((arg0: string) => void);
66
+ private configForTesting?: Object;
66
67
 
67
68
  async attach(): Promise<void> {
68
69
  await SDK.TargetManager.TargetManager.instance().suspendAllTargets();
@@ -113,6 +114,7 @@ export class ProtocolService {
113
114
  url: inspectedURL,
114
115
  categoryIDs,
115
116
  flags,
117
+ config: this.configForTesting,
116
118
  locales: this.getLocales(),
117
119
  target: this.targetInfo,
118
120
  });
@@ -134,6 +136,7 @@ export class ProtocolService {
134
136
  url: inspectedURL,
135
137
  categoryIDs,
136
138
  flags,
139
+ config: this.configForTesting,
137
140
  locales: this.getLocales(),
138
141
  target: this.targetInfo,
139
142
  });
@@ -178,7 +181,7 @@ export class ProtocolService {
178
181
  method?: string,
179
182
  };
180
183
  if (protocolMessage.sessionId || (protocolMessage.method && protocolMessage.method.startsWith('Target'))) {
181
- void this.send('dispatchProtocolMessage', {message: JSON.stringify(message)});
184
+ void this.send('dispatchProtocolMessage', {message});
182
185
  }
183
186
  }
184
187
 
@@ -215,7 +218,7 @@ export class ProtocolService {
215
218
  }
216
219
 
217
220
  private onWorkerMessage(event: MessageEvent): void {
218
- const lighthouseMessage = JSON.parse(event.data);
221
+ const lighthouseMessage = event.data;
219
222
 
220
223
  if (lighthouseMessage.action === 'statusUpdate') {
221
224
  if (this.lighthouseMessageUpdateCallback && lighthouseMessage.args && 'message' in lighthouseMessage.args) {
@@ -237,17 +240,17 @@ export class ProtocolService {
237
240
  private async send(action: string, args: {[x: string]: string|string[]|Object} = {}): Promise<void> {
238
241
  const worker = await this.ensureWorkerExists();
239
242
  const messageId = lastId++;
240
- worker.postMessage(JSON.stringify({id: messageId, action, args: {...args, id: messageId}}));
243
+ worker.postMessage({id: messageId, action, args: {...args, id: messageId}});
241
244
  }
242
245
 
243
246
  /** sendWithResponse currently only handles the original startLighthouse request and LHR-filled response. */
244
- private async sendWithResponse(action: string, args: {[x: string]: string|string[]|Object} = {}):
247
+ private async sendWithResponse(action: string, args: {[x: string]: string|string[]|Object|undefined} = {}):
245
248
  Promise<ReportRenderer.RunnerResult> {
246
249
  const worker = await this.ensureWorkerExists();
247
250
  const messageId = lastId++;
248
251
  const messageResult = new Promise<ReportRenderer.RunnerResult>(resolve => {
249
252
  const workerListener = (event: MessageEvent): void => {
250
- const lighthouseMessage = JSON.parse(event.data);
253
+ const lighthouseMessage = event.data;
251
254
 
252
255
  if (lighthouseMessage.id === messageId) {
253
256
  worker.removeEventListener('message', workerListener);
@@ -256,7 +259,7 @@ export class ProtocolService {
256
259
  };
257
260
  worker.addEventListener('message', workerListener);
258
261
  });
259
- worker.postMessage(JSON.stringify({id: messageId, action, args: {...args, id: messageId}}));
262
+ worker.postMessage({id: messageId, action, args: {...args, id: messageId}});
260
263
 
261
264
  return messageResult;
262
265
  }
package/package.json CHANGED
@@ -56,5 +56,5 @@
56
56
  "unittest": "scripts/test/run_unittests.py --no-text-coverage",
57
57
  "watch": "vpython third_party/node/node.py --output scripts/watch_build.js"
58
58
  },
59
- "version": "1.0.1033742"
59
+ "version": "1.0.1034881"
60
60
  }