source-map-support.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /**
  2. * Module dependencies.
  3. */
  4. var SourceMap = require('source-map').SourceMapGenerator;
  5. var SourceMapConsumer = require('source-map').SourceMapConsumer;
  6. var sourceMapResolve = require('source-map-resolve');
  7. var urix = require('urix');
  8. var fs = require('fs');
  9. var path = require('path');
  10. /**
  11. * Expose `mixin()`.
  12. */
  13. module.exports = mixin;
  14. /**
  15. * Mixin source map support into `compiler`.
  16. *
  17. * @param {Compiler} compiler
  18. * @api public
  19. */
  20. function mixin(compiler) {
  21. compiler._comment = compiler.comment;
  22. compiler.map = new SourceMap();
  23. compiler.position = { line: 1, column: 1 };
  24. compiler.files = {};
  25. for (var k in exports) compiler[k] = exports[k];
  26. }
  27. /**
  28. * Update position.
  29. *
  30. * @param {String} str
  31. * @api private
  32. */
  33. exports.updatePosition = function(str) {
  34. var lines = str.match(/\n/g);
  35. if (lines) this.position.line += lines.length;
  36. var i = str.lastIndexOf('\n');
  37. this.position.column = ~i ? str.length - i : this.position.column + str.length;
  38. };
  39. /**
  40. * Emit `str`.
  41. *
  42. * @param {String} str
  43. * @param {Object} [pos]
  44. * @return {String}
  45. * @api private
  46. */
  47. exports.emit = function(str, pos) {
  48. if (pos) {
  49. var sourceFile = urix(pos.source || 'source.css');
  50. this.map.addMapping({
  51. source: sourceFile,
  52. generated: {
  53. line: this.position.line,
  54. column: Math.max(this.position.column - 1, 0)
  55. },
  56. original: {
  57. line: pos.start.line,
  58. column: pos.start.column - 1
  59. }
  60. });
  61. this.addFile(sourceFile, pos);
  62. }
  63. this.updatePosition(str);
  64. return str;
  65. };
  66. /**
  67. * Adds a file to the source map output if it has not already been added
  68. * @param {String} file
  69. * @param {Object} pos
  70. */
  71. exports.addFile = function(file, pos) {
  72. if (typeof pos.content !== 'string') return;
  73. if (Object.prototype.hasOwnProperty.call(this.files, file)) return;
  74. this.files[file] = pos.content;
  75. };
  76. /**
  77. * Applies any original source maps to the output and embeds the source file
  78. * contents in the source map.
  79. */
  80. exports.applySourceMaps = function() {
  81. Object.keys(this.files).forEach(function(file) {
  82. var content = this.files[file];
  83. this.map.setSourceContent(file, content);
  84. if (this.options.inputSourcemaps !== false) {
  85. var originalMap = sourceMapResolve.resolveSync(
  86. content, file, fs.readFileSync);
  87. if (originalMap) {
  88. var map = new SourceMapConsumer(originalMap.map);
  89. var relativeTo = originalMap.sourcesRelativeTo;
  90. this.map.applySourceMap(map, file, urix(path.dirname(relativeTo)));
  91. }
  92. }
  93. }, this);
  94. };
  95. /**
  96. * Process comments, drops sourceMap comments.
  97. * @param {Object} node
  98. */
  99. exports.comment = function(node) {
  100. if (/^# sourceMappingURL=/.test(node.comment))
  101. return this.emit('', node.position);
  102. else
  103. return this._comment(node);
  104. };