lighthouse 8.6.0 → 9.0.0-dev.20211118
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.
- package/changelog.md +121 -0
- package/dist/report/bundle.esm.js +6009 -0
- package/dist/report/flow.js +98 -25
- package/dist/report/standalone.js +41 -35
- package/flow-report/.eslintrc.cjs +2 -0
- package/flow-report/assets/standalone-flow-template.html +3 -4
- package/flow-report/assets/styles.css +108 -31
- package/flow-report/src/app.tsx +25 -28
- package/flow-report/src/common.tsx +28 -15
- package/flow-report/src/header.tsx +12 -13
- package/flow-report/src/help-dialog.tsx +3 -4
- package/flow-report/src/i18n/i18n.tsx +57 -16
- package/flow-report/src/i18n/ui-strings.js +50 -0
- package/flow-report/src/icons.tsx +36 -8
- package/flow-report/src/sidebar/flow.tsx +3 -3
- package/flow-report/src/sidebar/sidebar.tsx +35 -14
- package/flow-report/src/summary/category.tsx +97 -24
- package/flow-report/src/summary/summary.tsx +21 -14
- package/flow-report/src/topbar.tsx +13 -12
- package/flow-report/src/util.ts +61 -27
- package/flow-report/src/wrappers/category-score.tsx +9 -27
- package/flow-report/src/wrappers/markdown.tsx +18 -0
- package/flow-report/src/wrappers/report.tsx +26 -37
- package/flow-report/standalone-flow.tsx +5 -4
- package/flow-report/test/common-test.tsx +32 -17
- package/flow-report/test/flow-report-pptr-test.ts +46 -0
- package/flow-report/test/header-test.tsx +6 -6
- package/flow-report/test/setup/env-setup.ts +11 -5
- package/flow-report/test/sidebar/sidebar-test.tsx +43 -1
- package/flow-report/test/summary/category-test.tsx +114 -21
- package/flow-report/test/summary/summary-test.tsx +4 -7
- package/flow-report/test/topbar-test.tsx +15 -14
- package/flow-report/test/util-test.tsx +69 -11
- package/flow-report/test/wrappers/category-score-test.tsx +84 -0
- package/flow-report/test/wrappers/markdown-test.tsx +17 -0
- package/flow-report/tsconfig.json +1 -0
- package/jest.config.js +4 -2
- package/lighthouse-cli/.eslintrc.cjs +2 -0
- package/lighthouse-cli/cli-flags.js +1 -1
- package/lighthouse-cli/run.js +1 -1
- package/lighthouse-cli/test/smokehouse/lighthouse-runners/bundle.js +4 -2
- package/lighthouse-cli/test/smokehouse/lighthouse-runners/cli.js +1 -1
- package/lighthouse-cli/test/smokehouse/smokehouse.js +1 -1
- package/lighthouse-core/audits/accessibility/axe-audit.js +7 -1
- package/lighthouse-core/audits/audit.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +2 -0
- package/lighthouse-core/audits/byte-efficiency/modern-image-formats.js +4 -2
- package/lighthouse-core/audits/byte-efficiency/offscreen-images.js +11 -10
- package/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js +5 -3
- package/lighthouse-core/audits/byte-efficiency/uses-responsive-images-snapshot.js +2 -1
- package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +2 -1
- package/lighthouse-core/audits/deprecations.js +33 -11
- package/lighthouse-core/audits/dobetterweb/uses-http2.js +27 -11
- package/lighthouse-core/audits/errors-in-console.js +0 -2
- package/lighthouse-core/audits/image-aspect-ratio.js +5 -5
- package/lighthouse-core/audits/image-size-responsive.js +6 -6
- package/lighthouse-core/audits/installable-manifest.js +16 -7
- package/lighthouse-core/audits/preload-lcp-image.js +7 -5
- package/lighthouse-core/audits/script-treemap-data.js +1 -1
- package/lighthouse-core/audits/unsized-images.js +2 -3
- package/lighthouse-core/computed/image-records.js +4 -3
- package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +3 -4
- package/lighthouse-core/computed/metrics/tbt-utils.js +57 -0
- package/lighthouse-core/computed/metrics/total-blocking-time.js +3 -53
- package/lighthouse-core/computed/resource-summary.js +1 -1
- package/lighthouse-core/config/config-helpers.js +21 -10
- package/lighthouse-core/config/constants.js +3 -4
- package/lighthouse-core/config/default-config.js +61 -71
- package/lighthouse-core/fraggle-rock/config/config.js +1 -1
- package/lighthouse-core/fraggle-rock/config/default-config.js +4 -5
- package/lighthouse-core/fraggle-rock/gather/base-gatherer.js +6 -1
- package/lighthouse-core/fraggle-rock/gather/session.js +3 -4
- package/lighthouse-core/gather/connections/cri.js +1 -1
- package/lighthouse-core/gather/driver/storage.js +0 -1
- package/lighthouse-core/gather/driver.js +3 -7
- package/lighthouse-core/gather/fetcher.js +4 -7
- package/lighthouse-core/gather/gather-runner.js +29 -6
- package/lighthouse-core/gather/gatherers/accessibility.js +27 -0
- package/lighthouse-core/gather/gatherers/dobetterweb/response-compression.js +1 -0
- package/lighthouse-core/gather/gatherers/image-elements.js +0 -3
- package/lighthouse-core/gather/gatherers/inspector-issues.js +5 -0
- package/lighthouse-core/lib/asset-saver.js +7 -4
- package/lighthouse-core/lib/emulation.js +45 -1
- package/lighthouse-core/lib/i18n/i18n.js +19 -8
- package/lighthouse-core/lib/lh-env.js +2 -0
- package/lighthouse-core/lib/page-functions.js +2 -1
- package/lighthouse-core/lib/proto-preprocessor.js +14 -2
- package/lighthouse-core/lib/statistics.js +26 -39
- package/lighthouse-core/lib/tappable-rects.js +8 -15
- package/lighthouse-core/lib/url-shim.js +1 -1
- package/lighthouse-core/runner.js +1 -1
- package/lighthouse-core/util-commonjs.js +65 -46
- package/package.json +27 -17
- package/readme.md +3 -3
- package/report/.eslintrc.cjs +2 -0
- package/report/README.md +1 -1
- package/report/assets/standalone-template.html +2 -3
- package/report/assets/styles.css +362 -256
- package/report/assets/templates.html +21 -76
- package/report/clients/bundle.js +1 -0
- package/report/clients/standalone.js +6 -15
- package/report/generator/README.md +1 -1
- package/report/renderer/api.js +66 -0
- package/report/renderer/category-renderer.js +76 -22
- package/report/renderer/components.js +59 -110
- package/report/renderer/crc-details-renderer.js +15 -12
- package/report/renderer/dom.js +16 -1
- package/report/renderer/drop-down-menu.js +2 -2
- package/report/renderer/element-screenshot-renderer.js +8 -8
- package/report/renderer/features-util.js +1 -1
- package/report/renderer/open-tab.js +9 -3
- package/report/renderer/performance-category-renderer.js +55 -34
- package/report/renderer/pwa-category-renderer.js +0 -10
- package/report/renderer/report-renderer.js +92 -44
- package/report/renderer/report-ui-features.js +36 -33
- package/report/renderer/swap-locale-feature.js +3 -3
- package/report/renderer/topbar-features.js +53 -48
- package/report/renderer/util.js +66 -46
- package/report/test/clients/bundle-test.js +70 -0
- package/report/test/renderer/category-renderer-test.js +76 -3
- package/report/test/renderer/i18n-test.js +0 -7
- package/report/test/renderer/performance-category-renderer-test.js +51 -14
- package/report/test/renderer/pwa-category-renderer-test.js +6 -6
- package/report/test/renderer/report-renderer-axe-test.js +11 -13
- package/report/test/renderer/report-renderer-test.js +52 -22
- package/report/test/renderer/report-ui-features-test.js +20 -10
- package/report/test/renderer/text-encoding-test.js +1 -1
- package/report/test/renderer/util-test.js +35 -31
- package/report/test-assets/faux-psi-template.html +3 -11
- package/report/test-assets/faux-psi.js +26 -22
- package/report/types/html-renderer.d.ts +2 -0
- package/report/types/report-renderer.d.ts +28 -0
- package/shared/localization/format.js +64 -30
- package/shared/localization/locales/ar-XB.json +72 -75
- package/shared/localization/locales/ar.json +72 -75
- package/shared/localization/locales/bg.json +72 -75
- package/shared/localization/locales/ca.json +72 -75
- package/shared/localization/locales/cs.json +89 -92
- package/shared/localization/locales/da.json +72 -75
- package/shared/localization/locales/de.json +89 -92
- package/shared/localization/locales/el.json +72 -75
- package/shared/localization/locales/en-GB.json +72 -75
- package/shared/localization/locales/en-US.json +78 -75
- package/shared/localization/locales/en-XA.json +72 -75
- package/shared/localization/locales/en-XL.json +78 -75
- package/shared/localization/locales/es-419.json +90 -93
- package/shared/localization/locales/es.json +90 -93
- package/shared/localization/locales/fi.json +72 -75
- package/shared/localization/locales/fil.json +72 -75
- package/shared/localization/locales/fr.json +89 -92
- package/shared/localization/locales/he.json +73 -76
- package/shared/localization/locales/hi.json +72 -75
- package/shared/localization/locales/hr.json +72 -75
- package/shared/localization/locales/hu.json +89 -92
- package/shared/localization/locales/id.json +89 -92
- package/shared/localization/locales/it.json +89 -92
- package/shared/localization/locales/ja.json +89 -92
- package/shared/localization/locales/ko.json +89 -92
- package/shared/localization/locales/lt.json +89 -92
- package/shared/localization/locales/lv.json +95 -98
- package/shared/localization/locales/nl.json +89 -92
- package/shared/localization/locales/no.json +72 -75
- package/shared/localization/locales/pl.json +72 -75
- package/shared/localization/locales/pt-PT.json +72 -75
- package/shared/localization/locales/pt.json +89 -92
- package/shared/localization/locales/ro.json +90 -93
- package/shared/localization/locales/ru.json +89 -92
- package/shared/localization/locales/sk.json +89 -92
- package/shared/localization/locales/sl.json +89 -92
- package/shared/localization/locales/sr-Latn.json +89 -92
- package/shared/localization/locales/sr.json +89 -92
- package/shared/localization/locales/sv.json +72 -75
- package/shared/localization/locales/ta.json +89 -92
- package/shared/localization/locales/te.json +89 -92
- package/shared/localization/locales/th.json +89 -92
- package/shared/localization/locales/tr.json +89 -92
- package/shared/localization/locales/uk.json +92 -95
- package/shared/localization/locales/vi.json +89 -92
- package/shared/localization/locales/zh-HK.json +89 -92
- package/shared/localization/locales/zh-TW.json +89 -92
- package/shared/localization/locales/zh.json +89 -92
- package/shared/localization/locales.js +6 -0
- package/shared/test/localization/format-test.js +45 -9
- package/shared/test/localization/swap-locale-test.js +0 -12
- package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +19 -11
- package/third-party/chromium-synchronization/installability-errors-test.js +3 -2
- package/third-party/download-content-shell/download-content-shell.js +2 -2
- package/third-party/download-content-shell/utils.js +0 -24
- package/third-party/snyk/snapshot.json +4 -1
- package/tsconfig-all.json +2 -2
- package/tsconfig.json +0 -1
- package/types/artifacts.d.ts +7 -7
- package/types/enquirer.d.ts +3 -1
- package/types/lhr/audit-details.d.ts +6 -5
- package/types/lhr/flow.d.ts +3 -2
- package/types/lhr/lhr.d.ts +1 -1
- package/types/node.d.ts +5 -5
- package/types/rollup-plugin-postprocess.d.ts +10 -0
- package/flow-report/src/wrappers/report-renderer.tsx +0 -46
- package/lighthouse-core/audits/dobetterweb/appcache-manifest.js +0 -67
- package/lighthouse-core/audits/dobetterweb/external-anchors-use-rel-noopener.js +0 -96
- package/lighthouse-core/audits/redirects-http.js +0 -59
- package/lighthouse-core/gather/gatherers/dobetterweb/appcache.js +0 -34
- package/lighthouse-core/gather/gatherers/http-redirect.js +0 -46
- package/lighthouse-core/lib/i18n/locales/en-US.ctc.json +0 -6699
- package/lighthouse-core/lib/i18n/locales/en-XL.ctc.json +0 -6672
- package/report/clients/psi.js +0 -158
- package/report/test/clients/psi-test.js +0 -143
- package/shared/localization/locales/en-US.ctc.json +0 -6877
- package/shared/localization/locales/en-XL.ctc.json +0 -6852
|
@@ -87,10 +87,37 @@ function createAxeRuleResultArtifact(result) {
|
|
|
87
87
|
// @ts-expect-error - getNodeDetails put into scope via stringification
|
|
88
88
|
const nodeDetails = getNodeDetails(/** @type {HTMLElement} */ (element));
|
|
89
89
|
|
|
90
|
+
/** @type {Set<HTMLElement>} */
|
|
91
|
+
const relatedNodeElements = new Set();
|
|
92
|
+
/** @param {import('axe-core/axe').ImpactValue} impact */
|
|
93
|
+
const impactToNumber =
|
|
94
|
+
(impact) => [null, 'minor', 'moderate', 'serious', 'critical'].indexOf(impact);
|
|
95
|
+
const checkResults = [...node.any, ...node.all, ...node.none]
|
|
96
|
+
// @ts-expect-error CheckResult.impact is a string, even though ImpactValue is a thing.
|
|
97
|
+
.sort((a, b) => impactToNumber(b.impact) - impactToNumber(a.impact));
|
|
98
|
+
for (const checkResult of checkResults) {
|
|
99
|
+
for (const relatedNode of checkResult.relatedNodes || []) {
|
|
100
|
+
/** @type {HTMLElement} */
|
|
101
|
+
// @ts-expect-error - should always exist, just being cautious.
|
|
102
|
+
const relatedElement = relatedNode.element;
|
|
103
|
+
|
|
104
|
+
// Prevent overloading the report with way too many nodes.
|
|
105
|
+
if (relatedNodeElements.size >= 3) break;
|
|
106
|
+
// Should always exist, just being cautious.
|
|
107
|
+
if (!relatedElement) continue;
|
|
108
|
+
if (element === relatedElement) continue;
|
|
109
|
+
|
|
110
|
+
relatedNodeElements.add(relatedElement);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// @ts-expect-error - getNodeDetails put into scope via stringification
|
|
114
|
+
const relatedNodeDetails = [...relatedNodeElements].map(getNodeDetails);
|
|
115
|
+
|
|
90
116
|
return {
|
|
91
117
|
target,
|
|
92
118
|
failureSummary,
|
|
93
119
|
node: nodeDetails,
|
|
120
|
+
relatedNodes: relatedNodeDetails,
|
|
94
121
|
};
|
|
95
122
|
});
|
|
96
123
|
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
const log = require('lighthouse-logger');
|
|
13
13
|
const FRGatherer = require('../../fraggle-rock/gather/base-gatherer.js');
|
|
14
14
|
const pageFunctions = require('../../lib/page-functions.js');
|
|
15
|
-
const URL = require('../../lib/url-shim.js');
|
|
16
15
|
const FontSize = require('./seo/font-size.js');
|
|
17
16
|
|
|
18
17
|
/* global window, getElementsInDocument, Image, getNodeDetails, ShadowRoot */
|
|
@@ -310,8 +309,6 @@ class ImageElements extends FRGatherer {
|
|
|
310
309
|
let skippedCount = 0;
|
|
311
310
|
|
|
312
311
|
for (const element of elements) {
|
|
313
|
-
element.mimeType = URL.guessMimeType(element.src);
|
|
314
|
-
|
|
315
312
|
if (reachedGatheringBudget) {
|
|
316
313
|
skippedCount++;
|
|
317
314
|
continue;
|
|
@@ -69,6 +69,8 @@ class InspectorIssues extends FRGatherer {
|
|
|
69
69
|
heavyAds: [],
|
|
70
70
|
/** @type {Array<LH.Crdp.Audits.ContentSecurityPolicyIssueDetails>} */
|
|
71
71
|
contentSecurityPolicy: [],
|
|
72
|
+
/** @type {Array<LH.Crdp.Audits.DeprecationIssueDetails>} */
|
|
73
|
+
deprecations: [],
|
|
72
74
|
};
|
|
73
75
|
|
|
74
76
|
for (const issue of this._issues) {
|
|
@@ -105,6 +107,9 @@ class InspectorIssues extends FRGatherer {
|
|
|
105
107
|
if (issue.details.contentSecurityPolicyIssueDetails) {
|
|
106
108
|
artifact.contentSecurityPolicy.push(issue.details.contentSecurityPolicyIssueDetails);
|
|
107
109
|
}
|
|
110
|
+
if (issue.details.deprecationIssueDetails) {
|
|
111
|
+
artifact.deprecations.push(issue.details.deprecationIssueDetails);
|
|
112
|
+
}
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
return artifact;
|
|
@@ -16,7 +16,10 @@ const Metrics = require('./traces/pwmetrics-events.js');
|
|
|
16
16
|
const NetworkAnalysisComputed = require('../computed/network-analysis.js');
|
|
17
17
|
const LoadSimulatorComputed = require('../computed/load-simulator.js');
|
|
18
18
|
const LHError = require('../lib/lh-error.js');
|
|
19
|
-
|
|
19
|
+
// TODO(esmodules): Rollup does not support `promisfy` or `stream.pipeline`. Bundled files
|
|
20
|
+
// don't need anything in this file except for `stringifyReplacer`, so a check for
|
|
21
|
+
// truthiness before using is enough.
|
|
22
|
+
const pipeline = promisify && promisify(stream.pipeline);
|
|
20
23
|
|
|
21
24
|
const artifactsFilename = 'artifacts.json';
|
|
22
25
|
const traceSuffix = '.trace.json';
|
|
@@ -235,9 +238,9 @@ async function saveTrace(traceData, traceFilename) {
|
|
|
235
238
|
const traceIter = traceJsonGenerator(traceData);
|
|
236
239
|
const writeStream = fs.createWriteStream(traceFilename);
|
|
237
240
|
|
|
238
|
-
// TODO: Can remove
|
|
241
|
+
// TODO: Can remove promisify(pipeline) in Node 15.
|
|
239
242
|
// https://nodejs.org/api/stream.html#stream_stream_pipeline_streams_callback
|
|
240
|
-
return pipeline(
|
|
243
|
+
return pipeline(traceIter, writeStream);
|
|
241
244
|
}
|
|
242
245
|
|
|
243
246
|
/**
|
|
@@ -250,7 +253,7 @@ function saveDevtoolsLog(devtoolsLog, devtoolLogFilename) {
|
|
|
250
253
|
const logIter = arrayOfObjectsJsonGenerator(devtoolsLog);
|
|
251
254
|
const writeStream = fs.createWriteStream(devtoolLogFilename);
|
|
252
255
|
|
|
253
|
-
return pipeline(
|
|
256
|
+
return pipeline(logIter, writeStream);
|
|
254
257
|
}
|
|
255
258
|
|
|
256
259
|
/**
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
+
const {version: lighthouseVersion} = require('../../package.json');
|
|
9
|
+
|
|
8
10
|
const NO_THROTTLING_METRICS = {
|
|
9
11
|
latency: 0,
|
|
10
12
|
downloadThroughput: 0,
|
|
@@ -16,6 +18,46 @@ const NO_CPU_THROTTLE_METRICS = {
|
|
|
16
18
|
rate: 1,
|
|
17
19
|
};
|
|
18
20
|
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} userAgent
|
|
23
|
+
* @param {LH.Config.Settings['formFactor']} formFactor
|
|
24
|
+
* @return {LH.Crdp.Emulation.SetUserAgentOverrideRequest['userAgentMetadata']}
|
|
25
|
+
*/
|
|
26
|
+
function parseUseragentIntoMetadata(userAgent, formFactor) {
|
|
27
|
+
const match = userAgent.match(/Chrome\/([\d.]+)/); // eg 'Chrome/(71.0.3577.0)'
|
|
28
|
+
const fullVersion = (match && match[1]) || '99.0.1234.0';
|
|
29
|
+
const [version] = fullVersion.split('.', 1);
|
|
30
|
+
const brands = [
|
|
31
|
+
{brand: 'Chromium', version},
|
|
32
|
+
{brand: 'Google Chrome', version},
|
|
33
|
+
{brand: 'Lighthouse', version: lighthouseVersion},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const motoG4Details = {
|
|
37
|
+
platform: 'Android',
|
|
38
|
+
platformVersion: '6.0',
|
|
39
|
+
architecture: '',
|
|
40
|
+
model: 'Moto G4',
|
|
41
|
+
};
|
|
42
|
+
const macDesktopDetails = {
|
|
43
|
+
platform: 'macOS',
|
|
44
|
+
platformVersion: '10.15.7',
|
|
45
|
+
architecture: 'x86',
|
|
46
|
+
model: '',
|
|
47
|
+
};
|
|
48
|
+
const mobile = formFactor === 'mobile';
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
brands,
|
|
52
|
+
fullVersion,
|
|
53
|
+
// Since config users can supply a custom useragent, they likely are emulating something
|
|
54
|
+
// other than Moto G4 and MacOS Desktop.
|
|
55
|
+
// TODO: Determine how to thoughtfully expose this metadata/client-hints configurability.
|
|
56
|
+
...(mobile ? motoG4Details : macDesktopDetails),
|
|
57
|
+
mobile,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
19
61
|
/**
|
|
20
62
|
* @param {LH.Gatherer.FRProtocolSession} session
|
|
21
63
|
* @param {LH.Config.Settings} settings
|
|
@@ -23,8 +65,10 @@ const NO_CPU_THROTTLE_METRICS = {
|
|
|
23
65
|
*/
|
|
24
66
|
async function emulate(session, settings) {
|
|
25
67
|
if (settings.emulatedUserAgent !== false) {
|
|
68
|
+
const userAgent = /** @type {string} */ (settings.emulatedUserAgent);
|
|
26
69
|
await session.sendCommand('Network.setUserAgentOverride', {
|
|
27
|
-
userAgent
|
|
70
|
+
userAgent,
|
|
71
|
+
userAgentMetadata: parseUseragentIntoMetadata(userAgent, settings.formFactor),
|
|
28
72
|
});
|
|
29
73
|
}
|
|
30
74
|
// See devtools-entry for one usecase for disabling screenEmulation
|
|
@@ -12,9 +12,11 @@ const lookupClosestLocale = require('lookup-closest-locale');
|
|
|
12
12
|
const {getAvailableLocales} = require('../../../shared/localization/format.js');
|
|
13
13
|
const log = require('lighthouse-logger');
|
|
14
14
|
const {LH_ROOT} = require('../../../root.js');
|
|
15
|
-
const {
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const {
|
|
16
|
+
isIcuMessage,
|
|
17
|
+
formatMessage,
|
|
18
|
+
DEFAULT_LOCALE,
|
|
19
|
+
} = require('../../../shared/localization/format.js');
|
|
18
20
|
|
|
19
21
|
const UIStrings = {
|
|
20
22
|
/** 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) */
|
|
@@ -118,23 +120,32 @@ const UIStrings = {
|
|
|
118
120
|
* - supported locales in Intl formatters
|
|
119
121
|
*
|
|
120
122
|
* If `locale` isn't provided or one could not be found, DEFAULT_LOCALE is returned.
|
|
123
|
+
*
|
|
124
|
+
* By default any of the locales Lighthouse has strings for can be returned, but this
|
|
125
|
+
* can be overriden with `possibleLocales`, useful e.g. when Lighthouse is bundled and
|
|
126
|
+
* only DEFAULT_LOCALE is available, but `possibleLocales` can be used to select a
|
|
127
|
+
* locale available to be downloaded on demand.
|
|
121
128
|
* @param {string|string[]=} locales
|
|
129
|
+
* @param {Array<string>=} possibleLocales
|
|
122
130
|
* @return {LH.Locale}
|
|
123
131
|
*/
|
|
124
|
-
function lookupLocale(locales) {
|
|
125
|
-
//
|
|
132
|
+
function lookupLocale(locales, possibleLocales) {
|
|
133
|
+
// TODO: lookupLocale may need to be split into two functions, one that canonicalizes
|
|
134
|
+
// locales and one that looks up the best locale filename for a given locale.
|
|
135
|
+
// e.g. `en-IE` is canonical, but uses `en-GB.json`. See TODO in locales.js
|
|
136
|
+
|
|
126
137
|
if (typeof Intl !== 'object') {
|
|
138
|
+
// If Node was built with `--with-intl=none`, `Intl` won't exist.
|
|
127
139
|
throw new Error('Lighthouse must be run in Node with `Intl` support. See https://nodejs.org/api/intl.html for help');
|
|
128
140
|
}
|
|
129
141
|
|
|
130
|
-
// TODO: could do more work to sniff out the user's locale
|
|
131
142
|
const canonicalLocales = Intl.getCanonicalLocales(locales);
|
|
132
143
|
|
|
133
144
|
// Filter by what's available in this runtime.
|
|
134
145
|
const availableLocales = Intl.NumberFormat.supportedLocalesOf(canonicalLocales);
|
|
135
146
|
|
|
136
147
|
// Get available locales and transform into object to match `lookupClosestLocale`'s API.
|
|
137
|
-
const localesWithMessages = getAvailableLocales();
|
|
148
|
+
const localesWithMessages = possibleLocales || getAvailableLocales();
|
|
138
149
|
const localesWithmessagesObj = /** @type {Record<LH.Locale, LhlMessages>} */ (
|
|
139
150
|
Object.fromEntries(localesWithMessages.map(l => [l, {}])));
|
|
140
151
|
|
|
@@ -182,7 +193,7 @@ function createIcuMessageFn(filename, fileStrings) {
|
|
|
182
193
|
return {
|
|
183
194
|
i18nId,
|
|
184
195
|
values,
|
|
185
|
-
formattedDefault:
|
|
196
|
+
formattedDefault: formatMessage(message, values, DEFAULT_LOCALE),
|
|
186
197
|
};
|
|
187
198
|
};
|
|
188
199
|
|
|
@@ -208,7 +208,8 @@ function computeBenchmarkIndex() {
|
|
|
208
208
|
|
|
209
209
|
while (Date.now() - start < 500) {
|
|
210
210
|
let s = '';
|
|
211
|
-
for (let j = 0; j < 10000; j++) s += 'a';
|
|
211
|
+
for (let j = 0; j < 10000; j++) s += 'a';
|
|
212
|
+
if (s.length === 1) throw new Error('will never happen, but prevents compiler optimizations');
|
|
212
213
|
|
|
213
214
|
iterations++;
|
|
214
215
|
}
|
|
@@ -29,10 +29,22 @@ function processForProto(lhr) {
|
|
|
29
29
|
// 'ignore unknown fields' in the language of conversion.
|
|
30
30
|
if (reportJson.configSettings) {
|
|
31
31
|
// The settings that are in both proto and LHR
|
|
32
|
-
const {
|
|
32
|
+
const {
|
|
33
|
+
formFactor,
|
|
34
|
+
locale,
|
|
35
|
+
onlyCategories,
|
|
36
|
+
channel,
|
|
37
|
+
throttling,
|
|
38
|
+
throttlingMethod} = reportJson.configSettings;
|
|
33
39
|
|
|
34
40
|
// @ts-expect-error - intentionally only a subset of settings.
|
|
35
|
-
reportJson.configSettings = {
|
|
41
|
+
reportJson.configSettings = {
|
|
42
|
+
formFactor,
|
|
43
|
+
locale,
|
|
44
|
+
onlyCategories,
|
|
45
|
+
channel,
|
|
46
|
+
throttling,
|
|
47
|
+
throttlingMethod};
|
|
36
48
|
}
|
|
37
49
|
|
|
38
50
|
// Remove runtimeError if it is NO_ERROR
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
+
// The exact double values for the max and min scores possible in each range.
|
|
9
|
+
const MIN_PASSING_SCORE = 0.90000000000000002220446049250313080847263336181640625;
|
|
10
|
+
const MAX_AVERAGE_SCORE = 0.899999999999999911182158029987476766109466552734375;
|
|
11
|
+
const MIN_AVERAGE_SCORE = 0.5;
|
|
12
|
+
const MAX_FAILING_SCORE = 0.499999999999999944488848768742172978818416595458984375;
|
|
13
|
+
|
|
8
14
|
/**
|
|
9
15
|
* Approximates the Gauss error function, the probability that a random variable
|
|
10
16
|
* from the standard normal distribution lies within [-x, x]. Moved from
|
|
@@ -28,37 +34,6 @@ function erf(x) {
|
|
|
28
34
|
return sign * (1 - y * Math.exp(-x * x));
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
/**
|
|
32
|
-
* Creates a log-normal distribution à la traceviewer's statistics package.
|
|
33
|
-
* Specified by providing the median value, at which the score will be 0.5,
|
|
34
|
-
* and the falloff, the initial point of diminishing returns where any
|
|
35
|
-
* improvement in value will yield increasingly smaller gains in score. Both
|
|
36
|
-
* values should be in the same units (e.g. milliseconds). See
|
|
37
|
-
* https://www.desmos.com/calculator/tx1wcjk8ch
|
|
38
|
-
* for an interactive view of the relationship between these parameters and
|
|
39
|
-
* the typical parameterization (location and shape) of the log-normal
|
|
40
|
-
* distribution.
|
|
41
|
-
* @param {number} median
|
|
42
|
-
* @param {number} falloff
|
|
43
|
-
* @return {{computeComplementaryPercentile: function(number): number}}
|
|
44
|
-
*/
|
|
45
|
-
function getLogNormalDistribution(median, falloff) {
|
|
46
|
-
const location = Math.log(median);
|
|
47
|
-
|
|
48
|
-
// The "falloff" value specified the location of the smaller of the positive
|
|
49
|
-
// roots of the third derivative of the log-normal CDF. Calculate the shape
|
|
50
|
-
// parameter in terms of that value and the median.
|
|
51
|
-
const logRatio = Math.log(falloff / median);
|
|
52
|
-
const shape = Math.sqrt(1 - 3 * logRatio - Math.sqrt((logRatio - 3) * (logRatio - 3) - 8)) / 2;
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
computeComplementaryPercentile(x) {
|
|
56
|
-
const standardizedX = (Math.log(x) - location) / (Math.SQRT2 * shape);
|
|
57
|
-
return (1 - erf(standardizedX)) / 2;
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
37
|
/**
|
|
63
38
|
* Returns the score (1 - percentile) of `value` in a log-normal distribution
|
|
64
39
|
* specified by the `median` value, at which the score will be 0.5, and a 10th
|
|
@@ -76,24 +51,37 @@ function getLogNormalScore({median, p10}, value) {
|
|
|
76
51
|
// Required for the log-normal distribution.
|
|
77
52
|
if (median <= 0) throw new Error('median must be greater than zero');
|
|
78
53
|
if (p10 <= 0) throw new Error('p10 must be greater than zero');
|
|
79
|
-
// Not required, but if p10 > median, it flips around and becomes the p90 point.
|
|
54
|
+
// Not strictly required, but if p10 > median, it flips around and becomes the p90 point.
|
|
80
55
|
if (p10 >= median) throw new Error('p10 must be less than the median');
|
|
81
56
|
|
|
82
57
|
// Non-positive values aren't in the distribution, so always 1.
|
|
83
58
|
if (value <= 0) return 1;
|
|
84
59
|
|
|
85
|
-
// Closest double to `erfc-1(
|
|
60
|
+
// Closest double to `erfc-1(1/5)`.
|
|
86
61
|
const INVERSE_ERFC_ONE_FIFTH = 0.9061938024368232;
|
|
87
62
|
|
|
88
|
-
// Shape (σ) is
|
|
63
|
+
// Shape (σ) is `|log(p10/median) / (sqrt(2)*erfc^-1(1/5))|` and
|
|
89
64
|
// standardizedX is `1/2 erfc(log(value/median) / (sqrt(2)*σ))`, so simplify a bit.
|
|
90
|
-
const
|
|
91
|
-
const
|
|
65
|
+
const xRatio = Math.max(Number.MIN_VALUE, value / median); // value and median are > 0, so is ratio.
|
|
66
|
+
const xLogRatio = Math.log(xRatio);
|
|
67
|
+
const p10Ratio = Math.max(Number.MIN_VALUE, p10 / median); // p10 and median are > 0, so is ratio.
|
|
68
|
+
const p10LogRatio = -Math.log(p10Ratio); // negate to keep σ positive.
|
|
92
69
|
const standardizedX = xLogRatio * INVERSE_ERFC_ONE_FIFTH / p10LogRatio;
|
|
93
70
|
const complementaryPercentile = (1 - erf(standardizedX)) / 2;
|
|
94
71
|
|
|
95
|
-
// Clamp to
|
|
96
|
-
|
|
72
|
+
// Clamp to avoid floating-point out-of-bounds issues and keep score in expected range.
|
|
73
|
+
let score;
|
|
74
|
+
if (value <= p10) {
|
|
75
|
+
// Passing. Clamp to [0.9, 1].
|
|
76
|
+
score = Math.max(MIN_PASSING_SCORE, Math.min(1, complementaryPercentile));
|
|
77
|
+
} else if (value <= median) {
|
|
78
|
+
// Average. Clamp to [0.5, 0.9).
|
|
79
|
+
score = Math.max(MIN_AVERAGE_SCORE, Math.min(MAX_AVERAGE_SCORE, complementaryPercentile));
|
|
80
|
+
} else {
|
|
81
|
+
// Failing. Clamp to [0, 0.5).
|
|
82
|
+
score = Math.max(0, Math.min(MAX_FAILING_SCORE, complementaryPercentile));
|
|
83
|
+
}
|
|
84
|
+
return score;
|
|
97
85
|
}
|
|
98
86
|
|
|
99
87
|
/**
|
|
@@ -112,6 +100,5 @@ function linearInterpolation(x0, y0, x1, y1, x) {
|
|
|
112
100
|
|
|
113
101
|
module.exports = {
|
|
114
102
|
linearInterpolation,
|
|
115
|
-
getLogNormalDistribution,
|
|
116
103
|
getLogNormalScore,
|
|
117
104
|
};
|
|
@@ -5,14 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
filterOutRectsContainedByOthers,
|
|
10
|
-
filterOutTinyRects,
|
|
11
|
-
rectsTouchOrOverlap,
|
|
12
|
-
rectContainsPoint,
|
|
13
|
-
getBoundingRect,
|
|
14
|
-
getRectCenterPoint,
|
|
15
|
-
} = require('./rect-helpers.js');
|
|
8
|
+
const RectHelpers = require('./rect-helpers.js');
|
|
16
9
|
|
|
17
10
|
/**
|
|
18
11
|
* Merge client rects together and remove small ones. This may result in a larger overall
|
|
@@ -23,8 +16,8 @@ const {
|
|
|
23
16
|
function getTappableRectsFromClientRects(clientRects) {
|
|
24
17
|
// 1x1px rect shouldn't be reason to treat the rect as something the user should tap on.
|
|
25
18
|
// Often they're made invisble in some obscure way anyway, and only exist for e.g. accessibiliity.
|
|
26
|
-
clientRects = filterOutTinyRects(clientRects);
|
|
27
|
-
clientRects = filterOutRectsContainedByOthers(clientRects);
|
|
19
|
+
clientRects = RectHelpers.filterOutTinyRects(clientRects);
|
|
20
|
+
clientRects = RectHelpers.filterOutRectsContainedByOthers(clientRects);
|
|
28
21
|
clientRects = mergeTouchingClientRects(clientRects);
|
|
29
22
|
return clientRects;
|
|
30
23
|
}
|
|
@@ -68,17 +61,17 @@ function mergeTouchingClientRects(clientRects) {
|
|
|
68
61
|
const rectsLineUpVertically =
|
|
69
62
|
almostEqual(crA.left, crB.left) || almostEqual(crA.right, crB.right);
|
|
70
63
|
const canMerge =
|
|
71
|
-
rectsTouchOrOverlap(crA, crB) &&
|
|
64
|
+
RectHelpers.rectsTouchOrOverlap(crA, crB) &&
|
|
72
65
|
(rectsLineUpHorizontally || rectsLineUpVertically);
|
|
73
66
|
|
|
74
67
|
if (canMerge) {
|
|
75
|
-
const replacementClientRect = getBoundingRect([crA, crB]);
|
|
76
|
-
const mergedRectCenter = getRectCenterPoint(replacementClientRect);
|
|
68
|
+
const replacementClientRect = RectHelpers.getBoundingRect([crA, crB]);
|
|
69
|
+
const mergedRectCenter = RectHelpers.getRectCenterPoint(replacementClientRect);
|
|
77
70
|
|
|
78
71
|
if (
|
|
79
72
|
!(
|
|
80
|
-
rectContainsPoint(crA, mergedRectCenter) ||
|
|
81
|
-
rectContainsPoint(crB, mergedRectCenter)
|
|
73
|
+
RectHelpers.rectContainsPoint(crA, mergedRectCenter) ||
|
|
74
|
+
RectHelpers.rectContainsPoint(crB, mergedRectCenter)
|
|
82
75
|
)
|
|
83
76
|
) {
|
|
84
77
|
// Don't merge because the new shape is too different from the
|
|
@@ -20,6 +20,7 @@ const URL = require('./lib/url-shim.js');
|
|
|
20
20
|
const Sentry = require('./lib/sentry.js');
|
|
21
21
|
const generateReport = require('../report/generator/report-generator.js').generateReport;
|
|
22
22
|
const LHError = require('./lib/lh-error.js');
|
|
23
|
+
const {version: lighthouseVersion} = require('../package.json');
|
|
23
24
|
|
|
24
25
|
/** @typedef {import('./gather/connections/connection.js')} Connection */
|
|
25
26
|
/** @typedef {import('./lib/arbitrary-equality-map.js')} ArbitraryEqualityMap */
|
|
@@ -112,7 +113,6 @@ class Runner {
|
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
// Entering: conclusion of the lighthouse result object
|
|
115
|
-
const lighthouseVersion = require('../package.json').version;
|
|
116
116
|
|
|
117
117
|
// Use version from gathering stage.
|
|
118
118
|
// If accessibility gatherer didn't run or errored, it won't be in credits.
|