createMappingsSerializer.js 5.5 KB

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