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

Side by Side Diff: packages/source_maps/lib/parser.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 4 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
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 /// 19 ///
20 /// [mapUrl], which may be either a [String] or a [Uri], indicates the URL of 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 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. 22 /// map will be interpreted as relative to this URL when generating spans.
23 // 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
24 // the string represenation. 24 // the string represenation.
25 // 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
26 // `)]}'` begins the string representation of the map. 26 // `)]}'` begins the string representation of the map.
27 Mapping parse(String jsonMap, {Map<String, Map> otherMaps, mapUrl}) => 27 Mapping parse(String jsonMap, {Map<String, Map> otherMaps, mapUrl}) =>
28 parseJson(JSON.decode(jsonMap), otherMaps: otherMaps, mapUrl: mapUrl); 28 parseJson(JSON.decode(jsonMap), otherMaps: otherMaps, mapUrl: mapUrl);
29 29
30 /// Parses a source map directly from a json map object. 30 /// Parses a source map or source map bundle directly from a json string.
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 parseExtended(String jsonMap, {Map<String, Map> otherMaps, mapUrl}) =>
36 parseJsonExtended(JSON.decode(jsonMap),
37 otherMaps: otherMaps, mapUrl: mapUrl);
38
39 /// Parses a source map or source map bundle.
40 ///
41 /// [mapUrl], which may be either a [String] or a [Uri], indicates the URL of
42 /// the source map file itself. If it's passed, any URLs in the source
43 /// map will be interpreted as relative to this URL when generating spans.
44 Mapping parseJsonExtended(/*List|Map*/ json,
45 {Map<String, Map> otherMaps, mapUrl}) {
46 if (json is List) {
47 return new MappingBundle.fromJson(json, mapUrl: mapUrl);
48 }
49 return parseJson(json as Map);
50 }
51
52 /// Parses a source map
31 /// 53 ///
32 /// [mapUrl], which may be either a [String] or a [Uri], indicates the URL of 54 /// [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 55 /// 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. 56 /// map will be interpreted as relative to this URL when generating spans.
35 Mapping parseJson(Map map, {Map<String, Map> otherMaps, mapUrl}) { 57 Mapping parseJson(Map map, {Map<String, Map> otherMaps, mapUrl}) {
36 if (map['version'] != 3) { 58 if (map['version'] != 3) {
37 throw new ArgumentError( 59 throw new ArgumentError('unexpected source map version: ${map["version"]}. '
38 'unexpected source map version: ${map["version"]}. '
39 'Only version 3 is supported.'); 60 'Only version 3 is supported.');
40 } 61 }
41 62
42 if (map.containsKey('sections')) { 63 if (map.containsKey('sections')) {
43 if (map.containsKey('mappings') || map.containsKey('sources') || 64 if (map.containsKey('mappings') ||
65 map.containsKey('sources') ||
44 map.containsKey('names')) { 66 map.containsKey('names')) {
45 throw new FormatException('map containing "sections" ' 67 throw new FormatException('map containing "sections" '
46 'cannot contain "mappings", "sources", or "names".'); 68 'cannot contain "mappings", "sources", or "names".');
47 } 69 }
48 return new MultiSectionMapping.fromJson(map['sections'], otherMaps, 70 return new MultiSectionMapping.fromJson(map['sections'], otherMaps,
49 mapUrl: mapUrl); 71 mapUrl: mapUrl);
50 } 72 }
51 return new SingleMapping.fromJson(map, mapUrl: mapUrl); 73 return new SingleMapping.fromJson(map, mapUrl: mapUrl);
52 } 74 }
53 75
54
55 /// A mapping parsed out of a source map. 76 /// A mapping parsed out of a source map.
56 abstract class Mapping { 77 abstract class Mapping {
57 /// Returns the span associated with [line] and [column]. 78 /// Returns the span associated with [line] and [column].
58 SourceMapSpan spanFor(int line, int column, {Map<String, SourceFile> files}); 79 ///
80 /// [uri] is the optional location of the output file to find the span for
81 /// to disambiguate cases where a mapping may have different mappings for
82 /// different output files.
83 SourceMapSpan spanFor(int line, int column,
84 {Map<String, SourceFile> files, String uri});
59 85
60 /// Returns the span associated with [location]. 86 /// Returns the span associated with [location].
61 SourceMapSpan spanForLocation(SourceLocation location, 87 SourceMapSpan spanForLocation(SourceLocation location,
62 {Map<String, SourceFile> files}) { 88 {Map<String, SourceFile> files}) {
63 return spanFor(location.line, location.column, files: files); 89 return spanFor(location.line, location.column,
90 uri: location.sourceUrl?.toString(), files: files);
64 } 91 }
65 } 92 }
66 93
67 /// A meta-level map containing sections. 94 /// A meta-level map containing sections.
68 class MultiSectionMapping extends Mapping { 95 class MultiSectionMapping extends Mapping {
69 /// For each section, the start line offset. 96 /// For each section, the start line offset.
70 final List<int> _lineStart = <int>[]; 97 final List<int> _lineStart = <int>[];
71 98
72 /// For each section, the start column offset. 99 /// For each section, the start column offset.
73 final List<int> _columnStart = <int>[]; 100 final List<int> _columnStart = <int>[];
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 } else { 136 } else {
110 throw new FormatException('section missing url or map'); 137 throw new FormatException('section missing url or map');
111 } 138 }
112 } 139 }
113 if (_lineStart.length == 0) { 140 if (_lineStart.length == 0) {
114 throw new FormatException('expected at least one section'); 141 throw new FormatException('expected at least one section');
115 } 142 }
116 } 143 }
117 144
118 int _indexFor(line, column) { 145 int _indexFor(line, column) {
119 for(int i = 0; i < _lineStart.length; i++) { 146 for (int i = 0; i < _lineStart.length; i++) {
120 if (line < _lineStart[i]) return i - 1; 147 if (line < _lineStart[i]) return i - 1;
121 if (line == _lineStart[i] && column < _columnStart[i]) return i - 1; 148 if (line == _lineStart[i] && column < _columnStart[i]) return i - 1;
122 } 149 }
123 return _lineStart.length - 1; 150 return _lineStart.length - 1;
124 } 151 }
125 152
126 SourceMapSpan spanFor(int line, int column, {Map<String, SourceFile> files}) { 153 SourceMapSpan spanFor(int line, int column,
154 {Map<String, SourceFile> files, String uri}) {
155 // TODO(jacobr): perhaps verify that targetUrl matches the actual uri
156 // or at least ends in the same file name.
127 int index = _indexFor(line, column); 157 int index = _indexFor(line, column);
128 return _maps[index].spanFor( 158 return _maps[index].spanFor(
129 line - _lineStart[index], column - _columnStart[index], files: files); 159 line - _lineStart[index], column - _columnStart[index],
160 files: files);
130 } 161 }
131 162
132 String toString() { 163 String toString() {
133 var buff = new StringBuffer("$runtimeType : ["); 164 var buff = new StringBuffer("$runtimeType : [");
134 for (int i = 0; i < _lineStart.length; i++) { 165 for (int i = 0; i < _lineStart.length; i++) {
135 buff..write('(') 166 buff
136 ..write(_lineStart[i]) 167 ..write('(')
137 ..write(',') 168 ..write(_lineStart[i])
138 ..write(_columnStart[i]) 169 ..write(',')
139 ..write(':') 170 ..write(_columnStart[i])
140 ..write(_maps[i]) 171 ..write(':')
141 ..write(')'); 172 ..write(_maps[i])
173 ..write(')');
142 } 174 }
143 buff.write(']'); 175 buff.write(']');
144 return buff.toString(); 176 return buff.toString();
145 } 177 }
146 } 178 }
147 179
180 class MappingBundle extends Mapping {
181 Map<String, SingleMapping> _mappings = {};
182
183 MappingBundle() {}
184
185 MappingBundle.fromJson(List json, {String mapUrl}) {
186 for (var map in json) {
187 addMapping(parseJson(map, mapUrl: mapUrl) as SingleMapping);
188 }
189 }
190
191 addMapping(SingleMapping mapping) {
192 // TODO(jacobr): verify that targetUrl is valid uri instead of a windows
193 // path.
194 _mappings[mapping.targetUrl] = mapping;
195 }
196
197 /// Encodes the Mapping mappings as a json map.
198 List toJson() => _mappings.values.map((v) => v.toJson()).toList();
199
200 String toString() {
201 var buff = new StringBuffer();
202 for (var map in _mappings.values) {
203 buff.write(map.toString());
204 }
205 return buff.toString();
206 }
207
208 bool containsMapping(String url) => _mappings.containsKey(url);
209
210 SourceMapSpan spanFor(int line, int column,
211 {Map<String, SourceFile> files, String uri}) {
212 if (uri == null) {
213 throw new ArgumentError.notNull('uri');
214 }
215
216 // Find the longest suffix of the uri that matches the sourcemap
217 // where the suffix starts after a path segment boundary.
218 // We consider ":" and "/" as path segment boundaries so that
219 // "package:" uris can be handled with minimal special casing. Having a
220 // few false positive path segment boundaries is not a significant issue
221 // as we prefer the longest matching prefix.
222 // Using package:path `path.split` to find path segment boundaries would
223 // not generate all of the path segment boundaries we want for "package:"
224 // urls as "package:package_name" would be one path segment when we want
225 // "package" and "package_name" to be sepearate path segments.
226
227 bool onBoundary = true;
228 var separatorCodeUnits = ['/'.codeUnitAt(0), ':'.codeUnitAt(0)];
229 for (var i = 0; i < uri.length; ++i) {
230 if (onBoundary) {
231 var candidate = uri.substring(i);
232 if (_mappings.containsKey(candidate)) {
233 return _mappings[candidate]
234 .spanFor(line, column, files: files, uri: candidate);
235 }
236 }
237 onBoundary = separatorCodeUnits.contains(uri.codeUnitAt(i));
238 }
239
240 // Note: when there is no source map for an uri, this behaves like an
241 // identity function, returning the requested location as the result.
242
243 // Create a mock offset for the output location. We compute it in terms
244 // of the input line and column to minimize the chances that two different
245 // line and column locations are mapped to the same offset.
246 var offset = line * 1000000 + column;
247 var location = new SourceLocation(offset,
248 line: line, column: column, sourceUrl: Uri.parse(uri));
249 return new SourceMapSpan(location, location, "");
250 }
251 }
252
148 /// A map containing direct source mappings. 253 /// A map containing direct source mappings.
149 class SingleMapping extends Mapping { 254 class SingleMapping extends Mapping {
150 /// Source urls used in the mapping, indexed by id. 255 /// Source urls used in the mapping, indexed by id.
151 final List<String> urls; 256 final List<String> urls;
152 257
153 /// Source names used in the mapping, indexed by id. 258 /// Source names used in the mapping, indexed by id.
154 final List<String> names; 259 final List<String> names;
155 260
156 /// Entries indicating the beginning of each span. 261 /// Entries indicating the beginning of each span.
157 final List<TargetLineEntry> lines; 262 final List<TargetLineEntry> lines;
158 263
159 /// Url of the target file. 264 /// Url of the target file.
160 String targetUrl; 265 String targetUrl;
161 266
162 /// Source root prepended to all entries in [urls]. 267 /// Source root prepended to all entries in [urls].
163 String sourceRoot; 268 String sourceRoot;
164 269
165 final Uri _mapUrl; 270 final Uri _mapUrl;
166 271
167 SingleMapping._(this.targetUrl, this.urls, this.names, this.lines) 272 SingleMapping._(this.targetUrl, this.urls, this.names, this.lines)
168 : _mapUrl = null; 273 : _mapUrl = null;
169 274
170 factory SingleMapping.fromEntries( 275 factory SingleMapping.fromEntries(Iterable<builder.Entry> entries,
171 Iterable<builder.Entry> entries, [String fileUrl]) { 276 [String fileUrl]) {
172 // The entries needs to be sorted by the target offsets. 277 // The entries needs to be sorted by the target offsets.
173 var sourceEntries = new List.from(entries)..sort(); 278 var sourceEntries = new List.from(entries)..sort();
174 var lines = <TargetLineEntry>[]; 279 var lines = <TargetLineEntry>[];
175 280
176 // Indices associated with file urls that will be part of the source map. We 281 // Indices associated with file urls that will be part of the source map. We
177 // use a linked hash-map so that `_urls.keys[_urls[u]] == u` 282 // use a linked hash-map so that `_urls.keys[_urls[u]] == u`
178 var urls = new LinkedHashMap<String, int>(); 283 var urls = new LinkedHashMap<String, int>();
179 284
180 // Indices associated with identifiers that will be part of the source map. 285 // Indices associated with identifiers that will be part of the source map.
181 // We use a linked hash-map so that `_names.keys[_names[n]] == n` 286 // We use a linked hash-map so that `_names.keys[_names[n]] == n`
182 var names = new LinkedHashMap<String, int>(); 287 var names = new LinkedHashMap<String, int>();
183 288
184 var lineNum; 289 var lineNum;
185 var targetEntries; 290 List<TargetEntry> targetEntries;
186 for (var sourceEntry in sourceEntries) { 291 for (var sourceEntry in sourceEntries) {
187 if (lineNum == null || sourceEntry.target.line > lineNum) { 292 if (lineNum == null || sourceEntry.target.line > lineNum) {
188 lineNum = sourceEntry.target.line; 293 lineNum = sourceEntry.target.line;
189 targetEntries = <TargetEntry>[]; 294 targetEntries = <TargetEntry>[];
190 lines.add(new TargetLineEntry(lineNum, targetEntries)); 295 lines.add(new TargetLineEntry(lineNum, targetEntries));
191 } 296 }
192 297
193 if (sourceEntry.source == null) { 298 if (sourceEntry.source == null) {
194 targetEntries.add(new TargetEntry(sourceEntry.target.column)); 299 targetEntries.add(new TargetEntry(sourceEntry.target.column));
195 } else { 300 } else {
196 var sourceUrl = sourceEntry.source.sourceUrl; 301 var sourceUrl = sourceEntry.source.sourceUrl;
197 var urlId = urls.putIfAbsent( 302 var urlId = urls.putIfAbsent(
198 sourceUrl == null ? '' : sourceUrl.toString(), () => urls.length); 303 sourceUrl == null ? '' : sourceUrl.toString(), () => urls.length);
199 var srcNameId = sourceEntry.identifierName == null ? null : 304 var srcNameId = sourceEntry.identifierName == null
200 names.putIfAbsent(sourceEntry.identifierName, () => names.length); 305 ? null
201 targetEntries.add(new TargetEntry( 306 : names.putIfAbsent(sourceEntry.identifierName, () => names.length);
202 sourceEntry.target.column, 307 targetEntries.add(new TargetEntry(sourceEntry.target.column, urlId,
203 urlId, 308 sourceEntry.source.line, sourceEntry.source.column, srcNameId));
204 sourceEntry.source.line,
205 sourceEntry.source.column,
206 srcNameId));
207 } 309 }
208 } 310 }
209 return new SingleMapping._( 311 return new SingleMapping._(
210 fileUrl, urls.keys.toList(), names.keys.toList(), lines); 312 fileUrl, urls.keys.toList(), names.keys.toList(), lines);
211 } 313 }
212 314
213 SingleMapping.fromJson(Map map, {mapUrl}) 315 SingleMapping.fromJson(Map map, {mapUrl})
214 : targetUrl = map['file'], 316 : targetUrl = map['file'],
215 urls = map['sources'], 317 urls = new List<String>.from(map['sources']),
216 names = map['names'], 318 names = new List<String>.from(map['names']),
217 sourceRoot = map['sourceRoot'], 319 sourceRoot = map['sourceRoot'],
218 lines = <TargetLineEntry>[], 320 lines = <TargetLineEntry>[],
219 _mapUrl = mapUrl is String ? Uri.parse(mapUrl) : mapUrl { 321 _mapUrl = mapUrl is String ? Uri.parse(mapUrl) : mapUrl {
220 int line = 0; 322 int line = 0;
221 int column = 0; 323 int column = 0;
222 int srcUrlId = 0; 324 int srcUrlId = 0;
223 int srcLine = 0; 325 int srcLine = 0;
224 int srcColumn = 0; 326 int srcColumn = 0;
225 int srcNameId = 0; 327 int srcNameId = 0;
226 var tokenizer = new _MappingTokenizer(map['mappings']); 328 var tokenizer = new _MappingTokenizer(map['mappings']);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 if (!tokenizer.nextKind.isValue) throw _segmentError(3, line); 366 if (!tokenizer.nextKind.isValue) throw _segmentError(3, line);
265 srcColumn += tokenizer._consumeValue(); 367 srcColumn += tokenizer._consumeValue();
266 if (!tokenizer.nextKind.isValue) { 368 if (!tokenizer.nextKind.isValue) {
267 entries.add(new TargetEntry(column, srcUrlId, srcLine, srcColumn)); 369 entries.add(new TargetEntry(column, srcUrlId, srcLine, srcColumn));
268 } else { 370 } else {
269 srcNameId += tokenizer._consumeValue(); 371 srcNameId += tokenizer._consumeValue();
270 if (srcNameId >= names.length) { 372 if (srcNameId >= names.length) {
271 throw new StateError( 373 throw new StateError(
272 'Invalid name id: $targetUrl, $line, $srcNameId'); 374 'Invalid name id: $targetUrl, $line, $srcNameId');
273 } 375 }
274 entries.add(new TargetEntry(column, srcUrlId, srcLine, srcColumn, 376 entries.add(
275 srcNameId)); 377 new TargetEntry(column, srcUrlId, srcLine, srcColumn, srcNameId));
276 } 378 }
277 } 379 }
278 if (tokenizer.nextKind.isNewSegment) tokenizer._consumeNewSegment(); 380 if (tokenizer.nextKind.isNewSegment) tokenizer._consumeNewSegment();
279 } 381 }
280 if (!entries.isEmpty) { 382 if (!entries.isEmpty) {
281 lines.add(new TargetLineEntry(line, entries)); 383 lines.add(new TargetLineEntry(line, entries));
282 } 384 }
283 } 385 }
284 386
285 /// Encodes the Mapping mappings as a json map. 387 /// Encodes the Mapping mappings as a json map.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 421
320 if (segment.sourceNameId == null) continue; 422 if (segment.sourceNameId == null) continue;
321 srcNameId = _append(buff, srcNameId, segment.sourceNameId); 423 srcNameId = _append(buff, srcNameId, segment.sourceNameId);
322 } 424 }
323 } 425 }
324 426
325 var result = { 427 var result = {
326 'version': 3, 428 'version': 3,
327 'sourceRoot': sourceRoot == null ? '' : sourceRoot, 429 'sourceRoot': sourceRoot == null ? '' : sourceRoot,
328 'sources': urls, 430 'sources': urls,
329 'names' : names, 431 'names': names,
330 'mappings' : buff.toString() 432 'mappings': buff.toString()
331 }; 433 };
332 if (targetUrl != null) { 434 if (targetUrl != null) {
333 result['file'] = targetUrl; 435 result['file'] = targetUrl;
334 } 436 }
335 return result; 437 return result;
336 } 438 }
337 439
338 /// Appends to [buff] a VLQ encoding of [newValue] using the difference 440 /// Appends to [buff] a VLQ encoding of [newValue] using the difference
339 /// between [oldValue] and [newValue] 441 /// between [oldValue] and [newValue]
340 static int _append(StringBuffer buff, int oldValue, int newValue) { 442 static int _append(StringBuffer buff, int oldValue, int newValue) {
341 buff.writeAll(encodeVlq(newValue - oldValue)); 443 buff.writeAll(encodeVlq(newValue - oldValue));
342 return newValue; 444 return newValue;
343 } 445 }
344 446
345 _segmentError(int seen, int line) => new StateError( 447 _segmentError(int seen, int line) =>
346 'Invalid entry in sourcemap, expected 1, 4, or 5' 448 new StateError('Invalid entry in sourcemap, expected 1, 4, or 5'
347 ' values, but got $seen.\ntargeturl: $targetUrl, line: $line'); 449 ' values, but got $seen.\ntargeturl: $targetUrl, line: $line');
348 450
349 /// Returns [TargetLineEntry] which includes the location in the target [line] 451 /// Returns [TargetLineEntry] which includes the location in the target [line]
350 /// number. In particular, the resulting entry is the last entry whose line 452 /// number. In particular, the resulting entry is the last entry whose line
351 /// number is lower or equal to [line]. 453 /// number is lower or equal to [line].
352 TargetLineEntry _findLine(int line) { 454 TargetLineEntry _findLine(int line) {
353 int index = binarySearch(lines, (e) => e.line > line); 455 int index = binarySearch(lines, (e) => e.line > line);
354 return (index <= 0) ? null : lines[index - 1]; 456 return (index <= 0) ? null : lines[index - 1];
355 } 457 }
356 458
357 /// Returns [TargetEntry] which includes the location denoted by 459 /// Returns [TargetEntry] which includes the location denoted by
358 /// [line], [column]. If [lineEntry] corresponds to [line], then this will be 460 /// [line], [column]. If [lineEntry] corresponds to [line], then this will be
359 /// the last entry whose column is lower or equal than [column]. If 461 /// the last entry whose column is lower or equal than [column]. If
360 /// [lineEntry] corresponds to a line prior to [line], then the result will be 462 /// [lineEntry] corresponds to a line prior to [line], then the result will be
361 /// the very last entry on that line. 463 /// the very last entry on that line.
362 TargetEntry _findColumn(int line, int column, TargetLineEntry lineEntry) { 464 TargetEntry _findColumn(int line, int column, TargetLineEntry lineEntry) {
363 if (lineEntry == null || lineEntry.entries.length == 0) return null; 465 if (lineEntry == null || lineEntry.entries.length == 0) return null;
364 if (lineEntry.line != line) return lineEntry.entries.last; 466 if (lineEntry.line != line) return lineEntry.entries.last;
365 var entries = lineEntry.entries; 467 var entries = lineEntry.entries;
366 int index = binarySearch(entries, (e) => e.column > column); 468 int index = binarySearch(entries, (e) => e.column > column);
367 return (index <= 0) ? null : entries[index - 1]; 469 return (index <= 0) ? null : entries[index - 1];
368 } 470 }
369 471
370 SourceMapSpan spanFor(int line, int column, {Map<String, SourceFile> files}) { 472 SourceMapSpan spanFor(int line, int column,
473 {Map<String, SourceFile> files, String uri}) {
371 var entry = _findColumn(line, column, _findLine(line)); 474 var entry = _findColumn(line, column, _findLine(line));
372 if (entry == null || entry.sourceUrlId == null) return null; 475 if (entry == null || entry.sourceUrlId == null) return null;
373 var url = urls[entry.sourceUrlId]; 476 var url = urls[entry.sourceUrlId];
374 if (sourceRoot != null) { 477 if (sourceRoot != null) {
375 url = '${sourceRoot}${url}'; 478 url = '${sourceRoot}${url}';
376 } 479 }
377 if (files != null && files[url] != null) { 480 if (files != null && files[url] != null) {
378 var file = files[url]; 481 var file = files[url];
379 var start = file.getOffset(entry.sourceLine, entry.sourceColumn); 482 var start = file.getOffset(entry.sourceLine, entry.sourceColumn);
380 if (entry.sourceNameId != null) { 483 if (entry.sourceNameId != null) {
(...skipping 14 matching lines...) Expand all
395 if (entry.sourceNameId != null) { 498 if (entry.sourceNameId != null) {
396 return new SourceMapSpan.identifier(start, names[entry.sourceNameId]); 499 return new SourceMapSpan.identifier(start, names[entry.sourceNameId]);
397 } else { 500 } else {
398 return new SourceMapSpan(start, start, ''); 501 return new SourceMapSpan(start, start, '');
399 } 502 }
400 } 503 }
401 } 504 }
402 505
403 String toString() { 506 String toString() {
404 return (new StringBuffer("$runtimeType : [") 507 return (new StringBuffer("$runtimeType : [")
405 ..write('targetUrl: ') 508 ..write('targetUrl: ')
406 ..write(targetUrl) 509 ..write(targetUrl)
407 ..write(', sourceRoot: ') 510 ..write(', sourceRoot: ')
408 ..write(sourceRoot) 511 ..write(sourceRoot)
409 ..write(', urls: ') 512 ..write(', urls: ')
410 ..write(urls) 513 ..write(urls)
411 ..write(', names: ') 514 ..write(', names: ')
412 ..write(names) 515 ..write(names)
413 ..write(', lines: ') 516 ..write(', lines: ')
414 ..write(lines) 517 ..write(lines)
415 ..write(']')).toString(); 518 ..write(']'))
519 .toString();
416 } 520 }
417 521
418 String get debugString { 522 String get debugString {
419 var buff = new StringBuffer(); 523 var buff = new StringBuffer();
420 for (var lineEntry in lines) { 524 for (var lineEntry in lines) {
421 var line = lineEntry.line; 525 var line = lineEntry.line;
422 for (var entry in lineEntry.entries) { 526 for (var entry in lineEntry.entries) {
423 buff..write(targetUrl) 527 buff
528 ..write(targetUrl)
529 ..write(': ')
530 ..write(line)
531 ..write(':')
532 ..write(entry.column);
533 if (entry.sourceUrlId != null) {
534 buff
535 ..write(' --> ')
536 ..write(sourceRoot)
537 ..write(urls[entry.sourceUrlId])
424 ..write(': ') 538 ..write(': ')
425 ..write(line) 539 ..write(entry.sourceLine)
426 ..write(':') 540 ..write(':')
427 ..write(entry.column); 541 ..write(entry.sourceColumn);
428 if (entry.sourceUrlId != null) {
429 buff..write(' --> ')
430 ..write(sourceRoot)
431 ..write(urls[entry.sourceUrlId])
432 ..write(': ')
433 ..write(entry.sourceLine)
434 ..write(':')
435 ..write(entry.sourceColumn);
436 } 542 }
437 if (entry.sourceNameId != null) { 543 if (entry.sourceNameId != null) {
438 buff..write(' (') 544 buff..write(' (')..write(names[entry.sourceNameId])..write(')');
439 ..write(names[entry.sourceNameId])
440 ..write(')');
441 } 545 }
442 buff.write('\n'); 546 buff.write('\n');
443 } 547 }
444 } 548 }
445 return buff.toString(); 549 return buff.toString();
446 } 550 }
447 } 551 }
448 552
449 /// A line entry read from a source map. 553 /// A line entry read from a source map.
450 class TargetLineEntry { 554 class TargetLineEntry {
451 final int line; 555 final int line;
452 List<TargetEntry> entries; 556 List<TargetEntry> entries;
453 TargetLineEntry(this.line, this.entries); 557 TargetLineEntry(this.line, this.entries);
454 558
455 String toString() => '$runtimeType: $line $entries'; 559 String toString() => '$runtimeType: $line $entries';
456 } 560 }
457 561
458 /// A target segment entry read from a source map 562 /// A target segment entry read from a source map
459 class TargetEntry { 563 class TargetEntry {
460 final int column; 564 final int column;
461 final int sourceUrlId; 565 final int sourceUrlId;
462 final int sourceLine; 566 final int sourceLine;
463 final int sourceColumn; 567 final int sourceColumn;
464 final int sourceNameId; 568 final int sourceNameId;
465 569
466 TargetEntry(this.column, [this.sourceUrlId, this.sourceLine, 570 TargetEntry(this.column,
467 this.sourceColumn, this.sourceNameId]); 571 [this.sourceUrlId,
572 this.sourceLine,
573 this.sourceColumn,
574 this.sourceNameId]);
468 575
469 String toString() => '$runtimeType: ' 576 String toString() => '$runtimeType: '
470 '($column, $sourceUrlId, $sourceLine, $sourceColumn, $sourceNameId)'; 577 '($column, $sourceUrlId, $sourceLine, $sourceColumn, $sourceNameId)';
471 } 578 }
472 579
473 /** A character iterator over a string that can peek one character ahead. */ 580 /** A character iterator over a string that can peek one character ahead. */
474 class _MappingTokenizer implements Iterator<String> { 581 class _MappingTokenizer implements Iterator<String> {
475 final String _internal; 582 final String _internal;
476 final int _length; 583 final int _length;
477 int index = -1; 584 int index = -1;
478 _MappingTokenizer(String internal) 585 _MappingTokenizer(String internal)
479 : _internal = internal, 586 : _internal = internal,
480 _length = internal.length; 587 _length = internal.length;
481 588
482 // Iterator API is used by decodeVlq to consume VLQ entries. 589 // Iterator API is used by decodeVlq to consume VLQ entries.
483 bool moveNext() => ++index < _length; 590 bool moveNext() => ++index < _length;
484 String get current => 591 String get current =>
485 (index >= 0 && index < _length) ? _internal[index] : null; 592 (index >= 0 && index < _length) ? _internal[index] : null;
486 593
487 bool get hasTokens => index < _length - 1 && _length > 0; 594 bool get hasTokens => index < _length - 1 && _length > 0;
488 595
489 _TokenKind get nextKind { 596 _TokenKind get nextKind {
490 if (!hasTokens) return _TokenKind.EOF; 597 if (!hasTokens) return _TokenKind.EOF;
491 var next = _internal[index + 1]; 598 var next = _internal[index + 1];
492 if (next == ';') return _TokenKind.LINE; 599 if (next == ';') return _TokenKind.LINE;
493 if (next == ',') return _TokenKind.SEGMENT; 600 if (next == ',') return _TokenKind.SEGMENT;
494 return _TokenKind.VALUE; 601 return _TokenKind.VALUE;
495 } 602 }
496 603
497 int _consumeValue() => decodeVlq(this); 604 int _consumeValue() => decodeVlq(this);
498 void _consumeNewLine() { ++index; } 605 void _consumeNewLine() {
499 void _consumeNewSegment() { ++index; } 606 ++index;
607 }
608
609 void _consumeNewSegment() {
610 ++index;
611 }
500 612
501 // Print the state of the iterator, with colors indicating the current 613 // Print the state of the iterator, with colors indicating the current
502 // position. 614 // position.
503 String toString() { 615 String toString() {
504 var buff = new StringBuffer(); 616 var buff = new StringBuffer();
505 for (int i = 0; i < index; i++) { 617 for (int i = 0; i < index; i++) {
506 buff.write(_internal[i]); 618 buff.write(_internal[i]);
507 } 619 }
508 buff.write(''); 620 buff.write('');
509 buff.write(current == null ? '' : current); 621 buff.write(current == null ? '' : current);
(...skipping 12 matching lines...) Expand all
522 static const _TokenKind EOF = const _TokenKind(isEof: true); 634 static const _TokenKind EOF = const _TokenKind(isEof: true);
523 static const _TokenKind VALUE = const _TokenKind(); 635 static const _TokenKind VALUE = const _TokenKind();
524 final bool isNewLine; 636 final bool isNewLine;
525 final bool isNewSegment; 637 final bool isNewSegment;
526 final bool isEof; 638 final bool isEof;
527 bool get isValue => !isNewLine && !isNewSegment && !isEof; 639 bool get isValue => !isNewLine && !isNewSegment && !isEof;
528 640
529 const _TokenKind( 641 const _TokenKind(
530 {this.isNewLine: false, this.isNewSegment: false, this.isEof: false}); 642 {this.isNewLine: false, this.isNewSegment: false, this.isEof: false});
531 } 643 }
OLDNEW
« no previous file with comments | « packages/source_maps/lib/builder.dart ('k') | packages/source_maps/lib/src/source_map_span.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698