Support GitLab flavored fenced blockquote (dart-lang/markdown#403)

diff --git a/pkgs/markdown/lib/src/block_parser.dart b/pkgs/markdown/lib/src/block_parser.dart
index f8645e4..256ff1e 100644
--- a/pkgs/markdown/lib/src/block_parser.dart
+++ b/pkgs/markdown/lib/src/block_parser.dart
@@ -29,6 +29,9 @@
 /// Fenced code block.
 final _codeFencePattern = RegExp(r'^[ ]{0,3}(`{3,}|~{3,})(.*)$');
 
+/// Fenced blockquotes.
+final _blockquoteFencePattern = RegExp(r'^>{3}\s*$');
+
 /// Three or more hyphens, asterisks or underscores by themselves. Note that
 /// a line like `----` is valid as both HR and SETEXT. In case of a tie,
 /// SETEXT should win.
@@ -328,6 +331,42 @@
   }
 }
 
+/// Parses lines fenced by `>>>` to blockquotes
+class FencedBlockquoteSyntax extends BlockSyntax {
+  const FencedBlockquoteSyntax();
+
+  @override
+  RegExp get pattern => _blockquoteFencePattern;
+
+  @override
+  List<String> parseChildLines(BlockParser parser) {
+    final childLines = <String>[];
+    parser.advance();
+
+    while (!parser.isDone) {
+      final match = pattern.hasMatch(parser.current);
+      if (!match) {
+        childLines.add(parser.current);
+        parser.advance();
+      } else {
+        parser.advance();
+        break;
+      }
+    }
+
+    return childLines;
+  }
+
+  @override
+  Node? parse(BlockParser parser) {
+    final childLines = parseChildLines(parser);
+
+    // Recursively parse the contents of the blockquote.
+    final children = BlockParser(childLines, parser.document).parseLines();
+    return Element('blockquote', children);
+  }
+}
+
 /// Parses email-style blockquotes: `> quote`.
 class BlockquoteSyntax extends BlockSyntax {
   @override
diff --git a/pkgs/markdown/test/extensions/fenced_blockquotes.unit b/pkgs/markdown/test/extensions/fenced_blockquotes.unit
new file mode 100644
index 0000000..8124ad4
--- /dev/null
+++ b/pkgs/markdown/test/extensions/fenced_blockquotes.unit
@@ -0,0 +1,70 @@
+>>> simple block quote
+>>>
+# Foo
+bar
+baz
+>>>
+
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> has blank lines
+>>>
+
+foo
+
+
+
+
+bar
+
+
+>>>
+
+<<<
+<blockquote>
+<p>foo</p>
+<p>bar</p>
+</blockquote>
+>>> with nested block quote
+>>>
+foo
+> bar
+>>>
+
+<<<
+<blockquote>
+<p>foo</p>
+<blockquote>
+<p>bar</p>
+</blockquote>
+</blockquote>
+>>> with nested indented clode block
+>>>
+    foo
+    bar
+>>>
+
+<<<
+<blockquote>
+<pre><code>foo
+bar
+</code></pre>
+</blockquote>
+>>> with nested fenced clode block
+>>>
+```
+foo
+bar
+```
+>>>
+
+<<<
+<blockquote>
+<pre><code>foo
+bar
+</code></pre>
+</blockquote>
\ No newline at end of file
diff --git a/pkgs/markdown/test/markdown_test.dart b/pkgs/markdown/test/markdown_test.dart
index 1abe941..945b904 100644
--- a/pkgs/markdown/test/markdown_test.dart
+++ b/pkgs/markdown/test/markdown_test.dart
@@ -18,6 +18,8 @@
   testFile('extensions/setext_headers_with_ids.unit',
       blockSyntaxes: [const SetextHeaderWithIdSyntax()]);
   testFile('extensions/tables.unit', blockSyntaxes: [const TableSyntax()]);
+  testFile('extensions/fenced_blockquotes.unit',
+      blockSyntaxes: [const FencedBlockquoteSyntax()]);
 
   // Inline syntax extensions
   testFile('extensions/emojis.unit', inlineSyntaxes: [EmojiSyntax()]);