source-map-output.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. module.exports = function (environment) {
  2. var SourceMapOutput = function (options) {
  3. this._css = [];
  4. this._rootNode = options.rootNode;
  5. this._contentsMap = options.contentsMap;
  6. this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap;
  7. if (options.sourceMapFilename) {
  8. this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/');
  9. }
  10. this._outputFilename = options.outputFilename;
  11. this.sourceMapURL = options.sourceMapURL;
  12. if (options.sourceMapBasepath) {
  13. this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/');
  14. }
  15. if (options.sourceMapRootpath) {
  16. this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/');
  17. if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') {
  18. this._sourceMapRootpath += '/';
  19. }
  20. } else {
  21. this._sourceMapRootpath = '';
  22. }
  23. this._outputSourceFiles = options.outputSourceFiles;
  24. this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator();
  25. this._lineNumber = 0;
  26. this._column = 0;
  27. };
  28. SourceMapOutput.prototype.removeBasepath = function(path) {
  29. if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) {
  30. path = path.substring(this._sourceMapBasepath.length);
  31. if (path.charAt(0) === '\\' || path.charAt(0) === '/') {
  32. path = path.substring(1);
  33. }
  34. }
  35. return path;
  36. };
  37. SourceMapOutput.prototype.normalizeFilename = function(filename) {
  38. filename = filename.replace(/\\/g, '/');
  39. filename = this.removeBasepath(filename);
  40. return (this._sourceMapRootpath || '') + filename;
  41. };
  42. SourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) {
  43. // ignore adding empty strings
  44. if (!chunk) {
  45. return;
  46. }
  47. var lines,
  48. sourceLines,
  49. columns,
  50. sourceColumns,
  51. i;
  52. if (fileInfo && fileInfo.filename) {
  53. var inputSource = this._contentsMap[fileInfo.filename];
  54. // remove vars/banner added to the top of the file
  55. if (this._contentsIgnoredCharsMap[fileInfo.filename]) {
  56. // adjust the index
  57. index -= this._contentsIgnoredCharsMap[fileInfo.filename];
  58. if (index < 0) { index = 0; }
  59. // adjust the source
  60. inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]);
  61. }
  62. inputSource = inputSource.substring(0, index);
  63. sourceLines = inputSource.split('\n');
  64. sourceColumns = sourceLines[sourceLines.length - 1];
  65. }
  66. lines = chunk.split('\n');
  67. columns = lines[lines.length - 1];
  68. if (fileInfo && fileInfo.filename) {
  69. if (!mapLines) {
  70. this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column},
  71. original: { line: sourceLines.length, column: sourceColumns.length},
  72. source: this.normalizeFilename(fileInfo.filename)});
  73. } else {
  74. for (i = 0; i < lines.length; i++) {
  75. this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0},
  76. original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0},
  77. source: this.normalizeFilename(fileInfo.filename)});
  78. }
  79. }
  80. }
  81. if (lines.length === 1) {
  82. this._column += columns.length;
  83. } else {
  84. this._lineNumber += lines.length - 1;
  85. this._column = columns.length;
  86. }
  87. this._css.push(chunk);
  88. };
  89. SourceMapOutput.prototype.isEmpty = function() {
  90. return this._css.length === 0;
  91. };
  92. SourceMapOutput.prototype.toCSS = function(context) {
  93. this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null });
  94. if (this._outputSourceFiles) {
  95. for (var filename in this._contentsMap) {
  96. if (this._contentsMap.hasOwnProperty(filename)) {
  97. var source = this._contentsMap[filename];
  98. if (this._contentsIgnoredCharsMap[filename]) {
  99. source = source.slice(this._contentsIgnoredCharsMap[filename]);
  100. }
  101. this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source);
  102. }
  103. }
  104. }
  105. this._rootNode.genCSS(context, this);
  106. if (this._css.length > 0) {
  107. var sourceMapURL,
  108. sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON());
  109. if (this.sourceMapURL) {
  110. sourceMapURL = this.sourceMapURL;
  111. } else if (this._sourceMapFilename) {
  112. sourceMapURL = this._sourceMapFilename;
  113. }
  114. this.sourceMapURL = sourceMapURL;
  115. this.sourceMap = sourceMapContent;
  116. }
  117. return this._css.join('');
  118. };
  119. return SourceMapOutput;
  120. };