/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ var fs = require("fs"); var path = require("path"); var async = require("async"); var loaderUtils = require("loader-utils"); var separatorRegex = /[/\\]/; // Matches only the last occurrence of sourceMappingURL var baseRegex = "\\s*[@#]\\s*sourceMappingURL\\s*=\\s*([^\\s]*)(?![\\S\\s]*sourceMappingURL)", // Matches /* ... */ comments regex1 = new RegExp("/\\*" + baseRegex + "\\s*\\*/"), // Matches // .... comments regex2 = new RegExp("//" + baseRegex + "($|\n|\r\n?)"), // Matches DataUrls regexDataUrl = /data:[^;\n]+(?:;charset=[^;\n]+)?;base64,([a-zA-Z0-9+/]+={0,2})/; module.exports = function (input, inputMap) { this.cacheable && this.cacheable(); var resolve = this.resolve; var addDependency = this.addDependency; var emitWarning = this.emitWarning || function () { }; var match = input.match(regex1) || input.match(regex2); if (match) { var url = match[1]; var dataUrlMatch = regexDataUrl.exec(url); var callback = this.async(); if (dataUrlMatch) { var mapBase64 = dataUrlMatch[1]; var mapStr = (new Buffer(mapBase64, "base64")).toString(); var map; try { map = JSON.parse(mapStr) } catch (e) { emitWarning("Cannot parse inline SourceMap '" + mapBase64.substr(0, 50) + "': " + e); return untouched(); } processMap(map, this.context, callback); } else { resolve(this.context, loaderUtils.urlToRequest(url, true), function (err, result) { if (err) { emitWarning("Cannot find SourceMap '" + url + "': " + err); return untouched(); } addDependency(result); fs.readFile(result, "utf-8", function (err, content) { if (err) { emitWarning("Cannot open SourceMap '" + result + "': " + err); return untouched(); } var map; try { map = JSON.parse(content); } catch (e) { emitWarning("Cannot parse SourceMap '" + url + "': " + e); return untouched(); } processMap(map, path.dirname(result), callback); }); }.bind(this)); } } else { var callback = this.callback; return untouched(); } function untouched() { callback(null, input, inputMap); } function resize(arr, size, defval) { while (arr.length > size) { arr.pop(); } while (arr.length < size) { arr.push(defval); } } function processMap(map, context, callback) { function setResult(map) { callback(null, input.replace(match[0], ''), map); } var sourcesWithoutContent = []; map.sourcesContent = map.sourcesContent || []; resize(map.sourcesContent, map.sources.length, null); map.sourcesContent.forEach(function (sourceContent, i) { if (!sourceContent) { sourcesWithoutContent.push({source: map.sources[i], index: i}) } else { var source = map.sources[i]; if (separatorRegex.test(source) && !path.isAbsolute(source)) { map.sources[i] = path.resolve(context, source); } } }); if (sourcesWithoutContent.length == 0) { setResult(map) } else { var sourcePrefix = map.sourceRoot ? map.sourceRoot + "/" : ""; async.map(sourcesWithoutContent, function (item, callback) { var source = sourcePrefix + item.source; map.sources = map.sources.map(function (s) { return sourcePrefix + s; }); delete map.sourceRoot; resolve(context, loaderUtils.urlToRequest(source, true), function (err, result) { if (err) { // TODO(ilgonmic): Not all JS files have sources content, and we don't extract sources from jar, // so there is no content for these files // emitWarning("Cannot find source file '" + source + "': " + err); return callback(null, null); } addDependency(result); fs.readFile(result, "utf-8", function (err, content) { if (err) { emitWarning("Cannot open source file '" + result + "': " + err); return callback(null, null); } callback(null, { index: item.index, source: result, content: content }); }); }); }, function (err, info) { info.forEach(function (item) { if (item) { map.sources[item.index] = item.source; map.sourcesContent[item.index] = item.content; } }); setResult(map); }); } } };