Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(326)

Side by Side Diff: lib/parser.dart

Issue 1112743002: Add a mapUrl parameter to parse() and parseJson(). (Closed) Base URL: git@github.com:dart-lang/source_maps.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « CHANGELOG.md ('k') | pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// Contains the top-level function to parse source maps version 3. 5 /// Contains the top-level function to parse source maps version 3.
6 library source_maps.parser; 6 library source_maps.parser;
7 7
8 import 'dart:collection'; 8 import 'dart:collection';
9 import 'dart:convert'; 9 import 'dart:convert';
10 10
11 import 'package:source_span/source_span.dart'; 11 import 'package:source_span/source_span.dart';
12 12
13 import 'builder.dart' as builder; 13 import 'builder.dart' as builder;
14 import 'src/source_map_span.dart'; 14 import 'src/source_map_span.dart';
15 import 'src/utils.dart'; 15 import 'src/utils.dart';
16 import 'src/vlq.dart'; 16 import 'src/vlq.dart';
17 17
18 /// Parses a source map directly from a json string. 18 /// Parses a source map directly from a json string.
19 ///
20 /// [mapUrl], which may be either a [String] or a [Uri], indicates the URL of
21 /// the source map file itself. If it's passed, any URLs in the source
22 /// map will be interpreted as relative to this URL when generating spans.
19 // TODO(sigmund): evaluate whether other maps should have the json parsed, or 23 // TODO(sigmund): evaluate whether other maps should have the json parsed, or
20 // the string represenation. 24 // the string represenation.
21 // TODO(tjblasi): Ignore the first line of [jsonMap] if the JSON safety string 25 // TODO(tjblasi): Ignore the first line of [jsonMap] if the JSON safety string
22 // `)]}'` begins the string representation of the map. 26 // `)]}'` begins the string representation of the map.
23 Mapping parse(String jsonMap, {Map<String, Map> otherMaps}) => 27 Mapping parse(String jsonMap, {Map<String, Map> otherMaps, mapUrl}) =>
24 parseJson(JSON.decode(jsonMap), otherMaps: otherMaps); 28 parseJson(JSON.decode(jsonMap), otherMaps: otherMaps, mapUrl: mapUrl);
25 29
26 /// Parses a source map directly from a json map object. 30 /// Parses a source map directly from a json map object.
27 Mapping parseJson(Map map, {Map<String, Map> otherMaps}) { 31 ///
32 /// [mapUrl], which may be either a [String] or a [Uri], indicates the URL of
33 /// the source map file itself. If it's passed, any URLs in the source
34 /// map will be interpreted as relative to this URL when generating spans.
35 Mapping parseJson(Map map, {Map<String, Map> otherMaps, mapUrl}) {
28 if (map['version'] != 3) { 36 if (map['version'] != 3) {
29 throw new ArgumentError( 37 throw new ArgumentError(
30 'unexpected source map version: ${map["version"]}. ' 38 'unexpected source map version: ${map["version"]}. '
31 'Only version 3 is supported.'); 39 'Only version 3 is supported.');
32 } 40 }
33 41
34 if (map.containsKey('sections')) { 42 if (map.containsKey('sections')) {
35 if (map.containsKey('mappings') || map.containsKey('sources') || 43 if (map.containsKey('mappings') || map.containsKey('sources') ||
36 map.containsKey('names')) { 44 map.containsKey('names')) {
37 throw new FormatException('map containing "sections" ' 45 throw new FormatException('map containing "sections" '
38 'cannot contain "mappings", "sources", or "names".'); 46 'cannot contain "mappings", "sources", or "names".');
39 } 47 }
40 return new MultiSectionMapping.fromJson(map['sections'], otherMaps); 48 return new MultiSectionMapping.fromJson(map['sections'], otherMaps,
49 mapUrl: mapUrl);
41 } 50 }
42 return new SingleMapping.fromJson(map); 51 return new SingleMapping.fromJson(map, mapUrl: mapUrl);
43 } 52 }
44 53
45 54
46 /// A mapping parsed out of a source map. 55 /// A mapping parsed out of a source map.
47 abstract class Mapping { 56 abstract class Mapping {
48 /// Returns the span associated with [line] and [column]. 57 /// Returns the span associated with [line] and [column].
49 SourceMapSpan spanFor(int line, int column, {Map<String, SourceFile> files}); 58 SourceMapSpan spanFor(int line, int column, {Map<String, SourceFile> files});
50 59
51 /// Returns the span associated with [location]. 60 /// Returns the span associated with [location].
52 SourceMapSpan spanForLocation(SourceLocation location, 61 SourceMapSpan spanForLocation(SourceLocation location,
53 {Map<String, SourceFile> files}) { 62 {Map<String, SourceFile> files}) {
54 return spanFor(location.line, location.column, files: files); 63 return spanFor(location.line, location.column, files: files);
55 } 64 }
56 } 65 }
57 66
58 /// A meta-level map containing sections. 67 /// A meta-level map containing sections.
59 class MultiSectionMapping extends Mapping { 68 class MultiSectionMapping extends Mapping {
60 /// For each section, the start line offset. 69 /// For each section, the start line offset.
61 final List<int> _lineStart = <int>[]; 70 final List<int> _lineStart = <int>[];
62 71
63 /// For each section, the start column offset. 72 /// For each section, the start column offset.
64 final List<int> _columnStart = <int>[]; 73 final List<int> _columnStart = <int>[];
65 74
66 /// For each section, the actual source map information, which is not adjusted 75 /// For each section, the actual source map information, which is not adjusted
67 /// for offsets. 76 /// for offsets.
68 final List<Mapping> _maps = <Mapping>[]; 77 final List<Mapping> _maps = <Mapping>[];
69 78
70 /// Creates a section mapping from json. 79 /// Creates a section mapping from json.
71 MultiSectionMapping.fromJson(List sections, Map<String, Map> otherMaps) { 80 MultiSectionMapping.fromJson(List sections, Map<String, Map> otherMaps,
81 {mapUrl}) {
72 for (var section in sections) { 82 for (var section in sections) {
73 var offset = section['offset']; 83 var offset = section['offset'];
74 if (offset == null) throw new FormatException('section missing offset'); 84 if (offset == null) throw new FormatException('section missing offset');
75 85
76 var line = section['offset']['line']; 86 var line = section['offset']['line'];
77 if (line == null) throw new FormatException('offset missing line'); 87 if (line == null) throw new FormatException('offset missing line');
78 88
79 var column = section['offset']['column']; 89 var column = section['offset']['column'];
80 if (column == null) throw new FormatException('offset missing column'); 90 if (column == null) throw new FormatException('offset missing column');
81 91
82 _lineStart.add(line); 92 _lineStart.add(line);
83 _columnStart.add(column); 93 _columnStart.add(column);
84 94
85 var url = section['url']; 95 var url = section['url'];
86 var map = section['map']; 96 var map = section['map'];
87 97
88 if (url != null && map != null) { 98 if (url != null && map != null) {
89 throw new FormatException("section can't use both url and map entries"); 99 throw new FormatException("section can't use both url and map entries");
90 } else if (url != null) { 100 } else if (url != null) {
91 if (otherMaps == null || otherMaps[url] == null) { 101 if (otherMaps == null || otherMaps[url] == null) {
92 throw new FormatException( 102 throw new FormatException(
93 'section contains refers to $url, but no map was ' 103 'section contains refers to $url, but no map was '
94 'given for it. Make sure a map is passed in "otherMaps"'); 104 'given for it. Make sure a map is passed in "otherMaps"');
95 } 105 }
96 _maps.add(parseJson(otherMaps[url], otherMaps: otherMaps)); 106 _maps.add(parseJson(otherMaps[url], otherMaps: otherMaps, mapUrl: url));
97 } else if (map != null) { 107 } else if (map != null) {
98 _maps.add(parseJson(map, otherMaps: otherMaps)); 108 _maps.add(parseJson(map, otherMaps: otherMaps, mapUrl: mapUrl));
99 } else { 109 } else {
100 throw new FormatException('section missing url or map'); 110 throw new FormatException('section missing url or map');
101 } 111 }
102 } 112 }
103 if (_lineStart.length == 0) { 113 if (_lineStart.length == 0) {
104 throw new FormatException('expected at least one section'); 114 throw new FormatException('expected at least one section');
105 } 115 }
106 } 116 }
107 117
108 int _indexFor(line, column) { 118 int _indexFor(line, column) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 152
143 /// Source names used in the mapping, indexed by id. 153 /// Source names used in the mapping, indexed by id.
144 final List<String> names; 154 final List<String> names;
145 155
146 /// Entries indicating the beginning of each span. 156 /// Entries indicating the beginning of each span.
147 final List<TargetLineEntry> lines; 157 final List<TargetLineEntry> lines;
148 158
149 /// Url of the target file. 159 /// Url of the target file.
150 String targetUrl; 160 String targetUrl;
151 161
152 /// Source root appended to the start of all entries in [urls]. 162 /// Source root prepended to all entries in [urls].
153 String sourceRoot; 163 String sourceRoot;
154 164
155 SingleMapping._(this.targetUrl, this.urls, this.names, this.lines); 165 final Uri _mapUrl;
166
167 SingleMapping._(this.targetUrl, this.urls, this.names, this.lines)
168 : _mapUrl = null;
156 169
157 factory SingleMapping.fromEntries( 170 factory SingleMapping.fromEntries(
158 Iterable<builder.Entry> entries, [String fileUrl]) { 171 Iterable<builder.Entry> entries, [String fileUrl]) {
159 // The entries needs to be sorted by the target offsets. 172 // The entries needs to be sorted by the target offsets.
160 var sourceEntries = new List.from(entries)..sort(); 173 var sourceEntries = new List.from(entries)..sort();
161 var lines = <TargetLineEntry>[]; 174 var lines = <TargetLineEntry>[];
162 175
163 // Indices associated with file urls that will be part of the source map. We 176 // Indices associated with file urls that will be part of the source map. We
164 // use a linked hash-map so that `_urls.keys[_urls[u]] == u` 177 // use a linked hash-map so that `_urls.keys[_urls[u]] == u`
165 var urls = new LinkedHashMap<String, int>(); 178 var urls = new LinkedHashMap<String, int>();
(...skipping 24 matching lines...) Expand all
190 urlId, 203 urlId,
191 sourceEntry.source.line, 204 sourceEntry.source.line,
192 sourceEntry.source.column, 205 sourceEntry.source.column,
193 srcNameId)); 206 srcNameId));
194 } 207 }
195 } 208 }
196 return new SingleMapping._( 209 return new SingleMapping._(
197 fileUrl, urls.keys.toList(), names.keys.toList(), lines); 210 fileUrl, urls.keys.toList(), names.keys.toList(), lines);
198 } 211 }
199 212
200 SingleMapping.fromJson(Map map) 213 SingleMapping.fromJson(Map map, {mapUrl})
201 : targetUrl = map['file'], 214 : targetUrl = map['file'],
202 urls = map['sources'], 215 urls = map['sources'],
203 names = map['names'], 216 names = map['names'],
204 sourceRoot = map['sourceRoot'], 217 sourceRoot = map['sourceRoot'],
205 lines = <TargetLineEntry>[] { 218 lines = <TargetLineEntry>[],
219 _mapUrl = mapUrl is String ? Uri.parse(mapUrl) : mapUrl {
206 int line = 0; 220 int line = 0;
207 int column = 0; 221 int column = 0;
208 int srcUrlId = 0; 222 int srcUrlId = 0;
209 int srcLine = 0; 223 int srcLine = 0;
210 int srcColumn = 0; 224 int srcColumn = 0;
211 int srcNameId = 0; 225 int srcNameId = 0;
212 var tokenizer = new _MappingTokenizer(map['mappings']); 226 var tokenizer = new _MappingTokenizer(map['mappings']);
213 var entries = <TargetEntry>[]; 227 var entries = <TargetEntry>[];
214 228
215 while (tokenizer.hasTokens) { 229 while (tokenizer.hasTokens) {
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 if (entry.sourceNameId != null) { 380 if (entry.sourceNameId != null) {
367 var text = names[entry.sourceNameId]; 381 var text = names[entry.sourceNameId];
368 return new SourceMapFileSpan( 382 return new SourceMapFileSpan(
369 files[url].span(start, start + text.length), 383 files[url].span(start, start + text.length),
370 isIdentifier: true); 384 isIdentifier: true);
371 } else { 385 } else {
372 return new SourceMapFileSpan(files[url].location(start).pointSpan()); 386 return new SourceMapFileSpan(files[url].location(start).pointSpan());
373 } 387 }
374 } else { 388 } else {
375 var start = new SourceLocation(0, 389 var start = new SourceLocation(0,
376 sourceUrl: url, line: entry.sourceLine, column: entry.sourceColumn); 390 sourceUrl: _mapUrl == null ? url : _mapUrl.resolve(url),
391 line: entry.sourceLine,
392 column: entry.sourceColumn);
393
377 // Offset and other context is not available. 394 // Offset and other context is not available.
378 if (entry.sourceNameId != null) { 395 if (entry.sourceNameId != null) {
379 return new SourceMapSpan.identifier(start, names[entry.sourceNameId]); 396 return new SourceMapSpan.identifier(start, names[entry.sourceNameId]);
380 } else { 397 } else {
381 return new SourceMapSpan(start, start, ''); 398 return new SourceMapSpan(start, start, '');
382 } 399 }
383 } 400 }
384 } 401 }
385 402
386 String toString() { 403 String toString() {
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 static const _TokenKind EOF = const _TokenKind(isEof: true); 522 static const _TokenKind EOF = const _TokenKind(isEof: true);
506 static const _TokenKind VALUE = const _TokenKind(); 523 static const _TokenKind VALUE = const _TokenKind();
507 final bool isNewLine; 524 final bool isNewLine;
508 final bool isNewSegment; 525 final bool isNewSegment;
509 final bool isEof; 526 final bool isEof;
510 bool get isValue => !isNewLine && !isNewSegment && !isEof; 527 bool get isValue => !isNewLine && !isNewSegment && !isEof;
511 528
512 const _TokenKind( 529 const _TokenKind(
513 {this.isNewLine: false, this.isNewSegment: false, this.isEof: false}); 530 {this.isNewLine: false, this.isNewSegment: false, this.isEof: false});
514 } 531 }
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698