lighthouse 13.5.0-dev.20261014 → 13.5.0-dev.20261016
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/cli/test/smokehouse/version-check.d.ts +1 -1
- package/core/audits/baseline.d.ts +3 -1
- package/core/audits/baseline.js +4 -3
- package/core/audits/insights/insight-audit.js +31 -26
- package/core/config/config-helpers.js +1 -2
- package/core/gather/base-artifacts.js +1 -1
- package/core/gather/driver/storage.js +3 -2
- package/core/lib/arbitrary-equality-map.d.ts +14 -3
- package/core/lib/arbitrary-equality-map.js +73 -6
- package/core/runner.js +1 -1
- package/package.json +5 -9
- package/shared/localization/swap-locale.js +10 -5
|
@@ -11,5 +11,5 @@ export function chromiumVersionCheck(opts: {
|
|
|
11
11
|
* @param {number[]} versionA
|
|
12
12
|
* @param {number[]} versionB
|
|
13
13
|
*/
|
|
14
|
-
export function compareVersions(versionA: number[], versionB: number[]):
|
|
14
|
+
export function compareVersions(versionA: number[], versionB: number[]): 0 | 1 | -1;
|
|
15
15
|
//# sourceMappingURL=version-check.d.ts.map
|
|
@@ -796,8 +796,10 @@ declare class Baseline extends Audit {
|
|
|
796
796
|
* - `high`: `baseline === 'high'` (Widely Available — 30 months past `baseline_low_date`; note that
|
|
797
797
|
* `featureData.high[id]` still stores the feature's `baseline_low_date`).
|
|
798
798
|
*
|
|
799
|
+
* Widely Available rows always show `baseline_low_date`, including rows promoted at runtime.
|
|
799
800
|
* If a feature in `featureData.low` has reached `baseline_low_date + 30 months <= currentDate` at runtime,
|
|
800
|
-
* we dynamically promote it from `low` (Newly Available) to `high` (Widely Available)
|
|
801
|
+
* we dynamically promote it from `low` (Newly Available) to `high` (Widely Available); promotion
|
|
802
|
+
* only changes the tier.
|
|
801
803
|
*
|
|
802
804
|
* @param {string} featureId
|
|
803
805
|
* @param {{high: Record<string, string>, low: Record<string, string>, limited: string[]}} featureData
|
package/core/audits/baseline.js
CHANGED
|
@@ -55,8 +55,10 @@ class Baseline extends Audit {
|
|
|
55
55
|
* - `high`: `baseline === 'high'` (Widely Available — 30 months past `baseline_low_date`; note that
|
|
56
56
|
* `featureData.high[id]` still stores the feature's `baseline_low_date`).
|
|
57
57
|
*
|
|
58
|
+
* Widely Available rows always show `baseline_low_date`, including rows promoted at runtime.
|
|
58
59
|
* If a feature in `featureData.low` has reached `baseline_low_date + 30 months <= currentDate` at runtime,
|
|
59
|
-
* we dynamically promote it from `low` (Newly Available) to `high` (Widely Available)
|
|
60
|
+
* we dynamically promote it from `low` (Newly Available) to `high` (Widely Available); promotion
|
|
61
|
+
* only changes the tier.
|
|
60
62
|
*
|
|
61
63
|
* @param {string} featureId
|
|
62
64
|
* @param {{high: Record<string, string>, low: Record<string, string>, limited: string[]}} featureData
|
|
@@ -76,11 +78,10 @@ class Baseline extends Audit {
|
|
|
76
78
|
const lowData = /** @type {Record<string, string>} */ (featureData.low);
|
|
77
79
|
const widelyAvailableDate = new Date(lowData[featureId]);
|
|
78
80
|
widelyAvailableDate.setUTCMonth(widelyAvailableDate.getUTCMonth() + 30);
|
|
79
|
-
const widelyAvailableDateStr = widelyAvailableDate.toISOString().slice(0, 10);
|
|
80
81
|
|
|
81
82
|
if (widelyAvailableDate <= currentDate) {
|
|
82
83
|
return {
|
|
83
|
-
displayStatus: `Widely Available (${
|
|
84
|
+
displayStatus: `Widely Available (${lowData[featureId]})`,
|
|
84
85
|
baselineTier: 'high',
|
|
85
86
|
};
|
|
86
87
|
} else {
|
|
@@ -136,36 +136,41 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
|
|
|
136
136
|
// TODO: consider adding a `estimatedSavingsText` to InsightModel, which can capture
|
|
137
137
|
// the exact i18n string used by RPP; and include the same est. timing savings.
|
|
138
138
|
let displayValue;
|
|
139
|
+
let wastedMs;
|
|
140
|
+
|
|
141
|
+
switch (insight.insightKey) {
|
|
142
|
+
case 'DocumentLatency':
|
|
143
|
+
case 'FontDisplay':
|
|
144
|
+
case 'RenderBlocking': {
|
|
145
|
+
wastedMs = metricSavings?.FCP ?? 0;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
139
148
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
switch (insight.insightKey) {
|
|
146
|
-
case 'DocumentLatency':
|
|
147
|
-
case 'DuplicatedJavaScript':
|
|
148
|
-
case 'FontDisplay':
|
|
149
|
-
case 'LegacyJavaScript':
|
|
150
|
-
case 'RenderBlocking': {
|
|
151
|
-
wastedMs = metricSavings?.FCP;
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
case 'LCPDiscovery':
|
|
156
|
-
case 'ModernHTTP': {
|
|
157
|
-
wastedMs = metricSavings?.LCP;
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
149
|
+
case 'LCPDiscovery':
|
|
150
|
+
case 'ModernHTTP': {
|
|
151
|
+
wastedMs = metricSavings?.LCP ?? 0;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
160
154
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
155
|
+
case 'Viewport': {
|
|
156
|
+
wastedMs = metricSavings?.INP ?? 0;
|
|
157
|
+
break;
|
|
165
158
|
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (insight.wastedBytes) {
|
|
162
|
+
displayValue = str_(i18n.UIStrings.displayValueByteSavings, {wastedBytes: insight.wastedBytes});
|
|
163
|
+
} else if (wastedMs) {
|
|
164
|
+
displayValue = str_(i18n.UIStrings.displayValueMsSavings, {wastedMs});
|
|
165
|
+
}
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
if (numericValue === undefined) {
|
|
168
|
+
if (wastedMs !== undefined) {
|
|
169
|
+
numericValue = wastedMs;
|
|
170
|
+
numericUnit = 'millisecond';
|
|
171
|
+
} else if (insight.wastedBytes !== undefined) {
|
|
172
|
+
numericValue = insight.wastedBytes;
|
|
173
|
+
numericUnit = 'byte';
|
|
169
174
|
}
|
|
170
175
|
}
|
|
171
176
|
|
|
@@ -7,8 +7,6 @@ import path from 'path';
|
|
|
7
7
|
import {createRequire} from 'module';
|
|
8
8
|
import url from 'url';
|
|
9
9
|
|
|
10
|
-
import {isEqual} from 'lodash-es';
|
|
11
|
-
|
|
12
10
|
import * as LH from '../../types/lh.js';
|
|
13
11
|
import * as constants from './constants.js';
|
|
14
12
|
import ConfigPlugin from './config-plugin.js';
|
|
@@ -16,6 +14,7 @@ import {Runner} from '../runner.js';
|
|
|
16
14
|
import * as i18n from '../lib/i18n/i18n.js';
|
|
17
15
|
import * as validation from './validation.js';
|
|
18
16
|
import {getModuleDirectory} from '../../shared/esm-utils.js';
|
|
17
|
+
import {isEqual} from '../lib/arbitrary-equality-map.js';
|
|
19
18
|
|
|
20
19
|
const require = createRequire(import.meta.url);
|
|
21
20
|
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import log from 'lighthouse-logger';
|
|
8
|
-
import {isEqual} from 'lodash-es';
|
|
9
8
|
|
|
10
9
|
import {
|
|
11
10
|
getBrowserVersion, getBenchmarkIndex, getEnvironmentWarnings,
|
|
12
11
|
getDevicePixelRatio,
|
|
13
12
|
} from './driver/environment.js';
|
|
13
|
+
import {isEqual} from '../lib/arbitrary-equality-map.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* @param {LH.Config.ResolvedConfig} resolvedConfig
|
|
@@ -41,13 +41,14 @@ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
|
41
41
|
* @return {Promise<LH.IcuMessage[]>}
|
|
42
42
|
*/
|
|
43
43
|
async function clearDataForOrigin(session, url, clearStorageTypes) {
|
|
44
|
+
const origin = new URL(url).origin;
|
|
45
|
+
if (origin === 'null') return [];
|
|
46
|
+
|
|
44
47
|
const status = {msg: 'Cleaning origin data', id: 'lh:storage:clearDataForOrigin'};
|
|
45
48
|
log.time(status);
|
|
46
49
|
|
|
47
50
|
const warnings = [];
|
|
48
51
|
|
|
49
|
-
const origin = new URL(url).origin;
|
|
50
|
-
|
|
51
52
|
const typesToClear = clearStorageTypes.join(',');
|
|
52
53
|
|
|
53
54
|
// `Storage.clearDataForOrigin` is one of our PROTOCOL_TIMEOUT culprits and this command is also
|
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export class ArbitraryEqualityMap {
|
|
7
7
|
/**
|
|
8
|
-
* Determines whether two objects are deeply equal.
|
|
9
|
-
* easy usage by consumers.
|
|
10
|
-
* See https://lodash.com/docs/4.17.5#isEqual.
|
|
8
|
+
* Determines whether two objects are deeply equal.
|
|
11
9
|
* @param {*} objA
|
|
12
10
|
* @param {*} objB
|
|
13
11
|
* @return {boolean}
|
|
@@ -44,4 +42,17 @@ export class ArbitraryEqualityMap {
|
|
|
44
42
|
*/
|
|
45
43
|
_findIndexOf(key: any): number;
|
|
46
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* @license
|
|
47
|
+
* Copyright 2018 Google LLC
|
|
48
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* @param {*} a
|
|
52
|
+
* @param {*} b
|
|
53
|
+
* @param {WeakMap<object, object>=} seen
|
|
54
|
+
* @return {boolean}
|
|
55
|
+
*/
|
|
56
|
+
declare function deepEquals(a: any, b: any, seen?: WeakMap<object, object> | undefined): boolean;
|
|
57
|
+
export { deepEquals as isEqual };
|
|
47
58
|
//# sourceMappingURL=arbitrary-equality-map.d.ts.map
|
|
@@ -4,7 +4,76 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @param {*} a
|
|
9
|
+
* @param {*} b
|
|
10
|
+
* @param {WeakMap<object, object>=} seen
|
|
11
|
+
* @return {boolean}
|
|
12
|
+
*/
|
|
13
|
+
function deepEquals(a, b, seen) {
|
|
14
|
+
if (a === b || (Number.isNaN(a) && Number.isNaN(b))) return true;
|
|
15
|
+
if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (a.constructor !== b.constructor) return false;
|
|
19
|
+
|
|
20
|
+
if (a instanceof Date && b instanceof Date) {
|
|
21
|
+
return a.getTime() === b.getTime() || (Number.isNaN(a.getTime()) && Number.isNaN(b.getTime()));
|
|
22
|
+
}
|
|
23
|
+
if (a instanceof RegExp && b instanceof RegExp) {
|
|
24
|
+
return a.source === b.source && a.flags === b.flags;
|
|
25
|
+
}
|
|
26
|
+
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
27
|
+
if (a.byteLength !== b.byteLength) return false;
|
|
28
|
+
const viewA = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
|
|
29
|
+
const viewB = new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
|
|
30
|
+
for (let i = 0; i < viewA.length; i++) {
|
|
31
|
+
if (viewA[i] !== viewB[i]) return false;
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (seen) {
|
|
37
|
+
if (seen.get(a) === b) return true;
|
|
38
|
+
} else {
|
|
39
|
+
seen = new WeakMap();
|
|
40
|
+
}
|
|
41
|
+
seen.set(a, b);
|
|
42
|
+
|
|
43
|
+
if (Array.isArray(a)) {
|
|
44
|
+
const arrB = /** @type {unknown[]} */ (b);
|
|
45
|
+
if (a.length !== arrB.length) return false;
|
|
46
|
+
for (let i = 0; i < a.length; i++) {
|
|
47
|
+
if (!deepEquals(a[i], arrB[i], seen)) return false;
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (a instanceof Map && b instanceof Map) {
|
|
53
|
+
if (a.size !== b.size) return false;
|
|
54
|
+
for (const [k, v] of a) {
|
|
55
|
+
if (!b.has(k) || !deepEquals(v, b.get(k), seen)) return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (a instanceof Set && b instanceof Set) {
|
|
61
|
+
if (a.size !== b.size) return false;
|
|
62
|
+
for (const v of a) {
|
|
63
|
+
if (!b.has(v)) return false;
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const keysA = Object.keys(a);
|
|
69
|
+
const keysB = Object.keys(b);
|
|
70
|
+
if (keysA.length !== keysB.length) return false;
|
|
71
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
72
|
+
const key = keysA[i];
|
|
73
|
+
if (!Object.hasOwn(b, key) || !deepEquals(a[key], b[key], seen)) return false;
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
8
77
|
|
|
9
78
|
/**
|
|
10
79
|
* @fileoverview This class is designed to allow maps with arbitrary equality functions.
|
|
@@ -65,16 +134,14 @@ class ArbitraryEqualityMap {
|
|
|
65
134
|
}
|
|
66
135
|
|
|
67
136
|
/**
|
|
68
|
-
* Determines whether two objects are deeply equal.
|
|
69
|
-
* easy usage by consumers.
|
|
70
|
-
* See https://lodash.com/docs/4.17.5#isEqual.
|
|
137
|
+
* Determines whether two objects are deeply equal.
|
|
71
138
|
* @param {*} objA
|
|
72
139
|
* @param {*} objB
|
|
73
140
|
* @return {boolean}
|
|
74
141
|
*/
|
|
75
142
|
static deepEquals(objA, objB) {
|
|
76
|
-
return
|
|
143
|
+
return deepEquals(objA, objB);
|
|
77
144
|
}
|
|
78
145
|
}
|
|
79
146
|
|
|
80
|
-
export {ArbitraryEqualityMap};
|
|
147
|
+
export {ArbitraryEqualityMap, deepEquals as isEqual};
|
package/core/runner.js
CHANGED
|
@@ -9,7 +9,6 @@ import path from 'path';
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
import log from 'lighthouse-logger';
|
|
12
|
-
import {isEqual} from 'lodash-es';
|
|
13
12
|
|
|
14
13
|
import {ReportScoring} from './scoring.js';
|
|
15
14
|
import {Audit} from './audits/audit.js';
|
|
@@ -24,6 +23,7 @@ import {getModuleDirectory} from '../shared/esm-utils.js';
|
|
|
24
23
|
import {EntityClassification} from './computed/entity-classification.js';
|
|
25
24
|
import UrlUtils from './lib/url-utils.js';
|
|
26
25
|
import {Util} from '../shared/util.js';
|
|
26
|
+
import {isEqual} from './lib/arbitrary-equality-map.js';
|
|
27
27
|
|
|
28
28
|
const moduleDir = getModuleDirectory(import.meta);
|
|
29
29
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lighthouse",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "13.5.0-dev.
|
|
4
|
+
"version": "13.5.0-dev.20261016",
|
|
5
5
|
"description": "Automated auditing, performance metrics, and best practices for the web.",
|
|
6
6
|
"main": "./core/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -121,7 +121,6 @@
|
|
|
121
121
|
"@types/google.analytics": "0.0.39",
|
|
122
122
|
"@types/gtag.js": "0.0.20",
|
|
123
123
|
"@types/jsdom": "^16.2.13",
|
|
124
|
-
"@types/lodash-es": "^4.17.12",
|
|
125
124
|
"@types/mocha": "^9.0.0",
|
|
126
125
|
"@types/node": "*",
|
|
127
126
|
"@types/pako": "^1.0.1",
|
|
@@ -129,9 +128,8 @@
|
|
|
129
128
|
"@types/resize-observer-browser": "^0.1.1",
|
|
130
129
|
"@types/resolve": "^1.20.2",
|
|
131
130
|
"@types/semver": "^5.5.0",
|
|
132
|
-
"@types/
|
|
133
|
-
"@types/yargs": "^
|
|
134
|
-
"@types/yargs-parser": "^20.2.1",
|
|
131
|
+
"@types/yargs": "^17.0.35",
|
|
132
|
+
"@types/yargs-parser": "^21.0.3",
|
|
135
133
|
"@typescript-eslint/eslint-plugin": "^8.60.1",
|
|
136
134
|
"@typescript-eslint/parser": "^8.60.1",
|
|
137
135
|
"acorn": "^8.5.0",
|
|
@@ -196,7 +194,6 @@
|
|
|
196
194
|
"js-library-detector": "^6.7.0",
|
|
197
195
|
"lighthouse-logger": "^2.0.2",
|
|
198
196
|
"lighthouse-stack-packs": "1.12.3",
|
|
199
|
-
"lodash-es": "^4.17.21",
|
|
200
197
|
"lookup-closest-locale": "6.2.0",
|
|
201
198
|
"open": "^8.4.0",
|
|
202
199
|
"puppeteer-core": "^25.12.0",
|
|
@@ -204,9 +201,8 @@
|
|
|
204
201
|
"speedline-core": "^1.4.3",
|
|
205
202
|
"third-party-web": "^0.30.0",
|
|
206
203
|
"tldts-icann": "^7.4.16",
|
|
207
|
-
"
|
|
208
|
-
"yargs": "^
|
|
209
|
-
"yargs-parser": "^21.0.0"
|
|
204
|
+
"yargs": "^18.2.0",
|
|
205
|
+
"yargs-parser": "^22.0.0"
|
|
210
206
|
},
|
|
211
207
|
"resolutions": {
|
|
212
208
|
"puppeteer/**/devtools-protocol": "0.0.1704951",
|
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {set} from 'lodash-es';
|
|
8
|
-
import {get} from 'lodash-es';
|
|
9
|
-
|
|
10
7
|
import * as format from './format.js';
|
|
11
8
|
|
|
12
9
|
/**
|
|
@@ -70,9 +67,17 @@ function swapLocale(lhr, requestedLocale) {
|
|
|
70
67
|
values = instance.values;
|
|
71
68
|
}
|
|
72
69
|
|
|
70
|
+
const keys = path.replace(/\[([^\]]+)\]/g, '.$1').replace(/^\./, '').split('.');
|
|
71
|
+
/** @type {any} */
|
|
72
|
+
let parent = lhr;
|
|
73
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
74
|
+
parent = parent?.[keys[i]];
|
|
75
|
+
}
|
|
76
|
+
const lastKey = keys[keys.length - 1];
|
|
77
|
+
|
|
73
78
|
// If the path isn't valid or the value isn't a string, there's no point in trying to replace it.
|
|
74
79
|
/** @type {unknown} */
|
|
75
|
-
const originalString =
|
|
80
|
+
const originalString = parent?.[lastKey];
|
|
76
81
|
if (typeof originalString !== 'string') {
|
|
77
82
|
continue;
|
|
78
83
|
}
|
|
@@ -96,7 +101,7 @@ function swapLocale(lhr, requestedLocale) {
|
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
// Write string back into the LHR.
|
|
99
|
-
|
|
104
|
+
parent[lastKey] = relocalizedString;
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
107
|
|