trace-mapping.umd.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@jridgewell/sourcemap-codec'), require('@jridgewell/resolve-uri')) :
  3. typeof define === 'function' && define.amd ? define(['exports', '@jridgewell/sourcemap-codec', '@jridgewell/resolve-uri'], factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.traceMapping = {}, global.sourcemapCodec, global.resolveURI));
  5. })(this, (function (exports, sourcemapCodec, resolveUri) { 'use strict';
  6. function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
  7. var resolveUri__default = /*#__PURE__*/_interopDefaultLegacy(resolveUri);
  8. function resolve(input, base) {
  9. // The base is always treated as a directory, if it's not empty.
  10. // https://github.com/mozilla/source-map/blob/8cb3ee57/lib/util.js#L327
  11. // https://github.com/chromium/chromium/blob/da4adbb3/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js#L400-L401
  12. if (base && !base.endsWith('/'))
  13. base += '/';
  14. return resolveUri__default["default"](input, base);
  15. }
  16. /**
  17. * Removes everything after the last "/", but leaves the slash.
  18. */
  19. function stripFilename(path) {
  20. if (!path)
  21. return '';
  22. const index = path.lastIndexOf('/');
  23. return path.slice(0, index + 1);
  24. }
  25. function maybeSort(mappings, owned) {
  26. const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
  27. if (unsortedIndex === mappings.length)
  28. return mappings;
  29. // If we own the array (meaning we parsed it from JSON), then we're free to directly mutate it. If
  30. // not, we do not want to modify the consumer's input array.
  31. if (!owned)
  32. mappings = mappings.slice();
  33. for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) {
  34. mappings[i] = sortSegments(mappings[i], owned);
  35. }
  36. return mappings;
  37. }
  38. function nextUnsortedSegmentLine(mappings, start) {
  39. for (let i = start; i < mappings.length; i++) {
  40. if (!isSorted(mappings[i]))
  41. return i;
  42. }
  43. return mappings.length;
  44. }
  45. function isSorted(line) {
  46. for (let j = 1; j < line.length; j++) {
  47. if (line[j][0] < line[j - 1][0]) {
  48. return false;
  49. }
  50. }
  51. return true;
  52. }
  53. function sortSegments(line, owned) {
  54. if (!owned)
  55. line = line.slice();
  56. return line.sort(sortComparator);
  57. }
  58. function sortComparator(a, b) {
  59. return a[0] - b[0];
  60. }
  61. /**
  62. * A binary search implementation that returns the index if a match is found.
  63. * If no match is found, then the left-index (the index associated with the item that comes just
  64. * before the desired index) is returned. To maintain proper sort order, a splice would happen at
  65. * the next index:
  66. *
  67. * ```js
  68. * const array = [1, 3];
  69. * const needle = 2;
  70. * const index = binarySearch(array, needle, (item, needle) => item - needle);
  71. *
  72. * assert.equal(index, 0);
  73. * array.splice(index + 1, 0, needle);
  74. * assert.deepEqual(array, [1, 2, 3]);
  75. * ```
  76. */
  77. function binarySearch(haystack, needle, low, high) {
  78. while (low <= high) {
  79. const mid = low + ((high - low) >> 1);
  80. const cmp = haystack[mid][0] - needle;
  81. if (cmp === 0) {
  82. return mid;
  83. }
  84. if (cmp < 0) {
  85. low = mid + 1;
  86. }
  87. else {
  88. high = mid - 1;
  89. }
  90. }
  91. return low - 1;
  92. }
  93. function memoizedState() {
  94. return {
  95. lastKey: -1,
  96. lastNeedle: -1,
  97. lastIndex: -1,
  98. };
  99. }
  100. /**
  101. * This overly complicated beast is just to record the last tested line/column and the resulting
  102. * index, allowing us to skip a few tests if mappings are monotonically increasing.
  103. */
  104. function memoizedBinarySearch(haystack, needle, state, key) {
  105. const { lastKey, lastNeedle, lastIndex } = state;
  106. let low = 0;
  107. let high = haystack.length - 1;
  108. if (key === lastKey) {
  109. if (needle === lastNeedle) {
  110. return lastIndex;
  111. }
  112. if (needle >= lastNeedle) {
  113. // lastIndex may be -1 if the previous needle was not found.
  114. low = Math.max(lastIndex, 0);
  115. }
  116. else {
  117. high = lastIndex;
  118. }
  119. }
  120. state.lastKey = key;
  121. state.lastNeedle = needle;
  122. return (state.lastIndex = binarySearch(haystack, needle, low, high));
  123. }
  124. const INVALID_MAPPING = Object.freeze({
  125. source: null,
  126. line: null,
  127. column: null,
  128. name: null,
  129. });
  130. /**
  131. * Returns the encoded (VLQ string) form of the SourceMap's mappings field.
  132. */
  133. exports.encodedMappings = void 0;
  134. /**
  135. * Returns the decoded (array of lines of segments) form of the SourceMap's mappings field.
  136. */
  137. exports.decodedMappings = void 0;
  138. /**
  139. * A low-level API to find the segment associated with a generated line/column (think, from a
  140. * stack trace). Line and column here are 0-based, unlike `originalPositionFor`.
  141. */
  142. exports.traceSegment = void 0;
  143. /**
  144. * A higher-level API to find the source/line/column associated with a generated line/column
  145. * (think, from a stack trace). Line is 1-based, but column is 0-based, due to legacy behavior in
  146. * `source-map` library.
  147. */
  148. exports.originalPositionFor = void 0;
  149. /**
  150. * Iterates each mapping in generated position order.
  151. */
  152. exports.eachMapping = void 0;
  153. /**
  154. * A helper that skips sorting of the input map's mappings array, which can be expensive for larger
  155. * maps.
  156. */
  157. exports.presortedDecodedMap = void 0;
  158. class TraceMap {
  159. constructor(map, mapUrl) {
  160. this._binarySearchMemo = memoizedState();
  161. const isString = typeof map === 'string';
  162. const parsed = isString ? JSON.parse(map) : map;
  163. const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
  164. this.version = version;
  165. this.file = file;
  166. this.names = names;
  167. this.sourceRoot = sourceRoot;
  168. this.sources = sources;
  169. this.sourcesContent = sourcesContent;
  170. if (sourceRoot || mapUrl) {
  171. const from = resolve(sourceRoot || '', stripFilename(mapUrl));
  172. this.resolvedSources = sources.map((s) => resolve(s || '', from));
  173. }
  174. else {
  175. this.resolvedSources = sources.map((s) => s || '');
  176. }
  177. const { mappings } = parsed;
  178. if (typeof mappings === 'string') {
  179. this._encoded = mappings;
  180. this._decoded = sourcemapCodec.decode(mappings);
  181. }
  182. else {
  183. this._encoded = undefined;
  184. this._decoded = maybeSort(mappings, isString);
  185. }
  186. }
  187. }
  188. (() => {
  189. exports.encodedMappings = (map) => {
  190. var _a;
  191. return ((_a = map._encoded) !== null && _a !== void 0 ? _a : (map._encoded = sourcemapCodec.encode(map._decoded)));
  192. };
  193. exports.decodedMappings = (map) => {
  194. return map._decoded;
  195. };
  196. exports.traceSegment = (map, line, column) => {
  197. const decoded = map._decoded;
  198. // It's common for parent source maps to have pointers to lines that have no
  199. // mapping (like a "//# sourceMappingURL=") at the end of the child file.
  200. if (line >= decoded.length)
  201. return null;
  202. const segments = decoded[line];
  203. const index = memoizedBinarySearch(segments, column, map._binarySearchMemo, line);
  204. // we come before any mapped segment
  205. if (index < 0)
  206. return null;
  207. return segments[index];
  208. };
  209. exports.originalPositionFor = (map, { line, column }) => {
  210. if (line < 1)
  211. throw new Error('`line` must be greater than 0 (lines start at line 1)');
  212. if (column < 0) {
  213. throw new Error('`column` must be greater than or equal to 0 (columns start at column 0)');
  214. }
  215. const segment = exports.traceSegment(map, line - 1, column);
  216. if (segment == null)
  217. return INVALID_MAPPING;
  218. if (segment.length == 1)
  219. return INVALID_MAPPING;
  220. const { names, resolvedSources } = map;
  221. return {
  222. source: resolvedSources[segment[1]],
  223. line: segment[2] + 1,
  224. column: segment[3],
  225. name: segment.length === 5 ? names[segment[4]] : null,
  226. };
  227. };
  228. exports.eachMapping = (map, cb) => {
  229. const decoded = map._decoded;
  230. const { names, resolvedSources } = map;
  231. for (let i = 0; i < decoded.length; i++) {
  232. const line = decoded[i];
  233. for (let j = 0; j < line.length; j++) {
  234. const seg = line[j];
  235. const generatedLine = i + 1;
  236. const generatedColumn = seg[0];
  237. let source = null;
  238. let originalLine = null;
  239. let originalColumn = null;
  240. let name = null;
  241. if (seg.length !== 1) {
  242. source = resolvedSources[seg[1]];
  243. originalLine = seg[2] + 1;
  244. originalColumn = seg[3];
  245. }
  246. if (seg.length === 5)
  247. name = names[seg[4]];
  248. cb({
  249. generatedLine,
  250. generatedColumn,
  251. source,
  252. originalLine,
  253. originalColumn,
  254. name,
  255. });
  256. }
  257. }
  258. };
  259. exports.presortedDecodedMap = (map, mapUrl) => {
  260. const clone = Object.assign({}, map);
  261. clone.mappings = [];
  262. const tracer = new TraceMap(clone, mapUrl);
  263. tracer._decoded = map.mappings;
  264. return tracer;
  265. };
  266. })();
  267. exports.TraceMap = TraceMap;
  268. Object.defineProperty(exports, '__esModule', { value: true });
  269. }));
  270. //# sourceMappingURL=trace-mapping.umd.js.map