1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 // This is a copy from blink dev tools, see:
29 // http://src.chromium.org/viewvc/blink/trunk/Source/devtools/front_end/SourceMap.js
32 // Added to make the file work without dev tools
34 WebInspector.ParsedURL = {};
35 WebInspector.ParsedURL.completeURL = function(){};
36 // start of original file content
39 * Copyright (C) 2012 Google Inc. All rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions are
45 * * Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * * Redistributions in binary form must reproduce the above
48 * copyright notice, this list of conditions and the following disclaimer
49 * in the documentation and/or other materials provided with the
51 * * Neither the name of Google Inc. nor the names of its
52 * contributors may be used to endorse or promote products derived from
53 * this software without specific prior written permission.
55 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
56 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
57 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
58 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
59 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
60 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
61 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
62 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
63 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
64 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
65 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69 * Implements Source Map V3 model. See http://code.google.com/p/closure-compiler/wiki/SourceMaps
70 * for format description.
72 * @param {string} sourceMappingURL
73 * @param {SourceMapV3} payload
75 WebInspector.SourceMap = function(sourceMappingURL, payload)
77 if (!WebInspector.SourceMap.prototype._base64Map) {
78 const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
79 WebInspector.SourceMap.prototype._base64Map = {};
80 for (var i = 0; i < base64Digits.length; ++i)
81 WebInspector.SourceMap.prototype._base64Map[base64Digits.charAt(i)] = i;
84 this._sourceMappingURL = sourceMappingURL;
85 this._reverseMappingsBySourceURL = {};
88 this._sourceContentByURL = {};
89 this._parseMappingPayload(payload);
93 * @param {string} sourceMapURL
94 * @param {string} compiledURL
95 * @param {function(WebInspector.SourceMap)} callback
97 WebInspector.SourceMap.load = function(sourceMapURL, compiledURL, callback)
99 NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.mainFrame.id, sourceMapURL, undefined, contentLoaded.bind(this));
102 * @param {?Protocol.Error} error
103 * @param {number} statusCode
104 * @param {NetworkAgent.Headers} headers
105 * @param {string} content
107 function contentLoaded(error, statusCode, headers, content)
109 if (error || !content || statusCode >= 400) {
110 console.error("Could not load content for " + sourceMapURL + " : " + (error || ("HTTP status code: " + statusCode)));
115 if (content.slice(0, 3) === ")]}")
116 content = content.substring(content.indexOf('\n'));
118 var payload = /** @type {SourceMapV3} */ (JSON.parse(content));
119 var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourceMapURL;
120 callback(new WebInspector.SourceMap(baseURL, payload));
122 console.error(e.message);
128 WebInspector.SourceMap.prototype = {
130 * @return {Array.<string>}
134 return Object.keys(this._sources);
138 * @param {string} sourceURL
139 * @return {string|undefined}
141 sourceContent: function(sourceURL)
143 return this._sourceContentByURL[sourceURL];
147 * @param {string} sourceURL
148 * @param {WebInspector.ResourceType} contentType
149 * @return {WebInspector.ContentProvider}
151 sourceContentProvider: function(sourceURL, contentType)
153 var lastIndexOfDot = sourceURL.lastIndexOf(".");
154 var extension = lastIndexOfDot !== -1 ? sourceURL.substr(lastIndexOfDot + 1) : "";
155 var mimeType = WebInspector.ResourceType.mimeTypesForExtensions[extension.toLowerCase()];
156 var sourceContent = this.sourceContent(sourceURL);
158 return new WebInspector.StaticContentProvider(contentType, sourceContent, mimeType);
159 return new WebInspector.CompilerSourceMappingContentProvider(sourceURL, contentType, mimeType);
163 * @param {SourceMapV3} mappingPayload
165 _parseMappingPayload: function(mappingPayload)
167 if (mappingPayload.sections)
168 this._parseSections(mappingPayload.sections);
170 this._parseMap(mappingPayload, 0, 0);
174 * @param {Array.<SourceMapV3.Section>} sections
176 _parseSections: function(sections)
178 for (var i = 0; i < sections.length; ++i) {
179 var section = sections[i];
180 this._parseMap(section.map, section.offset.line, section.offset.column);
185 * @param {number} lineNumber in compiled resource
186 * @param {number} columnNumber in compiled resource
189 findEntry: function(lineNumber, columnNumber)
192 var count = this._mappings.length;
194 var step = count >> 1;
195 var middle = first + step;
196 var mapping = this._mappings[middle];
197 if (lineNumber < mapping[0] || (lineNumber === mapping[0] && columnNumber < mapping[1]))
204 var entry = this._mappings[first];
205 if (!first && entry && (lineNumber < entry[0] || (lineNumber === entry[0] && columnNumber < entry[1])))
211 * @param {string} sourceURL of the originating resource
212 * @param {number} lineNumber in the originating resource
215 findEntryReversed: function(sourceURL, lineNumber)
217 var mappings = this._reverseMappingsBySourceURL[sourceURL];
218 for ( ; lineNumber < mappings.length; ++lineNumber) {
219 var mapping = mappings[lineNumber];
223 return this._mappings[0];
229 _parseMap: function(map, lineNumber, columnNumber)
232 var sourceLineNumber = 0;
233 var sourceColumnNumber = 0;
237 var originalToCanonicalURLMap = {};
238 for (var i = 0; i < map.sources.length; ++i) {
239 var originalSourceURL = map.sources[i];
240 var sourceRoot = map.sourceRoot || "";
241 if (sourceRoot && !sourceRoot.endsWith("/"))
243 var href = sourceRoot + originalSourceURL;
244 var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href;
245 originalToCanonicalURLMap[originalSourceURL] = url;
247 this._sources[url] = true;
249 if (map.sourcesContent && map.sourcesContent[i])
250 this._sourceContentByURL[url] = map.sourcesContent[i];
253 var stringCharIterator = new WebInspector.SourceMap.StringCharIterator(map.mappings);
254 var sourceURL = sources[sourceIndex];
257 if (stringCharIterator.peek() === ",")
258 stringCharIterator.next();
260 while (stringCharIterator.peek() === ";") {
263 stringCharIterator.next();
265 if (!stringCharIterator.hasNext())
269 columnNumber += this._decodeVLQ(stringCharIterator);
270 if (this._isSeparator(stringCharIterator.peek())) {
271 this._mappings.push([lineNumber, columnNumber]);
275 var sourceIndexDelta = this._decodeVLQ(stringCharIterator);
276 if (sourceIndexDelta) {
277 sourceIndex += sourceIndexDelta;
278 sourceURL = sources[sourceIndex];
280 sourceLineNumber += this._decodeVLQ(stringCharIterator);
281 sourceColumnNumber += this._decodeVLQ(stringCharIterator);
282 if (!this._isSeparator(stringCharIterator.peek()))
283 nameIndex += this._decodeVLQ(stringCharIterator);
285 this._mappings.push([lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber]);
288 for (var i = 0; i < this._mappings.length; ++i) {
289 var mapping = this._mappings[i];
290 var url = mapping[2];
293 if (!this._reverseMappingsBySourceURL[url])
294 this._reverseMappingsBySourceURL[url] = [];
295 var reverseMappings = this._reverseMappingsBySourceURL[url];
296 var sourceLine = mapping[3];
297 if (!reverseMappings[sourceLine])
298 reverseMappings[sourceLine] = [mapping[0], mapping[1]];
303 * @param {string} char
306 _isSeparator: function(char)
308 return char === "," || char === ";";
312 * @param {WebInspector.SourceMap.StringCharIterator} stringCharIterator
315 _decodeVLQ: function(stringCharIterator)
317 // Read unsigned value.
321 var digit = this._base64Map[stringCharIterator.next()];
322 result += (digit & this._VLQ_BASE_MASK) << shift;
323 shift += this._VLQ_BASE_SHIFT;
324 } while (digit & this._VLQ_CONTINUATION_MASK);
327 var negative = result & 1;
329 return negative ? -result : result;
333 _VLQ_BASE_MASK: (1 << 5) - 1,
334 _VLQ_CONTINUATION_MASK: 1 << 5
339 * @param {string} string
341 WebInspector.SourceMap.StringCharIterator = function(string)
343 this._string = string;
347 WebInspector.SourceMap.StringCharIterator.prototype = {
353 return this._string.charAt(this._position++);
361 return this._string.charAt(this._position);
369 return this._position < this._string.length;