-
Notifications
You must be signed in to change notification settings - Fork 319
Шубин Игорь #263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Шубин Игорь #263
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="ApprovalTests" Version="7.0.0"/> | ||
| <PackageReference Include="FluentAssertions" Version="8.8.0"/> | ||
| <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1"/> | ||
| <PackageReference Include="NUnit" Version="4.4.0"/> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| using Markdown.Parsers; | ||
| using Markdown.Tokenizer; | ||
|
|
||
| namespace Markdown; | ||
|
|
||
| public class Md | ||
| { | ||
| public string Render(string markdownText) | ||
| { | ||
| var tokenizer = new MarkdownTokenizer(markdownText); | ||
| var tokens = tokenizer.Tokenize(); | ||
| var parser = new MarkdownParser(tokens); | ||
| var markdownDocument = parser.ParseTokens(); | ||
| var htmlText = markdownDocument.ToHtml(); | ||
|
|
||
| return htmlText; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| namespace Markdown.Nodes.Interfaces; | ||
|
|
||
| public abstract class InternalMarkdownNode : MarkdownNode | ||
| { | ||
| protected InternalMarkdownNode(string value) : base(value) | ||
| { | ||
| } | ||
|
|
||
| public override void AddChild(MarkdownNode node) | ||
| { | ||
| Children.Add(node); | ||
| } | ||
|
|
||
| public override void AddChildren(List<MarkdownNode> nodes) | ||
| { | ||
| Children.AddRange(nodes); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| namespace Markdown.Nodes.Interfaces; | ||
|
|
||
| public abstract class LeafMarkdownNode : MarkdownNode | ||
| { | ||
| protected LeafMarkdownNode(string value) : base(value) | ||
| { | ||
| } | ||
| } | ||
|
Comment on lines
1
to
8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Тут кажется чтобы был правильный смысл, нужно поменять наследование. Мы ведь сейчас можем в листы дерева добавлять еще ноды, т.к. мне класс Ты еще занес в крайние ноды ImageNode, но что если я захочу написать например вот так
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Мы не сможем добавлять в листы дерева (или если сделаем апкаст) еще ноды, т.к там будет эксепшн. В паттерне composite у листьев оставляют методы пустыми или выбрасывают эксепшн. Еще как вариант, сделать флаг, является ли нода листом. Насчет поменять наследование, в теории должно сработать. И как ты говорил выше, можно отказаться от такого подхода вообще, оставив только список, и в данной задаче, как я понимаю, можно не усложнять? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Вот эта часть мне не очень нравится в этом решении, хоть это и по паттерну
Точнее, я не понимал в каком контексте мы будем этот метод С учетом того, что переделали решение на токенайзер и парсер и теперь парсер должен сам понимать у кого что он может вызывать, чтобы собрать дерево - теперь такой подход норм и его можно оставить) |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| namespace Markdown.Nodes.Interfaces; | ||
|
|
||
| public abstract class MarkdownNode | ||
| { | ||
| public readonly List<MarkdownNode> Children = []; | ||
| public readonly string Value; | ||
|
|
||
| protected MarkdownNode(string value) | ||
| { | ||
| Value = value; | ||
| } | ||
|
|
||
| public virtual void AddChild(MarkdownNode node) | ||
| { | ||
| } | ||
|
|
||
| public virtual void AddChildren(List<MarkdownNode> nodes) | ||
| { | ||
| } | ||
|
|
||
| public abstract string ToHtml(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| using System.Text; | ||
| using Markdown.Nodes.Interfaces; | ||
|
|
||
| namespace Markdown.Nodes.Internal; | ||
|
|
||
| public class AltNode : InternalMarkdownNode | ||
| { | ||
| public AltNode(string value) : base(value) | ||
| { | ||
| } | ||
|
|
||
| public override string ToHtml() | ||
| { | ||
| var textBuilder = new StringBuilder(); | ||
| foreach (var child in Children) | ||
| textBuilder.Append(child.ToHtml()); | ||
|
|
||
| return textBuilder.ToString(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| using System.Text; | ||
| using Markdown.Nodes.Interfaces; | ||
|
|
||
| namespace Markdown.Nodes.Internal; | ||
|
|
||
| public class BoldNode : InternalMarkdownNode | ||
| { | ||
| public BoldNode(string value) : base(value) | ||
| { | ||
| } | ||
|
|
||
| public override string ToHtml() | ||
| { | ||
| var textBuilder = new StringBuilder(); | ||
| foreach (var child in Children) textBuilder.Append(child.ToHtml()); | ||
|
|
||
| return $"<strong>{textBuilder}</strong>"; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| using System.Text; | ||
| using Markdown.Nodes.Interfaces; | ||
|
|
||
| namespace Markdown.Nodes.Internal; | ||
|
|
||
| public class HeaderNode : InternalMarkdownNode | ||
| { | ||
| public HeaderNode(string value) : base(value) | ||
| { | ||
| } | ||
|
|
||
| public override string ToHtml() | ||
| { | ||
| var textBuilder = new StringBuilder(); | ||
| var controlCharacters = new StringBuilder(); | ||
| foreach (var child in Children) | ||
| if (child.Value is "\n" or "\r") | ||
| controlCharacters.Append(child.ToHtml()); | ||
| else | ||
| textBuilder.Append(child.ToHtml()); | ||
|
|
||
| return $"<h1>{textBuilder}</h1>{controlCharacters}"; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| using Markdown.Nodes.Interfaces; | ||
|
|
||
| namespace Markdown.Nodes.Internal; | ||
|
|
||
| public class ImageNode : InternalMarkdownNode | ||
| { | ||
| public ImageNode(string value) : base(value) | ||
| { | ||
| } | ||
|
|
||
| public override string ToHtml() | ||
| { | ||
| var alt = Children[0].ToHtml(); | ||
| var url = Children[1].ToHtml(); | ||
| return $"<img src =\"{url}\" alt=\"{alt}\">"; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| using System.Text; | ||
| using Markdown.Nodes.Interfaces; | ||
|
|
||
| namespace Markdown.Nodes.Internal; | ||
|
|
||
| public class ItalicNode : InternalMarkdownNode | ||
| { | ||
| public ItalicNode(string value) : base(value) | ||
| { | ||
| } | ||
|
|
||
| public override string ToHtml() | ||
| { | ||
| var textBuilder = new StringBuilder(); | ||
| foreach (var child in Children) textBuilder.Append(child.ToHtml()); | ||
|
|
||
| return $"<em>{textBuilder}</em>"; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| using System.Text; | ||
| using Markdown.Nodes.Interfaces; | ||
|
|
||
| namespace Markdown.Nodes.Internal; | ||
|
|
||
| public class MarkdownDocumentNode : InternalMarkdownNode | ||
| { | ||
| public MarkdownDocumentNode(string value) : base(value) | ||
| { | ||
| } | ||
|
|
||
| public override string ToHtml() | ||
| { | ||
| var textBuilder = new StringBuilder(); | ||
| foreach (var child in Children) | ||
| textBuilder.Append(child.ToHtml()); | ||
|
|
||
| return textBuilder.ToString(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| using Markdown.Nodes.Interfaces; | ||
|
|
||
| namespace Markdown.Nodes.Leaf; | ||
|
|
||
| public class TextNode : LeafMarkdownNode | ||
| { | ||
| public TextNode(string value) : base(value) | ||
| { | ||
| } | ||
|
|
||
| public override string ToHtml() | ||
| { | ||
| return Value; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| using Markdown.Nodes.Interfaces; | ||
|
|
||
| namespace Markdown.Nodes.Leaf; | ||
|
|
||
| public class UrlNode : LeafMarkdownNode | ||
| { | ||
| public UrlNode(string value) : base(value) | ||
| { | ||
| } | ||
|
|
||
| public override string ToHtml() | ||
| { | ||
| return Value; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| using Markdown.Nodes.Interfaces; | ||
| using Markdown.Nodes.Leaf; | ||
| using Markdown.Parsers.Interfaces; | ||
| using Markdown.Tokenizer; | ||
|
|
||
| namespace Markdown.Parsers; | ||
|
|
||
| public class EscapeParser : IParser | ||
| { | ||
| private readonly MarkdownParser parser; | ||
|
|
||
| public EscapeParser(MarkdownParser parser) | ||
| { | ||
| this.parser = parser; | ||
| } | ||
|
|
||
| public ParseStatus TryParse(out MarkdownNode node) | ||
| { | ||
| node = new TextNode(@"\"); | ||
| if (parser.CurrentToken.Type != TokenType.Escape) | ||
| return ParseStatus.Fail(); | ||
|
|
||
| parser.MoveNext(); | ||
| node = new TextNode($"{parser.CurrentToken.Value}"); | ||
|
|
||
| return ParseStatus.Ok(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| using Markdown.Nodes.Interfaces; | ||
| using Markdown.Nodes.Internal; | ||
| using Markdown.Nodes.Leaf; | ||
| using Markdown.Parsers.Interfaces; | ||
| using Markdown.Tokenizer; | ||
|
|
||
| namespace Markdown.Parsers; | ||
|
|
||
| public class HeaderParser : IParser | ||
| { | ||
| private readonly MarkdownParser parser; | ||
| private readonly HashSet<TokenType> expectedStopSymbols = [TokenType.NewLine, TokenType.Carriage]; | ||
|
|
||
| public HeaderParser(MarkdownParser parser) | ||
| { | ||
| this.parser = parser; | ||
| } | ||
|
|
||
| public ParseStatus TryParse(out MarkdownNode node) | ||
| { | ||
| if (parser.NextToken != null | ||
| && (parser.CurrentToken.Type != TokenType.Hash | ||
| || (parser.CurrentToken.Type == TokenType.Hash && parser.NextToken.Type != TokenType.Space))) | ||
| { | ||
| node = new TextNode("#"); | ||
| return ParseStatus.Fail(); | ||
| } | ||
| parser.MoveNext(); | ||
|
|
||
| node = new HeaderNode("#"); | ||
| parser.ParentStack.Push(parser.CurrentParent); | ||
| parser.CurrentParent = node; | ||
| parser.MoveNext(); | ||
| parser.ParseTokens(null, expectedStopSymbols); | ||
|
|
||
| if (parser.CurrentToken.Type != TokenType.Eof) | ||
| node.AddChild(new TextNode($"{parser.CurrentToken.Value}")); | ||
|
|
||
| if (!expectedStopSymbols.Contains(parser.CurrentToken.Type)) | ||
| parser.CurrentParent = parser.ParentStack.Pop(); | ||
|
|
||
| return ParseStatus.Ok(); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Этот класс сейчас тоже кажется избыточным. Вот мои доводы почему:
Мы хотим, чтобы наш класс
MarkdownNodeи все его реализации умели делать следующее:Отдельно выделю, т.к. коммент не про это
Будто бы сразу же приходит в голову список - ровно то, для чего он нужен. И тогда кажется логичным пускай сразу в
MarkdownNodeи реализуется этот список, для дерева это тоже подходит. А тут мы получается вынесли реализацию списка в отдельный класс и это прямо слишком абстракцияСходу в голову не приходит адекватный сценарий, в котором мы решим не использовать список, а например словарь, потому что нам не нужны функции словаря, нам даже уметь доставать по индексу не нужно. А ради таких призрачных сценариев не стоит усложнять код, а просто следовать принципу KISS :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ответил ниже
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Нуу, в целом теперь окей, наверное если мы оставим реализацию того, что у нас листья наследуются от
MarkdownNodeто тогда и этот класс можно оставить с реализацией списка