lighthouse 9.5.0-dev.20220620 → 9.5.0-dev.20220623
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/lighthouse-cli/bin.js +8 -2
- package/lighthouse-cli/test/smokehouse/__snapshots__/report-assert-test.js.snap +71 -0
- package/lighthouse-cli/test/smokehouse/report-assert-test.js +264 -0
- package/lighthouse-cli/test/smokehouse/report-assert.js +39 -35
- package/lighthouse-core/audits/byte-efficiency/unused-javascript.js +1 -1
- package/lighthouse-core/config/config-helpers.js +15 -0
- package/lighthouse-core/fraggle-rock/config/config.js +45 -1
- package/lighthouse-core/fraggle-rock/gather/driver.js +13 -5
- package/lighthouse-core/fraggle-rock/gather/session.js +23 -67
- package/lighthouse-core/gather/driver/navigation.js +1 -1
- package/lighthouse-core/gather/driver/network-monitor.js +19 -81
- package/lighthouse-core/gather/driver/target-manager.js +110 -45
- package/lighthouse-core/gather/driver.js +24 -16
- package/lighthouse-core/gather/gatherers/devtools-log.js +7 -11
- package/lighthouse-core/gather/gatherers/full-page-screenshot.js +1 -1
- package/lighthouse-core/index.js +24 -9
- package/lighthouse-core/lib/cdt/Common.js +13 -0
- package/lighthouse-core/lib/cdt/Platform.js +3 -0
- package/lighthouse-core/lib/cdt/generated/ParsedURL.js +178 -0
- package/lighthouse-core/lib/cdt/generated/SourceMap.js +155 -62
- package/lighthouse-core/lib/network-recorder.js +9 -18
- package/package.json +2 -2
- package/third-party/devtools-tests/README.md +14 -0
- package/third-party/devtools-tests/e2e/lighthouse/generate-report_test.ts +29 -0
- package/third-party/devtools-tests/e2e/lighthouse/indexeddb-warning_test.ts +29 -0
- package/third-party/devtools-tests/e2e/resources/lighthouse/lighthouse-storage.html +11 -0
- package/third-party/download-content-shell/README.md +1 -0
- package/third-party/download-content-shell/download-content-shell.js +6 -1
- package/types/gatherer.d.ts +5 -2
- package/types/protocol.d.ts +26 -17
package/lighthouse-core/index.js
CHANGED
|
@@ -11,6 +11,8 @@ const ChromeProtocol = require('./gather/connections/cri.js');
|
|
|
11
11
|
const Config = require('./config/config.js');
|
|
12
12
|
const URL = require('./lib/url-shim.js');
|
|
13
13
|
const fraggleRock = require('./fraggle-rock/api.js');
|
|
14
|
+
const {initializeConfig} = require('./fraggle-rock/config/config.js');
|
|
15
|
+
const {flagsToFRContext} = require('./config/config-helpers.js');
|
|
14
16
|
|
|
15
17
|
/** @typedef {import('./gather/connections/connection.js')} Connection */
|
|
16
18
|
|
|
@@ -38,19 +40,14 @@ const fraggleRock = require('./fraggle-rock/api.js');
|
|
|
38
40
|
* @return {Promise<LH.RunnerResult|undefined>}
|
|
39
41
|
*/
|
|
40
42
|
async function lighthouse(url, flags = {}, configJSON, page) {
|
|
41
|
-
const configContext =
|
|
42
|
-
configPath: flags.configPath,
|
|
43
|
-
settingsOverrides: flags,
|
|
44
|
-
logLevel: flags.logLevel,
|
|
45
|
-
hostname: flags.hostname,
|
|
46
|
-
port: flags.port,
|
|
47
|
-
};
|
|
43
|
+
const configContext = flagsToFRContext(flags);
|
|
48
44
|
return fraggleRock.navigation(url, {page, config: configJSON, configContext});
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
/**
|
|
52
48
|
* Run Lighthouse using the legacy navigation runner.
|
|
53
49
|
* This is left in place for any clients that don't support FR navigations yet (e.g. Lightrider)
|
|
50
|
+
* @deprecated
|
|
54
51
|
* @param {string=} url The URL to test. Optional if running in auditMode.
|
|
55
52
|
* @param {LH.Flags=} flags Optional settings for the Lighthouse run. If present,
|
|
56
53
|
* they will override any settings in the config.
|
|
@@ -64,7 +61,7 @@ async function legacyNavigation(url, flags = {}, configJSON, userConnection) {
|
|
|
64
61
|
flags.logLevel = flags.logLevel || 'error';
|
|
65
62
|
log.setLevel(flags.logLevel);
|
|
66
63
|
|
|
67
|
-
const config = await
|
|
64
|
+
const config = await generateLegacyConfig(configJSON, flags);
|
|
68
65
|
const computedCache = new Map();
|
|
69
66
|
const options = {config, computedCache};
|
|
70
67
|
const connection = userConnection || new ChromeProtocol(flags.port, flags.hostname);
|
|
@@ -83,14 +80,32 @@ async function legacyNavigation(url, flags = {}, configJSON, userConnection) {
|
|
|
83
80
|
* not present, the default config is used.
|
|
84
81
|
* @param {LH.Flags=} flags Optional settings for the Lighthouse run. If present,
|
|
85
82
|
* they will override any settings in the config.
|
|
83
|
+
* @param {LH.Gatherer.GatherMode=} gatherMode Gather mode used to collect artifacts. If present
|
|
84
|
+
* the config may override certain settings based on the mode.
|
|
85
|
+
* @return {Promise<LH.Config.FRConfig>}
|
|
86
|
+
*/
|
|
87
|
+
async function generateConfig(configJson, flags = {}, gatherMode = 'navigation') {
|
|
88
|
+
const configContext = flagsToFRContext(flags);
|
|
89
|
+
const {config} = await initializeConfig(configJson, {...configContext, gatherMode});
|
|
90
|
+
return config;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Generate a legacy Lighthouse Config.
|
|
95
|
+
* @deprecated
|
|
96
|
+
* @param {LH.Config.Json=} configJson Configuration for the Lighthouse run. If
|
|
97
|
+
* not present, the default config is used.
|
|
98
|
+
* @param {LH.Flags=} flags Optional settings for the Lighthouse run. If present,
|
|
99
|
+
* they will override any settings in the config.
|
|
86
100
|
* @return {Promise<Config>}
|
|
87
101
|
*/
|
|
88
|
-
function
|
|
102
|
+
function generateLegacyConfig(configJson, flags) {
|
|
89
103
|
return Config.fromJson(configJson, flags);
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
lighthouse.legacyNavigation = legacyNavigation;
|
|
93
107
|
lighthouse.generateConfig = generateConfig;
|
|
108
|
+
lighthouse.generateLegacyConfig = generateLegacyConfig;
|
|
94
109
|
lighthouse.getAuditList = Runner.getAuditList;
|
|
95
110
|
lighthouse.traceCategories = require('./gather/driver.js').traceCategories;
|
|
96
111
|
lighthouse.Audit = require('./audits/audit.js');
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* @license Copyright 2022 The Lighthouse Authors. All Rights Reserved.
|
|
4
|
+
* 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
|
|
5
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
6
|
+
*/
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const ParsedURL = require('./generated/ParsedURL.js');
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
ParsedURL,
|
|
13
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// generated by yarn build-cdt-lib
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
"use strict";
|
|
5
|
+
/*
|
|
6
|
+
* Copyright (C) 2012 Google Inc. All rights reserved.
|
|
7
|
+
*
|
|
8
|
+
* Redistribution and use in source and binary forms, with or without
|
|
9
|
+
* modification, are permitted provided that the following conditions are
|
|
10
|
+
* met:
|
|
11
|
+
*
|
|
12
|
+
* * Redistributions of source code must retain the above copyright
|
|
13
|
+
* notice, this list of conditions and the following disclaimer.
|
|
14
|
+
* * Redistributions in binary form must reproduce the above
|
|
15
|
+
* copyright notice, this list of conditions and the following disclaimer
|
|
16
|
+
* in the documentation and/or other materials provided with the
|
|
17
|
+
* distribution.
|
|
18
|
+
* * Neither the name of Google Inc. nor the names of its
|
|
19
|
+
* contributors may be used to endorse or promote products derived from
|
|
20
|
+
* this software without specific prior written permission.
|
|
21
|
+
*
|
|
22
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
23
|
+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
24
|
+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
25
|
+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
26
|
+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
27
|
+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
28
|
+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
29
|
+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
30
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
31
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
32
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
33
|
+
*/
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.ParsedURL = exports.normalizePath = void 0;
|
|
36
|
+
;
|
|
37
|
+
/**
|
|
38
|
+
* http://tools.ietf.org/html/rfc3986#section-5.2.4
|
|
39
|
+
*/
|
|
40
|
+
function normalizePath(path) {
|
|
41
|
+
if (path.indexOf('..') === -1 && path.indexOf('.') === -1) {
|
|
42
|
+
return path;
|
|
43
|
+
}
|
|
44
|
+
// Remove leading slash (will be added back below) so we
|
|
45
|
+
// can handle all (including empty) segments consistently.
|
|
46
|
+
const segments = (path[0] === '/' ? path.substring(1) : path).split('/');
|
|
47
|
+
const normalizedSegments = [];
|
|
48
|
+
for (const segment of segments) {
|
|
49
|
+
if (segment === '.') {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
else if (segment === '..') {
|
|
53
|
+
normalizedSegments.pop();
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
normalizedSegments.push(segment);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
let normalizedPath = normalizedSegments.join('/');
|
|
60
|
+
if (path[0] === '/' && normalizedPath) {
|
|
61
|
+
normalizedPath = '/' + normalizedPath;
|
|
62
|
+
}
|
|
63
|
+
if (normalizedPath[normalizedPath.length - 1] !== '/' &&
|
|
64
|
+
((path[path.length - 1] === '/') || (segments[segments.length - 1] === '.') ||
|
|
65
|
+
(segments[segments.length - 1] === '..'))) {
|
|
66
|
+
normalizedPath = normalizedPath + '/';
|
|
67
|
+
}
|
|
68
|
+
return normalizedPath;
|
|
69
|
+
}
|
|
70
|
+
exports.normalizePath = normalizePath;
|
|
71
|
+
class ParsedURL {
|
|
72
|
+
isValid;
|
|
73
|
+
url;
|
|
74
|
+
scheme;
|
|
75
|
+
user;
|
|
76
|
+
host;
|
|
77
|
+
port;
|
|
78
|
+
path;
|
|
79
|
+
queryParams;
|
|
80
|
+
fragment;
|
|
81
|
+
folderPathComponents;
|
|
82
|
+
lastPathComponent;
|
|
83
|
+
blobInnerScheme;
|
|
84
|
+
#displayNameInternal;
|
|
85
|
+
#dataURLDisplayNameInternal;
|
|
86
|
+
constructor(url) {
|
|
87
|
+
this.isValid = false;
|
|
88
|
+
this.url = url;
|
|
89
|
+
this.scheme = '';
|
|
90
|
+
this.user = '';
|
|
91
|
+
this.host = '';
|
|
92
|
+
this.port = '';
|
|
93
|
+
this.path = '';
|
|
94
|
+
this.queryParams = '';
|
|
95
|
+
this.fragment = '';
|
|
96
|
+
this.folderPathComponents = '';
|
|
97
|
+
this.lastPathComponent = '';
|
|
98
|
+
const isBlobUrl = this.url.startsWith('blob:');
|
|
99
|
+
const urlToMatch = isBlobUrl ? url.substring(5) : url;
|
|
100
|
+
const match = urlToMatch.match(ParsedURL.urlRegex());
|
|
101
|
+
if (match) {
|
|
102
|
+
this.isValid = true;
|
|
103
|
+
if (isBlobUrl) {
|
|
104
|
+
this.blobInnerScheme = match[2].toLowerCase();
|
|
105
|
+
this.scheme = 'blob';
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
this.scheme = match[2].toLowerCase();
|
|
109
|
+
}
|
|
110
|
+
this.user = match[3] ?? '';
|
|
111
|
+
this.host = match[4] ?? '';
|
|
112
|
+
this.port = match[5] ?? '';
|
|
113
|
+
this.path = match[6] ?? '/';
|
|
114
|
+
this.queryParams = match[7] ?? '';
|
|
115
|
+
this.fragment = match[8] ?? '';
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
if (this.url.startsWith('data:')) {
|
|
119
|
+
this.scheme = 'data';
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (this.url.startsWith('blob:')) {
|
|
123
|
+
this.scheme = 'blob';
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (this.url === 'about:blank') {
|
|
127
|
+
this.scheme = 'about';
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
this.path = this.url;
|
|
131
|
+
}
|
|
132
|
+
const lastSlashIndex = this.path.lastIndexOf('/');
|
|
133
|
+
if (lastSlashIndex !== -1) {
|
|
134
|
+
this.folderPathComponents = this.path.substring(0, lastSlashIndex);
|
|
135
|
+
this.lastPathComponent = this.path.substring(lastSlashIndex + 1);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
this.lastPathComponent = this.path;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
static concatenate(devToolsPath, ...appendage) {
|
|
142
|
+
return devToolsPath.concat(...appendage);
|
|
143
|
+
}
|
|
144
|
+
static beginsWithWindowsDriveLetter(url) {
|
|
145
|
+
return /^[A-Za-z]:/.test(url);
|
|
146
|
+
}
|
|
147
|
+
static beginsWithScheme(url) {
|
|
148
|
+
return /^[A-Za-z][A-Za-z0-9+.-]*:/.test(url);
|
|
149
|
+
}
|
|
150
|
+
static isRelativeURL(url) {
|
|
151
|
+
return !this.beginsWithScheme(url) || this.beginsWithWindowsDriveLetter(url);
|
|
152
|
+
}
|
|
153
|
+
get displayName() {
|
|
154
|
+
if (this.#displayNameInternal) {
|
|
155
|
+
return this.#displayNameInternal;
|
|
156
|
+
}
|
|
157
|
+
if (this.isDataURL()) {
|
|
158
|
+
return this.dataURLDisplayName();
|
|
159
|
+
}
|
|
160
|
+
if (this.isBlobURL()) {
|
|
161
|
+
return this.url;
|
|
162
|
+
}
|
|
163
|
+
if (this.isAboutBlank()) {
|
|
164
|
+
return this.url;
|
|
165
|
+
}
|
|
166
|
+
this.#displayNameInternal = this.lastPathComponent;
|
|
167
|
+
if (!this.#displayNameInternal) {
|
|
168
|
+
this.#displayNameInternal = (this.host || '') + '/';
|
|
169
|
+
}
|
|
170
|
+
if (this.#displayNameInternal === '/') {
|
|
171
|
+
this.#displayNameInternal = this.url;
|
|
172
|
+
}
|
|
173
|
+
return this.#displayNameInternal;
|
|
174
|
+
}
|
|
175
|
+
static urlRegexInstance = null;
|
|
176
|
+
}
|
|
177
|
+
exports.ParsedURL = ParsedURL;
|
|
178
|
+
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// generated by yarn build-cdt-lib
|
|
3
|
-
|
|
3
|
+
/* eslint-disable */
|
|
4
4
|
"use strict";
|
|
5
|
+
const Common = require('../Common.js');
|
|
6
|
+
const Platform = require('../Platform.js');
|
|
7
|
+
// Copyright 2021 The Chromium Authors. All rights reserved.
|
|
8
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
9
|
+
// found in the LICENSE file.
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.TextSourceMap = exports.SourceMapEntry = exports.Offset = exports.Section = exports.SourceMapV3 = void 0;
|
|
5
12
|
/*
|
|
6
13
|
* Copyright (C) 2012 Google Inc. All rights reserved.
|
|
7
14
|
*
|
|
@@ -15,7 +22,7 @@ const Platform = require('../Platform.js');
|
|
|
15
22
|
* copyright notice, this list of conditions and the following disclaimer
|
|
16
23
|
* in the documentation and/or other materials provided with the
|
|
17
24
|
* distribution.
|
|
18
|
-
* * Neither the name of Google Inc. nor the names of its
|
|
25
|
+
* * Neither the #name of Google Inc. nor the names of its
|
|
19
26
|
* contributors may be used to endorse or promote products derived from
|
|
20
27
|
* this software without specific prior written permission.
|
|
21
28
|
*
|
|
@@ -31,8 +38,6 @@ const Platform = require('../Platform.js');
|
|
|
31
38
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
32
39
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
33
40
|
*/
|
|
34
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.TextSourceMap = exports.SourceMapEntry = exports.Offset = exports.Section = exports.SourceMapV3 = void 0;
|
|
36
41
|
;
|
|
37
42
|
;
|
|
38
43
|
;
|
|
@@ -43,21 +48,40 @@ exports.TextSourceMap = exports.SourceMapEntry = exports.Offset = exports.Sectio
|
|
|
43
48
|
;
|
|
44
49
|
;
|
|
45
50
|
class SourceMapV3 {
|
|
51
|
+
version;
|
|
52
|
+
file;
|
|
53
|
+
sources;
|
|
54
|
+
sections;
|
|
55
|
+
mappings;
|
|
56
|
+
sourceRoot;
|
|
57
|
+
names;
|
|
58
|
+
sourcesContent;
|
|
46
59
|
constructor() {
|
|
47
60
|
}
|
|
48
61
|
}
|
|
49
62
|
exports.SourceMapV3 = SourceMapV3;
|
|
50
63
|
class Section {
|
|
64
|
+
map;
|
|
65
|
+
offset;
|
|
66
|
+
url;
|
|
51
67
|
constructor() {
|
|
52
68
|
}
|
|
53
69
|
}
|
|
54
70
|
exports.Section = Section;
|
|
55
71
|
class Offset {
|
|
72
|
+
line;
|
|
73
|
+
column;
|
|
56
74
|
constructor() {
|
|
57
75
|
}
|
|
58
76
|
}
|
|
59
77
|
exports.Offset = Offset;
|
|
60
78
|
class SourceMapEntry {
|
|
79
|
+
lineNumber;
|
|
80
|
+
columnNumber;
|
|
81
|
+
sourceURL;
|
|
82
|
+
sourceLineNumber;
|
|
83
|
+
sourceColumnNumber;
|
|
84
|
+
name;
|
|
61
85
|
constructor(lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber, name) {
|
|
62
86
|
this.lineNumber = lineNumber;
|
|
63
87
|
this.columnNumber = columnNumber;
|
|
@@ -81,20 +105,27 @@ for (let i = 0; i < base64Digits.length; ++i) {
|
|
|
81
105
|
}
|
|
82
106
|
const sourceMapToSourceList = new WeakMap();
|
|
83
107
|
class TextSourceMap {
|
|
108
|
+
#initiator;
|
|
109
|
+
#json;
|
|
110
|
+
#compiledURLInternal;
|
|
111
|
+
#sourceMappingURL;
|
|
112
|
+
#baseURL;
|
|
113
|
+
#mappingsInternal;
|
|
114
|
+
#sourceInfos;
|
|
84
115
|
/**
|
|
85
116
|
* Implements Source Map V3 model. See https://github.com/google/closure-compiler/wiki/Source-Maps
|
|
86
117
|
* for format description.
|
|
87
118
|
*/
|
|
88
119
|
constructor(compiledURL, sourceMappingURL, payload, initiator) {
|
|
89
|
-
this
|
|
90
|
-
this
|
|
91
|
-
this
|
|
92
|
-
this
|
|
93
|
-
this
|
|
94
|
-
this
|
|
95
|
-
this
|
|
96
|
-
if (this
|
|
97
|
-
const sectionWithURL = Boolean(this
|
|
120
|
+
this.#initiator = initiator;
|
|
121
|
+
this.#json = payload;
|
|
122
|
+
this.#compiledURLInternal = compiledURL;
|
|
123
|
+
this.#sourceMappingURL = sourceMappingURL;
|
|
124
|
+
this.#baseURL = (sourceMappingURL.startsWith('data:') ? compiledURL : sourceMappingURL);
|
|
125
|
+
this.#mappingsInternal = null;
|
|
126
|
+
this.#sourceInfos = new Map();
|
|
127
|
+
if (this.#json.sections) {
|
|
128
|
+
const sectionWithURL = Boolean(this.#json.sections.find(section => Boolean(section.url)));
|
|
98
129
|
if (sectionWithURL) {
|
|
99
130
|
console.warn(`SourceMap "${sourceMappingURL}" contains unsupported "URL" field in one of its sections.`);
|
|
100
131
|
}
|
|
@@ -102,16 +133,16 @@ class TextSourceMap {
|
|
|
102
133
|
this.eachSection(this.parseSources.bind(this));
|
|
103
134
|
}
|
|
104
135
|
compiledURL() {
|
|
105
|
-
return this
|
|
136
|
+
return this.#compiledURLInternal;
|
|
106
137
|
}
|
|
107
138
|
url() {
|
|
108
|
-
return this
|
|
139
|
+
return this.#sourceMappingURL;
|
|
109
140
|
}
|
|
110
141
|
sourceURLs() {
|
|
111
|
-
return [...this
|
|
142
|
+
return [...this.#sourceInfos.keys()];
|
|
112
143
|
}
|
|
113
144
|
embeddedContentByURL(sourceURL) {
|
|
114
|
-
const entry = this
|
|
145
|
+
const entry = this.#sourceInfos.get(sourceURL);
|
|
115
146
|
if (!entry) {
|
|
116
147
|
return null;
|
|
117
148
|
}
|
|
@@ -123,52 +154,92 @@ class TextSourceMap {
|
|
|
123
154
|
return index ? mappings[index - 1] : null;
|
|
124
155
|
}
|
|
125
156
|
sourceLineMapping(sourceURL, lineNumber, columnNumber) {
|
|
126
|
-
const mappings = this.
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
|
|
157
|
+
const mappings = this.mappings();
|
|
158
|
+
const reverseMappings = this.reversedMappings(sourceURL);
|
|
159
|
+
const first = Platform.ArrayUtilities.lowerBound(reverseMappings, lineNumber, lineComparator);
|
|
160
|
+
const last = Platform.ArrayUtilities.upperBound(reverseMappings, lineNumber, lineComparator);
|
|
161
|
+
if (first >= reverseMappings.length || mappings[reverseMappings[first]].sourceLineNumber !== lineNumber) {
|
|
130
162
|
return null;
|
|
131
163
|
}
|
|
132
|
-
const columnMappings =
|
|
164
|
+
const columnMappings = reverseMappings.slice(first, last);
|
|
133
165
|
if (!columnMappings.length) {
|
|
134
166
|
return null;
|
|
135
167
|
}
|
|
136
|
-
const index = Platform.ArrayUtilities.lowerBound(columnMappings, columnNumber, (columnNumber,
|
|
137
|
-
return index >= columnMappings.length ? columnMappings[columnMappings.length - 1] :
|
|
138
|
-
|
|
139
|
-
|
|
168
|
+
const index = Platform.ArrayUtilities.lowerBound(columnMappings, columnNumber, (columnNumber, i) => columnNumber - mappings[i].sourceColumnNumber);
|
|
169
|
+
return index >= columnMappings.length ? mappings[columnMappings[columnMappings.length - 1]] :
|
|
170
|
+
mappings[columnMappings[index]];
|
|
171
|
+
function lineComparator(lineNumber, i) {
|
|
172
|
+
return lineNumber - mappings[i].sourceLineNumber;
|
|
140
173
|
}
|
|
141
174
|
}
|
|
142
|
-
|
|
143
|
-
const mappings = this.
|
|
144
|
-
const
|
|
175
|
+
findReverseIndices(sourceURL, lineNumber, columnNumber) {
|
|
176
|
+
const mappings = this.mappings();
|
|
177
|
+
const reverseMappings = this.reversedMappings(sourceURL);
|
|
178
|
+
const endIndex = Platform.ArrayUtilities.upperBound(reverseMappings, undefined, (unused, i) => lineNumber - mappings[i].sourceLineNumber || columnNumber - mappings[i].sourceColumnNumber);
|
|
145
179
|
let startIndex = endIndex;
|
|
146
|
-
while (startIndex > 0 &&
|
|
147
|
-
mappings[startIndex - 1].
|
|
180
|
+
while (startIndex > 0 &&
|
|
181
|
+
mappings[reverseMappings[startIndex - 1]].sourceLineNumber ===
|
|
182
|
+
mappings[reverseMappings[endIndex - 1]].sourceLineNumber &&
|
|
183
|
+
mappings[reverseMappings[startIndex - 1]].sourceColumnNumber ===
|
|
184
|
+
mappings[reverseMappings[endIndex - 1]].sourceColumnNumber) {
|
|
148
185
|
--startIndex;
|
|
149
186
|
}
|
|
150
|
-
return
|
|
187
|
+
return reverseMappings.slice(startIndex, endIndex);
|
|
188
|
+
}
|
|
189
|
+
findReverseEntries(sourceURL, lineNumber, columnNumber) {
|
|
190
|
+
const mappings = this.mappings();
|
|
191
|
+
return this.findReverseIndices(sourceURL, lineNumber, columnNumber).map(i => mappings[i]);
|
|
192
|
+
}
|
|
193
|
+
findReverseRanges(sourceURL, lineNumber, columnNumber) {
|
|
194
|
+
const mappings = this.mappings();
|
|
195
|
+
const indices = this.findReverseIndices(sourceURL, lineNumber, columnNumber);
|
|
196
|
+
const ranges = [];
|
|
197
|
+
for (let i = 0; i < indices.length; ++i) {
|
|
198
|
+
const startIndex = indices[i];
|
|
199
|
+
// Merge adjacent ranges.
|
|
200
|
+
let endIndex = startIndex + 1;
|
|
201
|
+
while (i + 1 < indices.length && endIndex === indices[i + 1]) {
|
|
202
|
+
++endIndex;
|
|
203
|
+
++i;
|
|
204
|
+
}
|
|
205
|
+
// Source maps don't contain end positions for entries, but each entry is assumed to
|
|
206
|
+
// span until the following entry. This doesn't work however in case of the last
|
|
207
|
+
// entry, where there's no following entry. We also don't know the number of lines
|
|
208
|
+
// and columns in the original source code (which might not be available at all), so
|
|
209
|
+
// for that case we store the maximum signed 32-bit integer, which is definitely going
|
|
210
|
+
// to be larger than any script we can process and can safely be serialized as part of
|
|
211
|
+
// the skip list we send to V8 with `Debugger.stepOver` (http://crbug.com/1305956).
|
|
212
|
+
const startLine = mappings[startIndex].lineNumber;
|
|
213
|
+
const startColumn = mappings[startIndex].columnNumber;
|
|
214
|
+
const endLine = endIndex < mappings.length ? mappings[endIndex].lineNumber : 2 ** 31 - 1;
|
|
215
|
+
const endColumn = endIndex < mappings.length ? mappings[endIndex].columnNumber : 2 ** 31 - 1;
|
|
216
|
+
ranges.push(new TextUtils.TextRange.TextRange(startLine, startColumn, endLine, endColumn));
|
|
217
|
+
}
|
|
218
|
+
return ranges;
|
|
151
219
|
}
|
|
152
220
|
/** @return {Array<{lineNumber: number, columnNumber: number, sourceURL?: string, sourceLineNumber: number, sourceColumnNumber: number, name?: string, lastColumnNumber?: number}>} */
|
|
153
|
-
mappings() {
|
|
154
|
-
if (this
|
|
155
|
-
this
|
|
221
|
+
mappings() {
|
|
222
|
+
if (this.#mappingsInternal === null) {
|
|
223
|
+
this.#mappingsInternal = [];
|
|
156
224
|
this.eachSection(this.parseMap.bind(this));
|
|
157
|
-
this
|
|
225
|
+
this.#json = null;
|
|
158
226
|
}
|
|
159
|
-
return
|
|
227
|
+
return this.#mappingsInternal;
|
|
160
228
|
}
|
|
161
229
|
reversedMappings(sourceURL) {
|
|
162
|
-
const info = this
|
|
230
|
+
const info = this.#sourceInfos.get(sourceURL);
|
|
163
231
|
if (!info) {
|
|
164
232
|
return [];
|
|
165
233
|
}
|
|
166
234
|
const mappings = this.mappings();
|
|
167
235
|
if (info.reverseMappings === null) {
|
|
168
|
-
|
|
236
|
+
const indexes = Array(mappings.length).fill(0).map((_, i) => i);
|
|
237
|
+
info.reverseMappings = indexes.filter(i => mappings[i].sourceURL === sourceURL).sort(sourceMappingComparator);
|
|
169
238
|
}
|
|
170
239
|
return info.reverseMappings;
|
|
171
|
-
function sourceMappingComparator(
|
|
240
|
+
function sourceMappingComparator(indexA, indexB) {
|
|
241
|
+
const a = mappings[indexA];
|
|
242
|
+
const b = mappings[indexB];
|
|
172
243
|
if (a.sourceLineNumber !== b.sourceLineNumber) {
|
|
173
244
|
return a.sourceLineNumber - b.sourceLineNumber;
|
|
174
245
|
}
|
|
@@ -182,30 +253,43 @@ mappings() {
|
|
|
182
253
|
}
|
|
183
254
|
}
|
|
184
255
|
eachSection(callback) {
|
|
185
|
-
if (!this
|
|
256
|
+
if (!this.#json) {
|
|
186
257
|
return;
|
|
187
258
|
}
|
|
188
|
-
if (!this
|
|
189
|
-
callback(this
|
|
259
|
+
if (!this.#json.sections) {
|
|
260
|
+
callback(this.#json, 0, 0);
|
|
190
261
|
return;
|
|
191
262
|
}
|
|
192
|
-
for (const section of this
|
|
263
|
+
for (const section of this.#json.sections) {
|
|
193
264
|
callback(section.map, section.offset.line, section.offset.column);
|
|
194
265
|
}
|
|
195
266
|
}
|
|
196
267
|
parseSources(sourceMap) {
|
|
197
268
|
const sourcesList = [];
|
|
198
|
-
|
|
199
|
-
if (sourceRoot && !sourceRoot.endsWith('/')) {
|
|
200
|
-
sourceRoot += '/';
|
|
201
|
-
}
|
|
269
|
+
const sourceRoot = sourceMap.sourceRoot || Platform.DevToolsPath.EmptyUrlString;
|
|
202
270
|
for (let i = 0; i < sourceMap.sources.length; ++i) {
|
|
203
|
-
|
|
271
|
+
let href = sourceMap.sources[i];
|
|
272
|
+
// The source map v3 proposal says to prepend the sourceRoot to the source URL
|
|
273
|
+
// and if the resulting URL is not absolute, then resolve the source URL against
|
|
274
|
+
// the source map URL. Appending the sourceRoot (if one exists) is not likely to
|
|
275
|
+
// be meaningful or useful if the source URL is already absolute though. In this
|
|
276
|
+
// case, use the source URL as is without prepending the sourceRoot.
|
|
277
|
+
if (Common.ParsedURL.ParsedURL.isRelativeURL(href)) {
|
|
278
|
+
if (sourceRoot && !sourceRoot.endsWith('/') && href && !href.startsWith('/')) {
|
|
279
|
+
href = Common.ParsedURL.ParsedURL.concatenate(sourceRoot, '/', href);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
href = Common.ParsedURL.ParsedURL.concatenate(sourceRoot, href);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
204
285
|
let url = '' || href;
|
|
205
286
|
const source = sourceMap.sourcesContent && sourceMap.sourcesContent[i];
|
|
206
|
-
if (url === this
|
|
287
|
+
if (url === this.#compiledURLInternal && source) {
|
|
207
288
|
}
|
|
208
|
-
this
|
|
289
|
+
if (this.#sourceInfos.has(url)) {
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
this.#sourceInfos.set(url, new TextSourceMap.SourceInfo(source || null, null));
|
|
209
293
|
sourcesList.push(url);
|
|
210
294
|
}
|
|
211
295
|
sourceMapToSourceList.set(sourceMap, sourcesList);
|
|
@@ -282,27 +366,31 @@ mappings() {
|
|
|
282
366
|
return negative ? -result : result;
|
|
283
367
|
}
|
|
284
368
|
reverseMapTextRange(url, textRange) {
|
|
285
|
-
function comparator(position,
|
|
286
|
-
if (position.lineNumber !==
|
|
287
|
-
return position.lineNumber -
|
|
369
|
+
function comparator(position, mappingIndex) {
|
|
370
|
+
if (position.lineNumber !== mappings[mappingIndex].sourceLineNumber) {
|
|
371
|
+
return position.lineNumber - mappings[mappingIndex].sourceLineNumber;
|
|
288
372
|
}
|
|
289
|
-
return position.columnNumber -
|
|
373
|
+
return position.columnNumber - mappings[mappingIndex].sourceColumnNumber;
|
|
374
|
+
}
|
|
375
|
+
const reverseMappings = this.reversedMappings(url);
|
|
376
|
+
const mappings = this.mappings();
|
|
377
|
+
if (!reverseMappings.length) {
|
|
378
|
+
return null;
|
|
290
379
|
}
|
|
291
|
-
const
|
|
292
|
-
|
|
380
|
+
const startIndex = Platform.ArrayUtilities.lowerBound(reverseMappings, { lineNumber: textRange.startLine, columnNumber: textRange.startColumn }, comparator);
|
|
381
|
+
const endIndex = Platform.ArrayUtilities.upperBound(reverseMappings, { lineNumber: textRange.endLine, columnNumber: textRange.endColumn }, comparator);
|
|
382
|
+
if (endIndex >= reverseMappings.length) {
|
|
293
383
|
return null;
|
|
294
384
|
}
|
|
295
|
-
const
|
|
296
|
-
const
|
|
297
|
-
const startMapping = mappings[startIndex];
|
|
298
|
-
const endMapping = mappings[endIndex];
|
|
385
|
+
const startMapping = mappings[reverseMappings[startIndex]];
|
|
386
|
+
const endMapping = mappings[reverseMappings[endIndex]];
|
|
299
387
|
return new TextUtils.TextRange.TextRange(startMapping.lineNumber, startMapping.columnNumber, endMapping.lineNumber, endMapping.columnNumber);
|
|
300
388
|
}
|
|
301
389
|
mapsOrigin() {
|
|
302
390
|
const mappings = this.mappings();
|
|
303
391
|
if (mappings.length > 0) {
|
|
304
392
|
const firstEntry = mappings[0];
|
|
305
|
-
return
|
|
393
|
+
return firstEntry?.lineNumber === 0 || firstEntry.columnNumber === 0;
|
|
306
394
|
}
|
|
307
395
|
return false;
|
|
308
396
|
}
|
|
@@ -319,6 +407,8 @@ exports.TextSourceMap = TextSourceMap;
|
|
|
319
407
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
320
408
|
TextSourceMap._VLQ_CONTINUATION_MASK = 1 << 5;
|
|
321
409
|
class StringCharIterator {
|
|
410
|
+
string;
|
|
411
|
+
position;
|
|
322
412
|
constructor(string) {
|
|
323
413
|
this.string = string;
|
|
324
414
|
this.position = 0;
|
|
@@ -335,6 +425,8 @@ exports.TextSourceMap = TextSourceMap;
|
|
|
335
425
|
}
|
|
336
426
|
TextSourceMap.StringCharIterator = StringCharIterator;
|
|
337
427
|
class SourceInfo {
|
|
428
|
+
content;
|
|
429
|
+
reverseMappings;
|
|
338
430
|
constructor(content, reverseMappings) {
|
|
339
431
|
this.content = content;
|
|
340
432
|
this.reverseMappings = reverseMappings;
|
|
@@ -343,4 +435,5 @@ exports.TextSourceMap = TextSourceMap;
|
|
|
343
435
|
TextSourceMap.SourceInfo = SourceInfo;
|
|
344
436
|
})(TextSourceMap = exports.TextSourceMap || (exports.TextSourceMap = {}));
|
|
345
437
|
|
|
438
|
+
|
|
346
439
|
module.exports = TextSourceMap;
|