From b76558692fe17ae05f36e8cde5cd36f52afe6cc0 Mon Sep 17 00:00:00 2001 From: mysticmnd Date: Tue, 24 Feb 2026 14:18:17 +0530 Subject: [PATCH 1/5] feat: add CommonMark mode and spec harness --- README.md | 4 + .../CommonMarkSpecTests.cs | 134 + ...sisInsideWord_ThenInsertSpaces.verified.md | 1 + src/ReverseMarkdown.Test/ConverterTests.cs | 22 +- .../ReverseMarkdown.Test.csproj | 1 + src/ReverseMarkdown.Test/TestData/README.md | 5 + .../TestData/commonmark.json | 5218 +++++++++++++++++ src/ReverseMarkdown/Config.cs | 15 + src/ReverseMarkdown/Converter.cs | 66 +- src/ReverseMarkdown/Converters/A.cs | 147 +- src/ReverseMarkdown/Converters/Br.cs | 9 +- src/ReverseMarkdown/Converters/Code.cs | 46 +- .../Converters/ConverterBase.cs | 13 +- src/ReverseMarkdown/Converters/Div.cs | 5 + src/ReverseMarkdown/Converters/Em.cs | 116 +- src/ReverseMarkdown/Converters/H.cs | 29 +- src/ReverseMarkdown/Converters/Img.cs | 6 + src/ReverseMarkdown/Converters/Li.cs | 47 +- src/ReverseMarkdown/Converters/Ol.cs | 27 +- src/ReverseMarkdown/Converters/P.cs | 30 +- src/ReverseMarkdown/Converters/Pre.cs | 59 +- src/ReverseMarkdown/Converters/S.cs | 5 + src/ReverseMarkdown/Converters/Strong.cs | 95 +- src/ReverseMarkdown/Converters/Table.cs | 5 + src/ReverseMarkdown/Converters/Text.cs | 220 +- .../Helpers/StringExtensions.cs | 19 + 26 files changed, 6284 insertions(+), 60 deletions(-) create mode 100644 src/ReverseMarkdown.Test/CommonMarkSpecTests.cs create mode 100644 src/ReverseMarkdown.Test/ConverterTests.When_CommonMark_Enabled_InlineEmphasisInsideWord_ThenInsertSpaces.verified.md create mode 100644 src/ReverseMarkdown.Test/TestData/README.md create mode 100644 src/ReverseMarkdown.Test/TestData/commonmark.json diff --git a/README.md b/README.md index 7238b7a..c7cd487 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ If you have used and benefitted from this library. Please feel free to sponsor m **Markdown flavors** - GitHub Flavoured Markdown conversion for br, pre, tasklists, and table. Use `var config = new ReverseMarkdown.Config(githubFlavoured:true);`. By default the table will always be converted to Github flavored markdown immaterial of this flag - Slack Flavoured Markdown conversion. Use `var config = new ReverseMarkdown.Config { SlackFlavored = true };` +- CommonMark-focused output with opt-in flags to preserve compatibility. Use `var config = new ReverseMarkdown.Config { CommonMark = true };` **Tables** - Support for nested tables (converted as HTML inside markdown) @@ -89,6 +90,9 @@ var converter = new ReverseMarkdown.Converter(config); * `DefaultCodeBlockLanguage` - Option to set the default code block language for Github style markdown if class based language markers are not available * `GithubFlavored` - Github style markdown for br, pre and table. Default is false * `SlackFlavored` - Slack style markdown formatting. When enabled, uses `*` for bold, `_` for italic, `~` for strikethrough, and `•` for list bullets. Default is false +* `CommonMark` - Enable CommonMark-focused output rules. Default is false +* `CommonMarkUseHtmlInlineTags` - When CommonMark is enabled, emit HTML for inline tags (`em`, `strong`, `a`, `img`) to avoid delimiter edge cases. Default is true +* `CommonMarkIntrawordEmphasisSpacing` - When CommonMark is enabled, insert spaces to avoid intraword emphasis. Default is false * `CleanupUnnecessarySpaces` - Cleanup unnecessary spaces in the output. Default is true * `SuppressDivNewlines` - Removes prefixed newlines from `div` tags. Default is false * `ListBulletChar` - Allows you to change the bullet character. Default value is `-`. Some systems expect the bullet character to be `*` rather than `-`, this config allows you to change it. Note: This option is ignored when `SlackFlavored` is enabled diff --git a/src/ReverseMarkdown.Test/CommonMarkSpecTests.cs b/src/ReverseMarkdown.Test/CommonMarkSpecTests.cs new file mode 100644 index 0000000..4841f0f --- /dev/null +++ b/src/ReverseMarkdown.Test/CommonMarkSpecTests.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using Markdig; +using Xunit; +using Xunit.Abstractions; + +namespace ReverseMarkdown.Test +{ + public class CommonMarkSpecTests + { + private readonly ITestOutputHelper _output; + + public CommonMarkSpecTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void CommonMark_Spec_Examples_RoundTripHtml() + { + var specPath = GetSpecPath(); + Assert.True( + File.Exists(specPath), + "CommonMark spec file not found. Download commonmark.json to src/ReverseMarkdown.Test/TestData/commonmark.json" + ); + + var json = File.ReadAllText(specPath); + var examples = JsonSerializer.Deserialize>( + json, + new JsonSerializerOptions { PropertyNameCaseInsensitive = true } + ); + if (examples == null || examples.Count == 0) { + throw new InvalidOperationException("CommonMark spec file is empty or invalid."); + } + + var maxExamples = GetIntEnvironmentVariable("COMMONMARK_MAX_EXAMPLES"); + var selected = maxExamples > 0 ? examples.Take(maxExamples).ToList() : examples; + + var converter = new Converter(new Config { CommonMark = true }); + var pipeline = new MarkdownPipelineBuilder().Build(); + var failures = new List(); + + foreach (var example in selected) { + if (string.IsNullOrEmpty(example.Html)) { + continue; + } + + var markdown = converter.Convert(example.Html); + var roundTripHtml = Markdown.ToHtml(markdown, pipeline); + + var expected = NormalizeHtml(example.Html); + var actual = NormalizeHtml(roundTripHtml); + + if (!string.Equals(expected, actual, StringComparison.Ordinal)) { + failures.Add(FormatFailure(example, markdown, expected, actual)); + if (failures.Count >= 10) { + break; + } + } + } + + if (failures.Count > 0) { + var message = $"CommonMark failures: {failures.Count}/{selected.Count}"; + _output.WriteLine(message); + foreach (var failure in failures) { + _output.WriteLine(failure); + } + + Assert.Fail(message); + } + } + + private static string NormalizeHtml(string html) + { + if (string.IsNullOrEmpty(html)) { + return string.Empty; + } + + var normalized = html.Replace("\r\n", "\n").TrimEnd(); + normalized = normalized.Replace("
", "
"); + normalized = normalized.Replace("
", "
"); + normalized = normalized.Replace("
", "
"); + normalized = normalized.Replace("
", "
"); + normalized = normalized.Replace(" ", "\n"); + normalized = normalized.Replace(" ", "\n"); + normalized = System.Text.RegularExpressions.Regex.Replace(normalized, @">\s+<", "><"); + + var doc = new HtmlAgilityPack.HtmlDocument(); + doc.LoadHtml(normalized); + normalized = doc.DocumentNode.InnerHtml; + normalized = normalized.Replace("\u00A0", " "); + + return normalized; + } + + private static string FormatFailure(CommonMarkExample example, string markdown, string expected, string actual) + { + return $"Example {example.Example} ({example.Section}):\n" + + $"Markdown:\n{markdown}\n" + + $"Expected HTML:\n{expected}\n" + + $"Actual HTML:\n{actual}\n"; + } + + private static int GetIntEnvironmentVariable(string name) + { + var value = Environment.GetEnvironmentVariable(name); + return int.TryParse(value, out var result) ? result : 0; + } + + private static string GetSpecPath() + { + var directory = new DirectoryInfo(AppContext.BaseDirectory); + while (directory != null && !File.Exists(Path.Combine(directory.FullName, "ReverseMarkdown.Test.csproj"))) { + directory = directory.Parent; + } + + if (directory == null) { + throw new DirectoryNotFoundException("Could not locate test project directory."); + } + + return Path.Combine(directory.FullName, "TestData", "commonmark.json"); + } + + private sealed class CommonMarkExample + { + public int Example { get; set; } + public string Section { get; set; } = string.Empty; + public string Html { get; set; } = string.Empty; + } + } +} diff --git a/src/ReverseMarkdown.Test/ConverterTests.When_CommonMark_Enabled_InlineEmphasisInsideWord_ThenInsertSpaces.verified.md b/src/ReverseMarkdown.Test/ConverterTests.When_CommonMark_Enabled_InlineEmphasisInsideWord_ThenInsertSpaces.verified.md new file mode 100644 index 0000000..130e19c --- /dev/null +++ b/src/ReverseMarkdown.Test/ConverterTests.When_CommonMark_Enabled_InlineEmphasisInsideWord_ThenInsertSpaces.verified.md @@ -0,0 +1 @@ +he **ll** o and th *in* g diff --git a/src/ReverseMarkdown.Test/ConverterTests.cs b/src/ReverseMarkdown.Test/ConverterTests.cs index 1adb7ee..ff2f5e5 100644 --- a/src/ReverseMarkdown.Test/ConverterTests.cs +++ b/src/ReverseMarkdown.Test/ConverterTests.cs @@ -289,11 +289,23 @@ public Task WhenThereIsEmTag_ThenConvertToMarkdownSingleAsterisks() } [Fact] - public Task WhenThereIsITag_ThenConvertToMarkdownSingleAsterisks() - { - var html = "This is a sample paragraph"; - return CheckConversion(html); - } + public Task WhenThereIsITag_ThenConvertToMarkdownSingleAsterisks() + { + var html = "This is a sample paragraph"; + return CheckConversion(html); + } + + [Fact] + public Task When_CommonMark_Enabled_InlineEmphasisInsideWord_ThenInsertSpaces() + { + var html = "hello and thing"; + return CheckConversion(html, new Config + { + CommonMark = true, + CommonMarkIntrawordEmphasisSpacing = true, + CommonMarkUseHtmlInlineTags = false + }); + } [Fact] public Task WhenThereIsEncompassingEmOrITag_ThenConvertToMarkdownSingleAsterisks_AnyEmOrITagsInsideAreIgnored() diff --git a/src/ReverseMarkdown.Test/ReverseMarkdown.Test.csproj b/src/ReverseMarkdown.Test/ReverseMarkdown.Test.csproj index d829d17..a7be903 100644 --- a/src/ReverseMarkdown.Test/ReverseMarkdown.Test.csproj +++ b/src/ReverseMarkdown.Test/ReverseMarkdown.Test.csproj @@ -17,6 +17,7 @@ all + diff --git a/src/ReverseMarkdown.Test/TestData/README.md b/src/ReverseMarkdown.Test/TestData/README.md new file mode 100644 index 0000000..2c76b33 --- /dev/null +++ b/src/ReverseMarkdown.Test/TestData/README.md @@ -0,0 +1,5 @@ +CommonMark test data + +Download commonmark.json from the CommonMark spec repository and save it here: + +https://raw.githubusercontent.com/commonmark/commonmark-spec/master/commonmark.json diff --git a/src/ReverseMarkdown.Test/TestData/commonmark.json b/src/ReverseMarkdown.Test/TestData/commonmark.json new file mode 100644 index 0000000..1f89e66 --- /dev/null +++ b/src/ReverseMarkdown.Test/TestData/commonmark.json @@ -0,0 +1,5218 @@ +[ + { + "markdown": "\tfoo\tbaz\t\tbim\n", + "html": "
foo\tbaz\t\tbim\n
\n", + "example": 1, + "start_line": 355, + "end_line": 360, + "section": "Tabs" + }, + { + "markdown": " \tfoo\tbaz\t\tbim\n", + "html": "
foo\tbaz\t\tbim\n
\n", + "example": 2, + "start_line": 362, + "end_line": 367, + "section": "Tabs" + }, + { + "markdown": " a\ta\n ὐ\ta\n", + "html": "
a\ta\nὐ\ta\n
\n", + "example": 3, + "start_line": 369, + "end_line": 376, + "section": "Tabs" + }, + { + "markdown": " - foo\n\n\tbar\n", + "html": "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
\n", + "example": 4, + "start_line": 382, + "end_line": 393, + "section": "Tabs" + }, + { + "markdown": "- foo\n\n\t\tbar\n", + "html": "
    \n
  • \n

    foo

    \n
      bar\n
    \n
  • \n
\n", + "example": 5, + "start_line": 395, + "end_line": 407, + "section": "Tabs" + }, + { + "markdown": ">\t\tfoo\n", + "html": "
\n
  foo\n
\n
\n", + "example": 6, + "start_line": 418, + "end_line": 425, + "section": "Tabs" + }, + { + "markdown": "-\t\tfoo\n", + "html": "
    \n
  • \n
      foo\n
    \n
  • \n
\n", + "example": 7, + "start_line": 427, + "end_line": 436, + "section": "Tabs" + }, + { + "markdown": " foo\n\tbar\n", + "html": "
foo\nbar\n
\n", + "example": 8, + "start_line": 439, + "end_line": 446, + "section": "Tabs" + }, + { + "markdown": " - foo\n - bar\n\t - baz\n", + "html": "
    \n
  • foo\n
      \n
    • bar\n
        \n
      • baz
      • \n
      \n
    • \n
    \n
  • \n
\n", + "example": 9, + "start_line": 448, + "end_line": 464, + "section": "Tabs" + }, + { + "markdown": "#\tFoo\n", + "html": "

Foo

\n", + "example": 10, + "start_line": 466, + "end_line": 470, + "section": "Tabs" + }, + { + "markdown": "*\t*\t*\t\n", + "html": "
\n", + "example": 11, + "start_line": 472, + "end_line": 476, + "section": "Tabs" + }, + { + "markdown": "\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~\n", + "html": "

!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~

\n", + "example": 12, + "start_line": 489, + "end_line": 493, + "section": "Backslash escapes" + }, + { + "markdown": "\\\t\\A\\a\\ \\3\\φ\\«\n", + "html": "

\\\t\\A\\a\\ \\3\\φ\\«

\n", + "example": 13, + "start_line": 499, + "end_line": 503, + "section": "Backslash escapes" + }, + { + "markdown": "\\*not emphasized*\n\\
not a tag\n\\[not a link](/foo)\n\\`not code`\n1\\. not a list\n\\* not a list\n\\# not a heading\n\\[foo]: /url \"not a reference\"\n\\ö not a character entity\n", + "html": "

*not emphasized*\n<br/> not a tag\n[not a link](/foo)\n`not code`\n1. not a list\n* not a list\n# not a heading\n[foo]: /url "not a reference"\n&ouml; not a character entity

\n", + "example": 14, + "start_line": 509, + "end_line": 529, + "section": "Backslash escapes" + }, + { + "markdown": "\\\\*emphasis*\n", + "html": "

\\emphasis

\n", + "example": 15, + "start_line": 534, + "end_line": 538, + "section": "Backslash escapes" + }, + { + "markdown": "foo\\\nbar\n", + "html": "

foo
\nbar

\n", + "example": 16, + "start_line": 543, + "end_line": 549, + "section": "Backslash escapes" + }, + { + "markdown": "`` \\[\\` ``\n", + "html": "

\\[\\`

\n", + "example": 17, + "start_line": 555, + "end_line": 559, + "section": "Backslash escapes" + }, + { + "markdown": " \\[\\]\n", + "html": "
\\[\\]\n
\n", + "example": 18, + "start_line": 562, + "end_line": 567, + "section": "Backslash escapes" + }, + { + "markdown": "~~~\n\\[\\]\n~~~\n", + "html": "
\\[\\]\n
\n", + "example": 19, + "start_line": 570, + "end_line": 577, + "section": "Backslash escapes" + }, + { + "markdown": "\n", + "html": "

https://example.com?find=\\*

\n", + "example": 20, + "start_line": 580, + "end_line": 584, + "section": "Backslash escapes" + }, + { + "markdown": "\n", + "html": "\n", + "example": 21, + "start_line": 587, + "end_line": 591, + "section": "Backslash escapes" + }, + { + "markdown": "[foo](/bar\\* \"ti\\*tle\")\n", + "html": "

foo

\n", + "example": 22, + "start_line": 597, + "end_line": 601, + "section": "Backslash escapes" + }, + { + "markdown": "[foo]\n\n[foo]: /bar\\* \"ti\\*tle\"\n", + "html": "

foo

\n", + "example": 23, + "start_line": 604, + "end_line": 610, + "section": "Backslash escapes" + }, + { + "markdown": "``` foo\\+bar\nfoo\n```\n", + "html": "
foo\n
\n", + "example": 24, + "start_line": 613, + "end_line": 620, + "section": "Backslash escapes" + }, + { + "markdown": "  & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸\n", + "html": "

  & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸

\n", + "example": 25, + "start_line": 649, + "end_line": 657, + "section": "Entity and numeric character references" + }, + { + "markdown": "# Ӓ Ϡ �\n", + "html": "

# Ӓ Ϡ �

\n", + "example": 26, + "start_line": 668, + "end_line": 672, + "section": "Entity and numeric character references" + }, + { + "markdown": "" ആ ಫ\n", + "html": "

" ആ ಫ

\n", + "example": 27, + "start_line": 681, + "end_line": 685, + "section": "Entity and numeric character references" + }, + { + "markdown": "  &x; &#; &#x;\n�\n&#abcdef0;\n&ThisIsNotDefined; &hi?;\n", + "html": "

&nbsp &x; &#; &#x;\n&#87654321;\n&#abcdef0;\n&ThisIsNotDefined; &hi?;

\n", + "example": 28, + "start_line": 690, + "end_line": 700, + "section": "Entity and numeric character references" + }, + { + "markdown": "©\n", + "html": "

&copy

\n", + "example": 29, + "start_line": 707, + "end_line": 711, + "section": "Entity and numeric character references" + }, + { + "markdown": "&MadeUpEntity;\n", + "html": "

&MadeUpEntity;

\n", + "example": 30, + "start_line": 717, + "end_line": 721, + "section": "Entity and numeric character references" + }, + { + "markdown": "\n", + "html": "\n", + "example": 31, + "start_line": 728, + "end_line": 732, + "section": "Entity and numeric character references" + }, + { + "markdown": "[foo](/föö \"föö\")\n", + "html": "

foo

\n", + "example": 32, + "start_line": 735, + "end_line": 739, + "section": "Entity and numeric character references" + }, + { + "markdown": "[foo]\n\n[foo]: /föö \"föö\"\n", + "html": "

foo

\n", + "example": 33, + "start_line": 742, + "end_line": 748, + "section": "Entity and numeric character references" + }, + { + "markdown": "``` föö\nfoo\n```\n", + "html": "
foo\n
\n", + "example": 34, + "start_line": 751, + "end_line": 758, + "section": "Entity and numeric character references" + }, + { + "markdown": "`föö`\n", + "html": "

f&ouml;&ouml;

\n", + "example": 35, + "start_line": 764, + "end_line": 768, + "section": "Entity and numeric character references" + }, + { + "markdown": " föfö\n", + "html": "
f&ouml;f&ouml;\n
\n", + "example": 36, + "start_line": 771, + "end_line": 776, + "section": "Entity and numeric character references" + }, + { + "markdown": "*foo*\n*foo*\n", + "html": "

*foo*\nfoo

\n", + "example": 37, + "start_line": 783, + "end_line": 789, + "section": "Entity and numeric character references" + }, + { + "markdown": "* foo\n\n* foo\n", + "html": "

* foo

\n
    \n
  • foo
  • \n
\n", + "example": 38, + "start_line": 791, + "end_line": 800, + "section": "Entity and numeric character references" + }, + { + "markdown": "foo bar\n", + "html": "

foo\n\nbar

\n", + "example": 39, + "start_line": 802, + "end_line": 808, + "section": "Entity and numeric character references" + }, + { + "markdown": " foo\n", + "html": "

\tfoo

\n", + "example": 40, + "start_line": 810, + "end_line": 814, + "section": "Entity and numeric character references" + }, + { + "markdown": "[a](url "tit")\n", + "html": "

[a](url "tit")

\n", + "example": 41, + "start_line": 817, + "end_line": 821, + "section": "Entity and numeric character references" + }, + { + "markdown": "- `one\n- two`\n", + "html": "
    \n
  • `one
  • \n
  • two`
  • \n
\n", + "example": 42, + "start_line": 840, + "end_line": 848, + "section": "Precedence" + }, + { + "markdown": "***\n---\n___\n", + "html": "
\n
\n
\n", + "example": 43, + "start_line": 879, + "end_line": 887, + "section": "Thematic breaks" + }, + { + "markdown": "+++\n", + "html": "

+++

\n", + "example": 44, + "start_line": 892, + "end_line": 896, + "section": "Thematic breaks" + }, + { + "markdown": "===\n", + "html": "

===

\n", + "example": 45, + "start_line": 899, + "end_line": 903, + "section": "Thematic breaks" + }, + { + "markdown": "--\n**\n__\n", + "html": "

--\n**\n__

\n", + "example": 46, + "start_line": 908, + "end_line": 916, + "section": "Thematic breaks" + }, + { + "markdown": " ***\n ***\n ***\n", + "html": "
\n
\n
\n", + "example": 47, + "start_line": 921, + "end_line": 929, + "section": "Thematic breaks" + }, + { + "markdown": " ***\n", + "html": "
***\n
\n", + "example": 48, + "start_line": 934, + "end_line": 939, + "section": "Thematic breaks" + }, + { + "markdown": "Foo\n ***\n", + "html": "

Foo\n***

\n", + "example": 49, + "start_line": 942, + "end_line": 948, + "section": "Thematic breaks" + }, + { + "markdown": "_____________________________________\n", + "html": "
\n", + "example": 50, + "start_line": 953, + "end_line": 957, + "section": "Thematic breaks" + }, + { + "markdown": " - - -\n", + "html": "
\n", + "example": 51, + "start_line": 962, + "end_line": 966, + "section": "Thematic breaks" + }, + { + "markdown": " ** * ** * ** * **\n", + "html": "
\n", + "example": 52, + "start_line": 969, + "end_line": 973, + "section": "Thematic breaks" + }, + { + "markdown": "- - - -\n", + "html": "
\n", + "example": 53, + "start_line": 976, + "end_line": 980, + "section": "Thematic breaks" + }, + { + "markdown": "- - - - \n", + "html": "
\n", + "example": 54, + "start_line": 985, + "end_line": 989, + "section": "Thematic breaks" + }, + { + "markdown": "_ _ _ _ a\n\na------\n\n---a---\n", + "html": "

_ _ _ _ a

\n

a------

\n

---a---

\n", + "example": 55, + "start_line": 994, + "end_line": 1004, + "section": "Thematic breaks" + }, + { + "markdown": " *-*\n", + "html": "

-

\n", + "example": 56, + "start_line": 1010, + "end_line": 1014, + "section": "Thematic breaks" + }, + { + "markdown": "- foo\n***\n- bar\n", + "html": "
    \n
  • foo
  • \n
\n
\n
    \n
  • bar
  • \n
\n", + "example": 57, + "start_line": 1019, + "end_line": 1031, + "section": "Thematic breaks" + }, + { + "markdown": "Foo\n***\nbar\n", + "html": "

Foo

\n
\n

bar

\n", + "example": 58, + "start_line": 1036, + "end_line": 1044, + "section": "Thematic breaks" + }, + { + "markdown": "Foo\n---\nbar\n", + "html": "

Foo

\n

bar

\n", + "example": 59, + "start_line": 1053, + "end_line": 1060, + "section": "Thematic breaks" + }, + { + "markdown": "* Foo\n* * *\n* Bar\n", + "html": "
    \n
  • Foo
  • \n
\n
\n
    \n
  • Bar
  • \n
\n", + "example": 60, + "start_line": 1066, + "end_line": 1078, + "section": "Thematic breaks" + }, + { + "markdown": "- Foo\n- * * *\n", + "html": "
    \n
  • Foo
  • \n
  • \n
    \n
  • \n
\n", + "example": 61, + "start_line": 1083, + "end_line": 1093, + "section": "Thematic breaks" + }, + { + "markdown": "# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n", + "html": "

foo

\n

foo

\n

foo

\n

foo

\n
foo
\n
foo
\n", + "example": 62, + "start_line": 1112, + "end_line": 1126, + "section": "ATX headings" + }, + { + "markdown": "####### foo\n", + "html": "

####### foo

\n", + "example": 63, + "start_line": 1131, + "end_line": 1135, + "section": "ATX headings" + }, + { + "markdown": "#5 bolt\n\n#hashtag\n", + "html": "

#5 bolt

\n

#hashtag

\n", + "example": 64, + "start_line": 1146, + "end_line": 1153, + "section": "ATX headings" + }, + { + "markdown": "\\## foo\n", + "html": "

## foo

\n", + "example": 65, + "start_line": 1158, + "end_line": 1162, + "section": "ATX headings" + }, + { + "markdown": "# foo *bar* \\*baz\\*\n", + "html": "

foo bar *baz*

\n", + "example": 66, + "start_line": 1167, + "end_line": 1171, + "section": "ATX headings" + }, + { + "markdown": "# foo \n", + "html": "

foo

\n", + "example": 67, + "start_line": 1176, + "end_line": 1180, + "section": "ATX headings" + }, + { + "markdown": " ### foo\n ## foo\n # foo\n", + "html": "

foo

\n

foo

\n

foo

\n", + "example": 68, + "start_line": 1185, + "end_line": 1193, + "section": "ATX headings" + }, + { + "markdown": " # foo\n", + "html": "
# foo\n
\n", + "example": 69, + "start_line": 1198, + "end_line": 1203, + "section": "ATX headings" + }, + { + "markdown": "foo\n # bar\n", + "html": "

foo\n# bar

\n", + "example": 70, + "start_line": 1206, + "end_line": 1212, + "section": "ATX headings" + }, + { + "markdown": "## foo ##\n ### bar ###\n", + "html": "

foo

\n

bar

\n", + "example": 71, + "start_line": 1217, + "end_line": 1223, + "section": "ATX headings" + }, + { + "markdown": "# foo ##################################\n##### foo ##\n", + "html": "

foo

\n
foo
\n", + "example": 72, + "start_line": 1228, + "end_line": 1234, + "section": "ATX headings" + }, + { + "markdown": "### foo ### \n", + "html": "

foo

\n", + "example": 73, + "start_line": 1239, + "end_line": 1243, + "section": "ATX headings" + }, + { + "markdown": "### foo ### b\n", + "html": "

foo ### b

\n", + "example": 74, + "start_line": 1250, + "end_line": 1254, + "section": "ATX headings" + }, + { + "markdown": "# foo#\n", + "html": "

foo#

\n", + "example": 75, + "start_line": 1259, + "end_line": 1263, + "section": "ATX headings" + }, + { + "markdown": "### foo \\###\n## foo #\\##\n# foo \\#\n", + "html": "

foo ###

\n

foo ###

\n

foo #

\n", + "example": 76, + "start_line": 1269, + "end_line": 1277, + "section": "ATX headings" + }, + { + "markdown": "****\n## foo\n****\n", + "html": "
\n

foo

\n
\n", + "example": 77, + "start_line": 1283, + "end_line": 1291, + "section": "ATX headings" + }, + { + "markdown": "Foo bar\n# baz\nBar foo\n", + "html": "

Foo bar

\n

baz

\n

Bar foo

\n", + "example": 78, + "start_line": 1294, + "end_line": 1302, + "section": "ATX headings" + }, + { + "markdown": "## \n#\n### ###\n", + "html": "

\n

\n

\n", + "example": 79, + "start_line": 1307, + "end_line": 1315, + "section": "ATX headings" + }, + { + "markdown": "Foo *bar*\n=========\n\nFoo *bar*\n---------\n", + "html": "

Foo bar

\n

Foo bar

\n", + "example": 80, + "start_line": 1347, + "end_line": 1356, + "section": "Setext headings" + }, + { + "markdown": "Foo *bar\nbaz*\n====\n", + "html": "

Foo bar\nbaz

\n", + "example": 81, + "start_line": 1361, + "end_line": 1368, + "section": "Setext headings" + }, + { + "markdown": " Foo *bar\nbaz*\t\n====\n", + "html": "

Foo bar\nbaz

\n", + "example": 82, + "start_line": 1375, + "end_line": 1382, + "section": "Setext headings" + }, + { + "markdown": "Foo\n-------------------------\n\nFoo\n=\n", + "html": "

Foo

\n

Foo

\n", + "example": 83, + "start_line": 1387, + "end_line": 1396, + "section": "Setext headings" + }, + { + "markdown": " Foo\n---\n\n Foo\n-----\n\n Foo\n ===\n", + "html": "

Foo

\n

Foo

\n

Foo

\n", + "example": 84, + "start_line": 1402, + "end_line": 1415, + "section": "Setext headings" + }, + { + "markdown": " Foo\n ---\n\n Foo\n---\n", + "html": "
Foo\n---\n\nFoo\n
\n
\n", + "example": 85, + "start_line": 1420, + "end_line": 1433, + "section": "Setext headings" + }, + { + "markdown": "Foo\n ---- \n", + "html": "

Foo

\n", + "example": 86, + "start_line": 1439, + "end_line": 1444, + "section": "Setext headings" + }, + { + "markdown": "Foo\n ---\n", + "html": "

Foo\n---

\n", + "example": 87, + "start_line": 1449, + "end_line": 1455, + "section": "Setext headings" + }, + { + "markdown": "Foo\n= =\n\nFoo\n--- -\n", + "html": "

Foo\n= =

\n

Foo

\n
\n", + "example": 88, + "start_line": 1460, + "end_line": 1471, + "section": "Setext headings" + }, + { + "markdown": "Foo \n-----\n", + "html": "

Foo

\n", + "example": 89, + "start_line": 1476, + "end_line": 1481, + "section": "Setext headings" + }, + { + "markdown": "Foo\\\n----\n", + "html": "

Foo\\

\n", + "example": 90, + "start_line": 1486, + "end_line": 1491, + "section": "Setext headings" + }, + { + "markdown": "`Foo\n----\n`\n\n\n", + "html": "

`Foo

\n

`

\n

<a title="a lot

\n

of dashes"/>

\n", + "example": 91, + "start_line": 1497, + "end_line": 1510, + "section": "Setext headings" + }, + { + "markdown": "> Foo\n---\n", + "html": "
\n

Foo

\n
\n
\n", + "example": 92, + "start_line": 1516, + "end_line": 1524, + "section": "Setext headings" + }, + { + "markdown": "> foo\nbar\n===\n", + "html": "
\n

foo\nbar\n===

\n
\n", + "example": 93, + "start_line": 1527, + "end_line": 1537, + "section": "Setext headings" + }, + { + "markdown": "- Foo\n---\n", + "html": "
    \n
  • Foo
  • \n
\n
\n", + "example": 94, + "start_line": 1540, + "end_line": 1548, + "section": "Setext headings" + }, + { + "markdown": "Foo\nBar\n---\n", + "html": "

Foo\nBar

\n", + "example": 95, + "start_line": 1555, + "end_line": 1562, + "section": "Setext headings" + }, + { + "markdown": "---\nFoo\n---\nBar\n---\nBaz\n", + "html": "
\n

Foo

\n

Bar

\n

Baz

\n", + "example": 96, + "start_line": 1568, + "end_line": 1580, + "section": "Setext headings" + }, + { + "markdown": "\n====\n", + "html": "

====

\n", + "example": 97, + "start_line": 1585, + "end_line": 1590, + "section": "Setext headings" + }, + { + "markdown": "---\n---\n", + "html": "
\n
\n", + "example": 98, + "start_line": 1597, + "end_line": 1603, + "section": "Setext headings" + }, + { + "markdown": "- foo\n-----\n", + "html": "
    \n
  • foo
  • \n
\n
\n", + "example": 99, + "start_line": 1606, + "end_line": 1614, + "section": "Setext headings" + }, + { + "markdown": " foo\n---\n", + "html": "
foo\n
\n
\n", + "example": 100, + "start_line": 1617, + "end_line": 1624, + "section": "Setext headings" + }, + { + "markdown": "> foo\n-----\n", + "html": "
\n

foo

\n
\n
\n", + "example": 101, + "start_line": 1627, + "end_line": 1635, + "section": "Setext headings" + }, + { + "markdown": "\\> foo\n------\n", + "html": "

> foo

\n", + "example": 102, + "start_line": 1641, + "end_line": 1646, + "section": "Setext headings" + }, + { + "markdown": "Foo\n\nbar\n---\nbaz\n", + "html": "

Foo

\n

bar

\n

baz

\n", + "example": 103, + "start_line": 1672, + "end_line": 1682, + "section": "Setext headings" + }, + { + "markdown": "Foo\nbar\n\n---\n\nbaz\n", + "html": "

Foo\nbar

\n
\n

baz

\n", + "example": 104, + "start_line": 1688, + "end_line": 1700, + "section": "Setext headings" + }, + { + "markdown": "Foo\nbar\n* * *\nbaz\n", + "html": "

Foo\nbar

\n
\n

baz

\n", + "example": 105, + "start_line": 1706, + "end_line": 1716, + "section": "Setext headings" + }, + { + "markdown": "Foo\nbar\n\\---\nbaz\n", + "html": "

Foo\nbar\n---\nbaz

\n", + "example": 106, + "start_line": 1721, + "end_line": 1731, + "section": "Setext headings" + }, + { + "markdown": " a simple\n indented code block\n", + "html": "
a simple\n  indented code block\n
\n", + "example": 107, + "start_line": 1749, + "end_line": 1756, + "section": "Indented code blocks" + }, + { + "markdown": " - foo\n\n bar\n", + "html": "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
\n", + "example": 108, + "start_line": 1763, + "end_line": 1774, + "section": "Indented code blocks" + }, + { + "markdown": "1. foo\n\n - bar\n", + "html": "
    \n
  1. \n

    foo

    \n
      \n
    • bar
    • \n
    \n
  2. \n
\n", + "example": 109, + "start_line": 1777, + "end_line": 1790, + "section": "Indented code blocks" + }, + { + "markdown": "
\n *hi*\n\n - one\n", + "html": "
<a/>\n*hi*\n\n- one\n
\n", + "example": 110, + "start_line": 1797, + "end_line": 1808, + "section": "Indented code blocks" + }, + { + "markdown": " chunk1\n\n chunk2\n \n \n \n chunk3\n", + "html": "
chunk1\n\nchunk2\n\n\n\nchunk3\n
\n", + "example": 111, + "start_line": 1813, + "end_line": 1830, + "section": "Indented code blocks" + }, + { + "markdown": " chunk1\n \n chunk2\n", + "html": "
chunk1\n  \n  chunk2\n
\n", + "example": 112, + "start_line": 1836, + "end_line": 1845, + "section": "Indented code blocks" + }, + { + "markdown": "Foo\n bar\n\n", + "html": "

Foo\nbar

\n", + "example": 113, + "start_line": 1851, + "end_line": 1858, + "section": "Indented code blocks" + }, + { + "markdown": " foo\nbar\n", + "html": "
foo\n
\n

bar

\n", + "example": 114, + "start_line": 1865, + "end_line": 1872, + "section": "Indented code blocks" + }, + { + "markdown": "# Heading\n foo\nHeading\n------\n foo\n----\n", + "html": "

Heading

\n
foo\n
\n

Heading

\n
foo\n
\n
\n", + "example": 115, + "start_line": 1878, + "end_line": 1893, + "section": "Indented code blocks" + }, + { + "markdown": " foo\n bar\n", + "html": "
    foo\nbar\n
\n", + "example": 116, + "start_line": 1898, + "end_line": 1905, + "section": "Indented code blocks" + }, + { + "markdown": "\n \n foo\n \n\n", + "html": "
foo\n
\n", + "example": 117, + "start_line": 1911, + "end_line": 1920, + "section": "Indented code blocks" + }, + { + "markdown": " foo \n", + "html": "
foo  \n
\n", + "example": 118, + "start_line": 1925, + "end_line": 1930, + "section": "Indented code blocks" + }, + { + "markdown": "```\n<\n >\n```\n", + "html": "
<\n >\n
\n", + "example": 119, + "start_line": 1980, + "end_line": 1989, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~\n<\n >\n~~~\n", + "html": "
<\n >\n
\n", + "example": 120, + "start_line": 1994, + "end_line": 2003, + "section": "Fenced code blocks" + }, + { + "markdown": "``\nfoo\n``\n", + "html": "

foo

\n", + "example": 121, + "start_line": 2007, + "end_line": 2013, + "section": "Fenced code blocks" + }, + { + "markdown": "```\naaa\n~~~\n```\n", + "html": "
aaa\n~~~\n
\n", + "example": 122, + "start_line": 2018, + "end_line": 2027, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~\naaa\n```\n~~~\n", + "html": "
aaa\n```\n
\n", + "example": 123, + "start_line": 2030, + "end_line": 2039, + "section": "Fenced code blocks" + }, + { + "markdown": "````\naaa\n```\n``````\n", + "html": "
aaa\n```\n
\n", + "example": 124, + "start_line": 2044, + "end_line": 2053, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~~\naaa\n~~~\n~~~~\n", + "html": "
aaa\n~~~\n
\n", + "example": 125, + "start_line": 2056, + "end_line": 2065, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n", + "html": "
\n", + "example": 126, + "start_line": 2071, + "end_line": 2075, + "section": "Fenced code blocks" + }, + { + "markdown": "`````\n\n```\naaa\n", + "html": "
\n```\naaa\n
\n", + "example": 127, + "start_line": 2078, + "end_line": 2088, + "section": "Fenced code blocks" + }, + { + "markdown": "> ```\n> aaa\n\nbbb\n", + "html": "
\n
aaa\n
\n
\n

bbb

\n", + "example": 128, + "start_line": 2091, + "end_line": 2102, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n\n \n```\n", + "html": "
\n  \n
\n", + "example": 129, + "start_line": 2107, + "end_line": 2116, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n```\n", + "html": "
\n", + "example": 130, + "start_line": 2121, + "end_line": 2126, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\n aaa\naaa\n```\n", + "html": "
aaa\naaa\n
\n", + "example": 131, + "start_line": 2133, + "end_line": 2142, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\naaa\n aaa\naaa\n ```\n", + "html": "
aaa\naaa\naaa\n
\n", + "example": 132, + "start_line": 2145, + "end_line": 2156, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\n aaa\n aaa\n aaa\n ```\n", + "html": "
aaa\n aaa\naaa\n
\n", + "example": 133, + "start_line": 2159, + "end_line": 2170, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\n aaa\n ```\n", + "html": "
```\naaa\n```\n
\n", + "example": 134, + "start_line": 2175, + "end_line": 2184, + "section": "Fenced code blocks" + }, + { + "markdown": "```\naaa\n ```\n", + "html": "
aaa\n
\n", + "example": 135, + "start_line": 2190, + "end_line": 2197, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\naaa\n ```\n", + "html": "
aaa\n
\n", + "example": 136, + "start_line": 2200, + "end_line": 2207, + "section": "Fenced code blocks" + }, + { + "markdown": "```\naaa\n ```\n", + "html": "
aaa\n    ```\n
\n", + "example": 137, + "start_line": 2212, + "end_line": 2220, + "section": "Fenced code blocks" + }, + { + "markdown": "``` ```\naaa\n", + "html": "

\naaa

\n", + "example": 138, + "start_line": 2226, + "end_line": 2232, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~~~~\naaa\n~~~ ~~\n", + "html": "
aaa\n~~~ ~~\n
\n", + "example": 139, + "start_line": 2235, + "end_line": 2243, + "section": "Fenced code blocks" + }, + { + "markdown": "foo\n```\nbar\n```\nbaz\n", + "html": "

foo

\n
bar\n
\n

baz

\n", + "example": 140, + "start_line": 2249, + "end_line": 2260, + "section": "Fenced code blocks" + }, + { + "markdown": "foo\n---\n~~~\nbar\n~~~\n# baz\n", + "html": "

foo

\n
bar\n
\n

baz

\n", + "example": 141, + "start_line": 2266, + "end_line": 2278, + "section": "Fenced code blocks" + }, + { + "markdown": "```ruby\ndef foo(x)\n return 3\nend\n```\n", + "html": "
def foo(x)\n  return 3\nend\n
\n", + "example": 142, + "start_line": 2288, + "end_line": 2299, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~\n", + "html": "
def foo(x)\n  return 3\nend\n
\n", + "example": 143, + "start_line": 2302, + "end_line": 2313, + "section": "Fenced code blocks" + }, + { + "markdown": "````;\n````\n", + "html": "
\n", + "example": 144, + "start_line": 2316, + "end_line": 2321, + "section": "Fenced code blocks" + }, + { + "markdown": "``` aa ```\nfoo\n", + "html": "

aa\nfoo

\n", + "example": 145, + "start_line": 2326, + "end_line": 2332, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~ aa ``` ~~~\nfoo\n~~~\n", + "html": "
foo\n
\n", + "example": 146, + "start_line": 2337, + "end_line": 2344, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n``` aaa\n```\n", + "html": "
``` aaa\n
\n", + "example": 147, + "start_line": 2349, + "end_line": 2356, + "section": "Fenced code blocks" + }, + { + "markdown": "
\n
\n**Hello**,\n\n_world_.\n
\n
\n", + "html": "
\n
\n**Hello**,\n

world.\n

\n
\n", + "example": 148, + "start_line": 2428, + "end_line": 2443, + "section": "HTML blocks" + }, + { + "markdown": "\n \n \n \n
\n hi\n
\n\nokay.\n", + "html": "\n \n \n \n
\n hi\n
\n

okay.

\n", + "example": 149, + "start_line": 2457, + "end_line": 2476, + "section": "HTML blocks" + }, + { + "markdown": "
\n*foo*\n", + "example": 151, + "start_line": 2492, + "end_line": 2498, + "section": "HTML blocks" + }, + { + "markdown": "
\n\n*Markdown*\n\n
\n", + "html": "
\n

Markdown

\n
\n", + "example": 152, + "start_line": 2503, + "end_line": 2513, + "section": "HTML blocks" + }, + { + "markdown": "
\n
\n", + "html": "
\n
\n", + "example": 153, + "start_line": 2519, + "end_line": 2527, + "section": "HTML blocks" + }, + { + "markdown": "
\n
\n", + "html": "
\n
\n", + "example": 154, + "start_line": 2530, + "end_line": 2538, + "section": "HTML blocks" + }, + { + "markdown": "
\n*foo*\n\n*bar*\n", + "html": "
\n*foo*\n

bar

\n", + "example": 155, + "start_line": 2542, + "end_line": 2551, + "section": "HTML blocks" + }, + { + "markdown": "
\n", + "html": "\n", + "example": 159, + "start_line": 2591, + "end_line": 2595, + "section": "HTML blocks" + }, + { + "markdown": "
\nfoo\n
\n", + "html": "
\nfoo\n
\n", + "example": 160, + "start_line": 2598, + "end_line": 2606, + "section": "HTML blocks" + }, + { + "markdown": "
\n``` c\nint x = 33;\n```\n", + "html": "
\n``` c\nint x = 33;\n```\n", + "example": 161, + "start_line": 2615, + "end_line": 2625, + "section": "HTML blocks" + }, + { + "markdown": "\n*bar*\n\n", + "html": "\n*bar*\n\n", + "example": 162, + "start_line": 2632, + "end_line": 2640, + "section": "HTML blocks" + }, + { + "markdown": "\n*bar*\n\n", + "html": "\n*bar*\n\n", + "example": 163, + "start_line": 2645, + "end_line": 2653, + "section": "HTML blocks" + }, + { + "markdown": "\n*bar*\n\n", + "html": "\n*bar*\n\n", + "example": 164, + "start_line": 2656, + "end_line": 2664, + "section": "HTML blocks" + }, + { + "markdown": "\n*bar*\n", + "html": "\n*bar*\n", + "example": 165, + "start_line": 2667, + "end_line": 2673, + "section": "HTML blocks" + }, + { + "markdown": "\n*foo*\n\n", + "html": "\n*foo*\n\n", + "example": 166, + "start_line": 2682, + "end_line": 2690, + "section": "HTML blocks" + }, + { + "markdown": "\n\n*foo*\n\n\n", + "html": "\n

foo

\n
\n", + "example": 167, + "start_line": 2697, + "end_line": 2707, + "section": "HTML blocks" + }, + { + "markdown": "*foo*\n", + "html": "

foo

\n", + "example": 168, + "start_line": 2715, + "end_line": 2719, + "section": "HTML blocks" + }, + { + "markdown": "
\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n
\nokay\n", + "html": "
\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n
\n

okay

\n", + "example": 169, + "start_line": 2731, + "end_line": 2747, + "section": "HTML blocks" + }, + { + "markdown": "\nokay\n", + "html": "\n

okay

\n", + "example": 170, + "start_line": 2752, + "end_line": 2766, + "section": "HTML blocks" + }, + { + "markdown": "\n", + "html": "\n", + "example": 171, + "start_line": 2771, + "end_line": 2787, + "section": "HTML blocks" + }, + { + "markdown": "\nh1 {color:red;}\n\np {color:blue;}\n\nokay\n", + "html": "\nh1 {color:red;}\n\np {color:blue;}\n\n

okay

\n", + "example": 172, + "start_line": 2791, + "end_line": 2807, + "section": "HTML blocks" + }, + { + "markdown": "\n\nfoo\n", + "html": "\n\nfoo\n", + "example": 173, + "start_line": 2814, + "end_line": 2824, + "section": "HTML blocks" + }, + { + "markdown": ">
\n> foo\n\nbar\n", + "html": "
\n
\nfoo\n
\n

bar

\n", + "example": 174, + "start_line": 2827, + "end_line": 2838, + "section": "HTML blocks" + }, + { + "markdown": "-
\n- foo\n", + "html": "
    \n
  • \n
    \n
  • \n
  • foo
  • \n
\n", + "example": 175, + "start_line": 2841, + "end_line": 2851, + "section": "HTML blocks" + }, + { + "markdown": "\n*foo*\n", + "html": "\n

foo

\n", + "example": 176, + "start_line": 2856, + "end_line": 2862, + "section": "HTML blocks" + }, + { + "markdown": "*bar*\n*baz*\n", + "html": "*bar*\n

baz

\n", + "example": 177, + "start_line": 2865, + "end_line": 2871, + "section": "HTML blocks" + }, + { + "markdown": "1. *bar*\n", + "html": "1. *bar*\n", + "example": 178, + "start_line": 2877, + "end_line": 2885, + "section": "HTML blocks" + }, + { + "markdown": "\nokay\n", + "html": "\n

okay

\n", + "example": 179, + "start_line": 2890, + "end_line": 2902, + "section": "HTML blocks" + }, + { + "markdown": "';\n\n?>\nokay\n", + "html": "';\n\n?>\n

okay

\n", + "example": 180, + "start_line": 2908, + "end_line": 2922, + "section": "HTML blocks" + }, + { + "markdown": "\n", + "html": "\n", + "example": 181, + "start_line": 2927, + "end_line": 2931, + "section": "HTML blocks" + }, + { + "markdown": "\nokay\n", + "html": "\n

okay

\n", + "example": 182, + "start_line": 2936, + "end_line": 2964, + "section": "HTML blocks" + }, + { + "markdown": " \n\n \n", + "html": " \n
<!-- foo -->\n
\n", + "example": 183, + "start_line": 2970, + "end_line": 2978, + "section": "HTML blocks" + }, + { + "markdown": "
\n\n
\n", + "html": "
\n
<div>\n
\n", + "example": 184, + "start_line": 2981, + "end_line": 2989, + "section": "HTML blocks" + }, + { + "markdown": "Foo\n
\nbar\n
\n", + "html": "

Foo

\n
\nbar\n
\n", + "example": 185, + "start_line": 2995, + "end_line": 3005, + "section": "HTML blocks" + }, + { + "markdown": "
\nbar\n
\n*foo*\n", + "html": "
\nbar\n
\n*foo*\n", + "example": 186, + "start_line": 3012, + "end_line": 3022, + "section": "HTML blocks" + }, + { + "markdown": "Foo\n\nbaz\n", + "html": "

Foo\n\nbaz

\n", + "example": 187, + "start_line": 3027, + "end_line": 3035, + "section": "HTML blocks" + }, + { + "markdown": "
\n\n*Emphasized* text.\n\n
\n", + "html": "
\n

Emphasized text.

\n
\n", + "example": 188, + "start_line": 3068, + "end_line": 3078, + "section": "HTML blocks" + }, + { + "markdown": "
\n*Emphasized* text.\n
\n", + "html": "
\n*Emphasized* text.\n
\n", + "example": 189, + "start_line": 3081, + "end_line": 3089, + "section": "HTML blocks" + }, + { + "markdown": "\n\n\n\n\n\n\n\n
\nHi\n
\n", + "html": "\n\n\n\n
\nHi\n
\n", + "example": 190, + "start_line": 3103, + "end_line": 3123, + "section": "HTML blocks" + }, + { + "markdown": "\n\n \n\n \n\n \n\n
\n Hi\n
\n", + "html": "\n \n
<td>\n  Hi\n</td>\n
\n \n
\n", + "example": 191, + "start_line": 3130, + "end_line": 3151, + "section": "HTML blocks" + }, + { + "markdown": "[foo]: /url \"title\"\n\n[foo]\n", + "html": "

foo

\n", + "example": 192, + "start_line": 3179, + "end_line": 3185, + "section": "Link reference definitions" + }, + { + "markdown": " [foo]: \n /url \n 'the title' \n\n[foo]\n", + "html": "

foo

\n", + "example": 193, + "start_line": 3188, + "end_line": 3196, + "section": "Link reference definitions" + }, + { + "markdown": "[Foo*bar\\]]:my_(url) 'title (with parens)'\n\n[Foo*bar\\]]\n", + "html": "

Foo*bar]

\n", + "example": 194, + "start_line": 3199, + "end_line": 3205, + "section": "Link reference definitions" + }, + { + "markdown": "[Foo bar]:\n\n'title'\n\n[Foo bar]\n", + "html": "

Foo bar

\n", + "example": 195, + "start_line": 3208, + "end_line": 3216, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url '\ntitle\nline1\nline2\n'\n\n[foo]\n", + "html": "

foo

\n", + "example": 196, + "start_line": 3221, + "end_line": 3235, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url 'title\n\nwith blank line'\n\n[foo]\n", + "html": "

[foo]: /url 'title

\n

with blank line'

\n

[foo]

\n", + "example": 197, + "start_line": 3240, + "end_line": 3250, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]:\n/url\n\n[foo]\n", + "html": "

foo

\n", + "example": 198, + "start_line": 3255, + "end_line": 3262, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]:\n\n[foo]\n", + "html": "

[foo]:

\n

[foo]

\n", + "example": 199, + "start_line": 3267, + "end_line": 3274, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: <>\n\n[foo]\n", + "html": "

foo

\n", + "example": 200, + "start_line": 3279, + "end_line": 3285, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: (baz)\n\n[foo]\n", + "html": "

[foo]: (baz)

\n

[foo]

\n", + "example": 201, + "start_line": 3290, + "end_line": 3297, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\\bar\\*baz \"foo\\\"bar\\baz\"\n\n[foo]\n", + "html": "

foo

\n", + "example": 202, + "start_line": 3303, + "end_line": 3309, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]\n\n[foo]: url\n", + "html": "

foo

\n", + "example": 203, + "start_line": 3314, + "end_line": 3320, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]\n\n[foo]: first\n[foo]: second\n", + "html": "

foo

\n", + "example": 204, + "start_line": 3326, + "end_line": 3333, + "section": "Link reference definitions" + }, + { + "markdown": "[FOO]: /url\n\n[Foo]\n", + "html": "

Foo

\n", + "example": 205, + "start_line": 3339, + "end_line": 3345, + "section": "Link reference definitions" + }, + { + "markdown": "[ΑΓΩ]: /φου\n\n[αγω]\n", + "html": "

αγω

\n", + "example": 206, + "start_line": 3348, + "end_line": 3354, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n", + "html": "", + "example": 207, + "start_line": 3363, + "end_line": 3366, + "section": "Link reference definitions" + }, + { + "markdown": "[\nfoo\n]: /url\nbar\n", + "html": "

bar

\n", + "example": 208, + "start_line": 3371, + "end_line": 3378, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url \"title\" ok\n", + "html": "

[foo]: /url "title" ok

\n", + "example": 209, + "start_line": 3384, + "end_line": 3388, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n\"title\" ok\n", + "html": "

"title" ok

\n", + "example": 210, + "start_line": 3393, + "end_line": 3398, + "section": "Link reference definitions" + }, + { + "markdown": " [foo]: /url \"title\"\n\n[foo]\n", + "html": "
[foo]: /url "title"\n
\n

[foo]

\n", + "example": 211, + "start_line": 3404, + "end_line": 3412, + "section": "Link reference definitions" + }, + { + "markdown": "```\n[foo]: /url\n```\n\n[foo]\n", + "html": "
[foo]: /url\n
\n

[foo]

\n", + "example": 212, + "start_line": 3418, + "end_line": 3428, + "section": "Link reference definitions" + }, + { + "markdown": "Foo\n[bar]: /baz\n\n[bar]\n", + "html": "

Foo\n[bar]: /baz

\n

[bar]

\n", + "example": 213, + "start_line": 3433, + "end_line": 3442, + "section": "Link reference definitions" + }, + { + "markdown": "# [Foo]\n[foo]: /url\n> bar\n", + "html": "

Foo

\n
\n

bar

\n
\n", + "example": 214, + "start_line": 3448, + "end_line": 3457, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\nbar\n===\n[foo]\n", + "html": "

bar

\n

foo

\n", + "example": 215, + "start_line": 3459, + "end_line": 3467, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n===\n[foo]\n", + "html": "

===\nfoo

\n", + "example": 216, + "start_line": 3469, + "end_line": 3476, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /foo-url \"foo\"\n[bar]: /bar-url\n \"bar\"\n[baz]: /baz-url\n\n[foo],\n[bar],\n[baz]\n", + "html": "

foo,\nbar,\nbaz

\n", + "example": 217, + "start_line": 3482, + "end_line": 3495, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]\n\n> [foo]: /url\n", + "html": "

foo

\n
\n
\n", + "example": 218, + "start_line": 3503, + "end_line": 3511, + "section": "Link reference definitions" + }, + { + "markdown": "aaa\n\nbbb\n", + "html": "

aaa

\n

bbb

\n", + "example": 219, + "start_line": 3525, + "end_line": 3532, + "section": "Paragraphs" + }, + { + "markdown": "aaa\nbbb\n\nccc\nddd\n", + "html": "

aaa\nbbb

\n

ccc\nddd

\n", + "example": 220, + "start_line": 3537, + "end_line": 3548, + "section": "Paragraphs" + }, + { + "markdown": "aaa\n\n\nbbb\n", + "html": "

aaa

\n

bbb

\n", + "example": 221, + "start_line": 3553, + "end_line": 3561, + "section": "Paragraphs" + }, + { + "markdown": " aaa\n bbb\n", + "html": "

aaa\nbbb

\n", + "example": 222, + "start_line": 3566, + "end_line": 3572, + "section": "Paragraphs" + }, + { + "markdown": "aaa\n bbb\n ccc\n", + "html": "

aaa\nbbb\nccc

\n", + "example": 223, + "start_line": 3578, + "end_line": 3586, + "section": "Paragraphs" + }, + { + "markdown": " aaa\nbbb\n", + "html": "

aaa\nbbb

\n", + "example": 224, + "start_line": 3592, + "end_line": 3598, + "section": "Paragraphs" + }, + { + "markdown": " aaa\nbbb\n", + "html": "
aaa\n
\n

bbb

\n", + "example": 225, + "start_line": 3601, + "end_line": 3608, + "section": "Paragraphs" + }, + { + "markdown": "aaa \nbbb \n", + "html": "

aaa
\nbbb

\n", + "example": 226, + "start_line": 3615, + "end_line": 3621, + "section": "Paragraphs" + }, + { + "markdown": " \n\naaa\n \n\n# aaa\n\n \n", + "html": "

aaa

\n

aaa

\n", + "example": 227, + "start_line": 3632, + "end_line": 3644, + "section": "Blank lines" + }, + { + "markdown": "> # Foo\n> bar\n> baz\n", + "html": "
\n

Foo

\n

bar\nbaz

\n
\n", + "example": 228, + "start_line": 3700, + "end_line": 3710, + "section": "Block quotes" + }, + { + "markdown": "># Foo\n>bar\n> baz\n", + "html": "
\n

Foo

\n

bar\nbaz

\n
\n", + "example": 229, + "start_line": 3715, + "end_line": 3725, + "section": "Block quotes" + }, + { + "markdown": " > # Foo\n > bar\n > baz\n", + "html": "
\n

Foo

\n

bar\nbaz

\n
\n", + "example": 230, + "start_line": 3730, + "end_line": 3740, + "section": "Block quotes" + }, + { + "markdown": " > # Foo\n > bar\n > baz\n", + "html": "
> # Foo\n> bar\n> baz\n
\n", + "example": 231, + "start_line": 3745, + "end_line": 3754, + "section": "Block quotes" + }, + { + "markdown": "> # Foo\n> bar\nbaz\n", + "html": "
\n

Foo

\n

bar\nbaz

\n
\n", + "example": 232, + "start_line": 3760, + "end_line": 3770, + "section": "Block quotes" + }, + { + "markdown": "> bar\nbaz\n> foo\n", + "html": "
\n

bar\nbaz\nfoo

\n
\n", + "example": 233, + "start_line": 3776, + "end_line": 3786, + "section": "Block quotes" + }, + { + "markdown": "> foo\n---\n", + "html": "
\n

foo

\n
\n
\n", + "example": 234, + "start_line": 3800, + "end_line": 3808, + "section": "Block quotes" + }, + { + "markdown": "> - foo\n- bar\n", + "html": "
\n
    \n
  • foo
  • \n
\n
\n
    \n
  • bar
  • \n
\n", + "example": 235, + "start_line": 3820, + "end_line": 3832, + "section": "Block quotes" + }, + { + "markdown": "> foo\n bar\n", + "html": "
\n
foo\n
\n
\n
bar\n
\n", + "example": 236, + "start_line": 3838, + "end_line": 3848, + "section": "Block quotes" + }, + { + "markdown": "> ```\nfoo\n```\n", + "html": "
\n
\n
\n

foo

\n
\n", + "example": 237, + "start_line": 3851, + "end_line": 3861, + "section": "Block quotes" + }, + { + "markdown": "> foo\n - bar\n", + "html": "
\n

foo\n- bar

\n
\n", + "example": 238, + "start_line": 3867, + "end_line": 3875, + "section": "Block quotes" + }, + { + "markdown": ">\n", + "html": "
\n
\n", + "example": 239, + "start_line": 3891, + "end_line": 3896, + "section": "Block quotes" + }, + { + "markdown": ">\n> \n> \n", + "html": "
\n
\n", + "example": 240, + "start_line": 3899, + "end_line": 3906, + "section": "Block quotes" + }, + { + "markdown": ">\n> foo\n> \n", + "html": "
\n

foo

\n
\n", + "example": 241, + "start_line": 3911, + "end_line": 3919, + "section": "Block quotes" + }, + { + "markdown": "> foo\n\n> bar\n", + "html": "
\n

foo

\n
\n
\n

bar

\n
\n", + "example": 242, + "start_line": 3924, + "end_line": 3935, + "section": "Block quotes" + }, + { + "markdown": "> foo\n> bar\n", + "html": "
\n

foo\nbar

\n
\n", + "example": 243, + "start_line": 3946, + "end_line": 3954, + "section": "Block quotes" + }, + { + "markdown": "> foo\n>\n> bar\n", + "html": "
\n

foo

\n

bar

\n
\n", + "example": 244, + "start_line": 3959, + "end_line": 3968, + "section": "Block quotes" + }, + { + "markdown": "foo\n> bar\n", + "html": "

foo

\n
\n

bar

\n
\n", + "example": 245, + "start_line": 3973, + "end_line": 3981, + "section": "Block quotes" + }, + { + "markdown": "> aaa\n***\n> bbb\n", + "html": "
\n

aaa

\n
\n
\n
\n

bbb

\n
\n", + "example": 246, + "start_line": 3987, + "end_line": 3999, + "section": "Block quotes" + }, + { + "markdown": "> bar\nbaz\n", + "html": "
\n

bar\nbaz

\n
\n", + "example": 247, + "start_line": 4005, + "end_line": 4013, + "section": "Block quotes" + }, + { + "markdown": "> bar\n\nbaz\n", + "html": "
\n

bar

\n
\n

baz

\n", + "example": 248, + "start_line": 4016, + "end_line": 4025, + "section": "Block quotes" + }, + { + "markdown": "> bar\n>\nbaz\n", + "html": "
\n

bar

\n
\n

baz

\n", + "example": 249, + "start_line": 4028, + "end_line": 4037, + "section": "Block quotes" + }, + { + "markdown": "> > > foo\nbar\n", + "html": "
\n
\n
\n

foo\nbar

\n
\n
\n
\n", + "example": 250, + "start_line": 4044, + "end_line": 4056, + "section": "Block quotes" + }, + { + "markdown": ">>> foo\n> bar\n>>baz\n", + "html": "
\n
\n
\n

foo\nbar\nbaz

\n
\n
\n
\n", + "example": 251, + "start_line": 4059, + "end_line": 4073, + "section": "Block quotes" + }, + { + "markdown": "> code\n\n> not code\n", + "html": "
\n
code\n
\n
\n
\n

not code

\n
\n", + "example": 252, + "start_line": 4081, + "end_line": 4093, + "section": "Block quotes" + }, + { + "markdown": "A paragraph\nwith two lines.\n\n indented code\n\n> A block quote.\n", + "html": "

A paragraph\nwith two lines.

\n
indented code\n
\n
\n

A block quote.

\n
\n", + "example": 253, + "start_line": 4135, + "end_line": 4150, + "section": "List items" + }, + { + "markdown": "1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 254, + "start_line": 4157, + "end_line": 4176, + "section": "List items" + }, + { + "markdown": "- one\n\n two\n", + "html": "
    \n
  • one
  • \n
\n

two

\n", + "example": 255, + "start_line": 4190, + "end_line": 4199, + "section": "List items" + }, + { + "markdown": "- one\n\n two\n", + "html": "
    \n
  • \n

    one

    \n

    two

    \n
  • \n
\n", + "example": 256, + "start_line": 4202, + "end_line": 4213, + "section": "List items" + }, + { + "markdown": " - one\n\n two\n", + "html": "
    \n
  • one
  • \n
\n
 two\n
\n", + "example": 257, + "start_line": 4216, + "end_line": 4226, + "section": "List items" + }, + { + "markdown": " - one\n\n two\n", + "html": "
    \n
  • \n

    one

    \n

    two

    \n
  • \n
\n", + "example": 258, + "start_line": 4229, + "end_line": 4240, + "section": "List items" + }, + { + "markdown": " > > 1. one\n>>\n>> two\n", + "html": "
\n
\n
    \n
  1. \n

    one

    \n

    two

    \n
  2. \n
\n
\n
\n", + "example": 259, + "start_line": 4251, + "end_line": 4266, + "section": "List items" + }, + { + "markdown": ">>- one\n>>\n > > two\n", + "html": "
\n
\n
    \n
  • one
  • \n
\n

two

\n
\n
\n", + "example": 260, + "start_line": 4278, + "end_line": 4291, + "section": "List items" + }, + { + "markdown": "-one\n\n2.two\n", + "html": "

-one

\n

2.two

\n", + "example": 261, + "start_line": 4297, + "end_line": 4304, + "section": "List items" + }, + { + "markdown": "- foo\n\n\n bar\n", + "html": "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
\n", + "example": 262, + "start_line": 4310, + "end_line": 4322, + "section": "List items" + }, + { + "markdown": "1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam\n", + "html": "
    \n
  1. \n

    foo

    \n
    bar\n
    \n

    baz

    \n
    \n

    bam

    \n
    \n
  2. \n
\n", + "example": 263, + "start_line": 4327, + "end_line": 4349, + "section": "List items" + }, + { + "markdown": "- Foo\n\n bar\n\n\n baz\n", + "html": "
    \n
  • \n

    Foo

    \n
    bar\n\n\nbaz\n
    \n
  • \n
\n", + "example": 264, + "start_line": 4355, + "end_line": 4373, + "section": "List items" + }, + { + "markdown": "123456789. ok\n", + "html": "
    \n
  1. ok
  2. \n
\n", + "example": 265, + "start_line": 4377, + "end_line": 4383, + "section": "List items" + }, + { + "markdown": "1234567890. not ok\n", + "html": "

1234567890. not ok

\n", + "example": 266, + "start_line": 4386, + "end_line": 4390, + "section": "List items" + }, + { + "markdown": "0. ok\n", + "html": "
    \n
  1. ok
  2. \n
\n", + "example": 267, + "start_line": 4395, + "end_line": 4401, + "section": "List items" + }, + { + "markdown": "003. ok\n", + "html": "
    \n
  1. ok
  2. \n
\n", + "example": 268, + "start_line": 4404, + "end_line": 4410, + "section": "List items" + }, + { + "markdown": "-1. not ok\n", + "html": "

-1. not ok

\n", + "example": 269, + "start_line": 4415, + "end_line": 4419, + "section": "List items" + }, + { + "markdown": "- foo\n\n bar\n", + "html": "
    \n
  • \n

    foo

    \n
    bar\n
    \n
  • \n
\n", + "example": 270, + "start_line": 4438, + "end_line": 4450, + "section": "List items" + }, + { + "markdown": " 10. foo\n\n bar\n", + "html": "
    \n
  1. \n

    foo

    \n
    bar\n
    \n
  2. \n
\n", + "example": 271, + "start_line": 4455, + "end_line": 4467, + "section": "List items" + }, + { + "markdown": " indented code\n\nparagraph\n\n more code\n", + "html": "
indented code\n
\n

paragraph

\n
more code\n
\n", + "example": 272, + "start_line": 4474, + "end_line": 4486, + "section": "List items" + }, + { + "markdown": "1. indented code\n\n paragraph\n\n more code\n", + "html": "
    \n
  1. \n
    indented code\n
    \n

    paragraph

    \n
    more code\n
    \n
  2. \n
\n", + "example": 273, + "start_line": 4489, + "end_line": 4505, + "section": "List items" + }, + { + "markdown": "1. indented code\n\n paragraph\n\n more code\n", + "html": "
    \n
  1. \n
     indented code\n
    \n

    paragraph

    \n
    more code\n
    \n
  2. \n
\n", + "example": 274, + "start_line": 4511, + "end_line": 4527, + "section": "List items" + }, + { + "markdown": " foo\n\nbar\n", + "html": "

foo

\n

bar

\n", + "example": 275, + "start_line": 4538, + "end_line": 4545, + "section": "List items" + }, + { + "markdown": "- foo\n\n bar\n", + "html": "
    \n
  • foo
  • \n
\n

bar

\n", + "example": 276, + "start_line": 4548, + "end_line": 4557, + "section": "List items" + }, + { + "markdown": "- foo\n\n bar\n", + "html": "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
\n", + "example": 277, + "start_line": 4565, + "end_line": 4576, + "section": "List items" + }, + { + "markdown": "-\n foo\n-\n ```\n bar\n ```\n-\n baz\n", + "html": "
    \n
  • foo
  • \n
  • \n
    bar\n
    \n
  • \n
  • \n
    baz\n
    \n
  • \n
\n", + "example": 278, + "start_line": 4592, + "end_line": 4613, + "section": "List items" + }, + { + "markdown": "- \n foo\n", + "html": "
    \n
  • foo
  • \n
\n", + "example": 279, + "start_line": 4618, + "end_line": 4625, + "section": "List items" + }, + { + "markdown": "-\n\n foo\n", + "html": "
    \n
  • \n
\n

foo

\n", + "example": 280, + "start_line": 4632, + "end_line": 4641, + "section": "List items" + }, + { + "markdown": "- foo\n-\n- bar\n", + "html": "
    \n
  • foo
  • \n
  • \n
  • bar
  • \n
\n", + "example": 281, + "start_line": 4646, + "end_line": 4656, + "section": "List items" + }, + { + "markdown": "- foo\n- \n- bar\n", + "html": "
    \n
  • foo
  • \n
  • \n
  • bar
  • \n
\n", + "example": 282, + "start_line": 4661, + "end_line": 4671, + "section": "List items" + }, + { + "markdown": "1. foo\n2.\n3. bar\n", + "html": "
    \n
  1. foo
  2. \n
  3. \n
  4. bar
  5. \n
\n", + "example": 283, + "start_line": 4676, + "end_line": 4686, + "section": "List items" + }, + { + "markdown": "*\n", + "html": "
    \n
  • \n
\n", + "example": 284, + "start_line": 4691, + "end_line": 4697, + "section": "List items" + }, + { + "markdown": "foo\n*\n\nfoo\n1.\n", + "html": "

foo\n*

\n

foo\n1.

\n", + "example": 285, + "start_line": 4701, + "end_line": 4712, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 286, + "start_line": 4723, + "end_line": 4742, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 287, + "start_line": 4747, + "end_line": 4766, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 288, + "start_line": 4771, + "end_line": 4790, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
1.  A paragraph\n    with two lines.\n\n        indented code\n\n    > A block quote.\n
\n", + "example": 289, + "start_line": 4795, + "end_line": 4810, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 290, + "start_line": 4825, + "end_line": 4844, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n", + "html": "
    \n
  1. A paragraph\nwith two lines.
  2. \n
\n", + "example": 291, + "start_line": 4849, + "end_line": 4857, + "section": "List items" + }, + { + "markdown": "> 1. > Blockquote\ncontinued here.\n", + "html": "
\n
    \n
  1. \n
    \n

    Blockquote\ncontinued here.

    \n
    \n
  2. \n
\n
\n", + "example": 292, + "start_line": 4862, + "end_line": 4876, + "section": "List items" + }, + { + "markdown": "> 1. > Blockquote\n> continued here.\n", + "html": "
\n
    \n
  1. \n
    \n

    Blockquote\ncontinued here.

    \n
    \n
  2. \n
\n
\n", + "example": 293, + "start_line": 4879, + "end_line": 4893, + "section": "List items" + }, + { + "markdown": "- foo\n - bar\n - baz\n - boo\n", + "html": "
    \n
  • foo\n
      \n
    • bar\n
        \n
      • baz\n
          \n
        • boo
        • \n
        \n
      • \n
      \n
    • \n
    \n
  • \n
\n", + "example": 294, + "start_line": 4907, + "end_line": 4928, + "section": "List items" + }, + { + "markdown": "- foo\n - bar\n - baz\n - boo\n", + "html": "
    \n
  • foo
  • \n
  • bar
  • \n
  • baz
  • \n
  • boo
  • \n
\n", + "example": 295, + "start_line": 4933, + "end_line": 4945, + "section": "List items" + }, + { + "markdown": "10) foo\n - bar\n", + "html": "
    \n
  1. foo\n
      \n
    • bar
    • \n
    \n
  2. \n
\n", + "example": 296, + "start_line": 4950, + "end_line": 4961, + "section": "List items" + }, + { + "markdown": "10) foo\n - bar\n", + "html": "
    \n
  1. foo
  2. \n
\n
    \n
  • bar
  • \n
\n", + "example": 297, + "start_line": 4966, + "end_line": 4976, + "section": "List items" + }, + { + "markdown": "- - foo\n", + "html": "
    \n
  • \n
      \n
    • foo
    • \n
    \n
  • \n
\n", + "example": 298, + "start_line": 4981, + "end_line": 4991, + "section": "List items" + }, + { + "markdown": "1. - 2. foo\n", + "html": "
    \n
  1. \n
      \n
    • \n
        \n
      1. foo
      2. \n
      \n
    • \n
    \n
  2. \n
\n", + "example": 299, + "start_line": 4994, + "end_line": 5008, + "section": "List items" + }, + { + "markdown": "- # Foo\n- Bar\n ---\n baz\n", + "html": "
    \n
  • \n

    Foo

    \n
  • \n
  • \n

    Bar

    \nbaz
  • \n
\n", + "example": 300, + "start_line": 5013, + "end_line": 5027, + "section": "List items" + }, + { + "markdown": "- foo\n- bar\n+ baz\n", + "html": "
    \n
  • foo
  • \n
  • bar
  • \n
\n
    \n
  • baz
  • \n
\n", + "example": 301, + "start_line": 5249, + "end_line": 5261, + "section": "Lists" + }, + { + "markdown": "1. foo\n2. bar\n3) baz\n", + "html": "
    \n
  1. foo
  2. \n
  3. bar
  4. \n
\n
    \n
  1. baz
  2. \n
\n", + "example": 302, + "start_line": 5264, + "end_line": 5276, + "section": "Lists" + }, + { + "markdown": "Foo\n- bar\n- baz\n", + "html": "

Foo

\n
    \n
  • bar
  • \n
  • baz
  • \n
\n", + "example": 303, + "start_line": 5283, + "end_line": 5293, + "section": "Lists" + }, + { + "markdown": "The number of windows in my house is\n14. The number of doors is 6.\n", + "html": "

The number of windows in my house is\n14. The number of doors is 6.

\n", + "example": 304, + "start_line": 5360, + "end_line": 5366, + "section": "Lists" + }, + { + "markdown": "The number of windows in my house is\n1. The number of doors is 6.\n", + "html": "

The number of windows in my house is

\n
    \n
  1. The number of doors is 6.
  2. \n
\n", + "example": 305, + "start_line": 5370, + "end_line": 5378, + "section": "Lists" + }, + { + "markdown": "- foo\n\n- bar\n\n\n- baz\n", + "html": "
    \n
  • \n

    foo

    \n
  • \n
  • \n

    bar

    \n
  • \n
  • \n

    baz

    \n
  • \n
\n", + "example": 306, + "start_line": 5384, + "end_line": 5403, + "section": "Lists" + }, + { + "markdown": "- foo\n - bar\n - baz\n\n\n bim\n", + "html": "
    \n
  • foo\n
      \n
    • bar\n
        \n
      • \n

        baz

        \n

        bim

        \n
      • \n
      \n
    • \n
    \n
  • \n
\n", + "example": 307, + "start_line": 5405, + "end_line": 5427, + "section": "Lists" + }, + { + "markdown": "- foo\n- bar\n\n\n\n- baz\n- bim\n", + "html": "
    \n
  • foo
  • \n
  • bar
  • \n
\n\n
    \n
  • baz
  • \n
  • bim
  • \n
\n", + "example": 308, + "start_line": 5435, + "end_line": 5453, + "section": "Lists" + }, + { + "markdown": "- foo\n\n notcode\n\n- foo\n\n\n\n code\n", + "html": "
    \n
  • \n

    foo

    \n

    notcode

    \n
  • \n
  • \n

    foo

    \n
  • \n
\n\n
code\n
\n", + "example": 309, + "start_line": 5456, + "end_line": 5479, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n - c\n - d\n - e\n - f\n- g\n", + "html": "
    \n
  • a
  • \n
  • b
  • \n
  • c
  • \n
  • d
  • \n
  • e
  • \n
  • f
  • \n
  • g
  • \n
\n", + "example": 310, + "start_line": 5487, + "end_line": 5505, + "section": "Lists" + }, + { + "markdown": "1. a\n\n 2. b\n\n 3. c\n", + "html": "
    \n
  1. \n

    a

    \n
  2. \n
  3. \n

    b

    \n
  4. \n
  5. \n

    c

    \n
  6. \n
\n", + "example": 311, + "start_line": 5508, + "end_line": 5526, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n - c\n - d\n - e\n", + "html": "
    \n
  • a
  • \n
  • b
  • \n
  • c
  • \n
  • d\n- e
  • \n
\n", + "example": 312, + "start_line": 5532, + "end_line": 5546, + "section": "Lists" + }, + { + "markdown": "1. a\n\n 2. b\n\n 3. c\n", + "html": "
    \n
  1. \n

    a

    \n
  2. \n
  3. \n

    b

    \n
  4. \n
\n
3. c\n
\n", + "example": 313, + "start_line": 5552, + "end_line": 5569, + "section": "Lists" + }, + { + "markdown": "- a\n- b\n\n- c\n", + "html": "
    \n
  • \n

    a

    \n
  • \n
  • \n

    b

    \n
  • \n
  • \n

    c

    \n
  • \n
\n", + "example": 314, + "start_line": 5575, + "end_line": 5592, + "section": "Lists" + }, + { + "markdown": "* a\n*\n\n* c\n", + "html": "
    \n
  • \n

    a

    \n
  • \n
  • \n
  • \n

    c

    \n
  • \n
\n", + "example": 315, + "start_line": 5597, + "end_line": 5612, + "section": "Lists" + }, + { + "markdown": "- a\n- b\n\n c\n- d\n", + "html": "
    \n
  • \n

    a

    \n
  • \n
  • \n

    b

    \n

    c

    \n
  • \n
  • \n

    d

    \n
  • \n
\n", + "example": 316, + "start_line": 5619, + "end_line": 5638, + "section": "Lists" + }, + { + "markdown": "- a\n- b\n\n [ref]: /url\n- d\n", + "html": "
    \n
  • \n

    a

    \n
  • \n
  • \n

    b

    \n
  • \n
  • \n

    d

    \n
  • \n
\n", + "example": 317, + "start_line": 5641, + "end_line": 5659, + "section": "Lists" + }, + { + "markdown": "- a\n- ```\n b\n\n\n ```\n- c\n", + "html": "
    \n
  • a
  • \n
  • \n
    b\n\n\n
    \n
  • \n
  • c
  • \n
\n", + "example": 318, + "start_line": 5664, + "end_line": 5683, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n\n c\n- d\n", + "html": "
    \n
  • a\n
      \n
    • \n

      b

      \n

      c

      \n
    • \n
    \n
  • \n
  • d
  • \n
\n", + "example": 319, + "start_line": 5690, + "end_line": 5708, + "section": "Lists" + }, + { + "markdown": "* a\n > b\n >\n* c\n", + "html": "
    \n
  • a\n
    \n

    b

    \n
    \n
  • \n
  • c
  • \n
\n", + "example": 320, + "start_line": 5714, + "end_line": 5728, + "section": "Lists" + }, + { + "markdown": "- a\n > b\n ```\n c\n ```\n- d\n", + "html": "
    \n
  • a\n
    \n

    b

    \n
    \n
    c\n
    \n
  • \n
  • d
  • \n
\n", + "example": 321, + "start_line": 5734, + "end_line": 5752, + "section": "Lists" + }, + { + "markdown": "- a\n", + "html": "
    \n
  • a
  • \n
\n", + "example": 322, + "start_line": 5757, + "end_line": 5763, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n", + "html": "
    \n
  • a\n
      \n
    • b
    • \n
    \n
  • \n
\n", + "example": 323, + "start_line": 5766, + "end_line": 5777, + "section": "Lists" + }, + { + "markdown": "1. ```\n foo\n ```\n\n bar\n", + "html": "
    \n
  1. \n
    foo\n
    \n

    bar

    \n
  2. \n
\n", + "example": 324, + "start_line": 5783, + "end_line": 5797, + "section": "Lists" + }, + { + "markdown": "* foo\n * bar\n\n baz\n", + "html": "
    \n
  • \n

    foo

    \n
      \n
    • bar
    • \n
    \n

    baz

    \n
  • \n
\n", + "example": 325, + "start_line": 5802, + "end_line": 5817, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n - c\n\n- d\n - e\n - f\n", + "html": "
    \n
  • \n

    a

    \n
      \n
    • b
    • \n
    • c
    • \n
    \n
  • \n
  • \n

    d

    \n
      \n
    • e
    • \n
    • f
    • \n
    \n
  • \n
\n", + "example": 326, + "start_line": 5820, + "end_line": 5845, + "section": "Lists" + }, + { + "markdown": "`hi`lo`\n", + "html": "

hilo`

\n", + "example": 327, + "start_line": 5854, + "end_line": 5858, + "section": "Inlines" + }, + { + "markdown": "`foo`\n", + "html": "

foo

\n", + "example": 328, + "start_line": 5886, + "end_line": 5890, + "section": "Code spans" + }, + { + "markdown": "`` foo ` bar ``\n", + "html": "

foo ` bar

\n", + "example": 329, + "start_line": 5897, + "end_line": 5901, + "section": "Code spans" + }, + { + "markdown": "` `` `\n", + "html": "

``

\n", + "example": 330, + "start_line": 5907, + "end_line": 5911, + "section": "Code spans" + }, + { + "markdown": "` `` `\n", + "html": "

``

\n", + "example": 331, + "start_line": 5915, + "end_line": 5919, + "section": "Code spans" + }, + { + "markdown": "` a`\n", + "html": "

a

\n", + "example": 332, + "start_line": 5924, + "end_line": 5928, + "section": "Code spans" + }, + { + "markdown": "` b `\n", + "html": "

 b 

\n", + "example": 333, + "start_line": 5933, + "end_line": 5937, + "section": "Code spans" + }, + { + "markdown": "` `\n` `\n", + "html": "

 \n

\n", + "example": 334, + "start_line": 5941, + "end_line": 5947, + "section": "Code spans" + }, + { + "markdown": "``\nfoo\nbar \nbaz\n``\n", + "html": "

foo bar baz

\n", + "example": 335, + "start_line": 5952, + "end_line": 5960, + "section": "Code spans" + }, + { + "markdown": "``\nfoo \n``\n", + "html": "

foo

\n", + "example": 336, + "start_line": 5962, + "end_line": 5968, + "section": "Code spans" + }, + { + "markdown": "`foo bar \nbaz`\n", + "html": "

foo bar baz

\n", + "example": 337, + "start_line": 5973, + "end_line": 5978, + "section": "Code spans" + }, + { + "markdown": "`foo\\`bar`\n", + "html": "

foo\\bar`

\n", + "example": 338, + "start_line": 5990, + "end_line": 5994, + "section": "Code spans" + }, + { + "markdown": "``foo`bar``\n", + "html": "

foo`bar

\n", + "example": 339, + "start_line": 6001, + "end_line": 6005, + "section": "Code spans" + }, + { + "markdown": "` foo `` bar `\n", + "html": "

foo `` bar

\n", + "example": 340, + "start_line": 6007, + "end_line": 6011, + "section": "Code spans" + }, + { + "markdown": "*foo`*`\n", + "html": "

*foo*

\n", + "example": 341, + "start_line": 6019, + "end_line": 6023, + "section": "Code spans" + }, + { + "markdown": "[not a `link](/foo`)\n", + "html": "

[not a link](/foo)

\n", + "example": 342, + "start_line": 6028, + "end_line": 6032, + "section": "Code spans" + }, + { + "markdown": "``\n", + "html": "

<a href="">`

\n", + "example": 343, + "start_line": 6038, + "end_line": 6042, + "section": "Code spans" + }, + { + "markdown": "
`\n", + "html": "

`

\n", + "example": 344, + "start_line": 6047, + "end_line": 6051, + "section": "Code spans" + }, + { + "markdown": "``\n", + "html": "

<https://foo.bar.baz>`

\n", + "example": 345, + "start_line": 6056, + "end_line": 6060, + "section": "Code spans" + }, + { + "markdown": "`\n", + "html": "

https://foo.bar.`baz`

\n", + "example": 346, + "start_line": 6065, + "end_line": 6069, + "section": "Code spans" + }, + { + "markdown": "```foo``\n", + "html": "

```foo``

\n", + "example": 347, + "start_line": 6075, + "end_line": 6079, + "section": "Code spans" + }, + { + "markdown": "`foo\n", + "html": "

`foo

\n", + "example": 348, + "start_line": 6082, + "end_line": 6086, + "section": "Code spans" + }, + { + "markdown": "`foo``bar``\n", + "html": "

`foobar

\n", + "example": 349, + "start_line": 6091, + "end_line": 6095, + "section": "Code spans" + }, + { + "markdown": "*foo bar*\n", + "html": "

foo bar

\n", + "example": 350, + "start_line": 6308, + "end_line": 6312, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a * foo bar*\n", + "html": "

a * foo bar*

\n", + "example": 351, + "start_line": 6318, + "end_line": 6322, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a*\"foo\"*\n", + "html": "

a*"foo"*

\n", + "example": 352, + "start_line": 6329, + "end_line": 6333, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "* a *\n", + "html": "

* a *

\n", + "example": 353, + "start_line": 6338, + "end_line": 6342, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*$*alpha.\n\n*£*bravo.\n\n*€*charlie.\n", + "html": "

*$*alpha.

\n

*£*bravo.

\n

*€*charlie.

\n", + "example": 354, + "start_line": 6347, + "end_line": 6357, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo*bar*\n", + "html": "

foobar

\n", + "example": 355, + "start_line": 6362, + "end_line": 6366, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "5*6*78\n", + "html": "

5678

\n", + "example": 356, + "start_line": 6369, + "end_line": 6373, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo bar_\n", + "html": "

foo bar

\n", + "example": 357, + "start_line": 6378, + "end_line": 6382, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_ foo bar_\n", + "html": "

_ foo bar_

\n", + "example": 358, + "start_line": 6388, + "end_line": 6392, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a_\"foo\"_\n", + "html": "

a_"foo"_

\n", + "example": 359, + "start_line": 6398, + "end_line": 6402, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo_bar_\n", + "html": "

foo_bar_

\n", + "example": 360, + "start_line": 6407, + "end_line": 6411, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "5_6_78\n", + "html": "

5_6_78

\n", + "example": 361, + "start_line": 6414, + "end_line": 6418, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "пристаням_стремятся_\n", + "html": "

пристаням_стремятся_

\n", + "example": 362, + "start_line": 6421, + "end_line": 6425, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "aa_\"bb\"_cc\n", + "html": "

aa_"bb"_cc

\n", + "example": 363, + "start_line": 6431, + "end_line": 6435, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo-_(bar)_\n", + "html": "

foo-(bar)

\n", + "example": 364, + "start_line": 6442, + "end_line": 6446, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo*\n", + "html": "

_foo*

\n", + "example": 365, + "start_line": 6454, + "end_line": 6458, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo bar *\n", + "html": "

*foo bar *

\n", + "example": 366, + "start_line": 6464, + "end_line": 6468, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo bar\n*\n", + "html": "

*foo bar\n*

\n", + "example": 367, + "start_line": 6473, + "end_line": 6479, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*(*foo)\n", + "html": "

*(*foo)

\n", + "example": 368, + "start_line": 6486, + "end_line": 6490, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*(*foo*)*\n", + "html": "

(foo)

\n", + "example": 369, + "start_line": 6496, + "end_line": 6500, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo*bar\n", + "html": "

foobar

\n", + "example": 370, + "start_line": 6505, + "end_line": 6509, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo bar _\n", + "html": "

_foo bar _

\n", + "example": 371, + "start_line": 6518, + "end_line": 6522, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(_foo)\n", + "html": "

_(_foo)

\n", + "example": 372, + "start_line": 6528, + "end_line": 6532, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(_foo_)_\n", + "html": "

(foo)

\n", + "example": 373, + "start_line": 6537, + "end_line": 6541, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo_bar\n", + "html": "

_foo_bar

\n", + "example": 374, + "start_line": 6546, + "end_line": 6550, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_пристаням_стремятся\n", + "html": "

_пристаням_стремятся

\n", + "example": 375, + "start_line": 6553, + "end_line": 6557, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo_bar_baz_\n", + "html": "

foo_bar_baz

\n", + "example": 376, + "start_line": 6560, + "end_line": 6564, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(bar)_.\n", + "html": "

(bar).

\n", + "example": 377, + "start_line": 6571, + "end_line": 6575, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo bar**\n", + "html": "

foo bar

\n", + "example": 378, + "start_line": 6580, + "end_line": 6584, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "** foo bar**\n", + "html": "

** foo bar**

\n", + "example": 379, + "start_line": 6590, + "end_line": 6594, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a**\"foo\"**\n", + "html": "

a**"foo"**

\n", + "example": 380, + "start_line": 6601, + "end_line": 6605, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo**bar**\n", + "html": "

foobar

\n", + "example": 381, + "start_line": 6610, + "end_line": 6614, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo bar__\n", + "html": "

foo bar

\n", + "example": 382, + "start_line": 6619, + "end_line": 6623, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__ foo bar__\n", + "html": "

__ foo bar__

\n", + "example": 383, + "start_line": 6629, + "end_line": 6633, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__\nfoo bar__\n", + "html": "

__\nfoo bar__

\n", + "example": 384, + "start_line": 6637, + "end_line": 6643, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a__\"foo\"__\n", + "html": "

a__"foo"__

\n", + "example": 385, + "start_line": 6649, + "end_line": 6653, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo__bar__\n", + "html": "

foo__bar__

\n", + "example": 386, + "start_line": 6658, + "end_line": 6662, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "5__6__78\n", + "html": "

5__6__78

\n", + "example": 387, + "start_line": 6665, + "end_line": 6669, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "пристаням__стремятся__\n", + "html": "

пристаням__стремятся__

\n", + "example": 388, + "start_line": 6672, + "end_line": 6676, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo, __bar__, baz__\n", + "html": "

foo, bar, baz

\n", + "example": 389, + "start_line": 6679, + "end_line": 6683, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo-__(bar)__\n", + "html": "

foo-(bar)

\n", + "example": 390, + "start_line": 6690, + "end_line": 6694, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo bar **\n", + "html": "

**foo bar **

\n", + "example": 391, + "start_line": 6703, + "end_line": 6707, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**(**foo)\n", + "html": "

**(**foo)

\n", + "example": 392, + "start_line": 6716, + "end_line": 6720, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*(**foo**)*\n", + "html": "

(foo)

\n", + "example": 393, + "start_line": 6726, + "end_line": 6730, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**\n", + "html": "

Gomphocarpus (Gomphocarpus physocarpus, syn.\nAsclepias physocarpa)

\n", + "example": 394, + "start_line": 6733, + "end_line": 6739, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo \"*bar*\" foo**\n", + "html": "

foo "bar" foo

\n", + "example": 395, + "start_line": 6742, + "end_line": 6746, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo**bar\n", + "html": "

foobar

\n", + "example": 396, + "start_line": 6751, + "end_line": 6755, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo bar __\n", + "html": "

__foo bar __

\n", + "example": 397, + "start_line": 6763, + "end_line": 6767, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__(__foo)\n", + "html": "

__(__foo)

\n", + "example": 398, + "start_line": 6773, + "end_line": 6777, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(__foo__)_\n", + "html": "

(foo)

\n", + "example": 399, + "start_line": 6783, + "end_line": 6787, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo__bar\n", + "html": "

__foo__bar

\n", + "example": 400, + "start_line": 6792, + "end_line": 6796, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__пристаням__стремятся\n", + "html": "

__пристаням__стремятся

\n", + "example": 401, + "start_line": 6799, + "end_line": 6803, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo__bar__baz__\n", + "html": "

foo__bar__baz

\n", + "example": 402, + "start_line": 6806, + "end_line": 6810, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__(bar)__.\n", + "html": "

(bar).

\n", + "example": 403, + "start_line": 6817, + "end_line": 6821, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo [bar](/url)*\n", + "html": "

foo bar

\n", + "example": 404, + "start_line": 6829, + "end_line": 6833, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo\nbar*\n", + "html": "

foo\nbar

\n", + "example": 405, + "start_line": 6836, + "end_line": 6842, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo __bar__ baz_\n", + "html": "

foo bar baz

\n", + "example": 406, + "start_line": 6848, + "end_line": 6852, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo _bar_ baz_\n", + "html": "

foo bar baz

\n", + "example": 407, + "start_line": 6855, + "end_line": 6859, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo_ bar_\n", + "html": "

foo bar

\n", + "example": 408, + "start_line": 6862, + "end_line": 6866, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo *bar**\n", + "html": "

foo bar

\n", + "example": 409, + "start_line": 6869, + "end_line": 6873, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo **bar** baz*\n", + "html": "

foo bar baz

\n", + "example": 410, + "start_line": 6876, + "end_line": 6880, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**bar**baz*\n", + "html": "

foobarbaz

\n", + "example": 411, + "start_line": 6882, + "end_line": 6886, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**bar*\n", + "html": "

foo**bar

\n", + "example": 412, + "start_line": 6906, + "end_line": 6910, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo** bar*\n", + "html": "

foo bar

\n", + "example": 413, + "start_line": 6919, + "end_line": 6923, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo **bar***\n", + "html": "

foo bar

\n", + "example": 414, + "start_line": 6926, + "end_line": 6930, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**bar***\n", + "html": "

foobar

\n", + "example": 415, + "start_line": 6933, + "end_line": 6937, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo***bar***baz\n", + "html": "

foobarbaz

\n", + "example": 416, + "start_line": 6944, + "end_line": 6948, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo******bar*********baz\n", + "html": "

foobar***baz

\n", + "example": 417, + "start_line": 6950, + "end_line": 6954, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo **bar *baz* bim** bop*\n", + "html": "

foo bar baz bim bop

\n", + "example": 418, + "start_line": 6959, + "end_line": 6963, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo [*bar*](/url)*\n", + "html": "

foo bar

\n", + "example": 419, + "start_line": 6966, + "end_line": 6970, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "** is not an empty emphasis\n", + "html": "

** is not an empty emphasis

\n", + "example": 420, + "start_line": 6975, + "end_line": 6979, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**** is not an empty strong emphasis\n", + "html": "

**** is not an empty strong emphasis

\n", + "example": 421, + "start_line": 6982, + "end_line": 6986, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo [bar](/url)**\n", + "html": "

foo bar

\n", + "example": 422, + "start_line": 6995, + "end_line": 6999, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo\nbar**\n", + "html": "

foo\nbar

\n", + "example": 423, + "start_line": 7002, + "end_line": 7008, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo _bar_ baz__\n", + "html": "

foo bar baz

\n", + "example": 424, + "start_line": 7014, + "end_line": 7018, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo __bar__ baz__\n", + "html": "

foo bar baz

\n", + "example": 425, + "start_line": 7021, + "end_line": 7025, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____foo__ bar__\n", + "html": "

foo bar

\n", + "example": 426, + "start_line": 7028, + "end_line": 7032, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo **bar****\n", + "html": "

foo bar

\n", + "example": 427, + "start_line": 7035, + "end_line": 7039, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo *bar* baz**\n", + "html": "

foo bar baz

\n", + "example": 428, + "start_line": 7042, + "end_line": 7046, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo*bar*baz**\n", + "html": "

foobarbaz

\n", + "example": 429, + "start_line": 7049, + "end_line": 7053, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo* bar**\n", + "html": "

foo bar

\n", + "example": 430, + "start_line": 7056, + "end_line": 7060, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo *bar***\n", + "html": "

foo bar

\n", + "example": 431, + "start_line": 7063, + "end_line": 7067, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo *bar **baz**\nbim* bop**\n", + "html": "

foo bar baz\nbim bop

\n", + "example": 432, + "start_line": 7072, + "end_line": 7078, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo [*bar*](/url)**\n", + "html": "

foo bar

\n", + "example": 433, + "start_line": 7081, + "end_line": 7085, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__ is not an empty emphasis\n", + "html": "

__ is not an empty emphasis

\n", + "example": 434, + "start_line": 7090, + "end_line": 7094, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____ is not an empty strong emphasis\n", + "html": "

____ is not an empty strong emphasis

\n", + "example": 435, + "start_line": 7097, + "end_line": 7101, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo ***\n", + "html": "

foo ***

\n", + "example": 436, + "start_line": 7107, + "end_line": 7111, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo *\\**\n", + "html": "

foo *

\n", + "example": 437, + "start_line": 7114, + "end_line": 7118, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo *_*\n", + "html": "

foo _

\n", + "example": 438, + "start_line": 7121, + "end_line": 7125, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo *****\n", + "html": "

foo *****

\n", + "example": 439, + "start_line": 7128, + "end_line": 7132, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo **\\***\n", + "html": "

foo *

\n", + "example": 440, + "start_line": 7135, + "end_line": 7139, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo **_**\n", + "html": "

foo _

\n", + "example": 441, + "start_line": 7142, + "end_line": 7146, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo*\n", + "html": "

*foo

\n", + "example": 442, + "start_line": 7153, + "end_line": 7157, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**\n", + "html": "

foo*

\n", + "example": 443, + "start_line": 7160, + "end_line": 7164, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo**\n", + "html": "

*foo

\n", + "example": 444, + "start_line": 7167, + "end_line": 7171, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "****foo*\n", + "html": "

***foo

\n", + "example": 445, + "start_line": 7174, + "end_line": 7178, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo***\n", + "html": "

foo*

\n", + "example": 446, + "start_line": 7181, + "end_line": 7185, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo****\n", + "html": "

foo***

\n", + "example": 447, + "start_line": 7188, + "end_line": 7192, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo ___\n", + "html": "

foo ___

\n", + "example": 448, + "start_line": 7198, + "end_line": 7202, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo _\\__\n", + "html": "

foo _

\n", + "example": 449, + "start_line": 7205, + "end_line": 7209, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo _*_\n", + "html": "

foo *

\n", + "example": 450, + "start_line": 7212, + "end_line": 7216, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo _____\n", + "html": "

foo _____

\n", + "example": 451, + "start_line": 7219, + "end_line": 7223, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo __\\___\n", + "html": "

foo _

\n", + "example": 452, + "start_line": 7226, + "end_line": 7230, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo __*__\n", + "html": "

foo *

\n", + "example": 453, + "start_line": 7233, + "end_line": 7237, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo_\n", + "html": "

_foo

\n", + "example": 454, + "start_line": 7240, + "end_line": 7244, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo__\n", + "html": "

foo_

\n", + "example": 455, + "start_line": 7251, + "end_line": 7255, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "___foo__\n", + "html": "

_foo

\n", + "example": 456, + "start_line": 7258, + "end_line": 7262, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____foo_\n", + "html": "

___foo

\n", + "example": 457, + "start_line": 7265, + "end_line": 7269, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo___\n", + "html": "

foo_

\n", + "example": 458, + "start_line": 7272, + "end_line": 7276, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo____\n", + "html": "

foo___

\n", + "example": 459, + "start_line": 7279, + "end_line": 7283, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo**\n", + "html": "

foo

\n", + "example": 460, + "start_line": 7289, + "end_line": 7293, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*_foo_*\n", + "html": "

foo

\n", + "example": 461, + "start_line": 7296, + "end_line": 7300, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo__\n", + "html": "

foo

\n", + "example": 462, + "start_line": 7303, + "end_line": 7307, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_*foo*_\n", + "html": "

foo

\n", + "example": 463, + "start_line": 7310, + "end_line": 7314, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "****foo****\n", + "html": "

foo

\n", + "example": 464, + "start_line": 7320, + "end_line": 7324, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____foo____\n", + "html": "

foo

\n", + "example": 465, + "start_line": 7327, + "end_line": 7331, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "******foo******\n", + "html": "

foo

\n", + "example": 466, + "start_line": 7338, + "end_line": 7342, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo***\n", + "html": "

foo

\n", + "example": 467, + "start_line": 7347, + "end_line": 7351, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_____foo_____\n", + "html": "

foo

\n", + "example": 468, + "start_line": 7354, + "end_line": 7358, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo _bar* baz_\n", + "html": "

foo _bar baz_

\n", + "example": 469, + "start_line": 7363, + "end_line": 7367, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo __bar *baz bim__ bam*\n", + "html": "

foo bar *baz bim bam

\n", + "example": 470, + "start_line": 7370, + "end_line": 7374, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo **bar baz**\n", + "html": "

**foo bar baz

\n", + "example": 471, + "start_line": 7379, + "end_line": 7383, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo *bar baz*\n", + "html": "

*foo bar baz

\n", + "example": 472, + "start_line": 7386, + "end_line": 7390, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*[bar*](/url)\n", + "html": "

*bar*

\n", + "example": 473, + "start_line": 7395, + "end_line": 7399, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo [bar_](/url)\n", + "html": "

_foo bar_

\n", + "example": 474, + "start_line": 7402, + "end_line": 7406, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*\n", + "html": "

*

\n", + "example": 475, + "start_line": 7409, + "end_line": 7413, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**\n", + "html": "

**

\n", + "example": 476, + "start_line": 7416, + "end_line": 7420, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__\n", + "html": "

__

\n", + "example": 477, + "start_line": 7423, + "end_line": 7427, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*a `*`*\n", + "html": "

a *

\n", + "example": 478, + "start_line": 7430, + "end_line": 7434, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_a `_`_\n", + "html": "

a _

\n", + "example": 479, + "start_line": 7437, + "end_line": 7441, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**a\n", + "html": "

**ahttps://foo.bar/?q=**

\n", + "example": 480, + "start_line": 7444, + "end_line": 7448, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__a\n", + "html": "

__ahttps://foo.bar/?q=__

\n", + "example": 481, + "start_line": 7451, + "end_line": 7455, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "[link](/uri \"title\")\n", + "html": "

link

\n", + "example": 482, + "start_line": 7539, + "end_line": 7543, + "section": "Links" + }, + { + "markdown": "[link](/uri)\n", + "html": "

link

\n", + "example": 483, + "start_line": 7549, + "end_line": 7553, + "section": "Links" + }, + { + "markdown": "[](./target.md)\n", + "html": "

\n", + "example": 484, + "start_line": 7555, + "end_line": 7559, + "section": "Links" + }, + { + "markdown": "[link]()\n", + "html": "

link

\n", + "example": 485, + "start_line": 7562, + "end_line": 7566, + "section": "Links" + }, + { + "markdown": "[link](<>)\n", + "html": "

link

\n", + "example": 486, + "start_line": 7569, + "end_line": 7573, + "section": "Links" + }, + { + "markdown": "[]()\n", + "html": "

\n", + "example": 487, + "start_line": 7576, + "end_line": 7580, + "section": "Links" + }, + { + "markdown": "[link](/my uri)\n", + "html": "

[link](/my uri)

\n", + "example": 488, + "start_line": 7585, + "end_line": 7589, + "section": "Links" + }, + { + "markdown": "[link](
)\n", + "html": "

link

\n", + "example": 489, + "start_line": 7591, + "end_line": 7595, + "section": "Links" + }, + { + "markdown": "[link](foo\nbar)\n", + "html": "

[link](foo\nbar)

\n", + "example": 490, + "start_line": 7600, + "end_line": 7606, + "section": "Links" + }, + { + "markdown": "[link]()\n", + "html": "

[link]()

\n", + "example": 491, + "start_line": 7608, + "end_line": 7614, + "section": "Links" + }, + { + "markdown": "[a]()\n", + "html": "

a

\n", + "example": 492, + "start_line": 7619, + "end_line": 7623, + "section": "Links" + }, + { + "markdown": "[link]()\n", + "html": "

[link](<foo>)

\n", + "example": 493, + "start_line": 7627, + "end_line": 7631, + "section": "Links" + }, + { + "markdown": "[a](\n[a](c)\n", + "html": "

[a](<b)c\n[a](<b)c>\n[a](c)

\n", + "example": 494, + "start_line": 7636, + "end_line": 7644, + "section": "Links" + }, + { + "markdown": "[link](\\(foo\\))\n", + "html": "

link

\n", + "example": 495, + "start_line": 7648, + "end_line": 7652, + "section": "Links" + }, + { + "markdown": "[link](foo(and(bar)))\n", + "html": "

link

\n", + "example": 496, + "start_line": 7657, + "end_line": 7661, + "section": "Links" + }, + { + "markdown": "[link](foo(and(bar))\n", + "html": "

[link](foo(and(bar))

\n", + "example": 497, + "start_line": 7666, + "end_line": 7670, + "section": "Links" + }, + { + "markdown": "[link](foo\\(and\\(bar\\))\n", + "html": "

link

\n", + "example": 498, + "start_line": 7673, + "end_line": 7677, + "section": "Links" + }, + { + "markdown": "[link]()\n", + "html": "

link

\n", + "example": 499, + "start_line": 7680, + "end_line": 7684, + "section": "Links" + }, + { + "markdown": "[link](foo\\)\\:)\n", + "html": "

link

\n", + "example": 500, + "start_line": 7690, + "end_line": 7694, + "section": "Links" + }, + { + "markdown": "[link](#fragment)\n\n[link](https://example.com#fragment)\n\n[link](https://example.com?foo=3#frag)\n", + "html": "

link

\n

link

\n

link

\n", + "example": 501, + "start_line": 7699, + "end_line": 7709, + "section": "Links" + }, + { + "markdown": "[link](foo\\bar)\n", + "html": "

link

\n", + "example": 502, + "start_line": 7715, + "end_line": 7719, + "section": "Links" + }, + { + "markdown": "[link](foo%20bä)\n", + "html": "

link

\n", + "example": 503, + "start_line": 7731, + "end_line": 7735, + "section": "Links" + }, + { + "markdown": "[link](\"title\")\n", + "html": "

link

\n", + "example": 504, + "start_line": 7742, + "end_line": 7746, + "section": "Links" + }, + { + "markdown": "[link](/url \"title\")\n[link](/url 'title')\n[link](/url (title))\n", + "html": "

link\nlink\nlink

\n", + "example": 505, + "start_line": 7751, + "end_line": 7759, + "section": "Links" + }, + { + "markdown": "[link](/url \"title \\\""\")\n", + "html": "

link

\n", + "example": 506, + "start_line": 7765, + "end_line": 7769, + "section": "Links" + }, + { + "markdown": "[link](/url \"title\")\n", + "html": "

link

\n", + "example": 507, + "start_line": 7776, + "end_line": 7780, + "section": "Links" + }, + { + "markdown": "[link](/url \"title \"and\" title\")\n", + "html": "

[link](/url "title "and" title")

\n", + "example": 508, + "start_line": 7785, + "end_line": 7789, + "section": "Links" + }, + { + "markdown": "[link](/url 'title \"and\" title')\n", + "html": "

link

\n", + "example": 509, + "start_line": 7794, + "end_line": 7798, + "section": "Links" + }, + { + "markdown": "[link]( /uri\n \"title\" )\n", + "html": "

link

\n", + "example": 510, + "start_line": 7819, + "end_line": 7824, + "section": "Links" + }, + { + "markdown": "[link] (/uri)\n", + "html": "

[link] (/uri)

\n", + "example": 511, + "start_line": 7830, + "end_line": 7834, + "section": "Links" + }, + { + "markdown": "[link [foo [bar]]](/uri)\n", + "html": "

link [foo [bar]]

\n", + "example": 512, + "start_line": 7840, + "end_line": 7844, + "section": "Links" + }, + { + "markdown": "[link] bar](/uri)\n", + "html": "

[link] bar](/uri)

\n", + "example": 513, + "start_line": 7847, + "end_line": 7851, + "section": "Links" + }, + { + "markdown": "[link [bar](/uri)\n", + "html": "

[link bar

\n", + "example": 514, + "start_line": 7854, + "end_line": 7858, + "section": "Links" + }, + { + "markdown": "[link \\[bar](/uri)\n", + "html": "

link [bar

\n", + "example": 515, + "start_line": 7861, + "end_line": 7865, + "section": "Links" + }, + { + "markdown": "[link *foo **bar** `#`*](/uri)\n", + "html": "

link foo bar #

\n", + "example": 516, + "start_line": 7870, + "end_line": 7874, + "section": "Links" + }, + { + "markdown": "[![moon](moon.jpg)](/uri)\n", + "html": "

\"moon\"

\n", + "example": 517, + "start_line": 7877, + "end_line": 7881, + "section": "Links" + }, + { + "markdown": "[foo [bar](/uri)](/uri)\n", + "html": "

[foo bar](/uri)

\n", + "example": 518, + "start_line": 7886, + "end_line": 7890, + "section": "Links" + }, + { + "markdown": "[foo *[bar [baz](/uri)](/uri)*](/uri)\n", + "html": "

[foo [bar baz](/uri)](/uri)

\n", + "example": 519, + "start_line": 7893, + "end_line": 7897, + "section": "Links" + }, + { + "markdown": "![[[foo](uri1)](uri2)](uri3)\n", + "html": "

\"[foo](uri2)\"

\n", + "example": 520, + "start_line": 7900, + "end_line": 7904, + "section": "Links" + }, + { + "markdown": "*[foo*](/uri)\n", + "html": "

*foo*

\n", + "example": 521, + "start_line": 7910, + "end_line": 7914, + "section": "Links" + }, + { + "markdown": "[foo *bar](baz*)\n", + "html": "

foo *bar

\n", + "example": 522, + "start_line": 7917, + "end_line": 7921, + "section": "Links" + }, + { + "markdown": "*foo [bar* baz]\n", + "html": "

foo [bar baz]

\n", + "example": 523, + "start_line": 7927, + "end_line": 7931, + "section": "Links" + }, + { + "markdown": "[foo \n", + "html": "

[foo

\n", + "example": 524, + "start_line": 7937, + "end_line": 7941, + "section": "Links" + }, + { + "markdown": "[foo`](/uri)`\n", + "html": "

[foo](/uri)

\n", + "example": 525, + "start_line": 7944, + "end_line": 7948, + "section": "Links" + }, + { + "markdown": "[foo\n", + "html": "

[foohttps://example.com/?search=](uri)

\n", + "example": 526, + "start_line": 7951, + "end_line": 7955, + "section": "Links" + }, + { + "markdown": "[foo][bar]\n\n[bar]: /url \"title\"\n", + "html": "

foo

\n", + "example": 527, + "start_line": 7989, + "end_line": 7995, + "section": "Links" + }, + { + "markdown": "[link [foo [bar]]][ref]\n\n[ref]: /uri\n", + "html": "

link [foo [bar]]

\n", + "example": 528, + "start_line": 8004, + "end_line": 8010, + "section": "Links" + }, + { + "markdown": "[link \\[bar][ref]\n\n[ref]: /uri\n", + "html": "

link [bar

\n", + "example": 529, + "start_line": 8013, + "end_line": 8019, + "section": "Links" + }, + { + "markdown": "[link *foo **bar** `#`*][ref]\n\n[ref]: /uri\n", + "html": "

link foo bar #

\n", + "example": 530, + "start_line": 8024, + "end_line": 8030, + "section": "Links" + }, + { + "markdown": "[![moon](moon.jpg)][ref]\n\n[ref]: /uri\n", + "html": "

\"moon\"

\n", + "example": 531, + "start_line": 8033, + "end_line": 8039, + "section": "Links" + }, + { + "markdown": "[foo [bar](/uri)][ref]\n\n[ref]: /uri\n", + "html": "

[foo bar]ref

\n", + "example": 532, + "start_line": 8044, + "end_line": 8050, + "section": "Links" + }, + { + "markdown": "[foo *bar [baz][ref]*][ref]\n\n[ref]: /uri\n", + "html": "

[foo bar baz]ref

\n", + "example": 533, + "start_line": 8053, + "end_line": 8059, + "section": "Links" + }, + { + "markdown": "*[foo*][ref]\n\n[ref]: /uri\n", + "html": "

*foo*

\n", + "example": 534, + "start_line": 8068, + "end_line": 8074, + "section": "Links" + }, + { + "markdown": "[foo *bar][ref]*\n\n[ref]: /uri\n", + "html": "

foo *bar*

\n", + "example": 535, + "start_line": 8077, + "end_line": 8083, + "section": "Links" + }, + { + "markdown": "[foo \n\n[ref]: /uri\n", + "html": "

[foo

\n", + "example": 536, + "start_line": 8089, + "end_line": 8095, + "section": "Links" + }, + { + "markdown": "[foo`][ref]`\n\n[ref]: /uri\n", + "html": "

[foo][ref]

\n", + "example": 537, + "start_line": 8098, + "end_line": 8104, + "section": "Links" + }, + { + "markdown": "[foo\n\n[ref]: /uri\n", + "html": "

[foohttps://example.com/?search=][ref]

\n", + "example": 538, + "start_line": 8107, + "end_line": 8113, + "section": "Links" + }, + { + "markdown": "[foo][BaR]\n\n[bar]: /url \"title\"\n", + "html": "

foo

\n", + "example": 539, + "start_line": 8118, + "end_line": 8124, + "section": "Links" + }, + { + "markdown": "[ẞ]\n\n[SS]: /url\n", + "html": "

\n", + "example": 540, + "start_line": 8129, + "end_line": 8135, + "section": "Links" + }, + { + "markdown": "[Foo\n bar]: /url\n\n[Baz][Foo bar]\n", + "html": "

Baz

\n", + "example": 541, + "start_line": 8141, + "end_line": 8148, + "section": "Links" + }, + { + "markdown": "[foo] [bar]\n\n[bar]: /url \"title\"\n", + "html": "

[foo] bar

\n", + "example": 542, + "start_line": 8154, + "end_line": 8160, + "section": "Links" + }, + { + "markdown": "[foo]\n[bar]\n\n[bar]: /url \"title\"\n", + "html": "

[foo]\nbar

\n", + "example": 543, + "start_line": 8163, + "end_line": 8171, + "section": "Links" + }, + { + "markdown": "[foo]: /url1\n\n[foo]: /url2\n\n[bar][foo]\n", + "html": "

bar

\n", + "example": 544, + "start_line": 8204, + "end_line": 8212, + "section": "Links" + }, + { + "markdown": "[bar][foo\\!]\n\n[foo!]: /url\n", + "html": "

[bar][foo!]

\n", + "example": 545, + "start_line": 8219, + "end_line": 8225, + "section": "Links" + }, + { + "markdown": "[foo][ref[]\n\n[ref[]: /uri\n", + "html": "

[foo][ref[]

\n

[ref[]: /uri

\n", + "example": 546, + "start_line": 8231, + "end_line": 8238, + "section": "Links" + }, + { + "markdown": "[foo][ref[bar]]\n\n[ref[bar]]: /uri\n", + "html": "

[foo][ref[bar]]

\n

[ref[bar]]: /uri

\n", + "example": 547, + "start_line": 8241, + "end_line": 8248, + "section": "Links" + }, + { + "markdown": "[[[foo]]]\n\n[[[foo]]]: /url\n", + "html": "

[[[foo]]]

\n

[[[foo]]]: /url

\n", + "example": 548, + "start_line": 8251, + "end_line": 8258, + "section": "Links" + }, + { + "markdown": "[foo][ref\\[]\n\n[ref\\[]: /uri\n", + "html": "

foo

\n", + "example": 549, + "start_line": 8261, + "end_line": 8267, + "section": "Links" + }, + { + "markdown": "[bar\\\\]: /uri\n\n[bar\\\\]\n", + "html": "

bar\\

\n", + "example": 550, + "start_line": 8272, + "end_line": 8278, + "section": "Links" + }, + { + "markdown": "[]\n\n[]: /uri\n", + "html": "

[]

\n

[]: /uri

\n", + "example": 551, + "start_line": 8284, + "end_line": 8291, + "section": "Links" + }, + { + "markdown": "[\n ]\n\n[\n ]: /uri\n", + "html": "

[\n]

\n

[\n]: /uri

\n", + "example": 552, + "start_line": 8294, + "end_line": 8305, + "section": "Links" + }, + { + "markdown": "[foo][]\n\n[foo]: /url \"title\"\n", + "html": "

foo

\n", + "example": 553, + "start_line": 8317, + "end_line": 8323, + "section": "Links" + }, + { + "markdown": "[*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

foo bar

\n", + "example": 554, + "start_line": 8326, + "end_line": 8332, + "section": "Links" + }, + { + "markdown": "[Foo][]\n\n[foo]: /url \"title\"\n", + "html": "

Foo

\n", + "example": 555, + "start_line": 8337, + "end_line": 8343, + "section": "Links" + }, + { + "markdown": "[foo] \n[]\n\n[foo]: /url \"title\"\n", + "html": "

foo\n[]

\n", + "example": 556, + "start_line": 8350, + "end_line": 8358, + "section": "Links" + }, + { + "markdown": "[foo]\n\n[foo]: /url \"title\"\n", + "html": "

foo

\n", + "example": 557, + "start_line": 8370, + "end_line": 8376, + "section": "Links" + }, + { + "markdown": "[*foo* bar]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

foo bar

\n", + "example": 558, + "start_line": 8379, + "end_line": 8385, + "section": "Links" + }, + { + "markdown": "[[*foo* bar]]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

[foo bar]

\n", + "example": 559, + "start_line": 8388, + "end_line": 8394, + "section": "Links" + }, + { + "markdown": "[[bar [foo]\n\n[foo]: /url\n", + "html": "

[[bar foo

\n", + "example": 560, + "start_line": 8397, + "end_line": 8403, + "section": "Links" + }, + { + "markdown": "[Foo]\n\n[foo]: /url \"title\"\n", + "html": "

Foo

\n", + "example": 561, + "start_line": 8408, + "end_line": 8414, + "section": "Links" + }, + { + "markdown": "[foo] bar\n\n[foo]: /url\n", + "html": "

foo bar

\n", + "example": 562, + "start_line": 8419, + "end_line": 8425, + "section": "Links" + }, + { + "markdown": "\\[foo]\n\n[foo]: /url \"title\"\n", + "html": "

[foo]

\n", + "example": 563, + "start_line": 8431, + "end_line": 8437, + "section": "Links" + }, + { + "markdown": "[foo*]: /url\n\n*[foo*]\n", + "html": "

*foo*

\n", + "example": 564, + "start_line": 8443, + "end_line": 8449, + "section": "Links" + }, + { + "markdown": "[foo][bar]\n\n[foo]: /url1\n[bar]: /url2\n", + "html": "

foo

\n", + "example": 565, + "start_line": 8455, + "end_line": 8462, + "section": "Links" + }, + { + "markdown": "[foo][]\n\n[foo]: /url1\n", + "html": "

foo

\n", + "example": 566, + "start_line": 8464, + "end_line": 8470, + "section": "Links" + }, + { + "markdown": "[foo]()\n\n[foo]: /url1\n", + "html": "

foo

\n", + "example": 567, + "start_line": 8474, + "end_line": 8480, + "section": "Links" + }, + { + "markdown": "[foo](not a link)\n\n[foo]: /url1\n", + "html": "

foo(not a link)

\n", + "example": 568, + "start_line": 8482, + "end_line": 8488, + "section": "Links" + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url\n", + "html": "

[foo]bar

\n", + "example": 569, + "start_line": 8493, + "end_line": 8499, + "section": "Links" + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[bar]: /url2\n", + "html": "

foobaz

\n", + "example": 570, + "start_line": 8505, + "end_line": 8512, + "section": "Links" + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[foo]: /url2\n", + "html": "

[foo]bar

\n", + "example": 571, + "start_line": 8518, + "end_line": 8525, + "section": "Links" + }, + { + "markdown": "![foo](/url \"title\")\n", + "html": "

\"foo\"

\n", + "example": 572, + "start_line": 8541, + "end_line": 8545, + "section": "Images" + }, + { + "markdown": "![foo *bar*]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n", + "html": "

\"foo

\n", + "example": 573, + "start_line": 8548, + "end_line": 8554, + "section": "Images" + }, + { + "markdown": "![foo ![bar](/url)](/url2)\n", + "html": "

\"foo

\n", + "example": 574, + "start_line": 8557, + "end_line": 8561, + "section": "Images" + }, + { + "markdown": "![foo [bar](/url)](/url2)\n", + "html": "

\"foo

\n", + "example": 575, + "start_line": 8564, + "end_line": 8568, + "section": "Images" + }, + { + "markdown": "![foo *bar*][]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n", + "html": "

\"foo

\n", + "example": 576, + "start_line": 8578, + "end_line": 8584, + "section": "Images" + }, + { + "markdown": "![foo *bar*][foobar]\n\n[FOOBAR]: train.jpg \"train & tracks\"\n", + "html": "

\"foo

\n", + "example": 577, + "start_line": 8587, + "end_line": 8593, + "section": "Images" + }, + { + "markdown": "![foo](train.jpg)\n", + "html": "

\"foo\"

\n", + "example": 578, + "start_line": 8596, + "end_line": 8600, + "section": "Images" + }, + { + "markdown": "My ![foo bar](/path/to/train.jpg \"title\" )\n", + "html": "

My \"foo

\n", + "example": 579, + "start_line": 8603, + "end_line": 8607, + "section": "Images" + }, + { + "markdown": "![foo]()\n", + "html": "

\"foo\"

\n", + "example": 580, + "start_line": 8610, + "end_line": 8614, + "section": "Images" + }, + { + "markdown": "![](/url)\n", + "html": "

\"\"

\n", + "example": 581, + "start_line": 8617, + "end_line": 8621, + "section": "Images" + }, + { + "markdown": "![foo][bar]\n\n[bar]: /url\n", + "html": "

\"foo\"

\n", + "example": 582, + "start_line": 8626, + "end_line": 8632, + "section": "Images" + }, + { + "markdown": "![foo][bar]\n\n[BAR]: /url\n", + "html": "

\"foo\"

\n", + "example": 583, + "start_line": 8635, + "end_line": 8641, + "section": "Images" + }, + { + "markdown": "![foo][]\n\n[foo]: /url \"title\"\n", + "html": "

\"foo\"

\n", + "example": 584, + "start_line": 8646, + "end_line": 8652, + "section": "Images" + }, + { + "markdown": "![*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

\"foo

\n", + "example": 585, + "start_line": 8655, + "end_line": 8661, + "section": "Images" + }, + { + "markdown": "![Foo][]\n\n[foo]: /url \"title\"\n", + "html": "

\"Foo\"

\n", + "example": 586, + "start_line": 8666, + "end_line": 8672, + "section": "Images" + }, + { + "markdown": "![foo] \n[]\n\n[foo]: /url \"title\"\n", + "html": "

\"foo\"\n[]

\n", + "example": 587, + "start_line": 8678, + "end_line": 8686, + "section": "Images" + }, + { + "markdown": "![foo]\n\n[foo]: /url \"title\"\n", + "html": "

\"foo\"

\n", + "example": 588, + "start_line": 8691, + "end_line": 8697, + "section": "Images" + }, + { + "markdown": "![*foo* bar]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

\"foo

\n", + "example": 589, + "start_line": 8700, + "end_line": 8706, + "section": "Images" + }, + { + "markdown": "![[foo]]\n\n[[foo]]: /url \"title\"\n", + "html": "

![[foo]]

\n

[[foo]]: /url "title"

\n", + "example": 590, + "start_line": 8711, + "end_line": 8718, + "section": "Images" + }, + { + "markdown": "![Foo]\n\n[foo]: /url \"title\"\n", + "html": "

\"Foo\"

\n", + "example": 591, + "start_line": 8723, + "end_line": 8729, + "section": "Images" + }, + { + "markdown": "!\\[foo]\n\n[foo]: /url \"title\"\n", + "html": "

![foo]

\n", + "example": 592, + "start_line": 8735, + "end_line": 8741, + "section": "Images" + }, + { + "markdown": "\\![foo]\n\n[foo]: /url \"title\"\n", + "html": "

!foo

\n", + "example": 593, + "start_line": 8747, + "end_line": 8753, + "section": "Images" + }, + { + "markdown": "\n", + "html": "

http://foo.bar.baz

\n", + "example": 594, + "start_line": 8780, + "end_line": 8784, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

https://foo.bar.baz/test?q=hello&id=22&boolean

\n", + "example": 595, + "start_line": 8787, + "end_line": 8791, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

irc://foo.bar:2233/baz

\n", + "example": 596, + "start_line": 8794, + "end_line": 8798, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

MAILTO:FOO@BAR.BAZ

\n", + "example": 597, + "start_line": 8803, + "end_line": 8807, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

a+b+c:d

\n", + "example": 598, + "start_line": 8815, + "end_line": 8819, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

made-up-scheme://foo,bar

\n", + "example": 599, + "start_line": 8822, + "end_line": 8826, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

https://../

\n", + "example": 600, + "start_line": 8829, + "end_line": 8833, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

localhost:5001/foo

\n", + "example": 601, + "start_line": 8836, + "end_line": 8840, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

<https://foo.bar/baz bim>

\n", + "example": 602, + "start_line": 8845, + "end_line": 8849, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

https://example.com/\\[\\

\n", + "example": 603, + "start_line": 8854, + "end_line": 8858, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

foo@bar.example.com

\n", + "example": 604, + "start_line": 8876, + "end_line": 8880, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

foo+special@Bar.baz-bar0.com

\n", + "example": 605, + "start_line": 8883, + "end_line": 8887, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

<foo+@bar.example.com>

\n", + "example": 606, + "start_line": 8892, + "end_line": 8896, + "section": "Autolinks" + }, + { + "markdown": "<>\n", + "html": "

<>

\n", + "example": 607, + "start_line": 8901, + "end_line": 8905, + "section": "Autolinks" + }, + { + "markdown": "< https://foo.bar >\n", + "html": "

< https://foo.bar >

\n", + "example": 608, + "start_line": 8908, + "end_line": 8912, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

<m:abc>

\n", + "example": 609, + "start_line": 8915, + "end_line": 8919, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

<foo.bar.baz>

\n", + "example": 610, + "start_line": 8922, + "end_line": 8926, + "section": "Autolinks" + }, + { + "markdown": "https://example.com\n", + "html": "

https://example.com

\n", + "example": 611, + "start_line": 8929, + "end_line": 8933, + "section": "Autolinks" + }, + { + "markdown": "foo@bar.example.com\n", + "html": "

foo@bar.example.com

\n", + "example": 612, + "start_line": 8936, + "end_line": 8940, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 613, + "start_line": 9016, + "end_line": 9020, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 614, + "start_line": 9025, + "end_line": 9029, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 615, + "start_line": 9034, + "end_line": 9040, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 616, + "start_line": 9045, + "end_line": 9051, + "section": "Raw HTML" + }, + { + "markdown": "Foo \n", + "html": "

Foo

\n", + "example": 617, + "start_line": 9056, + "end_line": 9060, + "section": "Raw HTML" + }, + { + "markdown": "<33> <__>\n", + "html": "

<33> <__>

\n", + "example": 618, + "start_line": 9065, + "end_line": 9069, + "section": "Raw HTML" + }, + { + "markdown": "
\n", + "html": "

<a h*#ref="hi">

\n", + "example": 619, + "start_line": 9074, + "end_line": 9078, + "section": "Raw HTML" + }, + { + "markdown": "
\n", + "html": "

<a href="hi'> <a href=hi'>

\n", + "example": 620, + "start_line": 9083, + "end_line": 9087, + "section": "Raw HTML" + }, + { + "markdown": "< a><\nfoo>\n\n", + "html": "

< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop />

\n", + "example": 621, + "start_line": 9092, + "end_line": 9102, + "section": "Raw HTML" + }, + { + "markdown": "
\n", + "html": "

<a href='bar'title=title>

\n", + "example": 622, + "start_line": 9107, + "end_line": 9111, + "section": "Raw HTML" + }, + { + "markdown": "
\n", + "html": "

\n", + "example": 623, + "start_line": 9116, + "end_line": 9120, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

</a href="foo">

\n", + "example": 624, + "start_line": 9125, + "end_line": 9129, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 625, + "start_line": 9134, + "end_line": 9140, + "section": "Raw HTML" + }, + { + "markdown": "foo foo -->\n\nfoo foo -->\n", + "html": "

foo foo -->

\n

foo foo -->

\n", + "example": 626, + "start_line": 9142, + "end_line": 9149, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 627, + "start_line": 9154, + "end_line": 9158, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 628, + "start_line": 9163, + "end_line": 9167, + "section": "Raw HTML" + }, + { + "markdown": "foo &<]]>\n", + "html": "

foo &<]]>

\n", + "example": 629, + "start_line": 9172, + "end_line": 9176, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 630, + "start_line": 9182, + "end_line": 9186, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 631, + "start_line": 9191, + "end_line": 9195, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

<a href=""">

\n", + "example": 632, + "start_line": 9198, + "end_line": 9202, + "section": "Raw HTML" + }, + { + "markdown": "foo \nbaz\n", + "html": "

foo
\nbaz

\n", + "example": 633, + "start_line": 9212, + "end_line": 9218, + "section": "Hard line breaks" + }, + { + "markdown": "foo\\\nbaz\n", + "html": "

foo
\nbaz

\n", + "example": 634, + "start_line": 9224, + "end_line": 9230, + "section": "Hard line breaks" + }, + { + "markdown": "foo \nbaz\n", + "html": "

foo
\nbaz

\n", + "example": 635, + "start_line": 9235, + "end_line": 9241, + "section": "Hard line breaks" + }, + { + "markdown": "foo \n bar\n", + "html": "

foo
\nbar

\n", + "example": 636, + "start_line": 9246, + "end_line": 9252, + "section": "Hard line breaks" + }, + { + "markdown": "foo\\\n bar\n", + "html": "

foo
\nbar

\n", + "example": 637, + "start_line": 9255, + "end_line": 9261, + "section": "Hard line breaks" + }, + { + "markdown": "*foo \nbar*\n", + "html": "

foo
\nbar

\n", + "example": 638, + "start_line": 9267, + "end_line": 9273, + "section": "Hard line breaks" + }, + { + "markdown": "*foo\\\nbar*\n", + "html": "

foo
\nbar

\n", + "example": 639, + "start_line": 9276, + "end_line": 9282, + "section": "Hard line breaks" + }, + { + "markdown": "`code \nspan`\n", + "html": "

code span

\n", + "example": 640, + "start_line": 9287, + "end_line": 9292, + "section": "Hard line breaks" + }, + { + "markdown": "`code\\\nspan`\n", + "html": "

code\\ span

\n", + "example": 641, + "start_line": 9295, + "end_line": 9300, + "section": "Hard line breaks" + }, + { + "markdown": "
\n", + "html": "

\n", + "example": 642, + "start_line": 9305, + "end_line": 9311, + "section": "Hard line breaks" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 643, + "start_line": 9314, + "end_line": 9320, + "section": "Hard line breaks" + }, + { + "markdown": "foo\\\n", + "html": "

foo\\

\n", + "example": 644, + "start_line": 9327, + "end_line": 9331, + "section": "Hard line breaks" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 645, + "start_line": 9334, + "end_line": 9338, + "section": "Hard line breaks" + }, + { + "markdown": "### foo\\\n", + "html": "

foo\\

\n", + "example": 646, + "start_line": 9341, + "end_line": 9345, + "section": "Hard line breaks" + }, + { + "markdown": "### foo \n", + "html": "

foo

\n", + "example": 647, + "start_line": 9348, + "end_line": 9352, + "section": "Hard line breaks" + }, + { + "markdown": "foo\nbaz\n", + "html": "

foo\nbaz

\n", + "example": 648, + "start_line": 9363, + "end_line": 9369, + "section": "Soft line breaks" + }, + { + "markdown": "foo \n baz\n", + "html": "

foo\nbaz

\n", + "example": 649, + "start_line": 9375, + "end_line": 9381, + "section": "Soft line breaks" + }, + { + "markdown": "hello $.;'there\n", + "html": "

hello $.;'there

\n", + "example": 650, + "start_line": 9395, + "end_line": 9399, + "section": "Textual content" + }, + { + "markdown": "Foo χρῆν\n", + "html": "

Foo χρῆν

\n", + "example": 651, + "start_line": 9402, + "end_line": 9406, + "section": "Textual content" + }, + { + "markdown": "Multiple spaces\n", + "html": "

Multiple spaces

\n", + "example": 652, + "start_line": 9411, + "end_line": 9415, + "section": "Textual content" + } +] \ No newline at end of file diff --git a/src/ReverseMarkdown/Config.cs b/src/ReverseMarkdown/Config.cs index 7252771..10bef88 100644 --- a/src/ReverseMarkdown/Config.cs +++ b/src/ReverseMarkdown/Config.cs @@ -11,6 +11,21 @@ public class Config public bool SlackFlavored { get; set; } = false; + /// + /// Enable CommonMark compatible emphasis handling (avoid intraword emphasis by inserting spaces). + /// + public bool CommonMark { get; set; } = false; + + /// + /// When CommonMark is enabled, insert spaces to avoid intraword emphasis. + /// + public bool CommonMarkIntrawordEmphasisSpacing { get; set; } = false; + + /// + /// When CommonMark is enabled, emit HTML for inline tags (em/strong/a/img) to avoid delimiter edge cases. + /// + public bool CommonMarkUseHtmlInlineTags { get; set; } = true; + public bool SuppressDivNewlines { get; set; } = false; public bool RemoveComments { get; set; } = false; diff --git a/src/ReverseMarkdown/Converter.cs b/src/ReverseMarkdown/Converter.cs index 48a256e..a5e7de8 100644 --- a/src/ReverseMarkdown/Converter.cs +++ b/src/ReverseMarkdown/Converter.cs @@ -95,6 +95,33 @@ public Converter(Config config, params Assembly[]? additionalAssemblies) public virtual string Convert(string html) { using var _ = EnsureContext(); + + if (Config.CommonMark && LooksLikeCommonMarkHtmlBlock(html)) { + return html; + } + + if (Config.CommonMark) { + var trimmed = html.TrimStart('\uFEFF', ' ', '\t', '\r', '\n'); + if (trimmed.StartsWith("", StringComparison.OrdinalIgnoreCase) && + paragraphTrimmed.EndsWith("

", StringComparison.OrdinalIgnoreCase)) { + var inner = paragraphTrimmed.Substring(3, paragraphTrimmed.Length - 7); + if (inner.TrimStart().StartsWith("", StringComparison.Ordinal))) { + WriteRawHtmlAnchor(writer, node, EncodeAnchorText(node.InnerText)); + return; + } + + + + if (isCommonMark && (name.Contains('[') || name.Contains(']') || name.Contains('\n'))) { + writer.Write(node.OuterHtml); + return; + } + + var hrefAttribute = node.Attributes["href"]; + var hasHrefAttribute = hrefAttribute != null; + var href = node.GetAttributeValue("href", string.Empty).Trim(); + if (!isCommonMark) { + href = href.Replace(_escapeValues); + } + else { + href = href.Replace("\\", "\\\\"); + href = href.Replace("*", "\\*").Replace("_", "\\_"); + if (href.Contains('\n') || href.Contains('\r')) { + writer.Write(node.OuterHtml); + return; + } + var openCount = href.Count(c => c == '('); + var closeCount = href.Count(c => c == ')'); + if (closeCount > openCount) { + href = href.Replace(")", "\\)"); + } + if (href.Contains(' ') || href.Contains('(') || href.Contains(')')) { + href = $"<{href.Replace("<", "%3C").Replace(">", "%3E")}>"; + } + } + + if (isCommonMark && !hasHrefAttribute) { + writer.Write(node.OuterHtml); + return; + } + + if (isCommonMark && + node.OuterHtml.IndexOf("href=", StringComparison.OrdinalIgnoreCase) < 0) { + writer.Write(node.OuterHtml); + return; + } + + if (isCommonMark && hrefAttribute != null) { + if (hrefAttribute.Value.Contains("&", StringComparison.Ordinal) || + hrefAttribute.Value.Contains("\\", StringComparison.Ordinal)) { + writer.Write(node.OuterHtml); + return; + } + + var outerHtml = node.OuterHtml; + if (outerHtml.Contains("href=\"&", StringComparison.OrdinalIgnoreCase) || + outerHtml.Contains("href='&", StringComparison.OrdinalIgnoreCase) || + outerHtml.Contains("href=\"\\", StringComparison.OrdinalIgnoreCase) || + outerHtml.Contains("href='\\", StringComparison.OrdinalIgnoreCase)) { + writer.Write(outerHtml); + return; + } - var href = node.GetAttributeValue("href", string.Empty).Trim().Replace(_escapeValues); + var text = node.InnerText; + if (text.Contains("\\", StringComparison.Ordinal) || + text.Contains("[", StringComparison.Ordinal) || + text.Contains("]", StringComparison.Ordinal) || + text.Contains("<", StringComparison.Ordinal) || + text.Contains("*", StringComparison.Ordinal) || + text.Contains("_", StringComparison.Ordinal)) { + writer.Write(node.OuterHtml); + return; + } + } + + if (isCommonMark && string.IsNullOrEmpty(name)) { + if (!hasHrefAttribute) { + writer.Write(node.OuterHtml); + } + else if (string.IsNullOrEmpty(href)) { + writer.Write("[]()"); + } + else { + writer.Write("[]("); + writer.Write(href); + writer.Write(")"); + } + + return; + } + + if (isCommonMark && hrefAttribute != null && + hrefAttribute.Value.Contains("&", StringComparison.Ordinal)) { + writer.Write(node.OuterHtml); + return; + } + + if (isCommonMark && href.Contains('`')) { + writer.Write(node.OuterHtml); + return; + } var scheme = StringUtils.GetScheme(href); var isRemoveLinkWhenSameName = ( @@ -35,10 +145,10 @@ public override void Convert(TextWriter writer, HtmlNode node) ) ); - if (href.StartsWith("#") //anchor link + if ((!Converter.Config.CommonMark && href.StartsWith("#")) //anchor link || !Converter.Config.IsSchemeWhitelisted(scheme) //Not allowed scheme || isRemoveLinkWhenSameName - || string.IsNullOrEmpty(href) //We would otherwise print empty () here... + || (string.IsNullOrEmpty(href) && !Converter.Config.CommonMark) //We would otherwise print empty () here... ) { writer.Write(name); return; @@ -61,7 +171,13 @@ public override void Convert(TextWriter writer, HtmlNode node) var linkText = hasSingleChildImgNode ? name : StringUtils.EscapeLinkText(name); if (string.IsNullOrEmpty(linkText)) { - writer.Write(href); + if (Converter.Config.CommonMark && string.IsNullOrEmpty(href)) { + writer.Write("[]()"); + } + else { + writer.Write(href); + } + return; } @@ -83,5 +199,26 @@ public override void Convert(TextWriter writer, HtmlNode node) writer.Write(")"); } } + + private static void WriteRawHtmlAnchor(TextWriter writer, HtmlNode node, string text) + { + writer.Write("'); + writer.Write(text); + writer.Write("
"); + } + + private static string EncodeAnchorText(string text) + { + return text.Replace("\\", "\").Replace("<", "<").Replace(">", ">"); + } } } diff --git a/src/ReverseMarkdown/Converters/Br.cs b/src/ReverseMarkdown/Converters/Br.cs index 258b56c..1f06bc9 100644 --- a/src/ReverseMarkdown/Converters/Br.cs +++ b/src/ReverseMarkdown/Converters/Br.cs @@ -12,10 +12,15 @@ public Br(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { if (node.ParentNode.Name is "strong" or "b" or "em" or "i") { - return; + if (!Converter.Config.CommonMark) { + return; + } } - if (Converter.Config.GithubFlavored) { + if (Converter.Config.CommonMark) { + writer.WriteLine("\\"); + } + else if (Converter.Config.GithubFlavored) { writer.WriteLine(); } else { diff --git a/src/ReverseMarkdown/Converters/Code.cs b/src/ReverseMarkdown/Converters/Code.cs index 5255474..d18b995 100644 --- a/src/ReverseMarkdown/Converters/Code.cs +++ b/src/ReverseMarkdown/Converters/Code.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using HtmlAgilityPack; @@ -11,6 +12,29 @@ public Code(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { + if (Converter.Config.CommonMark) { + var content = node.InnerHtml; + var fence = CreateCommonMarkCodeFence(content); + writer.Write(fence); + var needsBacktickPadding = content.Length > 0 && (content[0] == '`' || content[^1] == '`'); + var needsWhitespacePadding = content.Length > 0 && + (char.IsWhiteSpace(content[0]) || char.IsWhiteSpace(content[^1])); + var needsPadding = needsBacktickPadding || needsWhitespacePadding; + + if (needsPadding) { + writer.Write(' '); + } + + DecodeHtml(writer, content); + + if (needsPadding) { + writer.Write(' '); + } + + writer.Write(fence); + return; + } + // Depending on the content "surrounding" the element, // leading/trailing whitespace is significant. For example, the // following HTML renders as expected in a browser (meaning there is @@ -53,5 +77,25 @@ public override void Convert(TextWriter writer, HtmlNode node) DecodeHtml(writer, node.InnerText); writer.Write('`'); } + + private static string CreateCommonMarkCodeFence(string content) + { + var maxRun = 0; + var currentRun = 0; + foreach (var c in content) { + if (c == '`') { + currentRun++; + if (currentRun > maxRun) { + maxRun = currentRun; + } + } + else { + currentRun = 0; + } + } + + var fenceLength = Math.Max(1, maxRun + 1); + return new string('`', fenceLength); + } } } diff --git a/src/ReverseMarkdown/Converters/ConverterBase.cs b/src/ReverseMarkdown/Converters/ConverterBase.cs index 125df1f..f7268bd 100644 --- a/src/ReverseMarkdown/Converters/ConverterBase.cs +++ b/src/ReverseMarkdown/Converters/ConverterBase.cs @@ -53,6 +53,7 @@ protected static void DecodeHtml(TextWriter writer, string html) protected string IndentationFor(HtmlNode node, bool zeroIndex = false) { var length = Context.AncestorsCount("ol") + Context.AncestorsCount("ul"); + var indentSize = Converter.Config.CommonMark ? 2 : 4; // li not required to have a parent ol/ul if (length == 0) { @@ -63,15 +64,21 @@ protected string IndentationFor(HtmlNode node, bool zeroIndex = false) length -= 1; } - return new string(' ', length * 4); + return new string(' ', length * indentSize); } - public static void TreatEmphasizeContentWhitespaceGuard(TextWriter writer, string content, string emphasis, string nextSiblingSpaceSuffix = "") + public static void TreatEmphasizeContentWhitespaceGuard( + TextWriter writer, + string content, + string emphasis, + string nextSiblingSpaceSuffix = "", + bool preserveLineEndings = false + ) { WriteLeadingSpace(writer, content); writer.Write(emphasis); - writer.Write(content.Chomp()); + writer.Write(preserveLineEndings ? content.Trim(' ') : content.Chomp()); writer.Write(emphasis); WriteTrailingSpace(writer, content, nextSiblingSpaceSuffix); diff --git a/src/ReverseMarkdown/Converters/Div.cs b/src/ReverseMarkdown/Converters/Div.cs index 1c6ca05..1570e50 100644 --- a/src/ReverseMarkdown/Converters/Div.cs +++ b/src/ReverseMarkdown/Converters/Div.cs @@ -19,6 +19,11 @@ public Div(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { + if (Converter.Config.CommonMark) { + writer.Write(node.OuterHtml); + return; + } + while (node.ChildNodes.Count == 1 && node.FirstChild.Name == "div") { node = node.FirstChild; } diff --git a/src/ReverseMarkdown/Converters/Em.cs b/src/ReverseMarkdown/Converters/Em.cs index 885611a..97aab02 100644 --- a/src/ReverseMarkdown/Converters/Em.cs +++ b/src/ReverseMarkdown/Converters/Em.cs @@ -12,24 +12,134 @@ public Em(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { + var isCommonMark = Converter.Config.CommonMark; + if (isCommonMark && Converter.Config.CommonMarkUseHtmlInlineTags) { + var innerHtml = node.InnerHtml; + if (innerHtml.Contains('[') || innerHtml.Contains(']')) { + writer.Write('<'); + writer.Write(node.Name); + foreach (var attribute in node.Attributes) { + writer.Write(' '); + writer.Write(attribute.Name); + writer.Write("=\""); + writer.Write(attribute.Value); + writer.Write('"'); + } + + writer.Write('>'); + writer.Write(innerHtml.Replace("[", "[").Replace("]", "]")); + writer.Write("'); + } + else { + writer.Write(node.OuterHtml); + } + + return; + } + var content = TreatChildrenAsString(node); - if (string.IsNullOrWhiteSpace(content) || AlreadyItalic()) { + if (string.IsNullOrWhiteSpace(content) || (!isCommonMark && AlreadyItalic())) { writer.Write(content); return; } + var commonMarkPrefix = string.Empty; + var commonMarkSuffix = string.Empty; + if (isCommonMark && Converter.Config.CommonMarkIntrawordEmphasisSpacing) { + var contentFirst = FirstNonWhitespaceChar(content); + var contentLast = LastNonWhitespaceChar(content); + var contentHasLeadingWhitespace = content.Length > 0 && char.IsWhiteSpace(content[0]); + var contentHasTrailingWhitespace = content.Length > 0 && char.IsWhiteSpace(content[content.Length - 1]); + + if (IsWordChar(contentFirst) && IsWordChar(contentLast)) { + var hasPrevWord = !contentHasLeadingWhitespace && + IsAdjacentWordChar(node.PreviousSibling, checkEnd: true); + var hasNextWord = !contentHasTrailingWhitespace && + IsAdjacentWordChar(node.NextSibling, checkEnd: false); + if (hasPrevWord && hasNextWord) { + commonMarkPrefix = " "; + commonMarkSuffix = " "; + } + } + } + var spaceSuffix = node.NextSibling?.Name is "i" or "em" ? " " : string.Empty; - var emphasis = Converter.Config.SlackFlavored ? "_" : "*"; - TreatEmphasizeContentWhitespaceGuard(writer, content, emphasis, spaceSuffix); + var emphasis = Converter.Config.SlackFlavored + ? "_" + : isCommonMark && Context.AncestorsAny("i") + ? "_" + : "*"; + var suffix = commonMarkSuffix.Length > 0 || spaceSuffix.Length > 0 ? " " : string.Empty; + if (commonMarkPrefix.Length > 0) { + writer.Write(commonMarkPrefix); + } + + TreatEmphasizeContentWhitespaceGuard( + writer, + content, + emphasis, + suffix, + preserveLineEndings: isCommonMark + ); } private bool AlreadyItalic() { return Context.AncestorsAny("i") || Context.AncestorsAny("em"); } + + private static bool IsWordChar(char? value) + { + return value.HasValue && char.IsLetterOrDigit(value.Value); + } + + private static char? FirstNonWhitespaceChar(string content) + { + foreach (var c in content) { + if (!char.IsWhiteSpace(c)) { + return c; + } + } + + return null; + } + + private static char? LastNonWhitespaceChar(string content) + { + for (var i = content.Length - 1; i >= 0; i--) { + var c = content[i]; + if (!char.IsWhiteSpace(c)) { + return c; + } + } + + return null; + } + + private static bool IsAdjacentWordChar(HtmlNode? sibling, bool checkEnd) + { + if (sibling == null) { + return false; + } + + var text = sibling.InnerText; + if (string.IsNullOrEmpty(text)) { + return false; + } + + var index = checkEnd ? text.Length - 1 : 0; + var c = text[index]; + if (char.IsWhiteSpace(c)) { + return false; + } + + return char.IsLetterOrDigit(c); + } } } diff --git a/src/ReverseMarkdown/Converters/H.cs b/src/ReverseMarkdown/Converters/H.cs index fe9fea5..2030ee4 100644 --- a/src/ReverseMarkdown/Converters/H.cs +++ b/src/ReverseMarkdown/Converters/H.cs @@ -24,11 +24,38 @@ public override void Convert(TextWriter writer, HtmlNode node) var level = node.Name[1] - '0'; // 'h1' -> 1, 'h2' -> 2, etc. + var content = TreatChildrenAsString(node); + if (Converter.Config.CommonMark) { + content = content.ReplaceLineEndings(" "); + content = EscapeTrailingHashes(content); + } + writer.WriteLine(); writer.Write(new string('#', level)); writer.Write(' '); - TreatChildren(writer, node); + writer.Write(content); writer.WriteLine(); } + + private static string EscapeTrailingHashes(string content) + { + if (string.IsNullOrEmpty(content)) { + return content; + } + + var index = content.Length - 1; + while (index >= 0 && content[index] == '#') { + index--; + } + + if (index == content.Length - 1) { + return content; + } + + var hashCount = content.Length - 1 - index; + var escapedHashes = new string('#', hashCount); + escapedHashes = escapedHashes.Replace("#", "\\#"); + return content[..(index + 1)] + escapedHashes; + } } } diff --git a/src/ReverseMarkdown/Converters/Img.cs b/src/ReverseMarkdown/Converters/Img.cs index 55ecf1b..9269b76 100644 --- a/src/ReverseMarkdown/Converters/Img.cs +++ b/src/ReverseMarkdown/Converters/Img.cs @@ -18,6 +18,7 @@ public override void Convert(TextWriter writer, HtmlNode node) throw new SlackUnsupportedTagException(node.Name); } + var altAttribute = node.Attributes["alt"]; var alt = node.GetAttributeValue("alt", string.Empty); var src = node.GetAttributeValue("src", string.Empty); @@ -58,6 +59,11 @@ public override void Convert(TextWriter writer, HtmlNode node) } } + if (Converter.Config.CommonMark && altAttribute == null) { + writer.Write(node.OuterHtml); + return; + } + writer.Write("!["); writer.Write(StringUtils.EscapeLinkText(alt)); writer.Write("]("); diff --git a/src/ReverseMarkdown/Converters/Li.cs b/src/ReverseMarkdown/Converters/Li.cs index ebb9ea1..47b44db 100644 --- a/src/ReverseMarkdown/Converters/Li.cs +++ b/src/ReverseMarkdown/Converters/Li.cs @@ -22,11 +22,13 @@ public override void Convert(TextWriter writer, HtmlNode node) } } - writer.Write(IndentationFor(node, true)); + var baseIndentation = IndentationFor(node, true); + writer.Write(baseIndentation); if (node.ParentNode is { Name: "ol" }) { // index are zero based hence add one - var index = node.ParentNode.SelectNodes("./li").IndexOf(node) + 1; + var start = node.ParentNode.GetAttributeValue("start", 1); + var index = node.ParentNode.SelectNodes("./li").IndexOf(node) + start; writer.Write(index); writer.Write(". "); } @@ -35,9 +37,44 @@ public override void Convert(TextWriter writer, HtmlNode node) writer.Write(' '); } - var content = ContentFor(node).Trim(); - writer.Write(content); - writer.WriteLine(); + var content = ContentFor(node); + + if (!Converter.Config.CommonMark) { + content = content.Trim(); + writer.Write(content); + writer.WriteLine(); + return; + } + + var markerLength = node.ParentNode is { Name: "ol" } + ? ($"{node.ParentNode.GetAttributeValue("start", 1) + node.ParentNode.SelectNodes("./li").IndexOf(node)}. ").Length + : 2; + + var indentation = baseIndentation + new string(' ', markerLength); + var lines = content.ReplaceLineEndings("\n").Split('\n'); + + if (lines.Length == 0) { + writer.WriteLine(); + return; + } + + writer.WriteLine(lines[0].TrimEnd()); + + for (var i = 1; i < lines.Length; i++) { + var line = lines[i]; + if (line.Length == 0) { + writer.WriteLine(); + continue; + } + + if (line[0] == ' ' || line[0] == '\t') { + writer.WriteLine(line); + continue; + } + + writer.Write(indentation); + writer.WriteLine(line); + } } private string ContentFor(HtmlNode node) diff --git a/src/ReverseMarkdown/Converters/Ol.cs b/src/ReverseMarkdown/Converters/Ol.cs index c42e209..0640c2f 100644 --- a/src/ReverseMarkdown/Converters/Ol.cs +++ b/src/ReverseMarkdown/Converters/Ol.cs @@ -1,5 +1,6 @@ using System.IO; using HtmlAgilityPack; +using ReverseMarkdown.Helpers; namespace ReverseMarkdown.Converters { @@ -12,6 +13,11 @@ public Ol(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { + if (Converter.Config.CommonMark) { + writer.Write(node.OuterHtml.CompactHtmlForCommonMarkBlock()); + return; + } + // Lists inside tables are not supported as markdown, so leave as HTML if (Context.AncestorsAny("table")) { writer.Write(node.OuterHtml); @@ -23,7 +29,26 @@ public override void Convert(TextWriter writer, HtmlNode node) if (block) writer.WriteLine(); TreatChildren(writer, node); - if (block) writer.WriteLine(); + if (block) { + writer.WriteLine(); + if (Converter.Config.CommonMark && NextElementIsList(node)) { + writer.WriteLine(); + } + } + } + + private static bool NextElementIsList(HtmlNode node) + { + var sibling = node.NextSibling; + while (sibling != null) { + if (sibling.NodeType == HtmlNodeType.Element) { + return sibling.Name is "ul" or "ol"; + } + + sibling = sibling.NextSibling; + } + + return false; } } } diff --git a/src/ReverseMarkdown/Converters/P.cs b/src/ReverseMarkdown/Converters/P.cs index 7c5f6dc..c035c95 100644 --- a/src/ReverseMarkdown/Converters/P.cs +++ b/src/ReverseMarkdown/Converters/P.cs @@ -25,16 +25,26 @@ public override void Convert(TextWriter writer, HtmlNode node) } } - private void TreatIndentation(TextWriter writer, HtmlNode node) - { - // If p follows a list item, add newline and indent it - var parentIsList = node.ParentNode.Name is "li" or "ol" or "ul"; - if (parentIsList && node.ParentNode.FirstChild != node) { - var length = Context.AncestorsCount("ol") + Context.AncestorsCount("ul"); - writer.WriteLine(); - writer.Write(new string(' ', length * 4)); - return; - } + private void TreatIndentation(TextWriter writer, HtmlNode node) + { + // If p follows a list item, add newline and indent it + var parentIsList = node.ParentNode.Name is "li" or "ol" or "ul"; + if (Converter.Config.CommonMark && parentIsList) { + if (node.ParentNode.FirstChild != node) { + writer.WriteLine(); + writer.WriteLine(); + } + + return; + } + + if (parentIsList && node.ParentNode.FirstChild != node) { + var length = Context.AncestorsCount("ol") + Context.AncestorsCount("ul"); + var indentSize = Converter.Config.CommonMark ? 2 : 4; + writer.WriteLine(); + writer.Write(new string(' ', length * indentSize)); + return; + } // If p is at the start of a table cell, no leading newline if (!Td.FirstNodeWithinCell(node)) { diff --git a/src/ReverseMarkdown/Converters/Pre.cs b/src/ReverseMarkdown/Converters/Pre.cs index aca9688..2189904 100644 --- a/src/ReverseMarkdown/Converters/Pre.cs +++ b/src/ReverseMarkdown/Converters/Pre.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Text.RegularExpressions; using HtmlAgilityPack; using ReverseMarkdown.Helpers; @@ -13,42 +14,51 @@ public Pre(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { - var isFencedCodeBlock = Converter.Config.GithubFlavored; + var isFencedCodeBlock = Converter.Config.GithubFlavored || Converter.Config.CommonMark; - // check if indentation need to be added if it is under an ordered or unordered list - var indentation = IndentationFor(node); + var indentation = Converter.Config.CommonMark + ? string.Empty + : IndentationFor(node); + var contentIndentation = indentation; // 4 space indent for code if it is not fenced code block if (!isFencedCodeBlock) { indentation += " "; + contentIndentation = indentation; } writer.WriteLine(); writer.WriteLine(); + // content: + var content = DecodeHtml(node.InnerText); + if (isFencedCodeBlock) { + var fence = Converter.Config.CommonMark + ? CreateCommonMarkFence(content) + : "```"; var lang = GetLanguage(node); writer.Write(indentation); - writer.Write("```"); + writer.Write(fence); writer.Write(lang); writer.WriteLine(); } - - // content: - var content = DecodeHtml(node.InnerText); foreach (var line in content.ReadLines()) { - writer.Write(indentation); + writer.Write(contentIndentation); writer.WriteLine(line); } if (string.IsNullOrEmpty(content)) { - if (!isFencedCodeBlock) writer.Write(indentation); + if (!isFencedCodeBlock) writer.Write(contentIndentation); writer.WriteLine(); } if (isFencedCodeBlock) { + var fence = Converter.Config.CommonMark + ? CreateCommonMarkFence(content) + : "```"; writer.Write(indentation); - writer.Write("```"); + writer.Write(fence); } writer.WriteLine(); @@ -59,6 +69,10 @@ public override void Convert(TextWriter writer, HtmlNode node) { var language = GetLanguageFromHighlightClassAttribute(node); + if (!Converter.Config.CommonMark && !string.IsNullOrEmpty(language)) { + language = language.TrimEnd(';'); + } + return !string.IsNullOrEmpty(language) ? language : Converter.Config.DefaultCodeBlockLanguage; @@ -92,7 +106,7 @@ private static string GetLanguageFromHighlightClassAttribute(HtmlNode node) /// Extracts class attribute syntax using: highlight-json, highlight-source-json, language-json, brush: language /// Returns the Language in Match.Groups[2] /// - [GeneratedRegex(@"(highlight-source-|language-|highlight-|brush:\s)([a-zA-Z0-9]+)")] + [GeneratedRegex(@"(highlight-source-|language-|highlight-|brush:\s)([^\s]+)")] private static partial Regex ClassRegex(); /// @@ -105,10 +119,31 @@ private static Match ClassMatch(HtmlNode node) { var val = node.GetAttributeValue("class", string.Empty); if (!string.IsNullOrEmpty(val)) { + val = System.Net.WebUtility.HtmlDecode(val); return ClassRegex().Match(val); } return Match.Empty; } + + private static string CreateCommonMarkFence(string content) + { + var maxRun = 0; + var currentRun = 0; + foreach (var c in content) { + if (c == '`') { + currentRun++; + if (currentRun > maxRun) { + maxRun = currentRun; + } + } + else { + currentRun = 0; + } + } + + var fenceLength = Math.Max(3, maxRun + 1); + return new string('`', fenceLength); + } } } diff --git a/src/ReverseMarkdown/Converters/S.cs b/src/ReverseMarkdown/Converters/S.cs index f2cf003..e410301 100644 --- a/src/ReverseMarkdown/Converters/S.cs +++ b/src/ReverseMarkdown/Converters/S.cs @@ -13,6 +13,11 @@ public S(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { + if (Converter.Config.CommonMark) { + writer.Write(node.OuterHtml); + return; + } + var content = TreatChildrenAsString(node); if (string.IsNullOrEmpty(content) || AlreadyStrikethrough()) { diff --git a/src/ReverseMarkdown/Converters/Strong.cs b/src/ReverseMarkdown/Converters/Strong.cs index 2bf3392..7a87763 100644 --- a/src/ReverseMarkdown/Converters/Strong.cs +++ b/src/ReverseMarkdown/Converters/Strong.cs @@ -12,24 +12,113 @@ public Strong(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { + var isCommonMark = Converter.Config.CommonMark; + if (isCommonMark && Converter.Config.CommonMarkUseHtmlInlineTags) { + writer.Write(node.OuterHtml); + return; + } + var content = TreatChildrenAsString(node); - if (string.IsNullOrEmpty(content) || AlreadyBold()) { + if (string.IsNullOrEmpty(content) || (!isCommonMark && AlreadyBold())) { writer.Write(content); return; } + var commonMarkPrefix = string.Empty; + var commonMarkSuffix = string.Empty; + if (isCommonMark && Converter.Config.CommonMarkIntrawordEmphasisSpacing) { + var contentFirst = FirstNonWhitespaceChar(content); + var contentLast = LastNonWhitespaceChar(content); + var contentHasLeadingWhitespace = content.Length > 0 && char.IsWhiteSpace(content[0]); + var contentHasTrailingWhitespace = content.Length > 0 && char.IsWhiteSpace(content[content.Length - 1]); + + if (IsWordChar(contentFirst) && IsWordChar(contentLast)) { + var hasPrevWord = !contentHasLeadingWhitespace && + IsAdjacentWordChar(node.PreviousSibling, checkEnd: true); + var hasNextWord = !contentHasTrailingWhitespace && + IsAdjacentWordChar(node.NextSibling, checkEnd: false); + if (hasPrevWord && hasNextWord) { + commonMarkPrefix = " "; + commonMarkSuffix = " "; + } + } + } + var spaceSuffix = node.NextSibling?.Name is "strong" or "b" ? " " : ""; - var emphasis = Converter.Config.SlackFlavored ? "*" : "**"; - TreatEmphasizeContentWhitespaceGuard(writer, content, emphasis, spaceSuffix); + var emphasis = Converter.Config.SlackFlavored + ? "*" + : isCommonMark && Context.AncestorsAny("strong") + ? "__" + : "**"; + var suffix = commonMarkSuffix.Length > 0 || spaceSuffix.Length > 0 ? " " : ""; + if (commonMarkPrefix.Length > 0) { + writer.Write(commonMarkPrefix); + } + + TreatEmphasizeContentWhitespaceGuard( + writer, + content, + emphasis, + suffix, + preserveLineEndings: isCommonMark + ); } private bool AlreadyBold() { return Context.AncestorsAny("strong") || Context.AncestorsAny("b"); } + + private static bool IsWordChar(char? value) + { + return value.HasValue && char.IsLetterOrDigit(value.Value); + } + + private static char? FirstNonWhitespaceChar(string content) + { + foreach (var c in content) { + if (!char.IsWhiteSpace(c)) { + return c; + } + } + + return null; + } + + private static char? LastNonWhitespaceChar(string content) + { + for (var i = content.Length - 1; i >= 0; i--) { + var c = content[i]; + if (!char.IsWhiteSpace(c)) { + return c; + } + } + + return null; + } + + private static bool IsAdjacentWordChar(HtmlNode? sibling, bool checkEnd) + { + if (sibling == null) { + return false; + } + + var text = sibling.InnerText; + if (string.IsNullOrEmpty(text)) { + return false; + } + + var index = checkEnd ? text.Length - 1 : 0; + var c = text[index]; + if (char.IsWhiteSpace(c)) { + return false; + } + + return char.IsLetterOrDigit(c); + } } } diff --git a/src/ReverseMarkdown/Converters/Table.cs b/src/ReverseMarkdown/Converters/Table.cs index 22ce0e2..f382873 100644 --- a/src/ReverseMarkdown/Converters/Table.cs +++ b/src/ReverseMarkdown/Converters/Table.cs @@ -15,6 +15,11 @@ public Table(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { + if (Converter.Config.CommonMark) { + writer.Write(node.OuterHtml); + return; + } + if (Converter.Config.SlackFlavored) { throw new SlackUnsupportedTagException(node.Name); } diff --git a/src/ReverseMarkdown/Converters/Text.cs b/src/ReverseMarkdown/Converters/Text.cs index 25cb983..d5c82e5 100644 --- a/src/ReverseMarkdown/Converters/Text.cs +++ b/src/ReverseMarkdown/Converters/Text.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using System.Text.RegularExpressions; using HtmlAgilityPack; @@ -52,18 +53,60 @@ public Text(Converter converter) : base(converter) public override void Convert(TextWriter writer, HtmlNode node) { - if (node.InnerText is " " or " " && node.ParentNode.Name is not ("ol" or "ul")) { - writer.Write(' '); + var isCommonMark = Converter.Config.CommonMark; + var innerText = node.InnerText; + if (innerText is " " or " " || innerText == "\u00A0") { + if (node.ParentNode.Name is not ("ol" or "ul")) { + if (isCommonMark && innerText != " ") { + writer.Write(" "); + } + else { + writer.Write(' '); + } + + return; + } } - else { - TreatText(writer, node); + + if (isCommonMark) { + if (innerText == "!" && node.NextSibling?.Name == "a") { + writer.Write("\\!"); + return; + } + + if (innerText == "*" && node.NextSibling?.Name == "img") { + writer.Write("\\*"); + return; + } } + + TreatText(writer, node); } private void TreatText(TextWriter writer, HtmlNode node) { - var text = node.InnerText; + var isCommonMark = Converter.Config.CommonMark; + var rawText = isCommonMark + ? node.OuterHtml + : node.InnerText; + if (isCommonMark && + (rawText.Contains("content

"; - - var config = new Config - { - RemoveComments = true - }; - return CheckConversion(html, config); - } - - [Fact] - public Task WhenBoldTagContainsBRTag_ThenConvertToMarkdown() - { - var html = "test
test
"; - return CheckConversion(html); - } - - [Fact] - public Task WhenAnchorTagContainsImgTag_LinkTextShouldNotBeEscaped() - { - var html = ""; - return CheckConversion(html); - } - - [Fact] - public Task - When_PRE_Without_Lang_Marker_Class_Att_And_GitHubFlavored_Config_With_DefaultCodeBlockLanguage_ThenConvertToGFM_PRE() - { - var html = @"
var test = ""hello world"";
"; - var config = new Config - { - GithubFlavored = true, - DefaultCodeBlockLanguage = "csharp" - }; - return CheckConversion(html, config); - } - - [Fact] - public Task - When_PRE_With_Parent_DIV_And_Non_GitHubFlavored_Config_FirstLine_CodeBlock_SpaceIndent_Should_Be_Retained() - { - var html = @"
var test = ""hello world"";
"; - return CheckConversion(html); - } - - [Fact] - public Task When_Converting_HTML_Ensure_To_Process_Only_Body() - { - var html = - "sample text"; - return CheckConversion(html); - } - - [Fact] - public Task When_Html_Containing_Nested_DIVs_Process_ONLY_Inner_Most_DIV() - { - var html = "
sample text
"; - return CheckConversion(html); - } - - [Fact] - public Task When_SingleChild_BlockTag_With_Parent_DIV_Ignore_Processing_DIV() - { - var html = "

sample text

"; - return CheckConversion(html); - } - - [Fact] - public Task When_Table_Within_List_Should_Be_Indented() - { - var html = - "
  1. Item1
  2. Item2
    col1col2col3
    data1data2data3
  3. Item3
"; - return CheckConversion(html); - } - - [Fact] - public Task When_Tag_In_PassThoughTags_List_Then_Use_PassThroughConverter() - { - var html = - @"This text has image . Next line of text"; - var config = new Config - { - PassThroughTags = ["img"] - }; - return CheckConversion(html, config); - } - - [Fact] - public Task When_CodeContainsSpaces_ShouldPreserveSpaces() - { - var html = "A JavaScript function ..."; - return CheckConversion(html); - } - - [Fact] - public Task When_CodeContainsSpanWithExtraSpaces_Should_NotNormalizeSpaces() - { - var html = "A JavaScript function ..."; - return CheckConversion(html); - } - - - [Fact] - public Task When_CodeContainsSpacesAndIsSurroundedByWhitespace_Should_NotRemoveSpaces() - { - var html = "A JavaScript function ..."; - return CheckConversion(html); - } - - [Fact] - public Task When_PreTag_Contains_IndentedFirstLine_Should_PreserveIndentation() - { - var html = "
    function foo {
"; - return CheckConversion(html); - } - - [Fact] - public Task When_PreTag_Contains_IndentedFirstLine_Should_PreserveIndentation_GFM() - { - var html = "
    function foo {
"; - - var config = new Config - { - GithubFlavored = true - }; - return CheckConversion(html, config); - } - - [Fact] - public Task When_PreTag_Within_List_Should_Be_Indented() - { - var html = - $"
  1. Item1
  2. Item2
     test
    {Environment.NewLine} test
  3. Item3
"; - return CheckConversion(html); - } - - [Fact] - public Task When_PreTag_Within_List_Should_Be_Indented_With_GitHub_FlavouredMarkdown() - { - var html = - $"
  1. Item1
  2. Item2
     test
    {Environment.NewLine} test
  3. Item3
"; - - var config = new Config - { - GithubFlavored = true - }; - return CheckConversion(html, config); - } - - [Fact] - public Task When_Text_Contains_NewLineChars_Should_Not_Convert_To_BR() - { - var html = "

line 1
line 2

"; - return CheckConversion(html); - } - - [Fact] - public Task When_Text_Contains_NewLineChars_Should_Not_Convert_To_BR_GitHub_Flavoured() - { - var html = "

line 1
line 2

"; - return CheckConversion(html, new Config - { - GithubFlavored = true - }); - } - - [Fact] - public Task When_Consecutive_Strong_Tags_Should_Convert_Properly() - { - var html = "block1block2block3block4"; - return CheckConversion(html); - } - - [Fact] - public Task When_Consecutive_Em_Tags_Should_Convert_Properly() - { - var html = "block1block2block3block4"; - return CheckConversion(html); - } - - [Fact] - public Task Li_With_No_Parent() - { - var html = "
  • item
  • "; - return CheckConversion(html); - } - - [Fact] - public Task When_Span_with_newline_Should_Convert_Properly() - { - var html = $"2 sets{Environment.NewLine}30 mountain climbers"; - return CheckConversion(html); - } - - [Fact] - public Task Bug255_table_newline_char_issue() - { - var html = - $"{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}
    ProgressionFocus
    "; - return CheckConversion(html); - } - - [Fact] - public Task When_Content_Contains_script_tags_ignore_it() - { - var html = - $"

    simple paragraph

    "; - return CheckConversion(html); - } - - [Fact] - public Task When_DescriptionListTag_ThenConvertToMarkdown_List() - { - var html = - "
    Coffee
    Filter Coffee
    Hot Black Coffee
    Milk
    White Cold Drink
    "; - return CheckConversion(html); - } - - [Fact] - public Task Bug294_Table_bug_with_row_superfluous_newlines() - { - var html = @" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    比较wordpresshexo & hugo
    搭建要求一台服务器以及运行环境静态生成页面,无需服务器。
    性能由于是动态生成页面,可以通过自行配置提高性能,但是仍然无法媲美静态页面几乎无需考虑性能问题
    访问速度依赖于服务器配置以及cdn加速。只需考虑cdn加速
    功能完善作为强大的cms功能很完善,需要的功能基本可以插件下载直接实现。额外功能也可以通过插件实现,不过稍微需要自行查找以及diy
    后台管理现成的后台管理功能,开箱即用由于静态博客,本身没有后台管理,有需求需要自行搜索实现
    "; - - return CheckConversion(html); - } - - [Fact] - public Task WhenTableHeadingWithAlignmentStyles_ThenTableHeaderShouldHaveProperAlignment() - { - var html = - $"
    Col1Col2Col2
    123
    "; - return CheckConversion(html); - } - - [Fact] - public Task When_Sup_And_Nested_Sup() - { - var html = $"This is the 1st sentence to test the sup tag conversion"; - return CheckConversion(html); - } - - [Fact] - public Task When_Anchor_Text_with_Underscore_Do_Not_Escape() - { - var html = $"This a sample paragraph from https://www.w3schools.com/html/mov_bbb.mp4"; - return CheckConversion(html); - } - - [Fact] - public Task When_Strikethrough_And_Nested_Strikethrough() - { - var html = $"This is the 1st sentence to test the strikethrough tag conversion"; - return CheckConversion(html); - } - - [Fact] - public Task When_Spaces_In_Inline_Tags_Should_Be_Retained() - { - var html = $"... example html code block"; - return CheckConversion(html); - } - - [Fact] - public Task When_SuppressNewlineFlag_PrefixDiv_Should_Be_Empty() - { - var html = $"
    the
    fox
    jumps
    over
    "; - return CheckConversion(html, new Config - { - SuppressDivNewlines = true - }); - } - - [Fact] - public Task WhenTable_WithColSpan_TableHeaderColumnSpansHandling_ThenConvertToGFMTable() - { - var html = - "
    col1col2col3
    data1data2.1data2.2data3
    "; - - var config = new Config - { - UnknownTags = Config.UnknownTagsOption.Bypass - }; - return CheckConversion(html, config); - } - - [Fact] - public Task Bug391_AnchorTagUnnecessarilyIndented() - { - var html = - "

    \n\n

    \n\n\n
    \nAn error occurred while importing data from feed 'FBA Producten'. More details can be found in the latest \">feed validation report.\n
    \n\n\n\n\n\" class=\"btn btn-primary btn-sm my-2\" target=\"_blank\">View feed 4"; - var config = new Config - { - GithubFlavored = true, - }; - - return CheckConversion(html, config); - } - + var html = LoadHtml("Unknown_Tag_Raise"); + var config = new Config + { + UnknownTags = Config.UnknownTagsOption.Raise + }; + var converter = new Converter(config); + return Verifier.Throws(() => converter.Convert(html), settings: _verifySettings) + .IgnoreMember(e => e.StackTrace); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Fact] - public Task Bug393_RegressionWithVaryingNewLines() + public void TestConversionWithPastedHtmlContainingUnicodeSpaces() { - const string html = "This is regular text\r\n

    This is HTML:

    • Line 1
    • Line 2
    • Line 3 has an unknown tag

    "; - var config = new Config { UnknownTags = Config.UnknownTagsOption.Bypass, ListBulletChar = '*' }; - return CheckConversion(html, config); + var html = LoadHtml("PastedHtmlUnicodeSpaces"); + + var config = new Config + { + GithubFlavored = true, + UnknownTags = + Config.UnknownTagsOption + .PassThrough, // Include the unknown tag completely in the result (default as well) + SmartHrefHandling = true // remove markdown output for links where appropriate + }; + var converter = new Converter(config); + var expected = converter.Convert(html); + + _testOutputHelper.WriteLine("Below is the generated markdown:"); + _testOutputHelper.WriteLine(expected); + + Assert.Contains("and **Weblog Publisher** for Windows", expected); } [Fact] public async Task Converter_Is_Thread_Safe_For_Concurrent_Use() { - var html = - "
    Head
    1. Item1
    2. Item2

    Tail

    "; + var html = LoadHtml("Converter_Is_Thread_Safe_For_Concurrent_Use"); var converter = new Converter(new Config { GithubFlavored = true }); var expected = converter.Convert(html); @@ -1702,364 +548,358 @@ public async Task Converter_Is_Thread_Safe_For_Concurrent_Use() Assert.Equal(expected, result); } } - - [Fact] - public Task SlackFlavored_Bold() - { - const string html = "test | test"; - var config = new Config { SlackFlavored = true }; - return CheckConversion(html, config); - } - - [Fact] - public Task SlackFlavored_Italic() - { - const string html = "test | test"; - var config = new Config { SlackFlavored = true }; - return CheckConversion(html, config); - } - - [Fact] - public Task SlackFlavored_Strikethrough() - { - const string html = "test"; - var config = new Config { SlackFlavored = true }; - return CheckConversion(html, config); - } - - [Fact] - public Task SlackFlavored_Bullets() - { - const string html = "
      \n
    • Item 1
    • \n
    • Item 2
    • \n
    • Item 3
    • \n
    "; - var config = new Config { SlackFlavored = true }; - return CheckConversion(html, config); - } - - [Fact] - public void SlackFlavored_Unsupported_Hr() - { - const string html = "
    "; - var config = new Config { SlackFlavored = true }; - var converter = new Converter(config); - Assert.Throws(() => converter.Convert(html)); - } - - [Fact] - public void SlackFlavored_Unsupported_Img() - { - const string html = ""; - var config = new Config { SlackFlavored = true }; - var converter = new Converter(config); - Assert.Throws(() => converter.Convert(html)); - } - - [Fact] - public void SlackFlavored_Unsupported_Sup() - { - const string html = "test"; - var config = new Config { SlackFlavored = true }; - var converter = new Converter(config); - Assert.Throws(() => converter.Convert(html)); - } - - [Fact] - public void SlackFlavored_Unsupported_Table() - { - const string html = "
    "; - var config = new Config { SlackFlavored = true }; - var converter = new Converter(config); - Assert.Throws(() => converter.Convert(html)); - } - - [Fact] - public void SlackFlavored_Unsupported_Table_Td() - { - const string html = ""; - var config = new Config { SlackFlavored = true }; - var converter = new Converter(config); - Assert.Throws(() => converter.Convert(html)); - } - - [Fact] - public void SlackFlavored_Unsupported_Table_Tr() - { - const string html = ""; - var config = new Config { SlackFlavored = true }; - var converter = new Converter(config); - Assert.Throws(() => converter.Convert(html)); - } - - [Fact] - public Task Bug403_unexpectedBehaviourWhenTableBodyRowsWithTHCells() - { - var html = $"{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}
    Heading1Heading2
    data 1data 2
    data 3data 4
    "; - var config = new Config { UnknownTags = Config.UnknownTagsOption.Bypass, ListBulletChar = '*', GithubFlavored = true}; - return CheckConversion(html, config); - } - - [Fact] - public Task EscapeMarkdownCharsInTextProperly() - { - var html = "[a-z]([0-9]){0,4}"; - return CheckConversion(html); - } - - [Fact] - public Task Bug400_MissingSpanSpaceWithItalics() - { - var html = "

    What we thought: When we built Pages, we assumed that customers would use them like newsletters to share relevant, continually-updated information with field teams.

    "; - return CheckConversion(html); - } - - [Fact] - public Task When_NestedParagraphs_FiveLevelsDeep_ThenConvertCorrectly() - { - // Tests moderately nested

    tags where HtmlAgilityPack creates nested structure - var html = "

    Level1

    Level2

    Level3

    Level4

    Level5

    "; - - var config = new Config - { - GithubFlavored = true, - UnknownTags = Config.UnknownTagsOption.Bypass - }; - - return CheckConversion(html, config); - } - - [Fact] - public Task When_NestedSpans_FiveLevelsDeep_ThenConvertCorrectly() - { - // Tests moderately nested tags to ensure span bypass converter handles nesting - var html = "Level1Level2Level3Level4Level5"; - - var config = new Config - { - UnknownTags = Config.UnknownTagsOption.Bypass - }; - - return CheckConversion(html, config); - } - - [Fact] - public Task When_InterleavedParagraphsAndSpans_ThenConvertCorrectly() - { - // Tests the interleaved

    pattern common in malformed HTML - var html = "

    Text1

    Text2

    Text3

    Text4

    "; - - var config = new Config - { - GithubFlavored = true, - UnknownTags = Config.UnknownTagsOption.Bypass - }; - - return CheckConversion(html, config); - } - - [Fact] - public Task When_ManySequentialUnclosedParagraphs_ThenConvertCorrectly() - { - // Tests sequential unclosed

    tags as found in user-generated content - var html = "

    Part1

    Part2

    Part3

    Part4

    Part5

    Part6

    Part7

    Part8"; - - var config = new Config - { - GithubFlavored = true, - UnknownTags = Config.UnknownTagsOption.Bypass - }; - - return CheckConversion(html, config); - } - - [Fact] - public Task When_UnclosedParagraphsWithSpansAndTextNodes_ThenConvertCorrectly() - { - // Tests mixed content: properly closed tags, text nodes, and unclosed nested tags - var html = @"

    Intro

    Filler text here.

    Section1

    Section2

    Section3"; - - var config = new Config - { - GithubFlavored = true, - UnknownTags = Config.UnknownTagsOption.Bypass - }; - - return CheckConversion(html, config); - } - - [Fact] - public Task When_EmptyNestedParagraphs_ThenConvertCorrectly() - { - // Tests deeply nested empty

    tags - var html = "

    "; - - var config = new Config - { - UnknownTags = Config.UnknownTagsOption.Bypass - }; - - return CheckConversion(html, config); - } - - [Fact] - public Task When_AlternatingEmptyAndFilledNestedParagraphs_ThenConvertCorrectly() - { - // Tests combination of empty and filled nested

    tags - var html = "

    A

    B

    C

    D

    E

    "; - - var config = new Config - { - UnknownTags = Config.UnknownTagsOption.Bypass - }; - - return CheckConversion(html, config); - } - - [Fact] - public Task When_NestedParagraphs_TenLevelsDeep_ThenConvertCorrectly() - { - // Tests deeper nesting (10 levels) to ensure performance remains linear after fix - var html = "

    L1

    L2

    L3

    L4

    L5

    L6

    L7

    L8

    L9

    L10

    "; - - var config = new Config - { - GithubFlavored = true, - UnknownTags = Config.UnknownTagsOption.Bypass - }; - - return CheckConversion(html, config); - } - - [Fact] - public Task When_NestedTableIsInTable_LeaveNestedTableAsHtml() - { - // Issue #411: Nested tables should be left as HTML, similar to lists in tables - var html = "
    StepInstructions
    1
    ConditionAction
    ADo X
    "; - return CheckConversion(html); - } - - [Fact] - public Task When_ComplexNestedTableIsInTable_LeaveNestedTableAsHtml() - { - // More complex nested table scenario - var html = @" - - - - - - - - -
    CategoryDetails
    Products - - - - -
    NamePrice
    Item 1$10
    Item 2$20
    -
    "; - return CheckConversion(html); - } - - [Fact] - public Task When_MultipleNestedTablesInTable_LeaveAllNestedTablesAsHtml() - { - // Multiple nested tables in different cells - var html = @" - - - - - - - - -
    Column 1Column 2
    - - -
    Nested 1
    -
    - - -
    Nested 2
    -
    "; - return CheckConversion(html); - } - - [Fact] - public Task WhenTable_WithCaption_ThenCaptionAppearsAboveTable() - { - var html = "
    Monthly Sales Report
    MonthSales
    January$1000
    "; - return CheckConversion(html); - } - - [Fact] - public Task WhenTable_WithoutCaption_ThenConvertNormally() - { - var html = "
    MonthSales
    January$1000
    "; - return CheckConversion(html); - } - - [Fact] - public Task WhenTable_WithEmptyCaption_ThenConvertNormally() - { - var html = "
    MonthSales
    January$1000
    "; - return CheckConversion(html); - } - - [Fact] - public Task WhenTable_WithCaptionContainingWhitespace_ThenTrimWhitespace() - { - var html = "
    Table Caption
    Col1
    Data1
    "; - return CheckConversion(html); - } - - [Fact] - public Task WhenTable_WithCaptionContainingMarkdownChars_ThenHandleProperly() - { - var html = "
    Sales Report [2024] - **Important**
    MonthSales
    Jan$100
    "; - return CheckConversion(html); - } - - [Fact] - public Task WhenTable_WithCaptionAndNoHeaderRow_EmptyRowHandling_ThenCaptionAppearsAboveTable() - { - var html = "
    Data Table
    data1data2
    data3data4
    "; - var config = new Config - { - TableWithoutHeaderRowHandling = Config.TableWithoutHeaderRowHandlingOption.EmptyRow - }; - return CheckConversion(html, config); - } - - [Fact] - public Task WhenTable_WithCaptionContainingNestedTags_ThenExtractTextOnly() - { - var html = "
    Sales Report for 2024
    Month
    Jan
    "; - return CheckConversion(html); - } - - [Fact] - public Task WhenTable_WithCaptionAndGithubFlavored_ThenCaptionAppearsAboveTable() - { - var html = "
    Code Review Summary
    PRStatus
    #123Approved
    "; - var config = new Config - { - GithubFlavored = true - }; - return CheckConversion(html, config); - } - - [Fact] - public Task WhenTable_WithCaptionContainingNewlines_ThenHandleNewlines() - { - var html = $"
    Multi{Environment.NewLine}Line{Environment.NewLine}Caption
    Col
    Data
    "; - return CheckConversion(html); - } - - [Fact] - public Task WhenTableRowWithDuplicateStyleKeysAfterTrimming_ThenConvertWithoutException() - { - var html = "
    Header
    Data
    "; - return CheckConversion(html); - } - } -} + + [Fact] + public void SlackFlavored_Unsupported_Hr() + { + var html = LoadHtml("SlackFlavored_Unsupported_Hr"); + var config = new Config { SlackFlavored = true }; + var converter = new Converter(config); + Assert.Throws(() => converter.Convert(html)); + } + + [Fact] + public void SlackFlavored_Unsupported_Img() + { + var html = LoadHtml("SlackFlavored_Unsupported_Img"); + var config = new Config { SlackFlavored = true }; + var converter = new Converter(config); + Assert.Throws(() => converter.Convert(html)); + } + + [Fact] + public void SlackFlavored_Unsupported_Sup() + { + var html = LoadHtml("SlackFlavored_Unsupported_Sup"); + var config = new Config { SlackFlavored = true }; + var converter = new Converter(config); + Assert.Throws(() => converter.Convert(html)); + } + + [Fact] + public void SlackFlavored_Unsupported_Table() + { + var html = LoadHtml("SlackFlavored_Unsupported_Table"); + var config = new Config { SlackFlavored = true }; + var converter = new Converter(config); + Assert.Throws(() => converter.Convert(html)); + } + + [Fact] + public void SlackFlavored_Unsupported_Table_Td() + { + var html = LoadHtml("SlackFlavored_Unsupported_Table_Td"); + var config = new Config { SlackFlavored = true }; + var converter = new Converter(config); + Assert.Throws(() => converter.Convert(html)); + } + + [Fact] + public void SlackFlavored_Unsupported_Table_Tr() + { + var html = LoadHtml("SlackFlavored_Unsupported_Table_Tr"); + var config = new Config { SlackFlavored = true }; + var converter = new Converter(config); + Assert.Throws(() => converter.Convert(html)); + } + + + + + + + + + + + + // [Fact] + // public Task When_TextWithinParagraphContainsNewlineChars_ConvertNewlineCharsToSpace() + // { + // // note that the string also has a tab space + // var html = + // $"

    This service will be{Environment.NewLine}temporarily unavailable due to planned maintenance{Environment.NewLine}from 02:00-04:00 on 30/01/2020

    "; + // return CheckConversion(html); + // } + + // [Fact] + // public Task WhenTableCellsWithPWithMarkupNewlines_ThenRenderBr() + // { + // var html = + // $"{Environment.NewLine}\t{Environment.NewLine}\t\t{Environment.NewLine}\t{Environment.NewLine}\t\t\t
    {Environment.NewLine}\t\t\t

    {Environment.NewLine}col1{Environment.NewLine}

    {Environment.NewLine}\t\t
    {Environment.NewLine}\t\t\t

    {Environment.NewLine}data1{Environment.NewLine}

    {Environment.NewLine}\t\t
    "; + // + // return CheckConversion(html); + // } + + } + + public class DataDrivenCasesTests + { + public static IEnumerable Cases => LoadCases() + .Select(testCase => new object[] { testCase }); + + [Theory] + [MemberData(nameof(Cases))] + public void CaseRuns(CaseData testCase) + { + var config = BuildConfig(testCase); + var converter = new Converter(config); + var result = converter.Convert(testCase.Html); + var expected = LoadExpected(testCase); + Assert.Equal(expected, result); + } + + private static IEnumerable LoadCases() + { + var path = GetCasesPath(); + if (!File.Exists(path)) { + throw new FileNotFoundException("cases.json not found", path); + } + + var json = File.ReadAllText(path); + var cases = JsonSerializer.Deserialize>( + json, + new JsonSerializerOptions { PropertyNameCaseInsensitive = true } + ); + + var filtered = (cases ?? new List()).Where(testCase => !testCase.DataOnly); + return ApplyTagFilter(filtered); + } + + private static IEnumerable ApplyTagFilter(IEnumerable cases) + { + var filter = Environment.GetEnvironmentVariable("RM_TEST_TAGS"); + if (string.IsNullOrWhiteSpace(filter)) { + return cases; + } + + var tags = filter.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + return cases.Where(testCase => testCase.Tags.Any(tag => tags.Contains(tag, StringComparer.OrdinalIgnoreCase))); + } + + private static string LoadExpected(CaseData testCase) + { + if (!string.IsNullOrWhiteSpace(testCase.Expected)) { + return testCase.Expected; + } + + if (string.IsNullOrWhiteSpace(testCase.ExpectedFile)) { + throw new InvalidOperationException($"Case '{testCase.Id}' missing expected output."); + } + + var projectDir = GetProjectDirectory(); + var path = Path.Combine(projectDir.FullName, testCase.ExpectedFile); + if (!File.Exists(path)) { + throw new FileNotFoundException($"Expected file not found for '{testCase.Id}'", path); + } + + var expected = File.ReadAllText(path); + if (expected.EndsWith("\r\n", StringComparison.Ordinal)) { + return expected[..^2]; + } + + if (expected.EndsWith("\n", StringComparison.Ordinal)) { + return expected[..^1]; + } + + return expected; + } + + private static Config BuildConfig(CaseData testCase) + { + if (!string.IsNullOrWhiteSpace(testCase.ConfigPreset)) { + return ConfigPresets.Get(testCase.ConfigPreset); + } + + var config = new Config(); + var overrides = testCase.Config; + if (overrides == null) { + return config; + } + + ApplyBool(overrides.GithubFlavored, value => config.GithubFlavored = value); + ApplyBool(overrides.SlackFlavored, value => config.SlackFlavored = value); + ApplyBool(overrides.CommonMark, value => config.CommonMark = value); + ApplyBool(overrides.CommonMarkIntrawordEmphasisSpacing, + value => config.CommonMarkIntrawordEmphasisSpacing = value); + ApplyBool(overrides.CommonMarkUseHtmlInlineTags, + value => config.CommonMarkUseHtmlInlineTags = value); + ApplyBool(overrides.SuppressDivNewlines, value => config.SuppressDivNewlines = value); + ApplyBool(overrides.RemoveComments, value => config.RemoveComments = value); + ApplyBool(overrides.SmartHrefHandling, value => config.SmartHrefHandling = value); + ApplyBool(overrides.CleanupUnnecessarySpaces, value => config.CleanupUnnecessarySpaces = value); + ApplyBool(overrides.TableHeaderColumnSpanHandling, + value => config.TableHeaderColumnSpanHandling = value); + + if (!string.IsNullOrWhiteSpace(overrides.DefaultCodeBlockLanguage)) { + config.DefaultCodeBlockLanguage = overrides.DefaultCodeBlockLanguage; + } + + if (!string.IsNullOrWhiteSpace(overrides.ListBulletChar)) { + config.ListBulletChar = overrides.ListBulletChar[0]; + } + + ApplyEnum(overrides.UnknownTags, + value => config.UnknownTags = value); + ApplyEnum(overrides.TableWithoutHeaderRowHandling, + value => config.TableWithoutHeaderRowHandling = value); + ApplyEnum(overrides.Base64Images, + value => config.Base64Images = value); + + if (!string.IsNullOrWhiteSpace(overrides.Base64ImageSaveDirectory)) { + config.Base64ImageSaveDirectory = overrides.Base64ImageSaveDirectory; + } + + if (overrides.WhitelistUriSchemes.Length > 0) { + foreach (var scheme in overrides.WhitelistUriSchemes) { + config.WhitelistUriSchemes.Add(scheme); + } + } + + if (overrides.PassThroughTags.Length > 0) { + foreach (var tag in overrides.PassThroughTags) { + config.PassThroughTags.Add(tag); + } + } + + if (overrides.UnknownTagsReplacer.Count > 0) { + foreach (var entry in overrides.UnknownTagsReplacer) { + config.UnknownTagsReplacer[entry.Key] = entry.Value; + } + } + + if (overrides.TagAliases.Count > 0) { + foreach (var entry in overrides.TagAliases) { + config.TagAliases[entry.Key] = entry.Value; + } + } + + return config; + } + + private static void ApplyBool(bool? value, Action apply) + { + if (value.HasValue) { + apply(value.Value); + } + } + + private static void ApplyEnum(string value, Action apply) where T : struct + { + if (string.IsNullOrWhiteSpace(value)) { + return; + } + + if (Enum.TryParse(value, out var parsed)) { + apply(parsed); + } + } + + private static DirectoryInfo GetProjectDirectory() + { + var directory = new DirectoryInfo(AppContext.BaseDirectory); + while (directory != null && !File.Exists(Path.Combine(directory.FullName, "ReverseMarkdown.Test.csproj"))) { + directory = directory.Parent; + } + + if (directory == null) { + throw new DirectoryNotFoundException("Could not locate test project directory."); + } + + return directory; + } + + private static string GetCasesPath() + { + return Path.Combine(GetProjectDirectory().FullName, "TestData", "cases.json"); + } + + public class CaseData + { + public string Id { get; set; } = string.Empty; + public string Html { get; set; } = string.Empty; + public string Expected { get; set; } = string.Empty; + public string ExpectedFile { get; set; } = string.Empty; + public CaseConfig Config { get; set; } = new CaseConfig(); + public string ConfigPreset { get; set; } = string.Empty; + public string[] Tags { get; set; } = Array.Empty(); + public bool DataOnly { get; set; } + + public override string ToString() + { + return Id; + } + } + + public class CaseConfig + { + public bool? GithubFlavored { get; set; } + public bool? SlackFlavored { get; set; } + public bool? CommonMark { get; set; } + public bool? CommonMarkIntrawordEmphasisSpacing { get; set; } + public bool? CommonMarkUseHtmlInlineTags { get; set; } + public bool? SuppressDivNewlines { get; set; } + public bool? RemoveComments { get; set; } + public bool? SmartHrefHandling { get; set; } + public bool? CleanupUnnecessarySpaces { get; set; } + public bool? TableHeaderColumnSpanHandling { get; set; } + public string DefaultCodeBlockLanguage { get; set; } = string.Empty; + public string ListBulletChar { get; set; } = string.Empty; + public string UnknownTags { get; set; } = string.Empty; + public string TableWithoutHeaderRowHandling { get; set; } = string.Empty; + public string Base64Images { get; set; } = string.Empty; + public string Base64ImageSaveDirectory { get; set; } = string.Empty; + public string[] WhitelistUriSchemes { get; set; } = Array.Empty(); + public string[] PassThroughTags { get; set; } = Array.Empty(); + public Dictionary UnknownTagsReplacer { get; set; } = new(); + public Dictionary TagAliases { get; set; } = new(); + } + + private static class ConfigPresets + { + public static Config Get(string name) + { + throw new InvalidOperationException($"Unknown config preset '{name}'."); + } + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ReverseMarkdown.Test/TestData/README.md b/src/ReverseMarkdown.Test/TestData/README.md index 2c76b33..6f3f1d4 100644 --- a/src/ReverseMarkdown.Test/TestData/README.md +++ b/src/ReverseMarkdown.Test/TestData/README.md @@ -3,3 +3,22 @@ CommonMark test data Download commonmark.json from the CommonMark spec repository and save it here: https://raw.githubusercontent.com/commonmark/commonmark-spec/master/commonmark.json + +Local data-driven test cases + +Add cases to cases.json with the following fields: + +- id: unique identifier, used for test naming +- html: source HTML input +- expected: expected markdown output (inline) +- expectedFile: filename of a snapshot in src/ReverseMarkdown.Test (optional alternative to expected) +- config: optional Config values (CommonMark, SlackFlavored, etc.) +- tags: optional tags for filtering via RM_TEST_TAGS + +Example: + +{ + "id": "basic-strong", + "html": "This is a sample paragraph", + "expected": "This is a **sample** paragraph" +} diff --git a/src/ReverseMarkdown.Test/TestData/cases.json b/src/ReverseMarkdown.Test/TestData/cases.json new file mode 100644 index 0000000..6a2f4d4 --- /dev/null +++ b/src/ReverseMarkdown.Test/TestData/cases.json @@ -0,0 +1,1238 @@ +[ + { + "id": "WhenThereIsAsideTag", + "html": " This text appears after aside.", + "expectedFile": "ConverterTests.WhenThereIsAsideTag.verified.md" + }, + { + "id": "WhenThereAreSemanticContainerTags", + "html": "
    Whatever Inc.

    Thanks for your enquiry.

    Section intro
    Article text
    Diagram
    Figure caption
    Mail us
    ", + "expectedFile": "ConverterTests.WhenThereAreSemanticContainerTags.verified.md", + "config": { + "UnknownTags": "PassThrough" + } + }, + { + "id": "WhenThereIsHtmlLink_ThenConvertToMarkdownLink", + "html": "This is a link", + "expectedFile": "ConverterTests.WhenThereIsHtmlLink_ThenConvertToMarkdownLink.verified.md" + }, + { + "id": "WhenThereIsHtmlLinkWithTitle_ThenConvertToMarkdownLink", + "html": "This is a link", + "expectedFile": "ConverterTests.WhenThereIsHtmlLinkWithTitle_ThenConvertToMarkdownLink.verified.md" + }, + { + "id": "WhenThereAreMultipleLinks_ThenConvertThemToMarkdownLinks", + "html": "This is first link and second link", + "expectedFile": "ConverterTests.WhenThereAreMultipleLinks_ThenConvertThemToMarkdownLinks.verified.md" + }, + { + "id": "WhenThereIsHtmlLinkNotWhitelisted_ThenBypass", + "html": "Leave http, https, ftp, ftps, file. Remove data, tel and whatever", + "expectedFile": "ConverterTests.WhenThereIsHtmlLinkNotWhitelisted_ThenBypass.verified.md", + "config": { + "WhitelistUriSchemes": [ + "http", + "https", + "ftp", + "ftps", + "file" + ] + } + }, + { + "id": "WhenThereHtmlWithHrefAndNoSchema_WhitelistedEmptyString_ThenConvertToMarkdown", + "html": "yeah", + "expectedFile": "ConverterTests.WhenThereHtmlWithHrefAndNoSchema_WhitelistedEmptyString_ThenConvertToMarkdown.verified.md", + "config": { + "WhitelistUriSchemes": [ + "" + ] + } + }, + { + "id": "WhenThereHtmlWithHrefAndNoSchema_NotWhitelisted_ThenConvertToPlain", + "html": "yeah", + "expectedFile": "ConverterTests.WhenThereHtmlWithHrefAndNoSchema_NotWhitelisted_ThenConvertToPlain.verified.md", + "config": { + "WhitelistUriSchemes": [ + "whatever" + ] + } + }, + { + "id": "WhenThereIsHtmlLinkWithDisallowedCharsInChildren_ThenEscapeTextInMarkdown", + "html": "this ]( might break things", + "expectedFile": "ConverterTests.WhenThereIsHtmlLinkWithDisallowedCharsInChildren_ThenEscapeTextInMarkdown.verified.md", + "config": { + "SmartHrefHandling": true + } + }, + { + "id": "WhenThereIsHtmlLinkWithParensInHref_ThenEscapeHrefInMarkdown", + "html": "link", + "expectedFile": "ConverterTests.WhenThereIsHtmlLinkWithParensInHref_ThenEscapeHrefInMarkdown.verified.md", + "config": { + "SmartHrefHandling": true + } + }, + { + "id": "WhenThereIsHtmlWithProtocolRelativeUrlHrefAndNameNotMatching_SmartHandling_ThenConvertToMarkdown", + "html": "example.com", + "expectedFile": "ConverterTests.WhenThereIsHtmlWithProtocolRelativeUrlHrefAndNameNotMatching_SmartHandling_ThenConvertToMarkdown.verified.md", + "config": { + "SmartHrefHandling": true + } + }, + { + "id": "WhenThereIsHtmlWithHrefAndNameNotMatching_SmartHandling_ThenConvertToMarkdown", + "html": "Something intact", + "expectedFile": "ConverterTests.WhenThereIsHtmlWithHrefAndNameNotMatching_SmartHandling_ThenConvertToMarkdown.verified.md", + "config": { + "SmartHrefHandling": true + } + }, + { + "id": "WhenThereIsHtmlWithHrefAndNameMatching_SmartHandling_ThenConvertToPlain", + "html": "http://example.com/abc?x", + "expectedFile": "ConverterTests.WhenThereIsHtmlWithHrefAndNameMatching_SmartHandling_ThenConvertToPlain.verified.md", + "config": { + "SmartHrefHandling": true + } + }, + { + "id": "WhenThereIsHtmlWithMailtoSchemeAndNameWithoutScheme_SmartHandling_ThenConvertToPlain", + "html": "george@example.com", + "expectedFile": "ConverterTests.WhenThereIsHtmlWithMailtoSchemeAndNameWithoutScheme_SmartHandling_ThenConvertToPlain.verified.md", + "config": { + "SmartHrefHandling": true + } + }, + { + "id": "WhenThereIsHtmlWithTelSchemeAndNameWithoutScheme_SmartHandling_ThenConvertToPlain", + "html": "+1123-45678", + "expectedFile": "ConverterTests.WhenThereIsHtmlWithTelSchemeAndNameWithoutScheme_SmartHandling_ThenConvertToPlain.verified.md", + "config": { + "SmartHrefHandling": true + } + }, + { + "id": "WhenThereIsHtmlLinkWithoutHttpSchemaAndNameWithoutScheme_SmartHandling_ThenConvertToMarkdown", + "html": "example.com", + "expectedFile": "ConverterTests.WhenThereIsHtmlLinkWithoutHttpSchemaAndNameWithoutScheme_SmartHandling_ThenConvertToMarkdown.verified.md", + "config": { + "SmartHrefHandling": true + } + }, + { + "id": "WhenThereAreStrongTag_ThenConvertToMarkdownDoubleAsterisks", + "html": "This paragraph contains bold text", + "expectedFile": "ConverterTests.WhenThereAreStrongTag_ThenConvertToMarkdownDoubleAsterisks.verified.md" + }, + { + "id": "WhenThereAreBTag_ThenConvertToMarkdownDoubleAsterisks", + "html": "This paragraph contains bold text", + "expectedFile": "ConverterTests.WhenThereAreBTag_ThenConvertToMarkdownDoubleAsterisks.verified.md" + }, + { + "id": "WhenThereIsEncompassingStrongOrBTag_ThenConvertToMarkdownDoubleAsterisks_AnyStrongOrBTagsInsideAreIgnored", + "html": "Paragraph is encompassed with strong tag and also has bold text words within it", + "expectedFile": "ConverterTests.WhenThereIsEncompassingStrongOrBTag_ThenConvertToMarkdownDoubleAsterisks_AnyStrongOrBTagsInsideAreIgnored.verified.md" + }, + { + "id": "WhenThereIsSingleAsteriskInText_ThenConvertToMarkdownEscapedAsterisk", + "html": "This is a sample(*) paragraph", + "expectedFile": "ConverterTests.WhenThereIsSingleAsteriskInText_ThenConvertToMarkdownEscapedAsterisk.verified.md" + }, + { + "id": "WhenThereIsEmTag_ThenConvertToMarkdownSingleAsterisks", + "html": "This is a sample paragraph", + "expected": "This is a *sample* paragraph" + }, + { + "id": "WhenThereIsITag_ThenConvertToMarkdownSingleAsterisks", + "html": "This is a sample paragraph", + "expected": "This is a *sample* paragraph" + }, + { + "id": "When_CommonMark_Enabled_InlineEmphasisInsideWord_ThenInsertSpaces", + "html": "hello and thing", + "expected": "he **ll** o and th *in* g", + "config": { + "CommonMark": true, + "CommonMarkIntrawordEmphasisSpacing": true, + "CommonMarkUseHtmlInlineTags": false + } + }, + { + "id": "WhenThereIsEncompassingEmOrITag_ThenConvertToMarkdownSingleAsterisks_AnyEmOrITagsInsideAreIgnored", + "html": "This is a sample paragraph", + "expectedFile": "ConverterTests.WhenThereIsEncompassingEmOrITag_ThenConvertToMarkdownSingleAsterisks_AnyEmOrITagsInsideAreIgnored.verified.md" + }, + { + "id": "WhenThereIsBreakTag_ThenConvertToMarkdownDoubleSpacesCarriageReturn", + "html": "This is a paragraph.
    This line appears after break.", + "expectedFile": "ConverterTests.WhenThereIsBreakTag_ThenConvertToMarkdownDoubleSpacesCarriageReturn.verified.md" + }, + { + "id": "WhenThereIsCodeTag_ThenConvertToMarkdownWithBackTick", + "html": "This text has code alert();", + "expected": "This text has code `alert();`" + }, + { + "id": "WhenThereIsH1Tag_ThenConvertToMarkdownHeader", + "html": "This text has

    header

    . This text appear after header.", + "expectedFile": "ConverterTests.WhenThereIsH1Tag_ThenConvertToMarkdownHeader.verified.md" + }, + { + "id": "WhenThereIsH2Tag_ThenConvertToMarkdownHeader", + "html": "This text has

    header

    . This text appear after header.", + "expectedFile": "ConverterTests.WhenThereIsH2Tag_ThenConvertToMarkdownHeader.verified.md" + }, + { + "id": "WhenThereIsH3Tag_ThenConvertToMarkdownHeader", + "html": "This text has

    header

    . This text appear after header.", + "expectedFile": "ConverterTests.WhenThereIsH3Tag_ThenConvertToMarkdownHeader.verified.md" + }, + { + "id": "WhenThereIsH4Tag_ThenConvertToMarkdownHeader", + "html": "This text has

    header

    . This text appear after header.", + "expectedFile": "ConverterTests.WhenThereIsH4Tag_ThenConvertToMarkdownHeader.verified.md" + }, + { + "id": "WhenThereIsH5Tag_ThenConvertToMarkdownHeader", + "html": "This text has
    header
    . This text appear after header.", + "expectedFile": "ConverterTests.WhenThereIsH5Tag_ThenConvertToMarkdownHeader.verified.md" + }, + { + "id": "WhenThereIsH6Tag_ThenConvertToMarkdownHeader", + "html": "This text has
    header
    . This text appear after header.", + "expectedFile": "ConverterTests.WhenThereIsH6Tag_ThenConvertToMarkdownHeader.verified.md" + }, + { + "id": "WhenThereIsHeadingInsideTable_ThenIgnoreHeadingLevel", + "html": "\n\n\n

    Heading text

    Content
    ", + "expectedFile": "ConverterTests.WhenThereIsHeadingInsideTable_ThenIgnoreHeadingLevel.verified.md" + }, + { + "id": "WhenThereIsBlockquoteTag_ThenConvertToMarkdownBlockquote", + "html": "This text has
    blockquote
    . This text appear after header.", + "expectedFile": "ConverterTests.WhenThereIsBlockquoteTag_ThenConvertToMarkdownBlockquote.verified.md" + }, + { + "id": "WhenThereIsEmptyBlockquoteTag_ThenConvertToMarkdownBlockquote", + "html": "This text has
    . This text appear after header.", + "expectedFile": "ConverterTests.WhenThereIsEmptyBlockquoteTag_ThenConvertToMarkdownBlockquote.verified.md" + }, + { + "id": "WhenThereIsParagraphTag_ThenConvertToMarkdownDoubleLineBreakBeforeAndAfter", + "html": "This text has markup

    paragraph.

    Next line of text", + "expectedFile": "ConverterTests.WhenThereIsParagraphTag_ThenConvertToMarkdownDoubleLineBreakBeforeAndAfter.verified.md" + }, + { + "id": "WhenThereIsHorizontalRule_ThenConvertToMarkdownHorizontalRule", + "html": "This text has horizontal rule.
    Next line of text", + "expectedFile": "ConverterTests.WhenThereIsHorizontalRule_ThenConvertToMarkdownHorizontalRule.verified.md" + }, + { + "id": "WhenThereIsImgTag_ThenConvertToMarkdownImage", + "html": "This text has image \"alt\". Next line of text", + "expectedFile": "ConverterTests.WhenThereIsImgTag_ThenConvertToMarkdownImage.verified.md" + }, + { + "id": "WhenThereIsImgTagWithoutTitle_ThenConvertToMarkdownImageWithoutTitle", + "html": "This text has image \"alt\". Next line of text", + "expectedFile": "ConverterTests.WhenThereIsImgTagWithoutTitle_ThenConvertToMarkdownImageWithoutTitle.verified.md" + }, + { + "id": "WhenThereIsImgTagWithoutAltText_ThenConvertToMarkdownImageWithoutAltText", + "html": "This text has image . Next line of text", + "expectedFile": "ConverterTests.WhenThereIsImgTagWithoutAltText_ThenConvertToMarkdownImageWithoutAltText.verified.md" + }, + { + "id": "WhenThereIsImgTagWithMultilineAltText_ThenEnsureNoBlankLinesInMarkdownAltText", + "html": "This text has image \"cat\n\ndog\". Next line of text", + "expectedFile": "ConverterTests.WhenThereIsImgTagWithMultilineAltText_ThenEnsureNoBlankLinesInMarkdownAltText.verified.md" + }, + { + "id": "WhenThereIsImgTagWithBracesInAltText_ThenEnsureAltTextIsEscapedInMarkdown", + "html": "This text has image \"a]b\". Next line of text", + "expectedFile": "ConverterTests.WhenThereIsImgTagWithBracesInAltText_ThenEnsureAltTextIsEscapedInMarkdown.verified.md" + }, + { + "id": "WhenThereIsImgTag_SchemeNotWhitelisted_ThenEmptyOutput", + "html": "", + "expectedFile": "ConverterTests.WhenThereIsImgTag_SchemeNotWhitelisted_ThenEmptyOutput.verified.md", + "config": { + "WhitelistUriSchemes": [ + "http" + ] + } + }, + { + "id": "WhenThereIsImgTag_SchemeIsWhitelisted_ThenConvertToMarkdown", + "html": "", + "expectedFile": "ConverterTests.WhenThereIsImgTag_SchemeIsWhitelisted_ThenConvertToMarkdown.verified.md", + "config": { + "WhitelistUriSchemes": [ + "data" + ] + } + }, + { + "id": "WhenThereIsImgTagAndSrcWithNoSchema_WhitelistedEmptyString_ThenConvertToMarkdown", + "html": "", + "expectedFile": "ConverterTests.WhenThereIsImgTagAndSrcWithNoSchema_WhitelistedEmptyString_ThenConvertToMarkdown.verified.md", + "config": { + "WhitelistUriSchemes": [ + "" + ] + } + }, + { + "id": "WhenThereIsImgTagAndSrcWithNoSchema_NotWhitelisted_ThenConvertToPlain", + "html": "", + "expectedFile": "ConverterTests.WhenThereIsImgTagAndSrcWithNoSchema_NotWhitelisted_ThenConvertToPlain.verified.md", + "config": { + "WhitelistUriSchemes": [ + "whatever" + ] + } + }, + { + "id": "WhenThereIsImgTagWithRelativeUrl_NotWhitelisted_ThenConvertToMarkdown", + "html": "", + "expectedFile": "ConverterTests.WhenThereIsImgTagWithRelativeUrl_NotWhitelisted_ThenConvertToMarkdown.verified.md", + "config": { + "WhitelistUriSchemes": [ + "data" + ] + } + }, + { + "id": "WhenThereIsImgTagWithUnixUrl_ConfigHasWhitelist_ThenConvertToMarkdown", + "html": "", + "expectedFile": "ConverterTests.WhenThereIsImgTagWithUnixUrl_ConfigHasWhitelist_ThenConvertToMarkdown.verified.md", + "config": { + "WhitelistUriSchemes": [ + "file" + ] + } + }, + { + "id": "WhenThereIsImgTagWithHttpProtocolRelativeUrl_ConfigHasWhitelist_ThenConvertToMarkdown", + "html": "", + "expectedFile": "ConverterTests.WhenThereIsImgTagWithHttpProtocolRelativeUrl_ConfigHasWhitelist_ThenConvertToMarkdown.verified.md", + "config": { + "WhitelistUriSchemes": [ + "http" + ] + } + }, + { + "id": "WhenThereIsBase64ImgTag_WithDefaultConfig_ThenIncludeInMarkdown", + "html": "

    Before

    \"test\"

    After

    ", + "expectedFile": "ConverterTests.WhenThereIsBase64ImgTag_WithDefaultConfig_ThenIncludeInMarkdown.verified.md" + }, + { + "id": "WhenThereIsBase64ImgTag_WithSkipConfig_ThenSkipImage", + "html": "

    Before

    \"test\"

    After

    ", + "expectedFile": "ConverterTests.WhenThereIsBase64ImgTag_WithSkipConfig_ThenSkipImage.verified.md", + "config": { + "Base64Images": "Skip" + } + }, + { + "id": "WhenThereIsBase64JpegImgTag_WithSkipConfig_ThenSkipImage", + "html": "\"jpeg\"", + "expectedFile": "ConverterTests.WhenThereIsBase64JpegImgTag_WithSkipConfig_ThenSkipImage.verified.md", + "config": { + "Base64Images": "Skip" + } + }, + { + "id": "WhenThereIsBase64ImgTag_WithSaveToFileConfigButNoDirectory_ThenSkipImage", + "html": "

    Before

    \"test\"

    After

    ", + "expectedFile": "ConverterTests.WhenThereIsBase64ImgTag_WithSaveToFileConfigButNoDirectory_ThenSkipImage.verified.md", + "config": { + "Base64Images": "SaveToFile" + } + }, + { + "id": "WhenThereIsPreTag_ThenConvertToMarkdownPre", + "html": "This text has pre tag content
    Predefined text
    Next line of text", + "expectedFile": "ConverterTests.WhenThereIsPreTag_ThenConvertToMarkdownPre.verified.md" + }, + { + "id": "WhenThereIsEmptyPreTag_ThenConvertToMarkdownPre", + "html": "This text has pre tag content

    Next line of text", + "expectedFile": "ConverterTests.WhenThereIsEmptyPreTag_ThenConvertToMarkdownPre.verified.md" + }, + { + "id": "WhenThereIsEmptyPreTag_ThenConvertToMarkdownPre_GFM", + "html": "This text has pre tag content

    Next line of text", + "expectedFile": "ConverterTests.WhenThereIsEmptyPreTag_ThenConvertToMarkdownPre_GFM.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "WhenThereIsUnorderedList_ThenConvertToMarkdownList", + "html": "This text has unordered list.
    • Item1
    • Item2
    ", + "expectedFile": "ConverterTests.WhenThereIsUnorderedList_ThenConvertToMarkdownList.verified.md" + }, + { + "id": "WhenThereIsUnorderedListAndBulletIsAsterisk_ThenConvertToMarkdownList", + "html": "This text has unordered list.
    • Item1
    • Item2
    ", + "expectedFile": "ConverterTests.WhenThereIsUnorderedListAndBulletIsAsterisk_ThenConvertToMarkdownList.verified.md", + "config": { + "ListBulletChar": "*" + } + }, + { + "id": "WhenThereIsInputListWithGithubFlavoredEnabled_ThenConvertToMarkdownCheckList", + "html": "
    • Unchecked
    • Checked
    ", + "expectedFile": "ConverterTests.WhenThereIsInputListWithGithubFlavoredEnabled_ThenConvertToMarkdownCheckList.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "WhenThereIsInputListWithGithubFlavoredDisabled_ThenConvertToTypicalMarkdownList", + "html": "
    • Unchecked
    • Checked
    ", + "expectedFile": "ConverterTests.WhenThereIsInputListWithGithubFlavoredDisabled_ThenConvertToTypicalMarkdownList.verified.md", + "config": { + "GithubFlavored": false + } + }, + { + "id": "WhenThereIsOrderedList_ThenConvertToMarkdownList", + "html": "This text has ordered list.
    1. Item1
    2. Item2
    ", + "expectedFile": "ConverterTests.WhenThereIsOrderedList_ThenConvertToMarkdownList.verified.md" + }, + { + "id": "WhenThereIsOrderedListWithNestedUnorderedList_ThenConvertToMarkdownListWithNestedList", + "html": "This text has ordered list.
    1. OuterItem1
      • InnerItem1
      • InnerItem2
    2. Item2
    ", + "expectedFile": "ConverterTests.WhenThereIsOrderedListWithNestedUnorderedList_ThenConvertToMarkdownListWithNestedList.verified.md" + }, + { + "id": "WhenThereIsUnorderedListWithNestedOrderedList_ThenConvertToMarkdownListWithNestedList", + "html": "This text has ordered list.
    • OuterItem1
      1. InnerItem1
      2. InnerItem2
    • Item2
    ", + "expectedFile": "ConverterTests.WhenThereIsUnorderedListWithNestedOrderedList_ThenConvertToMarkdownListWithNestedList.verified.md" + }, + { + "id": "WhenThereIsWhitespaceAroundNestedLists_PreventBlankLinesWhenConvertingToMarkdownList", + "html": "
      \n
    • OuterItem1\n
        \n
      1. InnerItem1
      2. \n
      \n
    • \n
    • Item2
    • \n
        \n
      1. InnerItem2
      2. \n
      \n
    • Item3
    • \n
    ", + "expectedFile": "ConverterTests.WhenThereIsWhitespaceAroundNestedLists_PreventBlankLinesWhenConvertingToMarkdownList.verified.md" + }, + { + "id": "WhenListItemTextContainsLeadingAndTrailingSpacesAndTabs_ThenConvertToMarkdownListItemWithSpacesAndTabsStripped", + "html": "
    1. \t This is a text with leading and trailing spaces and tabs\t\t
    ", + "expectedFile": "ConverterTests.WhenListItemTextContainsLeadingAndTrailingSpacesAndTabs_ThenConvertToMarkdownListItemWithSpacesAndTabsStripped.verified.md" + }, + { + "id": "WhenListContainsNewlineAndTabBetweenTagBorders_CleanupAndConvertToMarkdown", + "html": "
      \n\t
    1. \n\t\tItem1
    2. \n\t
    3. \n\t\tItem2
    ", + "expectedFile": "ConverterTests.WhenListContainsNewlineAndTabBetweenTagBorders_CleanupAndConvertToMarkdown.verified.md" + }, + { + "id": "WhenListContainsMultipleParagraphs_ConvertToMarkdownAndIndentSiblings", + "html": "
      \n\t
    1. \n\t\t

      Paragraph 1

      \n

      Paragraph 1.1

      \n

      Paragraph 1.2

    2. \n\t
    3. \n\t\t

      Paragraph 3

    ", + "expectedFile": "ConverterTests.WhenListContainsMultipleParagraphs_ConvertToMarkdownAndIndentSiblings.verified.md" + }, + { + "id": "WhenListContainsParagraphsOutsideItems_ConvertToMarkdownAndIndentSiblings", + "html": "
      \n\t
    1. Item1
    2. \n\t

      Item 1 additional info

      \n\t
    3. Item2
    4. \n
    ", + "expectedFile": "ConverterTests.WhenListContainsParagraphsOutsideItems_ConvertToMarkdownAndIndentSiblings.verified.md" + }, + { + "id": "When_OrderedListIsInTable_LeaveListAsHtml", + "html": "
    Heading
    1. Item1
    ", + "expectedFile": "ConverterTests.When_OrderedListIsInTable_LeaveListAsHtml.verified.md" + }, + { + "id": "When_UnorderedListIsInTable_LeaveListAsHtml", + "html": "
    Heading
    • Item1
    ", + "expectedFile": "ConverterTests.When_UnorderedListIsInTable_LeaveListAsHtml.verified.md" + }, + { + "id": "When_Underline_Tag_With_UnknownTagsReplacer_ThenConvertToItalics", + "html": "This is underline text.", + "expectedFile": "ConverterTests.When_Underline_Tag_With_UnknownTagsReplacer_ThenConvertToItalics.verified.md", + "config": { + "UnknownTagsReplacer": { + "u": "*" + } + } + }, + { + "id": "When_Underline_Tag_With_TagAlias_ThenConvertToItalics", + "html": "This is underline text.", + "expectedFile": "ConverterTests.When_Underline_Tag_With_TagAlias_ThenConvertToItalics.verified.md", + "config": { + "TagAliases": { + "u": "em" + } + } + }, + { + "id": "Check_Converter_With_Unknown_Tag_ByPass_Option", + "html": "text in unknown tag", + "expectedFile": "ConverterTests.Check_Converter_With_Unknown_Tag_ByPass_Option.verified.md", + "config": { + "UnknownTags": "Bypass" + } + }, + { + "id": "WhenStyletagWithBypassOption_ReturnEmpty", + "html": "", + "expectedFile": "ConverterTests.WhenStyletagWithBypassOption_ReturnEmpty.verified.md", + "config": { + "UnknownTags": "Bypass" + } + }, + { + "id": "Check_Converter_With_Unknown_Tag_Drop_Option", + "html": "text in unknown tag

    paragraph text

    ", + "expectedFile": "ConverterTests.Check_Converter_With_Unknown_Tag_Drop_Option.verified.md", + "config": { + "UnknownTags": "Drop" + } + }, + { + "id": "Check_Converter_With_Unknown_Tag_PassThrough_Option", + "html": "text in unknown tag

    paragraph text

    ", + "expectedFile": "ConverterTests.Check_Converter_With_Unknown_Tag_PassThrough_Option.verified.md", + "config": { + "UnknownTags": "PassThrough" + } + }, + { + "id": "WhenTable_ThenConvertToGFMTable", + "html": "
    col1col2col3
    data1data2data3
    ", + "expectedFile": "ConverterTests.WhenTable_ThenConvertToGFMTable.verified.md", + "config": { + "UnknownTags": "Bypass" + } + }, + { + "id": "WhenTable_WithoutHeaderRow_With_TableWithoutHeaderRowHandlingOptionEmptyRow_ThenConvertToGFMTable_WithEmptyHeaderRow", + "html": "
    data1data2data3
    data4data5data6
    ", + "expectedFile": "ConverterTests.WhenTable_WithoutHeaderRow_With_TableWithoutHeaderRowHandlingOptionEmptyRow_ThenConvertToGFMTable_WithEmptyHeaderRow.verified.md", + "config": { + "UnknownTags": "Bypass", + "TableWithoutHeaderRowHandling": "EmptyRow" + } + }, + { + "id": "WhenTable_WithoutHeaderRow_With_TableWithoutHeaderRowHandlingOptionDefault_ThenConvertToGFMTable_WithFirstRowAsHeaderRow", + "html": "
    data1data2data3
    data4data5data6
    ", + "expectedFile": "ConverterTests.WhenTable_WithoutHeaderRow_With_TableWithoutHeaderRowHandlingOptionDefault_ThenConvertToGFMTable_WithFirstRowAsHeaderRow.verified.md", + "config": { + "UnknownTags": "Bypass" + } + }, + { + "id": "WhenTable_Cell_Content_WithNewline_Add_BR_ThenConvertToGFMTable", + "html": "
    col1col2col3
    data line1\nline2data2data3
    ", + "expectedFile": "ConverterTests.WhenTable_Cell_Content_WithNewline_Add_BR_ThenConvertToGFMTable.verified.md", + "config": { + "UnknownTags": "Bypass" + } + }, + { + "id": "WhenTable_CellContainsParagraph_AddBrThenConvertToGFMTable", + "html": "
    col1

    line1

    line2

    ", + "expectedFile": "ConverterTests.WhenTable_CellContainsParagraph_AddBrThenConvertToGFMTable.verified.md" + }, + { + "id": "WhenTable_ContainsTheadTh_ConvertToGFMTable", + "html": "
    col1col2
    data1data2
    ", + "expectedFile": "ConverterTests.WhenTable_ContainsTheadTh_ConvertToGFMTable.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "WhenTable_ContainsTheadTd_ConvertToGFMTable", + "html": "
    col1col2
    data1data2
    ", + "expectedFile": "ConverterTests.WhenTable_ContainsTheadTd_ConvertToGFMTable.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "WhenTable_CellContainsBr_PreserveBrAndConvertToGFMTable", + "html": "
    col1
    line 1
    line 2
    ", + "expectedFile": "ConverterTests.WhenTable_CellContainsBr_PreserveBrAndConvertToGFMTable.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "WhenTable_HasEmptyRow_DropsEmptyRow", + "html": "
    abc
    ", + "expectedFile": "ConverterTests.WhenTable_HasEmptyRow_DropsEmptyRow.verified.md", + "config": { + "GithubFlavored": true, + "TableWithoutHeaderRowHandling": "EmptyRow" + } + }, + { + "id": "When_BR_With_GitHubFlavored_Config_ThenConvertToGFM_BR", + "html": "First part
    Second part", + "expectedFile": "ConverterTests.When_BR_With_GitHubFlavored_Config_ThenConvertToGFM_BR.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "When_PRE_With_GitHubFlavored_Config_ThenConvertToGFM_PRE", + "html": "
    var test = 'hello world';
    ", + "expectedFile": "ConverterTests.When_PRE_With_GitHubFlavored_Config_ThenConvertToGFM_PRE.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "When_PRE_With_Confluence_Lang_Class_Att_And_GitHubFlavored_Config_ThenConvertToGFM_PRE", + "html": "
    var test = 'hello world';
    ", + "expectedFile": "ConverterTests.When_PRE_With_Confluence_Lang_Class_Att_And_GitHubFlavored_Config_ThenConvertToGFM_PRE.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "When_PRE_With_Github_Site_DIV_Parent_And_GitHubFlavored_Config_ThenConvertToGFM_PRE", + "html": "
    var test = \"hello world\";
    ", + "expectedFile": "ConverterTests.When_PRE_With_Github_Site_DIV_Parent_And_GitHubFlavored_Config_ThenConvertToGFM_PRE.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "When_PRE_With_HighlightJs_Lang_Class_Att_And_GitHubFlavored_Config_ThenConvertToGFM_PRE", + "html": "
    var test = \"hello world\";
    ", + "expectedFile": "ConverterTests.When_PRE_With_HighlightJs_Lang_Class_Att_And_GitHubFlavored_Config_ThenConvertToGFM_PRE.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "When_PRE_With_Lang_Highlight_Class_Att_And_GitHubFlavored_Config_ThenConvertToGFM_PRE", + "html": "
    var test = 'hello world';
    ", + "expectedFile": "ConverterTests.When_PRE_With_Lang_Highlight_Class_Att_And_GitHubFlavored_Config_ThenConvertToGFM_PRE.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "WhenRemovedCommentsIsEnabled_CommentsAreRemoved", + "html": "Hello there content

    ", + "expectedFile": "ConverterTests.WhenCommentOverlapTag_WithRemoveComments_ThenDoNotStripContentBetweenComments.verified.md", + "config": { + "RemoveComments": true + } + }, + { + "id": "WhenBoldTagContainsBRTag_ThenConvertToMarkdown", + "html": "test
    test
    ", + "expectedFile": "ConverterTests.WhenBoldTagContainsBRTag_ThenConvertToMarkdown.verified.md" + }, + { + "id": "WhenAnchorTagContainsImgTag_LinkTextShouldNotBeEscaped", + "html": "", + "expectedFile": "ConverterTests.WhenAnchorTagContainsImgTag_LinkTextShouldNotBeEscaped.verified.md" + }, + { + "id": "When_PRE_Without_Lang_Marker_Class_Att_And_GitHubFlavored_Config_With_DefaultCodeBlockLanguage_ThenConvertToGFM_PRE", + "html": "
    var test = \"hello world\";
    ", + "expectedFile": "ConverterTests.When_PRE_Without_Lang_Marker_Class_Att_And_GitHubFlavored_Config_With_DefaultCodeBlockLanguage_ThenConvertToGFM_PRE.verified.md", + "config": { + "GithubFlavored": true, + "DefaultCodeBlockLanguage": "csharp" + } + }, + { + "id": "When_PRE_With_Parent_DIV_And_Non_GitHubFlavored_Config_FirstLine_CodeBlock_SpaceIndent_Should_Be_Retained", + "html": "
    var test = \"hello world\";
    ", + "expectedFile": "ConverterTests.When_PRE_With_Parent_DIV_And_Non_GitHubFlavored_Config_FirstLine_CodeBlock_SpaceIndent_Should_Be_Retained.verified.md" + }, + { + "id": "When_Converting_HTML_Ensure_To_Process_Only_Body", + "html": "sample text", + "expectedFile": "ConverterTests.When_Converting_HTML_Ensure_To_Process_Only_Body.verified.md" + }, + { + "id": "When_Html_Containing_Nested_DIVs_Process_ONLY_Inner_Most_DIV", + "html": "
    sample text
    ", + "expectedFile": "ConverterTests.When_Html_Containing_Nested_DIVs_Process_ONLY_Inner_Most_DIV.verified.md" + }, + { + "id": "When_SingleChild_BlockTag_With_Parent_DIV_Ignore_Processing_DIV", + "html": "

    sample text

    ", + "expectedFile": "ConverterTests.When_SingleChild_BlockTag_With_Parent_DIV_Ignore_Processing_DIV.verified.md" + }, + { + "id": "When_Table_Within_List_Should_Be_Indented", + "html": "
    1. Item1
    2. Item2
      col1col2col3
      data1data2data3
    3. Item3
    ", + "expectedFile": "ConverterTests.When_Table_Within_List_Should_Be_Indented.verified.md" + }, + { + "id": "When_Tag_In_PassThoughTags_List_Then_Use_PassThroughConverter", + "html": "This text has image \"alt\". Next line of text", + "expectedFile": "ConverterTests.When_Tag_In_PassThoughTags_List_Then_Use_PassThroughConverter.verified.md", + "config": { + "PassThroughTags": [ + "img" + ] + } + }, + { + "id": "When_CodeContainsSpaces_ShouldPreserveSpaces", + "html": "A JavaScript function ...", + "expectedFile": "ConverterTests.When_CodeContainsSpaces_ShouldPreserveSpaces.verified.md" + }, + { + "id": "When_CodeContainsSpanWithExtraSpaces_Should_NotNormalizeSpaces", + "html": "A JavaScript function ...", + "expectedFile": "ConverterTests.When_CodeContainsSpanWithExtraSpaces_Should_NotNormalizeSpaces.verified.md" + }, + { + "id": "When_CodeContainsSpacesAndIsSurroundedByWhitespace_Should_NotRemoveSpaces", + "html": "A JavaScript function ...", + "expectedFile": "ConverterTests.When_CodeContainsSpacesAndIsSurroundedByWhitespace_Should_NotRemoveSpaces.verified.md" + }, + { + "id": "When_PreTag_Contains_IndentedFirstLine_Should_PreserveIndentation", + "html": "
        function foo {
    ", + "expectedFile": "ConverterTests.When_PreTag_Contains_IndentedFirstLine_Should_PreserveIndentation.verified.md" + }, + { + "id": "When_PreTag_Contains_IndentedFirstLine_Should_PreserveIndentation_GFM", + "html": "
        function foo {
    ", + "expectedFile": "ConverterTests.When_PreTag_Contains_IndentedFirstLine_Should_PreserveIndentation_GFM.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "When_PreTag_Within_List_Should_Be_Indented", + "html": "
    1. Item1
    2. Item2
       test
      \n test
    3. Item3
    ", + "expectedFile": "ConverterTests.When_PreTag_Within_List_Should_Be_Indented.verified.md" + }, + { + "id": "When_PreTag_Within_List_Should_Be_Indented_With_GitHub_FlavouredMarkdown", + "html": "
    1. Item1
    2. Item2
       test
      \n test
    3. Item3
    ", + "expectedFile": "ConverterTests.When_PreTag_Within_List_Should_Be_Indented_With_GitHub_FlavouredMarkdown.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "When_Text_Contains_NewLineChars_Should_Not_Convert_To_BR", + "html": "

    line 1
    line 2

    ", + "expectedFile": "ConverterTests.When_Text_Contains_NewLineChars_Should_Not_Convert_To_BR.verified.md" + }, + { + "id": "When_Text_Contains_NewLineChars_Should_Not_Convert_To_BR_GitHub_Flavoured", + "html": "

    line 1
    line 2

    ", + "expectedFile": "ConverterTests.When_Text_Contains_NewLineChars_Should_Not_Convert_To_BR_GitHub_Flavoured.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "When_Consecutive_Strong_Tags_Should_Convert_Properly", + "html": "block1block2block3block4", + "expectedFile": "ConverterTests.When_Consecutive_Strong_Tags_Should_Convert_Properly.verified.md" + }, + { + "id": "When_Consecutive_Em_Tags_Should_Convert_Properly", + "html": "block1block2block3block4", + "expectedFile": "ConverterTests.When_Consecutive_Em_Tags_Should_Convert_Properly.verified.md" + }, + { + "id": "Li_With_No_Parent", + "html": "
  • item
  • ", + "expectedFile": "ConverterTests.Li_With_No_Parent.verified.md" + }, + { + "id": "When_Span_with_newline_Should_Convert_Properly", + "html": "2 sets\n30 mountain climbers", + "expectedFile": "ConverterTests.When_Span_with_newline_Should_Convert_Properly.verified.md" + }, + { + "id": "Bug255_table_newline_char_issue", + "html": "\n\n\n\n\n
    ProgressionFocus
    ", + "expectedFile": "ConverterTests.Bug255_table_newline_char_issue.verified.md" + }, + { + "id": "When_Content_Contains_script_tags_ignore_it", + "html": "

    simple paragraph

    ", + "expectedFile": "ConverterTests.When_Content_Contains_script_tags_ignore_it.verified.md" + }, + { + "id": "When_DescriptionListTag_ThenConvertToMarkdown_List", + "html": "
    Coffee
    Filter Coffee
    Hot Black Coffee
    Milk
    White Cold Drink
    ", + "expectedFile": "ConverterTests.When_DescriptionListTag_ThenConvertToMarkdown_List.verified.md" + }, + { + "id": "Bug294_Table_bug_with_row_superfluous_newlines", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
    \u6bd4\u8f83wordpresshexo & hugo
    \u642d\u5efa\u8981\u6c42\u4e00\u53f0\u670d\u52a1\u5668\u4ee5\u53ca\u8fd0\u884c\u73af\u5883\u9759\u6001\u751f\u6210\u9875\u9762\uff0c\u65e0\u9700\u670d\u52a1\u5668\u3002
    \u6027\u80fd\u7531\u4e8e\u662f\u52a8\u6001\u751f\u6210\u9875\u9762\uff0c\u53ef\u4ee5\u901a\u8fc7\u81ea\u884c\u914d\u7f6e\u63d0\u9ad8\u6027\u80fd\uff0c\u4f46\u662f\u4ecd\u7136\u65e0\u6cd5\u5ab2\u7f8e\u9759\u6001\u9875\u9762\u51e0\u4e4e\u65e0\u9700\u8003\u8651\u6027\u80fd\u95ee\u9898
    \u8bbf\u95ee\u901f\u5ea6\u4f9d\u8d56\u4e8e\u670d\u52a1\u5668\u914d\u7f6e\u4ee5\u53cacdn\u52a0\u901f\u3002\u53ea\u9700\u8003\u8651cdn\u52a0\u901f
    \u529f\u80fd\u5b8c\u5584\u4f5c\u4e3a\u5f3a\u5927\u7684cms\u529f\u80fd\u5f88\u5b8c\u5584\uff0c\u9700\u8981\u7684\u529f\u80fd\u57fa\u672c\u53ef\u4ee5\u63d2\u4ef6\u4e0b\u8f7d\u76f4\u63a5\u5b9e\u73b0\u3002\u989d\u5916\u529f\u80fd\u4e5f\u53ef\u4ee5\u901a\u8fc7\u63d2\u4ef6\u5b9e\u73b0\uff0c\u4e0d\u8fc7\u7a0d\u5fae\u9700\u8981\u81ea\u884c\u67e5\u627e\u4ee5\u53cadiy
    \u540e\u53f0\u7ba1\u7406\u73b0\u6210\u7684\u540e\u53f0\u7ba1\u7406\u529f\u80fd\uff0c\u5f00\u7bb1\u5373\u7528\u7531\u4e8e\u9759\u6001\u535a\u5ba2\uff0c\u672c\u8eab\u6ca1\u6709\u540e\u53f0\u7ba1\u7406\uff0c\u6709\u9700\u6c42\u9700\u8981\u81ea\u884c\u641c\u7d22\u5b9e\u73b0
    ", + "expectedFile": "ConverterTests.Bug294_Table_bug_with_row_superfluous_newlines.verified.md" + }, + { + "id": "WhenTableHeadingWithAlignmentStyles_ThenTableHeaderShouldHaveProperAlignment", + "html": "
    Col1Col2Col2
    123
    ", + "expectedFile": "ConverterTests.WhenTableHeadingWithAlignmentStyles_ThenTableHeaderShouldHaveProperAlignment.verified.md" + }, + { + "id": "When_Sup_And_Nested_Sup", + "html": "This is the 1st sentence to test the sup tag conversion", + "expectedFile": "ConverterTests.When_Sup_And_Nested_Sup.verified.md" + }, + { + "id": "When_Anchor_Text_with_Underscore_Do_Not_Escape", + "html": "This a sample paragraph from https://www.w3schools.com/html/mov_bbb.mp4", + "expectedFile": "ConverterTests.When_Anchor_Text_with_Underscore_Do_Not_Escape.verified.md" + }, + { + "id": "When_Strikethrough_And_Nested_Strikethrough", + "html": "This is the 1st sentence to test the strikethrough tag conversion", + "expectedFile": "ConverterTests.When_Strikethrough_And_Nested_Strikethrough.verified.md" + }, + { + "id": "When_Spaces_In_Inline_Tags_Should_Be_Retained", + "html": "... example html code block", + "expectedFile": "ConverterTests.When_Spaces_In_Inline_Tags_Should_Be_Retained.verified.md" + }, + { + "id": "When_SuppressNewlineFlag_PrefixDiv_Should_Be_Empty", + "html": "
    the
    fox
    jumps
    over
    ", + "expectedFile": "ConverterTests.When_SuppressNewlineFlag_PrefixDiv_Should_Be_Empty.verified.md", + "config": { + "SuppressDivNewlines": true + } + }, + { + "id": "WhenTable_WithColSpan_TableHeaderColumnSpansHandling_ThenConvertToGFMTable", + "html": "
    col1col2col3
    data1data2.1data2.2data3
    ", + "expectedFile": "ConverterTests.WhenTable_WithColSpan_TableHeaderColumnSpansHandling_ThenConvertToGFMTable.verified.md", + "config": { + "UnknownTags": "Bypass" + } + }, + { + "id": "Bug391_AnchorTagUnnecessarilyIndented", + "html": "

    \n\n

    \n\n\n
    \nAn error occurred while importing data from feed 'FBA Producten'. More details can be found in the latest \">feed validation report.\n
    \n\n\n\n\n\" class=\"btn btn-primary btn-sm my-2\" target=\"_blank\">View feed 4", + "expectedFile": "ConverterTests.Bug391_AnchorTagUnnecessarilyIndented.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "Bug403_unexpectedBehaviourWhenTableBodyRowsWithTHCells", + "html": "\n\n\n\n
    Heading1Heading2
    data 1data 2
    data 3data 4
    ", + "expectedFile": "ConverterTests.Bug403_unexpectedBehaviourWhenTableBodyRowsWithTHCells.verified.md", + "config": { + "UnknownTags": "Bypass", + "ListBulletChar": "*", + "GithubFlavored": true + } + }, + { + "id": "EscapeMarkdownCharsInTextProperly", + "html": "[a-z]([0-9]){0,4}", + "expectedFile": "ConverterTests.EscapeMarkdownCharsInTextProperly.verified.md" + }, + { + "id": "Bug400_MissingSpanSpaceWithItalics", + "html": "

    What we thought: When we built Pages, we assumed that customers would use them like newsletters to share relevant, continually-updated information with field teams.

    ", + "expectedFile": "ConverterTests.Bug400_MissingSpanSpaceWithItalics.verified.md" + }, + { + "id": "When_NestedParagraphs_FiveLevelsDeep_ThenConvertCorrectly", + "html": "

    Level1

    Level2

    Level3

    Level4

    Level5

    ", + "expectedFile": "ConverterTests.When_NestedParagraphs_FiveLevelsDeep_ThenConvertCorrectly.verified.md", + "config": { + "GithubFlavored": true, + "UnknownTags": "Bypass" + } + }, + { + "id": "When_NestedSpans_FiveLevelsDeep_ThenConvertCorrectly", + "html": "Level1Level2Level3Level4Level5", + "expectedFile": "ConverterTests.When_NestedSpans_FiveLevelsDeep_ThenConvertCorrectly.verified.md", + "config": { + "UnknownTags": "Bypass" + } + }, + { + "id": "When_InterleavedParagraphsAndSpans_ThenConvertCorrectly", + "html": "

    Text1

    Text2

    Text3

    Text4

    ", + "expectedFile": "ConverterTests.When_InterleavedParagraphsAndSpans_ThenConvertCorrectly.verified.md", + "config": { + "GithubFlavored": true, + "UnknownTags": "Bypass" + } + }, + { + "id": "When_ManySequentialUnclosedParagraphs_ThenConvertCorrectly", + "html": "

    Part1

    Part2

    Part3

    Part4

    Part5

    Part6

    Part7

    Part8", + "expectedFile": "ConverterTests.When_ManySequentialUnclosedParagraphs_ThenConvertCorrectly.verified.md", + "config": { + "GithubFlavored": true, + "UnknownTags": "Bypass" + } + }, + { + "id": "When_UnclosedParagraphsWithSpansAndTextNodes_ThenConvertCorrectly", + "html": "

    Intro

    Filler text here.

    Section1

    Section2

    Section3", + "expectedFile": "ConverterTests.When_UnclosedParagraphsWithSpansAndTextNodes_ThenConvertCorrectly.verified.md", + "config": { + "GithubFlavored": true, + "UnknownTags": "Bypass" + } + }, + { + "id": "When_EmptyNestedParagraphs_ThenConvertCorrectly", + "html": "

    ", + "expectedFile": "ConverterTests.When_EmptyNestedParagraphs_ThenConvertCorrectly.verified.md", + "config": { + "UnknownTags": "Bypass" + } + }, + { + "id": "When_AlternatingEmptyAndFilledNestedParagraphs_ThenConvertCorrectly", + "html": "

    A

    B

    C

    D

    E

    ", + "expectedFile": "ConverterTests.When_AlternatingEmptyAndFilledNestedParagraphs_ThenConvertCorrectly.verified.md", + "config": { + "UnknownTags": "Bypass" + } + }, + { + "id": "When_NestedParagraphs_TenLevelsDeep_ThenConvertCorrectly", + "html": "

    L1

    L2

    L3

    L4

    L5

    L6

    L7

    L8

    L9

    L10

    ", + "expectedFile": "ConverterTests.When_NestedParagraphs_TenLevelsDeep_ThenConvertCorrectly.verified.md", + "config": { + "GithubFlavored": true, + "UnknownTags": "Bypass" + } + }, + { + "id": "When_NestedTableIsInTable_LeaveNestedTableAsHtml", + "html": "
    StepInstructions
    1
    ConditionAction
    ADo X
    ", + "expectedFile": "ConverterTests.When_NestedTableIsInTable_LeaveNestedTableAsHtml.verified.md" + }, + { + "id": "When_ComplexNestedTableIsInTable_LeaveNestedTableAsHtml", + "html": "\n \n \n \n \n \n \n \n \n
    CategoryDetails
    Products\n \n \n \n \n
    NamePrice
    Item 1$10
    Item 2$20
    \n
    ", + "expectedFile": "ConverterTests.When_ComplexNestedTableIsInTable_LeaveNestedTableAsHtml.verified.md" + }, + { + "id": "When_MultipleNestedTablesInTable_LeaveAllNestedTablesAsHtml", + "html": "\n \n \n \n \n \n \n \n \n
    Column 1Column 2
    \n \n \n
    Nested 1
    \n
    \n \n \n
    Nested 2
    \n
    ", + "expectedFile": "ConverterTests.When_MultipleNestedTablesInTable_LeaveAllNestedTablesAsHtml.verified.md" + }, + { + "id": "WhenTable_WithCaption_ThenCaptionAppearsAboveTable", + "html": "
    Monthly Sales Report
    MonthSales
    January$1000
    ", + "expectedFile": "ConverterTests.WhenTable_WithCaption_ThenCaptionAppearsAboveTable.verified.md" + }, + { + "id": "WhenTable_WithoutCaption_ThenConvertNormally", + "html": "
    MonthSales
    January$1000
    ", + "expectedFile": "ConverterTests.WhenTable_WithoutCaption_ThenConvertNormally.verified.md" + }, + { + "id": "WhenTable_WithEmptyCaption_ThenConvertNormally", + "html": "
    MonthSales
    January$1000
    ", + "expectedFile": "ConverterTests.WhenTable_WithEmptyCaption_ThenConvertNormally.verified.md" + }, + { + "id": "WhenTable_WithCaptionContainingWhitespace_ThenTrimWhitespace", + "html": "
    Table Caption
    Col1
    Data1
    ", + "expectedFile": "ConverterTests.WhenTable_WithCaptionContainingWhitespace_ThenTrimWhitespace.verified.md" + }, + { + "id": "WhenTable_WithCaptionContainingMarkdownChars_ThenHandleProperly", + "html": "
    Sales Report [2024] - **Important**
    MonthSales
    Jan$100
    ", + "expectedFile": "ConverterTests.WhenTable_WithCaptionContainingMarkdownChars_ThenHandleProperly.verified.md" + }, + { + "id": "WhenTable_WithCaptionAndNoHeaderRow_EmptyRowHandling_ThenCaptionAppearsAboveTable", + "html": "
    Data Table
    data1data2
    data3data4
    ", + "expectedFile": "ConverterTests.WhenTable_WithCaptionAndNoHeaderRow_EmptyRowHandling_ThenCaptionAppearsAboveTable.verified.md", + "config": { + "TableWithoutHeaderRowHandling": "EmptyRow" + } + }, + { + "id": "WhenTable_WithCaptionContainingNestedTags_ThenExtractTextOnly", + "html": "
    Sales Report for 2024
    Month
    Jan
    ", + "expectedFile": "ConverterTests.WhenTable_WithCaptionContainingNestedTags_ThenExtractTextOnly.verified.md" + }, + { + "id": "WhenTable_WithCaptionAndGithubFlavored_ThenCaptionAppearsAboveTable", + "html": "
    Code Review Summary
    PRStatus
    #123Approved
    ", + "expectedFile": "ConverterTests.WhenTable_WithCaptionAndGithubFlavored_ThenCaptionAppearsAboveTable.verified.md", + "config": { + "GithubFlavored": true + } + }, + { + "id": "WhenTable_WithCaptionContainingNewlines_ThenHandleNewlines", + "html": "
    Multi\nLine\nCaption
    Col
    Data
    ", + "expectedFile": "ConverterTests.WhenTable_WithCaptionContainingNewlines_ThenHandleNewlines.verified.md" + }, + { + "id": "WhenTableRowWithDuplicateStyleKeysAfterTrimming_ThenConvertWithoutException", + "html": "
    Header
    Data
    ", + "expectedFile": "ConverterTests.WhenTableRowWithDuplicateStyleKeysAfterTrimming_ThenConvertWithoutException.verified.md" + }, + { + "id": "SmartHandling_HttpScheme_Http", + "html": "example.com", + "dataOnly": true + }, + { + "id": "SmartHandling_HttpScheme_Https", + "html": "example.com", + "dataOnly": true + }, + { + "id": "SmartHandling_OutputOnlyHref_Http", + "html": "example.com", + "dataOnly": true + }, + { + "id": "SmartHandling_OutputOnlyHref_Https", + "html": "example.com", + "dataOnly": true + }, + { + "id": "SmartHandling_NonWellFormed", + "html": "http://example.com/path/file name.docx", + "dataOnly": true + }, + { + "id": "SmartHandling_ImplicitFile", + "html": "\tc:\\\\directory\\filename", + "dataOnly": true + }, + { + "id": "SmartHandling_FileMissingSlash", + "html": "file://c:/directory/filename", + "dataOnly": true + }, + { + "id": "SmartHandling_UnescapedBackslashes", + "html": "http:\\\\host/path/file", + "dataOnly": true + }, + { + "id": "Base64_SaveToFile_Png", + "html": "

    Before

    \"test\"

    After

    ", + "dataOnly": true + }, + { + "id": "Base64_SaveToFile_Jpeg", + "html": "\"jpeg\"", + "dataOnly": true + }, + { + "id": "Base64_SaveToFile_Multiple", + "html": "\"first\"\"second\"", + "dataOnly": true + }, + { + "id": "Base64_SaveToFile_CustomName", + "html": "\"test\"", + "dataOnly": true + }, + { + "id": "Base64_SaveToFile_NonExistentDir", + "html": "\"test\"", + "dataOnly": true + }, + { + "id": "Underline_Tag_Alias", + "html": "This is underline text.", + "dataOnly": true + }, + { + "id": "Unknown_Tag_Raise", + "html": "text in unknown tag

    paragraph text

    ", + "dataOnly": true + }, + { + "id": "PastedHtmlUnicodeSpaces", + "html": "Markdown Monster is an easy to use and extensible\u00a0Markdown Editor,\u00a0Viewer\u00a0and\u00a0Weblog Publisher\u00a0for Windows. Our goal is to provide the best Markdown specific editor for Windows and make it as easy as possible to create Markdown documents. We provide a core editor and previewer, and a number of non-intrusive helpers to help embed content like images, links, tables, code and more into your documents with minimal effort.", + "dataOnly": true + }, + { + "id": "Bug393_RegressionWithVaryingNewLines", + "html": "This is regular text\n

    This is HTML:

    • Line 1
    • Line 2
    • Line 3 has an unknown tag

    ", + "expectedFile": "ConverterTests.Bug393_RegressionWithVaryingNewLines.verified.md", + "config": { + "UnknownTags": "Bypass", + "ListBulletChar": "*" + } + }, + { + "id": "SlackFlavored_Bold", + "html": "test | test", + "expectedFile": "ConverterTests.SlackFlavored_Bold.verified.md", + "config": { + "SlackFlavored": true + } + }, + { + "id": "SlackFlavored_Bullets", + "html": "
      \n
    • Item 1
    • \n
    • Item 2
    • \n
    • Item 3
    • \n
    ", + "expectedFile": "ConverterTests.SlackFlavored_Bullets.verified.md", + "config": { + "SlackFlavored": true + } + }, + { + "id": "SlackFlavored_Italic", + "html": "test | test", + "expectedFile": "ConverterTests.SlackFlavored_Italic.verified.md", + "config": { + "SlackFlavored": true + } + }, + { + "id": "SlackFlavored_Strikethrough", + "html": "test", + "expectedFile": "ConverterTests.SlackFlavored_Strikethrough.verified.md", + "config": { + "SlackFlavored": true + } + }, + { + "id": "Converter_Is_Thread_Safe_For_Concurrent_Use", + "html": "
    Head
    1. Item1
    2. Item2

    Tail

    ", + "dataOnly": true + }, + { + "id": "SlackFlavored_Unsupported_Hr", + "html": "
    ", + "dataOnly": true + }, + { + "id": "SlackFlavored_Unsupported_Img", + "html": "", + "dataOnly": true + }, + { + "id": "SlackFlavored_Unsupported_Sup", + "html": "test", + "dataOnly": true + }, + { + "id": "SlackFlavored_Unsupported_Table", + "html": "
    ", + "dataOnly": true + }, + { + "id": "SlackFlavored_Unsupported_Table_Td", + "html": "", + "dataOnly": true + }, + { + "id": "SlackFlavored_Unsupported_Table_Tr", + "html": "", + "dataOnly": true + } +] \ No newline at end of file From ca8cb584f92b6a5dbfd4c2a8f68cd3df1a4277be Mon Sep 17 00:00:00 2001 From: mysticmnd Date: Tue, 24 Feb 2026 16:22:38 +0530 Subject: [PATCH 4/5] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e5d54b..fcaa877 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you have used and benefitted from this library. Please feel free to sponsor m **Markdown flavors** - GitHub Flavoured Markdown conversion for br, pre, tasklists, and table. Use `var config = new ReverseMarkdown.Config(githubFlavoured:true);`. By default the table will always be converted to Github flavored markdown immaterial of this flag - Slack Flavoured Markdown conversion. Use `var config = new ReverseMarkdown.Config { SlackFlavored = true };` -- CommonMark-focused output with opt-in flags to preserve compatibility. Use `var config = new ReverseMarkdown.Config { CommonMark = true };` +- CommonMark-focused output with opt-in flags to preserve compatibility. Use `var config = new ReverseMarkdown.Config { CommonMark = true };` This mode may emit inline HTML for tricky emphasis/link cases unless you disable `CommonMarkUseHtmlInlineTags`. **Tables** - Support for nested tables (converted as HTML inside markdown) From 057f6ea81b2e351f00bd708a14a7c7c1b902bb65 Mon Sep 17 00:00:00 2001 From: mysticmnd Date: Tue, 24 Feb 2026 16:23:28 +0530 Subject: [PATCH 5/5] Bump up version to 5.2.0 --- src/ReverseMarkdown/ReverseMarkdown.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ReverseMarkdown/ReverseMarkdown.csproj b/src/ReverseMarkdown/ReverseMarkdown.csproj index 4977570..3f0ed13 100644 --- a/src/ReverseMarkdown/ReverseMarkdown.csproj +++ b/src/ReverseMarkdown/ReverseMarkdown.csproj @@ -1,7 +1,7 @@  ReverseMarkdown is a Html to Markdown converter library in c# - 5.1.0 + 5.2.0 Babu Annamalai net8.0;net9.0;net10.0 preview