From 5b6f1db2838ea0c14545e81b80a7096d82ae2985 Mon Sep 17 00:00:00 2001 From: Toinedb Date: Fri, 1 Nov 2024 18:08:29 +0100 Subject: [PATCH 1/3] code block options --- src/MarkdownParser/IViewSupplier.cs | 18 ++++ src/MarkdownParser/ListBulletFormatter.cs | 30 ------- src/MarkdownParser/MarkdownParser.csproj | 6 ++ src/MarkdownParser/ViewFormatter.cs | 13 ++- src/MarkdownParser/ViewWriter.cs | 82 ++++++++++++++----- .../MarkdownParser.Test.csproj | 6 ++ .../MarkdownParserSectionsSpecs.cs | 33 ++++++++ .../Mocks/StringComponentSupplier.cs | 15 ++++ .../Resources/Examples/Sections/codeblocks.md | 8 ++ 9 files changed, 155 insertions(+), 56 deletions(-) delete mode 100644 src/MarkdownParser/ListBulletFormatter.cs create mode 100644 test/MarkdownParser.Test/Resources/Examples/Sections/codeblocks.md diff --git a/src/MarkdownParser/IViewSupplier.cs b/src/MarkdownParser/IViewSupplier.cs index 2c7e231..1eff70f 100644 --- a/src/MarkdownParser/IViewSupplier.cs +++ b/src/MarkdownParser/IViewSupplier.cs @@ -72,5 +72,23 @@ public interface IViewSupplier /// placeholder string /// T GetPlaceholder(string placeholderName); + + /// + /// a view that shows fenced code found in MD blocks starting with ```cs + /// + /// + T GetFencedCodeBlock(string content, string codeInfo); + + /// + /// a view that shows indented code found in MD lines starting with at least 4 spaces + /// + /// + T GetIndentedCodeBlock(string content); + + /// + /// get a textual line break + /// + /// + string GetTextualLineBreak(); } } diff --git a/src/MarkdownParser/ListBulletFormatter.cs b/src/MarkdownParser/ListBulletFormatter.cs deleted file mode 100644 index 6a96d6a..0000000 --- a/src/MarkdownParser/ListBulletFormatter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Globalization; - -namespace MarkdownParser -{ - public static class ListBulletFormatter - { - public static string GetListItemBullet(bool isOrderedList, int sequenceNumber, int listLevel, string listItemBulletOddCharacter, string listItemBulletEvenCharacter) - { - // 'listlevel' even or odd (list start at level 1 == odd) - var isListOddLeveled = (listLevel % 2) != 0; - - if (!isOrderedList) - { - return (isListOddLeveled) - ? listItemBulletOddCharacter - : listItemBulletEvenCharacter; - } - - const int aCharacterPosition = 97; // character 'a' position in ASCI table - var sequenceNumberCharacterPosition = -1 + aCharacterPosition + sequenceNumber; - - var bullet = (isListOddLeveled) - ? sequenceNumber.ToString() - : Convert.ToChar(sequenceNumberCharacterPosition, CultureInfo.InvariantCulture).ToString(); - - return $"{bullet}."; - } - } -} diff --git a/src/MarkdownParser/MarkdownParser.csproj b/src/MarkdownParser/MarkdownParser.csproj index dc60480..5e485e8 100644 --- a/src/MarkdownParser/MarkdownParser.csproj +++ b/src/MarkdownParser/MarkdownParser.csproj @@ -49,4 +49,10 @@ + + + <_Parameter1>MarkdownParser.Test + + + diff --git a/src/MarkdownParser/ViewFormatter.cs b/src/MarkdownParser/ViewFormatter.cs index af12363..11ae746 100644 --- a/src/MarkdownParser/ViewFormatter.cs +++ b/src/MarkdownParser/ViewFormatter.cs @@ -69,17 +69,22 @@ private void WriteBlockToView(Block block, ViewWriter writer, bool continueWi writer.StartAndFinalizeThematicBreak(); break; case BlockTag.FencedCode: + writer.StartAndFinalizeFencedCodeBlock(block.StringContent, block.FencedCodeData.Info); + break; case BlockTag.IndentedCode: - // not supported + writer.StartAndFinalizeIndentedCodeBlock(block.StringContent); break; case BlockTag.HtmlBlock: - // TODO.....if needed + // TODO + var currentBlock3 = block; + break; //writer.StartBlock(BlockTag.Paragraph, block.StringContent.ToString()); //WriteBlockToView(block.FirstChild, writer); //writer.FinalizeParagraphBlock(); break; case BlockTag.ReferenceDefinition: - // not supported + // TODO + var currentBlock4 = block; break; default: throw new CommonMarkException("Block type " + block.Tag + " is not supported.", block); @@ -114,7 +119,7 @@ private void WriteInlineToView(Inline inline, ViewWriter writer) break; case InlineTag.SoftBreak: case InlineTag.LineBreak: - writer.AddText(Environment.NewLine); + writer.AddText(writer.GetTextualLineBreak()); break; case InlineTag.Placeholder: writer.StartAndFinalizePlaceholderBlock(inline.TargetUrl); diff --git a/src/MarkdownParser/ViewWriter.cs b/src/MarkdownParser/ViewWriter.cs index 6eb147d..2f3d6a4 100644 --- a/src/MarkdownParser/ViewWriter.cs +++ b/src/MarkdownParser/ViewWriter.cs @@ -1,7 +1,8 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; +using System.Text; using CommonMark.Syntax; namespace MarkdownParser @@ -10,8 +11,13 @@ public class ViewWriter { private IViewSupplier ViewSupplier { get; } private List WrittenViews { get; set; } = new List(); - private Stack> Workbench { get; } = new Stack>(); + + public ViewWriter(IViewSupplier viewSupplier) + { + ViewSupplier = viewSupplier; + } + private ViewWriterCache GetWorkbenchItem() { if (Workbench.Count == 0) @@ -22,11 +28,6 @@ private ViewWriterCache GetWorkbenchItem() return Workbench.Peek(); } - public ViewWriter(IViewSupplier viewSupplier) - { - ViewSupplier = viewSupplier; - } - public List Flush() { var collectedViews = WrittenViews; @@ -57,8 +58,9 @@ public void FinalizeParagraphBlock() foreach (var itemsCacheTuple in itemsCache) { - var view = !string.IsNullOrEmpty(itemsCacheTuple.Item1) ? - ViewSupplier.GetTextView(itemsCacheTuple.Item1) : itemsCacheTuple.Item2; + var view = !string.IsNullOrEmpty(itemsCacheTuple.Item1) + ? ViewSupplier.GetTextView(itemsCacheTuple.Item1) + : itemsCacheTuple.Item2; if (view != null) { @@ -94,7 +96,6 @@ public void FinalizeHeaderBlock(int headerLevel) var wbi = GetWorkbenchItem(); if (wbi.ComponentType != BlockTag.AtxHeading && wbi.ComponentType != BlockTag.SetextHeading) - { Debug.WriteLine($"Finalizing Header can not finalize {wbi.ComponentType}"); return; @@ -107,8 +108,9 @@ public void FinalizeHeaderBlock(int headerLevel) foreach (var itemsCacheTuple in itemsCache) { - var view = !string.IsNullOrEmpty(itemsCacheTuple.Item1) ? - ViewSupplier.GetHeaderView(itemsCacheTuple.Item1, headerLevel) : itemsCacheTuple.Item2; + var view = !string.IsNullOrEmpty(itemsCacheTuple.Item1) + ? ViewSupplier.GetHeaderView(itemsCacheTuple.Item1, headerLevel) + : itemsCacheTuple.Item2; views.Add(view); } @@ -155,8 +157,9 @@ public void FinalizeListItemBlock(ListData listData) foreach (var itemsCacheTuple in itemsCache) { - var view = !string.IsNullOrEmpty(itemsCacheTuple.Item1) ? - ViewSupplier.GetTextView(itemsCacheTuple.Item1) : itemsCacheTuple.Item2; + var view = !string.IsNullOrEmpty(itemsCacheTuple.Item1) + ? ViewSupplier.GetTextView(itemsCacheTuple.Item1) + : itemsCacheTuple.Item2; if (view != null) { @@ -164,9 +167,9 @@ public void FinalizeListItemBlock(ListData listData) } } - var flattendView = StackViews(views); + var flattenedView = StackViews(views); - var listItemView = ViewSupplier.GetListItemView(flattendView, isOrderedList, sequenceNumber, depthLevel); + var listItemView = ViewSupplier.GetListItemView(flattenedView, isOrderedList, sequenceNumber, depthLevel); StoreView(listItemView); } @@ -182,10 +185,26 @@ public void StartAndFinalizeImageBlock(string targetUrl, string subscription, st StoreView(imageView); } + public void StartAndFinalizeFencedCodeBlock(StringContent content, string blockInfo) + { + var parsedContent = ParseStringContentToString(content); + + var codeBlock = ViewSupplier.GetFencedCodeBlock(parsedContent, blockInfo); + StoreView(codeBlock); + } + + public void StartAndFinalizeIndentedCodeBlock(StringContent content) + { + var parsedContent = ParseStringContentToString(content); + + var codeBlock = ViewSupplier.GetIndentedCodeBlock(parsedContent); + StoreView(codeBlock); + } + public void StartAndFinalizeThematicBreak() { - var seperator = ViewSupplier.GetThematicBreak(); - StoreView(seperator); + var separator = ViewSupplier.GetThematicBreak(); + StoreView(separator); } public void StartAndFinalizePlaceholderBlock(string placeholderName) @@ -194,16 +213,23 @@ public void StartAndFinalizePlaceholderBlock(string placeholderName) StoreView(placeholderView); } + public string GetTextualLineBreak() + { + return ViewSupplier.GetTextualLineBreak(); + } + private T StackViews(List views) { - if (views == null || views.Count == 0) + if (views == null + || views.Count == 0) { return default(T); } // multiple views combine a single stack layout - var viewToStore = views.Count == 1 ? - views[0] : ViewSupplier.GetStackLayoutView(views); + var viewToStore = views.Count == 1 + ? views[0] + : ViewSupplier.GetStackLayoutView(views); return viewToStore; } @@ -226,6 +252,18 @@ private void StoreView(T view) WrittenViews.Add(view); } } + + private string ParseStringContentToString(StringContent content) + { + var stringWriter = new StringWriter(); + content.WriteTo(stringWriter); + var contentLines = stringWriter.ToString(); + + contentLines = contentLines.Replace("\r", ""); + contentLines = contentLines.TrimEnd('\n'); + contentLines = contentLines.Replace("\n", GetTextualLineBreak()); + return contentLines; + } } } diff --git a/test/MarkdownParser.Test/MarkdownParser.Test.csproj b/test/MarkdownParser.Test/MarkdownParser.Test.csproj index f93842d..9637277 100644 --- a/test/MarkdownParser.Test/MarkdownParser.Test.csproj +++ b/test/MarkdownParser.Test/MarkdownParser.Test.csproj @@ -13,20 +13,26 @@ + + + + + + diff --git a/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs b/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs index 5617526..d66bdc5 100644 --- a/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs +++ b/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs @@ -98,4 +98,37 @@ public void When_parsing_nested_list_it_should_output_nesting_by_level() splittedViews[12].Should().Be("_False.2.1_textview"); splittedViews[13].Should().Be("item2-3(mockComponentSupplier); + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + var parseResult = parser.Parse(markdown); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + parseResult.Count.Should().Be(2); + + var view0Parts = parseResult[0].Split('|'); + view0Parts[0].Should().Be("fencedcodeview>"); + view0Parts[1].Should().Be("(cs)"); + view0Parts[2].Should().Be("var myNumber = 1;\r\nmyNumber++;"); + view0Parts[3].Should().Be(""); + view1Parts[1].Should().Be("the first line for IndentedCode code block\r\nthe second line for IndentedCode code block\r\nthe third line for IndentedCode code block"); + view1Parts[2].Should().Be("|({codeInfo})|{content}||{content}| Date: Sat, 2 Nov 2024 14:26:33 +0100 Subject: [PATCH 2/3] html support --- src/MarkdownParser/IViewSupplier.cs | 14 +++- src/MarkdownParser/ViewFormatter.cs | 7 +- src/MarkdownParser/ViewWriter.cs | 23 ++++-- .../MarkdownParserSectionsSpecs.cs | 75 ++++++++++++++++--- .../Mocks/StringComponentSupplier.cs | 5 ++ .../Resources/Examples/Sections/htmlblocks.md | 14 ++++ 6 files changed, 110 insertions(+), 28 deletions(-) create mode 100644 test/MarkdownParser.Test/Resources/Examples/Sections/htmlblocks.md diff --git a/src/MarkdownParser/IViewSupplier.cs b/src/MarkdownParser/IViewSupplier.cs index 1eff70f..c68b5c9 100644 --- a/src/MarkdownParser/IViewSupplier.cs +++ b/src/MarkdownParser/IViewSupplier.cs @@ -4,6 +4,12 @@ namespace MarkdownParser { public interface IViewSupplier { + /// + /// get a textual line break + /// + /// + string GetTextualLineBreak(); + /// /// a default text view /// @@ -74,21 +80,21 @@ public interface IViewSupplier T GetPlaceholder(string placeholderName); /// - /// a view that shows fenced code found in MD blocks starting with ```cs + /// a view that shows fenced code (found in MD blocks starting with ```cs ) /// /// T GetFencedCodeBlock(string content, string codeInfo); /// - /// a view that shows indented code found in MD lines starting with at least 4 spaces + /// a view that shows indented code (found in MD lines starting with at least 4 spaces) /// /// T GetIndentedCodeBlock(string content); /// - /// get a textual line break + /// a view that shows html content /// /// - string GetTextualLineBreak(); + T GetHtmlBlock(string content); } } diff --git a/src/MarkdownParser/ViewFormatter.cs b/src/MarkdownParser/ViewFormatter.cs index 11ae746..a1d67d4 100644 --- a/src/MarkdownParser/ViewFormatter.cs +++ b/src/MarkdownParser/ViewFormatter.cs @@ -75,12 +75,7 @@ private void WriteBlockToView(Block block, ViewWriter writer, bool continueWi writer.StartAndFinalizeIndentedCodeBlock(block.StringContent); break; case BlockTag.HtmlBlock: - // TODO - var currentBlock3 = block; - break; - //writer.StartBlock(BlockTag.Paragraph, block.StringContent.ToString()); - //WriteBlockToView(block.FirstChild, writer); - //writer.FinalizeParagraphBlock(); + writer.StartAndFinalizeHtmlBlock(block.StringContent); break; case BlockTag.ReferenceDefinition: // TODO diff --git a/src/MarkdownParser/ViewWriter.cs b/src/MarkdownParser/ViewWriter.cs index 2f3d6a4..78134f2 100644 --- a/src/MarkdownParser/ViewWriter.cs +++ b/src/MarkdownParser/ViewWriter.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; using CommonMark.Syntax; namespace MarkdownParser @@ -187,18 +186,26 @@ public void StartAndFinalizeImageBlock(string targetUrl, string subscription, st public void StartAndFinalizeFencedCodeBlock(StringContent content, string blockInfo) { - var parsedContent = ParseStringContentToString(content); + var parsedContent = StringContentToStringWithLineBreaks(content); - var codeBlock = ViewSupplier.GetFencedCodeBlock(parsedContent, blockInfo); - StoreView(codeBlock); + var blockView = ViewSupplier.GetFencedCodeBlock(parsedContent, blockInfo); + StoreView(blockView); } public void StartAndFinalizeIndentedCodeBlock(StringContent content) { - var parsedContent = ParseStringContentToString(content); + var parsedContent = StringContentToStringWithLineBreaks(content); - var codeBlock = ViewSupplier.GetIndentedCodeBlock(parsedContent); - StoreView(codeBlock); + var blockView = ViewSupplier.GetIndentedCodeBlock(parsedContent); + StoreView(blockView); + } + + public void StartAndFinalizeHtmlBlock(StringContent content) + { + var parsedContent = StringContentToStringWithLineBreaks(content); + + var blockView = ViewSupplier.GetHtmlBlock(parsedContent); + StoreView(blockView); } public void StartAndFinalizeThematicBreak() @@ -253,7 +260,7 @@ private void StoreView(T view) } } - private string ParseStringContentToString(StringContent content) + private string StringContentToStringWithLineBreaks(StringContent content) { var stringWriter = new StringWriter(); content.WriteTo(stringWriter); diff --git a/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs b/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs index d66bdc5..a9022e4 100644 --- a/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs +++ b/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs @@ -120,15 +120,70 @@ public void When_parsing_codeblocks_it_should_output_code_views() //----------------------------------------------------------------------------------------------------------- parseResult.Count.Should().Be(2); - var view0Parts = parseResult[0].Split('|'); - view0Parts[0].Should().Be("fencedcodeview>"); - view0Parts[1].Should().Be("(cs)"); - view0Parts[2].Should().Be("var myNumber = 1;\r\nmyNumber++;"); - view0Parts[3].Should().Be(""); - view1Parts[1].Should().Be("the first line for IndentedCode code block\r\nthe second line for IndentedCode code block\r\nthe third line for IndentedCode code block"); - view1Parts[2].Should().Be(""); + codeViewComponentsGroup0[1].Should().Be("(cs)"); + codeViewComponentsGroup0[2].Should().Be("var myNumber = 1;\r\nmyNumber++;"); + codeViewComponentsGroup0[3].Should().Be(""); + codeViewComponentsGroup1[1].Should().Be("the first line for IndentedCode code block\r\nthe second line for IndentedCode code block\r\nthe third line for IndentedCode code block"); + codeViewComponentsGroup1[2].Should().Be("(mockComponentSupplier); + + var newLineIndicator = mockComponentSupplier.GetTextualLineBreak(); + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + var parseResult = parser.Parse(markdown); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + parseResult.Count.Should().Be(2); + + var htmlViewComponentsGroup0 = parseResult[0].Split('|'); + htmlViewComponentsGroup0.Length.Should().Be(3); + htmlViewComponentsGroup0.First().Should().Be("htmlview>"); + htmlViewComponentsGroup0.Last().Should().Be("First text in block

"); + firstHtmlViewContentGroup[1].Trim().Should().Be("
"); + firstHtmlViewContentGroup[2].Trim().Should().Be("

Header

"); + firstHtmlViewContentGroup[3].Trim().Should().Be("

Same block but nested element

"); + firstHtmlViewContentGroup[4].Trim().Should().Be("
"); + + var htmlViewComponentsGroup1 = parseResult[1].Split('|'); + htmlViewComponentsGroup1.Length.Should().Be(3); + htmlViewComponentsGroup1.First().Should().Be("htmlview>"); + htmlViewComponentsGroup1.Last().Should().Be(""); + secondHtmlViewContentGroup[1].Trim().Should().Be("
"); + secondHtmlViewContentGroup[2].Trim().Should().Be("

A heading

"); + secondHtmlViewContentGroup[3].Trim().Should().Be("

Posted by John Doe

"); + secondHtmlViewContentGroup[4].Trim().Should().Be("

Some additional information here

"); + secondHtmlViewContentGroup[5].Trim().Should().Be("
"); + secondHtmlViewContentGroup[6].Trim().Should().Be("

Lorem Ipsum...

"); + secondHtmlViewContentGroup[7].Trim().Should().Be(""); } } diff --git a/test/MarkdownParser.Test/Mocks/StringComponentSupplier.cs b/test/MarkdownParser.Test/Mocks/StringComponentSupplier.cs index 41dad75..254fb8c 100644 --- a/test/MarkdownParser.Test/Mocks/StringComponentSupplier.cs +++ b/test/MarkdownParser.Test/Mocks/StringComponentSupplier.cs @@ -62,6 +62,11 @@ public string GetIndentedCodeBlock(string content) return $"indentedview>|{content}||{content}|First text in block

+
+

Header

+

Same block but nested element

+
+ +
+
+

A heading

+

Posted by John Doe

+

Some additional information here

+
+

Lorem Ipsum...

+
\ No newline at end of file From 74d714140e730673df6babe112a98b3ddfcb27b5 Mon Sep 17 00:00:00 2001 From: Toinedb Date: Sat, 2 Nov 2024 16:36:03 +0100 Subject: [PATCH 3/3] suport reference definitions --- src/MarkdownParser/IViewSupplier.cs | 7 ++++ .../MarkdownReferenceDefinition.cs | 10 +++++ src/MarkdownParser/ViewFormatter.cs | 7 +++- src/MarkdownParser/ViewWriter.cs | 34 ++++++++++++++++ .../MarkdownParserSectionsSpecs.cs | 40 +++++++++++++++++++ .../Mocks/StringComponentSupplier.cs | 16 ++++++++ .../Examples/Sections/referencedefinitions.md | 7 ++++ 7 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 src/MarkdownParser/MarkdownReferenceDefinition.cs create mode 100644 test/MarkdownParser.Test/Resources/Examples/Sections/referencedefinitions.md diff --git a/src/MarkdownParser/IViewSupplier.cs b/src/MarkdownParser/IViewSupplier.cs index c68b5c9..522bb28 100644 --- a/src/MarkdownParser/IViewSupplier.cs +++ b/src/MarkdownParser/IViewSupplier.cs @@ -96,5 +96,12 @@ public interface IViewSupplier /// /// T GetHtmlBlock(string content); + + /// + /// a view that shows reference definitions ([link]s usually at the end of the document) + /// + /// collection of Reference Definitions + /// + T GetReferenceDefinitions(IEnumerable markdownReferenceDefinitions); } } diff --git a/src/MarkdownParser/MarkdownReferenceDefinition.cs b/src/MarkdownParser/MarkdownReferenceDefinition.cs new file mode 100644 index 0000000..5ab3892 --- /dev/null +++ b/src/MarkdownParser/MarkdownReferenceDefinition.cs @@ -0,0 +1,10 @@ +namespace MarkdownParser +{ + public class MarkdownReferenceDefinition + { + public string Label { get; set; } + public string Url { get; set; } + public string Title { get; set; } + public bool IsPlaceholder { get; set; } + } +} \ No newline at end of file diff --git a/src/MarkdownParser/ViewFormatter.cs b/src/MarkdownParser/ViewFormatter.cs index a1d67d4..851e480 100644 --- a/src/MarkdownParser/ViewFormatter.cs +++ b/src/MarkdownParser/ViewFormatter.cs @@ -17,12 +17,15 @@ public ViewFormatter(IViewSupplier viewSupplier) public List Format(Block markdownBlock) { WriteBlockToView(markdownBlock, _writer); + _writer.StartAndFinalizeReferenceDefinitions(); + return _writer.Flush(); } public List FormatSingleBlock(Block markdownBlock) { WriteBlockToView(markdownBlock, _writer, false); + return _writer.Flush(); } @@ -36,6 +39,7 @@ private void WriteBlockToView(Block block, ViewWriter writer, bool continueWi switch (block.Tag) { case BlockTag.Document: + _writer.RegisterReferenceDefinitions(block.Document.ReferenceMap); WriteBlockToView(block.FirstChild, writer); break; case BlockTag.Paragraph: @@ -78,8 +82,7 @@ private void WriteBlockToView(Block block, ViewWriter writer, bool continueWi writer.StartAndFinalizeHtmlBlock(block.StringContent); break; case BlockTag.ReferenceDefinition: - // TODO - var currentBlock4 = block; + // ignore, handled at the end of document by _writer.StartAndFinalizeReferenceDefinitions() break; default: throw new CommonMarkException("Block type " + block.Tag + " is not supported.", block); diff --git a/src/MarkdownParser/ViewWriter.cs b/src/MarkdownParser/ViewWriter.cs index 78134f2..2578803 100644 --- a/src/MarkdownParser/ViewWriter.cs +++ b/src/MarkdownParser/ViewWriter.cs @@ -11,6 +11,7 @@ public class ViewWriter private IViewSupplier ViewSupplier { get; } private List WrittenViews { get; set; } = new List(); private Stack> Workbench { get; } = new Stack>(); + private Dictionary _referenceDefinitions; public ViewWriter(IViewSupplier viewSupplier) { @@ -35,6 +36,11 @@ public List Flush() return collectedViews; } + public void RegisterReferenceDefinitions(Dictionary referenceDefinitions) + { + _referenceDefinitions = referenceDefinitions; + } + public void StartBlock(BlockTag blockType, string content = "") { Workbench.Push(new ViewWriterCache { ComponentType = blockType }); @@ -208,6 +214,34 @@ public void StartAndFinalizeHtmlBlock(StringContent content) StoreView(blockView); } + public void StartAndFinalizeReferenceDefinitions() + { + if (_referenceDefinitions == null || _referenceDefinitions.Count == 0) + { + return; + } + + var markdownReferenceDefinition = new List(); + foreach (var referenceDefinition in _referenceDefinitions) + { + if (referenceDefinition.Value == null) + { + continue; + } + + markdownReferenceDefinition.Add(new MarkdownReferenceDefinition() + { + IsPlaceholder = referenceDefinition.Value.IsPlaceholder, + Label = referenceDefinition.Value.Label, + Title = referenceDefinition.Value.Title, + Url = referenceDefinition.Value.Url + }); + } + + var view = ViewSupplier.GetReferenceDefinitions(markdownReferenceDefinition); + StoreView(view); + } + public void StartAndFinalizeThematicBreak() { var separator = ViewSupplier.GetThematicBreak(); diff --git a/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs b/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs index a9022e4..8500dba 100644 --- a/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs +++ b/test/MarkdownParser.Test/MarkdownParserSectionsSpecs.cs @@ -186,4 +186,44 @@ public void When_parsing_htmlblocks_it_should_output_html_views() secondHtmlViewContentGroup[6].Trim().Should().Be("

Lorem Ipsum...

"); secondHtmlViewContentGroup[7].Trim().Should().Be(""); } + + [TestMethod] + public void When_parsing_reference_definitions_it_should_output_specific_views() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + var markdown = FileReader.ReadFile("Sections.referencedefinitions.md"); + + var mockComponentSupplier = new StringComponentSupplier(); + var parser = new MarkdownParser(mockComponentSupplier); + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + var parseResult = parser.Parse(markdown); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + parseResult.Count.Should().Be(2); + parseResult[0].Should().StartWith("stackview>:+textview"); + + var referenceDefinitionsViewGroup = parseResult[1].Split('|'); + referenceDefinitionsViewGroup.Length.Should().Be(4); + referenceDefinitionsViewGroup.First().Should().Be("referencedefinitions>"); + referenceDefinitionsViewGroup.Last().Should().Be("|{content}| markdownReferenceDefinitions) + { + var content = "referencedefinitions>"; + foreach (var markdownReferenceDefinition in markdownReferenceDefinitions) + { + content += $"|{markdownReferenceDefinition.IsPlaceholder}"; + content += $"*{markdownReferenceDefinition.Label}"; + content += $"*{markdownReferenceDefinition.Title}"; + content += $"*{markdownReferenceDefinition.Url}"; + } + + content += "|