lighthouse 10.2.0 → 10.3.0-dev.20230613

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 (132) hide show
  1. package/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap +4 -6
  2. package/core/audits/accessibility/html-xml-lang-mismatch.d.ts +10 -0
  3. package/core/audits/accessibility/html-xml-lang-mismatch.js +47 -0
  4. package/core/audits/accessibility/input-button-name.d.ts +10 -0
  5. package/core/audits/accessibility/input-button-name.js +44 -0
  6. package/core/audits/accessibility/table-fake-caption.d.ts +10 -0
  7. package/core/audits/accessibility/table-fake-caption.js +47 -0
  8. package/core/audits/accessibility/td-has-header.d.ts +10 -0
  9. package/core/audits/accessibility/td-has-header.js +45 -0
  10. package/core/audits/audit.d.ts +2 -1
  11. package/core/audits/audit.js +5 -2
  12. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +3 -3
  13. package/core/audits/byte-efficiency/byte-efficiency-audit.js +14 -19
  14. package/core/audits/deprecations.js +1 -1
  15. package/core/audits/largest-contentful-paint-element.d.ts +14 -2
  16. package/core/audits/largest-contentful-paint-element.js +49 -31
  17. package/core/audits/layout-shift-elements.d.ts +3 -2
  18. package/core/audits/layout-shift-elements.js +10 -2
  19. package/core/audits/metrics.js +0 -2
  20. package/core/audits/network-requests.js +6 -0
  21. package/core/audits/seo/crawlable-anchors.js +4 -0
  22. package/core/audits/server-response-time.d.ts +2 -1
  23. package/core/audits/server-response-time.js +17 -3
  24. package/core/audits/uses-rel-preconnect.js +20 -4
  25. package/core/computed/entity-classification.d.ts +14 -1
  26. package/core/computed/entity-classification.js +61 -6
  27. package/core/computed/metrics/cumulative-layout-shift.d.ts +2 -9
  28. package/core/computed/metrics/cumulative-layout-shift.js +3 -16
  29. package/core/computed/metrics/time-to-first-byte.js +10 -7
  30. package/core/computed/metrics/timing-summary.js +0 -3
  31. package/core/config/default-config.js +8 -0
  32. package/core/gather/driver/execution-context.js +13 -5
  33. package/core/gather/driver/target-manager.d.ts +13 -0
  34. package/core/gather/driver/target-manager.js +49 -0
  35. package/core/gather/gatherers/accessibility.js +19 -20
  36. package/core/gather/gatherers/anchor-elements.js +2 -0
  37. package/core/gather/gatherers/global-listeners.js +38 -21
  38. package/core/gather/gatherers/inspector-issues.js +2 -1
  39. package/core/gather/gatherers/trace-elements.d.ts +3 -2
  40. package/core/gather/gatherers/trace-elements.js +10 -19
  41. package/core/legacy/config/config.d.ts +1 -1
  42. package/core/legacy/config/config.js +1 -1
  43. package/core/legacy/gather/driver.d.ts +1 -0
  44. package/core/legacy/gather/driver.js +11 -0
  45. package/core/lib/asset-saver.d.ts +4 -0
  46. package/core/lib/asset-saver.js +19 -0
  47. package/core/lib/bf-cache-strings.d.ts +3 -0
  48. package/core/lib/bf-cache-strings.js +248 -232
  49. package/core/lib/cdt/generated/SourceMap.d.ts +18 -31
  50. package/core/lib/cdt/generated/SourceMap.js +51 -101
  51. package/core/lib/dependency-graph/simulator/network-analyzer.d.ts +6 -2
  52. package/core/lib/dependency-graph/simulator/network-analyzer.js +45 -13
  53. package/core/lib/deprecation-description.d.ts +17 -0
  54. package/core/lib/deprecation-description.js +71 -0
  55. package/core/lib/deprecations-strings.d.ts +282 -63
  56. package/core/lib/deprecations-strings.js +282 -551
  57. package/core/lib/lh-error.d.ts +9 -4
  58. package/core/lib/lh-error.js +15 -11
  59. package/core/lib/network-request.d.ts +13 -6
  60. package/core/lib/network-request.js +39 -14
  61. package/core/lib/tracehouse/trace-processor.js +1 -1
  62. package/core/lib/url-utils.js +4 -0
  63. package/core/runner.js +4 -2
  64. package/dist/report/bundle.esm.js +24 -7
  65. package/dist/report/flow.js +3 -3
  66. package/dist/report/standalone.js +8 -8
  67. package/package.json +12 -12
  68. package/readme.md +7 -0
  69. package/report/assets/styles.css +18 -2
  70. package/report/assets/templates.html +4 -0
  71. package/report/renderer/category-renderer.js +5 -2
  72. package/report/renderer/components.js +2 -2
  73. package/report/renderer/dom.d.ts +4 -1
  74. package/report/renderer/dom.js +3 -2
  75. package/shared/localization/locales/ar-XB.json +20 -170
  76. package/shared/localization/locales/ar.json +20 -170
  77. package/shared/localization/locales/bg.json +19 -169
  78. package/shared/localization/locales/ca.json +19 -169
  79. package/shared/localization/locales/cs.json +19 -169
  80. package/shared/localization/locales/da.json +19 -169
  81. package/shared/localization/locales/de.json +19 -169
  82. package/shared/localization/locales/el.json +19 -169
  83. package/shared/localization/locales/en-GB.json +9 -159
  84. package/shared/localization/locales/en-US.json +151 -70
  85. package/shared/localization/locales/en-XA.json +20 -170
  86. package/shared/localization/locales/en-XL.json +151 -70
  87. package/shared/localization/locales/es-419.json +19 -169
  88. package/shared/localization/locales/es.json +19 -169
  89. package/shared/localization/locales/fi.json +19 -169
  90. package/shared/localization/locales/fil.json +17 -167
  91. package/shared/localization/locales/fr.json +18 -168
  92. package/shared/localization/locales/he.json +19 -169
  93. package/shared/localization/locales/hi.json +20 -170
  94. package/shared/localization/locales/hr.json +19 -169
  95. package/shared/localization/locales/hu.json +19 -169
  96. package/shared/localization/locales/id.json +19 -169
  97. package/shared/localization/locales/it.json +19 -169
  98. package/shared/localization/locales/ja.json +19 -169
  99. package/shared/localization/locales/ko.json +19 -169
  100. package/shared/localization/locales/lt.json +20 -170
  101. package/shared/localization/locales/lv.json +20 -170
  102. package/shared/localization/locales/nl.json +18 -168
  103. package/shared/localization/locales/no.json +19 -169
  104. package/shared/localization/locales/pl.json +19 -169
  105. package/shared/localization/locales/pt-PT.json +19 -169
  106. package/shared/localization/locales/pt.json +19 -169
  107. package/shared/localization/locales/ro.json +19 -169
  108. package/shared/localization/locales/ru.json +19 -169
  109. package/shared/localization/locales/sk.json +20 -170
  110. package/shared/localization/locales/sl.json +19 -169
  111. package/shared/localization/locales/sr-Latn.json +19 -169
  112. package/shared/localization/locales/sr.json +19 -169
  113. package/shared/localization/locales/sv.json +19 -169
  114. package/shared/localization/locales/ta.json +19 -169
  115. package/shared/localization/locales/te.json +19 -169
  116. package/shared/localization/locales/th.json +19 -169
  117. package/shared/localization/locales/tr.json +19 -169
  118. package/shared/localization/locales/uk.json +19 -169
  119. package/shared/localization/locales/vi.json +20 -170
  120. package/shared/localization/locales/zh-HK.json +19 -169
  121. package/shared/localization/locales/zh-TW.json +19 -169
  122. package/shared/localization/locales/zh.json +19 -169
  123. package/shared/util.d.ts +6 -0
  124. package/shared/util.js +14 -1
  125. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +2 -1
  126. package/tsconfig-base.json +1 -1
  127. package/types/artifacts.d.ts +10 -8
  128. package/types/audit.d.ts +5 -0
  129. package/types/gatherer.d.ts +1 -0
  130. package/types/lhr/audit-details.d.ts +1 -0
  131. package/types/lhr/audit-result.d.ts +10 -0
  132. package/types/internal/es-main.d.ts +0 -18
@@ -1,10 +1,10 @@
1
- export = TextSourceMap;
2
- declare class TextSourceMap {
1
+ export = SourceMap;
2
+ declare class SourceMap {
3
3
  /**
4
4
  * Implements Source Map V3 model. See https://github.com/google/closure-compiler/wiki/Source-Maps
5
5
  * for format description.
6
6
  */
7
- constructor(compiledURL: any, sourceMappingURL: any, payload: any, initiator: any);
7
+ constructor(compiledURL: any, sourceMappingURL: any, payload: any);
8
8
  compiledURL(): any;
9
9
  url(): any;
10
10
  sourceURLs(): any[];
@@ -36,22 +36,21 @@ declare class TextSourceMap {
36
36
  findReverseEntries(sourceURL: any, lineNumber: any, columnNumber: any): any;
37
37
  findReverseRanges(sourceURL: any, lineNumber: any, columnNumber: any): any[];
38
38
  /** @return {Array<{lineNumber: number, columnNumber: number, sourceURL?: string, sourceLineNumber: number, sourceColumnNumber: number, name?: string, lastColumnNumber?: number}>} */
39
- mappings(): Array<{
39
+ mappings(): {
40
40
  lineNumber: number;
41
41
  columnNumber: number;
42
- sourceURL?: string;
42
+ sourceURL?: string | undefined;
43
43
  sourceLineNumber: number;
44
44
  sourceColumnNumber: number;
45
- name?: string;
46
- lastColumnNumber?: number;
47
- }>;
45
+ name?: string | undefined;
46
+ lastColumnNumber?: number | undefined;
47
+ }[];
48
48
  reversedMappings(sourceURL: any): any;
49
49
  eachSection(callback: any): void;
50
50
  parseSources(sourceMap: any): void;
51
51
  parseMap(map: any, lineNumber: any, columnNumber: any): void;
52
52
  isSeparator(char: any): boolean;
53
53
  decodeVLQ(stringCharIterator: any): number;
54
- reverseMapTextRange(url: any, textRange: any): any;
55
54
  mapsOrigin(): boolean;
56
55
  hasIgnoreListHint(sourceURL: any): any;
57
56
  /**
@@ -63,30 +62,18 @@ declare class TextSourceMap {
63
62
  findRanges(predicate: any, options: any): any[];
64
63
  #private;
65
64
  }
66
- declare namespace TextSourceMap {
67
- export { __esModule, SourceMapV3, Section, Offset, SourceMapEntry, TextSourceMap };
65
+ declare namespace SourceMap {
66
+ export { parseSourceMap, __esModule, SourceMapEntry, SourceMap };
68
67
  }
68
+ /**
69
+ * Parses the {@link content} as JSON, ignoring BOM markers in the beginning, and
70
+ * also handling the CORB bypass prefix correctly.
71
+ *
72
+ * @param content the string representation of a sourcemap.
73
+ * @returns the {@link SourceMapV3} representation of the {@link content}.
74
+ */
75
+ declare function parseSourceMap(content: any): any;
69
76
  declare const __esModule: boolean;
70
- declare class SourceMapV3 {
71
- version: any;
72
- file: any;
73
- sources: any;
74
- sections: any;
75
- mappings: any;
76
- sourceRoot: any;
77
- names: any;
78
- sourcesContent: any;
79
- x_google_ignoreList: any;
80
- }
81
- declare class Section {
82
- map: any;
83
- offset: any;
84
- url: any;
85
- }
86
- declare class Offset {
87
- line: any;
88
- column: any;
89
- }
90
77
  declare class SourceMapEntry {
91
78
  static compare(entry1: any, entry2: any): number;
92
79
  constructor(lineNumber: any, columnNumber: any, sourceURL: any, sourceLineNumber: any, sourceColumnNumber: any, name: any);
@@ -8,7 +8,7 @@ const Platform = require('../Platform.js');
8
8
  // Use of this source code is governed by a BSD-style license that can be
9
9
  // found in the LICENSE file.
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.TextSourceMap = exports.SourceMapEntry = exports.Offset = exports.Section = exports.SourceMapV3 = void 0;
11
+ exports.SourceMap = exports.SourceMapEntry = exports.parseSourceMap = void 0;
12
12
  /*
13
13
  * Copyright (C) 2012 Google Inc. All rights reserved.
14
14
  *
@@ -41,42 +41,24 @@ exports.TextSourceMap = exports.SourceMapEntry = exports.Offset = exports.Sectio
41
41
  ;
42
42
  ;
43
43
  ;
44
- ;
45
- ;
46
- ;
47
- ;
48
- ;
49
- ;
50
- class SourceMapV3 {
51
- version;
52
- file;
53
- sources;
54
- sections;
55
- mappings;
56
- sourceRoot;
57
- names;
58
- sourcesContent;
59
- // eslint-disable-next-line @typescript-eslint/naming-convention
60
- x_google_ignoreList;
61
- constructor() {
44
+ /**
45
+ * Parses the {@link content} as JSON, ignoring BOM markers in the beginning, and
46
+ * also handling the CORB bypass prefix correctly.
47
+ *
48
+ * @param content the string representation of a sourcemap.
49
+ * @returns the {@link SourceMapV3} representation of the {@link content}.
50
+ */
51
+ function parseSourceMap(content) {
52
+ if (content.startsWith(')]}')) {
53
+ content = content.substring(content.indexOf('\n'));
62
54
  }
63
- }
64
- exports.SourceMapV3 = SourceMapV3;
65
- class Section {
66
- map;
67
- offset;
68
- url;
69
- constructor() {
55
+ if (content.charCodeAt(0) === 0xFEFF) {
56
+ // Strip BOM at the beginning before parsing the JSON.
57
+ content = content.slice(1);
70
58
  }
59
+ return JSON.parse(content);
71
60
  }
72
- exports.Section = Section;
73
- class Offset {
74
- line;
75
- column;
76
- constructor() {
77
- }
78
- }
79
- exports.Offset = Offset;
61
+ exports.parseSourceMap = parseSourceMap;
80
62
  class SourceMapEntry {
81
63
  lineNumber;
82
64
  columnNumber;
@@ -106,8 +88,7 @@ for (let i = 0; i < base64Digits.length; ++i) {
106
88
  base64Map.set(base64Digits.charAt(i), i);
107
89
  }
108
90
  const sourceMapToSourceList = new WeakMap();
109
- class TextSourceMap {
110
- #initiator;
91
+ class SourceMap {
111
92
  #json;
112
93
  #compiledURLInternal;
113
94
  #sourceMappingURL;
@@ -118,17 +99,15 @@ class TextSourceMap {
118
99
  * Implements Source Map V3 model. See https://github.com/google/closure-compiler/wiki/Source-Maps
119
100
  * for format description.
120
101
  */
121
- constructor(compiledURL, sourceMappingURL, payload, initiator) {
122
- this.#initiator = initiator;
102
+ constructor(compiledURL, sourceMappingURL, payload) {
123
103
  this.#json = payload;
124
104
  this.#compiledURLInternal = compiledURL;
125
105
  this.#sourceMappingURL = sourceMappingURL;
126
106
  this.#baseURL = (sourceMappingURL.startsWith('data:') ? compiledURL : sourceMappingURL);
127
107
  this.#mappingsInternal = null;
128
108
  this.#sourceInfos = new Map();
129
- if (this.#json.sections) {
130
- const sectionWithURL = Boolean(this.#json.sections.find(section => Boolean(section.url)));
131
- if (sectionWithURL) {
109
+ if ('sections' in this.#json) {
110
+ if (this.#json.sections.find(section => 'url' in section)) {
132
111
  console.warn(`SourceMap "${sourceMappingURL}" contains unsupported "URL" field in one of its sections.`);
133
112
  }
134
113
  }
@@ -266,6 +245,8 @@ class TextSourceMap {
266
245
  if (this.#mappingsInternal === null) {
267
246
  this.#mappingsInternal = [];
268
247
  this.eachSection(this.parseMap.bind(this));
248
+ // As per spec, mappings are not necessarily sorted.
249
+ this.mappings().sort(SourceMapEntry.compare);
269
250
  this.#computeReverseMappings(this.#mappingsInternal);
270
251
  this.#json = null;
271
252
  }
@@ -303,42 +284,43 @@ class TextSourceMap {
303
284
  if (!this.#json) {
304
285
  return;
305
286
  }
306
- if (!this.#json.sections) {
307
- callback(this.#json, 0, 0);
308
- return;
287
+ if ('sections' in this.#json) {
288
+ for (const section of this.#json.sections) {
289
+ if ('map' in section) {
290
+ callback(section.map, section.offset.line, section.offset.column);
291
+ }
292
+ }
309
293
  }
310
- for (const section of this.#json.sections) {
311
- callback(section.map, section.offset.line, section.offset.column);
294
+ else {
295
+ callback(this.#json, 0, 0);
312
296
  }
313
297
  }
314
298
  parseSources(sourceMap) {
315
299
  const sourcesList = [];
316
- const sourceRoot = sourceMap.sourceRoot || Platform.DevToolsPath.EmptyUrlString;
300
+ const sourceRoot = sourceMap.sourceRoot ?? '';
317
301
  const ignoreList = new Set(sourceMap.x_google_ignoreList);
318
302
  for (let i = 0; i < sourceMap.sources.length; ++i) {
319
303
  let href = sourceMap.sources[i];
320
304
  // The source map v3 proposal says to prepend the sourceRoot to the source URL
321
305
  // and if the resulting URL is not absolute, then resolve the source URL against
322
- // the source map URL. Appending the sourceRoot (if one exists) is not likely to
306
+ // the source map URL. Prepending the sourceRoot (if one exists) is not likely to
323
307
  // be meaningful or useful if the source URL is already absolute though. In this
324
308
  // case, use the source URL as is without prepending the sourceRoot.
325
309
  if (Common.ParsedURL.ParsedURL.isRelativeURL(href)) {
326
310
  if (sourceRoot && !sourceRoot.endsWith('/') && href && !href.startsWith('/')) {
327
- href = Common.ParsedURL.ParsedURL.concatenate(sourceRoot, '/', href);
311
+ href = sourceRoot.concat('/', href);
328
312
  }
329
313
  else {
330
- href = Common.ParsedURL.ParsedURL.concatenate(sourceRoot, href);
314
+ href = sourceRoot.concat(href);
331
315
  }
332
316
  }
333
- let url = '' || href;
317
+ const url = '' || href;
334
318
  const source = sourceMap.sourcesContent && sourceMap.sourcesContent[i];
335
- if (url === this.#compiledURLInternal && source) {
336
- }
337
319
  sourcesList.push(url);
338
320
  if (!this.#sourceInfos.has(url)) {
339
321
  const content = source ?? null;
340
322
  const ignoreListHint = ignoreList.has(i);
341
- this.#sourceInfos.set(url, new TextSourceMap.SourceInfo(content, ignoreListHint));
323
+ this.#sourceInfos.set(url, { content, ignoreListHint, reverseMappings: null });
342
324
  }
343
325
  }
344
326
  sourceMapToSourceList.set(sourceMap, sourcesList);
@@ -355,8 +337,8 @@ class TextSourceMap {
355
337
  // only reach this point when we are certain
356
338
  // we have the list available.
357
339
  const sources = sourceMapToSourceList.get(map);
358
- const names = map.names || [];
359
- const stringCharIterator = new TextSourceMap.StringCharIterator(map.mappings);
340
+ const names = map.names ?? [];
341
+ const stringCharIterator = new SourceMap.StringCharIterator(map.mappings);
360
342
  let sourceURL = sources && sources[sourceIndex];
361
343
  while (true) {
362
344
  if (stringCharIterator.peek() === ',') {
@@ -393,8 +375,6 @@ class TextSourceMap {
393
375
  nameIndex += this.decodeVLQ(stringCharIterator);
394
376
  this.mappings().push(new SourceMapEntry(lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber, names[nameIndex]));
395
377
  }
396
- // As per spec, mappings are not necessarily sorted.
397
- this.mappings().sort(SourceMapEntry.compare);
398
378
  }
399
379
  isSeparator(char) {
400
380
  return char === ',' || char === ';';
@@ -403,38 +383,17 @@ class TextSourceMap {
403
383
  // Read unsigned value.
404
384
  let result = 0;
405
385
  let shift = 0;
406
- let digit = TextSourceMap._VLQ_CONTINUATION_MASK;
407
- while (digit & TextSourceMap._VLQ_CONTINUATION_MASK) {
386
+ let digit = SourceMap._VLQ_CONTINUATION_MASK;
387
+ while (digit & SourceMap._VLQ_CONTINUATION_MASK) {
408
388
  digit = base64Map.get(stringCharIterator.next()) || 0;
409
- result += (digit & TextSourceMap._VLQ_BASE_MASK) << shift;
410
- shift += TextSourceMap._VLQ_BASE_SHIFT;
389
+ result += (digit & SourceMap._VLQ_BASE_MASK) << shift;
390
+ shift += SourceMap._VLQ_BASE_SHIFT;
411
391
  }
412
392
  // Fix the sign.
413
393
  const negative = result & 1;
414
394
  result >>= 1;
415
395
  return negative ? -result : result;
416
396
  }
417
- reverseMapTextRange(url, textRange) {
418
- function comparator(position, mappingIndex) {
419
- if (position.lineNumber !== mappings[mappingIndex].sourceLineNumber) {
420
- return position.lineNumber - mappings[mappingIndex].sourceLineNumber;
421
- }
422
- return position.columnNumber - mappings[mappingIndex].sourceColumnNumber;
423
- }
424
- const reverseMappings = this.reversedMappings(url);
425
- const mappings = this.mappings();
426
- if (!reverseMappings.length) {
427
- return null;
428
- }
429
- const startIndex = Platform.ArrayUtilities.lowerBound(reverseMappings, { lineNumber: textRange.startLine, columnNumber: textRange.startColumn }, comparator);
430
- const endIndex = Platform.ArrayUtilities.upperBound(reverseMappings, { lineNumber: textRange.endLine, columnNumber: textRange.endColumn }, comparator);
431
- if (endIndex >= reverseMappings.length) {
432
- return null;
433
- }
434
- const startMapping = mappings[reverseMappings[startIndex]];
435
- const endMapping = mappings[reverseMappings[endIndex]];
436
- return new TextUtils.TextRange.TextRange(startMapping.lineNumber, startMapping.columnNumber, endMapping.lineNumber, endMapping.columnNumber);
437
- }
438
397
  mapsOrigin() {
439
398
  const mappings = this.mappings();
440
399
  if (mappings.length > 0) {
@@ -482,17 +441,17 @@ class TextSourceMap {
482
441
  return ranges;
483
442
  }
484
443
  }
485
- exports.TextSourceMap = TextSourceMap;
486
- (function (TextSourceMap) {
444
+ exports.SourceMap = SourceMap;
445
+ (function (SourceMap) {
487
446
  // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
488
447
  // eslint-disable-next-line @typescript-eslint/naming-convention
489
- TextSourceMap._VLQ_BASE_SHIFT = 5;
448
+ SourceMap._VLQ_BASE_SHIFT = 5;
490
449
  // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
491
450
  // eslint-disable-next-line @typescript-eslint/naming-convention
492
- TextSourceMap._VLQ_BASE_MASK = (1 << 5) - 1;
451
+ SourceMap._VLQ_BASE_MASK = (1 << 5) - 1;
493
452
  // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
494
453
  // eslint-disable-next-line @typescript-eslint/naming-convention
495
- TextSourceMap._VLQ_CONTINUATION_MASK = 1 << 5;
454
+ SourceMap._VLQ_CONTINUATION_MASK = 1 << 5;
496
455
  class StringCharIterator {
497
456
  string;
498
457
  position;
@@ -510,18 +469,9 @@ exports.TextSourceMap = TextSourceMap;
510
469
  return this.position < this.string.length;
511
470
  }
512
471
  }
513
- TextSourceMap.StringCharIterator = StringCharIterator;
514
- class SourceInfo {
515
- content;
516
- ignoreListHint;
517
- reverseMappings = null;
518
- constructor(content, ignoreListHint) {
519
- this.content = content;
520
- this.ignoreListHint = ignoreListHint;
521
- }
522
- }
523
- TextSourceMap.SourceInfo = SourceInfo;
524
- })(TextSourceMap = exports.TextSourceMap || (exports.TextSourceMap = {}));
472
+ SourceMap.StringCharIterator = StringCharIterator;
473
+ })(SourceMap = exports.SourceMap || (exports.SourceMap = {}));
525
474
 
526
475
 
527
- module.exports = TextSourceMap;
476
+ module.exports = SourceMap;
477
+ SourceMap.parseSourceMap = parseSourceMap;
@@ -58,13 +58,17 @@ export class NetworkAnalyzer {
58
58
  connectionReused?: boolean | undefined;
59
59
  }) => number | number[] | undefined): Map<string, number[]>;
60
60
  /**
61
- * Estimates the observed RTT to each origin based on how long the TCP handshake took.
61
+ * Estimates the observed RTT to each origin based on how long the connection setup.
62
+ * For h1 and h2, this could includes two estimates - one for the TCP handshake, another for
63
+ * SSL negotiation.
64
+ * For h3, we get only one estimate since QUIC establishes a secure connection in a
65
+ * single handshake.
62
66
  * This is the most accurate and preferred method of measurement when the data is available.
63
67
  *
64
68
  * @param {LH.Artifacts.NetworkRequest[]} records
65
69
  * @return {Map<string, number[]>}
66
70
  */
67
- static _estimateRTTByOriginViaTCPTiming(records: LH.Artifacts.NetworkRequest[]): Map<string, number[]>;
71
+ static _estimateRTTByOriginViaConnectionTiming(records: LH.Artifacts.NetworkRequest[]): Map<string, number[]>;
68
72
  /**
69
73
  * Estimates the observed RTT to each origin based on how long a download took on a fresh connection.
70
74
  * NOTE: this will tend to overestimate the actual RTT quite significantly as the download can be
@@ -52,11 +52,22 @@ class NetworkAnalyzer {
52
52
  static getSummary(values) {
53
53
  values.sort((a, b) => a - b);
54
54
 
55
+ let median;
56
+ if (values.length === 0) {
57
+ median = values[0];
58
+ } else if (values.length % 2 === 0) {
59
+ const a = values[Math.floor((values.length - 1) / 2)];
60
+ const b = values[Math.floor((values.length - 1) / 2) + 1];
61
+ median = (a + b) / 2;
62
+ } else {
63
+ median = values[Math.floor((values.length - 1) / 2)];
64
+ }
65
+
55
66
  return {
56
67
  min: values[0],
57
68
  max: values[values.length - 1],
58
69
  avg: values.reduce((a, b) => a + b, 0) / values.length,
59
- median: values[Math.floor((values.length - 1) / 2)],
70
+ median,
60
71
  };
61
72
  }
62
73
 
@@ -114,22 +125,38 @@ class NetworkAnalyzer {
114
125
  }
115
126
 
116
127
  /**
117
- * Estimates the observed RTT to each origin based on how long the TCP handshake took.
128
+ * Estimates the observed RTT to each origin based on how long the connection setup.
129
+ * For h1 and h2, this could includes two estimates - one for the TCP handshake, another for
130
+ * SSL negotiation.
131
+ * For h3, we get only one estimate since QUIC establishes a secure connection in a
132
+ * single handshake.
118
133
  * This is the most accurate and preferred method of measurement when the data is available.
119
134
  *
120
135
  * @param {LH.Artifacts.NetworkRequest[]} records
121
136
  * @return {Map<string, number[]>}
122
137
  */
123
- static _estimateRTTByOriginViaTCPTiming(records) {
124
- return NetworkAnalyzer._estimateValueByOrigin(records, ({timing, connectionReused}) => {
138
+ static _estimateRTTByOriginViaConnectionTiming(records) {
139
+ return NetworkAnalyzer._estimateValueByOrigin(records, ({timing, connectionReused, record}) => {
125
140
  if (connectionReused) return;
126
141
 
127
- // If the request was SSL we get two estimates, one for the SSL negotiation and another for the
128
- // regular handshake. SSL can also be more than 1 RT but assume False Start was used.
129
- if (timing.sslStart > 0 && timing.sslEnd > 0) {
130
- return [timing.connectEnd - timing.sslStart, timing.sslStart - timing.connectStart];
131
- } else if (timing.connectStart > 0 && timing.connectEnd > 0) {
132
- return timing.connectEnd - timing.connectStart;
142
+ // In LR, network records are missing connection timing, but we've smuggled it in via headers.
143
+ if (global.isLightrider && record.lrStatistics) {
144
+ if (record.protocol.startsWith('h3')) {
145
+ return record.lrStatistics.TCPMs;
146
+ } else {
147
+ return [record.lrStatistics.TCPMs / 2, record.lrStatistics.TCPMs / 2];
148
+ }
149
+ }
150
+
151
+ const {connectStart, sslStart, sslEnd, connectEnd} = timing;
152
+ if (connectEnd >= 0 && connectStart >= 0 && record.protocol.startsWith('h3')) {
153
+ // These values are equal to sslStart and sslEnd for h3.
154
+ return connectEnd - connectStart;
155
+ } else if (sslStart >= 0 && sslEnd >= 0 && sslStart !== connectStart) {
156
+ // SSL can also be more than 1 RT but assume False Start was used.
157
+ return [connectEnd - sslStart, sslStart - connectStart];
158
+ } else if (connectStart >= 0 && connectEnd >= 0) {
159
+ return connectEnd - connectStart;
133
160
  }
134
161
  });
135
162
  }
@@ -177,7 +204,8 @@ class NetworkAnalyzer {
177
204
 
178
205
  // Assume everything before sendStart was just DNS + (SSL)? + TCP handshake
179
206
  // 1 RT for DNS, 1 RT (maybe) for SSL, 1 RT for TCP
180
- let roundTrips = 2;
207
+ let roundTrips = 1;
208
+ if (!record.protocol.startsWith('h3')) roundTrips += 1; // TCP
181
209
  if (record.parsedURL.scheme === 'https') roundTrips += 1;
182
210
  return timing.sendStart / roundTrips;
183
211
  });
@@ -210,8 +238,8 @@ class NetworkAnalyzer {
210
238
  // TTFB = DNS + (SSL)? + TCP handshake + 1 RT for request + server response time
211
239
  if (!connectionReused) {
212
240
  roundTrips += 1; // DNS
241
+ if (!record.protocol.startsWith('h3')) roundTrips += 1; // TCP
213
242
  if (record.parsedURL.scheme === 'https') roundTrips += 1; // SSL
214
- roundTrips += 1; // TCP handshake
215
243
  }
216
244
 
217
245
  // subtract out our estimated server response time
@@ -228,6 +256,10 @@ class NetworkAnalyzer {
228
256
  */
229
257
  static _estimateResponseTimeByOrigin(records, rttByOrigin) {
230
258
  return NetworkAnalyzer._estimateValueByOrigin(records, ({record, timing}) => {
259
+ // Lightrider does not have timings for sendEnd, but we do have this timing which should be
260
+ // close to the response time.
261
+ if (global.isLightrider && record.lrStatistics) return record.lrStatistics.requestMs;
262
+
231
263
  if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) return;
232
264
  if (!Number.isFinite(timing.sendEnd) || timing.sendEnd < 0) return;
233
265
 
@@ -318,7 +350,7 @@ class NetworkAnalyzer {
318
350
  useHeadersEndEstimates = true,
319
351
  } = options || {};
320
352
 
321
- let estimatesByOrigin = NetworkAnalyzer._estimateRTTByOriginViaTCPTiming(records);
353
+ let estimatesByOrigin = NetworkAnalyzer._estimateRTTByOriginViaConnectionTiming(records);
322
354
  if (!estimatesByOrigin.size || forceCoarseEstimates) {
323
355
  estimatesByOrigin = new Map();
324
356
  const estimatesViaDownload = NetworkAnalyzer._estimateRTTByOriginViaDownloadTiming(records);
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @param {LH.Crdp.Audits.DeprecationIssueDetails} issueDetails
3
+ */
4
+ export function getIssueDetailDescription(issueDetails: LH.Crdp.Audits.DeprecationIssueDetails): {
5
+ substitutions: Map<string, import("../index.js").IcuMessage | undefined>;
6
+ links: {
7
+ link: string;
8
+ linkTitle: import("../index.js").IcuMessage;
9
+ }[];
10
+ message: import("../index.js").IcuMessage | undefined;
11
+ };
12
+ export namespace UIStrings {
13
+ const feature: string;
14
+ const milestone: string;
15
+ const title: string;
16
+ }
17
+ //# sourceMappingURL=deprecation-description.d.ts.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @license Copyright 2023 The Lighthouse Authors. All Rights Reserved.
3
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
+ */
6
+
7
+ import * as i18n from '../lib/i18n/i18n.js';
8
+ import {DEPRECATIONS_METADATA, UIStrings as DeprecationUIStrings} from './deprecations-strings.js';
9
+
10
+ const UIStrings = {
11
+ // Store strings used across messages in this block.
12
+ /**
13
+ * @description This links to the chrome feature status page when one exists.
14
+ */
15
+ feature: 'Check the feature status page for more details.',
16
+ /**
17
+ * @description This links to the chromium dash schedule when a milestone is set.
18
+ * @example {100} milestone
19
+ */
20
+ milestone: 'This change will go into effect with milestone {milestone}.',
21
+ /**
22
+ * @description Title of issue raised when a deprecated feature is used
23
+ */
24
+ title: 'Deprecated Feature Used',
25
+ };
26
+
27
+ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
28
+ const deprecationsStr_ = i18n.createIcuMessageFn(import.meta.url, DeprecationUIStrings);
29
+
30
+ /**
31
+ * @param {LH.Crdp.Audits.DeprecationIssueDetails} issueDetails
32
+ */
33
+ function getIssueDetailDescription(issueDetails) {
34
+ let message;
35
+ const type = /** @type {keyof DEPRECATIONS_METADATA} */ (issueDetails.type);
36
+ const maybeEnglishMessage = DeprecationUIStrings[type];
37
+ if (maybeEnglishMessage) {
38
+ message = deprecationsStr_(maybeEnglishMessage);
39
+ }
40
+
41
+ const links = [];
42
+ /** @type {{chromeStatusFeature?: number, milestone?: number}|undefined} */
43
+ const deprecationMeta = DEPRECATIONS_METADATA[type];
44
+ const feature = deprecationMeta?.chromeStatusFeature ?? 0;
45
+ if (feature !== 0) {
46
+ links.push({
47
+ link: `https://chromestatus.com/feature/${feature}`,
48
+ linkTitle: str_(UIStrings.feature),
49
+ });
50
+ }
51
+ const milestone = deprecationMeta?.milestone ?? 0;
52
+ if (milestone !== 0) {
53
+ links.push({
54
+ link: 'https://chromiumdash.appspot.com/schedule',
55
+ linkTitle: str_(UIStrings.milestone, {milestone}),
56
+ });
57
+ }
58
+ return ({
59
+ substitutions: new Map([
60
+ ['PLACEHOLDER_title', str_(UIStrings.title)],
61
+ ['PLACEHOLDER_message', message],
62
+ ]),
63
+ links,
64
+ message,
65
+ });
66
+ }
67
+
68
+ export {
69
+ getIssueDetailDescription,
70
+ UIStrings,
71
+ };