PrefixSource.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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 {string}
  31. */
  32. this._prefix = prefix;
  33. /**
  34. * @private
  35. * @type {Source}
  36. */
  37. this._source =
  38. typeof source === "string" || Buffer.isBuffer(source)
  39. ? new RawSource(source, true)
  40. : source;
  41. }
  42. getPrefix() {
  43. return this._prefix;
  44. }
  45. original() {
  46. return this._source;
  47. }
  48. /**
  49. * @returns {SourceValue} source
  50. */
  51. source() {
  52. const node = /** @type {string} */ (this._source.source());
  53. const prefix = this._prefix;
  54. return prefix + node.replace(REPLACE_REGEX, `\n${prefix}`);
  55. }
  56. // TODO efficient buffer() implementation
  57. /**
  58. * @param {MapOptions=} options map options
  59. * @returns {RawSourceMap | null} map
  60. */
  61. map(options) {
  62. return getMap(this, options);
  63. }
  64. /**
  65. * @param {MapOptions=} options map options
  66. * @returns {SourceAndMap} source and map
  67. */
  68. sourceAndMap(options) {
  69. return getSourceAndMap(this, options);
  70. }
  71. /**
  72. * @param {Options} options options
  73. * @param {OnChunk} onChunk called for each chunk of code
  74. * @param {OnSource} onSource called for each source
  75. * @param {OnName} onName called for each name
  76. * @returns {GeneratedSourceInfo} generated source info
  77. */
  78. streamChunks(options, onChunk, onSource, onName) {
  79. const prefix = this._prefix;
  80. const prefixOffset = prefix.length;
  81. const linesOnly = Boolean(options && options.columns === false);
  82. const { generatedLine, generatedColumn, source } = streamChunks(
  83. this._source,
  84. options,
  85. (
  86. chunk,
  87. generatedLine,
  88. generatedColumn,
  89. sourceIndex,
  90. originalLine,
  91. originalColumn,
  92. nameIndex,
  93. ) => {
  94. if (generatedColumn !== 0) {
  95. // In the middle of the line, we just adject the column
  96. generatedColumn += prefixOffset;
  97. } else if (chunk !== undefined) {
  98. // At the start of the line, when we have source content
  99. // add the prefix as generated mapping
  100. // (in lines only mode we just add it to the original mapping
  101. // for performance reasons)
  102. if (linesOnly || sourceIndex < 0) {
  103. chunk = prefix + chunk;
  104. } else if (prefixOffset > 0) {
  105. onChunk(prefix, generatedLine, generatedColumn, -1, -1, -1, -1);
  106. generatedColumn += prefixOffset;
  107. }
  108. } else if (!linesOnly) {
  109. // Without source content, we only need to adject the column info
  110. // expect in lines only mode where prefix is added to original mapping
  111. generatedColumn += prefixOffset;
  112. }
  113. onChunk(
  114. chunk,
  115. generatedLine,
  116. generatedColumn,
  117. sourceIndex,
  118. originalLine,
  119. originalColumn,
  120. nameIndex,
  121. );
  122. },
  123. onSource,
  124. onName,
  125. );
  126. return {
  127. generatedLine,
  128. generatedColumn:
  129. generatedColumn === 0
  130. ? 0
  131. : prefixOffset + /** @type {number} */ (generatedColumn),
  132. source:
  133. source !== undefined
  134. ? prefix + source.replace(REPLACE_REGEX, `\n${prefix}`)
  135. : undefined,
  136. };
  137. }
  138. /**
  139. * @param {HashLike} hash hash
  140. * @returns {void}
  141. */
  142. updateHash(hash) {
  143. hash.update("PrefixSource");
  144. this._source.updateHash(hash);
  145. hash.update(this._prefix);
  146. }
  147. }
  148. module.exports = PrefixSource;