Chromium Code Reviews| 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 |