OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
11 * copyright notice, this list of conditions and the following disclaimer | 11 * copyright notice, this list of conditions and the following disclaimer |
12 * in the documentation and/or other materials provided with the | 12 * in the documentation and/or other materials provided with the |
13 * distribution. | 13 * distribution. |
14 * * Neither the name of Google Inc. nor the names of its | 14 * * Neither the name of Google Inc. nor the names of its |
15 * contributors may be used to endorse or promote products derived from | 15 * contributors may be used to endorse or promote products derived from |
16 * this software without specific prior written permission. | 16 * this software without specific prior written permission. |
17 * | 17 * |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | |
31 /** | 30 /** |
32 * @constructor | 31 * @unrestricted |
33 */ | 32 */ |
34 function SourceMapV3() | 33 var SourceMapV3 = class { |
35 { | 34 constructor() { |
36 /** @type {number} */ this.version; | 35 /** @type {number} */ this.version; |
37 /** @type {string|undefined} */ this.file; | 36 /** @type {string|undefined} */ this.file; |
38 /** @type {!Array.<string>} */ this.sources; | 37 /** @type {!Array.<string>} */ this.sources; |
39 /** @type {!Array.<!SourceMapV3.Section>|undefined} */ this.sections; | 38 /** @type {!Array.<!SourceMapV3.Section>|undefined} */ this.sections; |
40 /** @type {string} */ this.mappings; | 39 /** @type {string} */ this.mappings; |
41 /** @type {string|undefined} */ this.sourceRoot; | 40 /** @type {string|undefined} */ this.sourceRoot; |
42 /** @type {!Array.<string>|undefined} */ this.names; | 41 /** @type {!Array.<string>|undefined} */ this.names; |
43 } | 42 } |
44 | |
45 /** | |
46 * @constructor | |
47 */ | |
48 SourceMapV3.Section = function() | |
49 { | |
50 /** @type {!SourceMapV3} */ this.map; | |
51 /** @type {!SourceMapV3.Offset} */ this.offset; | |
52 }; | 43 }; |
53 | 44 |
54 /** | 45 /** |
55 * @constructor | 46 * @unrestricted |
56 */ | 47 */ |
57 SourceMapV3.Offset = function() | 48 SourceMapV3.Section = class { |
58 { | 49 constructor() { |
59 /** @type {number} */ this.line; | 50 /** @type {!SourceMapV3} */ this.map; |
60 /** @type {number} */ this.column; | 51 /** @type {!SourceMapV3.Offset} */ this.offset; |
| 52 } |
61 }; | 53 }; |
62 | 54 |
63 /** | 55 /** |
64 * @constructor | 56 * @unrestricted |
65 * @param {number} lineNumber | |
66 * @param {number} columnNumber | |
67 * @param {string=} sourceURL | |
68 * @param {number=} sourceLineNumber | |
69 * @param {number=} sourceColumnNumber | |
70 * @param {string=} name | |
71 */ | 57 */ |
72 WebInspector.SourceMapEntry = function(lineNumber, columnNumber, sourceURL, sour
ceLineNumber, sourceColumnNumber, name) | 58 SourceMapV3.Offset = class { |
73 { | 59 constructor() { |
| 60 /** @type {number} */ this.line; |
| 61 /** @type {number} */ this.column; |
| 62 } |
| 63 }; |
| 64 |
| 65 /** |
| 66 * @unrestricted |
| 67 */ |
| 68 WebInspector.SourceMapEntry = class { |
| 69 /** |
| 70 * @param {number} lineNumber |
| 71 * @param {number} columnNumber |
| 72 * @param {string=} sourceURL |
| 73 * @param {number=} sourceLineNumber |
| 74 * @param {number=} sourceColumnNumber |
| 75 * @param {string=} name |
| 76 */ |
| 77 constructor(lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColum
nNumber, name) { |
74 this.lineNumber = lineNumber; | 78 this.lineNumber = lineNumber; |
75 this.columnNumber = columnNumber; | 79 this.columnNumber = columnNumber; |
76 this.sourceURL = sourceURL; | 80 this.sourceURL = sourceURL; |
77 this.sourceLineNumber = sourceLineNumber; | 81 this.sourceLineNumber = sourceLineNumber; |
78 this.sourceColumnNumber = sourceColumnNumber; | 82 this.sourceColumnNumber = sourceColumnNumber; |
79 this.name = name; | 83 this.name = name; |
| 84 } |
80 }; | 85 }; |
81 | 86 |
82 /** | 87 /** |
83 * @interface | 88 * @interface |
84 */ | 89 */ |
85 WebInspector.SourceMap = function() { }; | 90 WebInspector.SourceMap = function() {}; |
86 | 91 |
87 WebInspector.SourceMap.prototype = { | 92 WebInspector.SourceMap.prototype = { |
88 /** | 93 /** |
89 * @return {string} | 94 * @return {string} |
90 */ | 95 */ |
91 compiledURL: function() { }, | 96 compiledURL: function() {}, |
92 | 97 |
93 /** | 98 /** |
94 * @return {string} | 99 * @return {string} |
95 */ | 100 */ |
96 url: function() { }, | 101 url: function() {}, |
97 | 102 |
98 /** | 103 /** |
99 * @return {!Array<string>} | 104 * @return {!Array<string>} |
100 */ | 105 */ |
101 sourceURLs: function() { }, | 106 sourceURLs: function() {}, |
102 | 107 |
103 /** | 108 /** |
104 * @param {string} sourceURL | 109 * @param {string} sourceURL |
105 * @param {!WebInspector.ResourceType} contentType | 110 * @param {!WebInspector.ResourceType} contentType |
106 * @return {!WebInspector.ContentProvider} | 111 * @return {!WebInspector.ContentProvider} |
107 */ | 112 */ |
108 sourceContentProvider: function(sourceURL, contentType) { }, | 113 sourceContentProvider: function(sourceURL, contentType) {}, |
109 | 114 |
110 /** | 115 /** |
111 * @param {string} sourceURL | 116 * @param {string} sourceURL |
112 * @return {?string} | 117 * @return {?string} |
113 */ | 118 */ |
114 embeddedContentByURL: function(sourceURL) { }, | 119 embeddedContentByURL: function(sourceURL) {}, |
115 | 120 |
116 /** | 121 /** |
117 * @param {number} lineNumber in compiled resource | 122 * @param {number} lineNumber in compiled resource |
118 * @param {number} columnNumber in compiled resource | 123 * @param {number} columnNumber in compiled resource |
119 * @return {?WebInspector.SourceMapEntry} | 124 * @return {?WebInspector.SourceMapEntry} |
120 */ | 125 */ |
121 findEntry: function(lineNumber, columnNumber) { }, | 126 findEntry: function(lineNumber, columnNumber) {}, |
122 | 127 |
123 /** | 128 /** |
124 * @return {boolean} | 129 * @return {boolean} |
125 */ | 130 */ |
126 editable: function() { }, | 131 editable: function() {}, |
127 | 132 |
128 /** | 133 /** |
129 * @param {!Array<!WebInspector.TextRange>} ranges | 134 * @param {!Array<!WebInspector.TextRange>} ranges |
130 * @param {!Array<string>} texts | 135 * @param {!Array<string>} texts |
131 * @return {!Promise<?WebInspector.SourceMap.EditResult>} | 136 * @return {!Promise<?WebInspector.SourceMap.EditResult>} |
132 */ | 137 */ |
133 editCompiled: function(ranges, texts) { }, | 138 editCompiled: function(ranges, texts) {}, |
134 }; | 139 }; |
135 | 140 |
136 /** | 141 /** |
137 * @constructor | 142 * @unrestricted |
138 * @param {!WebInspector.SourceMap} map | |
139 * @param {!Array<!WebInspector.SourceEdit>} compiledEdits | |
140 * @param {!Map<string, string>} newSources | |
141 */ | 143 */ |
142 WebInspector.SourceMap.EditResult = function(map, compiledEdits, newSources) | 144 WebInspector.SourceMap.EditResult = class { |
143 { | 145 /** |
| 146 * @param {!WebInspector.SourceMap} map |
| 147 * @param {!Array<!WebInspector.SourceEdit>} compiledEdits |
| 148 * @param {!Map<string, string>} newSources |
| 149 */ |
| 150 constructor(map, compiledEdits, newSources) { |
144 this.map = map; | 151 this.map = map; |
145 this.compiledEdits = compiledEdits; | 152 this.compiledEdits = compiledEdits; |
146 this.newSources = newSources; | 153 this.newSources = newSources; |
| 154 } |
147 }; | 155 }; |
148 | 156 |
149 /** | 157 /** |
150 * @interface | 158 * @interface |
151 */ | 159 */ |
152 WebInspector.SourceMapFactory = function() { }; | 160 WebInspector.SourceMapFactory = function() {}; |
153 | 161 |
154 WebInspector.SourceMapFactory.prototype = { | 162 WebInspector.SourceMapFactory.prototype = { |
155 /** | 163 /** |
156 * @param {!WebInspector.Target} target | 164 * @param {!WebInspector.Target} target |
157 * @param {!WebInspector.SourceMap} sourceMap | 165 * @param {!WebInspector.SourceMap} sourceMap |
158 * @return {!Promise<?WebInspector.SourceMap>} | 166 * @return {!Promise<?WebInspector.SourceMap>} |
159 */ | 167 */ |
160 editableSourceMap: function(target, sourceMap) { }, | 168 editableSourceMap: function(target, sourceMap) {}, |
161 }; | 169 }; |
162 | 170 |
163 /** | 171 /** |
164 * Implements Source Map V3 model. See https://github.com/google/closure-compile
r/wiki/Source-Maps | |
165 * for format description. | |
166 * @constructor | |
167 * @implements {WebInspector.SourceMap} | 172 * @implements {WebInspector.SourceMap} |
168 * @param {string} compiledURL | 173 * @unrestricted |
169 * @param {string} sourceMappingURL | |
170 * @param {!SourceMapV3} payload | |
171 */ | 174 */ |
172 WebInspector.TextSourceMap = function(compiledURL, sourceMappingURL, payload) | 175 WebInspector.TextSourceMap = class { |
173 { | 176 /** |
174 if (!WebInspector.TextSourceMap.prototype._base64Map) { | 177 * Implements Source Map V3 model. See https://github.com/google/closure-compi
ler/wiki/Source-Maps |
175 const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx
yz0123456789+/"; | 178 * for format description. |
176 WebInspector.TextSourceMap.prototype._base64Map = {}; | 179 * @param {string} compiledURL |
177 for (var i = 0; i < base64Digits.length; ++i) | 180 * @param {string} sourceMappingURL |
178 WebInspector.TextSourceMap.prototype._base64Map[base64Digits.charAt(
i)] = i; | 181 * @param {!SourceMapV3} payload |
| 182 */ |
| 183 constructor(compiledURL, sourceMappingURL, payload) { |
| 184 if (!WebInspector.TextSourceMap._base64Map) { |
| 185 const base64Digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789+/'; |
| 186 WebInspector.TextSourceMap._base64Map = {}; |
| 187 for (var i = 0; i < base64Digits.length; ++i) |
| 188 WebInspector.TextSourceMap._base64Map[base64Digits.charAt(i)] = i; |
179 } | 189 } |
180 | 190 |
181 this._json = payload; | 191 this._json = payload; |
182 this._compiledURL = compiledURL; | 192 this._compiledURL = compiledURL; |
183 this._sourceMappingURL = sourceMappingURL; | 193 this._sourceMappingURL = sourceMappingURL; |
184 /** @type {?Array<!WebInspector.SourceMapEntry>} */ | 194 /** @type {?Array<!WebInspector.SourceMapEntry>} */ |
185 this._mappings = null; | 195 this._mappings = null; |
186 /** @type {!Map<string, !WebInspector.TextSourceMap.SourceInfo>} */ | 196 /** @type {!Map<string, !WebInspector.TextSourceMap.SourceInfo>} */ |
187 this._sourceInfos = new Map(); | 197 this._sourceInfos = new Map(); |
188 this._eachSection(this._parseSources.bind(this)); | 198 this._eachSection(this._parseSources.bind(this)); |
189 }; | 199 } |
190 | 200 |
191 /** | 201 /** |
192 * @param {string} sourceMapURL | 202 * @param {string} sourceMapURL |
193 * @param {string} compiledURL | 203 * @param {string} compiledURL |
194 * @return {!Promise<?WebInspector.TextSourceMap>} | 204 * @return {!Promise<?WebInspector.TextSourceMap>} |
195 * @this {WebInspector.TextSourceMap} | 205 * @this {WebInspector.TextSourceMap} |
196 */ | 206 */ |
197 WebInspector.TextSourceMap.load = function(sourceMapURL, compiledURL) | 207 static load(sourceMapURL, compiledURL) { |
198 { | |
199 var callback; | 208 var callback; |
200 var promise = new Promise(fulfill => callback = fulfill); | 209 var promise = new Promise(fulfill => callback = fulfill); |
201 WebInspector.multitargetNetworkManager.loadResource(sourceMapURL, contentLoa
ded); | 210 WebInspector.multitargetNetworkManager.loadResource(sourceMapURL, contentLoa
ded); |
202 return promise; | 211 return promise; |
203 | 212 |
204 /** | 213 /** |
205 * @param {number} statusCode | 214 * @param {number} statusCode |
206 * @param {!Object.<string, string>} headers | 215 * @param {!Object.<string, string>} headers |
207 * @param {string} content | 216 * @param {string} content |
208 */ | 217 */ |
209 function contentLoaded(statusCode, headers, content) | 218 function contentLoaded(statusCode, headers, content) { |
210 { | 219 if (!content || statusCode >= 400) { |
211 if (!content || statusCode >= 400) { | 220 callback(null); |
212 callback(null); | 221 return; |
213 return; | 222 } |
214 } | 223 |
215 | 224 if (content.slice(0, 3) === ')]}') |
216 if (content.slice(0, 3) === ")]}") | 225 content = content.substring(content.indexOf('\n')); |
217 content = content.substring(content.indexOf("\n")); | 226 try { |
218 try { | 227 var payload = /** @type {!SourceMapV3} */ (JSON.parse(content)); |
219 var payload = /** @type {!SourceMapV3} */ (JSON.parse(content)); | 228 var baseURL = sourceMapURL.startsWith('data:') ? compiledURL : sourceMap
URL; |
220 var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourc
eMapURL; | 229 callback(new WebInspector.TextSourceMap(compiledURL, baseURL, payload)); |
221 callback(new WebInspector.TextSourceMap(compiledURL, baseURL, payloa
d)); | 230 } catch (e) { |
222 } catch (e) { | 231 console.error(e); |
223 console.error(e); | 232 WebInspector.console.warn('DevTools failed to parse SourceMap: ' + sourc
eMapURL); |
224 WebInspector.console.warn("DevTools failed to parse SourceMap: " + s
ourceMapURL); | 233 callback(null); |
225 callback(null); | 234 } |
226 } | 235 } |
227 } | 236 } |
228 }; | 237 |
229 | 238 /** |
230 WebInspector.TextSourceMap.prototype = { | 239 * @override |
| 240 * @return {string} |
| 241 */ |
| 242 compiledURL() { |
| 243 return this._compiledURL; |
| 244 } |
| 245 |
| 246 /** |
| 247 * @override |
| 248 * @return {string} |
| 249 */ |
| 250 url() { |
| 251 return this._sourceMappingURL; |
| 252 } |
| 253 |
| 254 /** |
| 255 * @override |
| 256 * @return {!Array.<string>} |
| 257 */ |
| 258 sourceURLs() { |
| 259 return this._sourceInfos.keysArray(); |
| 260 } |
| 261 |
| 262 /** |
| 263 * @override |
| 264 * @param {string} sourceURL |
| 265 * @param {!WebInspector.ResourceType} contentType |
| 266 * @return {!WebInspector.ContentProvider} |
| 267 */ |
| 268 sourceContentProvider(sourceURL, contentType) { |
| 269 var info = this._sourceInfos.get(sourceURL); |
| 270 if (info.content) |
| 271 return WebInspector.StaticContentProvider.fromString(sourceURL, contentTyp
e, info.content); |
| 272 return new WebInspector.CompilerSourceMappingContentProvider(sourceURL, cont
entType); |
| 273 } |
| 274 |
| 275 /** |
| 276 * @override |
| 277 * @param {string} sourceURL |
| 278 * @return {?string} |
| 279 */ |
| 280 embeddedContentByURL(sourceURL) { |
| 281 if (!this._sourceInfos.has(sourceURL)) |
| 282 return null; |
| 283 return this._sourceInfos.get(sourceURL).content; |
| 284 } |
| 285 |
| 286 /** |
| 287 * @override |
| 288 * @return {boolean} |
| 289 */ |
| 290 editable() { |
| 291 return false; |
| 292 } |
| 293 |
| 294 /** |
| 295 * @override |
| 296 * @param {!Array<!WebInspector.TextRange>} ranges |
| 297 * @param {!Array<string>} texts |
| 298 * @return {!Promise<?WebInspector.SourceMap.EditResult>} |
| 299 */ |
| 300 editCompiled(ranges, texts) { |
| 301 return Promise.resolve(/** @type {?WebInspector.SourceMap.EditResult} */ (nu
ll)); |
| 302 } |
| 303 |
| 304 /** |
| 305 * @override |
| 306 * @param {number} lineNumber in compiled resource |
| 307 * @param {number} columnNumber in compiled resource |
| 308 * @return {?WebInspector.SourceMapEntry} |
| 309 */ |
| 310 findEntry(lineNumber, columnNumber) { |
| 311 var first = 0; |
| 312 var mappings = this.mappings(); |
| 313 var count = mappings.length; |
| 314 while (count > 1) { |
| 315 var step = count >> 1; |
| 316 var middle = first + step; |
| 317 var mapping = mappings[middle]; |
| 318 if (lineNumber < mapping.lineNumber || |
| 319 (lineNumber === mapping.lineNumber && columnNumber < mapping.columnNum
ber)) { |
| 320 count = step; |
| 321 } else { |
| 322 first = middle; |
| 323 count -= step; |
| 324 } |
| 325 } |
| 326 var entry = mappings[first]; |
| 327 if (!first && entry && |
| 328 (lineNumber < entry.lineNumber || (lineNumber === entry.lineNumber && co
lumnNumber < entry.columnNumber))) |
| 329 return null; |
| 330 return entry; |
| 331 } |
| 332 |
| 333 /** |
| 334 * @param {string} sourceURL |
| 335 * @param {number} lineNumber |
| 336 * @return {?WebInspector.SourceMapEntry} |
| 337 */ |
| 338 firstSourceLineMapping(sourceURL, lineNumber) { |
| 339 var mappings = this._reversedMappings(sourceURL); |
| 340 var index = mappings.lowerBound(lineNumber, lineComparator); |
| 341 if (index >= mappings.length || mappings[index].sourceLineNumber !== lineNum
ber) |
| 342 return null; |
| 343 return mappings[index]; |
| 344 |
231 /** | 345 /** |
232 * @override | |
233 * @return {string} | |
234 */ | |
235 compiledURL: function() | |
236 { | |
237 return this._compiledURL; | |
238 }, | |
239 | |
240 /** | |
241 * @override | |
242 * @return {string} | |
243 */ | |
244 url: function() | |
245 { | |
246 return this._sourceMappingURL; | |
247 }, | |
248 | |
249 /** | |
250 * @override | |
251 * @return {!Array.<string>} | |
252 */ | |
253 sourceURLs: function() | |
254 { | |
255 return this._sourceInfos.keysArray(); | |
256 }, | |
257 | |
258 /** | |
259 * @override | |
260 * @param {string} sourceURL | |
261 * @param {!WebInspector.ResourceType} contentType | |
262 * @return {!WebInspector.ContentProvider} | |
263 */ | |
264 sourceContentProvider: function(sourceURL, contentType) | |
265 { | |
266 var info = this._sourceInfos.get(sourceURL); | |
267 if (info.content) | |
268 return WebInspector.StaticContentProvider.fromString(sourceURL, cont
entType, info.content); | |
269 return new WebInspector.CompilerSourceMappingContentProvider(sourceURL,
contentType); | |
270 }, | |
271 | |
272 /** | |
273 * @override | |
274 * @param {string} sourceURL | |
275 * @return {?string} | |
276 */ | |
277 embeddedContentByURL: function(sourceURL) | |
278 { | |
279 if (!this._sourceInfos.has(sourceURL)) | |
280 return null; | |
281 return this._sourceInfos.get(sourceURL).content; | |
282 }, | |
283 | |
284 /** | |
285 * @override | |
286 * @return {boolean} | |
287 */ | |
288 editable: function() | |
289 { | |
290 return false; | |
291 }, | |
292 | |
293 /** | |
294 * @override | |
295 * @param {!Array<!WebInspector.TextRange>} ranges | |
296 * @param {!Array<string>} texts | |
297 * @return {!Promise<?WebInspector.SourceMap.EditResult>} | |
298 */ | |
299 editCompiled: function(ranges, texts) | |
300 { | |
301 return Promise.resolve(/** @type {?WebInspector.SourceMap.EditResult} */
(null)); | |
302 }, | |
303 | |
304 /** | |
305 * @override | |
306 * @param {number} lineNumber in compiled resource | |
307 * @param {number} columnNumber in compiled resource | |
308 * @return {?WebInspector.SourceMapEntry} | |
309 */ | |
310 findEntry: function(lineNumber, columnNumber) | |
311 { | |
312 var first = 0; | |
313 var mappings = this.mappings(); | |
314 var count = mappings.length; | |
315 while (count > 1) { | |
316 var step = count >> 1; | |
317 var middle = first + step; | |
318 var mapping = mappings[middle]; | |
319 if (lineNumber < mapping.lineNumber || (lineNumber === mapping.lineN
umber && columnNumber < mapping.columnNumber)) { | |
320 count = step; | |
321 } else { | |
322 first = middle; | |
323 count -= step; | |
324 } | |
325 } | |
326 var entry = mappings[first]; | |
327 if (!first && entry && (lineNumber < entry.lineNumber || (lineNumber ===
entry.lineNumber && columnNumber < entry.columnNumber))) | |
328 return null; | |
329 return entry; | |
330 }, | |
331 | |
332 /** | |
333 * @param {string} sourceURL | |
334 * @param {number} lineNumber | 346 * @param {number} lineNumber |
335 * @return {?WebInspector.SourceMapEntry} | 347 * @param {!WebInspector.SourceMapEntry} mapping |
336 */ | |
337 firstSourceLineMapping: function(sourceURL, lineNumber) | |
338 { | |
339 var mappings = this._reversedMappings(sourceURL); | |
340 var index = mappings.lowerBound(lineNumber, lineComparator); | |
341 if (index >= mappings.length || mappings[index].sourceLineNumber !== lin
eNumber) | |
342 return null; | |
343 return mappings[index]; | |
344 | |
345 /** | |
346 * @param {number} lineNumber | |
347 * @param {!WebInspector.SourceMapEntry} mapping | |
348 * @return {number} | |
349 */ | |
350 function lineComparator(lineNumber, mapping) | |
351 { | |
352 return lineNumber - mapping.sourceLineNumber; | |
353 } | |
354 }, | |
355 | |
356 /** | |
357 * @return {!Array<!WebInspector.SourceMapEntry>} | |
358 */ | |
359 mappings: function() | |
360 { | |
361 if (this._mappings === null) { | |
362 this._mappings = []; | |
363 this._eachSection(this._parseMap.bind(this)); | |
364 this._json = null; | |
365 } | |
366 return /** @type {!Array<!WebInspector.SourceMapEntry>} */ (this._mappin
gs); | |
367 }, | |
368 | |
369 /** | |
370 * @param {string} sourceURL | |
371 * @return {!Array.<!WebInspector.SourceMapEntry>} | |
372 */ | |
373 _reversedMappings: function(sourceURL) | |
374 { | |
375 if (!this._sourceInfos.has(sourceURL)) | |
376 return []; | |
377 var mappings = this.mappings(); | |
378 var info = this._sourceInfos.get(sourceURL); | |
379 if (info.reverseMappings === null) | |
380 info.reverseMappings = mappings.filter((mapping) => mapping.sourceUR
L === sourceURL).sort(sourceMappingComparator); | |
381 return info.reverseMappings; | |
382 | |
383 /** | |
384 * @param {!WebInspector.SourceMapEntry} a | |
385 * @param {!WebInspector.SourceMapEntry} b | |
386 * @return {number} | |
387 */ | |
388 function sourceMappingComparator(a, b) | |
389 { | |
390 if (a.sourceLineNumber !== b.sourceLineNumber) | |
391 return a.sourceLineNumber - b.sourceLineNumber; | |
392 if (a.sourceColumnNumber !== b.sourceColumnNumber) | |
393 return a.sourceColumnNumber - b.sourceColumnNumber; | |
394 | |
395 if (a.lineNumber !== b.lineNumber) | |
396 return a.lineNumber - b.lineNumber; | |
397 | |
398 return a.columnNumber - b.columnNumber; | |
399 } | |
400 }, | |
401 | |
402 /** | |
403 * @param {function(!SourceMapV3, number, number)} callback | |
404 */ | |
405 _eachSection: function(callback) { | |
406 if (!this._json.sections) { | |
407 callback(this._json, 0, 0); | |
408 return; | |
409 } | |
410 for (var section of this._json.sections) | |
411 callback(section.map, section.offset.line, section.offset.column); | |
412 }, | |
413 | |
414 /** | |
415 * @param {!SourceMapV3} sourceMap | |
416 */ | |
417 _parseSources: function(sourceMap) { | |
418 var sourcesList = []; | |
419 var sourceRoot = sourceMap.sourceRoot || ""; | |
420 if (sourceRoot && !sourceRoot.endsWith("/")) | |
421 sourceRoot += "/"; | |
422 for (var i = 0; i < sourceMap.sources.length; ++i) { | |
423 var href = sourceRoot + sourceMap.sources[i]; | |
424 var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL,
href) || href; | |
425 var source = sourceMap.sourcesContent && sourceMap.sourcesContent[i]
; | |
426 if (url === this._compiledURL && source) | |
427 url += WebInspector.UIString(" [sm]"); | |
428 this._sourceInfos.set(url, new WebInspector.TextSourceMap.SourceInfo
(source, null)); | |
429 sourcesList.push(url); | |
430 } | |
431 sourceMap[WebInspector.TextSourceMap._sourcesListSymbol] = sourcesList; | |
432 }, | |
433 | |
434 /** | |
435 * @param {!SourceMapV3} map | |
436 * @param {number} lineNumber | |
437 * @param {number} columnNumber | |
438 */ | |
439 _parseMap: function(map, lineNumber, columnNumber) | |
440 { | |
441 var sourceIndex = 0; | |
442 var sourceLineNumber = 0; | |
443 var sourceColumnNumber = 0; | |
444 var nameIndex = 0; | |
445 var sources = map[WebInspector.TextSourceMap._sourcesListSymbol]; | |
446 var names = map.names || []; | |
447 var stringCharIterator = new WebInspector.TextSourceMap.StringCharIterat
or(map.mappings); | |
448 var sourceURL = sources[sourceIndex]; | |
449 | |
450 while (true) { | |
451 if (stringCharIterator.peek() === ",") | |
452 stringCharIterator.next(); | |
453 else { | |
454 while (stringCharIterator.peek() === ";") { | |
455 lineNumber += 1; | |
456 columnNumber = 0; | |
457 stringCharIterator.next(); | |
458 } | |
459 if (!stringCharIterator.hasNext()) | |
460 break; | |
461 } | |
462 | |
463 columnNumber += this._decodeVLQ(stringCharIterator); | |
464 if (!stringCharIterator.hasNext() || this._isSeparator(stringCharIte
rator.peek())) { | |
465 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber,
columnNumber)); | |
466 continue; | |
467 } | |
468 | |
469 var sourceIndexDelta = this._decodeVLQ(stringCharIterator); | |
470 if (sourceIndexDelta) { | |
471 sourceIndex += sourceIndexDelta; | |
472 sourceURL = sources[sourceIndex]; | |
473 } | |
474 sourceLineNumber += this._decodeVLQ(stringCharIterator); | |
475 sourceColumnNumber += this._decodeVLQ(stringCharIterator); | |
476 | |
477 if (!stringCharIterator.hasNext() || this._isSeparator(stringCharIte
rator.peek())) { | |
478 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber,
columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber)); | |
479 continue; | |
480 } | |
481 | |
482 nameIndex += this._decodeVLQ(stringCharIterator); | |
483 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, colu
mnNumber, sourceURL, sourceLineNumber, sourceColumnNumber, names[nameIndex])); | |
484 } | |
485 }, | |
486 | |
487 /** | |
488 * @param {string} char | |
489 * @return {boolean} | |
490 */ | |
491 _isSeparator: function(char) | |
492 { | |
493 return char === "," || char === ";"; | |
494 }, | |
495 | |
496 /** | |
497 * @param {!WebInspector.TextSourceMap.StringCharIterator} stringCharIterato
r | |
498 * @return {number} | 348 * @return {number} |
499 */ | 349 */ |
500 _decodeVLQ: function(stringCharIterator) | 350 function lineComparator(lineNumber, mapping) { |
501 { | 351 return lineNumber - mapping.sourceLineNumber; |
502 // Read unsigned value. | 352 } |
503 var result = 0; | 353 } |
504 var shift = 0; | 354 |
505 do { | 355 /** |
506 var digit = this._base64Map[stringCharIterator.next()]; | 356 * @return {!Array<!WebInspector.SourceMapEntry>} |
507 result += (digit & this._VLQ_BASE_MASK) << shift; | 357 */ |
508 shift += this._VLQ_BASE_SHIFT; | 358 mappings() { |
509 } while (digit & this._VLQ_CONTINUATION_MASK); | 359 if (this._mappings === null) { |
510 | 360 this._mappings = []; |
511 // Fix the sign. | 361 this._eachSection(this._parseMap.bind(this)); |
512 var negative = result & 1; | 362 this._json = null; |
513 result >>= 1; | 363 } |
514 return negative ? -result : result; | 364 return /** @type {!Array<!WebInspector.SourceMapEntry>} */ (this._mappings); |
515 }, | 365 } |
| 366 |
| 367 /** |
| 368 * @param {string} sourceURL |
| 369 * @return {!Array.<!WebInspector.SourceMapEntry>} |
| 370 */ |
| 371 _reversedMappings(sourceURL) { |
| 372 if (!this._sourceInfos.has(sourceURL)) |
| 373 return []; |
| 374 var mappings = this.mappings(); |
| 375 var info = this._sourceInfos.get(sourceURL); |
| 376 if (info.reverseMappings === null) |
| 377 info.reverseMappings = |
| 378 mappings.filter((mapping) => mapping.sourceURL === sourceURL).sort(sou
rceMappingComparator); |
| 379 return info.reverseMappings; |
516 | 380 |
517 /** | 381 /** |
518 * @param {string} url | 382 * @param {!WebInspector.SourceMapEntry} a |
519 * @param {!WebInspector.TextRange} textRange | 383 * @param {!WebInspector.SourceMapEntry} b |
520 * @return {!WebInspector.TextRange} | 384 * @return {number} |
521 */ | 385 */ |
522 reverseMapTextRange: function(url, textRange) | 386 function sourceMappingComparator(a, b) { |
523 { | 387 if (a.sourceLineNumber !== b.sourceLineNumber) |
524 /** | 388 return a.sourceLineNumber - b.sourceLineNumber; |
525 * @param {!{lineNumber: number, columnNumber: number}} position | 389 if (a.sourceColumnNumber !== b.sourceColumnNumber) |
526 * @param {!WebInspector.SourceMapEntry} mapping | 390 return a.sourceColumnNumber - b.sourceColumnNumber; |
527 * @return {number} | 391 |
528 */ | 392 if (a.lineNumber !== b.lineNumber) |
529 function comparator(position, mapping) | 393 return a.lineNumber - b.lineNumber; |
530 { | 394 |
531 if (position.lineNumber !== mapping.sourceLineNumber) | 395 return a.columnNumber - b.columnNumber; |
532 return position.lineNumber - mapping.sourceLineNumber; | 396 } |
533 | 397 } |
534 return position.columnNumber - mapping.sourceColumnNumber; | 398 |
| 399 /** |
| 400 * @param {function(!SourceMapV3, number, number)} callback |
| 401 */ |
| 402 _eachSection(callback) { |
| 403 if (!this._json.sections) { |
| 404 callback(this._json, 0, 0); |
| 405 return; |
| 406 } |
| 407 for (var section of this._json.sections) |
| 408 callback(section.map, section.offset.line, section.offset.column); |
| 409 } |
| 410 |
| 411 /** |
| 412 * @param {!SourceMapV3} sourceMap |
| 413 */ |
| 414 _parseSources(sourceMap) { |
| 415 var sourcesList = []; |
| 416 var sourceRoot = sourceMap.sourceRoot || ''; |
| 417 if (sourceRoot && !sourceRoot.endsWith('/')) |
| 418 sourceRoot += '/'; |
| 419 for (var i = 0; i < sourceMap.sources.length; ++i) { |
| 420 var href = sourceRoot + sourceMap.sources[i]; |
| 421 var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href)
|| href; |
| 422 var source = sourceMap.sourcesContent && sourceMap.sourcesContent[i]; |
| 423 if (url === this._compiledURL && source) |
| 424 url += WebInspector.UIString(' [sm]'); |
| 425 this._sourceInfos.set(url, new WebInspector.TextSourceMap.SourceInfo(sourc
e, null)); |
| 426 sourcesList.push(url); |
| 427 } |
| 428 sourceMap[WebInspector.TextSourceMap._sourcesListSymbol] = sourcesList; |
| 429 } |
| 430 |
| 431 /** |
| 432 * @param {!SourceMapV3} map |
| 433 * @param {number} lineNumber |
| 434 * @param {number} columnNumber |
| 435 */ |
| 436 _parseMap(map, lineNumber, columnNumber) { |
| 437 var sourceIndex = 0; |
| 438 var sourceLineNumber = 0; |
| 439 var sourceColumnNumber = 0; |
| 440 var nameIndex = 0; |
| 441 var sources = map[WebInspector.TextSourceMap._sourcesListSymbol]; |
| 442 var names = map.names || []; |
| 443 var stringCharIterator = new WebInspector.TextSourceMap.StringCharIterator(m
ap.mappings); |
| 444 var sourceURL = sources[sourceIndex]; |
| 445 |
| 446 while (true) { |
| 447 if (stringCharIterator.peek() === ',') |
| 448 stringCharIterator.next(); |
| 449 else { |
| 450 while (stringCharIterator.peek() === ';') { |
| 451 lineNumber += 1; |
| 452 columnNumber = 0; |
| 453 stringCharIterator.next(); |
535 } | 454 } |
536 | 455 if (!stringCharIterator.hasNext()) |
537 var mappings = this._reversedMappings(url); | 456 break; |
538 var startIndex = mappings.lowerBound({lineNumber: textRange.startLine, c
olumnNumber: textRange.startColumn}, comparator); | 457 } |
539 var endIndex = mappings.upperBound({lineNumber: textRange.endLine, colum
nNumber: textRange.endColumn}, comparator); | 458 |
540 | 459 columnNumber += this._decodeVLQ(stringCharIterator); |
541 var startMapping = mappings[startIndex]; | 460 if (!stringCharIterator.hasNext() || this._isSeparator(stringCharIterator.
peek())) { |
542 var endMapping = mappings[endIndex]; | 461 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, columnNu
mber)); |
543 return new WebInspector.TextRange(startMapping.lineNumber, startMapping.
columnNumber, endMapping.lineNumber, endMapping.columnNumber); | 462 continue; |
544 }, | 463 } |
545 | 464 |
546 _VLQ_BASE_SHIFT: 5, | 465 var sourceIndexDelta = this._decodeVLQ(stringCharIterator); |
547 _VLQ_BASE_MASK: (1 << 5) - 1, | 466 if (sourceIndexDelta) { |
548 _VLQ_CONTINUATION_MASK: 1 << 5 | 467 sourceIndex += sourceIndexDelta; |
| 468 sourceURL = sources[sourceIndex]; |
| 469 } |
| 470 sourceLineNumber += this._decodeVLQ(stringCharIterator); |
| 471 sourceColumnNumber += this._decodeVLQ(stringCharIterator); |
| 472 |
| 473 if (!stringCharIterator.hasNext() || this._isSeparator(stringCharIterator.
peek())) { |
| 474 this._mappings.push( |
| 475 new WebInspector.SourceMapEntry(lineNumber, columnNumber, sourceURL,
sourceLineNumber, sourceColumnNumber)); |
| 476 continue; |
| 477 } |
| 478 |
| 479 nameIndex += this._decodeVLQ(stringCharIterator); |
| 480 this._mappings.push(new WebInspector.SourceMapEntry( |
| 481 lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNum
ber, names[nameIndex])); |
| 482 } |
| 483 } |
| 484 |
| 485 /** |
| 486 * @param {string} char |
| 487 * @return {boolean} |
| 488 */ |
| 489 _isSeparator(char) { |
| 490 return char === ',' || char === ';'; |
| 491 } |
| 492 |
| 493 /** |
| 494 * @param {!WebInspector.TextSourceMap.StringCharIterator} stringCharIterator |
| 495 * @return {number} |
| 496 */ |
| 497 _decodeVLQ(stringCharIterator) { |
| 498 // Read unsigned value. |
| 499 var result = 0; |
| 500 var shift = 0; |
| 501 do { |
| 502 var digit = WebInspector.TextSourceMap._base64Map[stringCharIterator.next(
)]; |
| 503 result += (digit & WebInspector.TextSourceMap._VLQ_BASE_MASK) << shift; |
| 504 shift += WebInspector.TextSourceMap._VLQ_BASE_SHIFT; |
| 505 } while (digit & WebInspector.TextSourceMap._VLQ_CONTINUATION_MASK); |
| 506 |
| 507 // Fix the sign. |
| 508 var negative = result & 1; |
| 509 result >>= 1; |
| 510 return negative ? -result : result; |
| 511 } |
| 512 |
| 513 /** |
| 514 * @param {string} url |
| 515 * @param {!WebInspector.TextRange} textRange |
| 516 * @return {!WebInspector.TextRange} |
| 517 */ |
| 518 reverseMapTextRange(url, textRange) { |
| 519 /** |
| 520 * @param {!{lineNumber: number, columnNumber: number}} position |
| 521 * @param {!WebInspector.SourceMapEntry} mapping |
| 522 * @return {number} |
| 523 */ |
| 524 function comparator(position, mapping) { |
| 525 if (position.lineNumber !== mapping.sourceLineNumber) |
| 526 return position.lineNumber - mapping.sourceLineNumber; |
| 527 |
| 528 return position.columnNumber - mapping.sourceColumnNumber; |
| 529 } |
| 530 |
| 531 var mappings = this._reversedMappings(url); |
| 532 var startIndex = |
| 533 mappings.lowerBound({lineNumber: textRange.startLine, columnNumber: text
Range.startColumn}, comparator); |
| 534 var endIndex = mappings.upperBound({lineNumber: textRange.endLine, columnNum
ber: textRange.endColumn}, comparator); |
| 535 |
| 536 var startMapping = mappings[startIndex]; |
| 537 var endMapping = mappings[endIndex]; |
| 538 return new WebInspector.TextRange( |
| 539 startMapping.lineNumber, startMapping.columnNumber, endMapping.lineNumbe
r, endMapping.columnNumber); |
| 540 } |
549 }; | 541 }; |
550 | 542 |
| 543 WebInspector.TextSourceMap._VLQ_BASE_SHIFT = 5; |
| 544 WebInspector.TextSourceMap._VLQ_BASE_MASK = (1 << 5) - 1; |
| 545 WebInspector.TextSourceMap._VLQ_CONTINUATION_MASK = 1 << 5; |
| 546 |
| 547 |
551 /** | 548 /** |
552 * @constructor | 549 * @unrestricted |
553 * @param {string} string | |
554 */ | 550 */ |
555 WebInspector.TextSourceMap.StringCharIterator = function(string) | 551 WebInspector.TextSourceMap.StringCharIterator = class { |
556 { | 552 /** |
| 553 * @param {string} string |
| 554 */ |
| 555 constructor(string) { |
557 this._string = string; | 556 this._string = string; |
558 this._position = 0; | 557 this._position = 0; |
| 558 } |
| 559 |
| 560 /** |
| 561 * @return {string} |
| 562 */ |
| 563 next() { |
| 564 return this._string.charAt(this._position++); |
| 565 } |
| 566 |
| 567 /** |
| 568 * @return {string} |
| 569 */ |
| 570 peek() { |
| 571 return this._string.charAt(this._position); |
| 572 } |
| 573 |
| 574 /** |
| 575 * @return {boolean} |
| 576 */ |
| 577 hasNext() { |
| 578 return this._position < this._string.length; |
| 579 } |
559 }; | 580 }; |
560 | 581 |
561 WebInspector.TextSourceMap.StringCharIterator.prototype = { | |
562 /** | |
563 * @return {string} | |
564 */ | |
565 next: function() | |
566 { | |
567 return this._string.charAt(this._position++); | |
568 }, | |
569 | |
570 /** | |
571 * @return {string} | |
572 */ | |
573 peek: function() | |
574 { | |
575 return this._string.charAt(this._position); | |
576 }, | |
577 | |
578 /** | |
579 * @return {boolean} | |
580 */ | |
581 hasNext: function() | |
582 { | |
583 return this._position < this._string.length; | |
584 } | |
585 }; | |
586 | |
587 /** | 582 /** |
588 * @constructor | 583 * @unrestricted |
589 * @param {?string} content | |
590 * @param {?Array<!WebInspector.SourceMapEntry>} reverseMappings | |
591 */ | 584 */ |
592 WebInspector.TextSourceMap.SourceInfo = function(content, reverseMappings) { | 585 WebInspector.TextSourceMap.SourceInfo = class { |
| 586 /** |
| 587 * @param {?string} content |
| 588 * @param {?Array<!WebInspector.SourceMapEntry>} reverseMappings |
| 589 */ |
| 590 constructor(content, reverseMappings) { |
593 this.content = content; | 591 this.content = content; |
594 this.reverseMappings = reverseMappings; | 592 this.reverseMappings = reverseMappings; |
| 593 } |
595 }; | 594 }; |
596 | 595 |
597 WebInspector.TextSourceMap._sourcesListSymbol = Symbol("sourcesList"); | 596 WebInspector.TextSourceMap._sourcesListSymbol = Symbol('sourcesList'); |
OLD | NEW |