55/// Contains the top-level function to parse source maps version 3.
66library source_maps.parser;
77
8- import 'dart:collection' ;
98import 'dart:convert' ;
109
1110import 'package:source_span/source_span.dart' ;
@@ -258,6 +257,16 @@ class SingleMapping extends Mapping {
258257 /// Source names used in the mapping, indexed by id.
259258 final List <String > names;
260259
260+ /// The [SourceFile] s to which the entries in [lines] refer.
261+ ///
262+ /// This is in the same order as [urls] . If this was constructed using
263+ /// [fromEntries] , this contains files from any [FileLocation] s used to build
264+ /// the mapping. If it was parsed from JSON, it contains files for any sources
265+ /// whose contents were provided via the `"sourcesContent"` field.
266+ ///
267+ /// Files whose contents aren't available are `null` .
268+ final List <SourceFile > files;
269+
261270 /// Entries indicating the beginning of each span.
262271 final List <TargetLineEntry > lines;
263272
@@ -269,7 +278,7 @@ class SingleMapping extends Mapping {
269278
270279 final Uri _mapUrl;
271280
272- SingleMapping ._(this .targetUrl, this .urls, this .names, this .lines)
281+ SingleMapping ._(this .targetUrl, this .files, this . urls, this .names, this .lines)
273282 : _mapUrl = null ;
274283
275284 factory SingleMapping .fromEntries (Iterable <builder.Entry > entries,
@@ -279,12 +288,15 @@ class SingleMapping extends Mapping {
279288 var lines = < TargetLineEntry > [];
280289
281290 // Indices associated with file urls that will be part of the source map. We
282- // use a linked hash- map so that `_urls .keys[_urls [u]] == u`
283- var urls = new LinkedHashMap <String , int >() ;
291+ // rely on map order so that `urls .keys[urls [u]] == u`
292+ var urls = < String , int > {} ;
284293
285294 // Indices associated with identifiers that will be part of the source map.
286- // We use a linked hash-map so that `_names.keys[_names[n]] == n`
287- var names = new LinkedHashMap <String , int >();
295+ // We rely on map order so that `names.keys[names[n]] == n`
296+ var names = < String , int > {};
297+
298+ /// The file for each URL, indexed by [urls] ' values.
299+ var files = < int , SourceFile > {};
288300
289301 var lineNum;
290302 List <TargetEntry > targetEntries;
@@ -301,6 +313,12 @@ class SingleMapping extends Mapping {
301313 var sourceUrl = sourceEntry.source.sourceUrl;
302314 var urlId = urls.putIfAbsent (
303315 sourceUrl == null ? '' : sourceUrl.toString (), () => urls.length);
316+
317+ if (sourceEntry.source is FileLocation ) {
318+ files.putIfAbsent (
319+ urlId, () => (sourceEntry.source as FileLocation ).file);
320+ }
321+
304322 var srcNameId = sourceEntry.identifierName == null
305323 ? null
306324 : names.putIfAbsent (sourceEntry.identifierName, () => names.length);
@@ -309,16 +327,30 @@ class SingleMapping extends Mapping {
309327 }
310328 }
311329 return new SingleMapping ._(
312- fileUrl, urls.keys.toList (), names.keys.toList (), lines);
330+ fileUrl,
331+ urls.values.map ((i) => files[i]).toList (),
332+ urls.keys.toList (),
333+ names.keys.toList (),
334+ lines);
313335 }
314336
315337 SingleMapping .fromJson (Map map, {mapUrl})
316338 : targetUrl = map['file' ],
317339 urls = new List <String >.from (map['sources' ]),
318340 names = new List <String >.from (map['names' ]),
341+ files = new List (map['sources' ].length),
319342 sourceRoot = map['sourceRoot' ],
320343 lines = < TargetLineEntry > [],
321344 _mapUrl = mapUrl is String ? Uri .parse (mapUrl) : mapUrl {
345+ var sourcesContent = map['sourcesContent' ] == null
346+ ? const []
347+ : new List <String >.from (map['sourcesContent' ]);
348+ for (var i = 0 ; i < urls.length && i < sourcesContent.length; i++ ) {
349+ var source = sourcesContent[i];
350+ if (source == null ) continue ;
351+ files[i] = new SourceFile .fromString (source, url: urls[i]);
352+ }
353+
322354 int line = 0 ;
323355 int column = 0 ;
324356 int srcUrlId = 0 ;
@@ -385,7 +417,10 @@ class SingleMapping extends Mapping {
385417 }
386418
387419 /// Encodes the Mapping mappings as a json map.
388- Map toJson () {
420+ ///
421+ /// If [sourcesContent] is `true` , this includes the source file contents from
422+ /// [files] in the map if possible.
423+ Map toJson ({bool includeSourceContents: false }) {
389424 var buff = new StringBuffer ();
390425 var line = 0 ;
391426 var column = 0 ;
@@ -431,9 +466,12 @@ class SingleMapping extends Mapping {
431466 'names' : names,
432467 'mappings' : buff.toString ()
433468 };
434- if (targetUrl != null ) {
435- result['file' ] = targetUrl;
469+ if (targetUrl != null ) result['file' ] = targetUrl;
470+
471+ if (includeSourceContents) {
472+ result['sourcesContent' ] = files.map ((file) => file? .getText (0 )).toList ();
436473 }
474+
437475 return result;
438476 }
439477
0 commit comments