react / wstein / node_modules / browserify / node_modules / insert-module-globals / node_modules / combine-source-map / node_modules / inline-source-map / node_modules / source-map / lib / source-map / basic-source-map-consumer.js
80620 views/* -*- Mode: js; js-indent-level: 2; -*- */1/*2* Copyright 2011 Mozilla Foundation and contributors3* Licensed under the New BSD license. See LICENSE or:4* http://opensource.org/licenses/BSD-3-Clause5*/6if (typeof define !== 'function') {7var define = require('amdefine')(module, require);8}9define(function (require, exports, module) {1011var util = require('./util');12var binarySearch = require('./binary-search');13var ArraySet = require('./array-set').ArraySet;14var base64VLQ = require('./base64-vlq');15var SourceMapConsumer = require('./source-map-consumer').SourceMapConsumer;1617/**18* A BasicSourceMapConsumer instance represents a parsed source map which we can19* query for information about the original file positions by giving it a file20* position in the generated source.21*22* The only parameter is the raw source map (either as a JSON string, or23* already parsed to an object). According to the spec, source maps have the24* following attributes:25*26* - version: Which version of the source map spec this map is following.27* - sources: An array of URLs to the original source files.28* - names: An array of identifiers which can be referrenced by individual mappings.29* - sourceRoot: Optional. The URL root from which all sources are relative.30* - sourcesContent: Optional. An array of contents of the original source files.31* - mappings: A string of base64 VLQs which contain the actual mappings.32* - file: Optional. The generated file this source map is associated with.33*34* Here is an example source map, taken from the source map spec[0]:35*36* {37* version : 3,38* file: "out.js",39* sourceRoot : "",40* sources: ["foo.js", "bar.js"],41* names: ["src", "maps", "are", "fun"],42* mappings: "AA,AB;;ABCDE;"43* }44*45* [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#46*/47function BasicSourceMapConsumer(aSourceMap) {48var sourceMap = aSourceMap;49if (typeof aSourceMap === 'string') {50sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));51}5253var version = util.getArg(sourceMap, 'version');54var sources = util.getArg(sourceMap, 'sources');55// Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which56// requires the array) to play nice here.57var names = util.getArg(sourceMap, 'names', []);58var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);59var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);60var mappings = util.getArg(sourceMap, 'mappings');61var file = util.getArg(sourceMap, 'file', null);6263// Once again, Sass deviates from the spec and supplies the version as a64// string rather than a number, so we use loose equality checking here.65if (version != this._version) {66throw new Error('Unsupported version: ' + version);67}6869// Some source maps produce relative source paths like "./foo.js" instead of70// "foo.js". Normalize these first so that future comparisons will succeed.71// See bugzil.la/1090768.72sources = sources.map(util.normalize);7374// Pass `true` below to allow duplicate names and sources. While source maps75// are intended to be compressed and deduplicated, the TypeScript compiler76// sometimes generates source maps with duplicates in them. See Github issue77// #72 and bugzil.la/889492.78this._names = ArraySet.fromArray(names, true);79this._sources = ArraySet.fromArray(sources, true);8081this.sourceRoot = sourceRoot;82this.sourcesContent = sourcesContent;83this._mappings = mappings;84this.file = file;85}8687BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);88BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer;8990/**91* Create a BasicSourceMapConsumer from a SourceMapGenerator.92*93* @param SourceMapGenerator aSourceMap94* The source map that will be consumed.95* @returns BasicSourceMapConsumer96*/97BasicSourceMapConsumer.fromSourceMap =98function SourceMapConsumer_fromSourceMap(aSourceMap) {99var smc = Object.create(BasicSourceMapConsumer.prototype);100101smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true);102smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true);103smc.sourceRoot = aSourceMap._sourceRoot;104smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(),105smc.sourceRoot);106smc.file = aSourceMap._file;107108smc.__generatedMappings = aSourceMap._mappings.toArray().slice();109smc.__originalMappings = aSourceMap._mappings.toArray().slice()110.sort(util.compareByOriginalPositions);111112return smc;113};114115/**116* The version of the source mapping spec that we are consuming.117*/118BasicSourceMapConsumer.prototype._version = 3;119120/**121* The list of original sources.122*/123Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', {124get: function () {125return this._sources.toArray().map(function (s) {126return this.sourceRoot != null ? util.join(this.sourceRoot, s) : s;127}, this);128}129});130131/**132* Parse the mappings in a string in to a data structure which we can easily133* query (the ordered arrays in the `this.__generatedMappings` and134* `this.__originalMappings` properties).135*/136BasicSourceMapConsumer.prototype._parseMappings =137function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {138var generatedLine = 1;139var previousGeneratedColumn = 0;140var previousOriginalLine = 0;141var previousOriginalColumn = 0;142var previousSource = 0;143var previousName = 0;144var str = aStr;145var temp = {};146var mapping;147148while (str.length > 0) {149if (str.charAt(0) === ';') {150generatedLine++;151str = str.slice(1);152previousGeneratedColumn = 0;153}154else if (str.charAt(0) === ',') {155str = str.slice(1);156}157else {158mapping = {};159mapping.generatedLine = generatedLine;160161// Generated column.162base64VLQ.decode(str, temp);163mapping.generatedColumn = previousGeneratedColumn + temp.value;164previousGeneratedColumn = mapping.generatedColumn;165str = temp.rest;166167if (str.length > 0 && !this._nextCharIsMappingSeparator(str)) {168// Original source.169base64VLQ.decode(str, temp);170mapping.source = this._sources.at(previousSource + temp.value);171previousSource += temp.value;172str = temp.rest;173if (str.length === 0 || this._nextCharIsMappingSeparator(str)) {174throw new Error('Found a source, but no line and column');175}176177// Original line.178base64VLQ.decode(str, temp);179mapping.originalLine = previousOriginalLine + temp.value;180previousOriginalLine = mapping.originalLine;181// Lines are stored 0-based182mapping.originalLine += 1;183str = temp.rest;184if (str.length === 0 || this._nextCharIsMappingSeparator(str)) {185throw new Error('Found a source and line, but no column');186}187188// Original column.189base64VLQ.decode(str, temp);190mapping.originalColumn = previousOriginalColumn + temp.value;191previousOriginalColumn = mapping.originalColumn;192str = temp.rest;193194if (str.length > 0 && !this._nextCharIsMappingSeparator(str)) {195// Original name.196base64VLQ.decode(str, temp);197mapping.name = this._names.at(previousName + temp.value);198previousName += temp.value;199str = temp.rest;200}201}202203this.__generatedMappings.push(mapping);204if (typeof mapping.originalLine === 'number') {205this.__originalMappings.push(mapping);206}207}208}209210this.__generatedMappings.sort(util.compareByGeneratedPositions);211this.__originalMappings.sort(util.compareByOriginalPositions);212};213214/**215* Find the mapping that best matches the hypothetical "needle" mapping that216* we are searching for in the given "haystack" of mappings.217*/218BasicSourceMapConsumer.prototype._findMapping =219function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,220aColumnName, aComparator) {221// To return the position we are searching for, we must first find the222// mapping for the given position and then return the opposite position it223// points to. Because the mappings are sorted, we can use binary search to224// find the best mapping.225226if (aNeedle[aLineName] <= 0) {227throw new TypeError('Line must be greater than or equal to 1, got '228+ aNeedle[aLineName]);229}230if (aNeedle[aColumnName] < 0) {231throw new TypeError('Column must be greater than or equal to 0, got '232+ aNeedle[aColumnName]);233}234235return binarySearch.search(aNeedle, aMappings, aComparator);236};237238/**239* Compute the last column for each generated mapping. The last column is240* inclusive.241*/242BasicSourceMapConsumer.prototype.computeColumnSpans =243function SourceMapConsumer_computeColumnSpans() {244for (var index = 0; index < this._generatedMappings.length; ++index) {245var mapping = this._generatedMappings[index];246247// Mappings do not contain a field for the last generated columnt. We248// can come up with an optimistic estimate, however, by assuming that249// mappings are contiguous (i.e. given two consecutive mappings, the250// first mapping ends where the second one starts).251if (index + 1 < this._generatedMappings.length) {252var nextMapping = this._generatedMappings[index + 1];253254if (mapping.generatedLine === nextMapping.generatedLine) {255mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1;256continue;257}258}259260// The last mapping for each line spans the entire line.261mapping.lastGeneratedColumn = Infinity;262}263};264265/**266* Returns the original source, line, and column information for the generated267* source's line and column positions provided. The only argument is an object268* with the following properties:269*270* - line: The line number in the generated source.271* - column: The column number in the generated source.272*273* and an object is returned with the following properties:274*275* - source: The original source file, or null.276* - line: The line number in the original source, or null.277* - column: The column number in the original source, or null.278* - name: The original identifier, or null.279*/280BasicSourceMapConsumer.prototype.originalPositionFor =281function SourceMapConsumer_originalPositionFor(aArgs) {282var needle = {283generatedLine: util.getArg(aArgs, 'line'),284generatedColumn: util.getArg(aArgs, 'column')285};286287var index = this._findMapping(needle,288this._generatedMappings,289"generatedLine",290"generatedColumn",291util.compareByGeneratedPositions);292293if (index >= 0) {294var mapping = this._generatedMappings[index];295296if (mapping.generatedLine === needle.generatedLine) {297var source = util.getArg(mapping, 'source', null);298if (source != null && this.sourceRoot != null) {299source = util.join(this.sourceRoot, source);300}301return {302source: source,303line: util.getArg(mapping, 'originalLine', null),304column: util.getArg(mapping, 'originalColumn', null),305name: util.getArg(mapping, 'name', null)306};307}308}309310return {311source: null,312line: null,313column: null,314name: null315};316};317318/**319* Returns the original source content. The only argument is the url of the320* original source file. Returns null if no original source content is321* availible.322*/323BasicSourceMapConsumer.prototype.sourceContentFor =324function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) {325if (!this.sourcesContent) {326return null;327}328329if (this.sourceRoot != null) {330aSource = util.relative(this.sourceRoot, aSource);331}332333if (this._sources.has(aSource)) {334return this.sourcesContent[this._sources.indexOf(aSource)];335}336337var url;338if (this.sourceRoot != null339&& (url = util.urlParse(this.sourceRoot))) {340// XXX: file:// URIs and absolute paths lead to unexpected behavior for341// many users. We can help them out when they expect file:// URIs to342// behave like it would if they were running a local HTTP server. See343// https://bugzilla.mozilla.org/show_bug.cgi?id=885597.344var fileUriAbsPath = aSource.replace(/^file:\/\//, "");345if (url.scheme == "file"346&& this._sources.has(fileUriAbsPath)) {347return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]348}349350if ((!url.path || url.path == "/")351&& this._sources.has("/" + aSource)) {352return this.sourcesContent[this._sources.indexOf("/" + aSource)];353}354}355356// This function is used recursively from357// IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we358// don't want to throw if we can't find the source - we just want to359// return null, so we provide a flag to exit gracefully.360if (nullOnMissing) {361return null;362}363else {364throw new Error('"' + aSource + '" is not in the SourceMap.');365}366};367368/**369* Returns the generated line and column information for the original source,370* line, and column positions provided. The only argument is an object with371* the following properties:372*373* - source: The filename of the original source.374* - line: The line number in the original source.375* - column: The column number in the original source.376*377* and an object is returned with the following properties:378*379* - line: The line number in the generated source, or null.380* - column: The column number in the generated source, or null.381*/382BasicSourceMapConsumer.prototype.generatedPositionFor =383function SourceMapConsumer_generatedPositionFor(aArgs) {384var needle = {385source: util.getArg(aArgs, 'source'),386originalLine: util.getArg(aArgs, 'line'),387originalColumn: util.getArg(aArgs, 'column')388};389390if (this.sourceRoot != null) {391needle.source = util.relative(this.sourceRoot, needle.source);392}393394var index = this._findMapping(needle,395this._originalMappings,396"originalLine",397"originalColumn",398util.compareByOriginalPositions);399400if (index >= 0) {401var mapping = this._originalMappings[index];402403return {404line: util.getArg(mapping, 'generatedLine', null),405column: util.getArg(mapping, 'generatedColumn', null),406lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)407};408}409410return {411line: null,412column: null,413lastColumn: null414};415};416417exports.BasicSourceMapConsumer = BasicSourceMapConsumer;418419});420421422