PrefixSource.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RawSource = require("./RawSource");
  7. const Source = require("./Source");
  8. const { getMap, getSourceAndMap } = require("./helpers/getFromStreamChunks");
  9. const streamChunks = require("./helpers/streamChunks");
  10. /** @typedef {import("./Source").HashLike} HashLike */
  11. /** @typedef {import("./Source").MapOptions} MapOptions */
  12. /** @typedef {import("./Source").RawSourceMap} RawSourceMap */
  13. /** @typedef {import("./Source").SourceAndMap} SourceAndMap */
  14. /** @typedef {import("./Source").SourceValue} SourceValue */
  15. /** @typedef {import("./helpers/getGeneratedSourceInfo").GeneratedSourceInfo} GeneratedSourceInfo */
  16. /** @typedef {import("./helpers/streamChunks").OnChunk} OnChunk */
  17. /** @typedef {import("./helpers/streamChunks").OnName} OnName */
  18. /** @typedef {import("./helpers/streamChunks").OnSource} OnSource */
  19. /** @typedef {import("./helpers/streamChunks").Options} Options */
  20. const REPLACE_REGEX = /\n(?=.|\s)/g;
  21. class PrefixSource extends Source {
  22. /**
  23. * @param {string} prefix prefix
  24. * @param {string | Buffer | Source} source source
  25. */
  26. constructor(prefix, source) {
  27. super();
  28. /**
  29. * @private
  30. * @type {Source}
  31. */
  32. this._source =
  33. typeof source === "string" || Buffer.isBuffer(source)
  34. ? new RawSource(source, true)
  35. : source;
  36. this._prefix = prefix;
  37. }
  38. getPrefix() {
  39. return this._prefix;
  40. }
  41. original() {
  42. return this._source;
  43. }
  44. /**
  45. * @returns {SourceValue} source
  46. */
  47. source() {
  48. const node = /** @type {string} */ (this._source.source());
  49. const prefix = this._prefix;
  50. return prefix + node.replace(REPLACE_REGEX, `\n${prefix}`);
  51. }
  52. // TODO efficient buffer() implementation
  53. /**
  54. * @param {MapOptions=} options map options
  55. * @returns {RawSourceMap | null} map
  56. */
  57. map(options) {
  58. return getMap(this, options);
  59. }
  60. /**
  61. * @param {MapOptions=} options map options
  62. * @returns {SourceAndMap} source and map
  63. */
  64. sourceAndMap(options) {
  65. return getSourceAndMap(this, options);
  66. }
  67. /**
  68. * @param {Options} options options
  69. * @param {OnChunk} onChunk called for each chunk of code
  70. * @param {OnSource} onSource called for each source
  71. * @param {OnName} onName called for each name
  72. * @returns {GeneratedSourceInfo} generated source info
  73. */
  74. streamChunks(options, onChunk, onSource, onName) {
  75. const prefix = this._prefix;
  76. const prefixOffset = prefix.length;
  77. const linesOnly = Boolean(options && options.columns === false);
  78. const { generatedLine, generatedColumn, source } = streamChunks(
  79. this._source,
  80. options,
  81. (
  82. chunk,
  83. generatedLine,
  84. generatedColumn,
  85. sourceIndex,
  86. originalLine,
  87. originalColumn,
  88. nameIndex,
  89. ) => {
  90. if (generatedColumn !== 0) {
  91. // In the middle of the line, we just adject the column
  92. generatedColumn += prefixOffset;
  93. } else if (chunk !== undefined) {
  94. // At the start of the line, when we have source content
  95. // add the prefix as generated mapping
  96. // (in lines only mode we just add it to the original mapping
  97. // for performance reasons)
  98. if (linesOnly || sourceIndex < 0) {
  99. chunk = prefix + chunk;
  100. } else if (prefixOffset > 0) {
  101. onChunk(prefix, generatedLine, generatedColumn, -1, -1, -1, -1);
  102. generatedColumn += prefixOffset;
  103. }
  104. } else if (!linesOnly) {
  105. // Without source content, we only need to adject the column info
  106. // expect in lines only mode where prefix is added to original mapping
  107. generatedColumn += prefixOffset;
  108. }
  109. onChunk(
  110. chunk,
  111. generatedLine,
  112. generatedColumn,
  113. sourceIndex,
  114. originalLine,
  115. originalColumn,
  116. nameIndex,
  117. );
  118. },
  119. onSource,
  120. onName,
  121. );
  122. return {
  123. generatedLine,
  124. generatedColumn:
  125. generatedColumn === 0
  126. ? 0
  127. : prefixOffset + /** @type {number} */ (generatedColumn),
  128. source:
  129. source !== undefined
  130. ? prefix + source.replace(REPLACE_REGEX, `\n${prefix}`)
  131. : undefined,
  132. };
  133. }
  134. /**
  135. * @param {HashLike} hash hash
  136. * @returns {void}
  137. */
  138. updateHash(hash) {
  139. hash.update("PrefixSource");
  140. this._source.updateHash(hash);
  141. hash.update(this._prefix);
  142. }
  143. }
  144. module.exports = PrefixSource;