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

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

Issue 2371133003: [Devtools] Lazily build reverse mappings (Closed)
Patch Set: Make all parsing lazy. 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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 * @return {string} 89 * @return {string}
90 */ 90 */
91 compiledURL: function() { }, 91 compiledURL: function() { },
92 92
93 /** 93 /**
94 * @return {string} 94 * @return {string}
95 */ 95 */
96 url: function() { }, 96 url: function() { },
97 97
98 /** 98 /**
99 * @return {!Array<string>} 99 * @return {!Iterable<string>|!Array<string>}
lushnikov 2016/09/28 16:48:12 let's keep this array - we try to avoid polymorphi
eostroukhov 2016/09/28 23:26:33 This CL is about saving memory! ;) (Ok, I fixed t
100 */ 100 */
101 sourceURLs: function() { }, 101 sourceURLs: function() { },
102 102
103 /** 103 /**
104 * @param {string} sourceURL 104 * @param {string} sourceURL
105 * @param {!WebInspector.ResourceType} contentType 105 * @param {!WebInspector.ResourceType} contentType
106 * @return {!WebInspector.ContentProvider} 106 * @return {!WebInspector.ContentProvider}
107 */ 107 */
108 sourceContentProvider: function(sourceURL, contentType) { }, 108 sourceContentProvider: function(sourceURL, contentType) { },
109 109
(...skipping 55 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 this._sources = new Map();
lushnikov 2016/09/28 16:48:12 1. let's add jsdoc 2. let's name this _sourceURLTo
eostroukhov 2016/09/28 23:26:33 Done.
180 this._sourceContentByURL = {}; 181 this._sourceContentByURL = {};
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 10 matching lines...) Expand all
235 * @override 235 * @override
236 * @return {string} 236 * @return {string}
237 */ 237 */
238 url: function() 238 url: function()
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 {!Iterable.<string>}
246 */ 246 */
247 sourceURLs: function() 247 sourceURLs: function()
248 { 248 {
249 return Object.keys(this._sources); 249 return this._sources.keys();
lushnikov 2016/09/28 16:48:13 let's use .keysArray() to return array
eostroukhov 2016/09/28 23:26:33 Done.
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 {
(...skipping 17 matching lines...) Expand all
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._sources && !this._sources.has(sourceURL))
374 if (!mappings)
375 return []; 358 return [];
376 if (!mappings._sorted) { 359 let mappings = this.mappings();
lushnikov 2016/09/28 16:48:13 nit: we're not yet using "let" in the codebase
eostroukhov 2016/09/28 23:26:34 Done.
377 mappings.sort(sourceMappingComparator); 360 let reverseMappings = this._sources.get(sourceURL);
378 mappings._sorted = true; 361 if (reverseMappings === null) {
362 reverseMappings = mappings.filter((mapping) => mapping.sourceURL === sourceURL).sort(sourceMappingComparator);
363 this._sources.set(sourceURL, reverseMappings);
379 } 364 }
380 return mappings; 365 return reverseMappings;
381 366
382 /** 367 /**
383 * @param {!WebInspector.SourceMapEntry} a 368 * @param {!WebInspector.SourceMapEntry} a
384 * @param {!WebInspector.SourceMapEntry} b 369 * @param {!WebInspector.SourceMapEntry} b
385 * @return {number} 370 * @return {number}
386 */ 371 */
387 function sourceMappingComparator(a, b) 372 function sourceMappingComparator(a, b)
388 { 373 {
389 if (a.sourceLineNumber !== b.sourceLineNumber) 374 if (a.sourceLineNumber !== b.sourceLineNumber)
390 return a.sourceLineNumber - b.sourceLineNumber; 375 return a.sourceLineNumber - b.sourceLineNumber;
391 if (a.sourceColumnNumber !== b.sourceColumnNumber) 376 if (a.sourceColumnNumber !== b.sourceColumnNumber)
392 return a.sourceColumnNumber - b.sourceColumnNumber; 377 return a.sourceColumnNumber - b.sourceColumnNumber;
393 378
394 if (a.lineNumber !== b.lineNumber) 379 if (a.lineNumber !== b.lineNumber)
395 return a.lineNumber - b.lineNumber; 380 return a.lineNumber - b.lineNumber;
396 381
397 return a.columnNumber - b.columnNumber; 382 return a.columnNumber - b.columnNumber;
398 } 383 }
399 }, 384 },
400 385
401 /** 386 /**
387 * @param {function(!SourceMapV3, number, number)} callback
388 */
389 _eachSection: function(callback) {
390 const sections = this._json.sections || [this._json];
lushnikov 2016/09/28 16:48:13 let's bail out early instead: if (!this._json.sec
eostroukhov 2016/09/28 23:26:33 Done.
391 for (const section of sections) {
lushnikov 2016/09/28 16:48:13 nit: we're not yet using "const" in the codebase
eostroukhov 2016/09/28 23:26:33 Done.
392 const offset = section.offset || {line: 0, column: 0};
393 callback(section.map || section, offset.line, offset.column);
394 }
395 },
396
397 /**
398 * @param {!SourceMapV3} sourceMap
399 */
400 _parseSources: function(sourceMap) {
401 var sourceRoot = sourceMap.sourceRoot || "";
402 if (sourceRoot && !sourceRoot.endsWith("/"))
403 sourceRoot += "/";
404 for (var i = 0; i < sourceMap.sources.length; ++i) {
lushnikov 2016/09/28 16:48:13 this looks like a copy of the code in _parseMap. C
eostroukhov 2016/09/28 23:26:33 There are building different things - one is build
405 var href = sourceRoot + sourceMap.sources[i];
406 var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href;
407 var hasSource = sourceMap.sourcesContent && sourceMap.sourcesContent [i];
408 if (url === this._compiledURL && hasSource)
409 url += WebInspector.UIString(" [sm]");
410 this._sources.set(url, null);
411 if (hasSource)
412 this._sourceContentByURL[url] = sourceMap.sourcesContent[i];
413 }
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
413 var sources = []; 428 var sources = [];
414 var names = map.names || []; 429 var names = map.names || [];
415 var sourceRoot = map.sourceRoot || ""; 430 var sourceRoot = map.sourceRoot || "";
416 if (sourceRoot && !sourceRoot.endsWith("/")) 431 if (sourceRoot && !sourceRoot.endsWith("/"))
417 sourceRoot += "/"; 432 sourceRoot += "/";
418 for (var i = 0; i < map.sources.length; ++i) { 433 for (var i = 0; i < map.sources.length; ++i) {
419 var href = sourceRoot + map.sources[i]; 434 var href = sourceRoot + map.sources[i];
420 var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href; 435 var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href;
421 var hasSource = map.sourcesContent && map.sourcesContent[i]; 436 var hasSource = map.sourcesContent && map.sourcesContent[i];
422 if (url === this._compiledURL && hasSource) 437 if (url === this._compiledURL && hasSource)
423 url += WebInspector.UIString(" [sm]"); 438 url += WebInspector.UIString(" [sm]");
424 sources.push(url); 439 sources.push(url);
425 this._sources[url] = true;
426
427 if (hasSource)
428 this._sourceContentByURL[url] = map.sourcesContent[i];
429 } 440 }
430 441
431 var stringCharIterator = new WebInspector.TextSourceMap.StringCharIterat or(map.mappings); 442 var stringCharIterator = new WebInspector.TextSourceMap.StringCharIterat or(map.mappings);
432 var sourceURL = sources[sourceIndex]; 443 var sourceURL = sources[sourceIndex];
433 444
434 while (true) { 445 while (true) {
435 if (stringCharIterator.peek() === ",") 446 if (stringCharIterator.peek() === ",")
436 stringCharIterator.next(); 447 stringCharIterator.next();
437 else { 448 else {
438 while (stringCharIterator.peek() === ";") { 449 while (stringCharIterator.peek() === ";") {
(...skipping 20 matching lines...) Expand all
459 sourceColumnNumber += this._decodeVLQ(stringCharIterator); 470 sourceColumnNumber += this._decodeVLQ(stringCharIterator);
460 471
461 if (!stringCharIterator.hasNext() || this._isSeparator(stringCharIte rator.peek())) { 472 if (!stringCharIterator.hasNext() || this._isSeparator(stringCharIte rator.peek())) {
462 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber)); 473 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber));
463 continue; 474 continue;
464 } 475 }
465 476
466 nameIndex += this._decodeVLQ(stringCharIterator); 477 nameIndex += this._decodeVLQ(stringCharIterator);
467 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, colu mnNumber, sourceURL, sourceLineNumber, sourceColumnNumber, names[nameIndex])); 478 this._mappings.push(new WebInspector.SourceMapEntry(lineNumber, colu mnNumber, sourceURL, sourceLineNumber, sourceColumnNumber, names[nameIndex]));
468 } 479 }
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 }, 480 },
481 481
482 /** 482 /**
483 * @param {string} char 483 * @param {string} char
484 * @return {boolean} 484 * @return {boolean}
485 */ 485 */
486 _isSeparator: function(char) 486 _isSeparator: function(char)
487 { 487 {
488 return char === "," || char === ";"; 488 return char === "," || char === ";";
489 }, 489 },
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
571 }, 571 },
572 572
573 /** 573 /**
574 * @return {boolean} 574 * @return {boolean}
575 */ 575 */
576 hasNext: function() 576 hasNext: function()
577 { 577 {
578 return this._position < this._string.length; 578 return this._position < this._string.length;
579 } 579 }
580 } 580 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698