lighthouse 13.5.0-dev.20261023 → 13.6.0-dev.20261027

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 (99) hide show
  1. package/.agents/skills/update-ard-port/SKILL.md +4 -3
  2. package/cli/printer.js +5 -8
  3. package/core/audits/accessibility/accesskeys.js +1 -1
  4. package/core/audits/accessibility/aria-allowed-attr.js +1 -1
  5. package/core/audits/accessibility/aria-allowed-role.js +1 -1
  6. package/core/audits/accessibility/aria-command-name.js +1 -1
  7. package/core/audits/accessibility/aria-conditional-attr.js +1 -1
  8. package/core/audits/accessibility/aria-deprecated-role.js +1 -1
  9. package/core/audits/accessibility/aria-dialog-name.js +1 -1
  10. package/core/audits/accessibility/aria-hidden-body.js +1 -1
  11. package/core/audits/accessibility/aria-hidden-focus.js +1 -1
  12. package/core/audits/accessibility/aria-input-field-name.js +1 -1
  13. package/core/audits/accessibility/aria-meter-name.js +1 -1
  14. package/core/audits/accessibility/aria-progressbar-name.js +1 -1
  15. package/core/audits/accessibility/aria-prohibited-attr.js +1 -1
  16. package/core/audits/accessibility/aria-required-attr.js +1 -1
  17. package/core/audits/accessibility/aria-required-children.js +1 -1
  18. package/core/audits/accessibility/aria-required-parent.js +1 -1
  19. package/core/audits/accessibility/aria-roles.js +1 -1
  20. package/core/audits/accessibility/aria-text.js +1 -1
  21. package/core/audits/accessibility/aria-toggle-field-name.js +1 -1
  22. package/core/audits/accessibility/aria-tooltip-name.js +1 -1
  23. package/core/audits/accessibility/aria-treeitem-name.js +1 -1
  24. package/core/audits/accessibility/aria-valid-attr-value.js +1 -1
  25. package/core/audits/accessibility/aria-valid-attr.js +1 -1
  26. package/core/audits/accessibility/autocomplete-valid.js +1 -1
  27. package/core/audits/accessibility/button-name.js +1 -1
  28. package/core/audits/accessibility/bypass.js +1 -1
  29. package/core/audits/accessibility/color-contrast.js +1 -1
  30. package/core/audits/accessibility/definition-list.js +1 -1
  31. package/core/audits/accessibility/dlitem.js +1 -1
  32. package/core/audits/accessibility/document-title.js +1 -1
  33. package/core/audits/accessibility/duplicate-id-aria.js +1 -1
  34. package/core/audits/accessibility/empty-heading.js +1 -1
  35. package/core/audits/accessibility/form-field-multiple-labels.js +1 -1
  36. package/core/audits/accessibility/frame-title.js +1 -1
  37. package/core/audits/accessibility/heading-order.js +1 -1
  38. package/core/audits/accessibility/html-has-lang.js +1 -1
  39. package/core/audits/accessibility/html-lang-valid.js +1 -1
  40. package/core/audits/accessibility/html-xml-lang-mismatch.js +1 -1
  41. package/core/audits/accessibility/identical-links-same-purpose.js +1 -1
  42. package/core/audits/accessibility/image-alt.js +1 -1
  43. package/core/audits/accessibility/image-redundant-alt.js +1 -1
  44. package/core/audits/accessibility/input-button-name.js +1 -1
  45. package/core/audits/accessibility/input-image-alt.js +1 -1
  46. package/core/audits/accessibility/label-content-name-mismatch.js +1 -1
  47. package/core/audits/accessibility/label.js +1 -1
  48. package/core/audits/accessibility/landmark-one-main.js +1 -1
  49. package/core/audits/accessibility/link-in-text-block.js +1 -1
  50. package/core/audits/accessibility/link-name.js +1 -1
  51. package/core/audits/accessibility/list.js +1 -1
  52. package/core/audits/accessibility/listitem.js +1 -1
  53. package/core/audits/accessibility/meta-refresh.js +1 -1
  54. package/core/audits/accessibility/meta-viewport.js +1 -1
  55. package/core/audits/accessibility/object-alt.js +1 -1
  56. package/core/audits/accessibility/presentation-role-conflict.js +1 -1
  57. package/core/audits/accessibility/select-name.js +1 -1
  58. package/core/audits/accessibility/skip-link.js +1 -1
  59. package/core/audits/accessibility/svg-img-alt.js +1 -1
  60. package/core/audits/accessibility/tabindex.js +1 -1
  61. package/core/audits/accessibility/table-duplicate-name.js +1 -1
  62. package/core/audits/accessibility/table-fake-caption.js +1 -1
  63. package/core/audits/accessibility/target-size.js +1 -1
  64. package/core/audits/accessibility/td-has-header.js +1 -1
  65. package/core/audits/accessibility/td-headers-attr.js +1 -1
  66. package/core/audits/accessibility/th-has-data-cells.js +1 -1
  67. package/core/audits/accessibility/valid-lang.js +1 -1
  68. package/core/audits/accessibility/video-caption.js +1 -1
  69. package/core/audits/baseline.d.ts +5 -4
  70. package/core/lib/baseline/web-features-data.json +6 -4
  71. package/core/lib/baseline/web-features-metadata.json +1 -1
  72. package/core/lib/bf-cache-strings.js +188 -204
  73. package/core/lib/deprecations-strings.d.ts +43 -46
  74. package/core/lib/deprecations-strings.js +12 -14
  75. package/core/runner.js +6 -0
  76. package/dist/report/bundle.esm.js +10 -10
  77. package/dist/report/flow.js +4 -4
  78. package/dist/report/standalone.js +5 -5
  79. package/flow-report/src/common.tsx +5 -2
  80. package/flow-report/src/i18n/i18n.d.ts +2 -0
  81. package/flow-report/src/summary/summary.tsx +9 -1
  82. package/package.json +9 -9
  83. package/report/renderer/category-renderer.js +2 -2
  84. package/report/renderer/details-renderer.js +3 -2
  85. package/report/renderer/dom.d.ts +8 -2
  86. package/report/renderer/dom.js +29 -1
  87. package/report/renderer/element-screenshot-renderer.js +3 -0
  88. package/report/renderer/performance-category-renderer.js +1 -0
  89. package/report/renderer/report-renderer.js +4 -0
  90. package/report/renderer/report-utils.d.ts +1 -0
  91. package/report/renderer/report-utils.js +2 -0
  92. package/shared/localization/locales/en-US.json +69 -66
  93. package/shared/localization/locales/en-XL.json +69 -66
  94. package/third-party/ard/README.md +3 -3
  95. package/third-party/ard/ard-test.js +8 -2
  96. package/third-party/ard/ard.d.ts +1 -0
  97. package/third-party/ard/ard.js +8 -2
  98. package/third-party/ard/schema-validator.js +1 -1
  99. package/third-party/ard/spec/schemas/ard-entry.schema.json +1 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "13.5.0-dev.20261023",
4
+ "version": "13.6.0-dev.20261027",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {
@@ -119,7 +119,7 @@
119
119
  "acorn": "^8.19.0",
120
120
  "ajv": "^8.20.0",
121
121
  "archiver": "^8.0.0",
122
- "chrome-devtools-frontend": "1.0.1705227",
122
+ "chrome-devtools-frontend": "1.0.1726686",
123
123
  "concurrently": "^10.0.6",
124
124
  "conventional-changelog": "^8.1.3",
125
125
  "core-js-compat": "^3.51.0",
@@ -141,7 +141,7 @@
141
141
  "pako": "^3.0.2",
142
142
  "preact": "^10.29.8",
143
143
  "pretty-json-stringify": "^0.0.2",
144
- "puppeteer": "^25.15.0",
144
+ "puppeteer": "^25.16.0",
145
145
  "terser": "^5.51.2",
146
146
  "testdouble": "^4.0.0",
147
147
  "tsx": "^4.23.15",
@@ -149,18 +149,18 @@
149
149
  "typescript": "6.0.3",
150
150
  "typescript-eslint": "^8.60.1",
151
151
  "wait-for-expect": "^4.0.0",
152
- "web-features": "^3.43.0",
152
+ "web-features": "^3.44.0",
153
153
  "webtreemap-cdt": "^3.2.1"
154
154
  },
155
155
  "dependencies": {
156
156
  "@paulirish/trace_engine": "0.0.67",
157
157
  "@sentry/node": "^11.8.0",
158
158
  "ajv-formats": "^3.0.1",
159
- "axe-core": "4.13.0",
159
+ "axe-core": "4.14.0",
160
160
  "chrome-launcher": "^1.2.2",
161
161
  "configstore": "^8.0.0",
162
162
  "csp_evaluator": "1.1.8",
163
- "devtools-protocol": "0.0.1721602",
163
+ "devtools-protocol": "0.0.1727723",
164
164
  "enquirer": "^2.3.6",
165
165
  "http-link-header": "^1.1.1",
166
166
  "intl-messageformat": "^10.5.3",
@@ -168,7 +168,7 @@
168
168
  "lighthouse-logger": "^2.0.2",
169
169
  "lighthouse-stack-packs": "1.12.3",
170
170
  "open": "^11.0.4",
171
- "puppeteer-core": "^25.15.0",
171
+ "puppeteer-core": "^25.16.0",
172
172
  "robots-parser": "^3.0.1",
173
173
  "speedline-core": "^1.4.3",
174
174
  "third-party-web": "^0.30.0",
@@ -177,8 +177,8 @@
177
177
  "yargs-parser": "^22.0.0"
178
178
  },
179
179
  "resolutions": {
180
- "puppeteer/**/devtools-protocol": "0.0.1721602",
181
- "puppeteer-core/**/devtools-protocol": "0.0.1721602"
180
+ "puppeteer/**/devtools-protocol": "0.0.1727723",
181
+ "puppeteer-core/**/devtools-protocol": "0.0.1727723"
182
182
  },
183
183
  "repository": {
184
184
  "type": "git",
@@ -71,7 +71,7 @@ export class CategoryRenderer {
71
71
  if (audit.stackPacks) {
72
72
  audit.stackPacks.forEach(pack => {
73
73
  const packElmImg = this.dom.createElement('img', 'lh-audit__stackpack__img');
74
- packElmImg.src = pack.iconDataURL;
74
+ this.dom.safelySetImageSrc(packElmImg, pack.iconDataURL);
75
75
  packElmImg.alt = pack.title;
76
76
 
77
77
  const snippets = this.dom.convertMarkdownLinkSnippets(pack.description, {
@@ -141,7 +141,7 @@ export class CategoryRenderer {
141
141
 
142
142
  const imgEl = this.dom.createElement('img', 'lh-final-ss-image');
143
143
  const finalScreenshotDataUri = audit.details.data;
144
- imgEl.src = finalScreenshotDataUri;
144
+ this.dom.safelySetImageSrc(imgEl, finalScreenshotDataUri);
145
145
  imgEl.alt = audit.title;
146
146
 
147
147
  const firstCatHeaderEl = this.dom.find('.lh-category .lh-category-header', categoriesEl);
@@ -202,7 +202,7 @@ export class DetailsRenderer {
202
202
  _renderThumbnail(details) {
203
203
  const element = this._dom.createElement('img', 'lh-thumbnail');
204
204
  const strValue = details;
205
- element.src = strValue;
205
+ this._dom.safelySetImageSrc(element, strValue);
206
206
  element.title = strValue;
207
207
  element.alt = '';
208
208
  return element;
@@ -429,6 +429,7 @@ export class DetailsRenderer {
429
429
  this._dom.safelySetHref(entityLinkEl, matchedEntity.homepage);
430
430
  if (entityLinkEl.href) {
431
431
  entityLinkEl.target = '_blank';
432
+ entityLinkEl.rel = 'noopener';
432
433
  entityLinkEl.title = Globals.strings.openInANewTabTooltip;
433
434
  entityLinkEl.classList.add('lh-report-icon--external');
434
435
  firstTdEl.append(' ', entityLinkEl);
@@ -735,7 +736,7 @@ export class DetailsRenderer {
735
736
  for (const thumbnail of details.items) {
736
737
  const frameEl = this._dom.createChildOf(filmstripEl, 'div', 'lh-filmstrip__frame');
737
738
  const imgEl = this._dom.createChildOf(frameEl, 'img', 'lh-filmstrip__thumbnail');
738
- imgEl.src = thumbnail.data;
739
+ this._dom.safelySetImageSrc(imgEl, thumbnail.data);
739
740
  imgEl.alt = `Screenshot`;
740
741
  }
741
742
  return filmstripEl;
@@ -68,15 +68,21 @@ export class DOM {
68
68
  * Set link href, but safely, preventing `javascript:` protocol, etc.
69
69
  * @see https://github.com/google/safevalues/
70
70
  * @param {HTMLAnchorElement} elem
71
- * @param {string} url
71
+ * @param {string|undefined} url
72
72
  */
73
- safelySetHref(elem: HTMLAnchorElement, url: string): void;
73
+ safelySetHref(elem: HTMLAnchorElement, url: string | undefined): void;
74
74
  /**
75
75
  * Only create blob URLs for JSON & HTML
76
76
  * @param {HTMLAnchorElement} elem
77
77
  * @param {Blob} blob
78
78
  */
79
79
  safelySetBlobHref(elem: HTMLAnchorElement, blob: Blob): void;
80
+ /**
81
+ * Set img src, but safely, only allowing `https:`, `http:`, and `data:image/`.
82
+ * @param {HTMLImageElement} elem
83
+ * @param {string} url
84
+ */
85
+ safelySetImageSrc(elem: HTMLImageElement, url: string): void;
80
86
  /**
81
87
  * @param {string} markdownText
82
88
  * @return {Element}
@@ -169,7 +169,7 @@ export class DOM {
169
169
  * Set link href, but safely, preventing `javascript:` protocol, etc.
170
170
  * @see https://github.com/google/safevalues/
171
171
  * @param {HTMLAnchorElement} elem
172
- * @param {string} url
172
+ * @param {string|undefined} url
173
173
  */
174
174
  safelySetHref(elem, url) {
175
175
  // Defaults to '' to fix proto roundtrip issue. See https://github.com/GoogleChrome/lighthouse/issues/12868
@@ -189,6 +189,8 @@ export class DOM {
189
189
 
190
190
  if (parsed && allowedProtocols.includes(parsed.protocol)) {
191
191
  elem.href = parsed.href;
192
+ } else {
193
+ elem.removeAttribute('href');
192
194
  }
193
195
  }
194
196
 
@@ -205,6 +207,32 @@ export class DOM {
205
207
  elem.href = href;
206
208
  }
207
209
 
210
+ /**
211
+ * Set img src, but safely, only allowing `https:`, `http:`, and `data:image/`.
212
+ * @param {HTMLImageElement} elem
213
+ * @param {string} url
214
+ */
215
+ safelySetImageSrc(elem, url) {
216
+ url = url || '';
217
+
218
+ if (url.startsWith('data:image/')) {
219
+ elem.src = url;
220
+ return;
221
+ }
222
+
223
+ const allowedProtocols = ['https:', 'http:'];
224
+ let parsed;
225
+ try {
226
+ parsed = new URL(url);
227
+ } catch (_) {}
228
+
229
+ if (parsed && allowedProtocols.includes(parsed.protocol)) {
230
+ elem.src = parsed.href;
231
+ } else {
232
+ elem.removeAttribute('src');
233
+ }
234
+ }
235
+
208
236
  /**
209
237
  * @param {string} markdownText
210
238
  * @return {Element}
@@ -134,6 +134,9 @@ export class ElementScreenshotRenderer {
134
134
  * @param {LH.Result.FullPageScreenshot['screenshot']} screenshot
135
135
  */
136
136
  static installFullPageScreenshot(el, screenshot) {
137
+ if (!screenshot.data.startsWith('data:image/') || /['"()\\\r\n]/.test(screenshot.data)) {
138
+ return;
139
+ }
137
140
  el.style.setProperty('--element-screenshot-url', `url('${screenshot.data}')`);
138
141
  }
139
142
 
@@ -183,6 +183,7 @@ export class PerformanceCategoryRenderer extends CategoryRenderer {
183
183
  // Add link to score calculator.
184
184
  const calculatorLink = this.dom.createChildOf(estValuesEl, 'a', 'lh-calclink');
185
185
  calculatorLink.target = '_blank';
186
+ calculatorLink.rel = 'noopener';
186
187
  calculatorLink.textContent = strings.calculatorLink;
187
188
  this.dom.safelySetHref(calculatorLink, this._getScoringCalculatorHref(category.auditRefs));
188
189
  }
@@ -119,6 +119,7 @@ export class ReportRenderer {
119
119
  const channel = report.configSettings.channel;
120
120
  const benchmarkIndex = report.environment.benchmarkIndex.toFixed(0);
121
121
  const axeVersion = report.environment.credits?.['axe-core'];
122
+ const ardVersion = report.environment.credits?.['ard'];
122
123
 
123
124
  const devicesTooltipTextLines = [
124
125
  `${Globals.strings.runtimeSettingsBenchmark}: ${benchmarkIndex}`,
@@ -131,6 +132,9 @@ export class ReportRenderer {
131
132
  if (axeVersion) {
132
133
  devicesTooltipTextLines.push(`${Globals.strings.runtimeSettingsAxeVersion}: ${axeVersion}`);
133
134
  }
135
+ if (ardVersion) {
136
+ devicesTooltipTextLines.push(`${Globals.strings.runtimeSettingsArdVersion}: ${ardVersion}`);
137
+ }
134
138
 
135
139
  let stopwatchLabel = Globals.strings.runtimeAnalysisWindow;
136
140
  if (report.gatherMode === 'timespan') {
@@ -116,6 +116,7 @@ export namespace UIStrings {
116
116
  let runtimeSettingsUANetwork: string;
117
117
  let runtimeSettingsBenchmark: string;
118
118
  let runtimeSettingsAxeVersion: string;
119
+ let runtimeSettingsArdVersion: string;
119
120
  let runtimeSettingsScreenEmulation: string;
120
121
  let footerIssue: string;
121
122
  let runtimeNoEmulation: string;
@@ -441,6 +441,8 @@ const UIStrings = {
441
441
  runtimeSettingsBenchmark: 'Unthrottled CPU/Memory Power',
442
442
  /** Label for a row in a table that shows the version of the Axe library used. Example row values: 2.1.0, 3.2.3 */
443
443
  runtimeSettingsAxeVersion: 'Axe version',
444
+ /** Label for a row in a table that shows the version of the Agentic Resource Discovery (ARD) specification used. "ARD" should not be translated. Example row values: 0.91 (f073b1e), 1.0 (a1b2c3d) */
445
+ runtimeSettingsArdVersion: 'ARD version',
444
446
  /** Label for a row in a table that shows the screen resolution and DPR that was emulated for the Lighthouse run. Example values: '800x600, DPR: 3' */
445
447
  runtimeSettingsScreenEmulation: 'Screen emulation',
446
448