createMappingsSerializer.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const ALPHABET =
  7. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
  8. const CONTINUATION_BIT = 0x20;
  9. /**
  10. * @callback MappingsSerializer
  11. * @param {number} generatedLine generated line
  12. * @param {number} generatedColumn generated column
  13. * @param {number} sourceIndex source index
  14. * @param {number} originalLine original line
  15. * @param {number} originalColumn generated line
  16. * @param {number} nameIndex generated line
  17. * @returns {string} result
  18. */
  19. // eslint-disable-next-line valid-jsdoc
  20. /**
  21. * @param {{ columns?: boolean }=} options options
  22. * @returns {MappingsSerializer} mappings serializer
  23. */
  24. const createMappingsSerializer = (options) => {
  25. const linesOnly = options && options.columns === false;
  26. return linesOnly
  27. ? createLinesOnlyMappingsSerializer()
  28. : createFullMappingsSerializer();
  29. };
  30. const createFullMappingsSerializer = () => {
  31. let currentLine = 1;
  32. let currentColumn = 0;
  33. let currentSourceIndex = 0;
  34. let currentOriginalLine = 1;
  35. let currentOriginalColumn = 0;
  36. let currentNameIndex = 0;
  37. let activeMapping = false;
  38. let activeName = false;
  39. let initial = true;
  40. // eslint-disable-next-line valid-jsdoc
  41. /** @type {MappingsSerializer} */
  42. return (
  43. generatedLine,
  44. generatedColumn,
  45. sourceIndex,
  46. originalLine,
  47. originalColumn,
  48. nameIndex
  49. ) => {
  50. if (activeMapping && currentLine === generatedLine) {
  51. // A mapping is still active
  52. if (
  53. sourceIndex === currentSourceIndex &&
  54. originalLine === currentOriginalLine &&
  55. originalColumn === currentOriginalColumn &&
  56. !activeName &&
  57. nameIndex < 0
  58. ) {
  59. // avoid repeating the same original mapping
  60. return "";
  61. }
  62. } else {
  63. // No mapping is active
  64. if (sourceIndex < 0) {
  65. // avoid writing unneccessary generated mappings
  66. return "";
  67. }
  68. }
  69. /** @type {undefined | string} */
  70. let str;
  71. if (currentLine < generatedLine) {
  72. str = ";".repeat(generatedLine - currentLine);
  73. currentLine = generatedLine;
  74. currentColumn = 0;
  75. initial = false;
  76. } else if (initial) {
  77. str = "";
  78. initial = false;
  79. } else {
  80. str = ",";
  81. }
  82. /**
  83. * @param {number} value value
  84. * @returns {void}
  85. */
  86. const writeValue = (value) => {
  87. const sign = (value >>> 31) & 1;
  88. const mask = value >> 31;
  89. const absValue = (value + mask) ^ mask;
  90. let data = (absValue << 1) | sign;
  91. for (;;) {
  92. const sextet = data & 0x1f;
  93. data >>= 5;
  94. if (data === 0) {
  95. str += ALPHABET[sextet];
  96. break;
  97. } else {
  98. str += ALPHABET[sextet | CONTINUATION_BIT];
  99. }
  100. }
  101. };
  102. writeValue(generatedColumn - currentColumn);
  103. currentColumn = generatedColumn;
  104. if (sourceIndex >= 0) {
  105. activeMapping = true;
  106. if (sourceIndex === currentSourceIndex) {
  107. str += "A";
  108. } else {
  109. writeValue(sourceIndex - currentSourceIndex);
  110. currentSourceIndex = sourceIndex;
  111. }
  112. writeValue(originalLine - currentOriginalLine);
  113. currentOriginalLine = originalLine;
  114. if (originalColumn === currentOriginalColumn) {
  115. str += "A";
  116. } else {
  117. writeValue(originalColumn - currentOriginalColumn);
  118. currentOriginalColumn = originalColumn;
  119. }
  120. if (nameIndex >= 0) {
  121. writeValue(nameIndex - currentNameIndex);
  122. currentNameIndex = nameIndex;
  123. activeName = true;
  124. } else {
  125. activeName = false;
  126. }
  127. } else {
  128. activeMapping = false;
  129. }
  130. return str;
  131. };
  132. };
  133. const createLinesOnlyMappingsSerializer = () => {
  134. let lastWrittenLine = 0;
  135. let currentLine = 1;
  136. let currentSourceIndex = 0;
  137. let currentOriginalLine = 1;
  138. // eslint-disable-next-line valid-jsdoc
  139. /** @type {MappingsSerializer} */
  140. return (
  141. generatedLine,
  142. _generatedColumn,
  143. sourceIndex,
  144. originalLine,
  145. _originalColumn,
  146. _nameIndex
  147. ) => {
  148. if (sourceIndex < 0) {
  149. // avoid writing generated mappings at all
  150. return "";
  151. }
  152. if (lastWrittenLine === generatedLine) {
  153. // avoid writing multiple original mappings per line
  154. return "";
  155. }
  156. /** @type {undefined | string} */
  157. let str;
  158. /**
  159. * @param {number} value value
  160. * @returns {void}
  161. */
  162. const writeValue = (value) => {
  163. const sign = (value >>> 31) & 1;
  164. const mask = value >> 31;
  165. const absValue = (value + mask) ^ mask;
  166. let data = (absValue << 1) | sign;
  167. for (;;) {
  168. const sextet = data & 0x1f;
  169. data >>= 5;
  170. if (data === 0) {
  171. str += ALPHABET[sextet];
  172. break;
  173. } else {
  174. str += ALPHABET[sextet | CONTINUATION_BIT];
  175. }
  176. }
  177. };
  178. lastWrittenLine = generatedLine;
  179. if (generatedLine === currentLine + 1) {
  180. currentLine = generatedLine;
  181. if (sourceIndex === currentSourceIndex) {
  182. if (originalLine === currentOriginalLine + 1) {
  183. currentOriginalLine = originalLine;
  184. return ";AACA";
  185. } else {
  186. str = ";AA";
  187. writeValue(originalLine - currentOriginalLine);
  188. currentOriginalLine = originalLine;
  189. return str + "A";
  190. }
  191. } else {
  192. str = ";A";
  193. writeValue(sourceIndex - currentSourceIndex);
  194. currentSourceIndex = sourceIndex;
  195. writeValue(originalLine - currentOriginalLine);
  196. currentOriginalLine = originalLine;
  197. return str + "A";
  198. }
  199. } else {
  200. str = ";".repeat(generatedLine - currentLine);
  201. currentLine = generatedLine;
  202. if (sourceIndex === currentSourceIndex) {
  203. if (originalLine === currentOriginalLine + 1) {
  204. currentOriginalLine = originalLine;
  205. return str + "AACA";
  206. } else {
  207. str += "AA";
  208. writeValue(originalLine - currentOriginalLine);
  209. currentOriginalLine = originalLine;
  210. return str + "A";
  211. }
  212. } else {
  213. str += "A";
  214. writeValue(sourceIndex - currentSourceIndex);
  215. currentSourceIndex = sourceIndex;
  216. writeValue(originalLine - currentOriginalLine);
  217. currentOriginalLine = originalLine;
  218. return str + "A";
  219. }
  220. }
  221. };
  222. };
  223. module.exports = createMappingsSerializer;