Index: tools/SourceMap.js |
diff --git a/tools/SourceMap.js b/tools/SourceMap.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9cbd37a73553245c90c05b39ea0c2100971f165f |
--- /dev/null |
+++ b/tools/SourceMap.js |
@@ -0,0 +1,371 @@ |
+// 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; |
+ } |
+} |