OLD | NEW |
---|---|
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:path/path.dart' as path; | |
12 import 'package:source_span/source_span.dart'; | 11 import 'package:source_span/source_span.dart'; |
13 | 12 |
14 import 'builder.dart' as builder; | 13 import 'builder.dart' as builder; |
15 import 'src/source_map_span.dart'; | 14 import 'src/source_map_span.dart'; |
16 import 'src/utils.dart'; | 15 import 'src/utils.dart'; |
17 import 'src/vlq.dart'; | 16 import 'src/vlq.dart'; |
18 | 17 |
19 /// Parses a source map directly from a json string. | 18 /// Parses a source map directly from a json string. |
20 /// | 19 /// |
21 /// [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 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 buff.write(map.toString()); | 197 buff.write(map.toString()); |
199 } | 198 } |
200 return buff.toString(); | 199 return buff.toString(); |
201 } | 200 } |
202 | 201 |
203 SourceMapSpan spanFor(int line, int column, | 202 SourceMapSpan spanFor(int line, int column, |
204 {Map<String, SourceFile> files, String uri}) { | 203 {Map<String, SourceFile> files, String uri}) { |
205 if (uri == null) { | 204 if (uri == null) { |
206 throw new ArgumentError.notNull('uri'); | 205 throw new ArgumentError.notNull('uri'); |
207 } | 206 } |
208 if (_mappings.containsKey(uri)) { | 207 |
209 return _mappings[uri].spanFor(line, column, files: files, uri: uri); | 208 // Find the longest suffix of the uri that matches the sourcemap |
210 } | 209 // where the suffix starts after a path segment boundary. |
211 // Fall back to looking up the source map on just the basename. | 210 // We consider ":", "/", and "\" as path segment boundaries so that |
212 var name = path.basename(uri.toString()); | 211 // "package:" uris, windows paths, and linux paths can all be handled |
213 if (_mappings.containsKey(name)) { | 212 // properly with minimal special casing. Having a few false positive |
214 return _mappings[name].spanFor(line, column, files: files, uri: name); | 213 // path segment boundaries is not a significant issue as we prefer the |
214 // longest matching prefix. | |
215 // Using package:path `path.split` to find path segment boundaries would | |
216 // not generate all of the path segment boundaries we want for package: | |
217 // urls as "package:package_name" would be one path segment when we want | |
218 // "package" and "package_name" to be sepearate path segments. | |
219 | |
220 bool onBoundary = true; | |
221 var separatorCodeUnits = [ | |
222 '/'.codeUnitAt(0), | |
223 '\\'.codeUnitAt(0), | |
Siggi Cherem (dart-lang)
2016/12/14 19:10:34
we discussed this offline: let's get rid of the ha
Jacob
2016/12/14 19:17:00
Done.
| |
224 ':'.codeUnitAt(0) | |
225 ]; | |
226 for (var i = 0; i < uri.length; ++i) { | |
227 if (onBoundary) { | |
228 var candidate = uri.substring(i); | |
229 if (_mappings.containsKey(candidate)) { | |
230 return _mappings[candidate] | |
231 .spanFor(line, column, files: files, uri: candidate); | |
232 } | |
233 // The following two cases are needed to handle cases where the uri | |
234 // may use different path separator conventions that the source map | |
235 // bundle as is seasonable if we are using the source map bundle on | |
236 // the server while the files being considered are on the client. | |
237 | |
238 var webCandidate = candidate.replaceAll('\\', '/'); | |
239 if (_mappings.containsKey(webCandidate)) { | |
240 return _mappings[webCandidate] | |
241 .spanFor(line, column, files: files, uri: webCandidate); | |
242 } | |
243 | |
244 var windowsCandidate = candidate.replaceAll('/', '\\'); | |
245 if (_mappings.containsKey(windowsCandidate)) { | |
246 return _mappings[windowsCandidate] | |
247 .spanFor(line, column, files: files, uri: windowsCandidate); | |
248 } | |
249 } | |
250 onBoundary = separatorCodeUnits.contains(uri.codeUnitAt(i)); | |
215 } | 251 } |
216 | 252 |
217 // Note: when there is no source map for an uri, this behaves like an | 253 // Note: when there is no source map for an uri, this behaves like an |
218 // identity function, returning the requested location as the result. | 254 // identity function, returning the requested location as the result. |
219 | 255 |
220 // Create a mock offset for the output location. We compute it in terms | 256 // Create a mock offset for the output location. We compute it in terms |
221 // of the input line and column to minimize the chances that two different | 257 // of the input line and column to minimize the chances that two different |
222 // line and column locations are mapped to the same offset. | 258 // line and column locations are mapped to the same offset. |
223 var offset = line * 1000000 + column; | 259 var offset = line * 1000000 + column; |
224 var location = new SourceLocation(offset, | 260 var location = new SourceLocation(offset, |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
611 static const _TokenKind EOF = const _TokenKind(isEof: true); | 647 static const _TokenKind EOF = const _TokenKind(isEof: true); |
612 static const _TokenKind VALUE = const _TokenKind(); | 648 static const _TokenKind VALUE = const _TokenKind(); |
613 final bool isNewLine; | 649 final bool isNewLine; |
614 final bool isNewSegment; | 650 final bool isNewSegment; |
615 final bool isEof; | 651 final bool isEof; |
616 bool get isValue => !isNewLine && !isNewSegment && !isEof; | 652 bool get isValue => !isNewLine && !isNewSegment && !isEof; |
617 | 653 |
618 const _TokenKind( | 654 const _TokenKind( |
619 {this.isNewLine: false, this.isNewSegment: false, this.isEof: false}); | 655 {this.isNewLine: false, this.isNewSegment: false, this.isEof: false}); |
620 } | 656 } |
OLD | NEW |