lighthouse 12.6.1-dev.20250611 → 12.6.1-dev.20250613

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 (55) hide show
  1. package/cli/test/smokehouse/frontends/lib.js +0 -2
  2. package/cli/test/smokehouse/frontends/smokehouse-bin.js +1 -3
  3. package/cli/test/smokehouse/lighthouse-runners/cli.js +1 -1
  4. package/cli/test/smokehouse/smokehouse.js +0 -2
  5. package/core/audits/byte-efficiency/legacy-javascript.js +0 -1
  6. package/core/audits/deprecations.js +0 -2
  7. package/core/audits/insights/cls-culprits-insight.js +0 -2
  8. package/core/audits/insights/modern-http-insight.js +0 -2
  9. package/core/audits/third-party-cookies.js +0 -2
  10. package/core/audits/valid-source-maps.js +0 -2
  11. package/core/computed/js-bundles.js +0 -1
  12. package/core/computed/metrics/cumulative-layout-shift.js +1 -1
  13. package/core/computed/trace-engine-result.js +0 -1
  14. package/core/config/config.js +1 -1
  15. package/core/gather/driver/navigation.js +1 -3
  16. package/core/gather/driver/wait-for-condition.js +0 -1
  17. package/core/gather/fetcher.js +0 -2
  18. package/core/gather/gatherers/accessibility.js +1 -1
  19. package/core/gather/gatherers/anchor-elements.js +0 -2
  20. package/core/gather/gatherers/cache-contents.js +0 -2
  21. package/core/gather/gatherers/css-usage.js +0 -1
  22. package/core/gather/gatherers/dobetterweb/doctype.js +0 -2
  23. package/core/gather/gatherers/dobetterweb/domstats.js +1 -1
  24. package/core/gather/gatherers/full-page-screenshot.js +1 -1
  25. package/core/gather/gatherers/image-elements.js +1 -1
  26. package/core/gather/gatherers/link-elements.js +1 -1
  27. package/core/gather/gatherers/stacks.js +0 -1
  28. package/core/gather/gatherers/stylesheets.js +0 -1
  29. package/core/gather/gatherers/trace-elements.js +1 -1
  30. package/core/gather/gatherers/viewport-dimensions.js +0 -2
  31. package/core/index.cjs +0 -1
  32. package/core/index.d.cts +5 -0
  33. package/core/lib/i18n/i18n.js +0 -2
  34. package/core/lib/lantern-trace-saver.js +1 -1
  35. package/core/lib/lh-error.js +0 -1
  36. package/core/lib/manifest-parser.js +0 -2
  37. package/core/lib/minify-devtoolslog.js +0 -2
  38. package/core/lib/sentry.d.ts +1 -1
  39. package/core/lib/sentry.js +2 -2
  40. package/core/runner.js +0 -1
  41. package/core/scripts/manual-chrome-launcher.js +0 -1
  42. package/eslint.config.mjs +242 -0
  43. package/flow-report/src/common.tsx +1 -0
  44. package/flow-report/src/i18n/i18n.tsx +1 -0
  45. package/flow-report/src/util.ts +2 -0
  46. package/package.json +10 -6
  47. package/report/generator/file-namer.d.ts +5 -0
  48. package/report/generator/file-namer.js +1 -1
  49. package/report/generator/flow-report-assets.js +1 -1
  50. package/report/generator/report-assets.js +1 -1
  51. package/report/generator/report-generator.js +3 -3
  52. package/report/renderer/i18n-formatter.js +2 -1
  53. package/report/renderer/report-renderer.js +1 -0
  54. package/report/renderer/report-utils.js +3 -2
  55. package/report/renderer/text-encoding.js +0 -2
@@ -10,8 +10,6 @@
10
10
  * Supports skipping and modifiying expectations to match the environment.
11
11
  */
12
12
 
13
- /* eslint-disable no-console */
14
-
15
13
  import {cloneDeep} from 'lodash-es';
16
14
 
17
15
  import smokeTests from '../core-tests.js';
@@ -10,8 +10,6 @@
10
10
  * flags, start fixture webservers, then run smokehouse.
11
11
  */
12
12
 
13
- /* eslint-disable no-console */
14
-
15
13
  import path from 'path';
16
14
  import fs from 'fs';
17
15
  import url from 'url';
@@ -173,7 +171,7 @@ async function begin() {
173
171
  },
174
172
  'no-headless': {
175
173
  type: 'boolean',
176
- describe: 'Launch Chrome in typical desktop headful mode, rather than our default of `--headless=new` (https://developer.chrome.com/articles/new-headless/).', // eslint-disable-line max-len
174
+ describe: 'Launch Chrome in typical desktop headful mode, rather than our default of `--headless=new` (https://developer.chrome.com/articles/new-headless/).',
177
175
  },
178
176
  })
179
177
  .wrap(y.terminalWidth())
@@ -94,7 +94,7 @@ async function internalRun(url, tmpPath, config, logger, options) {
94
94
 
95
95
  try {
96
96
  await fs.access(outputPath);
97
- } catch (e) {
97
+ } catch {
98
98
  throw new ChildProcessError(`Lighthouse run failed to produce a report.`, logger.getLog());
99
99
  }
100
100
 
@@ -10,8 +10,6 @@
10
10
  * smoke tests passed.
11
11
  */
12
12
 
13
- /* eslint-disable no-console */
14
-
15
13
  /**
16
14
  * @typedef Run
17
15
  * @property {string[] | undefined} networkRequests
@@ -25,7 +25,6 @@ import {detectLegacyJavaScript} from '../../lib/legacy-javascript/legacy-javascr
25
25
  const UIStrings = {
26
26
  /** Title of a Lighthouse audit that tells the user about legacy polyfills and transforms used on the page. This is displayed in a list of audit titles that Lighthouse generates. */
27
27
  title: 'Avoid serving legacy JavaScript to modern browsers',
28
- // eslint-disable-next-line max-len
29
28
  // TODO: developer.chrome.com article. this codelab is good starting place: https://web.dev/articles/codelab-serve-modern-code
30
29
  /** Description of a Lighthouse audit that tells the user about old JavaScript that is no longer needed. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
31
30
  description: 'Polyfills and transforms enable legacy browsers to use new JavaScript features. However, many aren\'t necessary for modern browsers. Consider modifying your JavaScript build process to not transpile [Baseline](https://web.dev/baseline) features, unless you know you must support legacy browsers. [Learn why most sites can deploy ES6+ code without transpiling](https://philipwalton.com/articles/the-state-of-es5-on-the-web/)',
@@ -13,7 +13,6 @@ import {JSBundles} from '../computed/js-bundles.js';
13
13
  import * as i18n from '../lib/i18n/i18n.js';
14
14
  import {getIssueDetailDescription} from '../lib/deprecation-description.js';
15
15
 
16
- /* eslint-disable max-len */
17
16
  const UIStrings = {
18
17
  /** Title of a Lighthouse audit that provides detail on the use of deprecated APIs. This descriptive title is shown to users when the page does not use deprecated APIs. */
19
18
  title: 'Avoids deprecated APIs',
@@ -32,7 +31,6 @@ const UIStrings = {
32
31
  /** Table column header for line of code (eg. 432) that is using a deprecated API. */
33
32
  columnLine: 'Line',
34
33
  };
35
- /* eslint-enable max-len */
36
34
 
37
35
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
38
36
 
@@ -19,12 +19,10 @@ const MAX_LAYOUT_SHIFTS_PER_CLUSTER = 5;
19
19
  // eslint-disable-next-line max-len
20
20
  const insightStr_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/CLSCulprits.js', InsightUIStrings);
21
21
 
22
- /* eslint-disable max-len */
23
22
  const UIStrings = {
24
23
  /** Label for a column in a data table; entries in this column will be a number representing how large the layout shift was. */
25
24
  columnScore: 'Layout shift score',
26
25
  };
27
- /* eslint-enable max-len */
28
26
 
29
27
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
30
28
 
@@ -37,10 +37,8 @@ class ModernHTTPInsight extends Audit {
37
37
  return adaptInsightToAuditProduct(artifacts, context, 'ModernHTTP', (insight) => {
38
38
  /** @type {LH.Audit.Details.Table['headings']} */
39
39
  const headings = [
40
- /* eslint-disable max-len */
41
40
  {key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
42
41
  {key: 'protocol', valueType: 'text', label: str_(UIStrings.protocol)},
43
- /* eslint-enable max-len */
44
42
  ];
45
43
  /** @type {LH.Audit.Details.Table['items']} */
46
44
  const items =
@@ -11,7 +11,6 @@
11
11
  import {Audit} from './audit.js';
12
12
  import * as i18n from '../lib/i18n/i18n.js';
13
13
 
14
- /* eslint-disable max-len */
15
14
  const UIStrings = {
16
15
  /** Title of a Lighthouse audit that provides detail on the use of third party cookies. This descriptive title is shown to users when the page does not use third party cookies. */
17
16
  title: 'Avoids third-party cookies',
@@ -25,7 +24,6 @@ const UIStrings = {
25
24
  other {# cookies found}
26
25
  }`,
27
26
  };
28
- /* eslint-enable max-len */
29
27
 
30
28
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
31
29
 
@@ -121,7 +121,6 @@ class ValidSourceMaps extends Audit {
121
121
 
122
122
  /** @type {LH.Audit.Details.TableColumnHeading[]} */
123
123
  const headings = [
124
- /* eslint-disable max-len */
125
124
  {
126
125
  key: 'scriptUrl',
127
126
  valueType: 'url',
@@ -129,7 +128,6 @@ class ValidSourceMaps extends Audit {
129
128
  label: str_(i18n.UIStrings.columnURL),
130
129
  },
131
130
  {key: 'sourceMapUrl', valueType: 'url', label: str_(UIStrings.columnMapURL)},
132
- /* eslint-enable max-len */
133
131
  ];
134
132
 
135
133
  results.sort((a, b) => {
@@ -55,7 +55,6 @@ function computeGeneratedFileSizes(map, contentLength, content) {
55
55
  let mappingLength = 0;
56
56
  if (lastColNum !== undefined) {
57
57
  if (lastColNum > line.length) {
58
- // eslint-disable-next-line max-len
59
58
  const errorMessage =
60
59
  `${map.url()} mapping for last column out of bounds: ${lineNum + 1}:${lastColNum}`;
61
60
  log.error('JSBundles', errorMessage);
@@ -159,7 +159,6 @@ class CumulativeLayoutShift {
159
159
  LayoutShifts: TraceEngine.TraceHandlers.LayoutShifts,
160
160
  Screenshots: TraceEngine.TraceHandlers.Screenshots,
161
161
  });
162
- // eslint-disable-next-line max-len
163
162
  await processor.parse(/** @type {import('@paulirish/trace_engine').Types.Events.Event[]} */ (
164
163
  events
165
164
  ), {});
@@ -212,6 +211,7 @@ class CumulativeLayoutShift {
212
211
  throw new Error(`new trace engine differed. expected: ${expected}, got: ${got}`);
213
212
  }
214
213
  } catch (err) {
214
+ // eslint-disable-next-line no-console
215
215
  console.error(err);
216
216
  newEngineResultDiffered = true;
217
217
 
@@ -34,7 +34,6 @@ class TraceEngineResult {
34
34
  lanternSettings.precomputedLanternData = settings.precomputedLanternData;
35
35
  }
36
36
 
37
- // eslint-disable-next-line max-len
38
37
  await processor.parse(/** @type {import('@paulirish/trace_engine').Types.Events.Event[]} */ (
39
38
  traceEvents
40
39
  ), {
@@ -10,7 +10,7 @@ import log from 'lighthouse-logger';
10
10
 
11
11
  import {Runner} from '../runner.js';
12
12
  import defaultConfig from './default-config.js';
13
- import {nonSimulatedSettingsOverrides} from './constants.js'; // eslint-disable-line max-len
13
+ import {nonSimulatedSettingsOverrides} from './constants.js';
14
14
  import {
15
15
  throwInvalidDependencyOrder,
16
16
  isValidArtifactDependency,
@@ -6,7 +6,7 @@
6
6
 
7
7
  import log from 'lighthouse-logger';
8
8
 
9
- import {waitForFullyLoaded, waitForFrameNavigated, waitForUserToContinue} from './wait-for-condition.js'; // eslint-disable-line max-len
9
+ import {waitForFullyLoaded, waitForFrameNavigated, waitForUserToContinue} from './wait-for-condition.js';
10
10
  import * as constants from '../../config/constants.js';
11
11
  import * as i18n from '../../lib/i18n/i18n.js';
12
12
  import UrlUtils from '../../lib/url-utils.js';
@@ -43,7 +43,6 @@ const DEFAULT_CPU_QUIET_THRESHOLD = 0;
43
43
 
44
44
  /** @param {NavigationOptions} options */
45
45
  function resolveWaitForFullyLoadedOptions(options) {
46
- /* eslint-disable max-len */
47
46
  let {pauseAfterFcpMs, pauseAfterLoadMs, networkQuietThresholdMs, cpuQuietThresholdMs} = options;
48
47
  let maxWaitMs = options.maxWaitForLoad;
49
48
  let maxFCPMs = options.maxWaitForFcp;
@@ -56,7 +55,6 @@ function resolveWaitForFullyLoadedOptions(options) {
56
55
  if (typeof cpuQuietThresholdMs !== 'number') cpuQuietThresholdMs = DEFAULT_CPU_QUIET_THRESHOLD;
57
56
  if (typeof maxWaitMs !== 'number') maxWaitMs = constants.defaultSettings.maxWaitForLoad;
58
57
  if (typeof maxFCPMs !== 'number') maxFCPMs = constants.defaultSettings.maxWaitForFcp;
59
- /* eslint-enable max-len */
60
58
 
61
59
  if (!options.waitUntil.includes('fcp')) maxFCPMs = undefined;
62
60
 
@@ -138,7 +138,6 @@ function waitForNetworkIdle(session, networkMonitor, networkQuietOptions) {
138
138
  /** @type {Promise<void>} */
139
139
  const promise = new Promise((resolve, reject) => {
140
140
  const onIdle = () => {
141
- // eslint-disable-next-line no-use-before-define
142
141
  networkMonitor.once(busyEvent, onBusy);
143
142
  idleTimeout = setTimeout(() => {
144
143
  cancel();
@@ -10,8 +10,6 @@ import * as LH from '../../types/lh.js';
10
10
  * ignoring normal browser constraints such as CORS.
11
11
  */
12
12
 
13
- /* global fetch */
14
-
15
13
  /** @typedef {{content: string|null, status: number|null}} FetchResponse */
16
14
 
17
15
  class Fetcher {
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- /* global window, document, getNodeDetails */
7
+ /* global getNodeDetails */
8
8
 
9
9
  import BaseGatherer from '../base-gatherer.js';
10
10
  import {axeSource} from '../../lib/axe.js';
@@ -10,8 +10,6 @@ import BaseGatherer from '../base-gatherer.js';
10
10
  import {pageFunctions} from '../../lib/page-functions.js';
11
11
  import {resolveDevtoolsNodePathToObjectId} from '../driver/dom.js';
12
12
 
13
- /* eslint-env browser, node */
14
-
15
13
  /**
16
14
  * Function that is stringified and run in the page to collect anchor elements.
17
15
  * Additional complexity is introduced because anchors can be HTML or SVG elements.
@@ -4,8 +4,6 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- /* global caches */
8
-
9
7
  import BaseGatherer from '../base-gatherer.js';
10
8
 
11
9
  /**
@@ -30,7 +30,6 @@ class CSSUsage extends BaseGatherer {
30
30
 
31
31
  // Force style to recompute.
32
32
  // Doesn't appear to be necessary in newer versions of Chrome.
33
- /* global window, document */
34
33
  await executionContext.evaluate(() => window.getComputedStyle(document.body), {
35
34
  args: [],
36
35
  });
@@ -6,8 +6,6 @@
6
6
 
7
7
  import BaseGatherer from '../../base-gatherer.js';
8
8
 
9
- /* global document */
10
-
11
9
  /**
12
10
  * Get and return `name`, `publicId`, `systemId` from
13
11
  * `document.doctype`
@@ -9,7 +9,7 @@
9
9
  * and total number of elements used on the page.
10
10
  */
11
11
 
12
- /* global getNodeDetails document */
12
+ /* global getNodeDetails */
13
13
 
14
14
 
15
15
  import BaseGatherer from '../../base-gatherer.js';
@@ -3,7 +3,7 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
 
6
- /* globals window getBoundingClientRect requestAnimationFrame */
6
+ /* globals getBoundingClientRect */
7
7
 
8
8
  import BaseGatherer from '../base-gatherer.js';
9
9
  import * as emulation from '../../lib/emulation.js';
@@ -15,7 +15,7 @@ import BaseGatherer from '../base-gatherer.js';
15
15
  import {pageFunctions} from '../../lib/page-functions.js';
16
16
  import * as FontSize from './seo/font-size.js';
17
17
 
18
- /* global window, getElementsInDocument, Image, getNodeDetails, ShadowRoot */
18
+ /* global getElementsInDocument, getNodeDetails */
19
19
 
20
20
  /** @param {Element} element */
21
21
  /* c8 ignore start */
@@ -13,7 +13,7 @@ import {MainResource} from '../../computed/main-resource.js';
13
13
  import {Util} from '../../../shared/util.js';
14
14
  import * as i18n from '../../lib/i18n/i18n.js';
15
15
 
16
- /* globals HTMLLinkElement getNodeDetails */
16
+ /* globals getNodeDetails */
17
17
 
18
18
  /**
19
19
  * @fileoverview
@@ -8,7 +8,6 @@
8
8
  * @fileoverview Gathers a list of detected JS libraries and their versions.
9
9
  */
10
10
 
11
- /* global window */
12
11
  /* global d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests */
13
12
 
14
13
  import fs from 'fs';
@@ -74,7 +74,6 @@ class Stylesheets extends BaseGatherer {
74
74
 
75
75
  // Force style to recompute.
76
76
  // Doesn't appear to be necessary in newer versions of Chrome.
77
- /* global window, document */
78
77
  await executionContext.evaluate(() => window.getComputedStyle(document.body), {
79
78
  args: [],
80
79
  });
@@ -35,7 +35,7 @@ const MAX_LAYOUT_SHIFTS = 15;
35
35
  */
36
36
  /* c8 ignore start */
37
37
  function getNodeDetailsData() {
38
- const elem = this.nodeType === document.ELEMENT_NODE ? this : this.parentElement; // eslint-disable-line no-undef
38
+ const elem = this.nodeType === document.ELEMENT_NODE ? this : this.parentElement;
39
39
  let traceElement;
40
40
  if (elem) {
41
41
  // @ts-expect-error - getNodeDetails put into scope via stringification
@@ -6,8 +6,6 @@
6
6
 
7
7
  import BaseGatherer from '../base-gatherer.js';
8
8
 
9
- /* global window */
10
-
11
9
  /**
12
10
  * @return {LH.Artifacts.ViewportDimensions}
13
11
  */
package/core/index.cjs CHANGED
@@ -3,7 +3,6 @@
3
3
  * Copyright 2022 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- 'use strict';
7
6
 
8
7
  /**
9
8
  * @typedef ExportType
package/core/index.d.cts CHANGED
@@ -1,4 +1,9 @@
1
1
  export = lighthouse;
2
+ /**
3
+ * @license
4
+ * Copyright 2022 Google LLC
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
2
7
  /**
3
8
  * @typedef ExportType
4
9
  * @property {import('./index.js')['startFlow']} startFlow
@@ -17,7 +17,6 @@ import {LH_ROOT} from '../../../shared/root.js';
17
17
  import {isIcuMessage, formatMessage, DEFAULT_LOCALE} from '../../../shared/localization/format.js';
18
18
  import {getModulePath} from '../../../shared/esm-utils.js';
19
19
 
20
- /* eslint-disable max-len */
21
20
  const UIStrings = {
22
21
  /** Used to show the duration in milliseconds that something lasted. The `{timeInMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 63 ms) */
23
22
  ms: '{timeInMs, number, milliseconds}\xa0ms',
@@ -114,7 +113,6 @@ const UIStrings = {
114
113
  /** Table item value for the severity of a high impact, or dangerous vulnerability. Part of a ranking scale in the form: low, medium, high. */
115
114
  itemSeverityHigh: 'High',
116
115
  };
117
- /* eslint-enable max-len */
118
116
 
119
117
  /**
120
118
  * Look up the best available locale for the requested language through these fall backs:
@@ -153,7 +153,7 @@ function convertNodeTimingsToTrace(nodeTimings) {
153
153
 
154
154
  // 0ms requests get super-messed up rendering
155
155
  // Use 0.3ms instead so they're still hoverable, https://github.com/GoogleChrome/lighthouse/pull/5350#discussion_r194563201
156
- let {startTime, endTime} = timing; // eslint-disable-line prefer-const
156
+ let {startTime, endTime} = timing;
157
157
  if (startTime === endTime) endTime += 0.3;
158
158
 
159
159
  const requestData = {requestId: requestId.toString(), frame};
@@ -214,7 +214,6 @@ class LighthouseError extends Error {
214
214
  if (typeof possibleError === 'object' && possibleError !== null) {
215
215
  if (possibleError.sentinel === LHERROR_SENTINEL) {
216
216
  // Include sentinel in destructuring so it doesn't end up in `properties`.
217
- // eslint-disable-next-line no-unused-vars
218
217
  const {code, stack, cause, properties} = /** @type {SerializedLighthouseError} */ (possibleError);
219
218
  const errorDefinition = LighthouseError.errors[/** @type {keyof typeof ERRORS} */ (code)];
220
219
  const lhError = new LighthouseError(errorDefinition, properties, {cause});
@@ -458,7 +458,6 @@ function parseManifest(string, manifestUrl, documentUrl) {
458
458
  };
459
459
  }
460
460
 
461
- /* eslint-disable camelcase */
462
461
  const manifest = {
463
462
  name: parseName(jsonInput),
464
463
  short_name: parseShortName(jsonInput),
@@ -471,7 +470,6 @@ function parseManifest(string, manifestUrl, documentUrl) {
471
470
  theme_color: parseThemeColor(jsonInput),
472
471
  background_color: parseBackgroundColor(jsonInput),
473
472
  };
474
- /* eslint-enable camelcase */
475
473
 
476
474
  /** @type {string|undefined} */
477
475
  let manifestUrlWarning;
@@ -4,8 +4,6 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- /* eslint-disable no-console */
8
-
9
7
  /**
10
8
  * @fileoverview Minifies a devtools log by removing noisy header values, eliminating data URIs, etc.
11
9
  */
@@ -17,7 +17,7 @@ export namespace Sentry {
17
17
  export type Breadcrumb = import("@sentry/node").Breadcrumb;
18
18
  export type NodeClient = import("@sentry/node").NodeClient;
19
19
  export type NodeOptions = import("@sentry/node").NodeOptions;
20
- export type Severity = import("@sentry/node").Severity;
20
+ export type SeverityLevel = import("@sentry/node").SeverityLevel;
21
21
  /**
22
22
  * When called, replaces noops with actual Sentry implementation.
23
23
  * @param {{url: string, flags: LH.CliFlags, config?: LH.Config, environmentData: NodeOptions}} opts
@@ -11,7 +11,7 @@ import {initializeConfig} from '../config/config.js';
11
11
  /** @typedef {import('@sentry/node').Breadcrumb} Breadcrumb */
12
12
  /** @typedef {import('@sentry/node').NodeClient} NodeClient */
13
13
  /** @typedef {import('@sentry/node').NodeOptions} NodeOptions */
14
- /** @typedef {import('@sentry/node').Severity} Severity */
14
+ /** @typedef {import('@sentry/node').SeverityLevel} SeverityLevel */
15
15
 
16
16
  const SENTRY_URL = 'https://a6bb0da87ee048cc9ae2a345fc09ab2e:63a7029f46f74265981b7e005e0f69f8@sentry.io/174697';
17
17
 
@@ -26,7 +26,7 @@ const noop = () => { };
26
26
  */
27
27
  const sentryDelegate = {
28
28
  init,
29
- /** @type {(message: string, level?: Severity) => void} */
29
+ /** @type {(message: string, level?: SeverityLevel) => void} */
30
30
  captureMessage: noop,
31
31
  /** @type {(breadcrumb: Breadcrumb) => void} */
32
32
  captureBreadcrumb: noop,
package/core/runner.js CHANGED
@@ -458,7 +458,6 @@ vs: ${JSON.stringify(normalizedAuditSettings[k], null, 2)}`);
458
458
  for (const [artifactKey, possibleErrorArtifact] of possibleErrorArtifacts) {
459
459
  const isError = possibleErrorArtifact instanceof LighthouseError;
460
460
 
461
- // eslint-disable-next-line max-len
462
461
  if (isError && possibleErrorArtifact.lhrRuntimeError) {
463
462
  const errorMessage = possibleErrorArtifact.friendlyMessage || possibleErrorArtifact.message;
464
463
  // Prefer the stack trace closest to the error.
@@ -46,5 +46,4 @@ launch({
46
46
  ignoreDefaultFlags,
47
47
  chromeFlags,
48
48
  })
49
- // eslint-disable-next-line no-console
50
49
  .then(v => console.log(`✨ Chrome debugging port: ${v.port}`));
@@ -0,0 +1,242 @@
1
+ import path from 'node:path';
2
+ import {fileURLToPath} from 'node:url';
3
+
4
+ import localRules from 'eslint-plugin-local-rules';
5
+ import _import from 'eslint-plugin-import';
6
+ import {fixupPluginRules} from '@eslint/compat';
7
+ import globals from 'globals';
8
+ import tsParser from '@typescript-eslint/parser';
9
+ import js from '@eslint/js';
10
+ import {FlatCompat} from '@eslint/eslintrc';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+ const compat = new FlatCompat({
15
+ baseDirectory: __dirname,
16
+ recommendedConfig: js.configs.recommended,
17
+ allConfig: js.configs.all,
18
+ });
19
+
20
+ // See https://eslint.org/docs/latest/use/configure/configuration-files
21
+ export default [{
22
+ files: [
23
+ '**/*.cjs',
24
+ '**/*.js',
25
+ '**/*.mjs',
26
+ '**/*.ts',
27
+ '**/*.tsx',
28
+ ],
29
+ }, {
30
+ // Global ignores.
31
+ ignores: [
32
+ '.cz-config.js',
33
+ '**/.tmp',
34
+ '**/*.d.cts', // ignore d.ts files until we can properly lint them
35
+ '**/*.d.ts',
36
+ '**/dist',
37
+ '**/fixtures/**',
38
+ '**/node_modules/**',
39
+ '**/source-maps/**',
40
+ '**/third_party/**',
41
+ '**/third-party/**',
42
+ 'build/test/page-functions-test-case*out*.js',
43
+ 'core/scripts/legacy-javascript/variants/**',
44
+ 'coverage/**',
45
+ ],
46
+ }, ...compat.extends('eslint:recommended', 'google'), {
47
+ plugins: {
48
+ 'local-rules': localRules,
49
+ 'import': fixupPluginRules(_import),
50
+ },
51
+
52
+ languageOptions: {
53
+ globals: {
54
+ ...globals.node,
55
+ },
56
+
57
+ parser: tsParser,
58
+ ecmaVersion: 2020,
59
+ sourceType: 'module',
60
+
61
+ parserOptions: {
62
+ ecmaFeatures: {
63
+ globalReturn: true,
64
+ jsx: false,
65
+ },
66
+ },
67
+ },
68
+
69
+ rules: {
70
+ 'import/order': [2, {
71
+ 'groups': ['builtin', 'external', ['sibling', 'parent'], 'index', 'object', 'type'],
72
+ 'newlines-between': 'always',
73
+ }],
74
+
75
+ 'import/group-exports': 2,
76
+ 'import/exports-last': 2,
77
+ 'eqeqeq': 2,
78
+ 'no-console': 2,
79
+
80
+ 'indent': [2, 2, {
81
+ SwitchCase: 1,
82
+ VariableDeclarator: 2,
83
+
84
+ CallExpression: {
85
+ arguments: 'off',
86
+ },
87
+
88
+ MemberExpression: 'off',
89
+
90
+ FunctionExpression: {
91
+ body: 1,
92
+ parameters: 2,
93
+ },
94
+
95
+ ignoredNodes: [
96
+ 'ConditionalExpression > :matches(.consequent, .alternate)',
97
+ 'VariableDeclarator > ArrowFunctionExpression > :expression.body',
98
+ 'CallExpression > ArrowFunctionExpression > :expression.body',
99
+ ],
100
+ }],
101
+
102
+ 'no-floating-decimal': 2,
103
+
104
+ 'max-len': [2, 100, {
105
+ ignorePattern: 'readJson\\(|^import ',
106
+ ignoreComments: true,
107
+ ignoreUrls: true,
108
+ tabWidth: 2,
109
+ }],
110
+
111
+ 'no-empty': [2, {
112
+ allowEmptyCatch: true,
113
+ }],
114
+
115
+ 'no-implicit-coercion': [2, {
116
+ boolean: false,
117
+ number: true,
118
+ string: true,
119
+ }],
120
+
121
+ 'no-unused-expressions': [2, {
122
+ allowShortCircuit: true,
123
+ allowTernary: false,
124
+ }],
125
+
126
+ 'no-unused-vars': [2, {
127
+ vars: 'all',
128
+ args: 'after-used',
129
+ caughtErrors: 'none', // TODO: remove for new "all" default.
130
+ argsIgnorePattern: '(^reject$|^_+$)',
131
+ varsIgnorePattern: '(^_$|^LH$|^Lantern$|^TraceEngine$|^Protocol$)',
132
+ }],
133
+
134
+ 'no-cond-assign': 2,
135
+ 'space-infix-ops': 2,
136
+ 'strict': [2, 'global'],
137
+ 'prefer-const': 2,
138
+ 'curly': [2, 'multi-line'],
139
+
140
+ 'comma-dangle': [2, {
141
+ arrays: 'always-multiline',
142
+ objects: 'always-multiline',
143
+ imports: 'always-multiline',
144
+ exports: 'always-multiline',
145
+ functions: 'never',
146
+ }],
147
+
148
+ 'operator-linebreak': ['error', 'after', {
149
+ overrides: {
150
+ '?': 'ignore',
151
+ ':': 'ignore',
152
+ },
153
+ }],
154
+
155
+ 'local-rules/require-file-extension': 2,
156
+ 'require-jsdoc': 0,
157
+ 'valid-jsdoc': 0,
158
+ 'arrow-parens': 0,
159
+ },
160
+ }, {
161
+ files: ['cli/test/smokehouse/test-definitions/**'],
162
+
163
+ rules: {
164
+ 'max-len': 0,
165
+ },
166
+ }, {
167
+ files: [
168
+ '**/build/**',
169
+ '**/scripts/**',
170
+ '**/test/**',
171
+ ],
172
+
173
+ rules: {
174
+ 'no-console': 0,
175
+ },
176
+ }, {
177
+ files: [
178
+ 'docs/recipes/auth/**',
179
+ ],
180
+
181
+ rules: {
182
+ 'new-cap': 0,
183
+ 'no-console': 0,
184
+ 'no-unused-vars': 0,
185
+ },
186
+ }, {
187
+ files: [
188
+ '**/test/**',
189
+ 'docs/recipes/**',
190
+ ],
191
+
192
+ languageOptions: {
193
+ globals: {
194
+ ...globals.jest,
195
+ ...globals.mocha,
196
+ },
197
+ },
198
+ }, {
199
+ files: [
200
+ 'clients/**',
201
+ 'core/gather/gatherers/**',
202
+ 'docs/recipes/auth/**',
203
+ 'flow-report/**',
204
+ 'report/**',
205
+ 'treemap/**',
206
+ 'viewer/**',
207
+ ],
208
+ ignores: [
209
+ 'report/generator/**',
210
+ 'report/test/generator/**',
211
+ ],
212
+
213
+ languageOptions: {
214
+ globals: {
215
+ ...globals.browser,
216
+ },
217
+ },
218
+ }, {
219
+ files: [
220
+ 'clients/**',
221
+ ],
222
+
223
+ languageOptions: {
224
+ globals: {
225
+ chrome: true,
226
+ __lighthouse: true,
227
+ },
228
+ },
229
+ }, {
230
+ files: ['flow-report/**'],
231
+
232
+ languageOptions: {
233
+ globals: {
234
+ ...globals.browser,
235
+ ...globals.node,
236
+ },
237
+ },
238
+
239
+ rules: {
240
+ 'no-undef': 'off',
241
+ },
242
+ }];
@@ -88,6 +88,7 @@ const FlowStepThumbnail: FunctionComponent<{
88
88
  }
89
89
 
90
90
  if (!width || !height) {
91
+ // eslint-disable-next-line no-console
91
92
  console.warn(new Error('FlowStepThumbnail requested without any dimensions').stack);
92
93
  return <></>;
93
94
  }
@@ -26,6 +26,7 @@ function useLhrLocale() {
26
26
  const locale = firstLhr.configSettings.locale;
27
27
 
28
28
  if (flowResult.steps.some(step => step.lhr.configSettings.locale !== locale)) {
29
+ // eslint-disable-next-line no-console
29
30
  console.warn('LHRs have inconsistent locales');
30
31
  }
31
32
 
@@ -97,12 +97,14 @@ function useHashState(): LH.HashState|null {
97
97
 
98
98
  const index = Number(indexString);
99
99
  if (!Number.isFinite(index)) {
100
+ // eslint-disable-next-line no-console
100
101
  console.warn(`Invalid hash index: ${indexString}`);
101
102
  return null;
102
103
  }
103
104
 
104
105
  const step = flowResult.steps[index];
105
106
  if (!step) {
107
+ // eslint-disable-next-line no-console
106
108
  console.warn(`No flow step at index ${index}`);
107
109
  return null;
108
110
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "12.6.1-dev.20250611",
4
+ "version": "12.6.1-dev.20250613",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {
@@ -105,6 +105,9 @@
105
105
  "@build-tracker/cli": "^1.0.0-beta.15",
106
106
  "@esbuild-kit/esm-loader": "^2.1.1",
107
107
  "@esbuild-plugins/node-modules-polyfill": "^0.1.4",
108
+ "@eslint/compat": "^1.3.0",
109
+ "@eslint/eslintrc": "^3.3.1",
110
+ "@eslint/js": "^9.28.0",
108
111
  "@formatjs/icu-messageformat-parser": "^2.6.2",
109
112
  "@jest/fake-timers": "^29.7.0",
110
113
  "@testing-library/preact": "^3.1.1",
@@ -114,7 +117,7 @@
114
117
  "@types/configstore": "^6.0.2",
115
118
  "@types/cpy": "^5.1.0",
116
119
  "@types/debug": "^4.1.7",
117
- "@types/eslint": "^8.2.1",
120
+ "@types/eslint": "^9.6.1",
118
121
  "@types/estree": "^0.0.50",
119
122
  "@types/gh-pages": "^2.0.0",
120
123
  "@types/google.analytics": "0.0.39",
@@ -131,8 +134,8 @@
131
134
  "@types/ws": "^7.0.0",
132
135
  "@types/yargs": "^17.0.8",
133
136
  "@types/yargs-parser": "^20.2.1",
134
- "@typescript-eslint/eslint-plugin": "^5.48.0",
135
- "@typescript-eslint/parser": "^5.48.0",
137
+ "@typescript-eslint/eslint-plugin": "^8.34.0",
138
+ "@typescript-eslint/parser": "^8.34.0",
136
139
  "acorn": "^8.5.0",
137
140
  "angular": "^1.7.4",
138
141
  "archiver": "^3.0.0",
@@ -149,7 +152,7 @@
149
152
  "csv-validator": "^0.0.3",
150
153
  "es-main": "^1.2.0",
151
154
  "esbuild": "0.19.11",
152
- "eslint": "^8.4.1",
155
+ "eslint": "^9.28.0",
153
156
  "eslint-config-google": "^0.14.0",
154
157
  "eslint-formatter-codeframe": "^7.32.1",
155
158
  "eslint-plugin-import": "^2.25.3",
@@ -159,6 +162,7 @@
159
162
  "firebase": "^9.0.2",
160
163
  "gh-pages": "^2.0.1",
161
164
  "glob": "^7.1.3",
165
+ "globals": "^15.14.0",
162
166
  "idb-keyval": "2.2.0",
163
167
  "jest-mock": "^29.7.0",
164
168
  "jest-snapshot": "^29.7.0",
@@ -186,7 +190,7 @@
186
190
  },
187
191
  "dependencies": {
188
192
  "@paulirish/trace_engine": "0.0.53",
189
- "@sentry/node": "^7.0.0",
193
+ "@sentry/node": "^9.28.1",
190
194
  "axe-core": "^4.10.3",
191
195
  "chrome-launcher": "^1.2.0",
192
196
  "configstore": "^7.0.0",
@@ -7,6 +7,11 @@ export function getLhrFilenamePrefix(lhr: {
7
7
  finalDisplayedUrl: string;
8
8
  fetchTime: string;
9
9
  }): string;
10
+ /**
11
+ * @license
12
+ * Copyright 2017 Google LLC
13
+ * SPDX-License-Identifier: Apache-2.0
14
+ */
10
15
  /**
11
16
  * @fileoverview
12
17
  * @suppress {reportUnknownTypes}
@@ -3,7 +3,7 @@
3
3
  * Copyright 2017 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- 'use strict';
6
+
7
7
 
8
8
  /**
9
9
  * @fileoverview
@@ -3,7 +3,7 @@
3
3
  * Copyright 2021 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- 'use strict';
6
+
7
7
 
8
8
  import fs from 'fs';
9
9
 
@@ -3,7 +3,7 @@
3
3
  * Copyright 2018 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- 'use strict';
6
+
7
7
 
8
8
  import fs from 'fs';
9
9
 
@@ -3,7 +3,7 @@
3
3
  * Copyright 2017 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- 'use strict';
6
+
7
7
 
8
8
  import {reportAssets} from './report-assets.js';
9
9
 
@@ -69,11 +69,11 @@ class ReportGenerator {
69
69
  // we want to generate a report without minification.
70
70
  const sanitizedJavascript = reportAssets.FLOW_REPORT_JAVASCRIPT.replace(/<\//g, '\\u003c/');
71
71
  return ReportGenerator.replaceStrings(reportAssets.FLOW_REPORT_TEMPLATE, [
72
- /* eslint-disable max-len */
72
+
73
73
  {search: '%%LIGHTHOUSE_FLOW_JSON%%', replacement: sanitizedJson},
74
74
  {search: '%%LIGHTHOUSE_FLOW_JAVASCRIPT%%', replacement: sanitizedJavascript},
75
75
  {search: '/*%%LIGHTHOUSE_FLOW_CSS%%*/', replacement: reportAssets.FLOW_REPORT_CSS},
76
- /* eslint-enable max-len */
76
+
77
77
  ]);
78
78
  }
79
79
 
@@ -31,6 +31,7 @@ export class I18nFormatter {
31
31
  if (granularity !== undefined) {
32
32
  const log10 = -Math.log10(granularity);
33
33
  if (!Number.isInteger(log10)) {
34
+ // eslint-disable-next-line no-console
34
35
  console.warn(`granularity of ${granularity} is invalid. Using 1 instead`);
35
36
  granularity = 1;
36
37
  }
@@ -50,7 +51,7 @@ export class I18nFormatter {
50
51
  }
51
52
 
52
53
  let formatter;
53
- // eslint-disable-next-line max-len
54
+
54
55
  const cacheKey = [
55
56
  opts.minimumFractionDigits,
56
57
  opts.maximumFractionDigits,
@@ -37,6 +37,7 @@ export class ReportRenderer {
37
37
  renderReport(lhr, rootEl, opts) {
38
38
  // Allow legacy report rendering API
39
39
  if (!this._dom.rootEl && rootEl) {
40
+ // eslint-disable-next-line no-console
40
41
  console.warn('Please adopt the new report API in renderer/api.js.');
41
42
  const closestRoot = rootEl.closest('.lh-root');
42
43
  if (closestRoot) {
@@ -159,6 +159,7 @@ class ReportUtils {
159
159
  const aVal = a[key];
160
160
  const bVal = b[key];
161
161
  if (typeof aVal !== typeof bVal || !['number', 'string'].includes(typeof aVal)) {
162
+ // eslint-disable-next-line no-console
162
163
  console.warn(`Warning: Attempting to sort unsupported value type: ${key}.`);
163
164
  }
164
165
  if (typeof aVal === 'number' && typeof bVal === 'number' && aVal !== bVal) {
@@ -191,7 +192,7 @@ class ReportUtils {
191
192
  break;
192
193
  case 'devtools': {
193
194
  const {cpuSlowdownMultiplier, requestLatencyMs} = throttling;
194
- // eslint-disable-next-line max-len
195
+
195
196
  cpuThrottling = `${i18n.formatNumber(cpuSlowdownMultiplier)}x slowdown (DevTools)`;
196
197
  networkThrottling = `${i18n.formatMilliseconds(requestLatencyMs)} HTTP RTT, ` +
197
198
  `${i18n.formatKbps(throttling.downloadThroughputKbps)} down, ` +
@@ -207,7 +208,7 @@ class ReportUtils {
207
208
  }
208
209
  case 'simulate': {
209
210
  const {cpuSlowdownMultiplier, rttMs, throughputKbps} = throttling;
210
- // eslint-disable-next-line max-len
211
+
211
212
  cpuThrottling = `${i18n.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;
212
213
  networkThrottling = `${i18n.formatMilliseconds(rttMs)} TCP RTT, ` +
213
214
  `${i18n.formatKbps(throughputKbps)} throughput (Simulated)`;
@@ -4,8 +4,6 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- /* global CompressionStream */
8
-
9
7
  const btoa_ = typeof btoa !== 'undefined' ?
10
8
  btoa :
11
9
  /** @param {string} str */