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.
Files changed (30) hide show
  1. package/lighthouse-cli/bin.js +8 -2
  2. package/lighthouse-cli/test/smokehouse/__snapshots__/report-assert-test.js.snap +71 -0
  3. package/lighthouse-cli/test/smokehouse/report-assert-test.js +264 -0
  4. package/lighthouse-cli/test/smokehouse/report-assert.js +39 -35
  5. package/lighthouse-core/audits/byte-efficiency/unused-javascript.js +1 -1
  6. package/lighthouse-core/config/config-helpers.js +15 -0
  7. package/lighthouse-core/fraggle-rock/config/config.js +45 -1
  8. package/lighthouse-core/fraggle-rock/gather/driver.js +13 -5
  9. package/lighthouse-core/fraggle-rock/gather/session.js +23 -67
  10. package/lighthouse-core/gather/driver/navigation.js +1 -1
  11. package/lighthouse-core/gather/driver/network-monitor.js +19 -81
  12. package/lighthouse-core/gather/driver/target-manager.js +110 -45
  13. package/lighthouse-core/gather/driver.js +24 -16
  14. package/lighthouse-core/gather/gatherers/devtools-log.js +7 -11
  15. package/lighthouse-core/gather/gatherers/full-page-screenshot.js +1 -1
  16. package/lighthouse-core/index.js +24 -9
  17. package/lighthouse-core/lib/cdt/Common.js +13 -0
  18. package/lighthouse-core/lib/cdt/Platform.js +3 -0
  19. package/lighthouse-core/lib/cdt/generated/ParsedURL.js +178 -0
  20. package/lighthouse-core/lib/cdt/generated/SourceMap.js +155 -62
  21. package/lighthouse-core/lib/network-recorder.js +9 -18
  22. package/package.json +2 -2
  23. package/third-party/devtools-tests/README.md +14 -0
  24. package/third-party/devtools-tests/e2e/lighthouse/generate-report_test.ts +29 -0
  25. package/third-party/devtools-tests/e2e/lighthouse/indexeddb-warning_test.ts +29 -0
  26. package/third-party/devtools-tests/e2e/resources/lighthouse/lighthouse-storage.html +11 -0
  27. package/third-party/download-content-shell/README.md +1 -0
  28. package/third-party/download-content-shell/download-content-shell.js +6 -1
  29. package/types/gatherer.d.ts +5 -2
  30. package/types/protocol.d.ts +26 -17
@@ -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 generateConfig(configJSON, flags);
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 generateConfig(configJson, flags) {
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
+ };
@@ -52,4 +52,7 @@ module.exports = {
52
52
  lowerBound,
53
53
  upperBound,
54
54
  },
55
+ DevToolsPath: {
56
+ EmptyUrlString: '',
57
+ },
55
58
  };
@@ -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
- const Platform = require('../Platform.js');
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.initiator = initiator;
90
- this.json = payload;
91
- this.compiledURLInternal = compiledURL;
92
- this.sourceMappingURL = sourceMappingURL;
93
- this.baseURL = sourceMappingURL.startsWith('data:') ? compiledURL : sourceMappingURL;
94
- this.mappingsInternal = null;
95
- this.sourceInfos = new Map();
96
- if (this.json.sections) {
97
- const sectionWithURL = Boolean(this.json.sections.find(section => Boolean(section.url)));
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.compiledURLInternal;
136
+ return this.#compiledURLInternal;
106
137
  }
107
138
  url() {
108
- return this.sourceMappingURL;
139
+ return this.#sourceMappingURL;
109
140
  }
110
141
  sourceURLs() {
111
- return [...this.sourceInfos.keys()];
142
+ return [...this.#sourceInfos.keys()];
112
143
  }
113
144
  embeddedContentByURL(sourceURL) {
114
- const entry = this.sourceInfos.get(sourceURL);
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.reversedMappings(sourceURL);
127
- const first = Platform.ArrayUtilities.lowerBound(mappings, lineNumber, lineComparator);
128
- const last = Platform.ArrayUtilities.upperBound(mappings, lineNumber, lineComparator);
129
- if (first >= mappings.length || mappings[first].sourceLineNumber !== lineNumber) {
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 = mappings.slice(first, last);
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, mapping) => columnNumber - mapping.sourceColumnNumber);
137
- return index >= columnMappings.length ? columnMappings[columnMappings.length - 1] : columnMappings[index];
138
- function lineComparator(lineNumber, mapping) {
139
- return lineNumber - mapping.sourceLineNumber;
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
- findReverseEntries(sourceURL, lineNumber, columnNumber) {
143
- const mappings = this.reversedMappings(sourceURL);
144
- const endIndex = Platform.ArrayUtilities.upperBound(mappings, undefined, (unused, entry) => lineNumber - entry.sourceLineNumber || columnNumber - entry.sourceColumnNumber);
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 && mappings[startIndex - 1].sourceLineNumber === mappings[endIndex - 1].sourceLineNumber &&
147
- mappings[startIndex - 1].sourceColumnNumber === mappings[endIndex - 1].sourceColumnNumber) {
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 mappings.slice(startIndex, endIndex);
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.mappingsInternal === null) {
155
- this.mappingsInternal = [];
221
+ mappings() {
222
+ if (this.#mappingsInternal === null) {
223
+ this.#mappingsInternal = [];
156
224
  this.eachSection(this.parseMap.bind(this));
157
- this.json = null;
225
+ this.#json = null;
158
226
  }
159
- return /** @type {!Array<!SourceMapEntry>} */ this.mappingsInternal;
227
+ return this.#mappingsInternal;
160
228
  }
161
229
  reversedMappings(sourceURL) {
162
- const info = this.sourceInfos.get(sourceURL);
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
- info.reverseMappings = mappings.filter(mapping => mapping.sourceURL === sourceURL).sort(sourceMappingComparator);
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(a, b) {
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.json) {
256
+ if (!this.#json) {
186
257
  return;
187
258
  }
188
- if (!this.json.sections) {
189
- callback(this.json, 0, 0);
259
+ if (!this.#json.sections) {
260
+ callback(this.#json, 0, 0);
190
261
  return;
191
262
  }
192
- for (const section of this.json.sections) {
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
- let sourceRoot = sourceMap.sourceRoot || '';
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
- const href = sourceRoot + sourceMap.sources[i];
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.compiledURLInternal && source) {
287
+ if (url === this.#compiledURLInternal && source) {
207
288
  }
208
- this.sourceInfos.set(url, new TextSourceMap.SourceInfo(source || null, null));
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, mapping) {
286
- if (position.lineNumber !== mapping.sourceLineNumber) {
287
- return position.lineNumber - mapping.sourceLineNumber;
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 - mapping.sourceColumnNumber;
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 mappings = this.reversedMappings(url);
292
- if (!mappings.length) {
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 startIndex = Platform.ArrayUtilities.lowerBound(mappings, { lineNumber: textRange.startLine, columnNumber: textRange.startColumn }, comparator);
296
- const endIndex = Platform.ArrayUtilities.upperBound(mappings, { lineNumber: textRange.endLine, columnNumber: textRange.endColumn }, comparator);
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 (firstEntry === null || firstEntry === void 0 ? void 0 : firstEntry.lineNumber) === 0 || firstEntry.columnNumber === 0;
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;