feat(markdown): implemented expanding single link list items
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/tag/woodpecker Pipeline failed

This commit is contained in:
D. Moonfire 2022-12-24 00:38:24 -06:00
parent 16a888fe9e
commit 982e3b38c3
4 changed files with 226 additions and 0 deletions

View file

@ -0,0 +1,103 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using MfGames.Gallium;
using MfGames.Nitride.Contents;
using MfGames.Nitride.Slugs;
namespace MfGames.Nitride.Markdown;
/// <summary>
/// An operation that turns list items that starts with a link into a single
/// link for the entire list item, even if there are additional links in the
/// list.
/// </summary>
public class MakeSingleLinkListItems : IOperation
{
private readonly ISlugConverter slugs;
public MakeSingleLinkListItems(ISlugConverter slugs)
{
this.slugs = slugs;
}
/// <inheritdoc />
public IEnumerable<Entity> Run(IEnumerable<Entity> input)
{
return input
.SelectManyEntity<IsMarkdown>(
x => x
.Select(this.MakeSingleLinkLists));
}
/// <summary>
/// This turns all links that start with a link into a single link while
/// removing all trailing links within the line. This is to simplify the
/// rendering of the link on page.
/// </summary>
private Entity MakeSingleLinkLists(Entity entity)
{
string content = entity.GetText()!;
string output = Regex.Replace(
content,
@"- \[\[(?<label>[^\]]+?)\]\](?<post>[^\n]+)\n",
match =>
{
string wiki = match.Groups["label"].ToString();
string path = string.Format(
"/{0}/",
this.slugs.ToSlug(wiki.Split('|').First()));
string label = wiki.Split('|').Last();
string after = match.Groups["post"].ToString();
string post = this.RemoveLinks(after);
string value = $"- [{label}{post}]({path})\n";
return value;
});
output = Regex.Replace(
output,
@"- \[(?<label>[^\]]+?)\]\((?<path>[^\)]+?)\)(?<post>[^\n]+)\n",
match =>
{
string label = match.Groups["label"].ToString();
string path = match.Groups["path"].ToString();
string after = match.Groups["post"].ToString();
string post = this.RemoveLinks(after);
string value = $"- [{label}{post}]({path})\n";
return value;
});
return entity.SetTextContent(output);
}
/// <summary>
/// Removes a normal link and replaces it with the text.
/// </summary>
private string RemoveLinks(string input)
{
string output = Regex.Replace(
input,
@"\[\[(?<label>[^\]]+)\]\]",
match =>
{
string link1 = match.Groups["label"].ToString();
string path1 = string.Format(
"/{0}/",
this.slugs.ToSlug(link1.Split('|').First()));
string label1 = link1.Split('|').Last();
return label1;
});
output = Regex.Replace(
output,
@"\[(?<label>[^\]]+)\]\([^)]+\)",
match => match.Groups["label"].ToString());
return output;
}
}

View file

@ -12,6 +12,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MfGames.Nitride.Gemtext\MfGames.Nitride.Gemtext.csproj" /> <ProjectReference Include="..\MfGames.Nitride.Gemtext\MfGames.Nitride.Gemtext.csproj" />
<ProjectReference Include="..\MfGames.Nitride.Html\MfGames.Nitride.Html.csproj" /> <ProjectReference Include="..\MfGames.Nitride.Html\MfGames.Nitride.Html.csproj" />
<ProjectReference Include="..\MfGames.Nitride.Slugs\MfGames.Nitride.Slugs.csproj" />
<ProjectReference Include="..\MfGames.Nitride\MfGames.Nitride.csproj" /> <ProjectReference Include="..\MfGames.Nitride\MfGames.Nitride.csproj" />
</ItemGroup> </ItemGroup>

View file

@ -0,0 +1,100 @@
using System.Collections.Generic;
using System.Linq;
using MfGames.Gallium;
using MfGames.Nitride.Contents;
using MfGames.Nitride.Markdown;
using MfGames.Nitride.Tests;
using MfGames.TestSetup;
using Xunit;
using Xunit.Abstractions;
namespace MfGames.Nitride.Slugs.Tests;
/// <summary>
/// Tests the functionality of the WriteFiles().
/// </summary>
public class MakeSingleLinkListItemsTests : TestBase<MarkdownTestContext>
{
public MakeSingleLinkListItemsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void AlreadyFullMarkdownLink()
{
using MarkdownTestContext context = this.CreateContext();
List<Entity> input = new()
{
new Entity()
.Set(IsMarkdown.Instance)
.SetTextContent("- [Empty](link)"),
};
MakeSingleLinkListItems?
op = context.Resolve<MakeSingleLinkListItems>();
IEnumerable<Entity> output = op.Run(input);
string content = output.First().GetText()!.Trim();
Assert.Equal("- [Empty](link)", content);
}
[Fact]
public void ExtendSingleMarkdownLink()
{
using MarkdownTestContext context = this.CreateContext();
List<Entity> input = new()
{
new Entity()
.Set(IsMarkdown.Instance)
.SetTextContent("- [Empty](link) space"),
};
MakeSingleLinkListItems?
op = context.Resolve<MakeSingleLinkListItems>();
IEnumerable<Entity> output = op.Run(input);
string content = output.First().GetText()!.Trim();
Assert.Equal("- [Empty space](link)", content);
}
[Fact]
public void NoLinksNoChange()
{
using MarkdownTestContext context = this.CreateContext();
List<Entity> input = new()
{
new Entity()
.Set(IsMarkdown.Instance)
.SetTextContent("- Empty"),
};
MakeSingleLinkListItems?
op = context.Resolve<MakeSingleLinkListItems>();
IEnumerable<Entity> output = op.Run(input);
string content = output.First().GetText()!.Trim();
Assert.Equal("- Empty", content);
}
[Fact]
public void RemoveSecondMarkdownLink()
{
using MarkdownTestContext context = this.CreateContext();
List<Entity> input = new()
{
new Entity()
.Set(IsMarkdown.Instance)
.SetTextContent("- [Empty](link) [space](link2)"),
};
MakeSingleLinkListItems?
op = context.Resolve<MakeSingleLinkListItems>();
IEnumerable<Entity> output = op.Run(input);
string content = output.First().GetText()!.Trim();
Assert.Equal("- [Empty space](link)", content);
}
}

View file

@ -0,0 +1,22 @@
using Autofac;
using MfGames.Nitride.Markdown;
using MfGames.Nitride.Tests;
namespace MfGames.Nitride.Slugs.Tests;
public class MarkdownTestContext : NitrideTestContext
{
/// <inheritdoc />
protected override void ConfigureContainer(ContainerBuilder builder)
{
base.ConfigureContainer(builder);
builder.RegisterModule<NitrideSlugsModule>();
builder.RegisterModule<NitrideMarkdownModule>();
builder
.RegisterType<SimpleSlugConverter>()
.As<ISlugConverter>()
.SingleInstance();
}
}