Add support for Firefox anonymous stackTraces (#55)
Co-authored-by: Sinegovsky Ivan <ivan.sinegovsky@team.wrike.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d4bfa07..faf6eeb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.9.4-dev
+
+* Added support for firefox anonymous stack traces
+
## 1.9.3
* Set max SDK version to `<3.0.0`.
diff --git a/lib/src/frame.dart b/lib/src/frame.dart
index bbe5c79..53ae619 100644
--- a/lib/src/frame.dart
+++ b/lib/src/frame.dart
@@ -30,6 +30,11 @@
final _v8EvalLocation =
new RegExp(r'^eval at (?:\S.*?) \((.*)\)(?:, .*?:\d+:\d+)?$');
+// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > Function:3:40
+// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > eval:3:40
+final _firefoxEvalLocation =
+ new RegExp(r"(\S+)@(\S+) line (\d+) >.* (Function|eval):\d+:\d+");
+
// .VW.call$0@http://pub.dartlang.org/stuff.dart.js:560
// .VW.call$0("arg")@http://pub.dartlang.org/stuff.dart.js:560
// .VW.call$0/name<@http://pub.dartlang.org/stuff.dart.js:560
@@ -205,11 +210,33 @@
/// be retrieved.
factory Frame.parseIE(String frame) => new Frame.parseV8(frame);
+ /// Parses a string representation of a Firefox 'eval' or 'function' stack frame.
+ ///
+ /// for example:
+ /// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > Function:3:40
+ /// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > eval:3:40
+ factory Frame._parseFirefoxEval(String frame) =>
+ _catchFormatException(frame, () {
+ final match = _firefoxEvalLocation.firstMatch(frame);
+ if (match == null) return new UnparsedFrame(frame);
+ var member = match[1].replaceAll('/<', '');
+ final uri = _uriOrPathToUri(match[2]);
+ final line = int.parse(match[3]);
+ if (member.isEmpty || member == 'anonymous') {
+ member = '<fn>';
+ }
+ return new Frame(uri, line, null, member);
+ });
+
/// Parses a string representation of a Firefox stack frame.
factory Frame.parseFirefox(String frame) => _catchFormatException(frame, () {
var match = _firefoxSafariFrame.firstMatch(frame);
if (match == null) return new UnparsedFrame(frame);
+ if (match[3].contains(' line ')) {
+ return Frame._parseFirefoxEval(frame);
+ }
+
// Normally this is a URI, but in a jsshell trace it can be a path.
var uri = _uriOrPathToUri(match[3]);
diff --git a/lib/src/trace.dart b/lib/src/trace.dart
index 972c33e..9baff1c 100644
--- a/lib/src/trace.dart
+++ b/lib/src/trace.dart
@@ -27,6 +27,14 @@
/// though it is possible for the message to match this as well.
final _v8TraceLine = new RegExp(r" ?at ");
+/// A RegExp to match Firefox's eval and Function stack traces.
+/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack
+/// These stack traces looks like:
+/// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > Function:3:40
+/// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > eval:3:40
+final _firefoxEvalTrace =
+ new RegExp(r"@\S+ line \d+ >.* (Function|eval):\d+:\d+");
+
/// A RegExp to match Firefox and Safari's stack traces.
///
/// Firefox and Safari have very similar stack trace formats, so we use the same
@@ -120,7 +128,8 @@
if (trace.isEmpty) return new Trace(<Frame>[]);
if (trace.contains(_v8Trace)) return new Trace.parseV8(trace);
if (trace.contains("\tat ")) return new Trace.parseJSCore(trace);
- if (trace.contains(_firefoxSafariTrace)) {
+ if (trace.contains(_firefoxSafariTrace) ||
+ trace.contains(_firefoxEvalTrace)) {
return new Trace.parseFirefox(trace);
}
if (trace.contains(chainGap)) return new Chain.parse(trace).toTrace();
diff --git a/pubspec.yaml b/pubspec.yaml
index 6774615..8715eae 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -7,7 +7,7 @@
#
# When the major version is upgraded, you *must* update that version constraint
# in pub to stay in sync with this.
-version: 1.9.3
+version: 1.9.4-dev
description: A package for manipulating stack traces and printing them readably.
author: 'Dart Team <misc@dartlang.org>'
diff --git a/test/frame_test.dart b/test/frame_test.dart
index 42df4cd..1ec3c99 100644
--- a/test/frame_test.dart
+++ b/test/frame_test.dart
@@ -236,6 +236,52 @@
});
group('.parseFirefox/.parseSafari', () {
+ test('parses a Firefox stack trace with anonymous function', () {
+ var trace = new Trace.parse('''
+Foo._bar@http://pub.dartlang.org/stuff.js:18056:12
+anonymous/<@http://pub.dartlang.org/stuff.js line 693 > Function:3:40
+baz@http://pub.dartlang.org/buz.js:56355:55
+ ''');
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[0].line, equals(18056));
+ expect(trace.frames[0].column, equals(12));
+ expect(trace.frames[0].member, equals("Foo._bar"));
+ expect(trace.frames[1].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[1].line, equals(693));
+ expect(trace.frames[1].column, isNull);
+ expect(trace.frames[1].member, equals("<fn>"));
+ expect(trace.frames[2].uri,
+ equals(Uri.parse("http://pub.dartlang.org/buz.js")));
+ expect(trace.frames[2].line, equals(56355));
+ expect(trace.frames[2].column, equals(55));
+ expect(trace.frames[2].member, equals("baz"));
+ });
+
+ test(
+ 'parses a Firefox stack trace with nested evals in anonymous function correctly',
+ () {
+ var trace = new Trace.parse('''
+ Foo._bar@http://pub.dartlang.org/stuff.js:18056:12
+ anonymous@file:///C:/example.html line 7 > eval line 1 > eval:1:1
+ anonymous@file:///C:/example.html line 45 > Function:1:1
+ ''');
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[0].line, equals(18056));
+ expect(trace.frames[0].column, equals(12));
+ expect(trace.frames[0].member, equals("Foo._bar"));
+ expect(trace.frames[1].uri, equals(Uri.parse("file:///C:/example.html")));
+ expect(trace.frames[1].line, equals(7));
+ expect(trace.frames[1].column, isNull);
+ expect(trace.frames[1].member, equals("<fn>"));
+ expect(trace.frames[2].uri, equals(Uri.parse("file:///C:/example.html")));
+ expect(trace.frames[2].line, equals(45));
+ expect(trace.frames[2].column, isNull);
+ expect(trace.frames[2].member, equals("<fn>"));
+ });
+
test('parses a simple stack frame correctly', () {
var frame = new Frame.parseFirefox(
".VW.call\$0@http://pub.dartlang.org/stuff.dart.js:560");