OLD | NEW |
(Empty) | |
| 1 // This is a copy from blink dev tools, see: |
| 2 // http://src.chromium.org/viewvc/blink/trunk/Source/devtools/front_end/SourceMa
p.js |
| 3 // revision: 153407 |
| 4 |
| 5 // Added to make the file work without dev tools |
| 6 WebInspector = {}; |
| 7 WebInspector.ParsedURL = {}; |
| 8 WebInspector.ParsedURL.completeURL = function(){}; |
| 9 // start of original file |
| 10 /* |
| 11 * Copyright (C) 2012 Google Inc. All rights reserved. |
| 12 * |
| 13 * Redistribution and use in source and binary forms, with or without |
| 14 * modification, are permitted provided that the following conditions are |
| 15 * met: |
| 16 * |
| 17 * * Redistributions of source code must retain the above copyright |
| 18 * notice, this list of conditions and the following disclaimer. |
| 19 * * Redistributions in binary form must reproduce the above |
| 20 * copyright notice, this list of conditions and the following disclaimer |
| 21 * in the documentation and/or other materials provided with the |
| 22 * distribution. |
| 23 * * Neither the name of Google Inc. nor the names of its |
| 24 * contributors may be used to endorse or promote products derived from |
| 25 * this software without specific prior written permission. |
| 26 * |
| 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 38 */ |
| 39 |
| 40 /** |
| 41 * Implements Source Map V3 model. See http://code.google.com/p/closure-compiler
/wiki/SourceMaps |
| 42 * for format description. |
| 43 * @constructor |
| 44 * @param {string} sourceMappingURL |
| 45 * @param {SourceMapV3} payload |
| 46 */ |
| 47 WebInspector.SourceMap = function(sourceMappingURL, payload) |
| 48 { |
| 49 if (!WebInspector.SourceMap.prototype._base64Map) { |
| 50 const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx
yz0123456789+/"; |
| 51 WebInspector.SourceMap.prototype._base64Map = {}; |
| 52 for (var i = 0; i < base64Digits.length; ++i) |
| 53 WebInspector.SourceMap.prototype._base64Map[base64Digits.charAt(i)]
= i; |
| 54 } |
| 55 |
| 56 this._sourceMappingURL = sourceMappingURL; |
| 57 this._reverseMappingsBySourceURL = {}; |
| 58 this._mappings = []; |
| 59 this._sources = {}; |
| 60 this._sourceContentByURL = {}; |
| 61 this._parseMappingPayload(payload); |
| 62 } |
| 63 |
| 64 /** |
| 65 * @param {string} sourceMapURL |
| 66 * @param {string} compiledURL |
| 67 * @param {function(WebInspector.SourceMap)} callback |
| 68 */ |
| 69 WebInspector.SourceMap.load = function(sourceMapURL, compiledURL, callback) |
| 70 { |
| 71 NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.mainFram
e.id, sourceMapURL, undefined, contentLoaded.bind(this)); |
| 72 |
| 73 /** |
| 74 * @param {?Protocol.Error} error |
| 75 * @param {number} statusCode |
| 76 * @param {NetworkAgent.Headers} headers |
| 77 * @param {string} content |
| 78 */ |
| 79 function contentLoaded(error, statusCode, headers, content) |
| 80 { |
| 81 if (error || !content || statusCode >= 400) { |
| 82 console.error("Could not load content for " + sourceMapURL + " : " +
(error || ("HTTP status code: " + statusCode))); |
| 83 callback(null); |
| 84 return; |
| 85 } |
| 86 |
| 87 if (content.slice(0, 3) === ")]}") |
| 88 content = content.substring(content.indexOf('\n')); |
| 89 try { |
| 90 var payload = /** @type {SourceMapV3} */ (JSON.parse(content)); |
| 91 var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourc
eMapURL; |
| 92 callback(new WebInspector.SourceMap(baseURL, payload)); |
| 93 } catch(e) { |
| 94 console.error(e.message); |
| 95 callback(null); |
| 96 } |
| 97 } |
| 98 } |
| 99 |
| 100 WebInspector.SourceMap.prototype = { |
| 101 /** |
| 102 * @return {Array.<string>} |
| 103 */ |
| 104 sources: function() |
| 105 { |
| 106 return Object.keys(this._sources); |
| 107 }, |
| 108 |
| 109 /** |
| 110 * @param {string} sourceURL |
| 111 * @return {string|undefined} |
| 112 */ |
| 113 sourceContent: function(sourceURL) |
| 114 { |
| 115 return this._sourceContentByURL[sourceURL]; |
| 116 }, |
| 117 |
| 118 /** |
| 119 * @param {string} sourceURL |
| 120 * @param {WebInspector.ResourceType} contentType |
| 121 * @return {WebInspector.ContentProvider} |
| 122 */ |
| 123 sourceContentProvider: function(sourceURL, contentType) |
| 124 { |
| 125 var lastIndexOfDot = sourceURL.lastIndexOf("."); |
| 126 var extension = lastIndexOfDot !== -1 ? sourceURL.substr(lastIndexOfDot
+ 1) : ""; |
| 127 var mimeType = WebInspector.ResourceType.mimeTypesForExtensions[extensio
n.toLowerCase()]; |
| 128 var sourceContent = this.sourceContent(sourceURL); |
| 129 if (sourceContent) |
| 130 return new WebInspector.StaticContentProvider(contentType, sourceCon
tent, mimeType); |
| 131 return new WebInspector.CompilerSourceMappingContentProvider(sourceURL,
contentType, mimeType); |
| 132 }, |
| 133 |
| 134 /** |
| 135 * @param {SourceMapV3} mappingPayload |
| 136 */ |
| 137 _parseMappingPayload: function(mappingPayload) |
| 138 { |
| 139 if (mappingPayload.sections) |
| 140 this._parseSections(mappingPayload.sections); |
| 141 else |
| 142 this._parseMap(mappingPayload, 0, 0); |
| 143 }, |
| 144 |
| 145 /** |
| 146 * @param {Array.<SourceMapV3.Section>} sections |
| 147 */ |
| 148 _parseSections: function(sections) |
| 149 { |
| 150 for (var i = 0; i < sections.length; ++i) { |
| 151 var section = sections[i]; |
| 152 this._parseMap(section.map, section.offset.line, section.offset.colu
mn); |
| 153 } |
| 154 }, |
| 155 |
| 156 /** |
| 157 * @param {number} lineNumber in compiled resource |
| 158 * @param {number} columnNumber in compiled resource |
| 159 * @return {?Array} |
| 160 */ |
| 161 findEntry: function(lineNumber, columnNumber) |
| 162 { |
| 163 var first = 0; |
| 164 var count = this._mappings.length; |
| 165 while (count > 1) { |
| 166 var step = count >> 1; |
| 167 var middle = first + step; |
| 168 var mapping = this._mappings[middle]; |
| 169 if (lineNumber < mapping[0] || (lineNumber === mapping[0] && columnNum
ber < mapping[1])) |
| 170 count = step; |
| 171 else { |
| 172 first = middle; |
| 173 count -= step; |
| 174 } |
| 175 } |
| 176 var entry = this._mappings[first]; |
| 177 if (!first && entry && (lineNumber < entry[0] || (lineNumber === entry[0
] && columnNumber < entry[1]))) |
| 178 return null; |
| 179 return entry; |
| 180 }, |
| 181 |
| 182 /** |
| 183 * @param {string} sourceURL of the originating resource |
| 184 * @param {number} lineNumber in the originating resource |
| 185 * @return {Array} |
| 186 */ |
| 187 findEntryReversed: function(sourceURL, lineNumber) |
| 188 { |
| 189 var mappings = this._reverseMappingsBySourceURL[sourceURL]; |
| 190 for ( ; lineNumber < mappings.length; ++lineNumber) { |
| 191 var mapping = mappings[lineNumber]; |
| 192 if (mapping) |
| 193 return mapping; |
| 194 } |
| 195 return this._mappings[0]; |
| 196 }, |
| 197 |
| 198 /** |
| 199 * @override |
| 200 */ |
| 201 _parseMap: function(map, lineNumber, columnNumber) |
| 202 { |
| 203 var sourceIndex = 0; |
| 204 var sourceLineNumber = 0; |
| 205 var sourceColumnNumber = 0; |
| 206 var nameIndex = 0; |
| 207 |
| 208 var sources = []; |
| 209 var originalToCanonicalURLMap = {}; |
| 210 for (var i = 0; i < map.sources.length; ++i) { |
| 211 var originalSourceURL = map.sources[i]; |
| 212 var sourceRoot = map.sourceRoot || ""; |
| 213 if (sourceRoot && !sourceRoot.endsWith("/")) |
| 214 sourceRoot += "/"; |
| 215 var href = sourceRoot + originalSourceURL; |
| 216 var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL,
href) || href; |
| 217 originalToCanonicalURLMap[originalSourceURL] = url; |
| 218 sources.push(url); |
| 219 this._sources[url] = true; |
| 220 |
| 221 if (map.sourcesContent && map.sourcesContent[i]) |
| 222 this._sourceContentByURL[url] = map.sourcesContent[i]; |
| 223 } |
| 224 |
| 225 var stringCharIterator = new WebInspector.SourceMap.StringCharIterator(m
ap.mappings); |
| 226 var sourceURL = sources[sourceIndex]; |
| 227 |
| 228 while (true) { |
| 229 if (stringCharIterator.peek() === ",") |
| 230 stringCharIterator.next(); |
| 231 else { |
| 232 while (stringCharIterator.peek() === ";") { |
| 233 lineNumber += 1; |
| 234 columnNumber = 0; |
| 235 stringCharIterator.next(); |
| 236 } |
| 237 if (!stringCharIterator.hasNext()) |
| 238 break; |
| 239 } |
| 240 |
| 241 columnNumber += this._decodeVLQ(stringCharIterator); |
| 242 if (this._isSeparator(stringCharIterator.peek())) { |
| 243 this._mappings.push([lineNumber, columnNumber]); |
| 244 continue; |
| 245 } |
| 246 |
| 247 var sourceIndexDelta = this._decodeVLQ(stringCharIterator); |
| 248 if (sourceIndexDelta) { |
| 249 sourceIndex += sourceIndexDelta; |
| 250 sourceURL = sources[sourceIndex]; |
| 251 } |
| 252 sourceLineNumber += this._decodeVLQ(stringCharIterator); |
| 253 sourceColumnNumber += this._decodeVLQ(stringCharIterator); |
| 254 if (!this._isSeparator(stringCharIterator.peek())) |
| 255 nameIndex += this._decodeVLQ(stringCharIterator); |
| 256 |
| 257 this._mappings.push([lineNumber, columnNumber, sourceURL, sourceLine
Number, sourceColumnNumber]); |
| 258 } |
| 259 |
| 260 for (var i = 0; i < this._mappings.length; ++i) { |
| 261 var mapping = this._mappings[i]; |
| 262 var url = mapping[2]; |
| 263 if (!url) |
| 264 continue; |
| 265 if (!this._reverseMappingsBySourceURL[url]) |
| 266 this._reverseMappingsBySourceURL[url] = []; |
| 267 var reverseMappings = this._reverseMappingsBySourceURL[url]; |
| 268 var sourceLine = mapping[3]; |
| 269 if (!reverseMappings[sourceLine]) |
| 270 reverseMappings[sourceLine] = [mapping[0], mapping[1]]; |
| 271 } |
| 272 }, |
| 273 |
| 274 /** |
| 275 * @param {string} char |
| 276 * @return {boolean} |
| 277 */ |
| 278 _isSeparator: function(char) |
| 279 { |
| 280 return char === "," || char === ";"; |
| 281 }, |
| 282 |
| 283 /** |
| 284 * @param {WebInspector.SourceMap.StringCharIterator} stringCharIterator |
| 285 * @return {number} |
| 286 */ |
| 287 _decodeVLQ: function(stringCharIterator) |
| 288 { |
| 289 // Read unsigned value. |
| 290 var result = 0; |
| 291 var shift = 0; |
| 292 do { |
| 293 var digit = this._base64Map[stringCharIterator.next()]; |
| 294 result += (digit & this._VLQ_BASE_MASK) << shift; |
| 295 shift += this._VLQ_BASE_SHIFT; |
| 296 } while (digit & this._VLQ_CONTINUATION_MASK); |
| 297 |
| 298 // Fix the sign. |
| 299 var negative = result & 1; |
| 300 result >>= 1; |
| 301 return negative ? -result : result; |
| 302 }, |
| 303 |
| 304 _VLQ_BASE_SHIFT: 5, |
| 305 _VLQ_BASE_MASK: (1 << 5) - 1, |
| 306 _VLQ_CONTINUATION_MASK: 1 << 5 |
| 307 } |
| 308 |
| 309 /** |
| 310 * @constructor |
| 311 * @param {string} string |
| 312 */ |
| 313 WebInspector.SourceMap.StringCharIterator = function(string) |
| 314 { |
| 315 this._string = string; |
| 316 this._position = 0; |
| 317 } |
| 318 |
| 319 WebInspector.SourceMap.StringCharIterator.prototype = { |
| 320 /** |
| 321 * @return {string} |
| 322 */ |
| 323 next: function() |
| 324 { |
| 325 return this._string.charAt(this._position++); |
| 326 }, |
| 327 |
| 328 /** |
| 329 * @return {string} |
| 330 */ |
| 331 peek: function() |
| 332 { |
| 333 return this._string.charAt(this._position); |
| 334 }, |
| 335 |
| 336 /** |
| 337 * @return {boolean} |
| 338 */ |
| 339 hasNext: function() |
| 340 { |
| 341 return this._position < this._string.length; |
| 342 } |
| 343 } |
OLD | NEW |