Skip to content

Commit

Permalink
Рабочее решение
Browse files Browse the repository at this point in the history
  • Loading branch information
kashin.aleksandr committed Dec 11, 2024
1 parent d5d124a commit 593897b
Show file tree
Hide file tree
Showing 58 changed files with 903 additions and 215 deletions.
2 changes: 1 addition & 1 deletion cs/Markdown/IMd.cs → cs/Markdown/IMarkdown.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Markdown;

public interface IMd
public interface IMarkdown
{
string Render(string markdown);
}
11 changes: 11 additions & 0 deletions cs/Markdown/Markdown.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,15 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="Verify.NUnit" Version="28.3.2" />
</ItemGroup>

<ItemGroup>
<Folder Include="Tests\Markdown\snapshots\" />
</ItemGroup>

</Project>
94 changes: 94 additions & 0 deletions cs/Markdown/MarkdownRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using Markdown.Render;
using Markdown.Tokenizer;
using Markdown.Tokenizer.Nodes;
using Markdown.Tokenizer.Tags;

namespace Markdown;

public class MarkdownRenderer : IMarkdown
{
public string Render(string markdown)
{
var tokenizer = new MarkdownTokenizer();
var renderer = new HtmlRenderer();
var tokens = tokenizer.Tokenize(markdown);
var tree = ToTree(tokens);
return renderer.Render(tree);
}

private Node ToTree(List<Token> tokens)
{
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;
}
}

return currentNode.Parent ?? currentNode;
}
}
15 changes: 0 additions & 15 deletions cs/Markdown/Md.cs

This file was deleted.

33 changes: 13 additions & 20 deletions cs/Markdown/Render/HtmlRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,28 @@
using System.Text;
using Markdown.Render.Renders;
using Markdown.Tokenizer;
using Markdown.Tokenizer.Nodes;

namespace Markdown.Render;

public class HtmlRenderer : ITokenRenderer
{
private readonly Dictionary<TokenType, ITokenRender> _renders = new()
{
{ TokenType.Italic , new ItalicRender() },
{ TokenType.Bold , new BoldRender() },
{ TokenType.Header, new HeadRender() },
{ TokenType.Text, new TextRender() },
{ TokenType.ItemList, new ItemListRender() }
};

public string Render(List<Token> tokens)
public string Render(Node tokens)
{
var sb = new StringBuilder();
foreach (var token in tokens)
{
sb.Append(Render(token));
}
foreach (var token in tokens.Children)
sb.Append(RenderToken(token));

return sb.ToString();
}

private string Render(Token token)
private string? RenderToken(Node node)
{
return _renders[token.Type].Render(token);
return node switch
{
TextNode textNode => textNode.Value,
HeaderNode => $"<h1>{Render(node)}</h1>",
ItalicNode => $"<em>{Render(node)}</em>",
BoldNode => $"<strong>{Render(node)}</strong>",
_ => throw new Exception($"Unknown token type: {node.GetType()}")
};
}


}
4 changes: 2 additions & 2 deletions cs/Markdown/Render/ITokenRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using Markdown.Tokenizer;
using Markdown.Tokenizer.Nodes;

namespace Markdown.Render;

public interface ITokenRenderer
{
string Render(List<Token> tokens);
string Render(Node tokens);
}
11 changes: 0 additions & 11 deletions cs/Markdown/Render/Renders/BoldRender.cs

This file was deleted.

11 changes: 0 additions & 11 deletions cs/Markdown/Render/Renders/HeadRender.cs

This file was deleted.

11 changes: 0 additions & 11 deletions cs/Markdown/Render/Renders/IItalicRender.cs

This file was deleted.

8 changes: 0 additions & 8 deletions cs/Markdown/Render/Renders/ITokenRender.cs

This file was deleted.

11 changes: 0 additions & 11 deletions cs/Markdown/Render/Renders/ItemListRender.cs

This file was deleted.

11 changes: 0 additions & 11 deletions cs/Markdown/Render/Renders/TextRender.cs

This file was deleted.

93 changes: 93 additions & 0 deletions cs/Markdown/Tests/Markdown/MarkdownTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
namespace Markdown.Tests.Markdown;

[TestFixture]
public class MarkdownTests
{
private static readonly VerifySettings Settings = new();
private static readonly MarkdownRenderer Renderer = new();

[OneTimeSetUp]
public void OneTimeSetUp()
{
Settings.UseDirectory("snapshots");
}

[TestCaseSource(nameof(ItalicTestCases))]
public string Test_1(string input) => Renderer.Render(input);

private static TestCaseData[] ItalicTestCases =
[
new TestCaseData("# Header").Returns("<h1>Header</h1>"),
new TestCaseData("\\# Header").Returns("# Header"),
new TestCaseData("\\\\# Header").Returns("\\<h1>Header</h1>"),
new TestCaseData("_Italic text_").Returns("<em>Italic text</em>"),
new TestCaseData("\\_Text_").Returns("_Text_"),
new TestCaseData("\\\\_Italic text_").Returns("\\<em>Italic text</em>"),
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("<em>нач</em>але"),
new TestCaseData("сер_еди_не").Returns("сер<em>еди</em>не"),
new TestCaseData("цифры_1_12_3").Returns("цифры_1_12_3"),
new TestCaseData("кон_це._").Returns("кон<em>це.</em>"),
new TestCaseData("в ра_зных сл_овах не").Returns("в ра_зных сл_овах не"),
new TestCaseData("__bold__").Returns("<strong>bold</strong>"),
new TestCaseData("_Text__").Returns("_Text__"),
new TestCaseData("__Text_").Returns("__Text_"),
new TestCaseData("__Italic __text").Returns("__Italic __text"),
new TestCaseData("__два _один_ может__").Returns("<strong>два <em>один</em> может</strong>"),
new TestCaseData("_одинарного __двойное__ не_").Returns( "<em>одинарного __двойное__ не</em>")
];

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__"));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Header</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Header</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Header one </h1><h1>Header two</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Header one </h1><h1>Header two</h1>
Loading

0 comments on commit 593897b

Please sign in to comment.