Skip to content
This repository was archived by the owner on Jan 14, 2025. It is now read-only.

Commit 28eb6b8

Browse files
authored
Add support for the sourcesContent field (#28)
1 parent 83473b6 commit 28eb6b8

File tree

4 files changed

+108
-11
lines changed

4 files changed

+108
-11
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 0.10.5
2+
3+
* Add a `SingleMapping.files` field which provides access to `SourceFile`s
4+
representing the `"sourcesContent"` fields in the source map.
5+
6+
* Add an `includeSourceContents` flag to `SingleMapping.toJson()` which
7+
indicates whether to include source file contents in the source map.
8+
19
## 0.10.4
210
* Implement `highlight` in `SourceMapFileSpan`.
311
* Require version `^1.3.0` of `source_span`.

lib/parser.dart

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
/// Contains the top-level function to parse source maps version 3.
66
library source_maps.parser;
77

8-
import 'dart:collection';
98
import 'dart:convert';
109

1110
import '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

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: source_maps
2-
version: 0.10.5-dev
2+
version: 0.10.5
33
author: Dart Team <misc@dartlang.org>
44
description: Library to programmatically manipulate source map files.
55
homepage: http://github.com/dart-lang/source_maps

test/parser_test.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,4 +341,55 @@ main() {
341341
var mapping = parseJsonExtended(SOURCE_MAP_BUNDLE) as MappingBundle;
342342
expect(mapping.toJson(), equals(SOURCE_MAP_BUNDLE));
343343
});
344+
345+
group("source files", () {
346+
group("from fromEntries()", () {
347+
test("are null for non-FileLocations", () {
348+
var mapping = new SingleMapping.fromEntries([
349+
new Entry(new SourceLocation(10, line: 1, column: 8),
350+
outputVar1.start, null)
351+
]);
352+
expect(mapping.files, equals([null]));
353+
});
354+
355+
test("use a file location's file", () {
356+
var mapping = new SingleMapping.fromEntries(
357+
[new Entry(inputVar1.start, outputVar1.start, null)]);
358+
expect(mapping.files, equals([input]));
359+
});
360+
});
361+
362+
group("from parse()", () {
363+
group("are null", () {
364+
test("with no sourcesContent field", () {
365+
var mapping = parseJson(EXPECTED_MAP) as SingleMapping;
366+
expect(mapping.files, equals([null]));
367+
});
368+
369+
test("with null sourcesContent values", () {
370+
var map = new Map.from(EXPECTED_MAP);
371+
map["sourcesContent"] = [null];
372+
var mapping = parseJson(map) as SingleMapping;
373+
expect(mapping.files, equals([null]));
374+
});
375+
376+
test("with a too-short sourcesContent", () {
377+
var map = new Map.from(EXPECTED_MAP);
378+
map["sourcesContent"] = [];
379+
var mapping = parseJson(map) as SingleMapping;
380+
expect(mapping.files, equals([null]));
381+
});
382+
});
383+
384+
test("are parsed from sourcesContent", () {
385+
var map = new Map.from(EXPECTED_MAP);
386+
map["sourcesContent"] = ["hello, world!"];
387+
var mapping = parseJson(map) as SingleMapping;
388+
389+
var file = mapping.files[0];
390+
expect(file.url, equals(Uri.parse("input.dart")));
391+
expect(file.getText(0), equals("hello, world!"));
392+
});
393+
});
394+
});
344395
}

0 commit comments

Comments
 (0)