source: imaps-frontend/node_modules/source-map-js/lib/source-map-consumer.js@ 0c6b92a

main
Last change on this file since 0c6b92a was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

  • Property mode set to 100644
File size: 40.6 KB
RevLine 
[d565449]1/* -*- Mode: js; js-indent-level: 2; -*- */
2/*
3 * Copyright 2011 Mozilla Foundation and contributors
4 * Licensed under the New BSD license. See LICENSE or:
5 * http://opensource.org/licenses/BSD-3-Clause
6 */
7
8var util = require('./util');
9var binarySearch = require('./binary-search');
10var ArraySet = require('./array-set').ArraySet;
11var base64VLQ = require('./base64-vlq');
12var quickSort = require('./quick-sort').quickSort;
13
14function SourceMapConsumer(aSourceMap, aSourceMapURL) {
15 var sourceMap = aSourceMap;
16 if (typeof aSourceMap === 'string') {
17 sourceMap = util.parseSourceMapInput(aSourceMap);
18 }
19
20 return sourceMap.sections != null
21 ? new IndexedSourceMapConsumer(sourceMap, aSourceMapURL)
22 : new BasicSourceMapConsumer(sourceMap, aSourceMapURL);
23}
24
25SourceMapConsumer.fromSourceMap = function(aSourceMap, aSourceMapURL) {
26 return BasicSourceMapConsumer.fromSourceMap(aSourceMap, aSourceMapURL);
27}
28
29/**
30 * The version of the source mapping spec that we are consuming.
31 */
32SourceMapConsumer.prototype._version = 3;
33
34// `__generatedMappings` and `__originalMappings` are arrays that hold the
35// parsed mapping coordinates from the source map's "mappings" attribute. They
36// are lazily instantiated, accessed via the `_generatedMappings` and
37// `_originalMappings` getters respectively, and we only parse the mappings
38// and create these arrays once queried for a source location. We jump through
39// these hoops because there can be many thousands of mappings, and parsing
40// them is expensive, so we only want to do it if we must.
41//
42// Each object in the arrays is of the form:
43//
44// {
45// generatedLine: The line number in the generated code,
46// generatedColumn: The column number in the generated code,
47// source: The path to the original source file that generated this
48// chunk of code,
49// originalLine: The line number in the original source that
50// corresponds to this chunk of generated code,
51// originalColumn: The column number in the original source that
52// corresponds to this chunk of generated code,
53// name: The name of the original symbol which generated this chunk of
54// code.
55// }
56//
57// All properties except for `generatedLine` and `generatedColumn` can be
58// `null`.
59//
60// `_generatedMappings` is ordered by the generated positions.
61//
62// `_originalMappings` is ordered by the original positions.
63
64SourceMapConsumer.prototype.__generatedMappings = null;
65Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', {
66 configurable: true,
67 enumerable: true,
68 get: function () {
69 if (!this.__generatedMappings) {
70 this._parseMappings(this._mappings, this.sourceRoot);
71 }
72
73 return this.__generatedMappings;
74 }
75});
76
77SourceMapConsumer.prototype.__originalMappings = null;
78Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', {
79 configurable: true,
80 enumerable: true,
81 get: function () {
82 if (!this.__originalMappings) {
83 this._parseMappings(this._mappings, this.sourceRoot);
84 }
85
86 return this.__originalMappings;
87 }
88});
89
90SourceMapConsumer.prototype._charIsMappingSeparator =
91 function SourceMapConsumer_charIsMappingSeparator(aStr, index) {
92 var c = aStr.charAt(index);
93 return c === ";" || c === ",";
94 };
95
96/**
97 * Parse the mappings in a string in to a data structure which we can easily
98 * query (the ordered arrays in the `this.__generatedMappings` and
99 * `this.__originalMappings` properties).
100 */
101SourceMapConsumer.prototype._parseMappings =
102 function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
103 throw new Error("Subclasses must implement _parseMappings");
104 };
105
106SourceMapConsumer.GENERATED_ORDER = 1;
107SourceMapConsumer.ORIGINAL_ORDER = 2;
108
109SourceMapConsumer.GREATEST_LOWER_BOUND = 1;
110SourceMapConsumer.LEAST_UPPER_BOUND = 2;
111
112/**
113 * Iterate over each mapping between an original source/line/column and a
114 * generated line/column in this source map.
115 *
116 * @param Function aCallback
117 * The function that is called with each mapping.
118 * @param Object aContext
119 * Optional. If specified, this object will be the value of `this` every
120 * time that `aCallback` is called.
121 * @param aOrder
122 * Either `SourceMapConsumer.GENERATED_ORDER` or
123 * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
124 * iterate over the mappings sorted by the generated file's line/column
125 * order or the original's source/line/column order, respectively. Defaults to
126 * `SourceMapConsumer.GENERATED_ORDER`.
127 */
128SourceMapConsumer.prototype.eachMapping =
129 function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
130 var context = aContext || null;
131 var order = aOrder || SourceMapConsumer.GENERATED_ORDER;
132
133 var mappings;
134 switch (order) {
135 case SourceMapConsumer.GENERATED_ORDER:
136 mappings = this._generatedMappings;
137 break;
138 case SourceMapConsumer.ORIGINAL_ORDER:
139 mappings = this._originalMappings;
140 break;
141 default:
142 throw new Error("Unknown order of iteration.");
143 }
144
145 var sourceRoot = this.sourceRoot;
146 var boundCallback = aCallback.bind(context);
147 var names = this._names;
148 var sources = this._sources;
149 var sourceMapURL = this._sourceMapURL;
150
151 for (var i = 0, n = mappings.length; i < n; i++) {
152 var mapping = mappings[i];
153 var source = mapping.source === null ? null : sources.at(mapping.source);
[0c6b92a]154 if(source !== null) {
155 source = util.computeSourceURL(sourceRoot, source, sourceMapURL);
156 }
[d565449]157 boundCallback({
158 source: source,
159 generatedLine: mapping.generatedLine,
160 generatedColumn: mapping.generatedColumn,
161 originalLine: mapping.originalLine,
162 originalColumn: mapping.originalColumn,
163 name: mapping.name === null ? null : names.at(mapping.name)
164 });
165 }
166 };
167
168/**
169 * Returns all generated line and column information for the original source,
170 * line, and column provided. If no column is provided, returns all mappings
171 * corresponding to a either the line we are searching for or the next
172 * closest line that has any mappings. Otherwise, returns all mappings
173 * corresponding to the given line and either the column we are searching for
174 * or the next closest column that has any offsets.
175 *
176 * The only argument is an object with the following properties:
177 *
178 * - source: The filename of the original source.
179 * - line: The line number in the original source. The line number is 1-based.
180 * - column: Optional. the column number in the original source.
181 * The column number is 0-based.
182 *
183 * and an array of objects is returned, each with the following properties:
184 *
185 * - line: The line number in the generated source, or null. The
186 * line number is 1-based.
187 * - column: The column number in the generated source, or null.
188 * The column number is 0-based.
189 */
190SourceMapConsumer.prototype.allGeneratedPositionsFor =
191 function SourceMapConsumer_allGeneratedPositionsFor(aArgs) {
192 var line = util.getArg(aArgs, 'line');
193
194 // When there is no exact match, BasicSourceMapConsumer.prototype._findMapping
195 // returns the index of the closest mapping less than the needle. By
196 // setting needle.originalColumn to 0, we thus find the last mapping for
197 // the given line, provided such a mapping exists.
198 var needle = {
199 source: util.getArg(aArgs, 'source'),
200 originalLine: line,
201 originalColumn: util.getArg(aArgs, 'column', 0)
202 };
203
204 needle.source = this._findSourceIndex(needle.source);
205 if (needle.source < 0) {
206 return [];
207 }
208
209 var mappings = [];
210
211 var index = this._findMapping(needle,
212 this._originalMappings,
213 "originalLine",
214 "originalColumn",
215 util.compareByOriginalPositions,
216 binarySearch.LEAST_UPPER_BOUND);
217 if (index >= 0) {
218 var mapping = this._originalMappings[index];
219
220 if (aArgs.column === undefined) {
221 var originalLine = mapping.originalLine;
222
223 // Iterate until either we run out of mappings, or we run into
224 // a mapping for a different line than the one we found. Since
225 // mappings are sorted, this is guaranteed to find all mappings for
226 // the line we found.
227 while (mapping && mapping.originalLine === originalLine) {
228 mappings.push({
229 line: util.getArg(mapping, 'generatedLine', null),
230 column: util.getArg(mapping, 'generatedColumn', null),
231 lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
232 });
233
234 mapping = this._originalMappings[++index];
235 }
236 } else {
237 var originalColumn = mapping.originalColumn;
238
239 // Iterate until either we run out of mappings, or we run into
240 // a mapping for a different line than the one we were searching for.
241 // Since mappings are sorted, this is guaranteed to find all mappings for
242 // the line we are searching for.
243 while (mapping &&
244 mapping.originalLine === line &&
245 mapping.originalColumn == originalColumn) {
246 mappings.push({
247 line: util.getArg(mapping, 'generatedLine', null),
248 column: util.getArg(mapping, 'generatedColumn', null),
249 lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
250 });
251
252 mapping = this._originalMappings[++index];
253 }
254 }
255 }
256
257 return mappings;
258 };
259
260exports.SourceMapConsumer = SourceMapConsumer;
261
262/**
263 * A BasicSourceMapConsumer instance represents a parsed source map which we can
264 * query for information about the original file positions by giving it a file
265 * position in the generated source.
266 *
267 * The first parameter is the raw source map (either as a JSON string, or
268 * already parsed to an object). According to the spec, source maps have the
269 * following attributes:
270 *
271 * - version: Which version of the source map spec this map is following.
272 * - sources: An array of URLs to the original source files.
273 * - names: An array of identifiers which can be referrenced by individual mappings.
274 * - sourceRoot: Optional. The URL root from which all sources are relative.
275 * - sourcesContent: Optional. An array of contents of the original source files.
276 * - mappings: A string of base64 VLQs which contain the actual mappings.
277 * - file: Optional. The generated file this source map is associated with.
278 *
279 * Here is an example source map, taken from the source map spec[0]:
280 *
281 * {
282 * version : 3,
283 * file: "out.js",
284 * sourceRoot : "",
285 * sources: ["foo.js", "bar.js"],
286 * names: ["src", "maps", "are", "fun"],
287 * mappings: "AA,AB;;ABCDE;"
288 * }
289 *
290 * The second parameter, if given, is a string whose value is the URL
291 * at which the source map was found. This URL is used to compute the
292 * sources array.
293 *
294 * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#
295 */
296function BasicSourceMapConsumer(aSourceMap, aSourceMapURL) {
297 var sourceMap = aSourceMap;
298 if (typeof aSourceMap === 'string') {
299 sourceMap = util.parseSourceMapInput(aSourceMap);
300 }
301
302 var version = util.getArg(sourceMap, 'version');
303 var sources = util.getArg(sourceMap, 'sources');
304 // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which
305 // requires the array) to play nice here.
306 var names = util.getArg(sourceMap, 'names', []);
307 var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
308 var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
309 var mappings = util.getArg(sourceMap, 'mappings');
310 var file = util.getArg(sourceMap, 'file', null);
311
312 // Once again, Sass deviates from the spec and supplies the version as a
313 // string rather than a number, so we use loose equality checking here.
314 if (version != this._version) {
315 throw new Error('Unsupported version: ' + version);
316 }
317
318 if (sourceRoot) {
319 sourceRoot = util.normalize(sourceRoot);
320 }
321
322 sources = sources
323 .map(String)
324 // Some source maps produce relative source paths like "./foo.js" instead of
325 // "foo.js". Normalize these first so that future comparisons will succeed.
326 // See bugzil.la/1090768.
327 .map(util.normalize)
328 // Always ensure that absolute sources are internally stored relative to
329 // the source root, if the source root is absolute. Not doing this would
330 // be particularly problematic when the source root is a prefix of the
331 // source (valid, but why??). See github issue #199 and bugzil.la/1188982.
332 .map(function (source) {
333 return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source)
334 ? util.relative(sourceRoot, source)
335 : source;
336 });
337
338 // Pass `true` below to allow duplicate names and sources. While source maps
339 // are intended to be compressed and deduplicated, the TypeScript compiler
340 // sometimes generates source maps with duplicates in them. See Github issue
341 // #72 and bugzil.la/889492.
342 this._names = ArraySet.fromArray(names.map(String), true);
343 this._sources = ArraySet.fromArray(sources, true);
344
345 this._absoluteSources = this._sources.toArray().map(function (s) {
346 return util.computeSourceURL(sourceRoot, s, aSourceMapURL);
347 });
348
349 this.sourceRoot = sourceRoot;
350 this.sourcesContent = sourcesContent;
351 this._mappings = mappings;
352 this._sourceMapURL = aSourceMapURL;
353 this.file = file;
354}
355
356BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);
357BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer;
358
359/**
360 * Utility function to find the index of a source. Returns -1 if not
361 * found.
362 */
363BasicSourceMapConsumer.prototype._findSourceIndex = function(aSource) {
364 var relativeSource = aSource;
365 if (this.sourceRoot != null) {
366 relativeSource = util.relative(this.sourceRoot, relativeSource);
367 }
368
369 if (this._sources.has(relativeSource)) {
370 return this._sources.indexOf(relativeSource);
371 }
372
373 // Maybe aSource is an absolute URL as returned by |sources|. In
374 // this case we can't simply undo the transform.
375 var i;
376 for (i = 0; i < this._absoluteSources.length; ++i) {
377 if (this._absoluteSources[i] == aSource) {
378 return i;
379 }
380 }
381
382 return -1;
383};
384
385/**
386 * Create a BasicSourceMapConsumer from a SourceMapGenerator.
387 *
388 * @param SourceMapGenerator aSourceMap
389 * The source map that will be consumed.
390 * @param String aSourceMapURL
391 * The URL at which the source map can be found (optional)
392 * @returns BasicSourceMapConsumer
393 */
394BasicSourceMapConsumer.fromSourceMap =
395 function SourceMapConsumer_fromSourceMap(aSourceMap, aSourceMapURL) {
396 var smc = Object.create(BasicSourceMapConsumer.prototype);
397
398 var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true);
399 var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true);
400 smc.sourceRoot = aSourceMap._sourceRoot;
401 smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(),
402 smc.sourceRoot);
403 smc.file = aSourceMap._file;
404 smc._sourceMapURL = aSourceMapURL;
405 smc._absoluteSources = smc._sources.toArray().map(function (s) {
406 return util.computeSourceURL(smc.sourceRoot, s, aSourceMapURL);
407 });
408
409 // Because we are modifying the entries (by converting string sources and
410 // names to indices into the sources and names ArraySets), we have to make
411 // a copy of the entry or else bad things happen. Shared mutable state
412 // strikes again! See github issue #191.
413
414 var generatedMappings = aSourceMap._mappings.toArray().slice();
415 var destGeneratedMappings = smc.__generatedMappings = [];
416 var destOriginalMappings = smc.__originalMappings = [];
417
418 for (var i = 0, length = generatedMappings.length; i < length; i++) {
419 var srcMapping = generatedMappings[i];
420 var destMapping = new Mapping;
421 destMapping.generatedLine = srcMapping.generatedLine;
422 destMapping.generatedColumn = srcMapping.generatedColumn;
423
424 if (srcMapping.source) {
425 destMapping.source = sources.indexOf(srcMapping.source);
426 destMapping.originalLine = srcMapping.originalLine;
427 destMapping.originalColumn = srcMapping.originalColumn;
428
429 if (srcMapping.name) {
430 destMapping.name = names.indexOf(srcMapping.name);
431 }
432
433 destOriginalMappings.push(destMapping);
434 }
435
436 destGeneratedMappings.push(destMapping);
437 }
438
439 quickSort(smc.__originalMappings, util.compareByOriginalPositions);
440
441 return smc;
442 };
443
444/**
445 * The version of the source mapping spec that we are consuming.
446 */
447BasicSourceMapConsumer.prototype._version = 3;
448
449/**
450 * The list of original sources.
451 */
452Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', {
453 get: function () {
454 return this._absoluteSources.slice();
455 }
456});
457
458/**
459 * Provide the JIT with a nice shape / hidden class.
460 */
461function Mapping() {
462 this.generatedLine = 0;
463 this.generatedColumn = 0;
464 this.source = null;
465 this.originalLine = null;
466 this.originalColumn = null;
467 this.name = null;
468}
469
470/**
471 * Parse the mappings in a string in to a data structure which we can easily
472 * query (the ordered arrays in the `this.__generatedMappings` and
473 * `this.__originalMappings` properties).
474 */
475
476const compareGenerated = util.compareByGeneratedPositionsDeflatedNoLine;
477function sortGenerated(array, start) {
478 let l = array.length;
479 let n = array.length - start;
480 if (n <= 1) {
481 return;
482 } else if (n == 2) {
483 let a = array[start];
484 let b = array[start + 1];
485 if (compareGenerated(a, b) > 0) {
486 array[start] = b;
487 array[start + 1] = a;
488 }
489 } else if (n < 20) {
490 for (let i = start; i < l; i++) {
491 for (let j = i; j > start; j--) {
492 let a = array[j - 1];
493 let b = array[j];
494 if (compareGenerated(a, b) <= 0) {
495 break;
496 }
497 array[j - 1] = b;
498 array[j] = a;
499 }
500 }
501 } else {
502 quickSort(array, compareGenerated, start);
503 }
504}
505BasicSourceMapConsumer.prototype._parseMappings =
506 function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
507 var generatedLine = 1;
508 var previousGeneratedColumn = 0;
509 var previousOriginalLine = 0;
510 var previousOriginalColumn = 0;
511 var previousSource = 0;
512 var previousName = 0;
513 var length = aStr.length;
514 var index = 0;
515 var cachedSegments = {};
516 var temp = {};
517 var originalMappings = [];
518 var generatedMappings = [];
519 var mapping, str, segment, end, value;
520
521 let subarrayStart = 0;
522 while (index < length) {
523 if (aStr.charAt(index) === ';') {
524 generatedLine++;
525 index++;
526 previousGeneratedColumn = 0;
527
528 sortGenerated(generatedMappings, subarrayStart);
529 subarrayStart = generatedMappings.length;
530 }
531 else if (aStr.charAt(index) === ',') {
532 index++;
533 }
534 else {
535 mapping = new Mapping();
536 mapping.generatedLine = generatedLine;
537
538 for (end = index; end < length; end++) {
539 if (this._charIsMappingSeparator(aStr, end)) {
540 break;
541 }
542 }
543 str = aStr.slice(index, end);
544
545 segment = [];
546 while (index < end) {
547 base64VLQ.decode(aStr, index, temp);
548 value = temp.value;
549 index = temp.rest;
550 segment.push(value);
551 }
552
553 if (segment.length === 2) {
554 throw new Error('Found a source, but no line and column');
555 }
556
557 if (segment.length === 3) {
558 throw new Error('Found a source and line, but no column');
559 }
560
561 // Generated column.
562 mapping.generatedColumn = previousGeneratedColumn + segment[0];
563 previousGeneratedColumn = mapping.generatedColumn;
564
565 if (segment.length > 1) {
566 // Original source.
567 mapping.source = previousSource + segment[1];
568 previousSource += segment[1];
569
570 // Original line.
571 mapping.originalLine = previousOriginalLine + segment[2];
572 previousOriginalLine = mapping.originalLine;
573 // Lines are stored 0-based
574 mapping.originalLine += 1;
575
576 // Original column.
577 mapping.originalColumn = previousOriginalColumn + segment[3];
578 previousOriginalColumn = mapping.originalColumn;
579
580 if (segment.length > 4) {
581 // Original name.
582 mapping.name = previousName + segment[4];
583 previousName += segment[4];
584 }
585 }
586
587 generatedMappings.push(mapping);
588 if (typeof mapping.originalLine === 'number') {
589 let currentSource = mapping.source;
590 while (originalMappings.length <= currentSource) {
591 originalMappings.push(null);
592 }
593 if (originalMappings[currentSource] === null) {
594 originalMappings[currentSource] = [];
595 }
596 originalMappings[currentSource].push(mapping);
597 }
598 }
599 }
600
601 sortGenerated(generatedMappings, subarrayStart);
602 this.__generatedMappings = generatedMappings;
603
604 for (var i = 0; i < originalMappings.length; i++) {
605 if (originalMappings[i] != null) {
606 quickSort(originalMappings[i], util.compareByOriginalPositionsNoSource);
607 }
608 }
609 this.__originalMappings = [].concat(...originalMappings);
610 };
611
612/**
613 * Find the mapping that best matches the hypothetical "needle" mapping that
614 * we are searching for in the given "haystack" of mappings.
615 */
616BasicSourceMapConsumer.prototype._findMapping =
617 function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,
618 aColumnName, aComparator, aBias) {
619 // To return the position we are searching for, we must first find the
620 // mapping for the given position and then return the opposite position it
621 // points to. Because the mappings are sorted, we can use binary search to
622 // find the best mapping.
623
624 if (aNeedle[aLineName] <= 0) {
625 throw new TypeError('Line must be greater than or equal to 1, got '
626 + aNeedle[aLineName]);
627 }
628 if (aNeedle[aColumnName] < 0) {
629 throw new TypeError('Column must be greater than or equal to 0, got '
630 + aNeedle[aColumnName]);
631 }
632
633 return binarySearch.search(aNeedle, aMappings, aComparator, aBias);
634 };
635
636/**
637 * Compute the last column for each generated mapping. The last column is
638 * inclusive.
639 */
640BasicSourceMapConsumer.prototype.computeColumnSpans =
641 function SourceMapConsumer_computeColumnSpans() {
642 for (var index = 0; index < this._generatedMappings.length; ++index) {
643 var mapping = this._generatedMappings[index];
644
645 // Mappings do not contain a field for the last generated columnt. We
646 // can come up with an optimistic estimate, however, by assuming that
647 // mappings are contiguous (i.e. given two consecutive mappings, the
648 // first mapping ends where the second one starts).
649 if (index + 1 < this._generatedMappings.length) {
650 var nextMapping = this._generatedMappings[index + 1];
651
652 if (mapping.generatedLine === nextMapping.generatedLine) {
653 mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1;
654 continue;
655 }
656 }
657
658 // The last mapping for each line spans the entire line.
659 mapping.lastGeneratedColumn = Infinity;
660 }
661 };
662
663/**
664 * Returns the original source, line, and column information for the generated
665 * source's line and column positions provided. The only argument is an object
666 * with the following properties:
667 *
668 * - line: The line number in the generated source. The line number
669 * is 1-based.
670 * - column: The column number in the generated source. The column
671 * number is 0-based.
672 * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or
673 * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the
674 * closest element that is smaller than or greater than the one we are
675 * searching for, respectively, if the exact element cannot be found.
676 * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'.
677 *
678 * and an object is returned with the following properties:
679 *
680 * - source: The original source file, or null.
681 * - line: The line number in the original source, or null. The
682 * line number is 1-based.
683 * - column: The column number in the original source, or null. The
684 * column number is 0-based.
685 * - name: The original identifier, or null.
686 */
687BasicSourceMapConsumer.prototype.originalPositionFor =
688 function SourceMapConsumer_originalPositionFor(aArgs) {
689 var needle = {
690 generatedLine: util.getArg(aArgs, 'line'),
691 generatedColumn: util.getArg(aArgs, 'column')
692 };
693
694 var index = this._findMapping(
695 needle,
696 this._generatedMappings,
697 "generatedLine",
698 "generatedColumn",
699 util.compareByGeneratedPositionsDeflated,
700 util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND)
701 );
702
703 if (index >= 0) {
704 var mapping = this._generatedMappings[index];
705
706 if (mapping.generatedLine === needle.generatedLine) {
707 var source = util.getArg(mapping, 'source', null);
708 if (source !== null) {
709 source = this._sources.at(source);
710 source = util.computeSourceURL(this.sourceRoot, source, this._sourceMapURL);
711 }
712 var name = util.getArg(mapping, 'name', null);
713 if (name !== null) {
714 name = this._names.at(name);
715 }
716 return {
717 source: source,
718 line: util.getArg(mapping, 'originalLine', null),
719 column: util.getArg(mapping, 'originalColumn', null),
720 name: name
721 };
722 }
723 }
724
725 return {
726 source: null,
727 line: null,
728 column: null,
729 name: null
730 };
731 };
732
733/**
734 * Return true if we have the source content for every source in the source
735 * map, false otherwise.
736 */
737BasicSourceMapConsumer.prototype.hasContentsOfAllSources =
738 function BasicSourceMapConsumer_hasContentsOfAllSources() {
739 if (!this.sourcesContent) {
740 return false;
741 }
742 return this.sourcesContent.length >= this._sources.size() &&
743 !this.sourcesContent.some(function (sc) { return sc == null; });
744 };
745
746/**
747 * Returns the original source content. The only argument is the url of the
748 * original source file. Returns null if no original source content is
749 * available.
750 */
751BasicSourceMapConsumer.prototype.sourceContentFor =
752 function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) {
753 if (!this.sourcesContent) {
754 return null;
755 }
756
757 var index = this._findSourceIndex(aSource);
758 if (index >= 0) {
759 return this.sourcesContent[index];
760 }
761
762 var relativeSource = aSource;
763 if (this.sourceRoot != null) {
764 relativeSource = util.relative(this.sourceRoot, relativeSource);
765 }
766
767 var url;
768 if (this.sourceRoot != null
769 && (url = util.urlParse(this.sourceRoot))) {
770 // XXX: file:// URIs and absolute paths lead to unexpected behavior for
771 // many users. We can help them out when they expect file:// URIs to
772 // behave like it would if they were running a local HTTP server. See
773 // https://bugzilla.mozilla.org/show_bug.cgi?id=885597.
774 var fileUriAbsPath = relativeSource.replace(/^file:\/\//, "");
775 if (url.scheme == "file"
776 && this._sources.has(fileUriAbsPath)) {
777 return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]
778 }
779
780 if ((!url.path || url.path == "/")
781 && this._sources.has("/" + relativeSource)) {
782 return this.sourcesContent[this._sources.indexOf("/" + relativeSource)];
783 }
784 }
785
786 // This function is used recursively from
787 // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we
788 // don't want to throw if we can't find the source - we just want to
789 // return null, so we provide a flag to exit gracefully.
790 if (nullOnMissing) {
791 return null;
792 }
793 else {
794 throw new Error('"' + relativeSource + '" is not in the SourceMap.');
795 }
796 };
797
798/**
799 * Returns the generated line and column information for the original source,
800 * line, and column positions provided. The only argument is an object with
801 * the following properties:
802 *
803 * - source: The filename of the original source.
804 * - line: The line number in the original source. The line number
805 * is 1-based.
806 * - column: The column number in the original source. The column
807 * number is 0-based.
808 * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or
809 * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the
810 * closest element that is smaller than or greater than the one we are
811 * searching for, respectively, if the exact element cannot be found.
812 * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'.
813 *
814 * and an object is returned with the following properties:
815 *
816 * - line: The line number in the generated source, or null. The
817 * line number is 1-based.
818 * - column: The column number in the generated source, or null.
819 * The column number is 0-based.
820 */
821BasicSourceMapConsumer.prototype.generatedPositionFor =
822 function SourceMapConsumer_generatedPositionFor(aArgs) {
823 var source = util.getArg(aArgs, 'source');
824 source = this._findSourceIndex(source);
825 if (source < 0) {
826 return {
827 line: null,
828 column: null,
829 lastColumn: null
830 };
831 }
832
833 var needle = {
834 source: source,
835 originalLine: util.getArg(aArgs, 'line'),
836 originalColumn: util.getArg(aArgs, 'column')
837 };
838
839 var index = this._findMapping(
840 needle,
841 this._originalMappings,
842 "originalLine",
843 "originalColumn",
844 util.compareByOriginalPositions,
845 util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND)
846 );
847
848 if (index >= 0) {
849 var mapping = this._originalMappings[index];
850
851 if (mapping.source === needle.source) {
852 return {
853 line: util.getArg(mapping, 'generatedLine', null),
854 column: util.getArg(mapping, 'generatedColumn', null),
855 lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
856 };
857 }
858 }
859
860 return {
861 line: null,
862 column: null,
863 lastColumn: null
864 };
865 };
866
867exports.BasicSourceMapConsumer = BasicSourceMapConsumer;
868
869/**
870 * An IndexedSourceMapConsumer instance represents a parsed source map which
871 * we can query for information. It differs from BasicSourceMapConsumer in
872 * that it takes "indexed" source maps (i.e. ones with a "sections" field) as
873 * input.
874 *
875 * The first parameter is a raw source map (either as a JSON string, or already
876 * parsed to an object). According to the spec for indexed source maps, they
877 * have the following attributes:
878 *
879 * - version: Which version of the source map spec this map is following.
880 * - file: Optional. The generated file this source map is associated with.
881 * - sections: A list of section definitions.
882 *
883 * Each value under the "sections" field has two fields:
884 * - offset: The offset into the original specified at which this section
885 * begins to apply, defined as an object with a "line" and "column"
886 * field.
887 * - map: A source map definition. This source map could also be indexed,
888 * but doesn't have to be.
889 *
890 * Instead of the "map" field, it's also possible to have a "url" field
891 * specifying a URL to retrieve a source map from, but that's currently
892 * unsupported.
893 *
894 * Here's an example source map, taken from the source map spec[0], but
895 * modified to omit a section which uses the "url" field.
896 *
897 * {
898 * version : 3,
899 * file: "app.js",
900 * sections: [{
901 * offset: {line:100, column:10},
902 * map: {
903 * version : 3,
904 * file: "section.js",
905 * sources: ["foo.js", "bar.js"],
906 * names: ["src", "maps", "are", "fun"],
907 * mappings: "AAAA,E;;ABCDE;"
908 * }
909 * }],
910 * }
911 *
912 * The second parameter, if given, is a string whose value is the URL
913 * at which the source map was found. This URL is used to compute the
914 * sources array.
915 *
916 * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt
917 */
918function IndexedSourceMapConsumer(aSourceMap, aSourceMapURL) {
919 var sourceMap = aSourceMap;
920 if (typeof aSourceMap === 'string') {
921 sourceMap = util.parseSourceMapInput(aSourceMap);
922 }
923
924 var version = util.getArg(sourceMap, 'version');
925 var sections = util.getArg(sourceMap, 'sections');
926
927 if (version != this._version) {
928 throw new Error('Unsupported version: ' + version);
929 }
930
931 this._sources = new ArraySet();
932 this._names = new ArraySet();
933
934 var lastOffset = {
935 line: -1,
936 column: 0
937 };
938 this._sections = sections.map(function (s) {
939 if (s.url) {
940 // The url field will require support for asynchronicity.
941 // See https://github.com/mozilla/source-map/issues/16
942 throw new Error('Support for url field in sections not implemented.');
943 }
944 var offset = util.getArg(s, 'offset');
945 var offsetLine = util.getArg(offset, 'line');
946 var offsetColumn = util.getArg(offset, 'column');
947
948 if (offsetLine < lastOffset.line ||
949 (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) {
950 throw new Error('Section offsets must be ordered and non-overlapping.');
951 }
952 lastOffset = offset;
953
954 return {
955 generatedOffset: {
956 // The offset fields are 0-based, but we use 1-based indices when
957 // encoding/decoding from VLQ.
958 generatedLine: offsetLine + 1,
959 generatedColumn: offsetColumn + 1
960 },
961 consumer: new SourceMapConsumer(util.getArg(s, 'map'), aSourceMapURL)
962 }
963 });
964}
965
966IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);
967IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer;
968
969/**
970 * The version of the source mapping spec that we are consuming.
971 */
972IndexedSourceMapConsumer.prototype._version = 3;
973
974/**
975 * The list of original sources.
976 */
977Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', {
978 get: function () {
979 var sources = [];
980 for (var i = 0; i < this._sections.length; i++) {
981 for (var j = 0; j < this._sections[i].consumer.sources.length; j++) {
982 sources.push(this._sections[i].consumer.sources[j]);
983 }
984 }
985 return sources;
986 }
987});
988
989/**
990 * Returns the original source, line, and column information for the generated
991 * source's line and column positions provided. The only argument is an object
992 * with the following properties:
993 *
994 * - line: The line number in the generated source. The line number
995 * is 1-based.
996 * - column: The column number in the generated source. The column
997 * number is 0-based.
998 *
999 * and an object is returned with the following properties:
1000 *
1001 * - source: The original source file, or null.
1002 * - line: The line number in the original source, or null. The
1003 * line number is 1-based.
1004 * - column: The column number in the original source, or null. The
1005 * column number is 0-based.
1006 * - name: The original identifier, or null.
1007 */
1008IndexedSourceMapConsumer.prototype.originalPositionFor =
1009 function IndexedSourceMapConsumer_originalPositionFor(aArgs) {
1010 var needle = {
1011 generatedLine: util.getArg(aArgs, 'line'),
1012 generatedColumn: util.getArg(aArgs, 'column')
1013 };
1014
1015 // Find the section containing the generated position we're trying to map
1016 // to an original position.
1017 var sectionIndex = binarySearch.search(needle, this._sections,
1018 function(needle, section) {
1019 var cmp = needle.generatedLine - section.generatedOffset.generatedLine;
1020 if (cmp) {
1021 return cmp;
1022 }
1023
1024 return (needle.generatedColumn -
1025 section.generatedOffset.generatedColumn);
1026 });
1027 var section = this._sections[sectionIndex];
1028
1029 if (!section) {
1030 return {
1031 source: null,
1032 line: null,
1033 column: null,
1034 name: null
1035 };
1036 }
1037
1038 return section.consumer.originalPositionFor({
1039 line: needle.generatedLine -
1040 (section.generatedOffset.generatedLine - 1),
1041 column: needle.generatedColumn -
1042 (section.generatedOffset.generatedLine === needle.generatedLine
1043 ? section.generatedOffset.generatedColumn - 1
1044 : 0),
1045 bias: aArgs.bias
1046 });
1047 };
1048
1049/**
1050 * Return true if we have the source content for every source in the source
1051 * map, false otherwise.
1052 */
1053IndexedSourceMapConsumer.prototype.hasContentsOfAllSources =
1054 function IndexedSourceMapConsumer_hasContentsOfAllSources() {
1055 return this._sections.every(function (s) {
1056 return s.consumer.hasContentsOfAllSources();
1057 });
1058 };
1059
1060/**
1061 * Returns the original source content. The only argument is the url of the
1062 * original source file. Returns null if no original source content is
1063 * available.
1064 */
1065IndexedSourceMapConsumer.prototype.sourceContentFor =
1066 function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) {
1067 for (var i = 0; i < this._sections.length; i++) {
1068 var section = this._sections[i];
1069
1070 var content = section.consumer.sourceContentFor(aSource, true);
1071 if (content || content === '') {
1072 return content;
1073 }
1074 }
1075 if (nullOnMissing) {
1076 return null;
1077 }
1078 else {
1079 throw new Error('"' + aSource + '" is not in the SourceMap.');
1080 }
1081 };
1082
1083/**
1084 * Returns the generated line and column information for the original source,
1085 * line, and column positions provided. The only argument is an object with
1086 * the following properties:
1087 *
1088 * - source: The filename of the original source.
1089 * - line: The line number in the original source. The line number
1090 * is 1-based.
1091 * - column: The column number in the original source. The column
1092 * number is 0-based.
1093 *
1094 * and an object is returned with the following properties:
1095 *
1096 * - line: The line number in the generated source, or null. The
1097 * line number is 1-based.
1098 * - column: The column number in the generated source, or null.
1099 * The column number is 0-based.
1100 */
1101IndexedSourceMapConsumer.prototype.generatedPositionFor =
1102 function IndexedSourceMapConsumer_generatedPositionFor(aArgs) {
1103 for (var i = 0; i < this._sections.length; i++) {
1104 var section = this._sections[i];
1105
1106 // Only consider this section if the requested source is in the list of
1107 // sources of the consumer.
1108 if (section.consumer._findSourceIndex(util.getArg(aArgs, 'source')) === -1) {
1109 continue;
1110 }
1111 var generatedPosition = section.consumer.generatedPositionFor(aArgs);
1112 if (generatedPosition) {
1113 var ret = {
1114 line: generatedPosition.line +
1115 (section.generatedOffset.generatedLine - 1),
1116 column: generatedPosition.column +
1117 (section.generatedOffset.generatedLine === generatedPosition.line
1118 ? section.generatedOffset.generatedColumn - 1
1119 : 0)
1120 };
1121 return ret;
1122 }
1123 }
1124
1125 return {
1126 line: null,
1127 column: null
1128 };
1129 };
1130
1131/**
1132 * Parse the mappings in a string in to a data structure which we can easily
1133 * query (the ordered arrays in the `this.__generatedMappings` and
1134 * `this.__originalMappings` properties).
1135 */
1136IndexedSourceMapConsumer.prototype._parseMappings =
1137 function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) {
1138 this.__generatedMappings = [];
1139 this.__originalMappings = [];
1140 for (var i = 0; i < this._sections.length; i++) {
1141 var section = this._sections[i];
1142 var sectionMappings = section.consumer._generatedMappings;
1143 for (var j = 0; j < sectionMappings.length; j++) {
1144 var mapping = sectionMappings[j];
1145
1146 var source = section.consumer._sources.at(mapping.source);
[0c6b92a]1147 if(source !== null) {
1148 source = util.computeSourceURL(section.consumer.sourceRoot, source, this._sourceMapURL);
1149 }
[d565449]1150 this._sources.add(source);
1151 source = this._sources.indexOf(source);
1152
1153 var name = null;
1154 if (mapping.name) {
1155 name = section.consumer._names.at(mapping.name);
1156 this._names.add(name);
1157 name = this._names.indexOf(name);
1158 }
1159
1160 // The mappings coming from the consumer for the section have
1161 // generated positions relative to the start of the section, so we
1162 // need to offset them to be relative to the start of the concatenated
1163 // generated file.
1164 var adjustedMapping = {
1165 source: source,
1166 generatedLine: mapping.generatedLine +
1167 (section.generatedOffset.generatedLine - 1),
1168 generatedColumn: mapping.generatedColumn +
1169 (section.generatedOffset.generatedLine === mapping.generatedLine
1170 ? section.generatedOffset.generatedColumn - 1
1171 : 0),
1172 originalLine: mapping.originalLine,
1173 originalColumn: mapping.originalColumn,
1174 name: name
1175 };
1176
1177 this.__generatedMappings.push(adjustedMapping);
1178 if (typeof adjustedMapping.originalLine === 'number') {
1179 this.__originalMappings.push(adjustedMapping);
1180 }
1181 }
1182 }
1183
1184 quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated);
1185 quickSort(this.__originalMappings, util.compareByOriginalPositions);
1186 };
1187
1188exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer;
Note: See TracBrowser for help on using the repository browser.