lighthouse 9.5.0-dev.20220813 → 9.5.0-dev.20220816

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 (105) hide show
  1. package/cli/commands/list-locales.js +1 -1
  2. package/cli/run.js +13 -0
  3. package/core/config/config-helpers.js +0 -15
  4. package/core/config/config.js +1 -1
  5. package/core/config/constants.js +1 -0
  6. package/core/config/default-config.js +0 -2
  7. package/core/fraggle-rock/api.js +1 -1
  8. package/core/fraggle-rock/config/config.js +12 -13
  9. package/core/fraggle-rock/gather/navigation-runner.js +17 -26
  10. package/core/fraggle-rock/gather/snapshot-runner.js +4 -5
  11. package/core/fraggle-rock/gather/timespan-runner.js +4 -5
  12. package/core/fraggle-rock/replay/stringify-extension.js +105 -0
  13. package/core/fraggle-rock/user-flow.js +10 -12
  14. package/core/gather/driver/execution-context.js +19 -2
  15. package/core/gather/gather-runner.js +1 -1
  16. package/core/index.js +2 -5
  17. package/core/lib/asset-saver.js +2 -2
  18. package/core/lib/cdt/generated/SourceMap.js +113 -27
  19. package/core/lib/deprecations-strings.js +74 -10
  20. package/core/lib/network-request.js +1 -0
  21. package/core/lib/page-functions.js +15 -3
  22. package/core/lib/traces/{pwmetrics-events.js → metric-trace-events.js} +3 -4
  23. package/core/runner.js +2 -2
  24. package/dist/report/bundle.esm.js +1 -14
  25. package/dist/report/flow.js +28 -27
  26. package/dist/report/standalone.js +4 -4
  27. package/flow-report/test/flow-report-pptr-test.ts +1 -1
  28. package/package.json +6 -5
  29. package/report/generator/file-namer.js +5 -1
  30. package/report/generator/flow-report-assets.js +10 -6
  31. package/report/generator/report-assets.js +8 -5
  32. package/report/generator/report-generator.js +7 -7
  33. package/report/generator/tsconfig.json +1 -0
  34. package/report/test/generator/file-namer-test.js +2 -2
  35. package/report/test/generator/report-generator-test.js +8 -9
  36. package/report/test/renderer/report-renderer-axe-test.js +2 -2
  37. package/report/test/renderer/report-ui-features-test.js +1 -1
  38. package/shared/localization/format.js +11 -13
  39. package/shared/localization/i18n-module.js +7 -2
  40. package/shared/localization/locales/ar-XB.json +0 -21
  41. package/shared/localization/locales/ar.json +0 -21
  42. package/shared/localization/locales/bg.json +0 -21
  43. package/shared/localization/locales/ca.json +0 -21
  44. package/shared/localization/locales/cs.json +0 -21
  45. package/shared/localization/locales/da.json +0 -21
  46. package/shared/localization/locales/de.json +0 -21
  47. package/shared/localization/locales/el.json +0 -21
  48. package/shared/localization/locales/en-GB.json +0 -21
  49. package/shared/localization/locales/en-US.json +13 -22
  50. package/shared/localization/locales/en-XA.json +0 -21
  51. package/shared/localization/locales/en-XL.json +13 -22
  52. package/shared/localization/locales/es-419.json +0 -21
  53. package/shared/localization/locales/es.json +0 -21
  54. package/shared/localization/locales/fi.json +0 -21
  55. package/shared/localization/locales/fil.json +0 -21
  56. package/shared/localization/locales/fr.json +0 -21
  57. package/shared/localization/locales/he.json +0 -21
  58. package/shared/localization/locales/hi.json +0 -21
  59. package/shared/localization/locales/hr.json +0 -21
  60. package/shared/localization/locales/hu.json +0 -21
  61. package/shared/localization/locales/id.json +0 -21
  62. package/shared/localization/locales/it.json +0 -21
  63. package/shared/localization/locales/ja.json +0 -21
  64. package/shared/localization/locales/ko.json +0 -21
  65. package/shared/localization/locales/lt.json +0 -21
  66. package/shared/localization/locales/lv.json +0 -21
  67. package/shared/localization/locales/nl.json +0 -21
  68. package/shared/localization/locales/no.json +0 -21
  69. package/shared/localization/locales/pl.json +0 -21
  70. package/shared/localization/locales/pt-PT.json +0 -21
  71. package/shared/localization/locales/pt.json +0 -21
  72. package/shared/localization/locales/ro.json +0 -21
  73. package/shared/localization/locales/ru.json +0 -21
  74. package/shared/localization/locales/sk.json +0 -21
  75. package/shared/localization/locales/sl.json +0 -21
  76. package/shared/localization/locales/sr-Latn.json +0 -21
  77. package/shared/localization/locales/sr.json +0 -21
  78. package/shared/localization/locales/sv.json +0 -21
  79. package/shared/localization/locales/ta.json +0 -21
  80. package/shared/localization/locales/te.json +0 -21
  81. package/shared/localization/locales/th.json +0 -21
  82. package/shared/localization/locales/tr.json +0 -21
  83. package/shared/localization/locales/uk.json +0 -21
  84. package/shared/localization/locales/vi.json +0 -21
  85. package/shared/localization/locales/zh-HK.json +0 -21
  86. package/shared/localization/locales/zh-TW.json +0 -21
  87. package/shared/localization/locales/zh.json +0 -21
  88. package/shared/localization/locales.js +53 -50
  89. package/shared/localization/swap-flow-locale.js +6 -2
  90. package/shared/localization/swap-locale.js +4 -4
  91. package/shared/test/localization/format-test.js +17 -20
  92. package/shared/test/localization/locales-test.js +2 -2
  93. package/shared/test/localization/swap-locale-test.js +3 -2
  94. package/shared/tsconfig.json +1 -0
  95. package/shared/type-verifiers.js +1 -1
  96. package/tsconfig.json +1 -5
  97. package/types/config.d.ts +0 -13
  98. package/types/externs.d.ts +1 -1
  99. package/types/lhr/settings.d.ts +2 -0
  100. package/types/user-flow.d.ts +1 -1
  101. package/core/audits/dobetterweb/no-vulnerable-libraries.js +0 -229
  102. package/report/generator/package.json +0 -4
  103. package/report/test/generator/package.json +0 -4
  104. package/shared/package.json +0 -4
  105. package/third-party/snyk/snapshot.json +0 -182
@@ -56,6 +56,8 @@ class SourceMapV3 {
56
56
  sourceRoot;
57
57
  names;
58
58
  sourcesContent;
59
+ // eslint-disable-next-line @typescript-eslint/naming-convention
60
+ x_google_ignoreList;
59
61
  constructor() {
60
62
  }
61
63
  }
@@ -153,6 +155,38 @@ class TextSourceMap {
153
155
  const index = Platform.ArrayUtilities.upperBound(mappings, undefined, (unused, entry) => lineNumber - entry.lineNumber || columnNumber - entry.columnNumber);
154
156
  return index ? mappings[index - 1] : null;
155
157
  }
158
+ findEntryRanges(lineNumber, columnNumber) {
159
+ const mappings = this.mappings();
160
+ const index = Platform.ArrayUtilities.upperBound(mappings, undefined, (unused, entry) => lineNumber - entry.lineNumber || columnNumber - entry.columnNumber);
161
+ if (!index) {
162
+ // If the line and column are preceding all the entries, then there is nothing to map.
163
+ return null;
164
+ }
165
+ const sourceURL = mappings[index].sourceURL;
166
+ if (!sourceURL) {
167
+ return null;
168
+ }
169
+ // Let us compute the range that contains the source position in the compiled code.
170
+ const endLine = index < mappings.length ? mappings[index].lineNumber : 2 ** 31 - 1;
171
+ const endColumn = index < mappings.length ? mappings[index].columnNumber : 2 ** 31 - 1;
172
+ const range = new TextUtils.TextRange.TextRange(mappings[index - 1].lineNumber, mappings[index - 1].columnNumber, endLine, endColumn);
173
+ // Now try to find the corresponding token in the original code.
174
+ const reverseMappings = this.reversedMappings(sourceURL);
175
+ const startSourceLine = mappings[index - 1].sourceLineNumber;
176
+ const startSourceColumn = mappings[index - 1].sourceColumnNumber;
177
+ const endReverseIndex = Platform.ArrayUtilities.upperBound(reverseMappings, undefined, (unused, i) => startSourceLine - mappings[i].sourceLineNumber || startSourceColumn - mappings[i].sourceColumnNumber);
178
+ if (!endReverseIndex) {
179
+ return null;
180
+ }
181
+ const endSourceLine = endReverseIndex < reverseMappings.length ?
182
+ mappings[reverseMappings[endReverseIndex]].sourceLineNumber :
183
+ 2 ** 31 - 1;
184
+ const endSourceColumn = endReverseIndex < reverseMappings.length ?
185
+ mappings[reverseMappings[endReverseIndex]].sourceColumnNumber :
186
+ 2 ** 31 - 1;
187
+ const sourceRange = new TextUtils.TextRange.TextRange(startSourceLine, startSourceColumn, endSourceLine, endSourceColumn);
188
+ return { range, sourceRange, sourceURL };
189
+ }
156
190
  sourceLineMapping(sourceURL, lineNumber, columnNumber) {
157
191
  const mappings = this.mappings();
158
192
  const reverseMappings = this.reversedMappings(sourceURL);
@@ -219,37 +253,48 @@ class TextSourceMap {
219
253
  }
220
254
  /** @return {Array<{lineNumber: number, columnNumber: number, sourceURL?: string, sourceLineNumber: number, sourceColumnNumber: number, name?: string, lastColumnNumber?: number}>} */
221
255
  mappings() {
256
+ this.#ensureMappingsProcessed();
257
+ return this.#mappingsInternal ?? [];
258
+ }
259
+ reversedMappings(sourceURL) {
260
+ this.#ensureMappingsProcessed();
261
+ return this.#sourceInfos.get(sourceURL)?.reverseMappings ?? [];
262
+ }
263
+ #ensureMappingsProcessed() {
222
264
  if (this.#mappingsInternal === null) {
223
265
  this.#mappingsInternal = [];
224
266
  this.eachSection(this.parseMap.bind(this));
267
+ this.#computeReverseMappings(this.#mappingsInternal);
225
268
  this.#json = null;
226
269
  }
227
- return this.#mappingsInternal;
228
270
  }
229
- reversedMappings(sourceURL) {
230
- const info = this.#sourceInfos.get(sourceURL);
231
- if (!info) {
232
- return [];
271
+ #computeReverseMappings(mappings) {
272
+ const reverseMappingsPerUrl = new Map();
273
+ for (let i = 0; i < mappings.length; i++) {
274
+ const entryUrl = mappings[i].sourceURL;
275
+ if (!entryUrl) {
276
+ continue;
277
+ }
278
+ let reverseMap = reverseMappingsPerUrl.get(entryUrl);
279
+ if (!reverseMap) {
280
+ reverseMap = [];
281
+ reverseMappingsPerUrl.set(entryUrl, reverseMap);
282
+ }
283
+ reverseMap.push(i);
233
284
  }
234
- const mappings = this.mappings();
235
- if (info.reverseMappings === null) {
236
- const indexes = Array(mappings.length).fill(0).map((_, i) => i);
237
- info.reverseMappings = indexes.filter(i => mappings[i].sourceURL === sourceURL).sort(sourceMappingComparator);
285
+ for (const [url, reverseMap] of reverseMappingsPerUrl.entries()) {
286
+ const info = this.#sourceInfos.get(url);
287
+ if (!info) {
288
+ continue;
289
+ }
290
+ reverseMap.sort(sourceMappingComparator);
291
+ info.reverseMappings = reverseMap;
238
292
  }
239
- return info.reverseMappings;
240
293
  function sourceMappingComparator(indexA, indexB) {
241
294
  const a = mappings[indexA];
242
295
  const b = mappings[indexB];
243
- if (a.sourceLineNumber !== b.sourceLineNumber) {
244
- return a.sourceLineNumber - b.sourceLineNumber;
245
- }
246
- if (a.sourceColumnNumber !== b.sourceColumnNumber) {
247
- return a.sourceColumnNumber - b.sourceColumnNumber;
248
- }
249
- if (a.lineNumber !== b.lineNumber) {
250
- return a.lineNumber - b.lineNumber;
251
- }
252
- return a.columnNumber - b.columnNumber;
296
+ return a.sourceLineNumber - b.sourceLineNumber || a.sourceColumnNumber - b.sourceColumnNumber ||
297
+ a.lineNumber - b.lineNumber || a.columnNumber - b.columnNumber;
253
298
  }
254
299
  }
255
300
  eachSection(callback) {
@@ -267,6 +312,7 @@ class TextSourceMap {
267
312
  parseSources(sourceMap) {
268
313
  const sourcesList = [];
269
314
  const sourceRoot = sourceMap.sourceRoot || Platform.DevToolsPath.EmptyUrlString;
315
+ const ignoreList = new Set(sourceMap.x_google_ignoreList);
270
316
  for (let i = 0; i < sourceMap.sources.length; ++i) {
271
317
  let href = sourceMap.sources[i];
272
318
  // The source map v3 proposal says to prepend the sourceRoot to the source URL
@@ -286,11 +332,12 @@ class TextSourceMap {
286
332
  const source = sourceMap.sourcesContent && sourceMap.sourcesContent[i];
287
333
  if (url === this.#compiledURLInternal && source) {
288
334
  }
289
- if (this.#sourceInfos.has(url)) {
290
- continue;
291
- }
292
- this.#sourceInfos.set(url, new TextSourceMap.SourceInfo(source || null, null));
293
335
  sourcesList.push(url);
336
+ if (!this.#sourceInfos.has(url)) {
337
+ const content = source ?? null;
338
+ const ignoreListHint = ignoreList.has(i);
339
+ this.#sourceInfos.set(url, new TextSourceMap.SourceInfo(content, ignoreListHint));
340
+ }
294
341
  }
295
342
  sourceMapToSourceList.set(sourceMap, sourcesList);
296
343
  }
@@ -394,6 +441,44 @@ class TextSourceMap {
394
441
  }
395
442
  return false;
396
443
  }
444
+ hasIgnoreListHint(sourceURL) {
445
+ return this.#sourceInfos.get(sourceURL)?.ignoreListHint ?? false;
446
+ }
447
+ /**
448
+ * Returns a list of ranges in the generated script for original sources that
449
+ * match a predicate. Each range is a [begin, end) pair, meaning that code at
450
+ * the beginning location, up to but not including the end location, matches
451
+ * the predicate.
452
+ */
453
+ findRanges(predicate, options) {
454
+ const mappings = this.mappings();
455
+ const ranges = [];
456
+ if (!mappings.length) {
457
+ return [];
458
+ }
459
+ let current = null;
460
+ // If the first mapping isn't at the beginning of the original source, it's
461
+ // up to the caller to decide if it should be considered matching the
462
+ // predicate or not. By default, it's not.
463
+ if ((mappings[0].lineNumber !== 0 || mappings[0].columnNumber !== 0) && options?.isStartMatching) {
464
+ current = TextUtils.TextRange.TextRange.createUnboundedFromLocation(0, 0);
465
+ ranges.push(current);
466
+ }
467
+ for (const { sourceURL, lineNumber, columnNumber } of mappings) {
468
+ const ignoreListHint = sourceURL && predicate(sourceURL);
469
+ if (!current && ignoreListHint) {
470
+ current = TextUtils.TextRange.TextRange.createUnboundedFromLocation(lineNumber, columnNumber);
471
+ ranges.push(current);
472
+ continue;
473
+ }
474
+ if (current && !ignoreListHint) {
475
+ current.endLine = lineNumber;
476
+ current.endColumn = columnNumber;
477
+ current = null;
478
+ }
479
+ }
480
+ return ranges;
481
+ }
397
482
  }
398
483
  exports.TextSourceMap = TextSourceMap;
399
484
  (function (TextSourceMap) {
@@ -426,10 +511,11 @@ exports.TextSourceMap = TextSourceMap;
426
511
  TextSourceMap.StringCharIterator = StringCharIterator;
427
512
  class SourceInfo {
428
513
  content;
429
- reverseMappings;
430
- constructor(content, reverseMappings) {
514
+ ignoreListHint;
515
+ reverseMappings = null;
516
+ constructor(content, ignoreListHint) {
431
517
  this.content = content;
432
- this.reverseMappings = reverseMappings;
518
+ this.ignoreListHint = ignoreListHint;
433
519
  }
434
520
  }
435
521
  TextSourceMap.SourceInfo = SourceInfo;
@@ -19,9 +19,14 @@ const UIStrings = {
19
19
  */
20
20
  title: 'Deprecated Feature Used',
21
21
 
22
- // Store alphabetized messages per DeprecationIssueType in this block.
23
22
  /**
24
- * @description TODO(crbug.com/1318846): Description needed for translation
23
+ * @description We show this warning when 1) an "authorization" header is
24
+ * attached to the request by scripts, 2) there is no "authorization" in
25
+ * the "access-control-allow-headers" header in the response, and 3) there
26
+ * is a wildcard symbol ("*") in the "access-control-allow-header" header
27
+ * in the response. This is allowed now, but we're planning to reject such
28
+ * responses and require responses to have an "access-control-allow-headers"
29
+ * containing "authorization".
25
30
  */
26
31
  authorizationCoveredByWildcard:
27
32
  'Authorization will not be covered by the wildcard symbol (*) in CORS `Access-Control-Allow-Headers` handling.',
@@ -69,7 +74,9 @@ const UIStrings = {
69
74
  */
70
75
  crossOriginWindowApi: 'Triggering {PH1} from cross origin iframes has been deprecated and will be removed in the future.',
71
76
  /**
72
- * @description TODO(crbug.com/1320339): Description needed for translation
77
+ * @description Warning displayed to developers when they hide the Cast button
78
+ * on a video element using the deprecated CSS selector instead of using the
79
+ * disableRemotePlayback attribute on the element.
73
80
  */
74
81
  cssSelectorInternalMediaControlsOverlayCastButton:
75
82
  'The `disableRemotePlayback` attribute should be used in order to disable the default Cast integration instead of using `-internal-media-controls-overlay-cast-button` selector.',
@@ -89,6 +96,10 @@ const UIStrings = {
89
96
  * @description Warning displayed to developers when the non-standard `Event.path` API is used to notify them that this API is deprecated.
90
97
  */
91
98
  eventPath: '`Event.path` is deprecated and will be removed. Please use `Event.composedPath()` instead.',
99
+ /**
100
+ * @description This message is shown when the deprecated Expect-CT header is present.
101
+ */
102
+ expectCTHeader: 'The `Expect-CT` header is deprecated and will be removed. Chrome requires Certificate Transparency for all publicly trusted certificates issued after April 30, 2018.',
92
103
  /**
93
104
  * @description Warning displayed to developers when the Geolocation API is used from an insecure origin (one that isn't localhost or doesn't use HTTPS) to notify them that this use is no longer supported.
94
105
  */
@@ -109,6 +120,12 @@ const UIStrings = {
109
120
  */
110
121
  hostCandidateAttributeGetter:
111
122
  '`RTCPeerConnectionIceErrorEvent.hostCandidate` is deprecated. Please use `RTCPeerConnectionIceErrorEvent.address` or `RTCPeerConnectionIceErrorEvent.port` instead.',
123
+ /**
124
+ * @description A deprecation warning shown in the DevTools Issues tab,
125
+ * when a service worker reads one of the fields from an event named
126
+ * "canmakepayment".
127
+ */
128
+ identityInCanMakePaymentEvent: 'The merchant origin and arbitrary data from the `canmakepayment` service worker event are deprecated and will be removed: `topOrigin`, `paymentRequestOrigin`, `methodData`, `modifiers`.',
112
129
  /**
113
130
  * @description TODO(crbug.com/1320343): Description needed for translation
114
131
  */
@@ -156,6 +173,16 @@ const UIStrings = {
156
173
  */
157
174
  obsoleteWebRtcCipherSuite:
158
175
  'Your partner is negotiating an obsolete (D)TLS version. Please check with your partner to have this fixed.',
176
+ /**
177
+ * @description Warning displayed to developers when `window.openDatabase` is used in non-secure contexts to notify that the API is deprecated and will be removed.
178
+ */
179
+ openWebDatabaseInsecureContext:
180
+ 'WebSQL in non-secure contexts is deprecated and will be removed in M107. Please use Web Storage or Indexed Database.',
181
+ /**
182
+ * @description Warning displayed to developers when persistent storage type is used to notify that storage type is deprecated.
183
+ */
184
+ persistentQuotaType:
185
+ '`StorageType.persistent` is deprecated. Please use standardized `navigator.storage` instead.',
159
186
  /**
160
187
  * @description This issue indicates that a `<source>` element with a `<picture>` parent was using an `src` attribute, which is not valid and is ignored by the browser. The `srcset` attribute should be used instead.
161
188
  */
@@ -172,7 +199,7 @@ const UIStrings = {
172
199
  * @description Warning displayed to developers when `window.webkitStorageInfo` is used to notify that the API is deprecated.
173
200
  */
174
201
  prefixedStorageInfo:
175
- '`window.webkitStorageInfo` is deprecated. Please use `navigator.webkitTemporaryStorage` or `navigator.webkitPersistentStorage` instead.',
202
+ '`window.webkitStorageInfo` is deprecated. Please use standardized `navigator.storage` instead.',
176
203
  /**
177
204
  * @description Standard message when one web API is deprecated in favor of another. Both
178
205
  * placeholders are always web API functions.
@@ -232,7 +259,8 @@ const UIStrings = {
232
259
  */
233
260
  rtcpMuxPolicyNegotiate: 'The `rtcpMuxPolicy` option is deprecated and will be removed.',
234
261
  /**
235
- * @description TODO(crbug.com/1318878): Description needed for translation
262
+ * @description A deprecation warning shown in the DevTools Issues tab. The placeholder is always the noun
263
+ * "SharedArrayBuffer" which refers to a JavaScript construct.
236
264
  */
237
265
  sharedArrayBufferConstructedWithoutIsolation:
238
266
  '`SharedArrayBuffer` will require cross-origin isolation. See https://developer.chrome.com/blog/enabling-shared-array-buffer/ for more details.',
@@ -244,16 +272,24 @@ const UIStrings = {
244
272
  textToSpeech_DisallowedByAutoplay:
245
273
  '`speechSynthesis.speak()` without user activation is deprecated and will be removed.',
246
274
  /**
247
- * @description TODO(crbug.com/1318879): Description needed for translation
275
+ * @description A deprecation warning shown in the DevTools Issues tab. The placeholder is always the noun
276
+ * "SharedArrayBuffer" which refers to a JavaScript construct. "Extensions" refers to Chrome extensions. The warning is shown
277
+ * when Chrome Extensions attempt to use "SharedArrayBuffer"s under insecure circumstances.
248
278
  */
249
279
  v8SharedArrayBufferConstructedInExtensionWithoutIsolation:
250
280
  'Extensions should opt into cross-origin isolation to continue using `SharedArrayBuffer`. See https://developer.chrome.com/docs/extensions/mv3/cross-origin-isolation/.',
251
281
  /**
252
- * @description TODO(crbug.com/1318881): Description needed for translation
282
+ * @description Warning displayed to developers that they are using
283
+ * `XMLHttpRequest` API in a way that they expect an unsupported character
284
+ * encoding `UTF-16` could be used in the server reply.
253
285
  */
254
286
  xhrJSONEncodingDetection: 'UTF-16 is not supported by response json in `XMLHttpRequest`',
255
287
  /**
256
- * @description TODO(crbug.com/1318882): Description needed for translation
288
+ * @description Warning displayed to developers. It is shown when
289
+ * the `XMLHttpRequest` API is used in a way that it slows down the page load
290
+ * of the next page. The `main thread` refers to an operating systems thread
291
+ * used to run most of the processing of HTML documents, so please use a
292
+ * consistent wording.
257
293
  */
258
294
  xmlHttpRequestSynchronousInNonWorkerOutsideBeforeUnload:
259
295
  'Synchronous `XMLHttpRequest` on the main thread is deprecated because of its detrimental effects to the end user\u2019s experience. For more help, check https://xhr.spec.whatwg.org/.',
@@ -306,7 +342,7 @@ function getDescription(issueDetails) {
306
342
  break;
307
343
  case 'CrossOriginAccessBasedOnDocumentDomain':
308
344
  message = str_(UIStrings.crossOriginAccessBasedOnDocumentDomain);
309
- milestone = 106;
345
+ milestone = 109;
310
346
  break;
311
347
  case 'CrossOriginWindowAlert':
312
348
  message = str_(UIStrings.crossOriginWindowApi, {PH1: 'window.alert'});
@@ -325,13 +361,18 @@ function getDescription(issueDetails) {
325
361
  break;
326
362
  case 'DocumentDomainSettingWithoutOriginAgentClusterHeader':
327
363
  message = str_(UIStrings.documentDomainSettingWithoutOriginAgentClusterHeader);
328
- milestone = 106;
364
+ milestone = 109;
329
365
  break;
330
366
  case 'EventPath':
331
367
  message = str_(UIStrings.eventPath);
332
368
  feature = 5726124632965120;
333
369
  milestone = 109;
334
370
  break;
371
+ case 'ExpectCTHeader':
372
+ message = str_(UIStrings.expectCTHeader);
373
+ feature = 6244547273687040;
374
+ milestone = 107;
375
+ break;
335
376
  case 'GeolocationInsecureOrigin':
336
377
  message = str_(UIStrings.geolocationInsecureOrigin);
337
378
  break;
@@ -344,6 +385,10 @@ function getDescription(issueDetails) {
344
385
  case 'HostCandidateAttributeGetter':
345
386
  message = str_(UIStrings.hostCandidateAttributeGetter);
346
387
  break;
388
+ case 'IdentityInCanMakePaymentEvent':
389
+ message = str_(UIStrings.identityInCanMakePaymentEvent);
390
+ feature = 5190978431352832;
391
+ break;
347
392
  case 'InsecurePrivateNetworkSubresourceRequest':
348
393
  message = str_(UIStrings.insecurePrivateNetworkSubresourceRequest);
349
394
  feature = 5436853517811712;
@@ -365,6 +410,15 @@ function getDescription(issueDetails) {
365
410
  message = str_(UIStrings.mediaSourceDurationTruncatingBuffered);
366
411
  feature = 6107495151960064;
367
412
  break;
413
+ case 'NavigateEventRestoreScroll':
414
+ message = str_(
415
+ UIStrings.deprecatedWithReplacement, {PH1: 'navigateEvent.restoreScroll()', PH2: 'navigateEvent.scroll()'});
416
+ break;
417
+ case 'NavigateEventTransitionWhile':
418
+ message = str_(
419
+ UIStrings.deprecatedWithReplacement,
420
+ {PH1: 'navigateEvent.transitionWhile()', PH2: 'navigateEvent.intercept()'});
421
+ break;
368
422
  case 'NoSysexWebMIDIWithoutPermission':
369
423
  message = str_(UIStrings.noSysexWebMIDIWithoutPermission);
370
424
  feature = 5138066234671104;
@@ -381,6 +435,16 @@ function getDescription(issueDetails) {
381
435
  message = str_(UIStrings.obsoleteWebRtcCipherSuite);
382
436
  milestone = 81;
383
437
  break;
438
+ case 'OpenWebDatabaseInsecureContext':
439
+ message = str_(UIStrings.openWebDatabaseInsecureContext);
440
+ feature = 5175124599767040;
441
+ milestone = 105;
442
+ break;
443
+ case 'PersistentQuotaType':
444
+ message = str_(UIStrings.persistentQuotaType);
445
+ feature = 5176235376246784;
446
+ milestone = 106;
447
+ break;
384
448
  case 'PictureSourceSrc':
385
449
  message = str_(UIStrings.pictureSourceSrc);
386
450
  break;
@@ -67,6 +67,7 @@ const RESOURCE_TYPES = {
67
67
  Ping: 'Ping',
68
68
  Preflight: 'Preflight',
69
69
  CSPViolationReport: 'CSPViolationReport',
70
+ Prefetch: 'Prefetch',
70
71
  };
71
72
 
72
73
  class NetworkRequest {
@@ -498,6 +498,18 @@ function getNodeDetails(element) {
498
498
  const selector = getNodeSelector(element);
499
499
 
500
500
  // Create an id that will be unique across all execution contexts.
501
+ //
502
+ // Made up of 3 components:
503
+ // - prefix unique to specific execution context
504
+ // - nth unique node seen by this function for this execution context
505
+ // - node tagName
506
+ //
507
+ // Every page load only has up to two associated contexts - the page context
508
+ // (denoted as `__lighthouseExecutionContextUniqueIdentifier` being undefined)
509
+ // and the isolated context. The id must be unique to distinguish gatherers running
510
+ // on different page loads that identify the same logical element, for purposes
511
+ // of the full page screenshot node lookup; hence the prefix.
512
+ //
501
513
  // The id could be any arbitrary string, the exact value is not important.
502
514
  // For example, tagName is added only because it might be useful for debugging.
503
515
  // But execution id and map size are added to ensure uniqueness.
@@ -507,9 +519,9 @@ function getNodeDetails(element) {
507
519
  let lhId = window.__lighthouseNodesDontTouchOrAllVarianceGoesAway.get(element);
508
520
  if (!lhId) {
509
521
  lhId = [
510
- window.__lighthouseExecutionContextId !== undefined ?
511
- window.__lighthouseExecutionContextId :
512
- 'page',
522
+ window.__lighthouseExecutionContextUniqueIdentifier === undefined ?
523
+ 'page' :
524
+ window.__lighthouseExecutionContextUniqueIdentifier,
513
525
  window.__lighthouseNodesDontTouchOrAllVarianceGoesAway.size,
514
526
  element.tagName,
515
527
  ].join('-');
@@ -19,7 +19,7 @@ function getUberMetrics(auditResults) {
19
19
  return metricsAudit.details.items[0];
20
20
  }
21
21
 
22
- class Metrics {
22
+ class MetricTraceEvents {
23
23
  /**
24
24
  * @param {Array<LH.TraceEvent>} traceEvents
25
25
  * @param {LH.Result['audits']} auditResults
@@ -100,7 +100,7 @@ class Metrics {
100
100
 
101
101
  /** @type {Array<{ts: number, id: string, name: string}>} */
102
102
  const resolvedMetrics = [];
103
- Metrics.metricsDefinitions.forEach(metric => {
103
+ MetricTraceEvents.metricsDefinitions.forEach(metric => {
104
104
  // Skip if auditResults is missing a particular audit result
105
105
  const ts = uberMetrics[metric.tsKey];
106
106
  if (ts === undefined) {
@@ -197,5 +197,4 @@ class Metrics {
197
197
  }
198
198
  }
199
199
 
200
- // TODO(esmodule): rename?
201
- export {Metrics};
200
+ export {MetricTraceEvents};
package/core/runner.js CHANGED
@@ -11,13 +11,13 @@ import {GatherRunner} from './gather/gather-runner.js';
11
11
  import {ReportScoring} from './scoring.js';
12
12
  import {Audit} from './audits/audit.js';
13
13
  import log from 'lighthouse-logger';
14
- import format from '../shared/localization/format.js';
14
+ import * as format from '../shared/localization/format.js';
15
15
  import * as stackPacks from './lib/stack-packs.js';
16
16
  import * as assetSaver from './lib/asset-saver.js';
17
17
  import fs from 'fs';
18
18
  import path from 'path';
19
19
  import {Sentry} from './lib/sentry.js';
20
- import ReportGenerator from '../report/generator/report-generator.js';
20
+ import {ReportGenerator} from '../report/generator/report-generator.js';
21
21
  import {LighthouseError} from './lib/lh-error.js';
22
22
  import {lighthouseVersion} from '../root.js';
23
23
  import {getModuleDirectory} from '../esm-utils.js';
@@ -5377,19 +5377,6 @@ function getLhrFilenamePrefix(lhr) {
5377
5377
  return getFilenamePrefix(hostname, lhr.fetchTime);
5378
5378
  }
5379
5379
 
5380
- /**
5381
- * Generate a filenamePrefix of name_YYYY-MM-DD_HH-MM-SS.
5382
- * @param {{name: string, steps: Array<{lhr: {fetchTime: string}}>}} flowResult
5383
- * @return {string}
5384
- */
5385
- function getFlowResultFilenamePrefix(flowResult) {
5386
- const lhr = flowResult.steps[0].lhr;
5387
- const name = flowResult.name.replace(/\s/g, '-');
5388
- return getFilenamePrefix(name, lhr.fetchTime);
5389
- }
5390
-
5391
- var fileNamer = {getLhrFilenamePrefix, getFilenamePrefix, getFlowResultFilenamePrefix};
5392
-
5393
5380
  /**
5394
5381
  * @license
5395
5382
  * Copyright 2017 The Lighthouse Authors. All Rights Reserved.
@@ -5726,7 +5713,7 @@ class ReportUIFeatures {
5726
5713
  */
5727
5714
  _saveFile(blob) {
5728
5715
  const ext = blob.type.match('json') ? '.json' : '.html';
5729
- const filename = fileNamer.getLhrFilenamePrefix(this.json) + ext;
5716
+ const filename = getLhrFilenamePrefix(this.json) + ext;
5730
5717
  if (this._opts.onSaveFileOverride) {
5731
5718
  this._opts.onSaveFileOverride(blob, filename);
5732
5719
  } else {