lighthouse 12.5.1 → 12.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/cli/run.js +1 -1
  2. package/cli/test/smokehouse/config/exclusions.js +2 -0
  3. package/cli/test/smokehouse/lib/concurrent-mapper.d.ts +3 -3
  4. package/core/audits/audit.d.ts +1 -1
  5. package/core/audits/audit.js +3 -2
  6. package/core/audits/bootup-time.d.ts +1 -1
  7. package/core/audits/bootup-time.js +3 -3
  8. package/core/audits/byte-efficiency/byte-efficiency-audit.js +1 -1
  9. package/core/audits/byte-efficiency/duplicated-javascript.js +1 -1
  10. package/core/audits/byte-efficiency/efficient-animated-content.js +1 -1
  11. package/core/audits/byte-efficiency/legacy-javascript.js +2 -3
  12. package/core/audits/byte-efficiency/modern-image-formats.js +1 -1
  13. package/core/audits/byte-efficiency/offscreen-images.js +4 -4
  14. package/core/audits/byte-efficiency/render-blocking-resources.js +4 -4
  15. package/core/audits/byte-efficiency/total-byte-weight.d.ts +1 -1
  16. package/core/audits/byte-efficiency/total-byte-weight.js +2 -2
  17. package/core/audits/byte-efficiency/unminified-css.js +1 -1
  18. package/core/audits/byte-efficiency/unminified-javascript.js +1 -1
  19. package/core/audits/byte-efficiency/unused-css-rules.js +2 -2
  20. package/core/audits/byte-efficiency/unused-javascript.js +1 -1
  21. package/core/audits/byte-efficiency/uses-long-cache-ttl.d.ts +1 -1
  22. package/core/audits/byte-efficiency/uses-long-cache-ttl.js +2 -2
  23. package/core/audits/byte-efficiency/uses-optimized-images.js +2 -2
  24. package/core/audits/byte-efficiency/uses-responsive-images.d.ts +1 -1
  25. package/core/audits/byte-efficiency/uses-responsive-images.js +1 -1
  26. package/core/audits/byte-efficiency/uses-text-compression.js +1 -1
  27. package/core/audits/clickjacking-mitigation.js +2 -2
  28. package/core/audits/critical-request-chains.js +3 -3
  29. package/core/audits/csp-xss.js +2 -2
  30. package/core/audits/diagnostics.js +3 -3
  31. package/core/audits/dobetterweb/charset.js +2 -2
  32. package/core/audits/dobetterweb/doctype.js +2 -2
  33. package/core/audits/dobetterweb/dom-size.d.ts +1 -1
  34. package/core/audits/dobetterweb/dom-size.js +3 -3
  35. package/core/audits/dobetterweb/uses-http2.js +2 -2
  36. package/core/audits/final-screenshot.js +2 -2
  37. package/core/audits/font-display.js +2 -2
  38. package/core/audits/has-hsts.js +2 -2
  39. package/core/audits/image-size-responsive.d.ts +3 -2
  40. package/core/audits/image-size-responsive.js +30 -4
  41. package/core/audits/insights/{use-cache-insight.d.ts → cache-insight.d.ts} +3 -3
  42. package/core/audits/insights/{use-cache-insight.js → cache-insight.js} +15 -13
  43. package/core/audits/insights/cls-culprits-insight.js +3 -3
  44. package/core/audits/insights/document-latency-insight.js +1 -1
  45. package/core/audits/insights/dom-size-insight.js +1 -1
  46. package/core/audits/insights/duplicated-javascript-insight.d.ts +13 -0
  47. package/core/audits/insights/duplicated-javascript-insight.js +36 -9
  48. package/core/audits/insights/font-display-insight.js +1 -1
  49. package/core/audits/insights/forced-reflow-insight.js +1 -1
  50. package/core/audits/insights/image-delivery-insight.js +1 -1
  51. package/core/audits/insights/insight-audit.d.ts +11 -9
  52. package/core/audits/insights/insight-audit.js +37 -35
  53. package/core/audits/insights/interaction-to-next-paint-insight.js +3 -6
  54. package/core/audits/insights/lcp-discovery-insight.js +6 -3
  55. package/core/audits/insights/lcp-phases-insight.js +3 -6
  56. package/core/audits/insights/legacy-javascript-insight.d.ts +23 -0
  57. package/core/audits/insights/legacy-javascript-insight.js +101 -0
  58. package/core/audits/insights/modern-http-insight.d.ts +11 -0
  59. package/core/audits/insights/modern-http-insight.js +53 -0
  60. package/core/audits/insights/network-dependency-tree-insight.d.ts +5 -0
  61. package/core/audits/insights/network-dependency-tree-insight.js +35 -13
  62. package/core/audits/insights/render-blocking-insight.js +1 -1
  63. package/core/audits/insights/slow-css-selector-insight.js +3 -1
  64. package/core/audits/insights/third-parties-insight.d.ts +3 -3
  65. package/core/audits/insights/third-parties-insight.js +28 -23
  66. package/core/audits/insights/viewport-insight.js +1 -1
  67. package/core/audits/is-on-https.js +2 -2
  68. package/core/audits/largest-contentful-paint-element.js +3 -3
  69. package/core/audits/layout-shifts.js +4 -4
  70. package/core/audits/lcp-lazy-loaded.js +1 -1
  71. package/core/audits/long-tasks.d.ts +1 -1
  72. package/core/audits/long-tasks.js +3 -3
  73. package/core/audits/main-thread-tasks.js +2 -2
  74. package/core/audits/mainthread-work-breakdown.d.ts +1 -1
  75. package/core/audits/mainthread-work-breakdown.js +2 -2
  76. package/core/audits/manual/manual-audit.d.ts +1 -1
  77. package/core/audits/metrics/cumulative-layout-shift.d.ts +1 -1
  78. package/core/audits/metrics/cumulative-layout-shift.js +2 -2
  79. package/core/audits/metrics/first-contentful-paint.js +3 -3
  80. package/core/audits/metrics/first-meaningful-paint.js +1 -1
  81. package/core/audits/metrics/interaction-to-next-paint.d.ts +1 -1
  82. package/core/audits/metrics/interaction-to-next-paint.js +2 -2
  83. package/core/audits/metrics/interactive.js +3 -3
  84. package/core/audits/metrics/largest-contentful-paint.js +3 -3
  85. package/core/audits/metrics/max-potential-fid.d.ts +1 -1
  86. package/core/audits/metrics/max-potential-fid.js +3 -3
  87. package/core/audits/metrics/speed-index.js +3 -3
  88. package/core/audits/metrics/total-blocking-time.js +3 -3
  89. package/core/audits/metrics.js +3 -3
  90. package/core/audits/network-requests.js +2 -2
  91. package/core/audits/network-rtt.js +2 -2
  92. package/core/audits/network-server-latency.js +2 -2
  93. package/core/audits/origin-isolation.js +2 -2
  94. package/core/audits/predictive-perf.js +3 -3
  95. package/core/audits/preload-fonts.js +2 -2
  96. package/core/audits/prioritize-lcp-image.js +3 -3
  97. package/core/audits/redirects.js +3 -3
  98. package/core/audits/resource-summary.js +2 -2
  99. package/core/audits/screenshot-thumbnails.js +2 -2
  100. package/core/audits/script-treemap-data.js +32 -2
  101. package/core/audits/seo/canonical.js +2 -2
  102. package/core/audits/seo/http-status-code.js +2 -2
  103. package/core/audits/seo/is-crawlable.js +2 -2
  104. package/core/audits/server-response-time.js +2 -2
  105. package/core/audits/third-party-cookies.js +1 -1
  106. package/core/audits/third-party-facades.js +2 -2
  107. package/core/audits/third-party-summary.js +2 -2
  108. package/core/audits/user-timings.d.ts +1 -1
  109. package/core/audits/user-timings.js +2 -2
  110. package/core/audits/uses-rel-preconnect.js +3 -3
  111. package/core/audits/uses-rel-preload.js +3 -3
  112. package/core/audits/valid-source-maps.js +2 -2
  113. package/core/audits/work-during-interaction.js +3 -3
  114. package/core/computed/critical-request-chains.d.ts +1 -1
  115. package/core/computed/document-urls.d.ts +4 -1
  116. package/core/computed/entity-classification.d.ts +1 -1
  117. package/core/computed/image-records.d.ts +1 -1
  118. package/core/computed/js-bundles.d.ts +1 -1
  119. package/core/computed/lcp-image-record.d.ts +1 -1
  120. package/core/computed/load-simulator.d.ts +1 -1
  121. package/core/computed/main-resource.d.ts +1 -1
  122. package/core/computed/main-thread-tasks.d.ts +1 -1
  123. package/core/computed/metrics/cumulative-layout-shift.d.ts +10 -1
  124. package/core/computed/metrics/first-contentful-paint-all-frames.d.ts +1 -1
  125. package/core/computed/metrics/first-contentful-paint.d.ts +1 -1
  126. package/core/computed/metrics/interactive.d.ts +1 -1
  127. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +1 -1
  128. package/core/computed/metrics/lantern-interactive.d.ts +1 -1
  129. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +1 -1
  130. package/core/computed/metrics/lantern-max-potential-fid.d.ts +1 -1
  131. package/core/computed/metrics/lantern-speed-index.d.ts +1 -1
  132. package/core/computed/metrics/lantern-total-blocking-time.d.ts +1 -1
  133. package/core/computed/metrics/largest-contentful-paint-all-frames.d.ts +1 -1
  134. package/core/computed/metrics/largest-contentful-paint.d.ts +1 -1
  135. package/core/computed/metrics/lcp-breakdown.d.ts +5 -1
  136. package/core/computed/metrics/max-potential-fid.d.ts +1 -1
  137. package/core/computed/metrics/responsiveness.d.ts +1 -1
  138. package/core/computed/metrics/speed-index.d.ts +1 -1
  139. package/core/computed/metrics/time-to-first-byte.d.ts +1 -1
  140. package/core/computed/metrics/timing-summary.d.ts +4 -1
  141. package/core/computed/metrics/total-blocking-time.d.ts +1 -1
  142. package/core/computed/module-duplication.d.ts +5 -1
  143. package/core/computed/navigation-insights.d.ts +1 -1
  144. package/core/computed/network-analysis.d.ts +1 -1
  145. package/core/computed/network-records.d.ts +1 -1
  146. package/core/computed/page-dependency-graph.d.ts +1 -1
  147. package/core/computed/processed-navigation.d.ts +1 -1
  148. package/core/computed/processed-trace.d.ts +1 -1
  149. package/core/computed/resource-summary.d.ts +1 -1
  150. package/core/computed/screenshots.d.ts +4 -1
  151. package/core/computed/speedline.d.ts +1 -1
  152. package/core/computed/tbt-impact-tasks.d.ts +1 -1
  153. package/core/computed/trace-engine-result.d.ts +1 -1
  154. package/core/computed/unused-css.d.ts +1 -1
  155. package/core/computed/unused-javascript-summary.d.ts +1 -1
  156. package/core/computed/user-timings.d.ts +1 -1
  157. package/core/computed/viewport-meta.d.ts +1 -1
  158. package/core/config/default-config.js +11 -6
  159. package/core/config/experimental-config.js +3 -2
  160. package/core/gather/driver/network-monitor.d.ts +1 -1
  161. package/core/gather/driver/network.d.ts +1 -1
  162. package/core/gather/driver.d.ts +1 -1
  163. package/core/gather/gatherers/devtools-log.d.ts +1 -1
  164. package/core/gather/gatherers/dobetterweb/optimized-images.js +3 -10
  165. package/core/gather/gatherers/trace-elements.d.ts +3 -4
  166. package/core/gather/gatherers/trace-elements.js +6 -8
  167. package/core/gather/gatherers/trace.js +0 -3
  168. package/core/gather/navigation-runner.d.ts +1 -1
  169. package/core/gather/snapshot-runner.d.ts +1 -1
  170. package/core/gather/timespan-runner.d.ts +1 -1
  171. package/core/index.d.ts +6 -6
  172. package/core/lib/asset-saver.d.ts +1 -1
  173. package/core/lib/asset-saver.js +1 -1
  174. package/core/lib/bf-cache-strings.js +2 -0
  175. package/core/lib/deprecations-strings.d.ts +71 -76
  176. package/core/lib/deprecations-strings.js +22 -25
  177. package/core/lib/i18n/README.md +1 -1
  178. package/core/lib/i18n/i18n.d.ts +1 -1
  179. package/core/lib/i18n/i18n.js +4 -4
  180. package/core/lib/legacy-javascript/legacy-javascript.js +4 -11
  181. package/core/lib/legacy-javascript/package.json +14 -0
  182. package/core/lib/page-functions.d.ts +1 -1
  183. package/core/lib/stack-packs.js +1 -1
  184. package/core/lib/tracehouse/cpu-profile-model.d.ts +1 -1
  185. package/core/lib/tracehouse/main-thread-tasks.d.ts +3 -3
  186. package/core/lib/tracehouse/main-thread-tasks.js +8 -0
  187. package/core/lib/tracehouse/trace-processor.d.ts +1 -1
  188. package/core/lib/traces/metric-trace-events.d.ts +2 -2
  189. package/core/runner.js +2 -1
  190. package/core/scoring.d.ts +539 -3
  191. package/core/user-flow.d.ts +6 -6
  192. package/dist/report/bundle.esm.js +89 -19
  193. package/dist/report/flow.js +92 -22
  194. package/dist/report/standalone.js +89 -19
  195. package/flow-report/src/i18n/i18n.d.ts +6 -2
  196. package/package.json +17 -16
  197. package/readme.md +1 -1
  198. package/report/README.md +1 -1
  199. package/report/assets/styles.css +76 -9
  200. package/report/assets/templates.html +3 -1
  201. package/report/clients/standalone.js +6 -4
  202. package/report/renderer/category-renderer.d.ts +2 -2
  203. package/report/renderer/components.js +3 -9
  204. package/report/renderer/crc-details-renderer.d.ts +13 -31
  205. package/report/renderer/crc-details-renderer.js +49 -47
  206. package/report/renderer/details-renderer.d.ts +1 -1
  207. package/report/renderer/details-renderer.js +6 -0
  208. package/report/renderer/dom.js +7 -0
  209. package/report/renderer/features-util.d.ts +1 -1
  210. package/report/renderer/performance-category-renderer.d.ts +28 -2
  211. package/report/renderer/performance-category-renderer.js +121 -3
  212. package/report/renderer/report-utils.d.ts +3 -1
  213. package/report/renderer/report-utils.js +11 -4
  214. package/report/renderer/topbar-features.js +1 -9
  215. package/shared/localization/format.d.ts +1 -1
  216. package/shared/localization/locales/ar-XB.json +66 -6
  217. package/shared/localization/locales/ar.json +66 -6
  218. package/shared/localization/locales/bg.json +66 -6
  219. package/shared/localization/locales/ca.json +66 -6
  220. package/shared/localization/locales/cs.json +66 -6
  221. package/shared/localization/locales/da.json +66 -6
  222. package/shared/localization/locales/de.json +66 -6
  223. package/shared/localization/locales/el.json +66 -6
  224. package/shared/localization/locales/en-GB.json +66 -6
  225. package/shared/localization/locales/en-US.json +87 -36
  226. package/shared/localization/locales/en-XA.json +0 -6
  227. package/shared/localization/locales/en-XL.json +87 -36
  228. package/shared/localization/locales/es-419.json +66 -6
  229. package/shared/localization/locales/es.json +67 -7
  230. package/shared/localization/locales/fi.json +66 -6
  231. package/shared/localization/locales/fil.json +66 -6
  232. package/shared/localization/locales/fr.json +66 -6
  233. package/shared/localization/locales/he.json +66 -6
  234. package/shared/localization/locales/hi.json +66 -6
  235. package/shared/localization/locales/hr.json +66 -6
  236. package/shared/localization/locales/hu.json +66 -6
  237. package/shared/localization/locales/id.json +66 -6
  238. package/shared/localization/locales/it.json +67 -7
  239. package/shared/localization/locales/ja.json +66 -6
  240. package/shared/localization/locales/ko.json +66 -6
  241. package/shared/localization/locales/lt.json +66 -6
  242. package/shared/localization/locales/lv.json +66 -6
  243. package/shared/localization/locales/nl.json +66 -6
  244. package/shared/localization/locales/no.json +66 -6
  245. package/shared/localization/locales/pl.json +66 -6
  246. package/shared/localization/locales/pt-PT.json +66 -6
  247. package/shared/localization/locales/pt.json +67 -7
  248. package/shared/localization/locales/ro.json +66 -6
  249. package/shared/localization/locales/ru.json +66 -6
  250. package/shared/localization/locales/sk.json +66 -6
  251. package/shared/localization/locales/sl.json +66 -6
  252. package/shared/localization/locales/sr-Latn.json +66 -6
  253. package/shared/localization/locales/sr.json +66 -6
  254. package/shared/localization/locales/sv.json +66 -6
  255. package/shared/localization/locales/ta.json +69 -9
  256. package/shared/localization/locales/te.json +66 -6
  257. package/shared/localization/locales/th.json +66 -6
  258. package/shared/localization/locales/tr.json +66 -6
  259. package/shared/localization/locales/uk.json +66 -6
  260. package/shared/localization/locales/vi.json +66 -6
  261. package/shared/localization/locales/zh-HK.json +67 -7
  262. package/shared/localization/locales/zh-TW.json +67 -7
  263. package/shared/localization/locales/zh.json +66 -6
  264. package/tsconfig-base.json +1 -1
  265. package/tsconfig.json +1 -0
  266. package/types/artifacts.d.ts +0 -2
  267. package/types/internal/node.d.ts +0 -16
  268. package/types/lhr/audit-details.d.ts +33 -1
  269. package/types/lhr/treemap.d.ts +5 -1
@@ -11,6 +11,8 @@
11
11
 
12
12
 
13
13
  import {Audit} from './audit.js';
14
+ import {ImageRecords} from '../computed/image-records.js';
15
+ import {NetworkRecords} from '../computed/network-records.js';
14
16
  import UrlUtils from '../lib/url-utils.js';
15
17
  import * as i18n from '../lib/i18n/i18n.js';
16
18
 
@@ -77,9 +79,10 @@ function isSmallerThanViewport(imageRect, viewportDimensions) {
77
79
 
78
80
  /**
79
81
  * @param {LH.Artifacts.ImageElement} image
82
+ * @param {LH.Artifacts.ImageElementRecord | undefined} imageRecord
80
83
  * @return {boolean}
81
84
  */
82
- function isCandidate(image) {
85
+ function isCandidate(image, imageRecord) {
83
86
  /** image-rendering solution for pixel art scaling.
84
87
  * https://developer.mozilla.org/en-US/docs/Games/Techniques/Crisp_pixel_art_look
85
88
  */
@@ -96,6 +99,10 @@ function isCandidate(image) {
96
99
  ) {
97
100
  return false;
98
101
  }
102
+ // Check the actual mimeType before guessing, since file extension is not guaranteed
103
+ if (imageRecord?.mimeType === 'image/svg+xml') {
104
+ return false;
105
+ }
99
106
  if (UrlUtils.guessMimeType(image.src) === 'image/svg+xml') {
100
107
  return false;
101
108
  }
@@ -243,19 +250,38 @@ class ImageSizeResponsive extends Audit {
243
250
  failureTitle: str_(UIStrings.failureTitle),
244
251
  description: str_(UIStrings.description),
245
252
  requiredArtifacts: ['ImageElements', 'ViewportDimensions'],
253
+ __internalOptionalArtifacts: ['DevtoolsLog'],
246
254
  };
247
255
  }
248
256
 
249
257
  /**
250
258
  * @param {LH.Artifacts} artifacts
251
- * @return {LH.Audit.Product}
259
+ * @param {LH.Audit.Context} context
260
+ * @return {Promise<LH.Audit.Product>}
252
261
  */
253
- static audit(artifacts) {
262
+ static async audit(artifacts, context) {
254
263
  const DPR = artifacts.ViewportDimensions.devicePixelRatio;
255
264
 
265
+ // Prepare ImageElementRecord map for retrieving the real mimeType
266
+ // Derived from ./is-on-https.js and ./byte-efficiency/uses-responsive-images.js
267
+ /** @type {Map<string, LH.Artifacts.ImageElementRecord>} */
268
+ const imageRecordsByURL = new Map();
269
+
270
+ if (artifacts.DevtoolsLog) {
271
+ // https://github.com/GoogleChrome/lighthouse/blob/main/docs/plugins.md#using-network-requests
272
+ // if DevtoolsLog is provided, use it to fetch image networkRecords
273
+ // else the empty imageRecordsByURL map will satisfy isCandidate with an undefined image and fallback to the original logic
274
+ const networkRecords = await NetworkRecords.request(artifacts.DevtoolsLog, context);
275
+ const images = await ImageRecords.request({
276
+ ImageElements: artifacts.ImageElements,
277
+ networkRecords,
278
+ }, context);
279
+ images.forEach(img => imageRecordsByURL.set(img.src, img));
280
+ }
281
+
256
282
  const results = Array
257
283
  .from(artifacts.ImageElements)
258
- .filter(isCandidate)
284
+ .filter(image => isCandidate(image, imageRecordsByURL.get(image.src)))
259
285
  .filter(imageHasNaturalDimensions)
260
286
  .filter(image => !imageHasRightSize(image, DPR))
261
287
  .filter(image => isVisible(image.clientRect, artifacts.ViewportDimensions))
@@ -1,5 +1,5 @@
1
- export default UseCacheInsight;
2
- declare class UseCacheInsight extends Audit {
1
+ export default CacheInsight;
2
+ declare class CacheInsight extends Audit {
3
3
  /**
4
4
  * @param {LH.Artifacts} artifacts
5
5
  * @param {LH.Audit.Context} context
@@ -8,4 +8,4 @@ declare class UseCacheInsight extends Audit {
8
8
  static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
9
  }
10
10
  import { Audit } from '../audit.js';
11
- //# sourceMappingURL=use-cache-insight.d.ts.map
11
+ //# sourceMappingURL=cache-insight.d.ts.map
@@ -4,27 +4,27 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/UseCache.js';
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/Cache.js';
8
8
 
9
9
  import {Audit} from '../audit.js';
10
10
  import * as i18n from '../../lib/i18n/i18n.js';
11
11
  import {adaptInsightToAuditProduct} from './insight-audit.js';
12
12
 
13
13
  // eslint-disable-next-line max-len
14
- const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/UseCache.js', UIStrings);
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js', UIStrings);
15
15
 
16
- class UseCacheInsight extends Audit {
16
+ class CacheInsight extends Audit {
17
17
  /**
18
18
  * @return {LH.Audit.Meta}
19
19
  */
20
20
  static get meta() {
21
21
  return {
22
- id: 'use-cache-insight',
22
+ id: 'cache-insight',
23
23
  title: str_(UIStrings.title),
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
26
26
  guidanceLevel: 3,
27
- requiredArtifacts: ['traces', 'SourceMaps'],
27
+ requiredArtifacts: ['Trace', 'SourceMaps'],
28
28
  replacesAudits: ['uses-long-cache-ttl'],
29
29
  };
30
30
  }
@@ -35,27 +35,29 @@ class UseCacheInsight extends Audit {
35
35
  * @return {Promise<LH.Audit.Product>}
36
36
  */
37
37
  static async audit(artifacts, context) {
38
- return adaptInsightToAuditProduct(artifacts, context, 'UseCache', (insight) => {
38
+ return adaptInsightToAuditProduct(artifacts, context, 'Cache', (insight) => {
39
39
  /** @type {LH.Audit.Details.Table['headings']} */
40
40
  const headings = [
41
41
  /* eslint-disable max-len */
42
42
  {key: 'url', valueType: 'url', label: str_(UIStrings.requestColumn)},
43
43
  {key: 'cacheLifetimeMs', valueType: 'ms', label: str_(UIStrings.cacheTTL), displayUnit: 'duration'},
44
- {key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize), displayUnit: 'kb', granularity: 1},
44
+ {key: 'wastedBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize), displayUnit: 'kb', granularity: 1},
45
45
  /* eslint-enable max-len */
46
46
  ];
47
+ // TODO: this should be the sorting in the model (instead it sorts by transfer size...)
48
+ const values = insight.requests.sort((a, b) => b.wastedBytes - a.wastedBytes);
47
49
  /** @type {LH.Audit.Details.Table['items']} */
48
- const items = insight.requests.map(request => ({
49
- url: request.request.args.data.url,
50
- cacheLifetimeMs: request.ttl * 1000,
51
- totalBytes: request.request.args.data.encodedDataLength,
50
+ const items = values.map(value => ({
51
+ url: value.request.args.data.url,
52
+ cacheLifetimeMs: value.ttl * 1000,
53
+ wastedBytes: value.wastedBytes,
52
54
  }));
53
55
  return Audit.makeTableDetails(headings, items, {
54
- sortedBy: ['totalBytes'],
56
+ sortedBy: ['wastedBytes'],
55
57
  skipSumming: ['cacheLifetimeMs'],
56
58
  });
57
59
  });
58
60
  }
59
61
  }
60
62
 
61
- export default UseCacheInsight;
63
+ export default CacheInsight;
@@ -39,7 +39,7 @@ class CLSCulpritsInsight extends Audit {
39
39
  failureTitle: insightStr_(InsightUIStrings.title),
40
40
  description: insightStr_(InsightUIStrings.description),
41
41
  guidanceLevel: 3,
42
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
42
+ requiredArtifacts: ['Trace', 'TraceElements', 'SourceMaps'],
43
43
  replacesAudits: ['layout-shifts', 'non-composited-animations', 'unsized-images'],
44
44
  };
45
45
  }
@@ -58,9 +58,9 @@ class CLSCulpritsInsight extends Audit {
58
58
 
59
59
  /** @type {SubItem[]} */
60
60
  const subItems = [];
61
- for (const backendNodeId of culprits.unsizedImages) {
61
+ for (const unsizedImage of culprits.unsizedImages) {
62
62
  subItems.push({
63
- extra: makeNodeItemForNodeId(TraceElements, backendNodeId),
63
+ extra: makeNodeItemForNodeId(TraceElements, unsizedImage.backendNodeId),
64
64
  cause: insightStr_(InsightUIStrings.unsizedImages),
65
65
  });
66
66
  }
@@ -24,7 +24,7 @@ class DocumentLatencyInsight extends Audit {
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
26
26
  guidanceLevel: 3,
27
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
27
+ requiredArtifacts: ['Trace', 'TraceElements', 'SourceMaps'],
28
28
  replacesAudits: ['redirects', 'server-response-time', 'uses-text-compression'],
29
29
  };
30
30
  }
@@ -24,7 +24,7 @@ class DOMSizeInsight extends Audit {
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
26
26
  guidanceLevel: 3,
27
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
27
+ requiredArtifacts: ['Trace', 'TraceElements', 'SourceMaps'],
28
28
  replacesAudits: ['dom-size'],
29
29
  };
30
30
  }
@@ -1,4 +1,17 @@
1
1
  export default DuplicatedJavaScriptInsight;
2
+ export type Item = LH.Audit.Details.TableItem & {
3
+ source: string;
4
+ subItems: {
5
+ type: "subitems";
6
+ items: SubItem[];
7
+ };
8
+ };
9
+ export type SubItem = {
10
+ url: string;
11
+ sourceTransferBytes: number | LH.Audit.Details.TextValue;
12
+ };
13
+ /** @typedef {LH.Audit.Details.TableItem & {source: string, subItems: {type: 'subitems', items: SubItem[]}}} Item */
14
+ /** @typedef {{url: string, sourceTransferBytes: number|LH.Audit.Details.TextValue}} SubItem */
2
15
  declare class DuplicatedJavaScriptInsight extends Audit {
3
16
  /**
4
17
  * @param {LH.Artifacts} artifacts
@@ -1,5 +1,3 @@
1
- /* eslint-disable no-unused-vars */ // TODO: remove once implemented.
2
-
3
1
  /**
4
2
  * @license
5
3
  * Copyright 2025 Google LLC
@@ -10,11 +8,14 @@ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/Duplicate
10
8
 
11
9
  import {Audit} from '../audit.js';
12
10
  import * as i18n from '../../lib/i18n/i18n.js';
13
- import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
11
+ import {adaptInsightToAuditProduct} from './insight-audit.js';
14
12
 
15
13
  // eslint-disable-next-line max-len
16
14
  const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/DuplicatedJavaScript.js', UIStrings);
17
15
 
16
+ /** @typedef {LH.Audit.Details.TableItem & {source: string, subItems: {type: 'subitems', items: SubItem[]}}} Item */
17
+ /** @typedef {{url: string, sourceTransferBytes: number|LH.Audit.Details.TextValue}} SubItem */
18
+
18
19
  class DuplicatedJavaScriptInsight extends Audit {
19
20
  /**
20
21
  * @return {LH.Audit.Meta}
@@ -25,8 +26,9 @@ class DuplicatedJavaScriptInsight extends Audit {
25
26
  title: str_(UIStrings.title),
26
27
  failureTitle: str_(UIStrings.title),
27
28
  description: str_(UIStrings.description),
28
- guidanceLevel: 3, // TODO: confirm/change.
29
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
29
+ guidanceLevel: 2,
30
+ requiredArtifacts: ['Trace', 'SourceMaps'],
31
+ replacesAudits: ['duplicated-javascript'],
30
32
  };
31
33
  }
32
34
 
@@ -36,16 +38,41 @@ class DuplicatedJavaScriptInsight extends Audit {
36
38
  * @return {Promise<LH.Audit.Product>}
37
39
  */
38
40
  static async audit(artifacts, context) {
39
- // TODO: implement.
40
41
  return adaptInsightToAuditProduct(artifacts, context, 'DuplicatedJavaScript', (insight) => {
41
42
  /** @type {LH.Audit.Details.Table['headings']} */
42
43
  const headings = [
43
44
  /* eslint-disable max-len */
45
+ {key: 'source', valueType: 'code', subItemsHeading: {key: 'url', valueType: 'url'}, label: str_(i18n.UIStrings.columnSource)},
46
+ {key: 'wastedBytes', valueType: 'bytes', subItemsHeading: {key: 'sourceTransferBytes'}, granularity: 10, label: str_(UIStrings.columnDuplicatedBytes)},
44
47
  /* eslint-enable max-len */
45
48
  ];
46
- /** @type {LH.Audit.Details.Table['items']} */
47
- const items = [
48
- ];
49
+
50
+ const entries = [...insight.duplicationGroupedByNodeModules.entries()].slice(0, 10);
51
+
52
+ /** @type {Item[]} */
53
+ const items = entries.map(([source, data]) => {
54
+ /** @type {Item} */
55
+ const item = {
56
+ source,
57
+ wastedBytes: data.estimatedDuplicateBytes,
58
+ subItems: {
59
+ type: 'subitems',
60
+ items: [],
61
+ },
62
+ };
63
+
64
+ for (const [index, {script, attributedSize}] of data.duplicates.entries()) {
65
+ /** @type {SubItem} */
66
+ const subItem = {
67
+ url: script.url ?? '',
68
+ sourceTransferBytes: index === 0 ? {type: 'text', value: '--'} : attributedSize,
69
+ };
70
+ item.subItems.items.push(subItem);
71
+ }
72
+
73
+ return item;
74
+ });
75
+
49
76
  return Audit.makeTableDetails(headings, items);
50
77
  });
51
78
  }
@@ -24,7 +24,7 @@ class FontDisplayInsight extends Audit {
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
26
26
  guidanceLevel: 3,
27
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
27
+ requiredArtifacts: ['Trace', 'TraceElements', 'SourceMaps'],
28
28
  replacesAudits: ['font-display'],
29
29
  };
30
30
  }
@@ -24,7 +24,7 @@ class ForcedReflowInsight extends Audit {
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
26
26
  guidanceLevel: 3,
27
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
27
+ requiredArtifacts: ['Trace', 'TraceElements', 'SourceMaps'],
28
28
  };
29
29
  }
30
30
 
@@ -29,7 +29,7 @@ class ImageDeliveryInsight extends Audit {
29
29
  failureTitle: str_(UIStrings.title),
30
30
  description: str_(UIStrings.description),
31
31
  guidanceLevel: 3,
32
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
32
+ requiredArtifacts: ['Trace', 'TraceElements', 'SourceMaps'],
33
33
  replacesAudits: [
34
34
  'modern-image-formats',
35
35
  'uses-optimized-images',
@@ -1,23 +1,25 @@
1
+ export type CreateDetailsExtras = {
2
+ insights: import("@paulirish/trace_engine/models/trace/insights/types.js").InsightSet;
3
+ parsedTrace: LH.Artifacts.TraceEngineResult["data"];
4
+ };
5
+ /**
6
+ * @typedef CreateDetailsExtras
7
+ * @property {import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet} insights
8
+ * @property {LH.Artifacts.TraceEngineResult['data']} parsedTrace
9
+ */
1
10
  /**
2
11
  * @param {LH.Artifacts} artifacts
3
12
  * @param {LH.Audit.Context} context
4
13
  * @param {T} insightName
5
- * @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T]) => LH.Audit.Details|undefined} createDetails
14
+ * @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T], extras: CreateDetailsExtras) => LH.Audit.Details|undefined} createDetails
6
15
  * @template {keyof import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModelsType} T
7
16
  * @return {Promise<LH.Audit.Product>}
8
17
  */
9
- export function adaptInsightToAuditProduct<T extends keyof import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModelsType>(artifacts: LH.Artifacts, context: LH.Audit.Context, insightName: T, createDetails: (insight: import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModels[T]) => LH.Audit.Details | undefined): Promise<LH.Audit.Product>;
18
+ export function adaptInsightToAuditProduct<T extends keyof import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModelsType>(artifacts: LH.Artifacts, context: LH.Audit.Context, insightName: T, createDetails: (insight: import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModels[T], extras: CreateDetailsExtras) => LH.Audit.Details | undefined): Promise<LH.Audit.Product>;
10
19
  /**
11
20
  * @param {LH.Artifacts.TraceElement[]} traceElements
12
21
  * @param {number|null|undefined} nodeId
13
22
  * @return {LH.Audit.Details.NodeValue|undefined}
14
23
  */
15
24
  export function makeNodeItemForNodeId(traceElements: LH.Artifacts.TraceElement[], nodeId: number | null | undefined): LH.Audit.Details.NodeValue | undefined;
16
- /**
17
- * @param {LH.Artifacts.TraceElement[]} traceElements
18
- * @param {number|null|undefined} nodeId
19
- * @param {LH.IcuMessage|string} label
20
- * @return {LH.Audit.Details.Table|undefined}
21
- */
22
- export function maybeMakeNodeElementTable(traceElements: LH.Artifacts.TraceElement[], nodeId: number | null | undefined, label: LH.IcuMessage | string): LH.Audit.Details.Table | undefined;
23
25
  //# sourceMappingURL=insight-audit.d.ts.map
@@ -9,35 +9,45 @@ import {NO_NAVIGATION} from '@paulirish/trace_engine/models/trace/types/TraceEve
9
9
  import {ProcessedTrace} from '../../computed/processed-trace.js';
10
10
  import {TraceEngineResult} from '../../computed/trace-engine-result.js';
11
11
  import {Audit} from '../audit.js';
12
+ import * as i18n from '../../lib/i18n/i18n.js';
13
+
14
+ const str_ = i18n.createIcuMessageFn(import.meta.url, {});
12
15
 
13
16
  /**
14
17
  * @param {LH.Artifacts} artifacts
15
18
  * @param {LH.Audit.Context} context
16
- * @return {Promise<import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet|undefined>}
19
+ * @return {Promise<{insights: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet|undefined, parsedTrace: LH.Artifacts.TraceEngineResult['data']}>}
17
20
  */
18
21
  async function getInsightSet(artifacts, context) {
19
22
  const settings = context.settings;
20
- const trace = artifacts.traces[Audit.DEFAULT_PASS];
23
+ const trace = artifacts.Trace;
21
24
  const processedTrace = await ProcessedTrace.request(trace, context);
22
25
  const SourceMaps = artifacts.SourceMaps;
23
26
  const traceEngineResult = await TraceEngineResult.request({trace, settings, SourceMaps}, context);
24
27
 
25
28
  const navigationId = processedTrace.timeOriginEvt.args.data?.navigationId;
26
29
  const key = navigationId ?? NO_NAVIGATION;
30
+ const insights = traceEngineResult.insights.get(key);
27
31
 
28
- return traceEngineResult.insights.get(key);
32
+ return {insights, parsedTrace: traceEngineResult.data};
29
33
  }
30
34
 
35
+ /**
36
+ * @typedef CreateDetailsExtras
37
+ * @property {import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet} insights
38
+ * @property {LH.Artifacts.TraceEngineResult['data']} parsedTrace
39
+ */
40
+
31
41
  /**
32
42
  * @param {LH.Artifacts} artifacts
33
43
  * @param {LH.Audit.Context} context
34
44
  * @param {T} insightName
35
- * @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T]) => LH.Audit.Details|undefined} createDetails
45
+ * @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T], extras: CreateDetailsExtras) => LH.Audit.Details|undefined} createDetails
36
46
  * @template {keyof import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModelsType} T
37
47
  * @return {Promise<LH.Audit.Product>}
38
48
  */
39
49
  async function adaptInsightToAuditProduct(artifacts, context, insightName, createDetails) {
40
- const insights = await getInsightSet(artifacts, context);
50
+ const {insights, parsedTrace} = await getInsightSet(artifacts, context);
41
51
  if (!insights) {
42
52
  return {
43
53
  scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,
@@ -54,7 +64,10 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
54
64
  };
55
65
  }
56
66
 
57
- const details = createDetails(insight);
67
+ const details = createDetails(insight, {
68
+ parsedTrace,
69
+ insights,
70
+ });
58
71
  if (!details || (details.type === 'table' && details.headings.length === 0)) {
59
72
  return {
60
73
  scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,
@@ -73,23 +86,30 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
73
86
  metricSavings = {...metricSavings, LCP: /** @type {any} */ (0)};
74
87
  }
75
88
 
76
- let score = 1;
77
- if (insight.state === 'fail') {
78
- score = 0;
79
- } else if (insightName === 'LCPPhases') {
80
- // TODO: change these insights to denote passing/failing/informative. Until then... hack it.
81
- score = metricSavings?.LCP ?? 0 >= 1000 ? 0 : 1;
82
- } else if (insightName === 'InteractionToNextPaint') {
83
- // TODO: change these insights to denote passing/failing/informative. Until then... hack it.
84
- score = metricSavings?.INP ?? 0 >= 500 ? 0 : 1;
89
+ // TODO: consider adding a `estimatedSavingsText` to InsightModel, which can capture
90
+ // the exact i18n string used by RPP; and include the same est. timing savings.
91
+ let displayValue;
92
+ if (insight.wastedBytes) {
93
+ displayValue = str_(i18n.UIStrings.displayValueByteSavings, {wastedBytes: insight.wastedBytes});
94
+ }
95
+
96
+ let score;
97
+ let scoreDisplayMode;
98
+ if (insight.state === 'fail' || insight.state === 'pass') {
99
+ score = insight.state === 'fail' ? 0 : 1;
100
+ scoreDisplayMode =
101
+ insight.metricSavings ? Audit.SCORING_MODES.METRIC_SAVINGS : Audit.SCORING_MODES.NUMERIC;
102
+ } else {
103
+ score = null;
104
+ scoreDisplayMode = Audit.SCORING_MODES.INFORMATIVE;
85
105
  }
86
106
 
87
107
  return {
88
- scoreDisplayMode:
89
- insight.metricSavings ? Audit.SCORING_MODES.METRIC_SAVINGS : Audit.SCORING_MODES.NUMERIC,
108
+ scoreDisplayMode,
90
109
  score,
91
110
  metricSavings,
92
111
  warnings: insight.warnings,
112
+ displayValue,
93
113
  details,
94
114
  };
95
115
  }
@@ -114,25 +134,7 @@ function makeNodeItemForNodeId(traceElements, nodeId) {
114
134
  return Audit.makeNodeItem(node);
115
135
  }
116
136
 
117
- /**
118
- * @param {LH.Artifacts.TraceElement[]} traceElements
119
- * @param {number|null|undefined} nodeId
120
- * @param {LH.IcuMessage|string} label
121
- * @return {LH.Audit.Details.Table|undefined}
122
- */
123
- function maybeMakeNodeElementTable(traceElements, nodeId, label) {
124
- const node = makeNodeItemForNodeId(traceElements, nodeId);
125
- if (!node) {
126
- return;
127
- }
128
-
129
- return Audit.makeTableDetails([
130
- {key: 'node', valueType: 'node', label},
131
- ], [{node}]);
132
- }
133
-
134
137
  export {
135
138
  adaptInsightToAuditProduct,
136
139
  makeNodeItemForNodeId,
137
- maybeMakeNodeElementTable,
138
140
  };
@@ -8,7 +8,7 @@ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/Interacti
8
8
 
9
9
  import {Audit} from '../audit.js';
10
10
  import * as i18n from '../../lib/i18n/i18n.js';
11
- import {adaptInsightToAuditProduct, maybeMakeNodeElementTable} from './insight-audit.js';
11
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
12
12
 
13
13
  // eslint-disable-next-line max-len
14
14
  const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/InteractionToNextPaint.js', UIStrings);
@@ -24,7 +24,7 @@ class InteractionToNextPaintInsight extends Audit {
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
26
26
  guidanceLevel: 3,
27
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
27
+ requiredArtifacts: ['Trace', 'TraceElements', 'SourceMaps'],
28
28
  replacesAudits: ['work-during-interaction'],
29
29
  };
30
30
  }
@@ -58,11 +58,8 @@ class InteractionToNextPaintInsight extends Audit {
58
58
  ];
59
59
 
60
60
  return Audit.makeListDetails([
61
- maybeMakeNodeElementTable(
62
- artifacts.TraceElements,
63
- event.args.data.beginEvent.args.data.nodeId,
64
- str_(i18n.UIStrings.columnElement)),
65
61
  Audit.makeTableDetails(headings, items),
62
+ makeNodeItemForNodeId(artifacts.TraceElements, event.args.data.beginEvent.args.data.nodeId),
66
63
  ].filter(table => !!table));
67
64
  });
68
65
  }
@@ -8,7 +8,7 @@ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/LCPDiscov
8
8
 
9
9
  import {Audit} from '../audit.js';
10
10
  import * as i18n from '../../lib/i18n/i18n.js';
11
- import {adaptInsightToAuditProduct} from './insight-audit.js';
11
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
12
12
 
13
13
  // eslint-disable-next-line max-len
14
14
  const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/LCPDiscovery.js', UIStrings);
@@ -24,7 +24,7 @@ class LCPDiscoveryInsight extends Audit {
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
26
26
  guidanceLevel: 3,
27
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
27
+ requiredArtifacts: ['Trace', 'TraceElements', 'SourceMaps'],
28
28
  replacesAudits: ['prioritize-lcp-image', 'lcp-lazy-loaded'],
29
29
  };
30
30
  }
@@ -40,7 +40,10 @@ class LCPDiscoveryInsight extends Audit {
40
40
  return;
41
41
  }
42
42
 
43
- return Audit.makeChecklistDetails(insight.checklist);
43
+ return Audit.makeListDetails([
44
+ Audit.makeChecklistDetails(insight.checklist),
45
+ makeNodeItemForNodeId(artifacts.TraceElements, insight.lcpEvent?.args.data?.nodeId),
46
+ ].filter(d => !!d));
44
47
  });
45
48
  }
46
49
  }
@@ -8,7 +8,7 @@ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/LCPPhases
8
8
 
9
9
  import {Audit} from '../audit.js';
10
10
  import * as i18n from '../../lib/i18n/i18n.js';
11
- import {adaptInsightToAuditProduct, maybeMakeNodeElementTable} from './insight-audit.js';
11
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
12
12
 
13
13
  // eslint-disable-next-line max-len
14
14
  const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/LCPPhases.js', UIStrings);
@@ -24,7 +24,7 @@ class LCPPhasesInsight extends Audit {
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
26
26
  guidanceLevel: 3,
27
- requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
27
+ requiredArtifacts: ['Trace', 'TraceElements', 'SourceMaps'],
28
28
  replacesAudits: ['largest-contentful-paint-element'],
29
29
  };
30
30
  }
@@ -74,11 +74,8 @@ class LCPPhasesInsight extends Audit {
74
74
  }
75
75
 
76
76
  return Audit.makeListDetails([
77
- maybeMakeNodeElementTable(
78
- artifacts.TraceElements,
79
- insight.lcpEvent?.args.data?.nodeId,
80
- str_(i18n.UIStrings.columnElement)),
81
77
  LCPPhasesInsight.makePhaseTable(insight.phases),
78
+ makeNodeItemForNodeId(artifacts.TraceElements, insight.lcpEvent?.args.data?.nodeId),
82
79
  ].filter(table => table !== undefined));
83
80
  });
84
81
  }
@@ -0,0 +1,23 @@
1
+ export default LegacyJavaScriptInsight;
2
+ export type Item = LH.Audit.Details.TableItem & {
3
+ subItems: {
4
+ type: "subitems";
5
+ items: SubItem[];
6
+ };
7
+ };
8
+ export type SubItem = {
9
+ signal: string;
10
+ location: LH.Audit.Details.SourceLocationValue;
11
+ };
12
+ /** @typedef {LH.Audit.Details.TableItem & {subItems: {type: 'subitems', items: SubItem[]}}} Item */
13
+ /** @typedef {{signal: string, location: LH.Audit.Details.SourceLocationValue}} SubItem */
14
+ declare class LegacyJavaScriptInsight extends Audit {
15
+ /**
16
+ * @param {LH.Artifacts} artifacts
17
+ * @param {LH.Audit.Context} context
18
+ * @return {Promise<LH.Audit.Product>}
19
+ */
20
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
21
+ }
22
+ import { Audit } from '../audit.js';
23
+ //# sourceMappingURL=legacy-javascript-insight.d.ts.map