-
Notifications
You must be signed in to change notification settings - Fork 300
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
Бабинцев Григорий #244
base: master
Are you sure you want to change the base?
Бабинцев Григорий #244
Changes from 1 commit
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,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="NUnit" Version="3.12.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Markdown\Markdown.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using NUnit.Framework; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Markdown.Builder; | ||
using Markdown.Checker; | ||
using Markdown.Config; | ||
using Markdown.Parser; | ||
using FluentAssertions; | ||
|
||
namespace Markdown.Tests | ||
{ | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// See https://aka.ms/new-console-template for more information | ||
Console.WriteLine("Hello, World!"); | ||
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. У тестов не делают Program файл и в целом Main метод, так как точка входа генерируется при сборке фреймворком для тестов |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
using Markdown.Domain.Tags; | ||
using Markdown.Domain; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Markdown.Extensions; | ||
|
||
namespace Markdown.Builder | ||
{ | ||
public class HtmlBuilder : IHtmlBuilder | ||
{ | ||
private readonly Dictionary<Tag, string> _htmlTagsMarkupDict; | ||
|
||
private int shift; | ||
|
||
public HtmlBuilder(Dictionary<Tag, string> htmlTagsMarkupDict) | ||
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. Предлагаю его спрятать внутрь реализации. В конструктор выносятся внешние зависимости (Singleton) и реализации интерфейсов. В данном случае словарь мапинга больше похож на внутрянку билдера. Но, можно передавать файл настроек и из него подтягивать, если необходимо |
||
{ | ||
_htmlTagsMarkupDict = htmlTagsMarkupDict; | ||
} | ||
|
||
public string BuildHtmlFromMarkdown(string markdownText, List<Token> tokens) | ||
{ | ||
var htmlResultText = new StringBuilder(markdownText); | ||
var htmlTags = ConvertToHtmlTags(tokens); | ||
shift = 0; | ||
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. В задаче это не требовалось, но такой подход не потокобезопасен. Вся обработка текста происходит в методах, а сдвиг хранится один на весь класс. Лучше его хранить локально и передавать как аргумент |
||
|
||
foreach (var tag in htmlTags) | ||
{ | ||
ReplaceMarkdownWithHtml(htmlResultText, tag); | ||
shift = htmlResultText.Length - markdownText.Length; | ||
} | ||
|
||
return htmlResultText.ToString(); | ||
} | ||
|
||
private void ReplaceMarkdownWithHtml(StringBuilder htmlResultText, HtmlTag tag) | ||
{ | ||
var mdTagLength = GetMdTagLength(tag); | ||
|
||
htmlResultText.Remove(tag.Index + shift, mdTagLength); | ||
|
||
htmlResultText.Insert(tag.Index + shift, tag.GetMarkup()); | ||
} | ||
|
||
private int GetMdTagLength(HtmlTag tag) | ||
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. Ой какая страшная логика. Сюда будет сложно добавить обработку нового типа. Может добавим в тэг информацию о длине? Тогда сможем сделать маркдаун независимую реализацию генератора. |
||
{ | ||
if (tag.Tag == Tag.Bold) | ||
{ | ||
shift--; | ||
return 2; | ||
} | ||
|
||
if (tag.IsClosing && (tag.Tag == Tag.Header || tag.Tag == Tag.EscapedSymbol)) | ||
{ | ||
shift++; | ||
return 0; | ||
} | ||
|
||
return 1; | ||
} | ||
|
||
private List<HtmlTag> ConvertToHtmlTags(List<Token> tokens) | ||
{ | ||
var htmlTags = new List<HtmlTag>(); | ||
|
||
foreach (var token in tokens) | ||
{ | ||
var htmlMarkup = _htmlTagsMarkupDict[token.TagType]; | ||
var tag = token.TagType; | ||
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. Всё-таки это tagType ну или textType |
||
|
||
htmlTags.Add(new HtmlTag(tag, token.StartIndex, false, htmlMarkup)); | ||
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. У нас уже имеется |
||
htmlTags.Add(new HtmlTag(tag, token.EndIndex, true, htmlMarkup)); | ||
} | ||
|
||
return htmlTags.OrderBy(tag => tag.Index).ToList(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
using Markdown.Domain.Tags; | ||
using Markdown.Domain; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Markdown.Checker | ||
{ | ||
public class TagChecker : ITagChecker | ||
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. Скорее MdTagResolver |
||
{ | ||
private int currentIndex; | ||
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. Точно хотим его выносить в общедоступные поля и терять потокобезопасность? |
||
|
||
public const char HASH_SYMBOL = '#'; | ||
public const char UNDERSCORE_SYMBOL = '_'; | ||
public const char SLASH_SYMBOL = '\\'; | ||
Comment on lines
+15
to
+17
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. Можно сделать private, так как снаружи нет смысла их использовать |
||
|
||
public Tuple<Tag, int> GetTagType(string line, int index) | ||
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. В явном виде создавать Tupl не нужно. Можно просто указывать в скобках типы, а под капотом оно само скомпилируется. Зато получим возможность указать имена возвращаемым переменным. А то совсем не понятно, что значит этот int
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. Может быть DefineTagType? |
||
{ | ||
currentIndex = index; | ||
var tag = Tag.None; | ||
|
||
switch (line[index]) | ||
{ | ||
case UNDERSCORE_SYMBOL: | ||
tag = GetTagForUnderscore(line); | ||
break; | ||
case SLASH_SYMBOL: | ||
tag = GetTagForSlash(line); | ||
break; | ||
case HASH_SYMBOL: | ||
if (index == 0) | ||
tag = Tag.Header; | ||
break; | ||
} | ||
|
||
return Tuple.Create(tag, currentIndex); | ||
} | ||
|
||
private Tag GetTagForSlash(string line) | ||
{ | ||
if (currentIndex < line.Length - 1 | ||
&& (line[currentIndex + 1] == SLASH_SYMBOL | ||
|| line[currentIndex + 1] == UNDERSCORE_SYMBOL | ||
|| line[currentIndex + 1] == HASH_SYMBOL)) | ||
{ | ||
return Tag.EscapedSymbol; | ||
} | ||
|
||
return Tag.None; | ||
} | ||
|
||
private Tag GetTagForUnderscore(string line) | ||
{ | ||
if (currentIndex < line.Length - 1 && line[currentIndex + 1] == UNDERSCORE_SYMBOL) | ||
return GetTagWithMultipleUnderscores(line); | ||
|
||
return Tag.Italic; | ||
} | ||
|
||
private Tag GetTagWithMultipleUnderscores(string line) | ||
{ | ||
if (currentIndex < line.Length - 2 && line[currentIndex + 2] == UNDERSCORE_SYMBOL) | ||
{ | ||
currentIndex = FindEndOfInvalidTag(line); | ||
return Tag.None; | ||
} | ||
|
||
currentIndex++; | ||
|
||
return Tag.Bold; | ||
} | ||
|
||
private int FindEndOfInvalidTag(string line) | ||
{ | ||
var endIndex = currentIndex; | ||
|
||
while (endIndex < line.Length && line[endIndex] == UNDERSCORE_SYMBOL) | ||
endIndex++; | ||
|
||
return endIndex; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using Markdown.Domain.Tags; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Markdown.Config | ||
{ | ||
public class MarkdownConfig | ||
{ | ||
public static Dictionary<Tag, string> HtmlTags => new Dictionary<Tag, string>() | ||
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. Важно ещё помнить, что стрелочный оператор генерирует новый объект на каждый вызов. Здесь это уместно, но чтобы предотвратить создание можно использовать |
||
{ | ||
{ Tag.Bold, "strong" }, { Tag.Italic, "em" }, | ||
{ Tag.Header, "h1" }, { Tag.EscapedSymbol, "" } | ||
Comment on lines
+14
to
+15
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. Либо все в строку, либо каждый элемент в новой. Смешивать вот так не стоит. В данном случае лучше каждую запись делать в новой строке
И тип у словаря при создании можно явно не определять, компилятор сам его вычислит по типу свойства |
||
}; | ||
|
||
public static Dictionary<Tag, string> MdTags => new Dictionary<Tag, string>() | ||
{ | ||
{ Tag.Bold, "__" }, { Tag.Italic, "_" }, | ||
{ Tag.Header, "# " }, { Tag.EscapedSymbol, ""} | ||
}; | ||
|
||
public static Dictionary<Tag, Tag> DifferentTags => new Dictionary<Tag, Tag>() | ||
{ | ||
{Tag.Bold, Tag.Italic}, | ||
{Tag.Italic, Tag.Bold} | ||
}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Markdown.Domain | ||
{ | ||
public interface IHtmlBuilder | ||
{ | ||
string BuildHtmlFromMarkdown(string markdownText, List<Token> tokens); | ||
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. Хотим привязываться именно к MD и HTML или видим интерфейс, который умеет генерировать что-то из списка токенов и исходного текста? |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Markdown.Domain | ||
{ | ||
public interface IMarkdownParser | ||
{ | ||
List<Token> ParseMarkdown(string line); | ||
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. Это интерфейс, который умеет преобразовывать какой-то текст в набор токенов, или жёсткая привязка в MD? |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Markdown.Domain.Tags; | ||
|
||
namespace Markdown.Domain | ||
{ | ||
public interface ITagChecker | ||
{ | ||
Tuple<Tag, int> GetTagType(string line, int index); | ||
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. Для читаемости рекомендую использовать имена для переменных внутри tuple. Тогда запись примет вид
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Markdown.Domain.Tags | ||
{ | ||
public class HtmlTag | ||
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. Можно заменить на record, так как по сути является дата классом
|
||
{ | ||
public Tag Tag { get; } | ||
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. Точно нужно сохранять тип тега, если уже известен способ оформления? Предлагаю сделать ему размер, который нужно пропускать, а не сам md тэг и потом при рендеринге вычислять этот отступ |
||
public int Index { get; } | ||
public bool IsClosing { get; } | ||
public string Markup { get; } | ||
|
||
public HtmlTag(Tag tag, int index, bool isClosing, string htmlMarkup) | ||
{ | ||
Tag = tag; | ||
Index = index; | ||
IsClosing = isClosing; | ||
Markup = htmlMarkup; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Markdown.Domain.Tags | ||
{ | ||
public class MdTag | ||
{ | ||
public Tag Tag { get; } | ||
public int Index { get; } | ||
|
||
public MdTag(Tag tag, int index) | ||
{ | ||
Tag = tag; | ||
Index = index; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Markdown.Domain.Tags | ||
{ | ||
public enum Tag | ||
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. Так как есть |
||
{ | ||
None, | ||
Bold, | ||
Italic, | ||
Header, | ||
EscapedSymbol, | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Markdown.Domain.Tags; | ||
|
||
namespace Markdown.Domain | ||
{ | ||
public class Token | ||
{ | ||
public Tag TagType { get; } | ||
public int StartIndex { get; } | ||
public int EndIndex { get; } | ||
public bool IsSingleTag { get; } | ||
|
||
public Token(Tag type, int startIndex, int endIndex, bool isSingleTag = false) | ||
{ | ||
TagType = type; | ||
IsSingleTag = isSingleTag; | ||
StartIndex = startIndex; | ||
EndIndex = endIndex; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using Markdown.Domain.Tags; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.CompilerServices; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Markdown.Extensions | ||
{ | ||
public static class HtmlTagExtensions | ||
{ | ||
public static string GetMarkup(this HtmlTag htmlTag) | ||
{ | ||
if (htmlTag.Tag == Tag.EscapedSymbol) | ||
return ""; | ||
|
||
var format = htmlTag.IsClosing ? "</{0}>" : "<{0}>"; | ||
|
||
return string.Format(format, htmlTag.Markup); | ||
} | ||
} | ||
} |
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.
Этот файл не подключен к проекту. Скорее всего ты нажал удалить в райдере. Но проекты (csproj) лишь исключаются из решения (sln), а файлы физически остаются. Но это была правильная идея для расположения тестов. Тогда здесь были бы файлы MdTetsts, HtmlBuilderTests, MarkdownParserTests