diff --git a/readme.md b/readme.md
index 77ed95d95..8787d40a1 100644
--- a/readme.md
+++ b/readme.md
@@ -19,6 +19,7 @@ You can **try Markdig online** and compare it to other implementations on [babel
- including **GFM fenced code blocks**.
- **Extensible** architecture
- Even the core Markdown/CommonMark parsing is pluggable, so it allows to disable builtin Markdown/Commonmark parsing (e.g [Disable HTML parsing](https://github.com/lunet-io/markdig/blob/7964bd0160d4c18e4155127a4c863d61ebd8944a/src/Markdig/MarkdownExtensions.cs#L306)) or change behaviour (e.g change matching `#` of a headers with `@`)
+- [**Roundtrip support**](./src/Markdig/Roundtrip.md): Parses trivia (whitespace, newlines and other characters) to support lossless parse ⭢ render roundtrip. This enables changing markdown documents without introducing undesired trivia changes.
- Built-in with **20+ extensions**, including:
- 2 kind of tables:
- [**Pipe tables**](src/Markdig.Tests/Specs/PipeTableSpecs.md) (inspired from GitHub tables and [PanDoc - Pipe Tables](http://pandoc.org/README.html#extension-pipe_tables))
diff --git a/src/Markdig.Tests/RoundtripSpecs/CommonMark.generated.cs b/src/Markdig.Tests/RoundtripSpecs/CommonMark.generated.cs
new file mode 100644
index 000000000..8406fdfa5
--- /dev/null
+++ b/src/Markdig.Tests/RoundtripSpecs/CommonMark.generated.cs
@@ -0,0 +1,15266 @@
+
+// --------------------------------
+// Roundtrip
+// --------------------------------
+
+using System;
+using NUnit.Framework;
+
+namespace Markdig.Tests.Specs.Roundtrip.Roundtrip
+{
+ [TestFixture]
+ public class TestPreliminariesTabs
+ {
+ // ---
+ // title: CommonMark Spec
+ // author: John MacFarlane
+ // version: 0.29
+ // date: '2019-04-06'
+ // license: '[CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)'
+ // ...
+ //
+ // # Introduction
+ //
+ // ## What is Markdown?
+ //
+ // Markdown is a plain text format for writing structured documents,
+ // based on conventions for indicating formatting in email
+ // and usenet posts. It was developed by John Gruber (with
+ // help from Aaron Swartz) and released in 2004 in the form of a
+ // [syntax description](http://daringfireball.net/projects/markdown/syntax)
+ // and a Perl script (`Markdown.pl`) for converting Markdown to
+ // HTML. In the next decade, dozens of implementations were
+ // developed in many languages. Some extended the original
+ // Markdown syntax with conventions for footnotes, tables, and
+ // other document elements. Some allowed Markdown documents to be
+ // rendered in formats other than HTML. Websites like Reddit,
+ // StackOverflow, and GitHub had millions of people using Markdown.
+ // And Markdown started to be used beyond the web, to author books,
+ // articles, slide shows, letters, and lecture notes.
+ //
+ // What distinguishes Markdown from many other lightweight markup
+ // syntaxes, which are often easier to write, is its readability.
+ // As Gruber writes:
+ //
+ // > The overriding design goal for Markdown's formatting syntax is
+ // > to make it as readable as possible. The idea is that a
+ // > Markdown-formatted document should be publishable as-is, as
+ // > plain text, without looking like it's been marked up with tags
+ // > or formatting instructions.
+ // > (
` tags? Can a list be partially "loose" and partially + // "tight"? What should we do with a list like this? + // + // ``` markdown + // 1. one + // + // 2. two + // 3. three + // ``` + // + // Or this? + // + // ``` markdown + // 1. one + // - a + // + // - b + // 2. two + // ``` + // + // (There are some relevant comments by John Gruber + // [here](http://article.gmane.org/gmane.text.markdown.general/2554).) + // + // 5. Can list markers be indented? Can ordered list markers be right-aligned? + // + // ``` markdown + // 8. item 1 + // 9. item 2 + // 10. item 2a + // ``` + // + // 6. Is this one list with a thematic break in its second item, + // or two lists separated by a thematic break? + // + // ``` markdown + // * a + // * * * * * + // * b + // ``` + // + // 7. When list markers change from numbers to bullets, do we have + // two lists or one? (The Markdown syntax description suggests two, + // but the perl scripts and many other implementations produce one.) + // + // ``` markdown + // 1. fee + // 2. fie + // - foe + // - fum + // ``` + // + // 8. What are the precedence rules for the markers of inline structure? + // For example, is the following a valid link, or does the code span + // take precedence ? + // + // ``` markdown + // [a backtick (`)](/url) and [another backtick (`)](/url). + // ``` + // + // 9. What are the precedence rules for markers of emphasis and strong + // emphasis? For example, how should the following be parsed? + // + // ``` markdown + // *foo *bar* baz* + // ``` + // + // 10. What are the precedence rules between block-level and inline-level + // structure? For example, how should the following be parsed? + // + // ``` markdown + // - `a long code span can contain a hyphen like this + // - and it can screw things up` + // ``` + // + // 11. Can list items include section headings? (`Markdown.pl` does not + // allow this, but does allow blockquotes to include headings.) + // + // ``` markdown + // - # Heading + // ``` + // + // 12. Can list items be empty? + // + // ``` markdown + // * a + // * + // * b + // ``` + // + // 13. Can link references be defined inside block quotes or list items? + // + // ``` markdown + // > Blockquote [foo]. + // > + // > [foo]: /url + // ``` + // + // 14. If there are multiple definitions for the same reference, which takes + // precedence? + // + // ``` markdown + // [foo]: /url1 + // [foo]: /url2 + // + // [foo][] + // ``` + // + // In the absence of a spec, early implementers consulted `Markdown.pl` + // to resolve these ambiguities. But `Markdown.pl` was quite buggy, and + // gave manifestly bad results in many cases, so it was not a + // satisfactory replacement for a spec. + // + // Because there is no unambiguous spec, implementations have diverged + // considerably. As a result, users are often surprised to find that + // a document that renders one way on one system (say, a GitHub wiki) + // renders differently on another (say, converting to docbook using + // pandoc). To make matters worse, because nothing in Markdown counts + // as a "syntax error," the divergence often isn't discovered right away. + // + // ## About this document + // + // This document attempts to specify Markdown syntax unambiguously. + // It contains many examples with side-by-side Markdown and + // HTML. These are intended to double as conformance tests. An + // accompanying script `spec_tests.py` can be used to run the tests + // against any Markdown program: + // + // python test/spec_tests.py --spec spec.txt --program PROGRAM + // + // Since this document describes how Markdown is to be parsed into + // an abstract syntax tree, it would have made sense to use an abstract + // representation of the syntax tree instead of HTML. But HTML is capable + // of representing the structural distinctions we need to make, and the + // choice of HTML for the tests makes it possible to run the tests against + // an implementation without writing an abstract syntax tree renderer. + // + // This document is generated from a text file, `spec.txt`, written + // in Markdown with a small extension for the side-by-side tests. + // The script `tools/makespec.py` can be used to convert `spec.txt` into + // HTML or CommonMark (which can then be converted into other formats). + // + // In the examples, the `→` character is used to represent tabs. + // + // # Preliminaries + // + // ## Characters and lines + // + // Any sequence of [characters] is a valid CommonMark + // document. + // + // A [character](@) is a Unicode code point. Although some + // code points (for example, combining accents) do not correspond to + // characters in an intuitive sense, all code points count as characters + // for purposes of this spec. + // + // This spec does not specify an encoding; it thinks of lines as composed + // of [characters] rather than bytes. A conforming parser may be limited + // to a certain encoding. + // + // A [line](@) is a sequence of zero or more [characters] + // other than newline (`U+000A`) or carriage return (`U+000D`), + // followed by a [line ending] or by the end of file. + // + // A [line ending](@) is a newline (`U+000A`), a carriage return + // (`U+000D`) not followed by a newline, or a carriage return and a + // following newline. + // + // A line containing no characters, or a line containing only spaces + // (`U+0020`) or tabs (`U+0009`), is called a [blank line](@). + // + // The following definitions of character classes will be used in this spec: + // + // A [whitespace character](@) is a space + // (`U+0020`), tab (`U+0009`), newline (`U+000A`), line tabulation (`U+000B`), + // form feed (`U+000C`), or carriage return (`U+000D`). + // + // [Whitespace](@) is a sequence of one or more [whitespace + // characters]. + // + // A [Unicode whitespace character](@) is + // any code point in the Unicode `Zs` general category, or a tab (`U+0009`), + // carriage return (`U+000D`), newline (`U+000A`), or form feed + // (`U+000C`). + // + // [Unicode whitespace](@) is a sequence of one + // or more [Unicode whitespace characters]. + // + // A [space](@) is `U+0020`. + // + // A [non-whitespace character](@) is any character + // that is not a [whitespace character]. + // + // An [ASCII punctuation character](@) + // is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`, + // `*`, `+`, `,`, `-`, `.`, `/` (U+0021–2F), + // `:`, `;`, `<`, `=`, `>`, `?`, `@` (U+003A–0040), + // `[`, `\`, `]`, `^`, `_`, `` ` `` (U+005B–0060), + // `{`, `|`, `}`, or `~` (U+007B–007E). + // + // A [punctuation character](@) is an [ASCII + // punctuation character] or anything in + // the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or `Ps`. + // + // ## Tabs + // + // Tabs in lines are not expanded to [spaces]. However, + // in contexts where whitespace helps to define block structure, + // tabs behave as if they were replaced by spaces with a tab stop + // of 4 characters. + // + // Thus, for example, a tab can be used instead of four spaces + // in an indented code block. (Note, however, that internal + // tabs are passed through as literal tabs, not expanded to + // spaces.) + [Test] + public void PreliminariesTabs_Example001() + { + // Example 1 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // →foo→baz→→bim + // + // Should be rendered as: + //
foo→baz→→bim
+ //
+
+ Console.WriteLine("Example 1\nSection Preliminaries / Tabs\n");
+ TestRoundtrip.TestSpec("\tfoo\tbaz\t\tbim", "foo\tbaz\t\tbim\n", "");
+ }
+
+ [Test]
+ public void PreliminariesTabs_Example002()
+ {
+ // Example 2
+ // Section: Preliminaries / Tabs
+ //
+ // The following Markdown:
+ // →foo→baz→→bim
+ //
+ // Should be rendered as:
+ // foo→baz→→bim
+ //
+
+ Console.WriteLine("Example 2\nSection Preliminaries / Tabs\n");
+ TestRoundtrip.TestSpec(" \tfoo\tbaz\t\tbim", "foo\tbaz\t\tbim\n", "");
+ }
+
+ [Test]
+ public void PreliminariesTabs_Example003()
+ {
+ // Example 3
+ // Section: Preliminaries / Tabs
+ //
+ // The following Markdown:
+ // a→a
+ // ὐ→a
+ //
+ // Should be rendered as:
+ // a→a
+ // ὐ→a
+ //
+
+ Console.WriteLine("Example 3\nSection Preliminaries / Tabs\n");
+ TestRoundtrip.TestSpec(" a\ta\n ὐ\ta", "a\ta\nὐ\ta\n", "");
+ }
+
+ // In the following example, a continuation paragraph of a list
+ // item is indented with a tab; this has exactly the same effect
+ // as indentation with four spaces would:
+ [Test]
+ public void PreliminariesTabs_Example004()
+ {
+ // Example 4
+ // Section: Preliminaries / Tabs
+ //
+ // The following Markdown:
+ // - foo
+ //
+ // →bar
+ //
+ // Should be rendered as:
+ // foo
+ //bar
+ //foo
\nbar
\nfoo
+ // bar
+ //
+ // foo
\n bar\n\n+ //+ + Console.WriteLine("Example 6\nSection Preliminaries / Tabs\n"); + TestRoundtrip.TestSpec(">\t\tfoo", "+ //foo + //
\n", ""); + } + + [Test] + public void PreliminariesTabs_Example007() + { + // Example 7 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // -→→foo + // + // Should be rendered as: + //\nfoo\n
foo
+ //
+ // foo\n\nfoo
+ // bar
+ //
+
+ Console.WriteLine("Example 8\nSection Preliminaries / Tabs\n");
+ TestRoundtrip.TestSpec(" foo\n\tbar", "foo\nbar\n", "");
+ }
+
+ [Test]
+ public void PreliminariesTabs_Example009()
+ {
+ // Example 9
+ // Section: Preliminaries / Tabs
+ //
+ // The following Markdown:
+ // - foo
+ // - bar
+ // → - baz
+ //
+ // Should be rendered as:
+ // +++
+ + Console.WriteLine("Example 14\nSection Leaf blocks / Thematic breaks\n"); + TestRoundtrip.TestSpec("+++", "+++
", ""); + } + + [Test] + public void LeafBlocksThematicBreaks_Example015() + { + // Example 15 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // === + // + // Should be rendered as: + //===
+ + Console.WriteLine("Example 15\nSection Leaf blocks / Thematic breaks\n"); + TestRoundtrip.TestSpec("===", "===
", ""); + } + + // Not enough characters: + [Test] + public void LeafBlocksThematicBreaks_Example016() + { + // Example 16 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // -- + // ** + // __ + // + // Should be rendered as: + //-- + // ** + // __
+ + Console.WriteLine("Example 16\nSection Leaf blocks / Thematic breaks\n"); + TestRoundtrip.TestSpec("--\n**\n__", "--\n**\n__
", ""); + } + + // One to three spaces indent are allowed: + [Test] + public void LeafBlocksThematicBreaks_Example017() + { + // Example 17 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // *** + // *** + // *** + // + // Should be rendered as: + //***
+ //
+
+ Console.WriteLine("Example 18\nSection Leaf blocks / Thematic breaks\n");
+ TestRoundtrip.TestSpec(" ***", "***\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksThematicBreaks_Example019()
+ {
+ // Example 19
+ // Section: Leaf blocks / Thematic breaks
+ //
+ // The following Markdown:
+ // Foo
+ // ***
+ //
+ // Should be rendered as:
+ // Foo + // ***
+ + Console.WriteLine("Example 19\nSection Leaf blocks / Thematic breaks\n"); + TestRoundtrip.TestSpec("Foo\n ***", "Foo\n***
", ""); + } + + // More than three characters may be used: + [Test] + public void LeafBlocksThematicBreaks_Example020() + { + // Example 20 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // _____________________________________ + // + // Should be rendered as: + //_ _ _ _ a
+ //a------
+ //---a---
+ + Console.WriteLine("Example 25\nSection Leaf blocks / Thematic breaks\n"); + TestRoundtrip.TestSpec("_ _ _ _ a\n\na------\n\n---a---", "_ _ _ _ a
\na------
\n---a---
", ""); + } + + // It is required that all of the [non-whitespace characters] be the same. + // So, this is not a thematic break: + [Test] + public void LeafBlocksThematicBreaks_Example026() + { + // Example 26 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // *-* + // + // Should be rendered as: + //-
+ + Console.WriteLine("Example 26\nSection Leaf blocks / Thematic breaks\n"); + TestRoundtrip.TestSpec(" *-*", "-
", ""); + } + + // Thematic breaks do not need blank lines before or after: + [Test] + public void LeafBlocksThematicBreaks_Example027() + { + // Example 27 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // - foo + // *** + // - bar + // + // Should be rendered as: + //Foo
+ //bar
+ + Console.WriteLine("Example 28\nSection Leaf blocks / Thematic breaks\n"); + TestRoundtrip.TestSpec("Foo\n***\nbar", "Foo
\nbar
", ""); + } + + // If a line of dashes that meets the above conditions for being a + // thematic break could also be interpreted as the underline of a [setext + // heading], the interpretation as a + // [setext heading] takes precedence. Thus, for example, + // this is a setext heading, not a paragraph followed by a thematic break: + [Test] + public void LeafBlocksThematicBreaks_Example029() + { + // Example 29 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // Foo + // --- + // bar + // + // Should be rendered as: + //bar
+ + Console.WriteLine("Example 29\nSection Leaf blocks / Thematic breaks\n"); + TestRoundtrip.TestSpec("Foo\n---\nbar", "bar
", ""); + } + + // When both a thematic break and a list item are possible + // interpretations of a line, the thematic break takes precedence: + [Test] + public void LeafBlocksThematicBreaks_Example030() + { + // Example 30 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // * Foo + // * * * + // * Bar + // + // Should be rendered as: + //####### foo
+ + Console.WriteLine("Example 33\nSection Leaf blocks / ATX headings\n"); + TestRoundtrip.TestSpec("####### foo", "####### foo
", ""); + } + + // At least one space is required between the `#` characters and the + // heading's contents, unless the heading is empty. Note that many + // implementations currently do not require the space. However, the + // space was required by the + // [original ATX implementation](http://www.aaronsw.com/2002/atx/atx.py), + // and it helps prevent things like the following from being parsed as + // headings: + [Test] + public void LeafBlocksATXHeadings_Example034() + { + // Example 34 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // #5 bolt + // + // #hashtag + // + // Should be rendered as: + //#5 bolt
+ //#hashtag
+ + Console.WriteLine("Example 34\nSection Leaf blocks / ATX headings\n"); + TestRoundtrip.TestSpec("#5 bolt\n\n#hashtag", "#5 bolt
\n#hashtag
", ""); + } + + // This is not a heading, because the first `#` is escaped: + [Test] + public void LeafBlocksATXHeadings_Example035() + { + // Example 35 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // \## foo + // + // Should be rendered as: + //## foo
+ + Console.WriteLine("Example 35\nSection Leaf blocks / ATX headings\n"); + TestRoundtrip.TestSpec("\\## foo", "## foo
", ""); + } + + // Contents are parsed as inlines: + [Test] + public void LeafBlocksATXHeadings_Example036() + { + // Example 36 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // # foo *bar* \*baz\* + // + // Should be rendered as: + //# foo
+ //
+
+ Console.WriteLine("Example 39\nSection Leaf blocks / ATX headings\n");
+ TestRoundtrip.TestSpec(" # foo", "# foo\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksATXHeadings_Example040()
+ {
+ // Example 40
+ // Section: Leaf blocks / ATX headings
+ //
+ // The following Markdown:
+ // foo
+ // # bar
+ //
+ // Should be rendered as:
+ // foo + // # bar
+ + Console.WriteLine("Example 40\nSection Leaf blocks / ATX headings\n"); + TestRoundtrip.TestSpec("foo\n # bar", "foo\n# bar
", ""); + } + + // A closing sequence of `#` characters is optional: + [Test] + public void LeafBlocksATXHeadings_Example041() + { + // Example 41 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // ## foo ## + // ### bar ### + // + // Should be rendered as: + //Foo bar
+ //Bar foo
+ + Console.WriteLine("Example 48\nSection Leaf blocks / ATX headings\n"); + TestRoundtrip.TestSpec("Foo bar\n# baz\nBar foo", "Foo bar
\nBar foo
", ""); + } + + // ATX headings can be empty: + [Test] + public void LeafBlocksATXHeadings_Example049() + { + // Example 49 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // ## + // # + // ### ### + // + // Should be rendered as: + // + // + // + + Console.WriteLine("Example 49\nSection Leaf blocks / ATX headings\n"); + TestRoundtrip.TestSpec("## \n#\n### ###", "\n\n", ""); + } + } + + [TestFixture] + public class TestLeafBlocksSetextHeadings + { + // ## Setext headings + // + // A [setext heading](@) consists of one or more + // lines of text, each containing at least one [non-whitespace + // character], with no more than 3 spaces indentation, followed by + // a [setext heading underline]. The lines of text must be such + // that, were they not followed by the setext heading underline, + // they would be interpreted as a paragraph: they cannot be + // interpretable as a [code fence], [ATX heading][ATX headings], + // [block quote][block quotes], [thematic break][thematic breaks], + // [list item][list items], or [HTML block][HTML blocks]. + // + // A [setext heading underline](@) is a sequence of + // `=` characters or a sequence of `-` characters, with no more than 3 + // spaces indentation and any number of trailing spaces. If a line + // containing a single `-` can be interpreted as an + // empty [list items], it should be interpreted this way + // and not as a [setext heading underline]. + // + // The heading is a level 1 heading if `=` characters are used in + // the [setext heading underline], and a level 2 heading if `-` + // characters are used. The contents of the heading are the result + // of parsing the preceding lines of text as CommonMark inline + // content. + // + // In general, a setext heading need not be preceded or followed by a + // blank line. However, it cannot interrupt a paragraph, so when a + // setext heading comes after a paragraph, a blank line is needed between + // them. + // + // Simple examples: + [Test] + public void LeafBlocksSetextHeadings_Example050() + { + // Example 50 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo *bar* + // ========= + // + // Foo *bar* + // --------- + // + // Should be rendered as: + //Foo
+ // ---
+ //
+ // Foo
+ //
+ // Foo\n---\n\nFoo\n\nFoo + // ---
+ + Console.WriteLine("Example 57\nSection Leaf blocks / Setext headings\n"); + TestRoundtrip.TestSpec("Foo\n ---", "Foo\n---
", ""); + } + + // The setext heading underline cannot contain internal spaces: + [Test] + public void LeafBlocksSetextHeadings_Example058() + { + // Example 58 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // = = + // + // Foo + // --- - + // + // Should be rendered as: + //Foo + // = =
+ //Foo
+ //Foo\n= =
\nFoo
\n`
+ //of dashes"/>
+ + Console.WriteLine("Example 61\nSection Leaf blocks / Setext headings\n"); + TestRoundtrip.TestSpec("`Foo\n----\n`\n\n", "`
\nof dashes"/>
", ""); + } + + // The setext heading underline cannot be a [lazy continuation + // line] in a list item or block quote: + [Test] + public void LeafBlocksSetextHeadings_Example062() + { + // Example 62 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // > Foo + // --- + // + // Should be rendered as: + //+ //+ //Foo
+ //
\n\nFoo
\n
+ //+ + Console.WriteLine("Example 63\nSection Leaf blocks / Setext headings\n"); + TestRoundtrip.TestSpec("> foo\nbar\n===", "foo + // bar + // ===
+ //
\n", ""); + } + + [Test] + public void LeafBlocksSetextHeadings_Example064() + { + // Example 64 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // - Foo + // --- + // + // Should be rendered as: + //foo\nbar\n===
\n
Baz
+ + Console.WriteLine("Example 66\nSection Leaf blocks / Setext headings\n"); + TestRoundtrip.TestSpec("---\nFoo\n---\nBar\n---\nBaz", "Baz
", ""); + } + + // Setext headings cannot be empty: + [Test] + public void LeafBlocksSetextHeadings_Example067() + { + // Example 67 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // + // ==== + // + // Should be rendered as: + //====
+ + Console.WriteLine("Example 67\nSection Leaf blocks / Setext headings\n"); + TestRoundtrip.TestSpec("\n====", "====
", ""); + } + + // Setext heading text lines must not be interpretable as block + // constructs other than paragraphs. So, the line of dashes + // in these examples gets interpreted as a thematic break: + [Test] + public void LeafBlocksSetextHeadings_Example068() + { + // Example 68 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // --- + // --- + // + // Should be rendered as: + //foo
+ //
+ // foo\n\n+ //+ //foo
+ //
\n\nfoo
\n
Foo
+ //baz
+ + Console.WriteLine("Example 73\nSection Leaf blocks / Setext headings\n"); + TestRoundtrip.TestSpec("Foo\n\nbar\n---\nbaz", "Foo
\nbaz
", ""); + } + + // Authors who want interpretation 2 can put blank lines around + // the thematic break, + [Test] + public void LeafBlocksSetextHeadings_Example074() + { + // Example 74 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // bar + // + // --- + // + // baz + // + // Should be rendered as: + //Foo + // bar
+ //baz
+ + Console.WriteLine("Example 74\nSection Leaf blocks / Setext headings\n"); + TestRoundtrip.TestSpec("Foo\nbar\n\n---\n\nbaz", "Foo\nbar
\nbaz
", ""); + } + + // or use a thematic break that cannot count as a [setext heading + // underline], such as + [Test] + public void LeafBlocksSetextHeadings_Example075() + { + // Example 75 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // bar + // * * * + // baz + // + // Should be rendered as: + //Foo + // bar
+ //baz
+ + Console.WriteLine("Example 75\nSection Leaf blocks / Setext headings\n"); + TestRoundtrip.TestSpec("Foo\nbar\n* * *\nbaz", "Foo\nbar
\nbaz
", ""); + } + + // Authors who want interpretation 3 can use backslash escapes: + [Test] + public void LeafBlocksSetextHeadings_Example076() + { + // Example 76 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // bar + // \--- + // baz + // + // Should be rendered as: + //Foo + // bar + // --- + // baz
+ + Console.WriteLine("Example 76\nSection Leaf blocks / Setext headings\n"); + TestRoundtrip.TestSpec("Foo\nbar\n\\---\nbaz", "Foo\nbar\n---\nbaz
", ""); + } + } + + [TestFixture] + public class TestLeafBlocksIndentedCodeBlocks + { + // ## Indented code blocks + // + // An [indented code block](@) is composed of one or more + // [indented chunks] separated by blank lines. + // An [indented chunk](@) is a sequence of non-blank lines, + // each indented four or more spaces. The contents of the code block are + // the literal contents of the lines, including trailing + // [line endings], minus four spaces of indentation. + // An indented code block has no [info string]. + // + // An indented code block cannot interrupt a paragraph, so there must be + // a blank line between a paragraph and a following indented code block. + // (A blank line is not needed, however, between a code block and a following + // paragraph.) + [Test] + public void LeafBlocksIndentedCodeBlocks_Example077() + { + // Example 77 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // a simple + // indented code block + // + // Should be rendered as: + //a simple
+ // indented code block
+ //
+
+ Console.WriteLine("Example 77\nSection Leaf blocks / Indented code blocks\n");
+ TestRoundtrip.TestSpec(" a simple\n indented code block", "a simple\n indented code block\n", "");
+ }
+
+ // If there is any ambiguity between an interpretation of indentation
+ // as a code block and as indicating that material belongs to a [list
+ // item][list items], the list item interpretation takes precedence:
+ [Test]
+ public void LeafBlocksIndentedCodeBlocks_Example078()
+ {
+ // Example 78
+ // Section: Leaf blocks / Indented code blocks
+ //
+ // The following Markdown:
+ // - foo
+ //
+ // bar
+ //
+ // Should be rendered as:
+ // foo
+ //bar
+ //foo
\nbar
\nfoo
+ //foo
\n<a/>
+ // *hi*
+ //
+ // - one
+ //
+
+ Console.WriteLine("Example 80\nSection Leaf blocks / Indented code blocks\n");
+ TestRoundtrip.TestSpec(" \n *hi*\n\n - one", "<a/>\n*hi*\n\n- one\n", "");
+ }
+
+ // Here we have three chunks separated by blank lines:
+ [Test]
+ public void LeafBlocksIndentedCodeBlocks_Example081()
+ {
+ // Example 81
+ // Section: Leaf blocks / Indented code blocks
+ //
+ // The following Markdown:
+ // chunk1
+ //
+ // chunk2
+ //
+ //
+ //
+ // chunk3
+ //
+ // Should be rendered as:
+ // chunk1
+ //
+ // chunk2
+ //
+ //
+ //
+ // chunk3
+ //
+
+ Console.WriteLine("Example 81\nSection Leaf blocks / Indented code blocks\n");
+ TestRoundtrip.TestSpec(" chunk1\n\n chunk2\n \n \n \n chunk3", "chunk1\n\nchunk2\n\n\n\nchunk3\n", "");
+ }
+
+ // Any initial spaces beyond four will be included in the content, even
+ // in interior blank lines:
+ [Test]
+ public void LeafBlocksIndentedCodeBlocks_Example082()
+ {
+ // Example 82
+ // Section: Leaf blocks / Indented code blocks
+ //
+ // The following Markdown:
+ // chunk1
+ //
+ // chunk2
+ //
+ // Should be rendered as:
+ // chunk1
+ //
+ // chunk2
+ //
+
+ Console.WriteLine("Example 82\nSection Leaf blocks / Indented code blocks\n");
+ TestRoundtrip.TestSpec(" chunk1\n \n chunk2", "chunk1\n \n chunk2\n", "");
+ }
+
+ // An indented code block cannot interrupt a paragraph. (This
+ // allows hanging indents and the like.)
+ [Test]
+ public void LeafBlocksIndentedCodeBlocks_Example083()
+ {
+ // Example 83
+ // Section: Leaf blocks / Indented code blocks
+ //
+ // The following Markdown:
+ // Foo
+ // bar
+ //
+ //
+ // Should be rendered as:
+ // Foo + // bar
+ + Console.WriteLine("Example 83\nSection Leaf blocks / Indented code blocks\n"); + TestRoundtrip.TestSpec("Foo\n bar\n", "Foo\nbar
", ""); + } + + // However, any non-blank line with fewer than four leading spaces ends + // the code block immediately. So a paragraph may occur immediately + // after indented code: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example084() + { + // Example 84 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // foo + // bar + // + // Should be rendered as: + //foo
+ //
+ // bar
+ + Console.WriteLine("Example 84\nSection Leaf blocks / Indented code blocks\n"); + TestRoundtrip.TestSpec(" foo\nbar", "foo\n\nbar
", ""); + } + + // And indented code can occur immediately before and after other kinds of + // blocks: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example085() + { + // Example 85 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // # Heading + // foo + // Heading + // ------ + // foo + // ---- + // + // Should be rendered as: + //foo
+ //
+ // foo
+ //
+ // foo\n\nfoo\n\n foo
+ // bar
+ //
+
+ Console.WriteLine("Example 86\nSection Leaf blocks / Indented code blocks\n");
+ TestRoundtrip.TestSpec(" foo\n bar", " foo\nbar\n", "");
+ }
+
+ // Blank lines preceding or following an indented code block
+ // are not included in it:
+ [Test]
+ public void LeafBlocksIndentedCodeBlocks_Example087()
+ {
+ // Example 87
+ // Section: Leaf blocks / Indented code blocks
+ //
+ // The following Markdown:
+ //
+ //
+ // foo
+ //
+ //
+ //
+ // Should be rendered as:
+ // foo
+ //
+
+ Console.WriteLine("Example 87\nSection Leaf blocks / Indented code blocks\n");
+ TestRoundtrip.TestSpec("\n \n foo\n \n", "foo\n", "");
+ }
+
+ // Trailing spaces are included in the code block's content:
+ [Test]
+ public void LeafBlocksIndentedCodeBlocks_Example088()
+ {
+ // Example 88
+ // Section: Leaf blocks / Indented code blocks
+ //
+ // The following Markdown:
+ // foo
+ //
+ // Should be rendered as:
+ // foo
+ //
+
+ Console.WriteLine("Example 88\nSection Leaf blocks / Indented code blocks\n");
+ TestRoundtrip.TestSpec(" foo ", "foo \n", "");
+ }
+ }
+
+ [TestFixture]
+ public class TestLeafBlocksFencedCodeBlocks
+ {
+ // ## Fenced code blocks
+ //
+ // A [code fence](@) is a sequence
+ // of at least three consecutive backtick characters (`` ` ``) or
+ // tildes (`~`). (Tildes and backticks cannot be mixed.)
+ // A [fenced code block](@)
+ // begins with a code fence, indented no more than three spaces.
+ //
+ // The line with the opening code fence may optionally contain some text
+ // following the code fence; this is trimmed of leading and trailing
+ // whitespace and called the [info string](@). If the [info string] comes
+ // after a backtick fence, it may not contain any backtick
+ // characters. (The reason for this restriction is that otherwise
+ // some inline code would be incorrectly interpreted as the
+ // beginning of a fenced code block.)
+ //
+ // The content of the code block consists of all subsequent lines, until
+ // a closing [code fence] of the same type as the code block
+ // began with (backticks or tildes), and with at least as many backticks
+ // or tildes as the opening code fence. If the leading code fence is
+ // indented N spaces, then up to N spaces of indentation are removed from
+ // each line of the content (if present). (If a content line is not
+ // indented, it is preserved unchanged. If it is indented less than N
+ // spaces, all of the indentation is removed.)
+ //
+ // The closing code fence may be indented up to three spaces, and may be
+ // followed only by spaces, which are ignored. If the end of the
+ // containing block (or document) is reached and no closing code fence
+ // has been found, the code block contains all of the lines after the
+ // opening code fence until the end of the containing block (or
+ // document). (An alternative spec would require backtracking in the
+ // event that a closing code fence is not found. But this makes parsing
+ // much less efficient, and there seems to be no real down side to the
+ // behavior described here.)
+ //
+ // A fenced code block may interrupt a paragraph, and does not require
+ // a blank line either before or after.
+ //
+ // The content of a code fence is treated as literal text, not parsed
+ // as inlines. The first word of the [info string] is typically used to
+ // specify the language of the code sample, and rendered in the `class`
+ // attribute of the `code` tag. However, this spec does not mandate any
+ // particular treatment of the [info string].
+ //
+ // Here is a simple example with backticks:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example089()
+ {
+ // Example 89
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // <
+ // >
+ // ```
+ //
+ // Should be rendered as:
+ // <
+ // >
+ //
+
+ Console.WriteLine("Example 89\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("```\n<\n >\n```", "<\n >\n", "");
+ }
+
+ // With tildes:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example090()
+ {
+ // Example 90
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ~~~
+ // <
+ // >
+ // ~~~
+ //
+ // Should be rendered as:
+ // <
+ // >
+ //
+
+ Console.WriteLine("Example 90\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("~~~\n<\n >\n~~~", "<\n >\n", "");
+ }
+
+ // Fewer than three backticks is not enough:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example091()
+ {
+ // Example 91
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ``
+ // foo
+ // ``
+ //
+ // Should be rendered as:
+ // foo
foo
aaa
+ // ~~~
+ //
+
+ Console.WriteLine("Example 92\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("```\naaa\n~~~\n```", "aaa\n~~~\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example093()
+ {
+ // Example 93
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ~~~
+ // aaa
+ // ```
+ // ~~~
+ //
+ // Should be rendered as:
+ // aaa
+ // ```
+ //
+
+ Console.WriteLine("Example 93\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("~~~\naaa\n```\n~~~", "aaa\n```\n", "");
+ }
+
+ // The closing code fence must be at least as long as the opening fence:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example094()
+ {
+ // Example 94
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ````
+ // aaa
+ // ```
+ // ``````
+ //
+ // Should be rendered as:
+ // aaa
+ // ```
+ //
+
+ Console.WriteLine("Example 94\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("````\naaa\n```\n``````", "aaa\n```\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example095()
+ {
+ // Example 95
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ~~~~
+ // aaa
+ // ~~~
+ // ~~~~
+ //
+ // Should be rendered as:
+ // aaa
+ // ~~~
+ //
+
+ Console.WriteLine("Example 95\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("~~~~\naaa\n~~~\n~~~~", "aaa\n~~~\n", "");
+ }
+
+ // Unclosed code blocks are closed by the end of the document
+ // (or the enclosing [block quote][block quotes] or [list item][list items]):
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example096()
+ {
+ // Example 96
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ //
+ // Should be rendered as:
+ //
+
+ Console.WriteLine("Example 96\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("```", "", "");
+ }
+
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example097()
+ {
+ // Example 97
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // `````
+ //
+ // ```
+ // aaa
+ //
+ // Should be rendered as:
+ //
+ // ```
+ // aaa
+ //
+
+ Console.WriteLine("Example 97\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("`````\n\n```\naaa", "\n```\naaa\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example098()
+ {
+ // Example 98
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // > ```
+ // > aaa
+ //
+ // bbb
+ //
+ // Should be rendered as:
+ // + //+ //+ //aaa + //
bbb
+ + Console.WriteLine("Example 98\nSection Leaf blocks / Fenced code blocks\n"); + TestRoundtrip.TestSpec("> ```\n> aaa\n\nbbb", "\n\n\naaa\n
bbb
", ""); + } + + // A code block can have all empty lines as its content: + [Test] + public void LeafBlocksFencedCodeBlocks_Example099() + { + // Example 99 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // + // + // ``` + // + // Should be rendered as: + //
+ //
+ //
+
+ Console.WriteLine("Example 99\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("```\n\n \n```", "\n \n", "");
+ }
+
+ // A code block can be empty:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example100()
+ {
+ // Example 100
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // ```
+ //
+ // Should be rendered as:
+ //
+
+ Console.WriteLine("Example 100\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("```\n```", "", "");
+ }
+
+ // Fences can be indented. If the opening fence is indented,
+ // content lines will have equivalent opening indentation removed,
+ // if present:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example101()
+ {
+ // Example 101
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // aaa
+ // aaa
+ // ```
+ //
+ // Should be rendered as:
+ // aaa
+ // aaa
+ //
+
+ Console.WriteLine("Example 101\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec(" ```\n aaa\naaa\n```", "aaa\naaa\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example102()
+ {
+ // Example 102
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // aaa
+ // aaa
+ // aaa
+ // ```
+ //
+ // Should be rendered as:
+ // aaa
+ // aaa
+ // aaa
+ //
+
+ Console.WriteLine("Example 102\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec(" ```\naaa\n aaa\naaa\n ```", "aaa\naaa\naaa\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example103()
+ {
+ // Example 103
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // aaa
+ // aaa
+ // aaa
+ // ```
+ //
+ // Should be rendered as:
+ // aaa
+ // aaa
+ // aaa
+ //
+
+ Console.WriteLine("Example 103\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec(" ```\n aaa\n aaa\n aaa\n ```", "aaa\n aaa\naaa\n", "");
+ }
+
+ // Four spaces indentation produces an indented code block:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example104()
+ {
+ // Example 104
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // aaa
+ // ```
+ //
+ // Should be rendered as:
+ // ```
+ // aaa
+ // ```
+ //
+
+ Console.WriteLine("Example 104\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec(" ```\n aaa\n ```", "```\naaa\n```\n", "");
+ }
+
+ // Closing fences may be indented by 0-3 spaces, and their indentation
+ // need not match that of the opening fence:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example105()
+ {
+ // Example 105
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // aaa
+ // ```
+ //
+ // Should be rendered as:
+ // aaa
+ //
+
+ Console.WriteLine("Example 105\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("```\naaa\n ```", "aaa\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example106()
+ {
+ // Example 106
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // aaa
+ // ```
+ //
+ // Should be rendered as:
+ // aaa
+ //
+
+ Console.WriteLine("Example 106\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec(" ```\naaa\n ```", "aaa\n", "");
+ }
+
+ // This is not a closing fence, because it is indented 4 spaces:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example107()
+ {
+ // Example 107
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // aaa
+ // ```
+ //
+ // Should be rendered as:
+ // aaa
+ // ```
+ //
+
+ Console.WriteLine("Example 107\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("```\naaa\n ```", "aaa\n ```\n", "");
+ }
+
+ // Code fences (opening and closing) cannot contain internal spaces:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example108()
+ {
+ // Example 108
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ``` ```
+ // aaa
+ //
+ // Should be rendered as:
+ //
+ // aaa
\naaa
aaa
+ // ~~~ ~~
+ //
+
+ Console.WriteLine("Example 109\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("~~~~~~\naaa\n~~~ ~~", "aaa\n~~~ ~~\n", "");
+ }
+
+ // Fenced code blocks can interrupt paragraphs, and can be followed
+ // directly by paragraphs, without a blank line between:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example110()
+ {
+ // Example 110
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // foo
+ // ```
+ // bar
+ // ```
+ // baz
+ //
+ // Should be rendered as:
+ // foo
+ //bar
+ //
+ // baz
+ + Console.WriteLine("Example 110\nSection Leaf blocks / Fenced code blocks\n"); + TestRoundtrip.TestSpec("foo\n```\nbar\n```\nbaz", "foo
\nbar\n\nbaz
", ""); + } + + // Other blocks can also occur before and after fenced code blocks + // without an intervening blank line: + [Test] + public void LeafBlocksFencedCodeBlocks_Example111() + { + // Example 111 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // foo + // --- + // ~~~ + // bar + // ~~~ + // # baz + // + // Should be rendered as: + //bar
+ //
+ // bar\n\ndef foo(x)
+ // return 3
+ // end
+ //
+
+ Console.WriteLine("Example 112\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("```ruby\ndef foo(x)\n return 3\nend\n```", "def foo(x)\n return 3\nend\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example113()
+ {
+ // Example 113
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ~~~~ ruby startline=3 $%@#$
+ // def foo(x)
+ // return 3
+ // end
+ // ~~~~~~~
+ //
+ // Should be rendered as:
+ // def foo(x)
+ // return 3
+ // end
+ //
+
+ Console.WriteLine("Example 113\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~", "def foo(x)\n return 3\nend\n", "");
+ }
+
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example114()
+ {
+ // Example 114
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ````;
+ // ````
+ //
+ // Should be rendered as:
+ //
+
+ Console.WriteLine("Example 114\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("````;\n````", "", "");
+ }
+
+ // [Info strings] for backtick code blocks cannot contain backticks:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example115()
+ {
+ // Example 115
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ``` aa ```
+ // foo
+ //
+ // Should be rendered as:
+ // aa
+ // foo
aa\nfoo
foo
+ //
+
+ Console.WriteLine("Example 116\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("~~~ aa ``` ~~~\nfoo\n~~~", "foo\n", "");
+ }
+
+ // Closing code fences cannot have [info strings]:
+ [Test]
+ public void LeafBlocksFencedCodeBlocks_Example117()
+ {
+ // Example 117
+ // Section: Leaf blocks / Fenced code blocks
+ //
+ // The following Markdown:
+ // ```
+ // ``` aaa
+ // ```
+ //
+ // Should be rendered as:
+ // ``` aaa
+ //
+
+ Console.WriteLine("Example 117\nSection Leaf blocks / Fenced code blocks\n");
+ TestRoundtrip.TestSpec("```\n``` aaa\n```", "``` aaa\n", "");
+ }
+ }
+
+ [TestFixture]
+ public class TestLeafBlocksHTMLBlocks
+ {
+ // ## HTML blocks
+ //
+ // An [HTML block](@) is a group of lines that is treated
+ // as raw HTML (and will not be escaped in HTML output).
+ //
+ // There are seven kinds of [HTML block], which can be defined by their
+ // start and end conditions. The block begins with a line that meets a
+ // [start condition](@) (after up to three spaces optional indentation).
+ // It ends with the first subsequent line that meets a matching [end
+ // condition](@), or the last line of the document, or the last line of
+ // the [container block](#container-blocks) containing the current HTML
+ // block, if no line is encountered that meets the [end condition]. If
+ // the first line meets both the [start condition] and the [end
+ // condition], the block will contain just that line.
+ //
+ // 1. **Start condition:** line begins with the string ``, ``, or `` (case-insensitive; it
+ // need not match the start tag).
+ //
+ // 2. **Start condition:** line begins with the string ``.
+ //
+ // 3. **Start condition:** line begins with the string ``.\
+ // **End condition:** line contains the string `?>`.
+ //
+ // 4. **Start condition:** line begins with the string ``.
+ //
+ // 5. **Start condition:** line begins with the string
+ // ``.
+ //
+ // 6. **Start condition:** line begins the string `<` or ``
+ // followed by one of the strings (case-insensitive) `address`,
+ // `article`, `aside`, `base`, `basefont`, `blockquote`, `body`,
+ // `caption`, `center`, `col`, `colgroup`, `dd`, `details`, `dialog`,
+ // `dir`, `div`, `dl`, `dt`, `fieldset`, `figcaption`, `figure`,
+ // `footer`, `form`, `frame`, `frameset`,
+ // `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `head`, `header`, `hr`,
+ // `html`, `iframe`, `legend`, `li`, `link`, `main`, `menu`, `menuitem`,
+ // `nav`, `noframes`, `ol`, `optgroup`, `option`, `p`, `param`,
+ // `section`, `source`, `summary`, `table`, `tbody`, `td`,
+ // `tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, followed
+ // by [whitespace], the end of the line, the string `>`, or
+ // the string `/>`.\
+ // **End condition:** line is followed by a [blank line].
+ //
+ // 7. **Start condition:** line begins with a complete [open tag]
+ // (with any [tag name] other than `script`,
+ // `style`, or `pre`) or a complete [closing tag],
+ // followed only by [whitespace] or the end of the line.\
+ // **End condition:** line is followed by a [blank line].
+ //
+ // HTML blocks continue until they are closed by their appropriate
+ // [end condition], or the last line of the document or other [container
+ // block](#container-blocks). This means any HTML **within an HTML
+ // block** that might otherwise be recognised as a start condition will
+ // be ignored by the parser and passed through as-is, without changing
+ // the parser's state.
+ //
+ // For instance, `` within a HTML block started by `