Skip to content

Commit

Permalink
Changed MarkdownItem constructor, method visibility and property attr…
Browse files Browse the repository at this point in the history
…ibutes to facilitate

  subclassing.
Updated Markdig dependency.
  • Loading branch information
WilStead committed Apr 26, 2021
1 parent b5e39df commit e9ad84f
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 74 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: publish
env:
VERSION: '0.2.3-preview'
VERSION: '0.3.0-preview'
PRERELEASE: true
on:
push:
Expand Down
27 changes: 27 additions & 0 deletions Test/SerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Tavenem.DataStorage;

namespace Tavenem.Wiki.Test
{
Expand Down Expand Up @@ -100,6 +101,32 @@ public void CategoryTest()
Assert.AreEqual(json, System.Text.Json.JsonSerializer.Serialize(deserialized));
}

[TestMethod]
public void MarkdownItemTest()
{
var value = new MarkdownItemTestSubclass(
"Test markdown",
"Test markdown",
"Test markdown",
new ReadOnlyCollection<WikiLink>(new[] { new WikiLink(false, false, false, false, "Test Title", "Test Namespace") }));

var json = System.Text.Json.JsonSerializer.Serialize(value);
Console.WriteLine();
Console.WriteLine(json);
var deserialized = System.Text.Json.JsonSerializer.Deserialize<MarkdownItemTestSubclass>(json);
Assert.AreEqual(value, deserialized);
Assert.AreEqual(json, System.Text.Json.JsonSerializer.Serialize(deserialized));

value = MarkdownItemTestSubclass.New(_Options, new InMemoryDataStore(), "Test markdown");

json = System.Text.Json.JsonSerializer.Serialize(value);
Console.WriteLine();
Console.WriteLine(json);
deserialized = System.Text.Json.JsonSerializer.Deserialize<MarkdownItemTestSubclass>(json);
Assert.AreEqual(value, deserialized);
Assert.AreEqual(json, System.Text.Json.JsonSerializer.Serialize(deserialized));
}

[TestMethod]
public void MessageTest()
{
Expand Down
7 changes: 7 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 0.3.0-preview
### Changed
- Changed MarkdownItem constructor, method visibility and property attributes to facilitate
subclassing.
### Updated
- Updated Markdig dependency.

## 0.2.3-preview
### Fixed
- Fixed editor parameter signature in creation callback.
Expand Down
4 changes: 1 addition & 3 deletions src/Converters/ArticleConverter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
using Tavenem.DataStorage;
Expand All @@ -17,8 +16,7 @@ public class ArticleConverter : JsonConverter<Article>
/// <param name="typeToConvert">The type to convert.</param>
/// <param name="options">An object that specifies serialization options to use.</param>
/// <returns>The converted value.</returns>
[return: MaybeNull]
public override Article Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override Article? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var initialReader = reader;

Expand Down
27 changes: 16 additions & 11 deletions src/MarkdownExtensions/TableOfContents/TableOfContentsExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Markdig.Parsers;
using Markdig.Renderers;
using Markdig.Syntax;
using System.Collections.Generic;
using System.Linq;

namespace Tavenem.Wiki.MarkdownExtensions.TableOfContents
Expand Down Expand Up @@ -130,19 +131,23 @@ private void PipelineOnDocumentProcessed(MarkdownDocument document)

foreach (var toC in toCs.Where(x => !x.IsNoToc))
{
var levelOffset = toC.Parent.Descendants<HeadingBlock>()
.Where(x => x.Line < toC.Line)
.OrderByDescending(x => x.Line)
.FirstOrDefault()?.Level ?? 0;
var levelOffset = toC.Parent is null
? 0
: toC.Parent.Descendants<HeadingBlock>()
.Where(x => x.Line < toC.Line)
.OrderByDescending(x => x.Line)
.FirstOrDefault()?.Level ?? 0;
toC.LevelOffset = levelOffset;

var headings = toC.Parent.Descendants<HeadingBlock>()
.Where(x => x.Line > toC.Line)
.OrderBy(x => x.Line)
.TakeWhile(x => x.Level > levelOffset)
.Where(x => x.Level >= levelOffset + toC.StartingLevel
&& x.Level < levelOffset + toC.StartingLevel + toC.Depth)
.ToList();
var headings = toC.Parent is null
? new List<HeadingBlock>()
: toC.Parent.Descendants<HeadingBlock>()
.Where(x => x.Line > toC.Line)
.OrderBy(x => x.Line)
.TakeWhile(x => x.Level > levelOffset)
.Where(x => x.Level >= levelOffset + toC.StartingLevel
&& x.Level < levelOffset + toC.StartingLevel + toC.Depth)
.ToList();

if (!toC.IsDefault || headings.Count >= Options.MinimumTopLevel)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,15 @@ protected override void Write(HtmlRenderer renderer, TableOfContentsBlock block)
}

string headingText;
using (var sw = new StringWriter())
if (headings[i].Inline is null)
{
headingText = string.Empty;
}
else
{
using var sw = new StringWriter();
var stripRenderer = new HtmlRenderer(sw);
stripRenderer.Render(headings[i].Inline);
stripRenderer.Render(headings[i].Inline!);
headingText = stripRenderer.Writer.ToString() ?? string.Empty;
}

Expand Down
2 changes: 1 addition & 1 deletion src/MarkdownExtensions/WikiLinks/WikiLinkInlineParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ and not SeparatorChar

private bool TryProcessLinkOrImage(InlineProcessor inlineState, ref StringSlice text)
{
var openParent = inlineState.Inline.FindParentOfType<WikiLinkDelimiterInline>().FirstOrDefault();
var openParent = inlineState.Inline?.FindParentOfType<WikiLinkDelimiterInline>().FirstOrDefault();
if (openParent is null)
{
return false;
Expand Down
21 changes: 11 additions & 10 deletions src/MarkdownExtensions/WikiLinks/WikiLinkInlineRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ protected override void Write(HtmlRenderer renderer, WikiLinkInline link)
}
var fullTitle = !link.IsCommons
&& !link.IsWikipedia
&& (link.Title.Length == 0 || link.Title[0] != '#')
? Article.GetFullTitle(Options, link.Title, link.WikiNamespace, link.IsTalk)
&& (string.IsNullOrEmpty(link.Title) || link.Title[0] != '#')
? Article.GetFullTitle(Options, link.Title ?? string.Empty, link.WikiNamespace, link.IsTalk)
: link.Title;

if (renderer.EnableHtmlForInline)
Expand All @@ -53,7 +53,7 @@ protected override void Write(HtmlRenderer renderer, WikiLinkInline link)
{
renderer.Write("<img src=\"/");
}
else if (link.Title.Length > 0 && link.Title[0] == '#')
else if (!string.IsNullOrEmpty(link.Title) && link.Title[0] == '#')
{
renderer.Write("<a href=\"");
}
Expand All @@ -69,7 +69,7 @@ protected override void Write(HtmlRenderer renderer, WikiLinkInline link)

if (!link.IsWikipedia
&& !link.IsCommons
&& (link.Title.Length == 0 || link.Title[0] != '#')
&& (string.IsNullOrEmpty(link.Title) || link.Title[0] != '#')
&& !string.IsNullOrEmpty(Options.LinkTemplate))
{
renderer.Write(" ");
Expand Down Expand Up @@ -110,33 +110,34 @@ protected override void Write(HtmlRenderer renderer, WikiLinkInline link)
renderer.Write("\"");
}

var heightIndex = link.GetAttributes()?.Properties?.FindIndex(x => x.Key.Equals("height", StringComparison.OrdinalIgnoreCase)) ?? -1;
var properties = link.GetAttributes()?.Properties;
var heightIndex = properties?.FindIndex(x => x.Key.Equals("height", StringComparison.OrdinalIgnoreCase)) ?? -1;
if (heightIndex != -1)
{
if (int.TryParse(link.GetAttributes().Properties[heightIndex].Value, out var heightInt))
if (int.TryParse(properties![heightIndex].Value, out var heightInt))
{
renderer.Write("height=\"");
renderer.Write(heightInt.ToString());
renderer.Write("\"");
}
else if (double.TryParse(link.GetAttributes().Properties[heightIndex].Value, out var heightFloat))
else if (double.TryParse(properties[heightIndex].Value, out var heightFloat))
{
renderer.Write("height=\"");
renderer.Write(heightFloat.ToString());
renderer.Write("\"");
}
}

var widthIndex = link.GetAttributes()?.Properties?.FindIndex(x => x.Key.Equals("width", StringComparison.OrdinalIgnoreCase)) ?? -1;
var widthIndex = properties?.FindIndex(x => x.Key.Equals("width", StringComparison.OrdinalIgnoreCase)) ?? -1;
if (widthIndex != -1)
{
if (int.TryParse(link.GetAttributes().Properties[widthIndex].Value, out var widthInt))
if (int.TryParse(properties![widthIndex].Value, out var widthInt))
{
renderer.Write("width=\"");
renderer.Write(widthInt.ToString());
renderer.Write("\"");
}
else if (double.TryParse(link.GetAttributes().Properties[widthIndex].Value, out var widthFloat))
else if (double.TryParse(properties[widthIndex].Value, out var widthFloat))
{
renderer.Write("width=\"");
renderer.Write(widthFloat.ToString());
Expand Down
123 changes: 84 additions & 39 deletions src/MarkdownItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using Tavenem.DataStorage;
using Tavenem.DiffPatchMerge;
using Tavenem.Wiki.MarkdownExtensions.TableOfContents;
Expand Down Expand Up @@ -41,23 +42,55 @@ public abstract class MarkdownItem : IdItem, ISerializable
/// <summary>
/// The rendered HTML content.
/// </summary>
public string Html { get; private protected set; } = null!; // Always initialized during ctor, but in one instance by the subclass.
[JsonInclude]
public string Html { get; private protected set; }

/// <summary>
/// The markdown content.
/// </summary>
[JsonInclude]
public string MarkdownContent { get; private protected set; }

/// <summary>
/// A preview of this item's rendered HTML.
/// </summary>
public string Preview { get; private protected set; } = null!; // Always initialized during ctor, but in one instance by the subclass.
[JsonInclude]
public string Preview { get; private protected set; }

/// <summary>
/// The wiki links within this content.
/// </summary>
[JsonInclude]
public IReadOnlyCollection<WikiLink> WikiLinks { get; private protected set; } = new List<WikiLink>().AsReadOnly();

/// <summary>
/// Initializes a new instance of <see cref="MarkdownItem"/>.
/// </summary>
/// <remarks>
/// Note: this constructor is most useful for deserializers.
/// </remarks>
protected MarkdownItem()
{
Html = string.Empty;
MarkdownContent = string.Empty;
Preview = string.Empty;
WikiLinks = new List<WikiLink>().AsReadOnly();
}

/// <summary>
/// Initializes a new instance of <see cref="MarkdownItem"/>.
/// </summary>
/// <remarks>
/// Note: this constructor is most useful for deserializers.
/// </remarks>
protected MarkdownItem(string id) : base(id)
{
Html = string.Empty;
MarkdownContent = string.Empty;
Preview = string.Empty;
WikiLinks = new List<WikiLink>().AsReadOnly();
}

/// <summary>
/// Initializes a new instance of <see cref="MarkdownItem"/>.
/// </summary>
Expand All @@ -69,7 +102,7 @@ public abstract class MarkdownItem : IdItem, ISerializable
/// <remarks>
/// Note: this constructor is most useful for deserializers.
/// </remarks>
private protected MarkdownItem(string id, string? markdownContent, string html, string preview, IReadOnlyCollection<WikiLink> wikiLinks) : base(id)
protected MarkdownItem(string id, string? markdownContent, string html, string preview, IReadOnlyCollection<WikiLink> wikiLinks) : base(id)
{
Html = html;
MarkdownContent = markdownContent ?? string.Empty;
Expand All @@ -88,7 +121,7 @@ private protected MarkdownItem(string id, string? markdownContent, string html,
/// A preview of this item's rendered HTML.
/// </param>
/// <param name="wikiLinks">The included <see cref="WikiLink"/> objects.</param>
private protected MarkdownItem(string? markdown, string? html, string? preview, IReadOnlyCollection<WikiLink> wikiLinks)
protected MarkdownItem(string? markdown, string? html, string? preview, IReadOnlyCollection<WikiLink> wikiLinks)
{
MarkdownContent = markdown ?? string.Empty;
Html = html ?? string.Empty;
Expand Down Expand Up @@ -378,6 +411,53 @@ public string GetPlainText(
public string GetPreview(IWikiOptions options, IDataStore dataStore)
=> RenderPreview(options, dataStore, PostprocessMarkdown(options, dataStore, MarkdownContent, isPreview: true));

/// <summary>
/// Identifies the <see cref="WikiLink"/>s in the given <paramref name="markdown"/>.
/// </summary>
/// <param name="options">An <see cref="WikiOptions"/> instance.</param>
/// <param name="dataStore">An <see cref="IDataStore"/> instance.</param>
/// <param name="markdown">The markdown.</param>
/// <param name="title">The title of the item.</param>
/// <param name="wikiNamespace">The namespace of the item.</param>
/// <returns>
/// A <see cref="List{T}"/> of <see cref="WikiLink"/>s.
/// </returns>
protected static List<WikiLink> GetWikiLinks(
IWikiOptions options,
IDataStore dataStore,
string? markdown,
string? title = null,
string? wikiNamespace = null)
=> string.IsNullOrEmpty(markdown)
? new List<WikiLink>()
: Markdown.Parse(markdown, WikiConfig.GetMarkdownPipeline(options, dataStore))
.Descendants<WikiLinkInline>()
.Where(x => !x.IsWikipedia
&& !x.IsCommons
&& (string.IsNullOrEmpty(x.Title)
|| x.Title.Length < 5
|| ((x.Title[0] != TransclusionParser.TransclusionOpenChar
|| x.Title[1] != TransclusionParser.TransclusionOpenChar
|| x.Title[^1] != TransclusionParser.TransclusionCloseChar
|| x.Title[^2] != TransclusionParser.TransclusionCloseChar)
&& (x.Title[0] != TransclusionParser.ParameterOpenChar
|| x.Title[1] != TransclusionParser.ParameterOpenChar
|| x.Title[^1] != TransclusionParser.ParameterCloseChar
|| x.Title[^2] != TransclusionParser.ParameterCloseChar))))
.Select(x =>
{
var anchorIndex = x.Title?.LastIndexOf('#') ?? -1;
return new WikiLink(
x.Article,
x.Missing && (x.Title != title || x.WikiNamespace != wikiNamespace),
x.IsCategory,
x.IsNamespaceEscaped,
x.IsTalk,
anchorIndex == -1 ? x.Title ?? string.Empty : x.Title![..anchorIndex],
x.WikiNamespace ?? options.DefaultNamespace);
})
.ToList();

private static bool AnyPreviews(MarkdownObject obj)
{
if (obj is ContainerBlock containerBlock)
Expand Down Expand Up @@ -420,41 +500,6 @@ private static bool AnyPreviews(MarkdownObject obj)
return false;
}

private protected static List<WikiLink> GetWikiLinks(
IWikiOptions options,
IDataStore dataStore,
string? markdown,
string? title = null,
string? wikiNamespace = null)
=> string.IsNullOrEmpty(markdown)
? new List<WikiLink>()
: Markdown.Parse(markdown, WikiConfig.GetMarkdownPipeline(options, dataStore))
.Descendants<WikiLinkInline>()
.Where(x => !x.IsWikipedia
&& !x.IsCommons
&& (x.Title.Length < 5
|| ((x.Title[0] != TransclusionParser.TransclusionOpenChar
|| x.Title[1] != TransclusionParser.TransclusionOpenChar
|| x.Title[^1] != TransclusionParser.TransclusionCloseChar
|| x.Title[^2] != TransclusionParser.TransclusionCloseChar)
&& (x.Title[0] != TransclusionParser.ParameterOpenChar
|| x.Title[1] != TransclusionParser.ParameterOpenChar
|| x.Title[^1] != TransclusionParser.ParameterCloseChar
|| x.Title[^2] != TransclusionParser.ParameterCloseChar))))
.Select(x =>
{
var anchorIndex = x.Title.LastIndexOf('#');
return new WikiLink(
x.Article,
x.Missing && (x.Title != title || x.WikiNamespace != wikiNamespace),
x.IsCategory,
x.IsNamespaceEscaped,
x.IsTalk,
anchorIndex == -1 ? x.Title : x.Title[..anchorIndex],
x.WikiNamespace ?? options.DefaultNamespace);
})
.ToList();

private static void Trim(MarkdownObject obj, ref int minCharactersAvailable, ref int maxCharactersAvailable)
{
if (obj is ContainerBlock containerBlock)
Expand Down
Loading

0 comments on commit e9ad84f

Please sign in to comment.