lighthouse 10.2.0-dev.20230514 → 10.2.0-dev.20230516
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/core/audits/seo/crawlable-anchors.js +4 -0
- package/core/computed/entity-classification.d.ts +14 -1
- package/core/computed/entity-classification.js +61 -6
- package/core/gather/gatherers/anchor-elements.js +2 -0
- package/core/lib/url-utils.js +4 -0
- package/dist/report/bundle.esm.js +14 -1
- package/dist/report/flow.js +1 -1
- package/dist/report/standalone.js +1 -1
- package/package.json +2 -2
- package/shared/util.d.ts +6 -0
- package/shared/util.js +14 -1
- package/types/artifacts.d.ts +1 -0
|
@@ -43,6 +43,7 @@ class CrawlableAnchors extends Audit {
|
|
|
43
43
|
rawHref,
|
|
44
44
|
name = '',
|
|
45
45
|
role = '',
|
|
46
|
+
id,
|
|
46
47
|
}) => {
|
|
47
48
|
rawHref = rawHref.replace( /\s/g, '');
|
|
48
49
|
name = name.trim();
|
|
@@ -52,6 +53,9 @@ class CrawlableAnchors extends Audit {
|
|
|
52
53
|
// Ignore mailto links even if they use one of the failing patterns. See https://github.com/GoogleChrome/lighthouse/issues/11443#issuecomment-694898412
|
|
53
54
|
if (rawHref.startsWith('mailto:')) return;
|
|
54
55
|
|
|
56
|
+
// Ignore `<a id="something">` elements acting as an anchor.
|
|
57
|
+
if (rawHref === '' && id) return;
|
|
58
|
+
|
|
55
59
|
const javaScriptVoidRegExp = /javascript:void(\(|)0(\)|)/;
|
|
56
60
|
|
|
57
61
|
if (rawHref.startsWith('file:')) return true;
|
|
@@ -10,12 +10,25 @@ declare const EntityClassificationComputed: typeof EntityClassification & {
|
|
|
10
10
|
};
|
|
11
11
|
/** @typedef {Map<string, LH.Artifacts.Entity>} EntityCache */
|
|
12
12
|
declare class EntityClassification {
|
|
13
|
+
/**
|
|
14
|
+
* @param {EntityCache} entityCache
|
|
15
|
+
* @param {string} url
|
|
16
|
+
* @param {string=} extensionName
|
|
17
|
+
* @return {LH.Artifacts.Entity}
|
|
18
|
+
*/
|
|
19
|
+
static makeupChromeExtensionEntity_(entityCache: EntityCache, url: string, extensionName?: string | undefined): LH.Artifacts.Entity;
|
|
13
20
|
/**
|
|
14
21
|
* @param {EntityCache} entityCache
|
|
15
22
|
* @param {string} url
|
|
16
23
|
* @return {LH.Artifacts.Entity | undefined}
|
|
17
24
|
*/
|
|
18
|
-
static
|
|
25
|
+
static _makeUpAnEntity(entityCache: EntityCache, url: string): LH.Artifacts.Entity | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Preload Chrome extensions found in the devtoolsLog into cache.
|
|
28
|
+
* @param {EntityCache} entityCache
|
|
29
|
+
* @param {LH.DevtoolsLog} devtoolsLog
|
|
30
|
+
*/
|
|
31
|
+
static _preloadChromeExtensionsToCache(entityCache: EntityCache, devtoolsLog: import("../index.js").DevtoolsLog): void;
|
|
19
32
|
/**
|
|
20
33
|
* @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
|
|
21
34
|
* @param {LH.Artifacts.ComputedContext} context
|
|
@@ -13,16 +13,51 @@ import thirdPartyWeb from '../lib/third-party-web.js';
|
|
|
13
13
|
/** @typedef {Map<string, LH.Artifacts.Entity>} EntityCache */
|
|
14
14
|
|
|
15
15
|
class EntityClassification {
|
|
16
|
+
/**
|
|
17
|
+
* @param {EntityCache} entityCache
|
|
18
|
+
* @param {string} url
|
|
19
|
+
* @param {string=} extensionName
|
|
20
|
+
* @return {LH.Artifacts.Entity}
|
|
21
|
+
*/
|
|
22
|
+
static makeupChromeExtensionEntity_(entityCache, url, extensionName) {
|
|
23
|
+
const origin = Util.getChromeExtensionOrigin(url);
|
|
24
|
+
const host = new URL(origin).host;
|
|
25
|
+
const name = extensionName || host;
|
|
26
|
+
|
|
27
|
+
const cachedEntity = entityCache.get(origin);
|
|
28
|
+
if (cachedEntity) return cachedEntity;
|
|
29
|
+
|
|
30
|
+
const chromeExtensionEntity = {
|
|
31
|
+
name,
|
|
32
|
+
company: name,
|
|
33
|
+
category: 'Chrome Extension',
|
|
34
|
+
homepage: 'https://chromewebstore.google.com/detail/' + host,
|
|
35
|
+
categories: [],
|
|
36
|
+
domains: [],
|
|
37
|
+
averageExecutionTime: 0,
|
|
38
|
+
totalExecutionTime: 0,
|
|
39
|
+
totalOccurrences: 0,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
entityCache.set(origin, chromeExtensionEntity);
|
|
43
|
+
return chromeExtensionEntity;
|
|
44
|
+
}
|
|
45
|
+
|
|
16
46
|
/**
|
|
17
47
|
* @param {EntityCache} entityCache
|
|
18
48
|
* @param {string} url
|
|
19
49
|
* @return {LH.Artifacts.Entity | undefined}
|
|
20
50
|
*/
|
|
21
|
-
static
|
|
51
|
+
static _makeUpAnEntity(entityCache, url) {
|
|
22
52
|
if (!UrlUtils.isValid(url)) return;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (
|
|
53
|
+
|
|
54
|
+
const parsedUrl = Util.createOrReturnURL(url);
|
|
55
|
+
if (parsedUrl.protocol === 'chrome-extension:') {
|
|
56
|
+
return EntityClassification.makeupChromeExtensionEntity_(entityCache, url);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Make up an entity only for valid http/https URLs.
|
|
60
|
+
if (!parsedUrl.protocol.startsWith('http')) return;
|
|
26
61
|
|
|
27
62
|
const rootDomain = Util.getRootDomain(url);
|
|
28
63
|
if (!rootDomain) return;
|
|
@@ -43,6 +78,24 @@ class EntityClassification {
|
|
|
43
78
|
return unrecognizedEntity;
|
|
44
79
|
}
|
|
45
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Preload Chrome extensions found in the devtoolsLog into cache.
|
|
83
|
+
* @param {EntityCache} entityCache
|
|
84
|
+
* @param {LH.DevtoolsLog} devtoolsLog
|
|
85
|
+
*/
|
|
86
|
+
static _preloadChromeExtensionsToCache(entityCache, devtoolsLog) {
|
|
87
|
+
for (const entry of devtoolsLog.values()) {
|
|
88
|
+
if (entry.method !== 'Runtime.executionContextCreated') continue;
|
|
89
|
+
|
|
90
|
+
const origin = entry.params.context.origin;
|
|
91
|
+
if (!origin.startsWith('chrome-extension:')) continue;
|
|
92
|
+
if (entityCache.has(origin)) continue;
|
|
93
|
+
|
|
94
|
+
EntityClassification.makeupChromeExtensionEntity_(entityCache, origin,
|
|
95
|
+
entry.params.context.name);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
46
99
|
/**
|
|
47
100
|
* @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
|
|
48
101
|
* @param {LH.Artifacts.ComputedContext} context
|
|
@@ -57,12 +110,14 @@ class EntityClassification {
|
|
|
57
110
|
/** @type {Map<LH.Artifacts.Entity, Set<string>>} */
|
|
58
111
|
const urlsByEntity = new Map();
|
|
59
112
|
|
|
113
|
+
EntityClassification._preloadChromeExtensionsToCache(madeUpEntityCache, data.devtoolsLog);
|
|
114
|
+
|
|
60
115
|
for (const record of networkRecords) {
|
|
61
116
|
const {url} = record;
|
|
62
117
|
if (entityByUrl.has(url)) continue;
|
|
63
118
|
|
|
64
119
|
const entity = thirdPartyWeb.getEntity(url) ||
|
|
65
|
-
EntityClassification.
|
|
120
|
+
EntityClassification._makeUpAnEntity(madeUpEntityCache, url);
|
|
66
121
|
if (!entity) continue;
|
|
67
122
|
|
|
68
123
|
const entityURLs = urlsByEntity.get(entity) || new Set();
|
|
@@ -76,7 +131,7 @@ class EntityClassification {
|
|
|
76
131
|
// See https://github.com/GoogleChrome/lighthouse/issues/13706
|
|
77
132
|
const firstPartyUrl = data.URL.mainDocumentUrl || data.URL.finalDisplayedUrl;
|
|
78
133
|
const firstParty = thirdPartyWeb.getEntity(firstPartyUrl) ||
|
|
79
|
-
EntityClassification.
|
|
134
|
+
EntityClassification._makeUpAnEntity(madeUpEntityCache, firstPartyUrl);
|
|
80
135
|
|
|
81
136
|
/**
|
|
82
137
|
* Convenience function to check if a URL belongs to first party.
|
|
@@ -53,6 +53,7 @@ function collectAnchorElements() {
|
|
|
53
53
|
text: node.innerText, // we don't want to return hidden text, so use innerText
|
|
54
54
|
rel: node.rel,
|
|
55
55
|
target: node.target,
|
|
56
|
+
id: node.getAttribute('id') || '',
|
|
56
57
|
// @ts-expect-error - getNodeDetails put into scope via stringification
|
|
57
58
|
node: getNodeDetails(node),
|
|
58
59
|
};
|
|
@@ -66,6 +67,7 @@ function collectAnchorElements() {
|
|
|
66
67
|
text: node.textContent || '',
|
|
67
68
|
rel: '',
|
|
68
69
|
target: node.target.baseVal || '',
|
|
70
|
+
id: node.getAttribute('id') || '',
|
|
69
71
|
// @ts-expect-error - getNodeDetails put into scope via stringification
|
|
70
72
|
node: getNodeDetails(node),
|
|
71
73
|
};
|
package/core/lib/url-utils.js
CHANGED
|
@@ -87,6 +87,10 @@ class UrlUtils {
|
|
|
87
87
|
static getOrigin(url) {
|
|
88
88
|
try {
|
|
89
89
|
const urlInfo = new URL(url);
|
|
90
|
+
if (urlInfo.protocol === 'chrome-extension:') {
|
|
91
|
+
// Chrome extensions return string "null" as origin, so we reconstruct the extension origin.
|
|
92
|
+
return Util.getChromeExtensionOrigin(url);
|
|
93
|
+
}
|
|
90
94
|
// check for both host and origin since some URLs schemes like data and file set origin to the
|
|
91
95
|
// string "null" instead of the object
|
|
92
96
|
return (urlInfo.host && urlInfo.origin) || null;
|
|
@@ -260,6 +260,16 @@ class Util {
|
|
|
260
260
|
return name;
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Returns the origin portion of a Chrome extension URL.
|
|
265
|
+
* @param {string} url
|
|
266
|
+
* @return {string}
|
|
267
|
+
*/
|
|
268
|
+
static getChromeExtensionOrigin(url) {
|
|
269
|
+
const parsedUrl = new URL(url);
|
|
270
|
+
return parsedUrl.protocol + '//' + parsedUrl.host;
|
|
271
|
+
}
|
|
272
|
+
|
|
263
273
|
/**
|
|
264
274
|
* Split a URL into a file, hostname and origin for easy display.
|
|
265
275
|
* @param {string} url
|
|
@@ -270,7 +280,10 @@ class Util {
|
|
|
270
280
|
return {
|
|
271
281
|
file: Util.getURLDisplayName(parsedUrl),
|
|
272
282
|
hostname: parsedUrl.hostname,
|
|
273
|
-
|
|
283
|
+
// Node's URL parsing behavior is different than Chrome and returns 'null'
|
|
284
|
+
// for chrome-extension:// URLs. See https://github.com/nodejs/node/issues/21955.
|
|
285
|
+
origin: parsedUrl.protocol === 'chrome-extension:' ?
|
|
286
|
+
Util.getChromeExtensionOrigin(url) : parsedUrl.origin,
|
|
274
287
|
};
|
|
275
288
|
}
|
|
276
289
|
|
package/dist/report/flow.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
15
|
* See the License for the specific language governing permissions and
|
|
16
16
|
* limitations under the License.
|
|
17
|
-
*/const oe="…",re={PASS:{label:"pass",minScore:.9},AVERAGE:{label:"average",minScore:.5},FAIL:{label:"fail"},ERROR:{label:"error"}},se=["com","co","gov","edu","ac","org","go","gob","or","net","in","ne","nic","gouv","web","spb","blog","jus","kiev","mil","wi","qc","ca","bel","on"];class le{static get RATINGS(){return re}static get PASS_THRESHOLD(){return.9}static get MS_DISPLAY_VALUE(){return"%10d ms"}static getFinalDisplayedUrl(e){if(e.finalDisplayedUrl)return e.finalDisplayedUrl;if(e.finalUrl)return e.finalUrl;throw new Error("Could not determine final displayed URL")}static getMainDocumentUrl(e){return e.mainDocumentUrl||e.finalUrl}static getFullPageScreenshot(e){if(e.fullPageScreenshot)return e.fullPageScreenshot;return e.audits["full-page-screenshot"]?.details}static splitMarkdownCodeSpans(e){const a=[],n=e.split(/`(.*?)`/g);for(let e=0;e<n.length;e++){const t=n[e];if(!t)continue;const i=e%2!=0;a.push({isCode:i,text:t})}return a}static splitMarkdownLink(e){const a=[],n=e.split(/\[([^\]]+?)\]\((https?:\/\/.*?)\)/g);for(;n.length;){const[e,t,i]=n.splice(0,3);e&&a.push({isLink:!1,text:e}),t&&i&&a.push({isLink:!0,text:t,linkHref:i})}return a}static truncate(e,a,n="…"){if(e.length<=a)return e;const t=new Intl.Segmenter(void 0,{granularity:"grapheme"}).segment(e)[Symbol.iterator]();let i=0;for(let o=0;o<=a-n.length;o++){const a=t.next();if(a.done)return e;i=a.value.index}for(let a=0;a<n.length;a++)if(t.next().done)return e;return e.slice(0,i)+n}static getURLDisplayName(e,a){const n=void 0!==(a=a||{numPathParts:void 0,preserveQuery:void 0,preserveHost:void 0}).numPathParts?a.numPathParts:2,t=void 0===a.preserveQuery||a.preserveQuery,i=a.preserveHost||!1;let o;if("about:"===e.protocol||"data:"===e.protocol)o=e.href;else{o=e.pathname;const a=o.split("/").filter((e=>e.length));n&&a.length>n&&(o=oe+a.slice(-1*n).join("/")),i&&(o=`${e.host}/${o.replace(/^\//,"")}`),t&&(o=`${o}${e.search}`)}if("data:"!==e.protocol&&(o=o.slice(0,200),o=o.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g,"$1…"),o=o.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,"$1…"),o=o.replace(/(\d{3})\d{6,}/g,"$1…"),o=o.replace(/\u2026+/g,oe),o.length>64&&o.includes("?")&&(o=o.replace(/\?([^=]*)(=)?.*/,"?$1$2…"),o.length>64&&(o=o.replace(/\?.*/,"?…")))),o.length>64){const e=o.lastIndexOf(".");o=e>=0?o.slice(0,63-(o.length-e))+`…${o.slice(e)}`:o.slice(0,63)+oe}return o}static parseURL(e){const a=new URL(e);return{file:le.getURLDisplayName(a),hostname:a.hostname,origin:a.origin}}static createOrReturnURL(e){return e instanceof URL?e:new URL(e)}static getTld(e){const a=e.split(".").slice(-2);return se.includes(a[0])?`.${a.join(".")}`:`.${a[a.length-1]}`}static getRootDomain(e){const a=le.createOrReturnURL(e).hostname,n=le.getTld(a).split(".");return a.split(".").slice(-n.length).join(".")}static filterRelevantLines(e,a,n){if(0===a.length)return e.slice(0,2*n+1);const t=new Set;return(a=a.sort(((e,a)=>(e.lineNumber||0)-(a.lineNumber||0)))).forEach((({lineNumber:e})=>{let a=e-n,i=e+n;for(;a<1;)a++,i++;t.has(a-3-1)&&(a-=3);for(let e=a;e<=i;e++){const a=e;t.add(a)}})),e.filter((e=>t.has(e.lineNumber)))}}
|
|
17
|
+
*/const oe="…",re={PASS:{label:"pass",minScore:.9},AVERAGE:{label:"average",minScore:.5},FAIL:{label:"fail"},ERROR:{label:"error"}},se=["com","co","gov","edu","ac","org","go","gob","or","net","in","ne","nic","gouv","web","spb","blog","jus","kiev","mil","wi","qc","ca","bel","on"];class le{static get RATINGS(){return re}static get PASS_THRESHOLD(){return.9}static get MS_DISPLAY_VALUE(){return"%10d ms"}static getFinalDisplayedUrl(e){if(e.finalDisplayedUrl)return e.finalDisplayedUrl;if(e.finalUrl)return e.finalUrl;throw new Error("Could not determine final displayed URL")}static getMainDocumentUrl(e){return e.mainDocumentUrl||e.finalUrl}static getFullPageScreenshot(e){if(e.fullPageScreenshot)return e.fullPageScreenshot;return e.audits["full-page-screenshot"]?.details}static splitMarkdownCodeSpans(e){const a=[],n=e.split(/`(.*?)`/g);for(let e=0;e<n.length;e++){const t=n[e];if(!t)continue;const i=e%2!=0;a.push({isCode:i,text:t})}return a}static splitMarkdownLink(e){const a=[],n=e.split(/\[([^\]]+?)\]\((https?:\/\/.*?)\)/g);for(;n.length;){const[e,t,i]=n.splice(0,3);e&&a.push({isLink:!1,text:e}),t&&i&&a.push({isLink:!0,text:t,linkHref:i})}return a}static truncate(e,a,n="…"){if(e.length<=a)return e;const t=new Intl.Segmenter(void 0,{granularity:"grapheme"}).segment(e)[Symbol.iterator]();let i=0;for(let o=0;o<=a-n.length;o++){const a=t.next();if(a.done)return e;i=a.value.index}for(let a=0;a<n.length;a++)if(t.next().done)return e;return e.slice(0,i)+n}static getURLDisplayName(e,a){const n=void 0!==(a=a||{numPathParts:void 0,preserveQuery:void 0,preserveHost:void 0}).numPathParts?a.numPathParts:2,t=void 0===a.preserveQuery||a.preserveQuery,i=a.preserveHost||!1;let o;if("about:"===e.protocol||"data:"===e.protocol)o=e.href;else{o=e.pathname;const a=o.split("/").filter((e=>e.length));n&&a.length>n&&(o=oe+a.slice(-1*n).join("/")),i&&(o=`${e.host}/${o.replace(/^\//,"")}`),t&&(o=`${o}${e.search}`)}if("data:"!==e.protocol&&(o=o.slice(0,200),o=o.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g,"$1…"),o=o.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,"$1…"),o=o.replace(/(\d{3})\d{6,}/g,"$1…"),o=o.replace(/\u2026+/g,oe),o.length>64&&o.includes("?")&&(o=o.replace(/\?([^=]*)(=)?.*/,"?$1$2…"),o.length>64&&(o=o.replace(/\?.*/,"?…")))),o.length>64){const e=o.lastIndexOf(".");o=e>=0?o.slice(0,63-(o.length-e))+`…${o.slice(e)}`:o.slice(0,63)+oe}return o}static getChromeExtensionOrigin(e){const a=new URL(e);return a.protocol+"//"+a.host}static parseURL(e){const a=new URL(e);return{file:le.getURLDisplayName(a),hostname:a.hostname,origin:"chrome-extension:"===a.protocol?le.getChromeExtensionOrigin(e):a.origin}}static createOrReturnURL(e){return e instanceof URL?e:new URL(e)}static getTld(e){const a=e.split(".").slice(-2);return se.includes(a[0])?`.${a.join(".")}`:`.${a[a.length-1]}`}static getRootDomain(e){const a=le.createOrReturnURL(e).hostname,n=le.getTld(a).split(".");return a.split(".").slice(-n.length).join(".")}static filterRelevantLines(e,a,n){if(0===a.length)return e.slice(0,2*n+1);const t=new Set;return(a=a.sort(((e,a)=>(e.lineNumber||0)-(a.lineNumber||0)))).forEach((({lineNumber:e})=>{let a=e-n,i=e+n;for(;a<1;)a++,i++;t.has(a-3-1)&&(a-=3);for(let e=a;e<=i;e++){const a=e;t.add(a)}})),e.filter((e=>t.has(e.lineNumber)))}}
|
|
18
18
|
/**
|
|
19
19
|
* @license Copyright 2023 The Lighthouse Authors. All Rights Reserved.
|
|
20
20
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
15
|
* See the License for the specific language governing permissions and
|
|
16
16
|
* limitations under the License.
|
|
17
|
-
*/const e="…",t={PASS:{label:"pass",minScore:.9},AVERAGE:{label:"average",minScore:.5},FAIL:{label:"fail"},ERROR:{label:"error"}},n=["com","co","gov","edu","ac","org","go","gob","or","net","in","ne","nic","gouv","web","spb","blog","jus","kiev","mil","wi","qc","ca","bel","on"];class r{static get RATINGS(){return t}static get PASS_THRESHOLD(){return.9}static get MS_DISPLAY_VALUE(){return"%10d ms"}static getFinalDisplayedUrl(e){if(e.finalDisplayedUrl)return e.finalDisplayedUrl;if(e.finalUrl)return e.finalUrl;throw new Error("Could not determine final displayed URL")}static getMainDocumentUrl(e){return e.mainDocumentUrl||e.finalUrl}static getFullPageScreenshot(e){if(e.fullPageScreenshot)return e.fullPageScreenshot;return e.audits["full-page-screenshot"]?.details}static splitMarkdownCodeSpans(e){const t=[],n=e.split(/`(.*?)`/g);for(let e=0;e<n.length;e++){const r=n[e];if(!r)continue;const o=e%2!=0;t.push({isCode:o,text:r})}return t}static splitMarkdownLink(e){const t=[],n=e.split(/\[([^\]]+?)\]\((https?:\/\/.*?)\)/g);for(;n.length;){const[e,r,o]=n.splice(0,3);e&&t.push({isLink:!1,text:e}),r&&o&&t.push({isLink:!0,text:r,linkHref:o})}return t}static truncate(e,t,n="…"){if(e.length<=t)return e;const r=new Intl.Segmenter(void 0,{granularity:"grapheme"}).segment(e)[Symbol.iterator]();let o=0;for(let i=0;i<=t-n.length;i++){const t=r.next();if(t.done)return e;o=t.value.index}for(let t=0;t<n.length;t++)if(r.next().done)return e;return e.slice(0,o)+n}static getURLDisplayName(t,n){const r=void 0!==(n=n||{numPathParts:void 0,preserveQuery:void 0,preserveHost:void 0}).numPathParts?n.numPathParts:2,o=void 0===n.preserveQuery||n.preserveQuery,i=n.preserveHost||!1;let a;if("about:"===t.protocol||"data:"===t.protocol)a=t.href;else{a=t.pathname;const n=a.split("/").filter((e=>e.length));r&&n.length>r&&(a=e+n.slice(-1*r).join("/")),i&&(a=`${t.host}/${a.replace(/^\//,"")}`),o&&(a=`${a}${t.search}`)}if("data:"!==t.protocol&&(a=a.slice(0,200),a=a.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g,"$1…"),a=a.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,"$1…"),a=a.replace(/(\d{3})\d{6,}/g,"$1…"),a=a.replace(/\u2026+/g,e),a.length>64&&a.includes("?")&&(a=a.replace(/\?([^=]*)(=)?.*/,"?$1$2…"),a.length>64&&(a=a.replace(/\?.*/,"?…")))),a.length>64){const t=a.lastIndexOf(".");a=t>=0?a.slice(0,63-(a.length-t))+`…${a.slice(t)}`:a.slice(0,63)+e}return a}static parseURL(e){const t=new URL(e);return{file:r.getURLDisplayName(t),hostname:t.hostname,origin:t.origin}}static createOrReturnURL(e){return e instanceof URL?e:new URL(e)}static getTld(e){const t=e.split(".").slice(-2);return n.includes(t[0])?`.${t.join(".")}`:`.${t[t.length-1]}`}static getRootDomain(e){const t=r.createOrReturnURL(e).hostname,n=r.getTld(t).split(".");return t.split(".").slice(-n.length).join(".")}static filterRelevantLines(e,t,n){if(0===t.length)return e.slice(0,2*n+1);const r=new Set;return(t=t.sort(((e,t)=>(e.lineNumber||0)-(t.lineNumber||0)))).forEach((({lineNumber:e})=>{let t=e-n,o=e+n;for(;t<1;)t++,o++;r.has(t-3-1)&&(t-=3);for(let e=t;e<=o;e++){const t=e;r.add(t)}})),e.filter((e=>r.has(e.lineNumber)))}}
|
|
17
|
+
*/const e="…",t={PASS:{label:"pass",minScore:.9},AVERAGE:{label:"average",minScore:.5},FAIL:{label:"fail"},ERROR:{label:"error"}},n=["com","co","gov","edu","ac","org","go","gob","or","net","in","ne","nic","gouv","web","spb","blog","jus","kiev","mil","wi","qc","ca","bel","on"];class r{static get RATINGS(){return t}static get PASS_THRESHOLD(){return.9}static get MS_DISPLAY_VALUE(){return"%10d ms"}static getFinalDisplayedUrl(e){if(e.finalDisplayedUrl)return e.finalDisplayedUrl;if(e.finalUrl)return e.finalUrl;throw new Error("Could not determine final displayed URL")}static getMainDocumentUrl(e){return e.mainDocumentUrl||e.finalUrl}static getFullPageScreenshot(e){if(e.fullPageScreenshot)return e.fullPageScreenshot;return e.audits["full-page-screenshot"]?.details}static splitMarkdownCodeSpans(e){const t=[],n=e.split(/`(.*?)`/g);for(let e=0;e<n.length;e++){const r=n[e];if(!r)continue;const o=e%2!=0;t.push({isCode:o,text:r})}return t}static splitMarkdownLink(e){const t=[],n=e.split(/\[([^\]]+?)\]\((https?:\/\/.*?)\)/g);for(;n.length;){const[e,r,o]=n.splice(0,3);e&&t.push({isLink:!1,text:e}),r&&o&&t.push({isLink:!0,text:r,linkHref:o})}return t}static truncate(e,t,n="…"){if(e.length<=t)return e;const r=new Intl.Segmenter(void 0,{granularity:"grapheme"}).segment(e)[Symbol.iterator]();let o=0;for(let i=0;i<=t-n.length;i++){const t=r.next();if(t.done)return e;o=t.value.index}for(let t=0;t<n.length;t++)if(r.next().done)return e;return e.slice(0,o)+n}static getURLDisplayName(t,n){const r=void 0!==(n=n||{numPathParts:void 0,preserveQuery:void 0,preserveHost:void 0}).numPathParts?n.numPathParts:2,o=void 0===n.preserveQuery||n.preserveQuery,i=n.preserveHost||!1;let a;if("about:"===t.protocol||"data:"===t.protocol)a=t.href;else{a=t.pathname;const n=a.split("/").filter((e=>e.length));r&&n.length>r&&(a=e+n.slice(-1*r).join("/")),i&&(a=`${t.host}/${a.replace(/^\//,"")}`),o&&(a=`${a}${t.search}`)}if("data:"!==t.protocol&&(a=a.slice(0,200),a=a.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g,"$1…"),a=a.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,"$1…"),a=a.replace(/(\d{3})\d{6,}/g,"$1…"),a=a.replace(/\u2026+/g,e),a.length>64&&a.includes("?")&&(a=a.replace(/\?([^=]*)(=)?.*/,"?$1$2…"),a.length>64&&(a=a.replace(/\?.*/,"?…")))),a.length>64){const t=a.lastIndexOf(".");a=t>=0?a.slice(0,63-(a.length-t))+`…${a.slice(t)}`:a.slice(0,63)+e}return a}static getChromeExtensionOrigin(e){const t=new URL(e);return t.protocol+"//"+t.host}static parseURL(e){const t=new URL(e);return{file:r.getURLDisplayName(t),hostname:t.hostname,origin:"chrome-extension:"===t.protocol?r.getChromeExtensionOrigin(e):t.origin}}static createOrReturnURL(e){return e instanceof URL?e:new URL(e)}static getTld(e){const t=e.split(".").slice(-2);return n.includes(t[0])?`.${t.join(".")}`:`.${t[t.length-1]}`}static getRootDomain(e){const t=r.createOrReturnURL(e).hostname,n=r.getTld(t).split(".");return t.split(".").slice(-n.length).join(".")}static filterRelevantLines(e,t,n){if(0===t.length)return e.slice(0,2*n+1);const r=new Set;return(t=t.sort(((e,t)=>(e.lineNumber||0)-(t.lineNumber||0)))).forEach((({lineNumber:e})=>{let t=e-n,o=e+n;for(;t<1;)t++,o++;r.has(t-3-1)&&(t-=3);for(let e=t;e<=o;e++){const t=e;r.add(t)}})),e.filter((e=>r.has(e.lineNumber)))}}
|
|
18
18
|
/**
|
|
19
19
|
* @license
|
|
20
20
|
* Copyright 2017 The Lighthouse Authors. All Rights Reserved.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lighthouse",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "10.2.0-dev.
|
|
4
|
+
"version": "10.2.0-dev.20230516",
|
|
5
5
|
"description": "Automated auditing, performance metrics, and best practices for the web.",
|
|
6
6
|
"main": "./core/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -197,7 +197,7 @@
|
|
|
197
197
|
"intl-messageformat": "^4.4.0",
|
|
198
198
|
"jpeg-js": "^0.4.4",
|
|
199
199
|
"js-library-detector": "^6.6.0",
|
|
200
|
-
"lighthouse-logger": "^1.
|
|
200
|
+
"lighthouse-logger": "^1.4.1",
|
|
201
201
|
"lighthouse-stack-packs": "1.10.0",
|
|
202
202
|
"lodash": "^4.17.21",
|
|
203
203
|
"lookup-closest-locale": "6.2.0",
|
package/shared/util.d.ts
CHANGED
|
@@ -83,6 +83,12 @@ export class Util {
|
|
|
83
83
|
preserveQuery?: boolean | undefined;
|
|
84
84
|
preserveHost?: boolean | undefined;
|
|
85
85
|
} | undefined): string;
|
|
86
|
+
/**
|
|
87
|
+
* Returns the origin portion of a Chrome extension URL.
|
|
88
|
+
* @param {string} url
|
|
89
|
+
* @return {string}
|
|
90
|
+
*/
|
|
91
|
+
static getChromeExtensionOrigin(url: string): string;
|
|
86
92
|
/**
|
|
87
93
|
* Split a URL into a file, hostname and origin for easy display.
|
|
88
94
|
* @param {string} url
|
package/shared/util.js
CHANGED
|
@@ -260,6 +260,16 @@ class Util {
|
|
|
260
260
|
return name;
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Returns the origin portion of a Chrome extension URL.
|
|
265
|
+
* @param {string} url
|
|
266
|
+
* @return {string}
|
|
267
|
+
*/
|
|
268
|
+
static getChromeExtensionOrigin(url) {
|
|
269
|
+
const parsedUrl = new URL(url);
|
|
270
|
+
return parsedUrl.protocol + '//' + parsedUrl.host;
|
|
271
|
+
}
|
|
272
|
+
|
|
263
273
|
/**
|
|
264
274
|
* Split a URL into a file, hostname and origin for easy display.
|
|
265
275
|
* @param {string} url
|
|
@@ -270,7 +280,10 @@ class Util {
|
|
|
270
280
|
return {
|
|
271
281
|
file: Util.getURLDisplayName(parsedUrl),
|
|
272
282
|
hostname: parsedUrl.hostname,
|
|
273
|
-
|
|
283
|
+
// Node's URL parsing behavior is different than Chrome and returns 'null'
|
|
284
|
+
// for chrome-extension:// URLs. See https://github.com/nodejs/node/issues/21955.
|
|
285
|
+
origin: parsedUrl.protocol === 'chrome-extension:' ?
|
|
286
|
+
Util.getChromeExtensionOrigin(url) : parsedUrl.origin,
|
|
274
287
|
};
|
|
275
288
|
}
|
|
276
289
|
|