Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/sdk/SourceMap.js

Issue 2371133003: [Devtools] Lazily build reverse mappings (Closed)
Patch Set: Comments were addressed Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 */ 165 */
166 WebInspector.TextSourceMap = function(compiledURL, sourceMappingURL, payload) 166 WebInspector.TextSourceMap = function(compiledURL, sourceMappingURL, payload)
167 { 167 {
168 if (!WebInspector.TextSourceMap.prototype._base64Map) { 168 if (!WebInspector.TextSourceMap.prototype._base64Map) {
169 const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx yz0123456789+/"; 169 const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx yz0123456789+/";
170 WebInspector.TextSourceMap.prototype._base64Map = {}; 170 WebInspector.TextSourceMap.prototype._base64Map = {};
171 for (var i = 0; i < base64Digits.length; ++i) 171 for (var i = 0; i < base64Digits.length; ++i)
172 WebInspector.TextSourceMap.prototype._base64Map[base64Digits.charAt( i)] = i; 172 WebInspector.TextSourceMap.prototype._base64Map[base64Digits.charAt( i)] = i;
173 } 173 }
174 174
175 this._json = payload;
175 this._compiledURL = compiledURL; 176 this._compiledURL = compiledURL;
176 this._sourceMappingURL = sourceMappingURL; 177 this._sourceMappingURL = sourceMappingURL;
177 this._reverseMappingsBySourceURL = new Map(); 178 /** @type {?Array<!WebInspector.SourceMapEntry>} */
178 this._mappings = []; 179 this._mappings = null;
179 this._sources = {}; 180 /** @type {!Map<string, !WebInspector.TextSourceMap.SourceInfo>} */
180 this._sourceContentByURL = {}; 181 this._sourceInfos = new Map();
181 this._parseMappingPayload(payload); 182 this._eachSection(this._parseSources.bind(this));
182 } 183 }
183 184
184 /** 185 /**
185 * @param {string} sourceMapURL 186 * @param {string} sourceMapURL
186 * @param {string} compiledURL 187 * @param {string} compiledURL
187 * @return {!Promise<?WebInspector.TextSourceMap>} 188 * @return {!Promise<?WebInspector.TextSourceMap>}
188 * @this {WebInspector.TextSourceMap} 189 * @this {WebInspector.TextSourceMap}
189 */ 190 */
190 WebInspector.TextSourceMap.load = function(sourceMapURL, compiledURL) 191 WebInspector.TextSourceMap.load = function(sourceMapURL, compiledURL)
191 { 192 {
(...skipping 12 matching lines...) Expand all
204 if (!content || statusCode >= 400) { 205 if (!content || statusCode >= 400) {
205 callback(null); 206 callback(null);
206 return; 207 return;
207 } 208 }
208 209
209 if (content.slice(0, 3) === ")]}") 210 if (content.slice(0, 3) === ")]}")
210 content = content.substring(content.indexOf("\n")); 211 content = content.substring(content.indexOf("\n"));
211 try { 212 try {
212 var payload = /** @type {!SourceMapV3} */ (JSON.parse(content)); 213 var payload = /** @type {!SourceMapV3} */ (JSON.parse(content));
213 var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourc eMapURL; 214 var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourc eMapURL;
214
215 callback(new WebInspector.TextSourceMap(compiledURL, baseURL, payloa d)); 215 callback(new WebInspector.TextSourceMap(compiledURL, baseURL, payloa d));
216 } catch (e) { 216 } catch (e) {
217 console.error(e); 217 console.error(e);
218 WebInspector.console.warn("DevTools failed to parse SourceMap: " + s ourceMapURL); 218 WebInspector.console.warn("DevTools failed to parse SourceMap: " + s ourceMapURL);
219 callback(null); 219 callback(null);
220 } 220 }
221 } 221 }
222 } 222 }
223 223
224 WebInspector.TextSourceMap.prototype = { 224 WebInspector.TextSourceMap.prototype = {
(...skipping 14 matching lines...) Expand all
239 { 239 {
240 return this._sourceMappingURL; 240 return this._sourceMappingURL;
241 }, 241 },
242 242
243 /** 243 /**
244 * @override 244 * @override
245 * @return {!Array.<string>} 245 * @return {!Array.<string>}
246 */ 246 */
247 sourceURLs: function() 247 sourceURLs: function()
248 { 248 {
249 return Object.keys(this._sources); 249 return this._sourceInfos.keysArray();
250 }, 250 },
251 251
252 /** 252 /**
253 * @override 253 * @override
254 * @param {string} sourceURL 254 * @param {string} sourceURL
255 * @param {!WebInspector.ResourceType} contentType 255 * @param {!WebInspector.ResourceType} contentType
256 * @return {!WebInspector.ContentProvider} 256 * @return {!WebInspector.ContentProvider}
257 */ 257 */
258 sourceContentProvider: function(sourceURL, contentType) 258 sourceContentProvider: function(sourceURL, contentType)
259 { 259 {
260 var sourceContent = this._sourceContentByURL[sourceURL]; 260 var info = this._sourceInfos.get(sourceURL);
261 if (sourceContent) 261 if (info.content)
262 return WebInspector.StaticContentProvider.fromString(sourceURL, cont entType, sourceContent); 262 return WebInspector.StaticContentProvider.fromString(sourceURL, cont entType, info.content);
263 return new WebInspector.CompilerSourceMappingContentProvider(sourceURL, contentType); 263 return new WebInspector.CompilerSourceMappingContentProvider(sourceURL, contentType);
264 }, 264 },
265 265
266 /** 266 /**
267 * @override 267 * @override
268 * @return {boolean} 268 * @return {boolean}
269 */ 269 */
270 editable: function() 270 editable: function()
271 { 271 {
272 return false; 272 return false;
273 }, 273 },
274 274
275 /** 275 /**
276 * @override 276 * @override
277 * @param {!Array<!WebInspector.TextRange>} ranges 277 * @param {!Array<!WebInspector.TextRange>} ranges
278 * @param {!Array<string>} texts 278 * @param {!Array<string>} texts
279 * @return {!Promise<?WebInspector.SourceMap.EditResult>} 279 * @return {!Promise<?WebInspector.SourceMap.EditResult>}
280 */ 280 */
281 editCompiled: function(ranges, texts) 281 editCompiled: function(ranges, texts)
282 { 282 {
283 return Promise.resolve(/** @type {?WebInspector.SourceMap.EditResult} */ (null)); 283 return Promise.resolve(/** @type {?WebInspector.SourceMap.EditResult} */ (null));
284 }, 284 },
285 285
286 /** 286 /**
287 * @param {!SourceMapV3} mappingPayload
288 */
289 _parseMappingPayload: function(mappingPayload)
290 {
291 if (mappingPayload.sections)
292 this._parseSections(mappingPayload.sections);
293 else
294 this._parseMap(mappingPayload, 0, 0);
295 },
296
297 /**
298 * @param {!Array.<!SourceMapV3.Section>} sections
299 */
300 _parseSections: function(sections)
301 {
302 for (var i = 0; i < sections.length; ++i) {
303 var section = sections[i];
304 this._parseMap(section.map, section.offset.line, section.offset.colu mn);
305 }
306 },
307
308 /**
309 * @override 287 * @override
310 * @param {number} lineNumber in compiled resource 288 * @param {number} lineNumber in compiled resource
311 * @param {number} columnNumber in compiled resource 289 * @param {number} columnNumber in compiled resource
312 * @return {?WebInspector.SourceMapEntry} 290 * @return {?WebInspector.SourceMapEntry}
313 */ 291 */
314 findEntry: function(lineNumber, columnNumber) 292 findEntry: function(lineNumber, columnNumber)
315 { 293 {
316 var first = 0; 294 var first = 0;
317 var count = this._mappings.length; 295 var mappings = this.mappings();
296 var count = mappings.length;
318 while (count > 1) { 297 while (count > 1) {
319 var step = count >> 1; 298 var step = count >> 1;
320 var middle = first + step; 299 var middle = first + step;
321 var mapping = this._mappings[middle]; 300 var mapping = mappings[middle];
322 if (lineNumber < mapping.lineNumber || (lineNumber === mapping.lineN umber && columnNumber < mapping.columnNumber)) { 301 if (lineNumber < mapping.lineNumber || (lineNumber === mapping.lineN umber && columnNumber < mapping.columnNumber)) {
323 count = step; 302 count = step;
324 } else { 303 } else {
325 first = middle; 304 first = middle;
326 count -= step; 305 count -= step;
327 } 306 }
328 } 307 }
329 var entry = this._mappings[first]; 308 var entry = mappings[first];
330 if (!first && entry && (lineNumber < entry.lineNumber || (lineNumber === entry.lineNumber && columnNumber < entry.columnNumber))) 309 if (!first && entry && (lineNumber < entry.lineNumber || (lineNumber === entry.lineNumber && columnNumber < entry.columnNumber)))
331 return null; 310 return null;
332 return entry; 311 return entry;
333 }, 312 },
334 313
335 /** 314 /**
336 * @param {string} sourceURL 315 * @param {string} sourceURL
337 * @param {number} lineNumber 316 * @param {number} lineNumber
338 * @return {?WebInspector.SourceMapEntry} 317 * @return {?WebInspector.SourceMapEntry}
339 */ 318 */
(...skipping 14 matching lines...) Expand all
354 { 333 {
355 return lineNumber - mapping.sourceLineNumber; 334 return lineNumber - mapping.sourceLineNumber;
356 } 335 }
357 }, 336 },
358 337
359 /** 338 /**
360 * @return {!Array<!WebInspector.SourceMapEntry>} 339 * @return {!Array<!WebInspector.SourceMapEntry>}
361 */ 340 */
362 mappings: function() 341 mappings: function()
363 { 342 {
364 return this._mappings; 343 if (this._mappings === null) {
344 this._mappings = [];
345 this._eachSection(this._parseMap.bind(this));
346 this._json = null;
347 }
348 return /** @type {!Array<!WebInspector.SourceMapEntry>} */ (this._mappin gs);
365 }, 349 },
366 350
367 /** 351 /**
368 * @param {string} sourceURL 352 * @param {string} sourceURL
369 * @return {!Array.<!WebInspector.SourceMapEntry>} 353 * @return {!Array.<!WebInspector.SourceMapEntry>}
370 */ 354 */
371 _reversedMappings: function(sourceURL) 355 _reversedMappings: function(sourceURL)
372 { 356 {
373 var mappings = this._reverseMappingsBySourceURL.get(sourceURL); 357 if (!this._sourceInfos.has(sourceURL))
374 if (!mappings)
375 return []; 358 return [];
376 if (!mappings._sorted) { 359 var mappings = this.mappings();
377 mappings.sort(sourceMappingComparator); 360 var info = this._sourceInfos.get(sourceURL);
378 mappings._sorted = true; 361 if (info.reverseMappings === null)
379 } 362 info.reverseMappings = mappings.filter((mapping) => mapping.sourceUR L === sourceURL).sort(sourceMappingComparator);
380 return mappings; 363 return info.reverseMappings;
381 364
382 /** 365 /**
383 * @param {!WebInspector.SourceMapEntry} a 366 * @param {!WebInspector.SourceMapEntry} a
384 * @param {!WebInspector.SourceMapEntry} b 367 * @param {!WebInspector.SourceMapEntry} b
385 * @return {number} 368 * @return {number}
386 */ 369 */
387 function sourceMappingComparator(a, b) 370 function sourceMappingComparator(a, b)
388 { 371 {
389 if (a.sourceLineNumber !== b.sourceLineNumber) 372 if (a.sourceLineNumber !== b.sourceLineNumber)
390 return a.sourceLineNumber - b.sourceLineNumber; 373 return a.sourceLineNumber - b.sourceLineNumber;
391 if (a.sourceColumnNumber !== b.sourceColumnNumber) 374 if (a.sourceColumnNumber !== b.sourceColumnNumber)
392 return a.sourceColumnNumber - b.sourceColumnNumber; 375 return a.sourceColumnNumber - b.sourceColumnNumber;
393 376
394 if (a.lineNumber !== b.lineNumber) 377 if (a.lineNumber !== b.lineNumber)
395 return a.lineNumber - b.lineNumber; 378 return a.lineNumber - b.lineNumber;
396 379
397 return a.columnNumber - b.columnNumber; 380 return a.columnNumber - b.columnNumber;
398 } 381 }
399 }, 382 },
400 383
401 /** 384 /**
385 * @param {function(!SourceMapV3, number, number)} callback
386 */
387 _eachSection: function(callback) {
388 if (!this._json.sections) {
389 callback(this._json, 0, 0);
390 return;
391 }
392 for (var section of this._json.sections)
393 callback(section.map, section.offset.line, section.offset.column);
394 },
395
396 /**
397 * @param {!SourceMapV3} sourceMap
398 */
399 _parseSources: function(sourceMap) {
400 var sourcesList = [];
401 var sourceRoot = sourceMap.sourceRoot || "";
402 if (sourceRoot && !sourceRoot.endsWith("/"))
403 sourceRoot += "/";
404 for (var i = 0; i < sourceMap.sources.length; ++i) {
405 var href = sourceRoot + sourceMap.sources[i];
406 var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href;
407 var source = sourceMap.sourcesContent && sourceMap.sourcesContent[i] ;
408 if (url === this._compiledURL && source)
409 url += WebInspector.UIString(" [sm]");
410 this._sourceInfos.set(url, new WebInspector.TextSourceMap.SourceInfo (source, null));
411 sourcesList.push(url);
412 }
413 sourceMap[WebInspector.TextSourceMap._sourcesListSymbol] = sourcesList;
414 },
415
416 /**
402 * @param {!SourceMapV3} map 417 * @param {!SourceMapV3} map
403 * @param {number} lineNumber 418 * @param {number} lineNumber
404 * @param {number} columnNumber 419 * @param {number} columnNumber
405 */ 420 */
406 _parseMap: function(map, lineNumber, columnNumber) 421 _parseMap: function(map, lineNumber, columnNumber)
407 { 422 {
408 var sourceIndex = 0; 423 var sourceIndex = 0;
409 var sourceLineNumber = 0; 424 var sourceLineNumber = 0;
410 var sourceColumnNumber = 0; 425 var sourceColumnNumber = 0;
411 var nameIndex = 0; 426 var nameIndex = 0;
412 427 var sources = map[WebInspector.TextSourceMap._sourcesListSymbol];
413 var sources = [];
414 var names = map.names || []; 428 var names = map.names || [];
415 var sourceRoot = map.sourceRoot || "";
416 if (sourceRoot && !sourceRoot.endsWith("/"))
417 sourceRoot += "/";
418 for (var i = 0; i < map.sources.length; ++i) {
419 var href = sourceRoot + map.sources[i];
420 var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href;
421 var hasSource = map.sourcesContent && map.sourcesContent[i];
422 if (url === this._compiledURL && hasSource)
423 url += WebInspector.UIString(" [sm]");
424 sources.push(url);
425 this._sources[url] = true;
426
427 if (hasSource)
428 this._sourceContentByURL[url] = map.sourcesContent[i];
429 }
430
431 var stringCharIterator = new WebInspector.TextSourceMap.StringCharIterat or(map.mappings); 429 var stringCharIterator = new WebInspector.TextSourceMap.StringCharIterat or(map.mappings);
432 var sourceURL = sources[sourceIndex]; 430 var sourceURL = sources[sourceIndex];
433 431
434 while (true) { 432 while (true) {
435 if (stringCharIterator.peek() === ",") 433 if (stringCharIterator.peek() === ",")
436 stringCharIterator.next(); 434 stringCharIterator.next();
437 else { 435 else {
438 while (stringCharIterator.peek() === ";") { 436 while (stringCharIterator.peek() === ";") {
439 lineNumber += 1; 437 lineNumber += 1;
440 columnNumber = 0; 438 columnNumber = 0;
(...skipping 18 matching lines...) Expand all
459 sourceColumnNumber += this._decodeVLQ(stringCharIterator); 457 sourceColumnNumber += this._decodeVLQ(stringCharIterator);
460 458
461 if (!stringCharIterator.hasNext() || this._isSeparator(stringCharIte rator.peek())) { 459 if (!stringCharIterator.hasNext() || this._isSeparator(stringCharIte rator.peek())) {
462 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber)); 460 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber));
463 continue; 461 continue;
464 } 462 }
465 463
466 nameIndex += this._decodeVLQ(stringCharIterator); 464 nameIndex += this._decodeVLQ(stringCharIterator);
467 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, colu mnNumber, sourceURL, sourceLineNumber, sourceColumnNumber, names[nameIndex])); 465 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, colu mnNumber, sourceURL, sourceLineNumber, sourceColumnNumber, names[nameIndex]));
468 } 466 }
469
470 for (var i = 0; i < this._mappings.length; ++i) {
471 var mapping = this._mappings[i];
472 var url = mapping.sourceURL;
473 if (!url)
474 continue;
475 if (!this._reverseMappingsBySourceURL.has(url))
476 this._reverseMappingsBySourceURL.set(url, []);
477 var reverseMappings = this._reverseMappingsBySourceURL.get(url);
478 reverseMappings.push(mapping);
479 }
480 }, 467 },
481 468
482 /** 469 /**
483 * @param {string} char 470 * @param {string} char
484 * @return {boolean} 471 * @return {boolean}
485 */ 472 */
486 _isSeparator: function(char) 473 _isSeparator: function(char)
487 { 474 {
488 return char === "," || char === ";"; 475 return char === "," || char === ";";
489 }, 476 },
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
571 }, 558 },
572 559
573 /** 560 /**
574 * @return {boolean} 561 * @return {boolean}
575 */ 562 */
576 hasNext: function() 563 hasNext: function()
577 { 564 {
578 return this._position < this._string.length; 565 return this._position < this._string.length;
579 } 566 }
580 } 567 }
568
569 /**
570 * @constructor
571 * @param {?string} content
572 * @param {?Array<!WebInspector.SourceMapEntry>} reverseMappings
573 */
574 WebInspector.TextSourceMap.SourceInfo = function(content, reverseMappings) {
575 this.content = content;
576 this.reverseMappings = reverseMappings;
577 }
578
579 WebInspector.TextSourceMap._sourcesListSymbol = Symbol("sourcesList");
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698