/** * An IndexedSourceMapConsumer instance represents a parsed source map which * we can query for information. It differs from BasicSourceMapConsumer in * that it takes "indexed" source maps (i.e. ones with a "sections" field) as * input. * * The only parameter is a raw source map (either as a JSON string, or already * parsed to an object). According to the spec for indexed source maps, they * have the following attributes: * * - version: Which version of the source map spec this map is following. * - file: Optional. The generated file this source map is associated with. * - sections: A list of section definitions. * * Each value under the "sections" field has two fields: * - offset: The offset into the original specified at which this section * begins to apply, defined as an object with a "line" and "column" * field. * - map: A source map definition. This source map could also be indexed, * but doesn't have to be. * * Instead of the "map" field, it's also possible to have a "url" field * specifying a URL to retrieve a source map from, but that's currently * unsupported. * * Here's an example source map, taken from the source map spec[0], but * modified to omit a section which uses the "url" field. * * { * version : 3, * file: "app.js", * sections: [{ * offset: {line:100, column:10}, * map: { * version : 3, * file: "section.js", * sources: ["foo.js", "bar.js"], * names: ["src", "maps", "are", "fun"], * mappings: "AAAA,E;;ABCDE;" * } * }], * } * * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt */ public IndexedSourceMapConsumer(SourceMapDescription sourceMapDescription) { var version = sourceMapDescription.Version; var sections = sourceMapDescription.Sections; if (version != Version) { throw new Exception($"Unsupported version: {version}"); } _sources = new ArraySet(); _names = new ArraySet(); var lastOffset = new Offset { Line = -1, Column = 0 }; _sections = sections.Select(s => { if (s.Url != null) { // The url field will require support for asynchronicity. // See https://github.com/mozilla/source-map/issues/16 throw new NotImplementedException("Support for url field in sections not implemented."); } var offset = s.Offset; var offsetLine = s.Offset.Line; var offsetColumn = s.Offset.Column; if (offsetLine < lastOffset.Line || (offsetLine == lastOffset.Line && offsetColumn < lastOffset.Column)) { throw new Exception("Section offsets must be ordered and non-overlapping."); } lastOffset = offset; return(new GeneratedSection { GeneratedOffset = new GeneratedOffset { // The offset fields are 0-based, but we use 1-based indices when // encoding/decoding from VLQ. GeneratedLine = offsetLine + 1, GeneratedColumn = offsetColumn + 1 }, Consumer = GetConsumer(s.Map) }); }).ToList(); }
/** * A BasicSourceMapConsumer instance represents a parsed source map which we can * query for information about the original file positions by giving it a file * position in the generated source. * * The only parameter is the raw source map (either as a JSON string, or * already parsed to an object). According to the spec, source maps have the * following attributes: * * - version: Which version of the source map spec this map is following. * - sources: An array of URLs to the original source files. * - names: An array of identifiers which can be referrenced by individual mappings. * - sourceRoot: Optional. The URL root from which all sources are relative. * - sourcesContent: Optional. An array of contents of the original source files. * - mappings: A string of base64 VLQs which contain the actual mappings. * - file: Optional. The generated file this source map is associated with. * * Here is an example source map, taken from the source map spec[0]: * * { * version : 3, * file: "out.js", * sourceRoot : "", * sources: ["foo.js", "bar.js"], * names: ["src", "maps", "are", "fun"], * mappings: "AA,AB;;ABCDE;" * } * * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# */ public BasicSourceMapConsumer(SourceMapDescription sourceMapDescription) { var sourceMapDescription1 = sourceMapDescription; int version = sourceMapDescription1.Version; string[] sources = sourceMapDescription1.Sources; // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which // requires the array) to play nice here. var names = sourceMapDescription1.Names ?? new string[0]; var sourceRoot = sourceMapDescription1.SourceRoot; var sourcesContent = sourceMapDescription1.SourcesContent; var mappings = sourceMapDescription1.Mappings; // Once again, Sass deviates from the spec and supplies the version as a // string rather than a number, so we use loose equality checking here. if (version != Version) { throw new Exception($"Unsupported version: {version}"); } sources = Enumerable.Select <string, string>(sources // Some source maps produce relative source paths like "./foo.js" instead of // "foo.js". Normalize these first so that future comparisons will succeed. // See bugzil.la/1090768. .Select(Util.Normalize), source => sourceRoot != null && Util.IsAbsolute(sourceRoot) && Util.IsAbsolute(source) ? Util.Relative(sourceRoot, source) : source) .ToArray(); // Pass `true` below to allow duplicate names and sources. While source maps // are intended to be compressed and deduplicated, the TypeScript compiler // sometimes generates source maps with duplicates in them. See Github issue // #72 and bugzil.la/889492. _names = new ArraySet(names, true); _sources = new ArraySet(sources, true); SourceRoot = sourceRoot; SourcesContent = sourcesContent; _mappings = mappings; }
public static ISourceMapConsumer GetConsumer(SourceMapDescription sourceMapDescription) { return(sourceMapDescription.Sections != null ? (ISourceMapConsumer) new IndexedSourceMapConsumer(sourceMapDescription) : new BasicSourceMapConsumer(sourceMapDescription)); }