index.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. 'use strict';
  2. var SourceMapGenerator = require('source-map').SourceMapGenerator;
  3. function offsetMapping(mapping, offset) {
  4. return { line: offset.line + mapping.line, column: offset.column + mapping.column };
  5. }
  6. function newlinesIn(src) {
  7. if (!src) return 0;
  8. var newlines = src.match(/\n/g);
  9. return newlines ? newlines.length : 0;
  10. }
  11. function Generator(opts) {
  12. opts = opts || {};
  13. this.generator = new SourceMapGenerator({ file: opts.file || '', sourceRoot: opts.sourceRoot || '' });
  14. this.sourcesContent = undefined;
  15. this.opts = opts;
  16. }
  17. /**
  18. * Adds the given mappings to the generator and offsets them if offset is given
  19. *
  20. * @name addMappings
  21. * @function
  22. * @param sourceFile {String} name of the source file
  23. * @param mappings {Array{{Object}} each object has the form { original: { line: _, column: _ }, generated: { line: _, column: _ } }
  24. * @param offset {Object} offset to apply to each mapping. Has the form { line: _, column: _ }
  25. * @return {Object} the generator to allow chaining
  26. */
  27. Generator.prototype.addMappings = function (sourceFile, mappings, offset) {
  28. var generator = this.generator;
  29. offset = offset || {};
  30. offset.line = offset.hasOwnProperty('line') ? offset.line : 0;
  31. offset.column = offset.hasOwnProperty('column') ? offset.column : 0;
  32. mappings.forEach(function (m) {
  33. // only set source if we have original position to handle edgecase (see inline-source-map tests)
  34. generator.addMapping({
  35. source : m.original ? sourceFile : undefined
  36. , original : m.original
  37. , generated : offsetMapping(m.generated, offset)
  38. });
  39. });
  40. return this;
  41. };
  42. /**
  43. * Generates mappings for the given source, assuming that no translation from original to generated is necessary.
  44. *
  45. * @name addGeneratedMappings
  46. * @function
  47. * @param sourceFile {String} name of the source file
  48. * @param source {String} source of the file
  49. * @param offset {Object} offset to apply to each mapping. Has the form { line: _, column: _ }
  50. * @return {Object} the generator to allow chaining
  51. */
  52. Generator.prototype.addGeneratedMappings = function (sourceFile, source, offset) {
  53. var mappings = []
  54. , linesToGenerate = newlinesIn(source) + 1;
  55. for (var line = 1; line <= linesToGenerate; line++) {
  56. var location = { line: line, column: 0 };
  57. mappings.push({ original: location, generated: location });
  58. }
  59. return this.addMappings(sourceFile, mappings, offset);
  60. };
  61. /**
  62. * Adds source content for the given source file.
  63. *
  64. * @name addSourceContent
  65. * @function
  66. * @param sourceFile {String} The source file for which a mapping is included
  67. * @param sourcesContent {String} The content of the source file
  68. * @return {Object} The generator to allow chaining
  69. */
  70. Generator.prototype.addSourceContent = function (sourceFile, sourcesContent) {
  71. this.sourcesContent = this.sourcesContent || {};
  72. this.sourcesContent[sourceFile] = sourcesContent;
  73. return this;
  74. };
  75. /**
  76. * @name base64Encode
  77. * @function
  78. * @return {String} bas64 encoded representation of the added mappings
  79. */
  80. Generator.prototype.base64Encode = function () {
  81. var map = this.toString();
  82. return new Buffer(map).toString('base64');
  83. };
  84. /**
  85. * @name inlineMappingUrl
  86. * @function
  87. * @return {String} comment with base64 encoded representation of the added mappings. Can be inlined at the end of the generated file.
  88. */
  89. Generator.prototype.inlineMappingUrl = function () {
  90. var charset = this.opts.charset || 'utf-8';
  91. return '//# sourceMappingURL=data:application/json;charset=' + charset + ';base64,' + this.base64Encode();
  92. };
  93. Generator.prototype.toJSON = function () {
  94. var map = this.generator.toJSON();
  95. if (!this.sourcesContent) return map;
  96. var toSourcesContent = (function (s) {
  97. if (typeof this.sourcesContent[s] === 'string') {
  98. return this.sourcesContent[s];
  99. } else {
  100. return null;
  101. }
  102. }).bind(this);
  103. map.sourcesContent = map.sources.map(toSourcesContent);
  104. return map;
  105. };
  106. Generator.prototype.toString = function () {
  107. return JSON.stringify(this);
  108. };
  109. Generator.prototype._mappings = function () {
  110. return this.generator._mappings._array;
  111. };
  112. Generator.prototype.gen = function () {
  113. return this.generator;
  114. };
  115. module.exports = function (opts) { return new Generator(opts); };
  116. module.exports.Generator = Generator;