22// for details. All rights reserved. Use of this source code is governed by a
33// BSD-style license that can be found in the LICENSE file.
44
5- import 'package:stack_trace/stack_trace.dart' as stack;
5+ import 'dart:io' ;
6+
7+ import 'package:path/path.dart' as path;
68
79/// Returns whether this URI is something that can be resolved to a file-like
810/// URI via the VM Service.
@@ -27,10 +29,9 @@ bool isResolvableUri(Uri uri) {
2729///
2830/// Frames that do not look like real Dart stack frames (such as including path
2931/// or URIs that look like real Dart libraries) will be filtered out but it
30- /// should not be assumed that if a [stack.Frame] is returned that the input
31- /// was necessarily a stack frame or that calling `toString` will return the
32- /// original input text.
33- stack.Frame ? parseDartStackFrame (String line) {
32+ /// should not be assumed that if a value is returned that the input
33+ /// was necessarily a stack frame.
34+ StackFrameLocation ? parseDartStackFrame (String line) {
3435 final frame = _parseStackFrame (line);
3536 final uri = frame? .uri;
3637 return uri != null && _isDartUri (uri) ? frame : null ;
@@ -68,35 +69,58 @@ bool _isDartUri(Uri uri) {
6869 return false ;
6970}
7071
72+ /// A [RegExp] for extracting URIs and optional line/columns out of a line from
73+ /// a stack trace.
74+ final _stackFrameLocationPattern =
75+ // Characters we consider part of a path:
76+ //
77+ // - `\w` word characters
78+ // - `-` dash (valid in paths and URI schemes)
79+ // - `:` colons (scheme or drive letters)
80+ // - `/` forward slashes (URIs)
81+ // - `\` black slashes (Windows paths)
82+ // - `%` percent (URL percent encoding)
83+ // - `+` plus (possible URL encoding of space)
84+ //
85+ // To avoid matching too much, we don't allow spaces even though they could
86+ // appear in relative paths. Most output should be URIs where they would be
87+ // encoded.
88+ //
89+ // The whole string must end with the line/col sequence, a non-word
90+ // character or be the end of the line. This avoids matching some strings
91+ // that contain ".dart" but probably aren't valid paths, like ".dart2".
92+ RegExp (r'([\w\-:\/\\%+]+\.dart)(?:(?:(?: +|:)(\d+):(\d+))|\W|$)' );
93+
7194/// Attempts to parse a line as a stack frame in order to read path/line/col
7295/// information.
7396///
74- /// It should not be assumed that if a [stack.Frame] is returned that the input
75- /// was necessarily a stack frame or that calling `toString` will return the
76- /// original input text.
77- stack.Frame ? _parseStackFrame (String line) {
78- // Because we split on \n, on Windows there may be trailing \r which prevents
79- // package:stack_trace from parsing correctly.
80- line = line.trim ();
81-
82- /// Helper to try parsing a frame with [parser] , returning `null` if it
83- /// fails to parse.
84- stack.Frame ? tryParseFrame (stack.Frame Function (String ) parser) {
85- final frame = parser (line);
86- return frame is stack.UnparsedFrame ? null : frame;
97+ /// It should not be assumed that if a value is returned that the input
98+ /// was necessarily a stack frame.
99+ StackFrameLocation ? _parseStackFrame (String input) {
100+ var match = _stackFrameLocationPattern.firstMatch (input);
101+ if (match == null ) return null ;
102+
103+ var uriMatch = match.group (1 );
104+ var lineMatch = match.group (2 );
105+ var colMatch = match.group (3 );
106+
107+ var uri = uriMatch != null ? Uri .tryParse (uriMatch) : null ;
108+ var line = lineMatch != null ? int .tryParse (lineMatch) : null ;
109+ var col = colMatch != null ? int .tryParse (colMatch) : null ;
110+
111+ if (uriMatch == null || uri == null ) {
112+ return null ;
113+ }
114+
115+ // If the URI has no scheme, assume a relative path from Directory.current.
116+ if (! uri.hasScheme && path.isRelative (uriMatch)) {
117+ var currentDirectoryPath = Directory .current.path;
118+ if (currentDirectoryPath.isNotEmpty) {
119+ uri = Uri .file (path.join (currentDirectoryPath, uriMatch));
120+ }
87121 }
88122
89- // Try different formats of stack frames.
90- // pkg:stack_trace does not have a generic Frame.parse() and Trace.parse()
91- // doesn't work well when the content includes non-stack-frame lines
92- // (https://github.com/dart-lang/stack_trace/issues/115).
93- return tryParseFrame ((line) => stack.Frame .parseVM (line)) ??
94- // TODO(dantup): Tidy up when constructor tear-offs are available.
95- tryParseFrame ((line) => stack.Frame .parseV8 (line)) ??
96- tryParseFrame ((line) => stack.Frame .parseSafari (line)) ??
97- tryParseFrame ((line) => stack.Frame .parseFirefox (line)) ??
98- tryParseFrame ((line) => stack.Frame .parseIE (line)) ??
99- tryParseFrame ((line) => stack.Frame .parseFriendly (line));
123+ return (uri: uri, line: line, column: col);
100124}
101125
102126/// Checks whether [flag] is in [args] , allowing for both underscore and
@@ -106,3 +130,5 @@ bool containsVmFlag(List<String> args, String flag) {
106130 final flagDashes = flag.replaceAll ('_' , '-' );
107131 return args.contains (flagUnderscores) || args.contains (flagDashes);
108132}
133+
134+ typedef StackFrameLocation = ({Uri uri, int ? line, int ? column});
0 commit comments