lighthouse 11.7.0 → 12.0.0-dev.20240422

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 (334) hide show
  1. package/CONTRIBUTING.md +2 -2
  2. package/cli/bin.js +0 -7
  3. package/cli/cli-flags.d.ts +1 -5
  4. package/cli/cli-flags.js +4 -8
  5. package/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap +14 -14
  6. package/cli/test/smokehouse/config/exclusions.js +3 -0
  7. package/cli/test/smokehouse/core-tests.js +6 -20
  8. package/cli/test/smokehouse/frontends/smokehouse-bin.js +2 -2
  9. package/core/audits/accessibility/accesskeys.js +1 -1
  10. package/core/audits/accessibility/aria-allowed-attr.js +1 -1
  11. package/core/audits/accessibility/aria-allowed-role.js +1 -1
  12. package/core/audits/accessibility/aria-command-name.js +1 -1
  13. package/core/audits/accessibility/aria-conditional-attr.d.ts +10 -0
  14. package/core/audits/accessibility/aria-conditional-attr.js +43 -0
  15. package/core/audits/accessibility/{duplicate-id-active.d.ts → aria-deprecated-role.d.ts} +3 -3
  16. package/core/audits/accessibility/aria-deprecated-role.js +43 -0
  17. package/core/audits/accessibility/aria-dialog-name.js +1 -1
  18. package/core/audits/accessibility/aria-hidden-body.js +1 -1
  19. package/core/audits/accessibility/aria-hidden-focus.js +1 -1
  20. package/core/audits/accessibility/aria-input-field-name.js +1 -1
  21. package/core/audits/accessibility/aria-meter-name.js +1 -1
  22. package/core/audits/accessibility/aria-progressbar-name.js +1 -1
  23. package/core/audits/accessibility/aria-prohibited-attr.d.ts +10 -0
  24. package/core/audits/accessibility/aria-prohibited-attr.js +44 -0
  25. package/core/audits/accessibility/aria-required-attr.js +1 -1
  26. package/core/audits/accessibility/aria-required-children.js +1 -1
  27. package/core/audits/accessibility/aria-required-parent.js +1 -1
  28. package/core/audits/accessibility/aria-roles.js +1 -1
  29. package/core/audits/accessibility/aria-text.js +1 -1
  30. package/core/audits/accessibility/aria-toggle-field-name.js +1 -1
  31. package/core/audits/accessibility/aria-tooltip-name.js +1 -1
  32. package/core/audits/accessibility/aria-treeitem-name.js +1 -1
  33. package/core/audits/accessibility/aria-valid-attr-value.js +1 -1
  34. package/core/audits/accessibility/aria-valid-attr.js +1 -1
  35. package/core/audits/accessibility/button-name.js +1 -1
  36. package/core/audits/accessibility/bypass.js +1 -1
  37. package/core/audits/accessibility/color-contrast.js +1 -1
  38. package/core/audits/accessibility/definition-list.js +1 -1
  39. package/core/audits/accessibility/dlitem.js +1 -1
  40. package/core/audits/accessibility/document-title.js +1 -1
  41. package/core/audits/accessibility/duplicate-id-aria.js +1 -1
  42. package/core/audits/accessibility/empty-heading.js +1 -1
  43. package/core/audits/accessibility/form-field-multiple-labels.js +1 -1
  44. package/core/audits/accessibility/frame-title.js +1 -1
  45. package/core/audits/accessibility/heading-order.js +1 -1
  46. package/core/audits/accessibility/html-has-lang.js +1 -1
  47. package/core/audits/accessibility/html-lang-valid.js +1 -1
  48. package/core/audits/accessibility/html-xml-lang-mismatch.js +1 -1
  49. package/core/audits/accessibility/identical-links-same-purpose.js +1 -1
  50. package/core/audits/accessibility/image-alt.js +1 -1
  51. package/core/audits/accessibility/image-redundant-alt.js +1 -1
  52. package/core/audits/accessibility/input-button-name.js +1 -1
  53. package/core/audits/accessibility/input-image-alt.js +1 -1
  54. package/core/audits/accessibility/label-content-name-mismatch.js +1 -1
  55. package/core/audits/accessibility/label.js +1 -1
  56. package/core/audits/accessibility/landmark-one-main.js +1 -1
  57. package/core/audits/accessibility/link-in-text-block.js +1 -1
  58. package/core/audits/accessibility/link-name.js +1 -1
  59. package/core/audits/accessibility/list.js +1 -1
  60. package/core/audits/accessibility/listitem.js +1 -1
  61. package/core/audits/accessibility/meta-refresh.js +1 -1
  62. package/core/audits/accessibility/meta-viewport.js +1 -1
  63. package/core/audits/accessibility/object-alt.js +1 -1
  64. package/core/audits/accessibility/select-name.js +1 -1
  65. package/core/audits/accessibility/skip-link.js +1 -1
  66. package/core/audits/accessibility/tabindex.js +1 -1
  67. package/core/audits/accessibility/table-duplicate-name.js +1 -1
  68. package/core/audits/accessibility/table-fake-caption.js +1 -1
  69. package/core/audits/accessibility/target-size.js +1 -2
  70. package/core/audits/accessibility/td-has-header.js +1 -1
  71. package/core/audits/accessibility/td-headers-attr.js +1 -1
  72. package/core/audits/accessibility/th-has-data-cells.js +1 -1
  73. package/core/audits/accessibility/valid-lang.js +1 -1
  74. package/core/audits/accessibility/video-caption.js +1 -1
  75. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +0 -16
  76. package/core/audits/byte-efficiency/byte-efficiency-audit.js +1 -38
  77. package/core/audits/byte-efficiency/offscreen-images.d.ts +0 -11
  78. package/core/audits/byte-efficiency/offscreen-images.js +0 -15
  79. package/core/audits/byte-efficiency/render-blocking-resources.js +27 -26
  80. package/core/audits/byte-efficiency/unminified-css.js +2 -2
  81. package/core/audits/byte-efficiency/unused-css-rules.js +3 -1
  82. package/core/audits/dobetterweb/uses-http2.d.ts +0 -13
  83. package/core/audits/dobetterweb/uses-http2.js +4 -38
  84. package/core/audits/font-display.js +2 -2
  85. package/core/audits/layout-shifts.js +2 -2
  86. package/core/audits/preload-fonts.d.ts +1 -5
  87. package/core/audits/preload-fonts.js +1 -10
  88. package/core/audits/prioritize-lcp-image.js +2 -2
  89. package/core/audits/redirects-http.d.ts +19 -0
  90. package/core/audits/redirects-http.js +75 -0
  91. package/core/audits/resource-summary.d.ts +2 -0
  92. package/core/audits/resource-summary.js +5 -4
  93. package/core/audits/seo/is-crawlable.d.ts +2 -1
  94. package/core/audits/seo/link-text.js +12 -0
  95. package/core/audits/uses-rel-preload.d.ts +1 -5
  96. package/core/audits/uses-rel-preload.js +5 -15
  97. package/core/audits/work-during-interaction.d.ts +2 -2
  98. package/core/audits/work-during-interaction.js +2 -2
  99. package/core/computed/js-bundles.d.ts +1 -1
  100. package/core/computed/metrics/cumulative-layout-shift.js +2 -2
  101. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +13 -82
  102. package/core/computed/metrics/lantern-first-contentful-paint.js +16 -178
  103. package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +13 -12
  104. package/core/computed/metrics/lantern-first-meaningful-paint.js +11 -49
  105. package/core/computed/metrics/lantern-interactive.d.ts +13 -21
  106. package/core/computed/metrics/lantern-interactive.js +12 -84
  107. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +13 -25
  108. package/core/computed/metrics/lantern-largest-contentful-paint.js +13 -80
  109. package/core/computed/metrics/lantern-max-potential-fid.d.ts +13 -24
  110. package/core/computed/metrics/lantern-max-potential-fid.js +12 -64
  111. package/core/computed/metrics/lantern-metric.d.ts +14 -18
  112. package/core/computed/metrics/lantern-metric.js +34 -30
  113. package/core/computed/metrics/lantern-speed-index.d.ts +13 -32
  114. package/core/computed/metrics/lantern-speed-index.js +13 -116
  115. package/core/computed/metrics/lantern-total-blocking-time.d.ts +13 -25
  116. package/core/computed/metrics/lantern-total-blocking-time.js +10 -94
  117. package/core/computed/metrics/metric.js +1 -3
  118. package/core/computed/module-duplication.d.ts +1 -1
  119. package/core/computed/navigation-insights.d.ts +36 -0
  120. package/core/computed/navigation-insights.js +35 -0
  121. package/core/computed/page-dependency-graph.js +3 -7
  122. package/core/computed/resource-summary.d.ts +10 -12
  123. package/core/computed/resource-summary.js +12 -19
  124. package/core/computed/trace-engine-result.d.ts +16 -3
  125. package/core/computed/trace-engine-result.js +19 -14
  126. package/core/computed/unused-css.d.ts +3 -1
  127. package/core/computed/unused-css.js +6 -5
  128. package/core/config/config-helpers.js +0 -4
  129. package/core/config/constants.js +0 -1
  130. package/core/config/default-config.js +63 -142
  131. package/core/config/experimental-config.js +11 -0
  132. package/core/config/filters.js +0 -1
  133. package/core/gather/driver/navigation.js +4 -1
  134. package/core/gather/driver/prepare.js +1 -1
  135. package/core/gather/driver/target-manager.js +4 -3
  136. package/core/gather/driver/wait-for-condition.js +2 -3
  137. package/core/gather/driver.d.ts +12 -0
  138. package/core/gather/driver.js +27 -0
  139. package/core/gather/gatherers/accessibility.js +4 -6
  140. package/core/gather/gatherers/css-usage.d.ts +0 -21
  141. package/core/gather/gatherers/css-usage.js +9 -119
  142. package/core/gather/gatherers/root-causes.d.ts +2 -2
  143. package/core/gather/gatherers/root-causes.js +6 -5
  144. package/core/gather/gatherers/stylesheets.d.ts +26 -0
  145. package/core/gather/gatherers/stylesheets.js +138 -0
  146. package/core/gather/gatherers/trace-elements.d.ts +4 -13
  147. package/core/gather/gatherers/trace-elements.js +42 -31
  148. package/core/gather/navigation-runner.js +3 -1
  149. package/core/gather/session.d.ts +8 -0
  150. package/core/gather/session.js +14 -1
  151. package/core/lib/emulation.js +2 -2
  152. package/core/lib/i18n/i18n.d.ts +0 -1
  153. package/core/lib/i18n/i18n.js +0 -2
  154. package/core/lib/lantern/cpu-node.d.ts +7 -1
  155. package/core/lib/lantern/cpu-node.js +12 -2
  156. package/core/lib/lantern/lantern-error.d.ts +8 -0
  157. package/core/lib/lantern/lantern-error.js +9 -0
  158. package/core/lib/lantern/metric.js +2 -6
  159. package/core/lib/lantern/metrics/first-contentful-paint.d.ts +79 -0
  160. package/core/lib/lantern/metrics/first-contentful-paint.js +200 -0
  161. package/core/lib/lantern/metrics/first-meaningful-paint.d.ts +6 -0
  162. package/core/lib/lantern/metrics/first-meaningful-paint.js +64 -0
  163. package/core/lib/lantern/metrics/interactive.d.ts +26 -0
  164. package/core/lib/lantern/metrics/interactive.js +112 -0
  165. package/core/lib/lantern/metrics/largest-contentful-paint.d.ts +19 -0
  166. package/core/lib/lantern/metrics/largest-contentful-paint.js +108 -0
  167. package/core/lib/lantern/metrics/max-potential-fid.d.ts +30 -0
  168. package/core/lib/lantern/metrics/max-potential-fid.js +92 -0
  169. package/core/lib/lantern/metrics/speed-index.d.ts +38 -0
  170. package/core/lib/lantern/metrics/speed-index.js +144 -0
  171. package/core/lib/lantern/metrics/total-blocking-time.d.ts +31 -0
  172. package/core/lib/lantern/metrics/total-blocking-time.js +128 -0
  173. package/core/lib/lantern/network-node.js +28 -4
  174. package/core/lib/lantern/page-dependency-graph.d.ts +4 -4
  175. package/core/lib/lantern/page-dependency-graph.js +19 -7
  176. package/core/lib/lantern/simulator/connection-pool.d.ts +2 -12
  177. package/core/lib/lantern/simulator/connection-pool.js +3 -22
  178. package/core/lib/lantern/simulator/network-analyzer.js +1 -12
  179. package/core/lib/lantern/simulator/simulator.d.ts +2 -4
  180. package/core/lib/lantern/simulator/simulator.js +7 -14
  181. package/core/lib/lantern/types/lantern.d.ts +5 -3
  182. package/core/lib/lantern-trace-saver.js +0 -1
  183. package/core/lib/lh-error.d.ts +9 -0
  184. package/core/lib/lh-error.js +13 -3
  185. package/core/lib/lighthouse-compatibility.js +53 -10
  186. package/core/lib/navigation-error.js +3 -0
  187. package/core/lib/network-request.d.ts +1 -0
  188. package/core/lib/network-request.js +29 -1
  189. package/core/lib/proto-preprocessor.js +24 -8
  190. package/core/lib/tracehouse/trace-processor.js +15 -2
  191. package/core/runner.js +18 -25
  192. package/dist/report/bundle.esm.js +11 -112
  193. package/dist/report/flow.js +16 -117
  194. package/dist/report/standalone.js +12 -113
  195. package/flow-report/src/help-dialog.tsx +0 -1
  196. package/flow-report/src/i18n/i18n.d.ts +0 -4
  197. package/flow-report/src/i18n/ui-strings.d.ts +0 -1
  198. package/flow-report/src/i18n/ui-strings.js +0 -2
  199. package/flow-report/src/summary/category.tsx +10 -12
  200. package/package.json +7 -7
  201. package/readme.md +4 -4
  202. package/report/assets/styles.css +1 -60
  203. package/report/assets/templates.html +0 -95
  204. package/report/renderer/category-renderer.js +1 -1
  205. package/report/renderer/components.d.ts +2 -2
  206. package/report/renderer/components.js +2 -103
  207. package/report/renderer/dom.d.ts +1 -1
  208. package/report/renderer/dom.js +1 -1
  209. package/report/renderer/performance-category-renderer.d.ts +0 -7
  210. package/report/renderer/performance-category-renderer.js +1 -32
  211. package/report/renderer/report-renderer.js +3 -13
  212. package/report/renderer/report-ui-features.js +1 -1
  213. package/report/renderer/report-utils.d.ts +0 -1
  214. package/report/renderer/report-utils.js +13 -13
  215. package/shared/localization/locales/ar-XB.json +62 -329
  216. package/shared/localization/locales/ar.json +62 -329
  217. package/shared/localization/locales/bg.json +62 -329
  218. package/shared/localization/locales/ca.json +62 -329
  219. package/shared/localization/locales/cs.json +62 -329
  220. package/shared/localization/locales/da.json +62 -329
  221. package/shared/localization/locales/de.json +62 -329
  222. package/shared/localization/locales/el.json +62 -329
  223. package/shared/localization/locales/en-GB.json +62 -329
  224. package/shared/localization/locales/en-US.json +101 -332
  225. package/shared/localization/locales/en-XA.json +62 -329
  226. package/shared/localization/locales/en-XL.json +101 -332
  227. package/shared/localization/locales/es-419.json +62 -329
  228. package/shared/localization/locales/es.json +62 -329
  229. package/shared/localization/locales/fi.json +62 -329
  230. package/shared/localization/locales/fil.json +61 -328
  231. package/shared/localization/locales/fr.json +62 -329
  232. package/shared/localization/locales/he.json +62 -329
  233. package/shared/localization/locales/hi.json +62 -329
  234. package/shared/localization/locales/hr.json +63 -330
  235. package/shared/localization/locales/hu.json +62 -329
  236. package/shared/localization/locales/id.json +62 -329
  237. package/shared/localization/locales/it.json +62 -329
  238. package/shared/localization/locales/ja.json +62 -329
  239. package/shared/localization/locales/ko.json +62 -329
  240. package/shared/localization/locales/lt.json +62 -329
  241. package/shared/localization/locales/lv.json +62 -329
  242. package/shared/localization/locales/nl.json +62 -329
  243. package/shared/localization/locales/no.json +62 -329
  244. package/shared/localization/locales/pl.json +61 -328
  245. package/shared/localization/locales/pt-PT.json +62 -329
  246. package/shared/localization/locales/pt.json +64 -331
  247. package/shared/localization/locales/ro.json +62 -329
  248. package/shared/localization/locales/ru.json +62 -329
  249. package/shared/localization/locales/sk.json +62 -329
  250. package/shared/localization/locales/sl.json +62 -329
  251. package/shared/localization/locales/sr-Latn.json +62 -329
  252. package/shared/localization/locales/sr.json +62 -329
  253. package/shared/localization/locales/sv.json +62 -329
  254. package/shared/localization/locales/ta.json +61 -328
  255. package/shared/localization/locales/te.json +62 -329
  256. package/shared/localization/locales/th.json +62 -329
  257. package/shared/localization/locales/tr.json +62 -329
  258. package/shared/localization/locales/uk.json +62 -329
  259. package/shared/localization/locales/vi.json +61 -328
  260. package/shared/localization/locales/zh-HK.json +62 -329
  261. package/shared/localization/locales/zh-TW.json +61 -328
  262. package/shared/localization/locales/zh.json +62 -329
  263. package/tsconfig.json +1 -3
  264. package/types/artifacts.d.ts +21 -110
  265. package/types/audit.d.ts +0 -10
  266. package/types/config.d.ts +0 -1
  267. package/types/externs.d.ts +0 -2
  268. package/types/gatherer.d.ts +3 -0
  269. package/types/internal/smokehouse.d.ts +1 -1
  270. package/types/lh.d.ts +0 -2
  271. package/types/lhr/audit-details.d.ts +9 -4
  272. package/types/lhr/lhr.d.ts +0 -4
  273. package/types/lhr/settings.d.ts +0 -4
  274. package/core/audits/accessibility/duplicate-id-active.js +0 -42
  275. package/core/audits/content-width.d.ts +0 -17
  276. package/core/audits/content-width.js +0 -76
  277. package/core/audits/installable-manifest.d.ts +0 -111
  278. package/core/audits/installable-manifest.js +0 -248
  279. package/core/audits/layout-shift-elements.d.ts +0 -16
  280. package/core/audits/layout-shift-elements.js +0 -101
  281. package/core/audits/manual/pwa-cross-browser.d.ts +0 -12
  282. package/core/audits/manual/pwa-cross-browser.js +0 -40
  283. package/core/audits/manual/pwa-each-page-has-url.d.ts +0 -12
  284. package/core/audits/manual/pwa-each-page-has-url.js +0 -38
  285. package/core/audits/manual/pwa-page-transitions.d.ts +0 -12
  286. package/core/audits/manual/pwa-page-transitions.js +0 -38
  287. package/core/audits/maskable-icon.d.ts +0 -25
  288. package/core/audits/maskable-icon.js +0 -70
  289. package/core/audits/multi-check-audit.d.ts +0 -28
  290. package/core/audits/multi-check-audit.js +0 -82
  291. package/core/audits/no-unload-listeners.d.ts +0 -16
  292. package/core/audits/no-unload-listeners.js +0 -86
  293. package/core/audits/performance-budget.d.ts +0 -39
  294. package/core/audits/performance-budget.js +0 -154
  295. package/core/audits/script-elements-test-audit.d.ts +0 -14
  296. package/core/audits/script-elements-test-audit.js +0 -29
  297. package/core/audits/seo/plugins.d.ts +0 -15
  298. package/core/audits/seo/plugins.js +0 -150
  299. package/core/audits/seo/tap-targets.d.ts +0 -50
  300. package/core/audits/seo/tap-targets.js +0 -352
  301. package/core/audits/splash-screen.d.ts +0 -37
  302. package/core/audits/splash-screen.js +0 -98
  303. package/core/audits/themed-omnibox.d.ts +0 -42
  304. package/core/audits/themed-omnibox.js +0 -102
  305. package/core/audits/timing-budget.d.ts +0 -43
  306. package/core/audits/timing-budget.js +0 -175
  307. package/core/computed/manifest-values.d.ts +0 -24
  308. package/core/computed/manifest-values.js +0 -136
  309. package/core/config/budget.d.ts +0 -74
  310. package/core/config/budget.js +0 -340
  311. package/core/config/metrics-to-audits.d.ts +0 -19
  312. package/core/config/metrics-to-audits.js +0 -62
  313. package/core/gather/driver/service-workers.d.ts +0 -16
  314. package/core/gather/driver/service-workers.js +0 -52
  315. package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.d.ts +0 -47
  316. package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.js +0 -233
  317. package/core/gather/gatherers/global-listeners.d.ts +0 -27
  318. package/core/gather/gatherers/global-listeners.js +0 -108
  319. package/core/gather/gatherers/installability-errors.d.ts +0 -17
  320. package/core/gather/gatherers/installability-errors.js +0 -56
  321. package/core/gather/gatherers/script-elements.d.ts +0 -21
  322. package/core/gather/gatherers/script-elements.js +0 -100
  323. package/core/gather/gatherers/seo/embedded-content.d.ts +0 -10
  324. package/core/gather/gatherers/seo/embedded-content.js +0 -63
  325. package/core/gather/gatherers/seo/tap-targets.d.ts +0 -21
  326. package/core/gather/gatherers/seo/tap-targets.js +0 -389
  327. package/core/gather/gatherers/service-worker.d.ts +0 -10
  328. package/core/gather/gatherers/service-worker.js +0 -32
  329. package/core/gather/gatherers/web-app-manifest.d.ts +0 -32
  330. package/core/gather/gatherers/web-app-manifest.js +0 -106
  331. package/report/renderer/pwa-category-renderer.d.ts +0 -55
  332. package/report/renderer/pwa-category-renderer.js +0 -184
  333. package/third-party/chromium-synchronization/installability-errors-test.js +0 -79
  334. package/types/lhr/budget.d.ts +0 -60
@@ -1,340 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2019 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- /**
8
- * @param {unknown} arr
9
- * @return {arr is Array<Record<string, unknown>>}
10
- */
11
- function isArrayOfUnknownObjects(arr) {
12
- return Array.isArray(arr) && arr.every(isObjectOfUnknownProperties);
13
- }
14
-
15
- /**
16
- * @param {unknown} val
17
- * @return {val is Record<string, unknown>}
18
- */
19
- function isObjectOfUnknownProperties(val) {
20
- return typeof val === 'object' && val !== null && !Array.isArray(val);
21
- }
22
-
23
- /**
24
- * Returns whether `val` is numeric. Will not coerce to a number. `NaN` will
25
- * return false, however ±Infinity will return true.
26
- * @param {unknown} val
27
- * @return {val is number}
28
- */
29
- function isNumber(val) {
30
- return typeof val === 'number' && !isNaN(val);
31
- }
32
-
33
- class Budget {
34
- /**
35
- * Asserts that obj has no own properties, throwing a nice error message if it does.
36
- * `objectName` is included for nicer logging.
37
- * @param {Record<string, unknown>} obj
38
- * @param {string} objectName
39
- */
40
- static assertNoExcessProperties(obj, objectName) {
41
- const invalidKeys = Object.keys(obj);
42
- if (invalidKeys.length > 0) {
43
- const keys = invalidKeys.join(', ');
44
- throw new Error(`${objectName} has unrecognized properties: [${keys}]`);
45
- }
46
- }
47
-
48
- /**
49
- * Asserts that `strings` has no duplicate strings in it, throwing an error if
50
- * it does. `arrayName` is included for nicer logging.
51
- * @param {Array<string>} strings
52
- * @param {string} arrayName
53
- */
54
- static assertNoDuplicateStrings(strings, arrayName) {
55
- const foundStrings = new Set();
56
- for (const string of strings) {
57
- if (foundStrings.has(string)) {
58
- throw new Error(`${arrayName} has duplicate entry of type '${string}'`);
59
- }
60
- foundStrings.add(string);
61
- }
62
- }
63
-
64
- /**
65
- * @param {Record<string, unknown>} resourceBudget
66
- * @return {LH.Budget.ResourceBudget}
67
- */
68
- static validateResourceBudget(resourceBudget) {
69
- const {resourceType, budget, ...invalidRest} = resourceBudget;
70
- Budget.assertNoExcessProperties(invalidRest, 'Resource Budget');
71
-
72
- /** @type {Array<LH.Budget.ResourceType>} */
73
- const validResourceTypes = [
74
- 'total',
75
- 'document',
76
- 'script',
77
- 'stylesheet',
78
- 'image',
79
- 'media',
80
- 'font',
81
- 'other',
82
- 'third-party',
83
- ];
84
- // Assume resourceType is an allowed string, throw if not.
85
- if (!validResourceTypes.includes(/** @type {LH.Budget.ResourceType} */ (resourceType))) {
86
- throw new Error(`Invalid resource type: ${resourceType}. \n` +
87
- `Valid resource types are: ${validResourceTypes.join(', ') }`);
88
- }
89
- if (!isNumber(budget)) {
90
- throw new Error(`Invalid budget: ${budget}`);
91
- }
92
- return {
93
- resourceType: /** @type {LH.Budget.ResourceType} */ (resourceType),
94
- budget,
95
- };
96
- }
97
-
98
- /**
99
- * @param {unknown} path
100
- * @param {string} error
101
- */
102
- static throwInvalidPathError(path, error) {
103
- throw new Error(`Invalid path ${path}. ${error}\n` +
104
- `'Path' should be specified using the 'robots.txt' format.\n` +
105
- `Learn more about the 'robots.txt' format here:\n` +
106
- `https://developers.google.com/search/reference/robots_txt#url-matching-based-on-path-values`);
107
- }
108
-
109
-
110
- /**
111
- * Validates that path is either: a) undefined or ) properly formed.
112
- * Verifies the quantity and location of the two robot.txt regex characters: $, *
113
- * @param {unknown} path
114
- * @return {undefined|string}
115
- */
116
- static validatePath(path) {
117
- if (path === undefined) {
118
- return undefined;
119
- } else if (typeof path !== 'string') {
120
- this.throwInvalidPathError(path, `Path should be a string.`);
121
- return;
122
- } else if (!path.startsWith('/')) {
123
- this.throwInvalidPathError(path, `Path should start with '/'.`);
124
- } else if ((path.match(/\*/g) || []).length > 1) {
125
- this.throwInvalidPathError(path, `Path should only contain one '*'.`);
126
- } else if ((path.match(/\$/g) || []).length > 1) {
127
- this.throwInvalidPathError(path, `Path should only contain one '$' character.`);
128
- } else if (path.includes('$') && !path.endsWith('$')) {
129
- this.throwInvalidPathError(path, `'$' character should only occur at end of path.`);
130
- }
131
- return path;
132
- }
133
-
134
- /**
135
- * Returns the budget that applies to a given URL.
136
- * If multiple budgets match based on thier 'path' property,
137
- * then the last-listed of those budgets is returned.
138
- * @param {LH.Util.Immutable<Array<LH.Budget>>|null} budgets
139
- * @param {string|undefined} url
140
- * @return {LH.Util.Immutable<LH.Budget> | undefined} budget
141
- */
142
- static getMatchingBudget(budgets, url) {
143
- if (budgets === null || url === undefined) return;
144
-
145
- // Applies the LAST matching budget.
146
- for (let i = budgets.length - 1; i >= 0; i--) {
147
- const budget = budgets[i];
148
- if (this.urlMatchesPattern(url, budget.path)) {
149
- return budget;
150
- }
151
- }
152
- }
153
-
154
- /**
155
- * Determines whether a URL matches against a robots.txt-style "path".
156
- * Pattern should use the robots.txt format. E.g. "/*-article.html" or "/". Reference:
157
- * https://developers.google.com/search/reference/robots_txt#url-matching-based-on-path-values
158
- * @param {string} url
159
- * @param {string=} pattern
160
- * @return {boolean}
161
- */
162
- static urlMatchesPattern(url, pattern = '/') {
163
- const urlObj = new URL(url);
164
- const urlPath = urlObj.pathname + urlObj.search;
165
-
166
- const hasWildcard = pattern.includes('*');
167
- const hasDollarSign = pattern.includes('$');
168
-
169
- /**
170
- * There are 4 different cases of path strings.
171
- * Paths should have already been validated with #validatePath.
172
- *
173
- * Case #1: No special characters
174
- * Example: "/cat"
175
- * Behavior: URL should start with given pattern.
176
- */
177
- if (!hasWildcard && !hasDollarSign) {
178
- return urlPath.startsWith(pattern);
179
- /**
180
- * Case #2: $ only
181
- * Example: "/js$"
182
- * Behavior: URL should be identical to pattern.
183
- */
184
- } else if (!hasWildcard && hasDollarSign) {
185
- return urlPath === pattern.slice(0, -1);
186
- /**
187
- * Case #3: * only
188
- * Example: "/vendor*chunk"
189
- * Behavior: URL should start with the string pattern that comes before the wildcard
190
- * & later in the string contain the string pattern that comes after the wildcard.
191
- */
192
- } else if (hasWildcard && !hasDollarSign) {
193
- const [beforeWildcard, afterWildcard] = pattern.split('*');
194
- const remainingUrl = urlPath.slice(beforeWildcard.length);
195
- return urlPath.startsWith(beforeWildcard) && remainingUrl.includes(afterWildcard);
196
- /**
197
- * Case #4: $ and *
198
- * Example: "/vendor*chunk.js$"
199
- * Behavior: URL should start with the string pattern that comes before the wildcard
200
- * & later in the string end with the string pattern that comes after the wildcard.
201
- */
202
- } else if (hasWildcard && hasDollarSign) {
203
- const [beforeWildcard, afterWildcard] = pattern.split('*');
204
- const urlEnd = urlPath.slice(beforeWildcard.length);
205
- return urlPath.startsWith(beforeWildcard) && urlEnd.endsWith(afterWildcard.slice(0, -1));
206
- }
207
- return false;
208
- }
209
-
210
- /**
211
- * @param {Record<string, unknown>} timingBudget
212
- * @return {LH.Budget.TimingBudget}
213
- */
214
- static validateTimingBudget(timingBudget) {
215
- const {metric, budget, ...invalidRest} = timingBudget;
216
- Budget.assertNoExcessProperties(invalidRest, 'Timing Budget');
217
-
218
- /** @type {Array<LH.Budget.TimingMetric>} */
219
- const validTimingMetrics = [
220
- 'first-contentful-paint',
221
- 'interactive',
222
- 'first-meaningful-paint',
223
- 'max-potential-fid',
224
- 'total-blocking-time',
225
- 'speed-index',
226
- 'largest-contentful-paint',
227
- 'cumulative-layout-shift',
228
- ];
229
- // Assume metric is an allowed string, throw if not.
230
- if (!validTimingMetrics.includes(/** @type {LH.Budget.TimingMetric} */ (metric))) {
231
- throw new Error(`Invalid timing metric: ${metric}. \n` +
232
- `Valid timing metrics are: ${validTimingMetrics.join(', ')}`);
233
- }
234
- if (!isNumber(budget)) {
235
- throw new Error(`Invalid budget: ${budget}`);
236
- }
237
- return {
238
- metric: /** @type {LH.Budget.TimingMetric} */ (metric),
239
- budget,
240
- };
241
- }
242
-
243
- /**
244
- * @param {string} hostname
245
- * @return {string}
246
- */
247
- static validateHostname(hostname) {
248
- const errMsg = `${hostname} is not a valid hostname.`;
249
- if (hostname.length === 0) {
250
- throw new Error(errMsg);
251
- }
252
- if (hostname.includes('/')) {
253
- throw new Error(errMsg);
254
- }
255
- if (hostname.includes(':')) {
256
- throw new Error(errMsg);
257
- }
258
- if (hostname.includes('*')) {
259
- if (!hostname.startsWith('*.') || hostname.lastIndexOf('*') > 0) {
260
- throw new Error(errMsg);
261
- }
262
- }
263
- return hostname;
264
- }
265
-
266
- /**
267
- * @param {unknown} hostnames
268
- * @return {undefined|Array<string>}
269
- */
270
- static validateHostnames(hostnames) {
271
- if (Array.isArray(hostnames) && hostnames.every(host => typeof host === 'string')) {
272
- return hostnames.map(Budget.validateHostname);
273
- } else if (hostnames !== undefined) {
274
- throw new Error(`firstPartyHostnames should be defined as an array of strings.`);
275
- }
276
- }
277
-
278
- /**
279
- * More info on the Budget format:
280
- * https://github.com/GoogleChrome/lighthouse/issues/6053#issuecomment-428385930
281
- * @param {unknown} budgetJson
282
- * @return {Array<LH.Budget>}
283
- */
284
- static initializeBudget(budgetJson) {
285
- // Clone to prevent modifications of original and to deactivate any live properties.
286
- budgetJson = JSON.parse(JSON.stringify(budgetJson));
287
- if (!isArrayOfUnknownObjects(budgetJson)) {
288
- throw new Error('Budget file is not defined as an array of budgets.');
289
- }
290
-
291
- const budgets = budgetJson.map((b, index) => {
292
- /** @type {LH.Budget} */
293
- const budget = {};
294
-
295
- const {path, options, resourceSizes, resourceCounts, timings, ...invalidRest} = b;
296
- Budget.assertNoExcessProperties(invalidRest, 'Budget');
297
-
298
- budget.path = Budget.validatePath(path);
299
-
300
- if (isObjectOfUnknownProperties(options)) {
301
- const {firstPartyHostnames, ...invalidRest} = options;
302
- Budget.assertNoExcessProperties(invalidRest, 'Options property');
303
- budget.options = {};
304
- budget.options.firstPartyHostnames = Budget.validateHostnames(firstPartyHostnames);
305
- } else if (options !== undefined) {
306
- throw new Error(`Invalid options property in budget at index ${index}`);
307
- }
308
-
309
- if (isArrayOfUnknownObjects(resourceSizes)) {
310
- budget.resourceSizes = resourceSizes.map(Budget.validateResourceBudget);
311
- Budget.assertNoDuplicateStrings(budget.resourceSizes.map(r => r.resourceType),
312
- `budgets[${index}].resourceSizes`);
313
- } else if (resourceSizes !== undefined) {
314
- throw new Error(`Invalid resourceSizes entry in budget at index ${index}`);
315
- }
316
-
317
- if (isArrayOfUnknownObjects(resourceCounts)) {
318
- budget.resourceCounts = resourceCounts.map(Budget.validateResourceBudget);
319
- Budget.assertNoDuplicateStrings(budget.resourceCounts.map(r => r.resourceType),
320
- `budgets[${index}].resourceCounts`);
321
- } else if (resourceCounts !== undefined) {
322
- throw new Error(`Invalid resourceCounts entry in budget at index ${index}`);
323
- }
324
-
325
- if (isArrayOfUnknownObjects(timings)) {
326
- budget.timings = timings.map(Budget.validateTimingBudget);
327
- Budget.assertNoDuplicateStrings(budget.timings.map(r => r.metric),
328
- `budgets[${index}].timings`);
329
- } else if (timings !== undefined) {
330
- throw new Error(`Invalid timings entry in budget at index ${index}`);
331
- }
332
-
333
- return budget;
334
- });
335
-
336
- return budgets;
337
- }
338
- }
339
-
340
- export {Budget};
@@ -1,19 +0,0 @@
1
- export namespace metricsToAudits {
2
- export { fcpRelevantAudits };
3
- export { lcpRelevantAudits };
4
- export { tbtRelevantAudits };
5
- export { clsRelevantAudits };
6
- export { inpRelevantAudits };
7
- }
8
- /**
9
- * @license
10
- * Copyright 2021 Google LLC
11
- * SPDX-License-Identifier: Apache-2.0
12
- */
13
- declare const fcpRelevantAudits: string[];
14
- declare const lcpRelevantAudits: string[];
15
- declare const tbtRelevantAudits: string[];
16
- declare const clsRelevantAudits: string[];
17
- declare const inpRelevantAudits: string[];
18
- export {};
19
- //# sourceMappingURL=metrics-to-audits.d.ts.map
@@ -1,62 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2021 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- // go/lh-audit-metric-mapping
8
- const fcpRelevantAudits = [
9
- 'server-response-time',
10
- 'render-blocking-resources',
11
- 'redirects',
12
- 'critical-request-chains',
13
- 'uses-text-compression',
14
- 'uses-rel-preconnect',
15
- 'uses-rel-preload',
16
- 'font-display',
17
- 'unminified-javascript',
18
- 'unminified-css',
19
- 'unused-css-rules',
20
- ];
21
-
22
- const lcpRelevantAudits = [
23
- ...fcpRelevantAudits,
24
- 'largest-contentful-paint-element',
25
- 'prioritize-lcp-image',
26
- 'unused-javascript',
27
- 'efficient-animated-content',
28
- 'total-byte-weight',
29
- 'lcp-lazy-loaded',
30
- ];
31
-
32
- const tbtRelevantAudits = [
33
- 'long-tasks',
34
- 'third-party-summary',
35
- 'third-party-facades',
36
- 'bootup-time',
37
- 'mainthread-work-breakdown',
38
- 'dom-size',
39
- 'duplicated-javascript',
40
- 'legacy-javascript',
41
- 'viewport',
42
- ];
43
-
44
- const clsRelevantAudits = [
45
- 'layout-shift-elements',
46
- 'layout-shifts',
47
- 'non-composited-animations',
48
- 'unsized-images',
49
- // 'preload-fonts', // actually in BP, rather than perf
50
- ];
51
-
52
- const inpRelevantAudits = [
53
- 'work-during-interaction',
54
- ];
55
-
56
- export const metricsToAudits = {
57
- fcpRelevantAudits,
58
- lcpRelevantAudits,
59
- tbtRelevantAudits,
60
- clsRelevantAudits,
61
- inpRelevantAudits,
62
- };
@@ -1,16 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2021 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- /**
7
- * @param {LH.Gatherer.ProtocolSession} session
8
- * @return {Promise<LH.Crdp.ServiceWorker.WorkerVersionUpdatedEvent>}
9
- */
10
- export function getServiceWorkerVersions(session: LH.Gatherer.ProtocolSession): Promise<LH.Crdp.ServiceWorker.WorkerVersionUpdatedEvent>;
11
- /**
12
- * @param {LH.Gatherer.ProtocolSession} session
13
- * @return {Promise<LH.Crdp.ServiceWorker.WorkerRegistrationUpdatedEvent>}
14
- */
15
- export function getServiceWorkerRegistrations(session: LH.Gatherer.ProtocolSession): Promise<LH.Crdp.ServiceWorker.WorkerRegistrationUpdatedEvent>;
16
- //# sourceMappingURL=service-workers.d.ts.map
@@ -1,52 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2021 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- /**
8
- * @param {LH.Gatherer.ProtocolSession} session
9
- * @return {Promise<LH.Crdp.ServiceWorker.WorkerVersionUpdatedEvent>}
10
- */
11
- function getServiceWorkerVersions(session) {
12
- return new Promise((resolve, reject) => {
13
- /**
14
- * @param {LH.Crdp.ServiceWorker.WorkerVersionUpdatedEvent} data
15
- */
16
- const versionUpdatedListener = data => {
17
- // find a service worker with runningStatus that looks like active
18
- // on slow connections the serviceworker might still be installing
19
- const activateCandidates = data.versions.filter(sw => {
20
- return sw.status !== 'redundant';
21
- });
22
-
23
- const hasActiveServiceWorker = activateCandidates.find(sw => {
24
- return sw.status === 'activated';
25
- });
26
-
27
- if (!activateCandidates.length || hasActiveServiceWorker) {
28
- session.off('ServiceWorker.workerVersionUpdated', versionUpdatedListener);
29
- session.sendCommand('ServiceWorker.disable').then(_ => resolve(data), reject);
30
- }
31
- };
32
-
33
- session.on('ServiceWorker.workerVersionUpdated', versionUpdatedListener);
34
-
35
- session.sendCommand('ServiceWorker.enable').catch(reject);
36
- });
37
- }
38
-
39
- /**
40
- * @param {LH.Gatherer.ProtocolSession} session
41
- * @return {Promise<LH.Crdp.ServiceWorker.WorkerRegistrationUpdatedEvent>}
42
- */
43
- function getServiceWorkerRegistrations(session) {
44
- return new Promise((resolve, reject) => {
45
- session.once('ServiceWorker.workerRegistrationUpdated', data => {
46
- session.sendCommand('ServiceWorker.disable').then(_ => resolve(data), reject);
47
- });
48
- session.sendCommand('ServiceWorker.enable').catch(reject);
49
- });
50
- }
51
-
52
- export {getServiceWorkerVersions, getServiceWorkerRegistrations};
@@ -1,47 +0,0 @@
1
- export default TagsBlockingFirstPaint;
2
- export type MediaChange = {
3
- href: string;
4
- media: string;
5
- msSinceHTMLEnd: number;
6
- matches: boolean;
7
- };
8
- export type LinkTag = {
9
- tagName: 'LINK';
10
- url: string;
11
- href: string;
12
- rel: string;
13
- media: string;
14
- disabled: boolean;
15
- mediaChanges: Array<MediaChange>;
16
- };
17
- export type ScriptTag = {
18
- tagName: 'SCRIPT';
19
- url: string;
20
- src: string;
21
- };
22
- declare class TagsBlockingFirstPaint extends BaseGatherer {
23
- /**
24
- * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
25
- * @return {Map<string, LH.Artifacts.NetworkRequest>}
26
- */
27
- static _filteredAndIndexedByUrl(networkRecords: Array<LH.Artifacts.NetworkRequest>): Map<string, LH.Artifacts.NetworkRequest>;
28
- /**
29
- * @param {LH.Gatherer.Driver} driver
30
- * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
31
- * @return {Promise<Array<LH.Artifacts.TagBlockingFirstPaint>>}
32
- */
33
- static findBlockingTags(driver: LH.Gatherer.Driver, networkRecords: Array<LH.Artifacts.NetworkRequest>): Promise<Array<LH.Artifacts.TagBlockingFirstPaint>>;
34
- /** @type {LH.Gatherer.GathererMeta<'DevtoolsLog'>} */
35
- meta: LH.Gatherer.GathererMeta<'DevtoolsLog'>;
36
- /**
37
- * @param {LH.Gatherer.Context} context
38
- */
39
- startSensitiveInstrumentation(context: LH.Gatherer.Context): Promise<void>;
40
- /**
41
- * @param {LH.Gatherer.Context<'DevtoolsLog'>} context
42
- * @return {Promise<LH.Artifacts['TagsBlockingFirstPaint']>}
43
- */
44
- getArtifact(context: LH.Gatherer.Context<'DevtoolsLog'>): Promise<LH.Artifacts['TagsBlockingFirstPaint']>;
45
- }
46
- import BaseGatherer from '../../base-gatherer.js';
47
- //# sourceMappingURL=tags-blocking-first-paint.d.ts.map