Make Chain.parse and Trace.parse more similar.

R=rnystrom@google.com

Review URL: https://codereview.chromium.org//1410683011 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dae0db6..624a934 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 1.5.0
+
+* `new Chain.parse()` now parses all the stack trace formats supported by `new
+  Trace.parse()`. Formats other than that emitted by `Chain.toString()` will
+  produce single-element chains.
+
+* `new Trace.parse()` now parses the output of `Chain.toString()`. It produces
+  the same result as `Chain.parse().toTrace()`.
+
 ## 1.4.2
 
 * Improve the display of `data:` URIs in stack traces.
diff --git a/lib/src/chain.dart b/lib/src/chain.dart
index acd17e9..2e07d4b 100644
--- a/lib/src/chain.dart
+++ b/lib/src/chain.dart
@@ -16,10 +16,6 @@
 /// A function that handles errors in the zone wrapped by [Chain.capture].
 typedef void ChainHandler(error, Chain chain);
 
-/// The line used in the string representation of stack chains to represent
-/// the gap between traces.
-const _gap = '===== asynchronous gap ===========================\n';
-
 /// A chain of stack traces.
 ///
 /// A stack chain is a collection of one or more stack traces that collectively
@@ -119,11 +115,15 @@
 
   /// Parses a string representation of a stack chain.
   ///
-  /// Specifically, this parses the output of [Chain.toString].
+  /// If [chain] is the output of a call to [Chain.toString], it will be parsed
+  /// as a full stack chain. Otherwise, it will be parsed as in [Trace.parse]
+  /// and returned as a single-trace chain.
   factory Chain.parse(String chain) {
     if (chain.isEmpty) return new Chain([]);
+    if (!chain.contains(chainGap)) return new Chain([new Trace.parse(chain)]);
+
     return new Chain(
-        chain.split(_gap).map((trace) => new Trace.parseFriendly(trace)));
+        chain.split(chainGap).map((trace) => new Trace.parseFriendly(trace)));
   }
 
   /// Returns a new [Chain] comprised of [traces].
@@ -191,6 +191,6 @@
       return trace.frames.map((frame) {
         return '${padRight(frame.location, longest)}  ${frame.member}\n';
       }).join();
-    }).join(_gap);
+    }).join(chainGap);
   }
 }
diff --git a/lib/src/trace.dart b/lib/src/trace.dart
index f615cd2..7f2c662 100644
--- a/lib/src/trace.dart
+++ b/lib/src/trace.dart
@@ -111,7 +111,8 @@
   /// Parses a string representation of a stack trace.
   ///
   /// [trace] should be formatted in the same way as a Dart VM or browser stack
-  /// trace.
+  /// trace. If it's formatted as a stack chain, this will return the equivalent
+  /// of [Chain.toTrace].
   factory Trace.parse(String trace) {
     try {
       if (trace.isEmpty) return new Trace(<Frame>[]);
@@ -120,6 +121,7 @@
       if (trace.contains(_firefoxSafariTrace)) {
         return new Trace.parseFirefox(trace);
       }
+      if (trace.contains(chainGap)) return new Chain.parse(trace).toTrace();
       if (trace.contains(_friendlyTrace)) {
         return new Trace.parseFriendly(trace);
       }
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 62a2820..1d09443 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -4,6 +4,10 @@
 
 library stack_trace.src.utils;
 
+/// The line used in the string representation of stack chains to represent
+/// the gap between traces.
+const chainGap = '===== asynchronous gap ===========================\n';
+
 /// Returns [string] with enough spaces added to the end to make it [length]
 /// characters long.
 String padRight(String string, int length) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 5c8b720..932f648 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.4.2
+version: 1.5.0
 author: "Dart Team <misc@dartlang.org>"
 homepage: http://github.com/dart-lang/stack_trace
 description: >