feat: implemented wiki links for both HTML and Gemtext

This commit is contained in:
D. Moonfire 2022-11-02 17:37:04 -05:00
parent 45f26437ff
commit cd9c8989dc
47 changed files with 670 additions and 106 deletions

View file

@ -9,6 +9,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Markdown.Gemtext",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Markdown.Gemtext.Tests", "tests\MfGames.Markdown.Gemtext.Tests\MfGames.Markdown.Gemtext.Tests.csproj", "{D2703B25-9AF7-49FF-93A4-CB124560F2A9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B4837F83-8560-4AC9-B1E3-6B8C0545A65B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Markdown", "src\MfGames.Markdown\MfGames.Markdown.csproj", "{482E332F-9E72-4F02-B528-9CF04AE05E82}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Markdown.Tests", "tests\MfGames.Markdown.Tests\MfGames.Markdown.Tests.csproj", "{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -46,9 +52,35 @@ Global
{D2703B25-9AF7-49FF-93A4-CB124560F2A9}.Release|x64.Build.0 = Release|Any CPU
{D2703B25-9AF7-49FF-93A4-CB124560F2A9}.Release|x86.ActiveCfg = Release|Any CPU
{D2703B25-9AF7-49FF-93A4-CB124560F2A9}.Release|x86.Build.0 = Release|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|x64.ActiveCfg = Debug|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|x64.Build.0 = Debug|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|x86.ActiveCfg = Debug|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|x86.Build.0 = Debug|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|Any CPU.Build.0 = Release|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|x64.ActiveCfg = Release|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|x64.Build.0 = Release|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|x86.ActiveCfg = Release|Any CPU
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|x86.Build.0 = Release|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|x64.ActiveCfg = Debug|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|x64.Build.0 = Debug|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|x86.ActiveCfg = Debug|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|x86.Build.0 = Debug|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|Any CPU.Build.0 = Release|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|x64.ActiveCfg = Release|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|x64.Build.0 = Release|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|x86.ActiveCfg = Release|Any CPU
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{2A1DE43D-544D-4CE0-ACC8-D15497BBCECA} = {954BA984-D50E-4D1C-880F-EAE678EF6945}
{D2703B25-9AF7-49FF-93A4-CB124560F2A9} = {954BA984-D50E-4D1C-880F-EAE678EF6945}
{D2703B25-9AF7-49FF-93A4-CB124560F2A9} = {B4837F83-8560-4AC9-B1E3-6B8C0545A65B}
{482E332F-9E72-4F02-B528-9CF04AE05E82} = {954BA984-D50E-4D1C-880F-EAE678EF6945}
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B} = {B4837F83-8560-4AC9-B1E3-6B8C0545A65B}
EndGlobalSection
EndGlobal

View file

@ -1,3 +1,33 @@
# MfGames.Markdown.Gemtext CIL
# MfGames.Markdown CIL
An extension for [Markdig](https://github.com/xoofx/markdig) that converts Markdown into Gemtext.
This is a set of libraries for working with Markdown in C#. Most of the code are extensions in [MarkDig](https://github.com/xoofx/markdig), an extensible library for converting Markdown.
The library includes the following:
- An extension for converting wiki links, such as `[[MfGames]]` into a link based on the title. This is for both HTML and Gemtext.
- A output library for using MarkDig to generate Gemtext for Gemini pods.
The documentation is rather light at the moment, but the tests are set up to show these can be used.
## Usage
These library are not on nuget.org (for various reasons). To use them, set up your NuGet.config to pull them from their repository.
```
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="mfgames.com" value="https://src.mfgames.com/api/packages/mfgames-cil/nuget/index.json" protocolVersion="3" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="mfgames.com">
<package pattern="MfGames.*" />
</packageSource>
</packageSourceMapping>
</configuration>
```

View file

@ -1,7 +1,12 @@
#!/usr/bin/env sh
# Set up logging.
log() { echo "🛠️ $(basename $0): $@"; }
# Move into the top level.
cd $(dirname $0)/..
./scripts/setup.sh || exit 1
echo "$(basename $0): building project"
log "building project"
dotnet build

View file

@ -1,3 +0,0 @@
npm install --ci
dotnet restore
dotnet build

View file

@ -1,5 +0,0 @@
npm install --ci
dotnet restore
dotnet build
npm install --ci
npx semantic-release

View file

@ -1,9 +0,0 @@
npm install --ci
npx commitlint-gitlab-ci -x @commitlint/config-conventional
dotnet restore
dotnet build
dotnet test --test-adapter-path:. --logger:"junit;LogFilePath=../artifacts/{assembly}-test-result.xml;MethodFormat=Default;FailureBodyFormat=Verbose" --collect:"XPlat Code Coverage"
dotnet new tool-manifest
dotnet tool install dotnet-reportgenerator-globaltool
dotnet tool run reportgenerator -reports:src/*/TestResults/*/coverage.cobertura.xml -targetdir:./coverage "-reporttypes:Cobertura;TextSummary"
grep "Line coverage" coverage/Summary.txt

View file

@ -1,39 +1,44 @@
#!/usr/bin/env sh
# Set up logging.
log() { echo "️🚢 $(basename $0): $@"; }
# Move into the root folder and make sure we're set up.
cd $(dirname $0)/..
./scripts/setup.sh || exit 1
# Verify the input.
if [ "x$GITEA_TOKEN" = "x" ]
then
echo "the environment variable GITEA_TOKEN is not defined"
log "the environment variable GITEA_TOKEN is not defined"
exit 1
fi
# Clean up everything from the previous runs.
echo "$(basename $0): cleaning project"
log "cleaning project"
dotnet clean
# Version the file based on the Git repository.
echo "$(basename $0): setting project version"
log "setting project version"
(cd src && dotnet dotnet-gitversion /updateprojectfiles)
SEMVER="v$(dotnet gitversion /output json | jq -r .SemVer)"
if [ "x$SEMVER" = "x" ]
then
echo "$(basename $0): cannot figure out the semantic version"
log "cannot figure out the semantic version"
exit 1
fi
# Build to pick up the new version.
echo "$(basename $0): building project $SEMVER"
log "building project $SEMVER"
dotnet build || exit 1
# Create and publish the NuGet packages.
echo "$(basename $0): creating NuGet packages"
log "creating NuGet packages"
dotnet pack -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg || exit 1
echo "$(basename $0): publishing NuGet package"
log "publishing NuGet package"
dotnet nuget remove source mfgames.com >& /dev/null
dotnet nuget add source --name mfgames.com --username dmoonfire --password $GITEA_TOKEN https://src.mfgames.com/api/packages/mfgames-cil/nuget/index.json --store-password-in-clear-text || exit 1
dotnet nuget push --skip-duplicate --source mfgames.com src/*/bin/Debug/*.nupkg || exit 1
@ -41,11 +46,11 @@ dotnet nuget push --skip-duplicate --source mfgames.com src/*/bin/Debug/*.nupkg
# Tag and push, but only if we don't have a tag.
if ! git tag | grep $SEMVER >& /dev/null
then
echo "$(basename $0): tagging and pushing"
log "tagging and pushing"
git remote add publish https://dmoonfire:$GITEA_TOKEN@src.mfgames.com/mfgames-cil/$(basename $(git config --get remote.origin.url))
git tag $SEMVER
git push publish $SEMVER || exit 1
git remote remove publish
else
echo "$(basename $0): not tagging, already exists"
log "not tagging, already exists"
fi

View file

@ -1,5 +1,8 @@
#!/usr/bin/env sh
# Set up logging.
log() { echo "📦️ $(basename $0): $@";
# Normalize our environment.
cd $(dirname $0)/..
@ -8,7 +11,7 @@ for e in dotnet lefthook prettier nixfmt
do
if ! which $e >& /dev/null
then
echo "Cannot find '$e' in the path"
log "Cannot find '$e' in the path"
exit 1
fi
done
@ -16,12 +19,12 @@ done
# Make sure we have lefthook is installed.
if [ ! -f .git/hooks/pre-commit ]
then
echo "$(basename $0): installing lefthook"
log "installing lefthook"
lefthook install
fi
# Make sure our tools are installed.
echo "$(basename $0): install .NET tools"
log "install .NET tools"
dotnet tool restore
# Everything is good.

View file

@ -2,6 +2,7 @@ using Markdig;
using Markdig.Extensions.SmartyPants;
using Markdig.Parsers.Inlines;
using Markdig.Renderers;
using MfGames.Markdown.Gemtext.Renderers;
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;

View file

@ -1,5 +1,6 @@
using Markdig;
using Markdig.Renderers;
using MfGames.Markdown.Gemtext.Renderers;
namespace MfGames.Markdown.Gemtext.Extensions

View file

@ -1,5 +1,6 @@
using Markdig;
using Markdig.Renderers;
using MfGames.Markdown.Gemtext.Renderers;
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
@ -26,7 +27,8 @@ namespace MfGames.Markdown.Gemtext.Extensions
return;
}
var heading = gemtext.ObjectRenderers.Find<HeadingRenderer>();
HeadingRenderer? heading =
gemtext.ObjectRenderers.Find<HeadingRenderer>();
if (heading != null)
{

View file

@ -1,5 +1,6 @@
using Markdig;
using Markdig.Renderers;
using MfGames.Markdown.Gemtext.Renderers;
namespace MfGames.Markdown.Gemtext.Extensions

View file

@ -1,5 +1,6 @@
using Markdig;
using Markdig.Renderers;
using MfGames.Markdown.Gemtext.Renderers;
namespace MfGames.Markdown.Gemtext.Extensions

View file

@ -1,8 +1,10 @@
using System;
using System.IO;
using Markdig;
using Markdig.Parsers;
using Markdig.Syntax;
using MfGames.Markdown.Gemtext.Renderers;
namespace MfGames.Markdown.Gemtext

View file

@ -9,12 +9,11 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>Dylan Moonfire</Authors>
<Company>Moonfire Games</Company>
<RepositoryUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-gemtext-cil</RepositoryUrl>
<RepositoryUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-cil</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<PackageTags>ecs</PackageTags>
<PackageProjectUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-gemtext-cil</PackageProjectUrl>
<PackageProjectUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-cil</PackageProjectUrl>
<PackageLicense>MIT</PackageLicense>
<Description>A Markdown extension to render Markdown in Gemtext.</Description>
<Description>A MarkDig extension to render Markdown in Gemtext.</Description>
</PropertyGroup>
<ItemGroup>

View file

@ -16,7 +16,7 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks
renderer.EnsureTwoLines();
// Go through each list item and write them out.
foreach (var item in listBlock)
foreach (Block? item in listBlock)
{
// If the list only contains a link, then we just render the
// link instead.

View file

@ -1,4 +1,5 @@
using Markdig.Syntax;
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks

View file

@ -1,4 +1,5 @@
using Markdig.Syntax;
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks

View file

@ -1,5 +1,6 @@
using System;
using System.Net;
using Markdig.Extensions.SmartyPants;
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines

View file

@ -1,4 +1,5 @@
using System.IO;
using Markdig.Syntax.Inlines;
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines
@ -25,7 +26,7 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines
// write out each link which is already formatted.
renderer.WriteLine();
foreach (var link in renderer.GatheredLinks)
foreach (string? link in renderer.GatheredLinks)
{
renderer.WriteLine();
renderer.Write(link);

View file

@ -1,4 +1,5 @@
using System.Linq;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;

View file

@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.IO;
using Markdig.Helpers;
using Markdig.Renderers;
using Markdig.Syntax;
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;

View file

@ -0,0 +1,11 @@
using Markdig.Syntax.Inlines;
namespace MfGames.Markdown.Extensions;
public class WikiLink : LinkInline
{
public WikiLink()
{
this.IsClosed = false;
}
}

View file

@ -0,0 +1,47 @@
using Markdig;
using Markdig.Parsers.Inlines;
using Markdig.Renderers;
namespace MfGames.Markdown.Extensions;
/// <summary>
/// Translate `[[Bob]]` into `/bob/`.
/// </summary>
public class WikiLinkExtension : IMarkdownExtension
{
public WikiLinkExtension()
: this(null)
{
}
public WikiLinkExtension(WikiLinkOptions? options)
{
this.Options = options ?? new WikiLinkOptions();
}
public WikiLinkOptions Options { get; set; }
/// <inheritdoc />
public void Setup(MarkdownPipelineBuilder pipeline)
{
WikiLinkInlineParser? parser = pipeline.InlineParsers
.FindExact<WikiLinkInlineParser>();
if (parser != null)
{
return;
}
parser = new WikiLinkInlineParser(this.Options);
pipeline.InlineParsers.InsertBefore<LinkInlineParser>(parser);
}
/// <inheritdoc />
public void Setup(
MarkdownPipeline pipeline,
IMarkdownRenderer renderer)
{
// No setup needed here because we're using LinkInline which does the
// bulk of the work.
}
}

View file

@ -0,0 +1,112 @@
using System.Linq;
using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Syntax.Inlines;
namespace MfGames.Markdown.Extensions;
public class WikiLinkInlineParser : InlineParser
{
private readonly WikiLinkOptions options;
public WikiLinkInlineParser(WikiLinkOptions options)
{
this.options = options;
this.OpeningCharacters = new[] { '[' };
}
/// <inheritdoc />
public override bool Match(
InlineProcessor processor,
ref StringSlice slice)
{
// We are looking for the `[[` opening for the tag and that the first
// one isn't escaped.
if (IsNotDelimiter(slice, '['))
{
return false;
}
// We need to loop over the entire link, including the `[[` and `]]`
// while keeping track since we'll swallow additional characters beyond
// the link.
int linkStart = slice.Start;
int linkEnd = slice.Start;
slice.Start += 2;
// Our content starts after the double '[['.
int contentStart = slice.Start;
// We need to find the end of the link (the `]]`).
while (IsNotDelimiter(slice, ']'))
{
slice.NextChar();
linkEnd = slice.Start;
}
// Pull out the components before we adjust for the ']]' for the end.
int contentEnd = linkEnd;
// Finish skipping over the `]]`.
slice.NextChar();
slice.NextChar();
// Format the label and the URL.
string content = slice.Text.Substring(
contentStart,
contentEnd - contentStart);
string[] contentParts = content.Split('|', 2);
string label = contentParts.Last();
string url = this.options.GetUrl(contentParts.First());
// Add in any trailing components. This merges the `'s` from
// `[[Dale]]'s` into the label.
while (this.options.IsTrailingLink(slice.CurrentChar))
{
label += slice.CurrentChar;
slice.NextChar();
linkEnd++;
}
// Create the link that we're replacing.
WikiLink link = new()
{
Span =
{
Start = processor.GetSourcePosition(
linkStart,
out int line,
out int column),
},
Line = line,
Column = column,
Url = url,
IsClosed = true,
};
link.AppendChild(
new LiteralInline()
{
Line = line,
Column = column,
Content = new StringSlice(label),
IsClosed = true,
});
// Replace the inline and then indicate we have a match.
processor.Inline = link;
return true;
}
private static bool IsNotDelimiter(
StringSlice slice,
char delimiter)
{
return slice.CurrentChar != delimiter
|| slice.PeekChar() != delimiter
|| slice.PeekCharExtra(-1) == '\\';
}
}

View file

@ -0,0 +1,31 @@
using System;
using Markdig.Helpers;
namespace MfGames.Markdown.Extensions;
public class WikiLinkOptions
{
public WikiLinkOptions()
{
this.GetUrl = a => a;
this.IsTrailingLink = a => a.IsAlpha() || a == '\'';
}
/// <summary>
/// The callback to determine the link from the given wiki link. This does
/// not include trailing additions or use the label (e.g., `(ab|cd)` would
/// get `ab` as the parameters of this function.
/// </summary>
public Func<string, string> GetUrl { get; set; }
/// <summary>
/// <para>
/// A callback to determine if the text after the link should be merged
/// with the link label. This allows links such as [[Dale]]'s to be turned
/// into "Dale's" but pointing to "Dale" as a page.
/// </para>
/// <para>The default is to include any character or the apostrophe.</para>
/// </summary>
public Func<char, bool> IsTrailingLink { get; set; }
}

View file

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>Dylan Moonfire</Authors>
<Company>Moonfire Games</Company>
<RepositoryUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-cil</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<PackageProjectUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-cil</PackageProjectUrl>
<PackageLicense>MIT</PackageLicense>
<Description>Various extensions for MarkDig and classes for working with Markdown.</Description>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Markdig" Version="0.30.3"/>
</ItemGroup>
</Project>

View file

@ -1,10 +1,11 @@
using Markdig;
using MfGames.Markdown.Gemtext;
using MfGames.Markdown.Gemtext.Extensions;
using MfGames.Markdown.Gemtext.Renderers;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
public class CodeInlineTests
{

View file

@ -1,7 +1,6 @@
using MfGames.Markdown.Gemtext;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
public class HeaderTests
{

View file

@ -1,7 +1,6 @@
using MfGames.Markdown.Gemtext;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
public class ImageLinkTests
{

View file

@ -1,9 +1,10 @@
using Markdig;
using MfGames.Markdown.Gemtext;
using MfGames.Markdown.Gemtext.Extensions;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
public class IncreaseHeaderDepthsAfterFirstTests
{

View file

@ -1,7 +1,6 @@
using MfGames.Markdown.Gemtext;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
public class LinkTests
{

View file

@ -1,7 +1,6 @@
using MfGames.Markdown.Gemtext;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
public class ListTests
{

View file

@ -2,10 +2,10 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>MfGames.Markdown.Gemini.Tests</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MfGames.TestSetup" Version="1.0.6"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1"/>
<PackageReference Include="JunitXml.TestLogger" Version="3.0.114"/>
<PackageReference Include="xunit" Version="2.4.2"/>
@ -21,6 +21,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\MfGames.Markdown.Gemtext\MfGames.Markdown.Gemtext.csproj"/>
<ProjectReference Include="..\..\src\MfGames.Markdown\MfGames.Markdown.csproj"/>
</ItemGroup>
</Project>

View file

@ -1,10 +1,11 @@
using Markdig;
using MfGames.Markdown.Gemtext;
using MfGames.Markdown.Gemtext.Extensions;
using MfGames.Markdown.Gemtext.Renderers;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
/// <summary>
/// Tests the various functionality of the ParagraphLinkHandling and

View file

@ -1,7 +1,6 @@
using MfGames.Markdown.Gemtext;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
public class PlainTextTests
{

View file

@ -1,7 +1,6 @@
using MfGames.Markdown.Gemtext;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
{
/// <summary>
/// https://github.com/makeworld-the-better-one/md2gemini/blob/master/tests/test_base_url.py

View file

@ -1,7 +1,6 @@
using MfGames.Markdown.Gemtext;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
{
/// <summary>
/// https://github.com/makeworld-the-better-one/md2gemini/blob/master/tests/test_codeblock.py

View file

@ -1,7 +1,6 @@
using MfGames.Markdown.Gemtext;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
{
/// <summary>
/// https://github.com/makeworld-the-better-one/md2gemini/blob/master/tests/test_list.py

View file

@ -1,9 +1,10 @@
using Markdig;
using MfGames.Markdown.Gemtext;
using MfGames.Markdown.Gemtext.Extensions;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
{
/// <summary>
/// Runs through various plain input tests.

View file

@ -1,12 +1,11 @@
using Markdig;
using MfGames.Markdown.Gemtext;
using MfGames.Markdown.Gemtext.Extensions;
using MfGames.Markdown.Gemtext.Renderers;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
{
/// <summary>
/// https://github.com/makeworld-the-better-one/md2gemini/blob/master/tests/test_strip_html.py

View file

@ -1,10 +1,11 @@
using Markdig;
using Markdig.Extensions.SmartyPants;
using MfGames.Markdown.Gemtext;
using MfGames.Markdown.Gemtext.Extensions;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
public class QuoteTests
{

View file

@ -2,12 +2,11 @@ using ConsoleTableExt;
using Markdig;
using MfGames.Markdown.Gemtext;
using MfGames.Markdown.Gemtext.Extensions;
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
namespace MfGames.Markdown.Gemtext.Tests
{
public class TableTests
{

View file

@ -0,0 +1,56 @@
using Markdig;
using MfGames.Markdown.Extensions;
using MfGames.Markdown.Gemtext.Extensions;
using MfGames.Markdown.Gemtext.Renderers;
using MfGames.TestSetup;
using Xunit;
using Xunit.Abstractions;
namespace MfGames.Markdown.Gemtext.Tests;
/// <summary>
/// Tests the functionality of the WriteFiles().
/// </summary>
public class WikiLinkTest : TestBase<TestContext>
{
public WikiLinkTest(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void PossessiveLabeledWikiLinkGemtext()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = MarkdownGemtext
.ToGemtext(
"[[Test|Label]]'s",
pipeline)
.Replace("%5E", "^");
Assert.Equal("=> ^test$ Label's", result);
}
private static MarkdownPipeline CreatePipeline()
{
// Convert all titles to slugs.
WikiLinkOptions options = new()
{
GetUrl = (title) => string.Format(
"^{0}$",
title.ToLowerInvariant().Replace(" ", "-")),
};
// Create the pipeline and return the results.
MarkdownPipelineBuilder builder = new MarkdownPipelineBuilder()
.Use(new WikiLinkExtension(options))
.Use(new SetBlockLinkHandling(BlockLinkHandling.DocumentEnd));
// Build the pipeline and return it.
MarkdownPipeline pipeline = builder.Build();
return pipeline;
}
}

View file

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Markdig" Version="0.30.3"/>
<PackageReference Include="MfGames.TestSetup" Version="1.0.6"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1"/>
<PackageReference Include="JunitXml.TestLogger" Version="3.0.114"/>
<PackageReference Include="xunit" Version="2.4.2"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\MfGames.Markdown\MfGames.Markdown.csproj"/>
</ItemGroup>
</Project>

View file

@ -0,0 +1,188 @@
using Markdig;
using MfGames.Markdown.Extensions;
using MfGames.TestSetup;
using Xunit;
using Xunit.Abstractions;
namespace MfGames.Markdown.Tests;
/// <summary>
/// Tests the functionality of the WriteFiles().
/// </summary>
public class WikiLinkTest : TestBase<TestContext>
{
public WikiLinkTest(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void BareStringHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown.ToHtml(
"This is text.",
pipeline);
Assert.Equal("<p>This is text.</p>\n", result);
}
[Fact]
public void BlankStringHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown.ToHtml(
"",
pipeline);
Assert.Equal("", result);
}
[Fact]
public void LabeledWikiLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown
.ToHtml(
"[[Test|Label]]",
pipeline)
.Replace("%5E", "^");
Assert.Equal("<p><a href=\"^test$\">Label</a></p>\n", result);
}
[Fact]
public void PossessiveLabeledWikiLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown
.ToHtml(
"[[Test|Label]]'s",
pipeline)
.Replace("%5E", "^");
Assert.Equal("<p><a href=\"^test$\">Label's</a></p>\n", result);
}
[Fact]
public void PossessiveWikiLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown
.ToHtml(
"[[Test]]'s",
pipeline)
.Replace("%5E", "^");
Assert.Equal("<p><a href=\"^test$\">Test's</a></p>\n", result);
}
[Fact]
public void PunctuationLabeledWikiLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown
.ToHtml(
"[[Test|Label]].",
pipeline)
.Replace("%5E", "^");
Assert.Equal("<p><a href=\"^test$\">Label</a>.</p>\n", result);
}
[Fact]
public void PunctuationWikiLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown
.ToHtml(
"[[Test]].",
pipeline)
.Replace("%5E", "^");
Assert.Equal("<p><a href=\"^test$\">Test</a>.</p>\n", result);
}
[Fact]
public void SentenceWikiLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown
.ToHtml(
"This is a [[test]] of this system.",
pipeline)
.Replace("%5E", "^");
Assert.Equal(
"<p>This is a <a href=\"^test$\">test</a> of this system.</p>\n",
result);
}
[Fact]
public void SimpleWikiLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown
.ToHtml(
"[[Test]]",
pipeline)
.Replace("%5E", "^");
Assert.Equal("<p><a href=\"^test$\">Test</a></p>\n", result);
}
[Fact]
public void StandardLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown.ToHtml(
"[Test](https://test/)",
pipeline);
Assert.Equal("<p><a href=\"https://test/\">Test</a></p>\n", result);
}
[Fact]
public void TrailingLabeledWikiLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown
.ToHtml(
"[[Test|Label]]s",
pipeline)
.Replace("%5E", "^");
Assert.Equal("<p><a href=\"^test$\">Labels</a></p>\n", result);
}
[Fact]
public void TrailingWikiLinkHtml()
{
MarkdownPipeline pipeline = CreatePipeline();
string result = Markdig.Markdown
.ToHtml(
"[[Test]]s",
pipeline)
.Replace("%5E", "^");
Assert.Equal("<p><a href=\"^test$\">Tests</a></p>\n", result);
}
private static MarkdownPipeline CreatePipeline()
{
WikiLinkOptions options = new()
{
GetUrl = (title) => string.Format(
"^{0}$",
title.ToLowerInvariant().Replace(" ", "-")),
};
MarkdownPipelineBuilder? builder = new MarkdownPipelineBuilder()
.Use(new WikiLinkExtension(options));
MarkdownPipeline? pipeline = builder.Build();
return pipeline;
}
}