index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. var fs = require("fs");
  6. var path = require("path");
  7. var async = require("async");
  8. var loaderUtils = require("loader-utils");
  9. // Matches only the last occurrence of sourceMappingURL
  10. var baseRegex = "\\s*[@#]\\s*sourceMappingURL\\s*=\\s*([^\\s]*)(?![\\S\\s]*sourceMappingURL)",
  11. // Matches /* ... */ comments
  12. regex1 = new RegExp("/\\*"+baseRegex+"\\s*\\*/"),
  13. // Matches // .... comments
  14. regex2 = new RegExp("//"+baseRegex+"($|\n|\r\n?)"),
  15. // Matches DataUrls
  16. regexDataUrl = /data:[^;\n]+(?:;charset=[^;\n]+)?;base64,([a-zA-Z0-9+/]+={0,2})/;
  17. module.exports = function(input, inputMap) {
  18. this.cacheable && this.cacheable();
  19. var resolve = this.resolve;
  20. var addDependency = this.addDependency;
  21. var emitWarning = this.emitWarning || function() {};
  22. var match = input.match(regex1) || input.match(regex2);
  23. if(match) {
  24. var url = match[1];
  25. var dataUrlMatch = regexDataUrl.exec(url);
  26. var callback = this.async();
  27. if(dataUrlMatch) {
  28. var mapBase64 = dataUrlMatch[1];
  29. var mapStr = (new Buffer(mapBase64, "base64")).toString();
  30. var map;
  31. try {
  32. map = JSON.parse(mapStr)
  33. } catch (e) {
  34. emitWarning("Cannot parse inline SourceMap '" + mapBase64.substr(0, 50) + "': " + e);
  35. return untouched();
  36. }
  37. processMap(map, this.context, callback);
  38. } else {
  39. resolve(this.context, loaderUtils.urlToRequest(url, true), function(err, result) {
  40. if(err) {
  41. emitWarning("Cannot find SourceMap '" + url + "': " + err);
  42. return untouched();
  43. }
  44. addDependency(result);
  45. fs.readFile(result, "utf-8", function(err, content) {
  46. if(err) {
  47. emitWarning("Cannot open SourceMap '" + result + "': " + err);
  48. return untouched();
  49. }
  50. var map;
  51. try {
  52. map = JSON.parse(content);
  53. } catch (e) {
  54. emitWarning("Cannot parse SourceMap '" + url + "': " + e);
  55. return untouched();
  56. }
  57. processMap(map, path.dirname(result), callback);
  58. });
  59. }.bind(this));
  60. return;
  61. }
  62. } else {
  63. var callback = this.callback;
  64. return untouched();
  65. }
  66. function untouched() {
  67. callback(null, input, inputMap);
  68. }
  69. function processMap(map, context, callback) {
  70. if(!map.sourcesContent || map.sourcesContent.length < map.sources.length) {
  71. var sourcePrefix = map.sourceRoot ? map.sourceRoot + "/" : "";
  72. map.sources = map.sources.map(function(s) { return sourcePrefix + s; });
  73. delete map.sourceRoot;
  74. var missingSources = map.sourcesContent ? map.sources.slice(map.sourcesContent.length) : map.sources;
  75. async.map(missingSources, function(source, callback) {
  76. resolve(context, loaderUtils.urlToRequest(source, true), function(err, result) {
  77. if(err) {
  78. emitWarning("Cannot find source file '" + source + "': " + err);
  79. return callback(null, null);
  80. }
  81. addDependency(result);
  82. fs.readFile(result, "utf-8", function(err, content) {
  83. if(err) {
  84. emitWarning("Cannot open source file '" + result + "': " + err);
  85. return callback(null, null);
  86. }
  87. callback(null, {
  88. source: result,
  89. content: content
  90. });
  91. });
  92. });
  93. }, function(err, info) {
  94. map.sourcesContent = map.sourcesContent || [];
  95. info.forEach(function(res) {
  96. if(res) {
  97. map.sources[map.sourcesContent.length] = res.source;
  98. map.sourcesContent.push(res.content);
  99. } else {
  100. map.sourcesContent.push(null);
  101. }
  102. });
  103. processMap(map, context, callback);
  104. });
  105. return;
  106. }
  107. callback(null, input.replace(match[0], ''), map);
  108. }
  109. }