| // Copyright 2013 the V8 project authors. All rights reserved. | |
| // Redistribution and use in source and binary forms, with or without | |
| // modification, are permitted provided that the following conditions are | |
| // met: | |
| // | |
| // * Redistributions of source code must retain the above copyright | |
| // notice, this list of conditions and the following disclaimer. | |
| // * Redistributions in binary form must reproduce the above | |
| // copyright notice, this list of conditions and the following | |
| // disclaimer in the documentation and/or other materials provided | |
| // with the distribution. | |
| // * Neither the name of Google Inc. nor the names of its | |
| // contributors may be used to endorse or promote products derived | |
| // from this software without specific prior written permission. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| // This is a copy from blink dev tools, see: | |
| // http://src.chromium.org/viewvc/blink/trunk/Source/devtools/front_end/SourceMap.js | |
| // revision: 153407 | |
| // Added to make the file work without dev tools | |
| WebInspector = {}; | |
| WebInspector.ParsedURL = {}; | |
| WebInspector.ParsedURL.completeURL = function(){}; | |
| // start of original file content | |
| /* | |
| * Copyright (C) 2012 Google Inc. All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: | |
| * | |
| * * Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * * Redistributions in binary form must reproduce the above | |
| * copyright notice, this list of conditions and the following disclaimer | |
| * in the documentation and/or other materials provided with the | |
| * distribution. | |
| * * Neither the name of Google Inc. nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| /** | |
| * Implements Source Map V3 model. See http://code.google.com/p/closure-compiler/wiki/SourceMaps | |
| * for format description. | |
| * @constructor | |
| * @param {string} sourceMappingURL | |
| * @param {SourceMapV3} payload | |
| */ | |
| WebInspector.SourceMap = function(sourceMappingURL, payload) | |
| { | |
| if (!WebInspector.SourceMap.prototype._base64Map) { | |
| const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
| WebInspector.SourceMap.prototype._base64Map = {}; | |
| for (var i = 0; i < base64Digits.length; ++i) | |
| WebInspector.SourceMap.prototype._base64Map[base64Digits.charAt(i)] = i; | |
| } | |
| this._sourceMappingURL = sourceMappingURL; | |
| this._reverseMappingsBySourceURL = {}; | |
| this._mappings = []; | |
| this._sources = {}; | |
| this._sourceContentByURL = {}; | |
| this._parseMappingPayload(payload); | |
| } | |
| /** | |
| * @param {string} sourceMapURL | |
| * @param {string} compiledURL | |
| * @param {function(WebInspector.SourceMap)} callback | |
| */ | |
| WebInspector.SourceMap.load = function(sourceMapURL, compiledURL, callback) | |
| { | |
| NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.mainFrame.id, sourceMapURL, undefined, contentLoaded.bind(this)); | |
| /** | |
| * @param {?Protocol.Error} error | |
| * @param {number} statusCode | |
| * @param {NetworkAgent.Headers} headers | |
| * @param {string} content | |
| */ | |
| function contentLoaded(error, statusCode, headers, content) | |
| { | |
| if (error || !content || statusCode >= 400) { | |
| console.error("Could not load content for " + sourceMapURL + " : " + (error || ("HTTP status code: " + statusCode))); | |
| callback(null); | |
| return; | |
| } | |
| if (content.slice(0, 3) === ")]}") | |
| content = content.substring(content.indexOf('\n')); | |
| try { | |
| var payload = /** @type {SourceMapV3} */ (JSON.parse(content)); | |
| var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourceMapURL; | |
| callback(new WebInspector.SourceMap(baseURL, payload)); | |
| } catch(e) { | |
| console.error(e.message); | |
| callback(null); | |
| } | |
| } | |
| } | |
| WebInspector.SourceMap.prototype = { | |
| /** | |
| * @return {Array.<string>} | |
| */ | |
| sources: function() | |
| { | |
| return Object.keys(this._sources); | |
| }, | |
| /** | |
| * @param {string} sourceURL | |
| * @return {string|undefined} | |
| */ | |
| sourceContent: function(sourceURL) | |
| { | |
| return this._sourceContentByURL[sourceURL]; | |
| }, | |
| /** | |
| * @param {string} sourceURL | |
| * @param {WebInspector.ResourceType} contentType | |
| * @return {WebInspector.ContentProvider} | |
| */ | |
| sourceContentProvider: function(sourceURL, contentType) | |
| { | |
| var lastIndexOfDot = sourceURL.lastIndexOf("."); | |
| var extension = lastIndexOfDot !== -1 ? sourceURL.substr(lastIndexOfDot + 1) : ""; | |
| var mimeType = WebInspector.ResourceType.mimeTypesForExtensions[extension.toLowerCase()]; | |
| var sourceContent = this.sourceContent(sourceURL); | |
| if (sourceContent) | |
| return new WebInspector.StaticContentProvider(contentType, sourceContent, mimeType); | |
| return new WebInspector.CompilerSourceMappingContentProvider(sourceURL, contentType, mimeType); | |
| }, | |
| /** | |
| * @param {SourceMapV3} mappingPayload | |
| */ | |
| _parseMappingPayload: function(mappingPayload) | |
| { | |
| if (mappingPayload.sections) | |
| this._parseSections(mappingPayload.sections); | |
| else | |
| this._parseMap(mappingPayload, 0, 0); | |
| }, | |
| /** | |
| * @param {Array.<SourceMapV3.Section>} sections | |
| */ | |
| _parseSections: function(sections) | |
| { | |
| for (var i = 0; i < sections.length; ++i) { | |
| var section = sections[i]; | |
| this._parseMap(section.map, section.offset.line, section.offset.column); | |
| } | |
| }, | |
| /** | |
| * @param {number} lineNumber in compiled resource | |
| * @param {number} columnNumber in compiled resource | |
| * @return {?Array} | |
| */ | |
| findEntry: function(lineNumber, columnNumber) | |
| { | |
| var first = 0; | |
| var count = this._mappings.length; | |
| while (count > 1) { | |
| var step = count >> 1; | |
| var middle = first + step; | |
| var mapping = this._mappings[middle]; | |
| if (lineNumber < mapping[0] || (lineNumber === mapping[0] && columnNumber < mapping[1])) | |
| count = step; | |
| else { | |
| first = middle; | |
| count -= step; | |
| } | |
| } | |
| var entry = this._mappings[first]; | |
| if (!first && entry && (lineNumber < entry[0] || (lineNumber === entry[0] && columnNumber < entry[1]))) | |
| return null; | |
| return entry; | |
| }, | |
| /** | |
| * @param {string} sourceURL of the originating resource | |
| * @param {number} lineNumber in the originating resource | |
| * @return {Array} | |
| */ | |
| findEntryReversed: function(sourceURL, lineNumber) | |
| { | |
| var mappings = this._reverseMappingsBySourceURL[sourceURL]; | |
| for ( ; lineNumber < mappings.length; ++lineNumber) { | |
| var mapping = mappings[lineNumber]; | |
| if (mapping) | |
| return mapping; | |
| } | |
| return this._mappings[0]; | |
| }, | |
| /** | |
| * @override | |
| */ | |
| _parseMap: function(map, lineNumber, columnNumber) | |
| { | |
| var sourceIndex = 0; | |
| var sourceLineNumber = 0; | |
| var sourceColumnNumber = 0; | |
| var nameIndex = 0; | |
| var sources = []; | |
| var originalToCanonicalURLMap = {}; | |
| for (var i = 0; i < map.sources.length; ++i) { | |
| var originalSourceURL = map.sources[i]; | |
| var sourceRoot = map.sourceRoot || ""; | |
| if (sourceRoot && !sourceRoot.endsWith("/")) | |
| sourceRoot += "/"; | |
| var href = sourceRoot + originalSourceURL; | |
| var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href; | |
| originalToCanonicalURLMap[originalSourceURL] = url; | |
| sources.push(url); | |
| this._sources[url] = true; | |
| if (map.sourcesContent && map.sourcesContent[i]) | |
| this._sourceContentByURL[url] = map.sourcesContent[i]; | |
| } | |
| var stringCharIterator = new WebInspector.SourceMap.StringCharIterator(map.mappings); | |
| var sourceURL = sources[sourceIndex]; | |
| while (true) { | |
| if (stringCharIterator.peek() === ",") | |
| stringCharIterator.next(); | |
| else { | |
| while (stringCharIterator.peek() === ";") { | |
| lineNumber += 1; | |
| columnNumber = 0; | |
| stringCharIterator.next(); | |
| } | |
| if (!stringCharIterator.hasNext()) | |
| break; | |
| } | |
| columnNumber += this._decodeVLQ(stringCharIterator); | |
| if (this._isSeparator(stringCharIterator.peek())) { | |
| this._mappings.push([lineNumber, columnNumber]); | |
| continue; | |
| } | |
| var sourceIndexDelta = this._decodeVLQ(stringCharIterator); | |
| if (sourceIndexDelta) { | |
| sourceIndex += sourceIndexDelta; | |
| sourceURL = sources[sourceIndex]; | |
| } | |
| sourceLineNumber += this._decodeVLQ(stringCharIterator); | |
| sourceColumnNumber += this._decodeVLQ(stringCharIterator); | |
| if (!this._isSeparator(stringCharIterator.peek())) | |
| nameIndex += this._decodeVLQ(stringCharIterator); | |
| this._mappings.push([lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber]); | |
| } | |
| for (var i = 0; i < this._mappings.length; ++i) { | |
| var mapping = this._mappings[i]; | |
| var url = mapping[2]; | |
| if (!url) | |
| continue; | |
| if (!this._reverseMappingsBySourceURL[url]) | |
| this._reverseMappingsBySourceURL[url] = []; | |
| var reverseMappings = this._reverseMappingsBySourceURL[url]; | |
| var sourceLine = mapping[3]; | |
| if (!reverseMappings[sourceLine]) | |
| reverseMappings[sourceLine] = [mapping[0], mapping[1]]; | |
| } | |
| }, | |
| /** | |
| * @param {string} char | |
| * @return {boolean} | |
| */ | |
| _isSeparator: function(char) | |
| { | |
| return char === "," || char === ";"; | |
| }, | |
| /** | |
| * @param {WebInspector.SourceMap.StringCharIterator} stringCharIterator | |
| * @return {number} | |
| */ | |
| _decodeVLQ: function(stringCharIterator) | |
| { | |
| // Read unsigned value. | |
| var result = 0; | |
| var shift = 0; | |
| do { | |
| var digit = this._base64Map[stringCharIterator.next()]; | |
| result += (digit & this._VLQ_BASE_MASK) << shift; | |
| shift += this._VLQ_BASE_SHIFT; | |
| } while (digit & this._VLQ_CONTINUATION_MASK); | |
| // Fix the sign. | |
| var negative = result & 1; | |
| result >>= 1; | |
| return negative ? -result : result; | |
| }, | |
| _VLQ_BASE_SHIFT: 5, | |
| _VLQ_BASE_MASK: (1 << 5) - 1, | |
| _VLQ_CONTINUATION_MASK: 1 << 5 | |
| } | |
| /** | |
| * @constructor | |
| * @param {string} string | |
| */ | |
| WebInspector.SourceMap.StringCharIterator = function(string) | |
| { | |
| this._string = string; | |
| this._position = 0; | |
| } | |
| WebInspector.SourceMap.StringCharIterator.prototype = { | |
| /** | |
| * @return {string} | |
| */ | |
| next: function() | |
| { | |
| return this._string.charAt(this._position++); | |
| }, | |
| /** | |
| * @return {string} | |
| */ | |
| peek: function() | |
| { | |
| return this._string.charAt(this._position); | |
| }, | |
| /** | |
| * @return {boolean} | |
| */ | |
| hasNext: function() | |
| { | |
| return this._position < this._string.length; | |
| } | |
| } |