diff --git a/cs/Markdown/IMarkdown.cs b/cs/Markdown/IMarkdownRenderer.cs
similarity index 63%
rename from cs/Markdown/IMarkdown.cs
rename to cs/Markdown/IMarkdownRenderer.cs
index 7ac783395..ead0a1aae 100644
--- a/cs/Markdown/IMarkdown.cs
+++ b/cs/Markdown/IMarkdownRenderer.cs
@@ -1,6 +1,6 @@
namespace Markdown;
-public interface IMarkdown
+public interface IMarkdownRenderer
{
string Render(string markdown);
}
\ No newline at end of file
diff --git a/cs/Markdown/Markdown.csproj b/cs/Markdown/Markdown.csproj
index fbc0a9283..d1bae7ba4 100644
--- a/cs/Markdown/Markdown.csproj
+++ b/cs/Markdown/Markdown.csproj
@@ -10,11 +10,6 @@
-
-
-
-
-
diff --git a/cs/Markdown/MarkdownRenderer.cs b/cs/Markdown/MarkdownRenderer.cs
index 1327312d8..f42041825 100644
--- a/cs/Markdown/MarkdownRenderer.cs
+++ b/cs/Markdown/MarkdownRenderer.cs
@@ -1,101 +1,31 @@
using Markdown.Render;
using Markdown.Tokenizer;
using Markdown.Tokenizer.Handlers;
-using Markdown.Tokenizer.Nodes;
-using Markdown.Tokenizer.Tags;
+using Markdown.TreeBuilder;
namespace Markdown;
-public class MarkdownRenderer : IMarkdown
+public class MarkdownRenderer : IMarkdownRenderer
{
+ private readonly ITreeRenderer treeRenderer = new TreeRenderer();
+ private readonly ITokenizer tokenizer;
private readonly List handlers = new()
{
new HeaderHandler(),
new ItalicHandler(),
new BoldHandler(),
};
- public string Render(string markdown)
+
+ public MarkdownRenderer()
{
- var tokenizer = new MarkdownTokenizer(new HandlerManager(handlers), new TagProcessor());
- var renderer = new HtmlRenderer();
- var tokens = tokenizer.Tokenize(markdown);
- var tree = ToTree(tokens);
- return renderer.Render(tree);
+ tokenizer = new MarkdownTokenizer(new HandlerManager(handlers), new TagProcessor());
}
- private Node ToTree(List tokens)
+ public string Render(string markdown)
{
- Node mainNode = new MainNode();
- Node currentNode = mainNode;
- for (int i = 0; i < tokens.Count; i++)
- {
- if (tokens[i].TagStatus == TagStatus.Broken)
- {
- currentNode.Children.Add(new TextNode{Value = tokens[i].Value});
- continue;
- }
-
- if (tokens[i] is ItalicTag tag)
- {
- if(tag.TagStatus == TagStatus.Open)
- {
- var node = new ItalicNode();
- currentNode.Children.Add(node);
- node.Parent = currentNode;
- currentNode = node;
- continue;
- }
-
- if (tag.TagStatus == TagStatus.Closed)
- {
- currentNode = currentNode.Parent;
- continue;
- }
- }
-
- if (tokens[i] is BoldTag boldTag)
- {
- if(boldTag.TagStatus == TagStatus.Open)
- {
- var node = new BoldNode();
- currentNode.Children.Add(node);
- node.Parent = currentNode;
- currentNode = node;
- continue;
- }
-
- if (boldTag.TagStatus == TagStatus.Closed)
- {
- currentNode = currentNode.Parent;
- continue;
- }
- }
-
- if (tokens[i] is HeaderTag)
- {
- var node = new HeaderNode();
- currentNode.Children.Add(node);
- node.Parent = currentNode;
- currentNode = node;
- continue;
- }
-
- if (tokens[i] is NewLineToken)
- {
- if (currentNode is HeaderNode)
- {
- currentNode = currentNode.Parent;
- }
- continue;
- }
-
- if (tokens[i] is TextToken textToken)
- {
- currentNode.Children.Add(new TextNode { Value = textToken.Value });
- continue;
- }
- }
+ var tokens = tokenizer.Tokenize(markdown);
+ var tree = new TreeBuilder.TreeBuilder(new NodeFactory()).Build(tokens);
- return currentNode.Parent ?? currentNode;
+ return treeRenderer.Render(tree);
}
}
\ No newline at end of file
diff --git a/cs/Markdown/Render/ITokenRenderer.cs b/cs/Markdown/Render/ITokenRenderer.cs
deleted file mode 100644
index 12d3d2928..000000000
--- a/cs/Markdown/Render/ITokenRenderer.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using Markdown.Tokenizer.Nodes;
-
-namespace Markdown.Render;
-
-public interface ITokenRenderer
-{
- string Render(Node tokens);
-}
\ No newline at end of file
diff --git a/cs/Markdown/Render/ITreeRenderer.cs b/cs/Markdown/Render/ITreeRenderer.cs
new file mode 100644
index 000000000..ffcc74676
--- /dev/null
+++ b/cs/Markdown/Render/ITreeRenderer.cs
@@ -0,0 +1,8 @@
+using Markdown.TreeBuilder.Nodes;
+
+namespace Markdown.Render;
+
+public interface ITreeRenderer
+{
+ string Render(Node tokens);
+}
\ No newline at end of file
diff --git a/cs/Markdown/Render/HtmlRenderer.cs b/cs/Markdown/Render/TreeRenderer.cs
similarity index 54%
rename from cs/Markdown/Render/HtmlRenderer.cs
rename to cs/Markdown/Render/TreeRenderer.cs
index 63d9d72ac..74eda954f 100644
--- a/cs/Markdown/Render/HtmlRenderer.cs
+++ b/cs/Markdown/Render/TreeRenderer.cs
@@ -1,9 +1,9 @@
using System.Text;
-using Markdown.Tokenizer.Nodes;
+using Markdown.TreeBuilder.Nodes;
namespace Markdown.Render;
-public class HtmlRenderer : ITokenRenderer
+public class TreeRenderer : ITreeRenderer
{
public string Render(Node tokens)
{
@@ -19,10 +19,7 @@ public string Render(Node tokens)
return node switch
{
TextNode textNode => textNode.Value,
- HeaderNode => $"{Render(node)}
",
- ItalicNode => $"{Render(node)}",
- BoldNode => $"{Render(node)}",
- _ => throw new Exception($"Unknown token type: {node.GetType()}")
+ _ => $"{node.OpenTag}{Render(node)}{node.CloseTag}"
};
}
}
\ No newline at end of file
diff --git a/cs/Markdown/Tests/Markdown/MarkdownTests.cs b/cs/Markdown/Tests/Markdown/MarkdownTests.cs
index a2e1df0c5..83a8c2166 100644
--- a/cs/Markdown/Tests/Markdown/MarkdownTests.cs
+++ b/cs/Markdown/Tests/Markdown/MarkdownTests.cs
@@ -1,93 +1,43 @@
-namespace Markdown.Tests.Markdown;
+using NUnit.Framework;
+
+namespace Markdown.Tests.Markdown;
[TestFixture]
public class MarkdownTests
{
- private static readonly VerifySettings Settings = new();
- private static readonly MarkdownRenderer Renderer = new();
+ private IMarkdownRenderer renderer;
- [OneTimeSetUp]
- public void OneTimeSetUp()
+ [SetUp]
+ public void SetUp()
{
- Settings.UseDirectory("snapshots");
+ renderer = new MarkdownRenderer();
}
- [TestCaseSource(nameof(ItalicTestCases))]
- public string Test_1(string input) => Renderer.Render(input);
+ [TestCaseSource(nameof(MarkdownRendererTestCases))]
+ public string MarkdownRenderer_Verify(string input) => renderer.Render(input);
- private static TestCaseData[] ItalicTestCases =
+ private static TestCaseData[] MarkdownRendererTestCases =
[
- new TestCaseData("# Header").Returns("Header
"),
- new TestCaseData("\\# Header").Returns("# Header"),
- new TestCaseData("\\\\# Header").Returns("\\Header
"),
- new TestCaseData("_Italic text_").Returns("Italic text"),
- new TestCaseData("\\_Text_").Returns("_Text_"),
- new TestCaseData("\\\\_Italic text_").Returns("\\Italic text"),
- new TestCaseData("_Italic text").Returns("_Italic text"),
- new TestCaseData("Italic text_").Returns("Italic text_"),
- new TestCaseData("Italic_ text_").Returns("Italic_ text_"),
- new TestCaseData("_Italic _text").Returns("_Italic _text"),
- new TestCaseData("_нач_але").Returns("начале"),
- new TestCaseData("сер_еди_не").Returns("середине"),
- new TestCaseData("цифры_1_12_3").Returns("цифры_1_12_3"),
- new TestCaseData("кон_це._").Returns("конце."),
- new TestCaseData("в ра_зных сл_овах не").Returns("в ра_зных сл_овах не"),
- new TestCaseData("__bold__").Returns("bold"),
- new TestCaseData("_Text__").Returns("_Text__"),
- new TestCaseData("__Text_").Returns("__Text_"),
- new TestCaseData("__Italic __text").Returns("__Italic __text"),
- new TestCaseData("__два _один_ может__").Returns("два один может"),
- new TestCaseData("_одинарного __двойное__ не_").Returns( "одинарного __двойное__ не")
+ new TestCaseData("# Header").Returns("Header
").SetDescription("Простой заголовок."),
+ new TestCaseData("\\# Header").Returns("# Header").SetDescription("Экранированный заголовок."),
+ new TestCaseData("\\\\# Header").Returns("\\Header
").SetDescription("Экранирован экранирования."),
+ new TestCaseData("_Italic text_").Returns("Italic text").SetDescription("Курсив"),
+ new TestCaseData("\\_Text_").Returns("_Text_").SetDescription("Экранирование курсива."),
+ new TestCaseData("\\\\_Italic text_").Returns("\\Italic text").SetDescription("Экранирование экранирования курсива."),
+ new TestCaseData("_Italic text").Returns("_Italic text").SetDescription("Одинокий открывающий тэг."),
+ new TestCaseData("Italic text_").Returns("Italic text_").SetDescription("Одинокий закрывающий тэг."),
+ new TestCaseData("Italic_ text_").Returns("Italic_ text_").SetDescription("Два закрывающих тэга."),
+ new TestCaseData("_Italic _text").Returns("_Italic _text").SetDescription("Два открывающих тэга."),
+ new TestCaseData("_нач_але").Returns("начале").SetDescription("Курсив в начале слова."),
+ new TestCaseData("сер_еди_не").Returns("середине").SetDescription("Курсив в середине слова."),
+ new TestCaseData("кон_це._").Returns("конце.").SetDescription("Курсив в конце слова."),
+ new TestCaseData("цифры_1_12_3").Returns("цифры_1_12_3").SetDescription("Между цифр - подчерки."),
+ new TestCaseData("в ра_зных сл_овах не").Returns("в ра_зных сл_овах не").SetDescription("В разных словах - не работает."),
+ new TestCaseData("__bold__").Returns("bold").SetDescription("Полужирный"),
+ new TestCaseData("_Text__").Returns("_Text__").SetDescription("Разные тэги 1"),
+ new TestCaseData("__Text_").Returns("__Text_").SetDescription("Разные тэги 2"),
+ new TestCaseData("__Italic __text").Returns("__Italic __text").SetDescription("Два открывающих тэга."),
+ new TestCaseData("__два _один_ может__").Returns("два один может").SetDescription("Курсив в полужирном."),
+ new TestCaseData("_одинарного __двойное__ не_").Returns( "одинарного __двойное__ не").SetDescription("Полужирный в курсиве - не работает."),
];
-
- private static Task Verify(string target) =>
- Verifier.Verify(target, Settings);
-
- [Test]
- public void SimpleText_Render_Verify() =>
- Verify(Renderer.Render("Text"));
-
- [Test]
- public void EscapedCharacter_Render_Verify() =>
- Verify(Renderer.Render(@"\_Text_"));
-
- [Test]
- public void ItalicText_Render_Verify() =>
- Verify(Renderer.Render("_Italic text_"));
-
- [Test]
- public void BoldText_Render_Verify() =>
- Verify(Renderer.Render("__Bold text__"));
-
- [Test]
- public void BoldWithItalicText_Render_Verify() =>
- Verify(Renderer.Render("__Bold _with italic_ text__"));
-
- [Test]
- public void SimpleHeader_Render_Verify() =>
- Verify(Renderer.Render("# Header"));
-
- [Test]
- public void TwoHeaders_Render_Verify() =>
- Verify(Renderer.Render("# Header one \n# Header two"));
- //
- // [Test]
- // public void HeaderWithItalic_Render_Verify() =>
- // Verify(Renderer.Render("# Header with _italic text_"));
- //
- // [Test]
- // public void HeaderWithBoldAndItalic_Render_Verify() =>
- // Verify(Renderer.Render("# Header with _italic_ and __bold__ text"));
- //
- // [Test]
- // public void HeaderWithItalicInBold_Render_Verify() =>
- // Verify(Renderer.Render("# Header ___italic_ in bold__ text"));
- //
- // [Test]
- // public void SimpleList_Render_Verify() =>
- // Verify(Renderer.Render("- item1\n- item2"));
- //
- // [Test]
- // public void ListWithItalicAndBold_Render_Verify() =>
- // Verify(Renderer.Render("- _item1_\n- __item2__"));
}
\ No newline at end of file
diff --git a/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.SimpleHeader_Render_Verify.received.txt b/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.SimpleHeader_Render_Verify.received.txt
deleted file mode 100644
index 35ba349aa..000000000
--- a/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.SimpleHeader_Render_Verify.received.txt
+++ /dev/null
@@ -1 +0,0 @@
-Header
\ No newline at end of file
diff --git a/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.SimpleHeader_Render_Verify.verified.txt b/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.SimpleHeader_Render_Verify.verified.txt
deleted file mode 100644
index 35ba349aa..000000000
--- a/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.SimpleHeader_Render_Verify.verified.txt
+++ /dev/null
@@ -1 +0,0 @@
-Header
\ No newline at end of file
diff --git a/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.TwoHeaders_Render_Verify.received.txt b/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.TwoHeaders_Render_Verify.received.txt
deleted file mode 100644
index 71b2c8c9a..000000000
--- a/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.TwoHeaders_Render_Verify.received.txt
+++ /dev/null
@@ -1 +0,0 @@
-Header one
Header two
\ No newline at end of file
diff --git a/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.TwoHeaders_Render_Verify.verified.txt b/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.TwoHeaders_Render_Verify.verified.txt
deleted file mode 100644
index 71b2c8c9a..000000000
--- a/cs/Markdown/Tests/Markdown/snapshots/MarkdownTests.TwoHeaders_Render_Verify.verified.txt
+++ /dev/null
@@ -1 +0,0 @@
-Header one
Header two
\ No newline at end of file
diff --git a/cs/Markdown/Tests/Tokenizer/BoldHandlerTests.cs b/cs/Markdown/Tests/Tokenizer/BoldHandlerTests.cs
index a1519b5a0..f6c553d13 100644
--- a/cs/Markdown/Tests/Tokenizer/BoldHandlerTests.cs
+++ b/cs/Markdown/Tests/Tokenizer/BoldHandlerTests.cs
@@ -2,23 +2,32 @@
using Markdown.Tokenizer;
using Markdown.Tokenizer.Handlers;
using Markdown.Tokenizer.Tags;
+using Markdown.TreeBuilder;
+using NUnit.Framework;
namespace Markdown.Tests.Tokenizer;
[TestFixture]
public class BoldHandlerTests
{
+ private ITokenizer tokenizer;
+
+ [SetUp]
+ public void SetUp()
+ {
+ var handlers = new List { new HeaderHandler(), new ItalicHandler(), new BoldHandler() };
+ tokenizer = new MarkdownTokenizer(new HandlerManager(handlers), new TagProcessor());
+ }
+
[TestCaseSource(nameof(BoldTokenSource))]
public void BoldTokenizerTests((string input, Token[] tags) testCase)
{
- var handlers = new List() { new HeaderHandler(), new ItalicHandler(), new BoldHandler() };
- var tokenizer = new MarkdownTokenizer(new HandlerManager(handlers), new TagProcessor());
- var res = tokenizer.Tokenize(testCase.input).ToArray();
+ var tokens = tokenizer.Tokenize(testCase.input).ToArray();
for (var i = 0; i < testCase.tags.Length; i++)
{
- res[i].Value.Should().Be(testCase.tags[i].Value);
- res[i].TokenType.Should().Be(testCase.tags[i].TokenType);
+ tokens[i].Value.Should().Be(testCase.tags[i].Value);
+ tokens[i].TokenType.Should().Be(testCase.tags[i].TokenType);
}
}
diff --git a/cs/Markdown/Tests/Tokenizer/HeaderHandlerTests.cs b/cs/Markdown/Tests/Tokenizer/HeaderHandlerTests.cs
index 5f81ce304..97a07735e 100644
--- a/cs/Markdown/Tests/Tokenizer/HeaderHandlerTests.cs
+++ b/cs/Markdown/Tests/Tokenizer/HeaderHandlerTests.cs
@@ -2,23 +2,32 @@
using Markdown.Tokenizer;
using Markdown.Tokenizer.Handlers;
using Markdown.Tokenizer.Tags;
+using Markdown.TreeBuilder;
+using NUnit.Framework;
namespace Markdown.Tests.Tokenizer;
[TestFixture]
public class HeaderHandlerTests
{
+ private ITokenizer tokenizer;
+
+ [SetUp]
+ public void SetUp()
+ {
+ var handlers = new List { new HeaderHandler(), new ItalicHandler(), new BoldHandler() };
+ tokenizer = new MarkdownTokenizer(new HandlerManager(handlers), new TagProcessor());
+ }
+
[TestCaseSource(nameof(HeaderTokenSource))]
public void HeaderTokenizerTests((string input, Token[] tags) testCase)
{
- var handlers = new List() { new HeaderHandler(), new ItalicHandler(), new BoldHandler() };
- var tokenizer = new MarkdownTokenizer(new HandlerManager(handlers), new TagProcessor());
- var res = tokenizer.Tokenize(testCase.input).ToArray();
+ var tokens = tokenizer.Tokenize(testCase.input).ToArray();
for (var i = 0; i < testCase.tags.Length; i++)
{
- res[i].Value.Should().Be(testCase.tags[i].Value);
- res[i].TokenType.Should().Be(testCase.tags[i].TokenType);
+ tokens[i].Value.Should().Be(testCase.tags[i].Value);
+ tokens[i].TokenType.Should().Be(testCase.tags[i].TokenType);
}
}
diff --git a/cs/Markdown/Tests/Tokenizer/ItalicHandlerTests.cs b/cs/Markdown/Tests/Tokenizer/ItalicHandlerTests.cs
index c2b68e3c5..45bbc1ce9 100644
--- a/cs/Markdown/Tests/Tokenizer/ItalicHandlerTests.cs
+++ b/cs/Markdown/Tests/Tokenizer/ItalicHandlerTests.cs
@@ -2,6 +2,8 @@
using Markdown.Tokenizer;
using Markdown.Tokenizer.Handlers;
using Markdown.Tokenizer.Tags;
+using Markdown.TreeBuilder;
+using NUnit.Framework;
namespace Markdown.Tests.Tokenizer;
@@ -9,17 +11,24 @@ namespace Markdown.Tests.Tokenizer;
[TestFixture]
public class ItalicParserTests
{
+ private ITokenizer tokenizer;
+
+ [SetUp]
+ public void SetUp()
+ {
+ var handlers = new List { new HeaderHandler(), new ItalicHandler(), new BoldHandler() };
+ tokenizer = new MarkdownTokenizer(new HandlerManager(handlers), new TagProcessor());
+ }
+
[TestCaseSource(nameof(ItalicTokenSource))]
public void ItalicTokenizerTests((string input, Token[] tags) testCase)
{
- var handlers = new List() { new HeaderHandler(), new ItalicHandler(), new BoldHandler() };
- var tokenizer = new MarkdownTokenizer(new HandlerManager(handlers), new TagProcessor());
- var res = tokenizer.Tokenize(testCase.input).ToArray();
+ var tokens = tokenizer.Tokenize(testCase.input).ToArray();
for (var i = 0; i < testCase.tags.Length; i++)
{
- res[i].Value.Should().Be(testCase.tags[i].Value);
- res[i].TokenType.Should().Be(testCase.tags[i].TokenType);
+ tokens[i].Value.Should().Be(testCase.tags[i].Value);
+ tokens[i].TokenType.Should().Be(testCase.tags[i].TokenType);
}
}
diff --git a/cs/Markdown/Tokenizer/Handlers/ItalicHandler.cs b/cs/Markdown/Tokenizer/Handlers/ItalicHandler.cs
index 8af2fb70f..1a26c97e8 100644
--- a/cs/Markdown/Tokenizer/Handlers/ItalicHandler.cs
+++ b/cs/Markdown/Tokenizer/Handlers/ItalicHandler.cs
@@ -8,10 +8,7 @@ public class ItalicHandler : IHandler
{
var symbol = ctx.Current;
- if(symbol != '_')
- return null;
-
- if(ctx.Next == '_')
+ if(symbol != '_' || ctx.Next == '_')
return null;
if (char.IsDigit(ctx.Previous ?? ' ') || char.IsDigit(ctx.Next ?? ' '))
diff --git a/cs/Markdown/Tokenizer/Nodes/BoldNode.cs b/cs/Markdown/Tokenizer/Nodes/BoldNode.cs
deleted file mode 100644
index 3e42a57e0..000000000
--- a/cs/Markdown/Tokenizer/Nodes/BoldNode.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Markdown.Tokenizer.Nodes;
-
-public class BoldNode : Node
-{
-
-}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/Nodes/HeaderNode.cs b/cs/Markdown/Tokenizer/Nodes/HeaderNode.cs
deleted file mode 100644
index aaf3bfa87..000000000
--- a/cs/Markdown/Tokenizer/Nodes/HeaderNode.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace Markdown.Tokenizer.Nodes;
-
-public class HeaderNode : Node
-{
-}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/Nodes/ItalicNode.cs b/cs/Markdown/Tokenizer/Nodes/ItalicNode.cs
deleted file mode 100644
index 528b72f7f..000000000
--- a/cs/Markdown/Tokenizer/Nodes/ItalicNode.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Markdown.Tokenizer.Nodes;
-
-public class ItalicNode : Node
-{
-
-}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/Nodes/MainNode.cs b/cs/Markdown/Tokenizer/Nodes/MainNode.cs
deleted file mode 100644
index f1db39b3c..000000000
--- a/cs/Markdown/Tokenizer/Nodes/MainNode.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Markdown.Tokenizer.Nodes;
-
-public class MainNode : Node
-{
-
-}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/Nodes/Node.cs b/cs/Markdown/Tokenizer/Nodes/Node.cs
deleted file mode 100644
index 91ddd509a..000000000
--- a/cs/Markdown/Tokenizer/Nodes/Node.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Markdown.Tokenizer.Nodes;
-
-public abstract class Node
-{
- public string? Value { get; set; }
- public List Children { get; } = new();
- public Node? Parent { get; set; }
-}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/Nodes/NodeType.cs b/cs/Markdown/Tokenizer/Nodes/NodeType.cs
deleted file mode 100644
index 2d70e7319..000000000
--- a/cs/Markdown/Tokenizer/Nodes/NodeType.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Markdown.Tokenizer.Nodes;
-
-public enum NodeType
-{
- Header
-}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/Nodes/TextNode.cs b/cs/Markdown/Tokenizer/Nodes/TextNode.cs
deleted file mode 100644
index 0ca76bc6f..000000000
--- a/cs/Markdown/Tokenizer/Nodes/TextNode.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Markdown.Tokenizer.Nodes;
-
-public class TextNode : Node
-{
-
-}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/TagProcessor.cs b/cs/Markdown/Tokenizer/TagProcessor.cs
index 8fe8747c4..5f6f9c68e 100644
--- a/cs/Markdown/Tokenizer/TagProcessor.cs
+++ b/cs/Markdown/Tokenizer/TagProcessor.cs
@@ -6,12 +6,12 @@ public class TagProcessor : ITagProcessor
{
public void Process(List tags, Stack tagStack)
{
- ProceedEscaped(tags);
- ProceedInWords(tags);
- ProceedTags(tagStack);
+ ProceedEscapedTags(tags);
+ ProceedInWordsTags(tags);
+ ProceedPairTags(tagStack);
}
- private void ProceedInWords(List tags)
+ private void ProceedInWordsTags(List tags)
{
for (var i = 0; i < tags.Count; i++)
{
@@ -42,7 +42,7 @@ private void ProceedInWords(List tags)
}
}
- private void ProceedEscaped(List tags)
+ private void ProceedEscapedTags(List tags)
{
for (var i = 0; i < tags.Count - 1; i++)
{
@@ -64,7 +64,7 @@ private void ProceedEscaped(List tags)
}
}
- private void ProceedTags(Stack tagStack)
+ private void ProceedPairTags(Stack tagStack)
{
var tempStack = new Stack();
diff --git a/cs/Markdown/Tokenizer/Tags/TagStatus.cs b/cs/Markdown/Tokenizer/Tags/TagStatus.cs
index 4b2830560..525959910 100644
--- a/cs/Markdown/Tokenizer/Tags/TagStatus.cs
+++ b/cs/Markdown/Tokenizer/Tags/TagStatus.cs
@@ -7,6 +7,5 @@ public enum TagStatus
Broken,
Escaped,
InWord,
- Undefined,
Single
}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/Tags/Token.cs b/cs/Markdown/Tokenizer/Tags/Token.cs
index 44fbfa9d5..21279f838 100644
--- a/cs/Markdown/Tokenizer/Tags/Token.cs
+++ b/cs/Markdown/Tokenizer/Tags/Token.cs
@@ -1,8 +1,8 @@
namespace Markdown.Tokenizer.Tags;
-public abstract class Token
+public class Token
{
- public virtual TagStatus TagStatus { get; set; }
+ public TagStatus TagStatus { get; set; }
public virtual TokenType TokenType { get; }
- public string Value { get; set; }
+ public string Value = string.Empty;
}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/TokenizerContext.cs b/cs/Markdown/Tokenizer/TokenizerContext.cs
index 7829feaf5..4b3526e5e 100644
--- a/cs/Markdown/Tokenizer/TokenizerContext.cs
+++ b/cs/Markdown/Tokenizer/TokenizerContext.cs
@@ -1,14 +1,8 @@
namespace Markdown.Tokenizer;
-public class TokenizerContext
+public class TokenizerContext(string text)
{
- private int position;
- private readonly string text;
- public TokenizerContext(string text)
- {
- this.text = text;
- position = 0;
- }
+ private int position = 0;
public bool IsEnd => position >= text.Length;
public char Current => text[position];
public int Position => position;
diff --git a/cs/Markdown/TreeBuilder/INodeFactory.cs b/cs/Markdown/TreeBuilder/INodeFactory.cs
new file mode 100644
index 000000000..48dc44819
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/INodeFactory.cs
@@ -0,0 +1,8 @@
+using Markdown.Tokenizer.Tags;
+
+namespace Markdown.TreeBuilder;
+
+public interface INodeFactory
+{
+ NodeAction? CreateNode(Token token);
+}
\ No newline at end of file
diff --git a/cs/Markdown/Tokenizer/MarkdownTokenizer.cs b/cs/Markdown/TreeBuilder/MarkdownTokenizer.cs
similarity index 89%
rename from cs/Markdown/Tokenizer/MarkdownTokenizer.cs
rename to cs/Markdown/TreeBuilder/MarkdownTokenizer.cs
index 1d30c8779..54d1bb373 100644
--- a/cs/Markdown/Tokenizer/MarkdownTokenizer.cs
+++ b/cs/Markdown/TreeBuilder/MarkdownTokenizer.cs
@@ -1,14 +1,14 @@
using System.Text;
-using Markdown.Tokenizer.Handlers;
+using Markdown.Tokenizer;
using Markdown.Tokenizer.Tags;
using Token = Markdown.Tokenizer.Tags.Token;
-namespace Markdown.Tokenizer;
+namespace Markdown.TreeBuilder;
public class MarkdownTokenizer(IHandlerManager handlerManager, ITagProcessor tagProcessor) : ITokenizer
{
- private readonly StringBuilder buffer = new();
- private List tags = new();
+ private readonly StringBuilder buffer = new();
+ private readonly List tags = new();
private readonly Stack tagStack = new();
public List Tokenize(string text)
diff --git a/cs/Markdown/TreeBuilder/NodeAction.cs b/cs/Markdown/TreeBuilder/NodeAction.cs
new file mode 100644
index 000000000..57eadaa14
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/NodeAction.cs
@@ -0,0 +1,16 @@
+using Markdown.TreeBuilder.Nodes;
+
+namespace Markdown.TreeBuilder;
+
+public abstract class NodeAction
+{
+ public class OpenNode : NodeAction
+ {
+ public Node Node { get; }
+ public OpenNode(Node node) => Node = node;
+ }
+
+ public class CloseNode : NodeAction { }
+
+ public class SkipNode : NodeAction { }
+}
\ No newline at end of file
diff --git a/cs/Markdown/TreeBuilder/NodeFactory.cs b/cs/Markdown/TreeBuilder/NodeFactory.cs
new file mode 100644
index 000000000..13a99a88d
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/NodeFactory.cs
@@ -0,0 +1,23 @@
+using Markdown.Tokenizer.Tags;
+using Markdown.TreeBuilder.Nodes;
+
+namespace Markdown.TreeBuilder;
+
+public class NodeFactory : INodeFactory
+{
+ public NodeAction? CreateNode(Token token)
+ {
+ return token switch
+ {
+ { TagStatus: TagStatus.Broken } => null,
+ ItalicTag { TagStatus: TagStatus.Open } => new NodeAction.OpenNode(new ItalicNode()),
+ ItalicTag { TagStatus: TagStatus.Closed } => new NodeAction.CloseNode(),
+ BoldTag { TagStatus: TagStatus.Open } => new NodeAction.OpenNode(new BoldNode()),
+ BoldTag { TagStatus: TagStatus.Closed } => new NodeAction.CloseNode(),
+ SlashToken { TagStatus: TagStatus.Escaped} => new NodeAction.SkipNode(),
+ HeaderTag => new NodeAction.OpenNode(new HeaderNode()),
+ NewLineToken => new NodeAction.SkipNode(),
+ _ => null
+ };
+ }
+}
\ No newline at end of file
diff --git a/cs/Markdown/TreeBuilder/Nodes/BoldNode.cs b/cs/Markdown/TreeBuilder/Nodes/BoldNode.cs
new file mode 100644
index 000000000..c83686c86
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/Nodes/BoldNode.cs
@@ -0,0 +1,7 @@
+namespace Markdown.TreeBuilder.Nodes;
+
+public class BoldNode : Node
+{
+ public override string OpenTag => "";
+ public override string CloseTag => "";
+}
\ No newline at end of file
diff --git a/cs/Markdown/TreeBuilder/Nodes/HeaderNode.cs b/cs/Markdown/TreeBuilder/Nodes/HeaderNode.cs
new file mode 100644
index 000000000..f7f608ef5
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/Nodes/HeaderNode.cs
@@ -0,0 +1,7 @@
+namespace Markdown.TreeBuilder.Nodes;
+
+public class HeaderNode : Node
+{
+ public override string OpenTag => "";
+ public override string CloseTag => "
";
+}
\ No newline at end of file
diff --git a/cs/Markdown/TreeBuilder/Nodes/ItalicNode.cs b/cs/Markdown/TreeBuilder/Nodes/ItalicNode.cs
new file mode 100644
index 000000000..fb8caa564
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/Nodes/ItalicNode.cs
@@ -0,0 +1,7 @@
+namespace Markdown.TreeBuilder.Nodes;
+
+public class ItalicNode : Node
+{
+ public override string OpenTag => "";
+ public override string CloseTag => "";
+}
\ No newline at end of file
diff --git a/cs/Markdown/TreeBuilder/Nodes/MainNode.cs b/cs/Markdown/TreeBuilder/Nodes/MainNode.cs
new file mode 100644
index 000000000..a67b493e0
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/Nodes/MainNode.cs
@@ -0,0 +1,4 @@
+namespace Markdown.TreeBuilder.Nodes;
+
+public class MainNode : Node
+{ }
\ No newline at end of file
diff --git a/cs/Markdown/TreeBuilder/Nodes/Node.cs b/cs/Markdown/TreeBuilder/Nodes/Node.cs
new file mode 100644
index 000000000..cafc9062c
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/Nodes/Node.cs
@@ -0,0 +1,10 @@
+namespace Markdown.TreeBuilder.Nodes;
+
+public abstract class Node
+{
+ public List Children { get; } = new();
+ public Node? Parent { get; set; }
+
+ public virtual string OpenTag => string.Empty;
+ public virtual string CloseTag => string.Empty;
+}
\ No newline at end of file
diff --git a/cs/Markdown/TreeBuilder/Nodes/TextNode.cs b/cs/Markdown/TreeBuilder/Nodes/TextNode.cs
new file mode 100644
index 000000000..62a4c96b2
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/Nodes/TextNode.cs
@@ -0,0 +1,6 @@
+namespace Markdown.TreeBuilder.Nodes;
+
+public class TextNode : Node
+{
+ public string? Value { get; init; } = string.Empty;
+}
\ No newline at end of file
diff --git a/cs/Markdown/TreeBuilder/TreeBuilder.cs b/cs/Markdown/TreeBuilder/TreeBuilder.cs
new file mode 100644
index 000000000..f5fbbb44d
--- /dev/null
+++ b/cs/Markdown/TreeBuilder/TreeBuilder.cs
@@ -0,0 +1,42 @@
+using Markdown.Tokenizer.Tags;
+using Markdown.TreeBuilder.Nodes;
+
+namespace Markdown.TreeBuilder;
+
+public class TreeBuilder(INodeFactory nodeFactory)
+{
+ public Node Build(List tokens)
+ {
+ Node mainNode = new MainNode();
+ var currentNode = mainNode;
+
+ foreach (var token in tokens)
+ {
+ var nodeAction = nodeFactory.CreateNode(token);
+
+ if (nodeAction == null)
+ {
+ currentNode.Children.Add(new TextNode { Value = token.Value });
+ continue;
+ }
+
+ switch (nodeAction)
+ {
+ case NodeAction.OpenNode openNode:
+ currentNode.Children.Add(openNode.Node);
+ openNode.Node.Parent = currentNode;
+ currentNode = openNode.Node;
+ break;
+
+ case NodeAction.CloseNode:
+ currentNode = currentNode.Parent ?? currentNode;
+ break;
+
+ case NodeAction.SkipNode:
+ break;
+ }
+ }
+
+ return mainNode;
+ }
+}
\ No newline at end of file