Skip to content

Commit

Permalink
Introduce the notion of minimal parsing (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mpdreamz authored Nov 18, 2024
1 parent b04f097 commit 816c727
Show file tree
Hide file tree
Showing 13 changed files with 69 additions and 56 deletions.
2 changes: 1 addition & 1 deletion src/Elastic.Markdown/DocumentationGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ await Parallel.ForEachAsync(DocumentationSet.Files, ctx, async (file, token) =>
var outputFile = OutputFile(file.RelativePath);
if (file is MarkdownFile markdown)
{
await markdown.ParseAsync(token);
await markdown.ParseFullAsync(token);
await HtmlWriter.WriteAsync(outputFile, markdown, token);
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/Elastic.Markdown/IO/ConfigurationFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace Elastic.Markdown.IO;

public class ConfigurationFile : DocumentationFile
public record ConfigurationFile : DocumentationFile
{
private readonly IFileInfo _sourceFile;
private readonly IDirectoryInfo _rootPath;
Expand Down
25 changes: 9 additions & 16 deletions src/Elastic.Markdown/IO/DocumentationFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,17 @@

namespace Elastic.Markdown.IO;

public abstract class DocumentationFile(IFileInfo sourceFile, IDirectoryInfo rootPath)
public abstract record DocumentationFile(IFileInfo SourceFile, IDirectoryInfo RootPath)
{
public IFileInfo SourceFile { get; } = sourceFile;
public string RelativePath { get; } = Path.GetRelativePath(rootPath.FullName, sourceFile.FullName);
public string RelativeFolder { get; } = Path.GetRelativePath(rootPath.FullName, sourceFile.Directory!.FullName);

public FileInfo OutputFile(IDirectoryInfo outputPath) =>
new(Path.Combine(outputPath.FullName, RelativePath.Replace(".md", ".html")));
public string RelativePath { get; } = Path.GetRelativePath(RootPath.FullName, SourceFile.FullName);
public string RelativeFolder { get; } = Path.GetRelativePath(RootPath.FullName, SourceFile.Directory!.FullName);
}

public class ImageFile(IFileInfo sourceFile, IDirectoryInfo rootPath, string mimeType = "image/png")
: DocumentationFile(sourceFile, rootPath)
{
public string MimeType { get; } = mimeType;
}
public record ImageFile(IFileInfo SourceFile, IDirectoryInfo RootPath, string MimeType = "image/png")
: DocumentationFile(SourceFile, RootPath);

public class StaticFile(IFileInfo sourceFile, IDirectoryInfo rootPath)
: DocumentationFile(sourceFile, rootPath);
public record StaticFile(IFileInfo SourceFile, IDirectoryInfo RootPath)
: DocumentationFile(SourceFile, RootPath);

public class ExcludedFile(IFileInfo sourceFile, IDirectoryInfo rootPath)
: DocumentationFile(sourceFile, rootPath);
public record ExcludedFile(IFileInfo SourceFile, IDirectoryInfo RootPath)
: DocumentationFile(SourceFile, RootPath);
6 changes: 2 additions & 4 deletions src/Elastic.Markdown/IO/DocumentationFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using Markdig.Helpers;

namespace Elastic.Markdown.IO;

public class DocumentationFolder
Expand Down Expand Up @@ -75,10 +73,10 @@ public async Task Resolve(Cancel ctx = default)
{
if (_resolved) return;

await Parallel.ForEachAsync(FilesInOrder, ctx, async (file, token) => await file.ParseAsync(token));
await Parallel.ForEachAsync(FilesInOrder, ctx, async (file, token) => await file.MinimalParse(token));
await Parallel.ForEachAsync(GroupsInOrder, ctx, async (group, token) => await group.Resolve(token));

await (Index?.ParseAsync(ctx) ?? Task.CompletedTask);
await (Index?.MinimalParse(ctx) ?? Task.CompletedTask);

_resolved = true;
}
Expand Down
3 changes: 1 addition & 2 deletions src/Elastic.Markdown/IO/DocumentationSet.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
using System.Globalization;

using System.IO.Abstractions;
using System.Text.Json;
using Elastic.Markdown.Diagnostics;
using Elastic.Markdown.Myst;

Expand Down
52 changes: 35 additions & 17 deletions src/Elastic.Markdown/IO/MarkdownFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,29 @@
// See the LICENSE file in the project root for more information
using System.IO.Abstractions;
using Elastic.Markdown.Myst;
using Elastic.Markdown.Myst.Directives;
using Elastic.Markdown.Slices;
using Markdig;
using Markdig.Extensions.Yaml;
using Markdig.Helpers;
using Markdig.Syntax;
using Slugify;

namespace Elastic.Markdown.IO;

public class MarkdownFile : DocumentationFile
public record MarkdownFile : DocumentationFile
{
private readonly SlugHelper _slugHelper = new();
private string? _navigationTitle;

public MarkdownFile(IFileInfo sourceFile, IDirectoryInfo rootPath, MarkdownParser parser, BuildContext context)
: base(sourceFile, rootPath)
{
ParentFolders = RelativePath.Split(Path.DirectorySeparatorChar).SkipLast(1).ToArray();
FileName = sourceFile.Name;
UrlPathPrefix = context.UrlPathPrefix;
MarkdownParser = parser;
}

public string? UrlPathPrefix { get; }
private MarkdownParser MarkdownParser { get; }
private FrontMatterParser FrontMatterParser { get; } = new();
public YamlFrontMatter? YamlFrontMatter { get; private set; }
public string? Title { get; private set; }
public string? NavigationTitle
Expand All @@ -38,16 +34,32 @@ public string? NavigationTitle
private set => _navigationTitle = value;
}

public List<PageTocItem> TableOfContents { get; } = new();
public IReadOnlyList<string> ParentFolders { get; }
private readonly List<PageTocItem> _tableOfContent = new();
public IReadOnlyCollection<PageTocItem> TableOfContents => _tableOfContent;

public string FileName { get; }
public string Url => $"{UrlPathPrefix}/{RelativePath.Replace(".md", ".html")}";

public async Task ParseAsync(Cancel ctx) => await ParseFullAsync(ctx);
private bool _instructionsParsed;

public async Task<MarkdownDocument> MinimalParse(Cancel ctx)
{
var document = await MarkdownParser.MinimalParseAsync(SourceFile, ctx);
ReadDocumentInstructions(document);
return document;
}

public async Task<MarkdownDocument> ParseFullAsync(Cancel ctx)
{
var document = await MarkdownParser.QuickParseAsync(SourceFile, ctx);
if (!_instructionsParsed)
await MinimalParse(ctx);

var document = await MarkdownParser.ParseAsync(SourceFile, YamlFrontMatter, ctx);
return document;
}

private void ReadDocumentInstructions(MarkdownDocument document)
{
if (document.FirstOrDefault() is YamlFrontMatterBlock yaml)
{
var raw = string.Join(Environment.NewLine, yaml.Lines.Lines);
Expand All @@ -63,14 +75,20 @@ public async Task<MarkdownDocument> ParseFullAsync(Cancel ctx)
.Where(title => !string.IsNullOrWhiteSpace(title))
.Select(title => new PageTocItem { Heading = title!, Slug = _slugHelper.GenerateSlug(title) })
.ToList();
TableOfContents.Clear();
TableOfContents.AddRange(contents);
return document;
_tableOfContent.Clear();
_tableOfContent.AddRange(contents);
_instructionsParsed = true;
}

public async Task<string> CreateHtmlAsync(YamlFrontMatter? matter, Cancel ctx)
{
var document = await MarkdownParser.ParseAsync(SourceFile, matter, ctx);
return document.ToHtml(MarkdownParser.Pipeline);
}

public string CreateHtml(MarkdownDocument document) =>
// var writer = new StringWriter();
// var renderer = new HtmlRenderer(writer);
// renderer.LinkRewriter = (s => s);
// MarkdownParser.Pipeline.Setup(renderer);
//
// var document = MarkdownParser.Parse(markdown, pipeline);
// renderer.Render(document);
// writer.Flush();
document.ToHtml(MarkdownParser.Pipeline);
}
4 changes: 2 additions & 2 deletions src/Elastic.Markdown/Myst/FrontMatterParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public class YamlFrontMatter
public Dictionary<string, string>? Properties { get; set; }
}

public class FrontMatterParser
public static class FrontMatterParser
{
public YamlFrontMatter Deserialize(string yaml)
public static YamlFrontMatter Deserialize(string yaml)
{
var input = new StringReader(yaml);

Expand Down
20 changes: 12 additions & 8 deletions src/Elastic.Markdown/Myst/MarkdownParser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.IO.Abstractions;
using Cysharp.IO;
using Elastic.Markdown.Myst.Comments;
Expand All @@ -17,7 +18,13 @@ public class MarkdownParser(IDirectoryInfo sourcePath, BuildContext context)
public IDirectoryInfo SourcePath { get; } = sourcePath;
public BuildContext Context { get; } = context;

public MarkdownPipeline Pipeline =>
public MarkdownPipeline MinimalPipeline { get; } =
new MarkdownPipelineBuilder()
.UseSubstitution()
.UseYamlFrontMatter()
.Build();

public MarkdownPipeline Pipeline { get; } =
new MarkdownPipelineBuilder()
.EnableTrackTrivia()
.UsePreciseSourceLocation()
Expand All @@ -30,17 +37,14 @@ public class MarkdownParser(IDirectoryInfo sourcePath, BuildContext context)
.UseGridTables()
.UsePipeTables()
.UseDirectives()
.DisableHtml()
.Build();


// TODO only scan for yaml front matter and toc information
public Task<MarkdownDocument> QuickParseAsync(IFileInfo path, Cancel ctx)
public Task<MarkdownDocument> MinimalParseAsync(IFileInfo path, Cancel ctx)
{
var context = new ParserContext(this, path, null, Context)
{
SkipValidation = true
};
return ParseAsync(path, context, Pipeline, ctx);
var context = new ParserContext(this, path, null, Context) { SkipValidation = true };
return ParseAsync(path, context, MinimalPipeline, ctx);
}

public Task<MarkdownDocument> ParseAsync(IFileInfo path, YamlFrontMatter? matter, Cancel ctx)
Expand Down
3 changes: 2 additions & 1 deletion src/Elastic.Markdown/Slices/HtmlWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ private async Task<string> RenderNavigation(MarkdownFile markdown, Cancel ctx =

public async Task<string> RenderLayout(MarkdownFile markdown, Cancel ctx = default)
{
var html = await markdown.CreateHtmlAsync(markdown.YamlFrontMatter, ctx);
var document = await markdown.ParseFullAsync(ctx);
var html = markdown.CreateHtml(document);
await DocumentationSet.Tree.Resolve(ctx);
var navigationHtml = await RenderNavigation(markdown, ctx);
var slice = Index.Create(new IndexViewModel
Expand Down
2 changes: 1 addition & 1 deletion src/docs-builder/Http/DocumentationWebHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private static async Task<IResult> ServeDocumentationFile(ReloadableGeneratorSta
{
case MarkdownFile markdown:
{
await markdown.ParseAsync(ctx);
await markdown.ParseFullAsync(ctx);
var rendered = await generator.RenderLayout(markdown, ctx);
return Results.Content(rendered, "text/html");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public virtual async Task InitializeAsync()
var collectTask = Task.Run(async () => await Collector.StartAsync(default), default);

Document = await File.ParseFullAsync(default);
Html = await File.CreateHtmlAsync(File.YamlFrontMatter, default);
Html = File.CreateHtml(Document);
Collector.Channel.TryComplete();

await collectTask;
Expand Down
2 changes: 1 addition & 1 deletion tests/Elastic.Markdown.Tests/Directives/ImageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class ImageBlockTests(ITestOutputHelper output) : DirectiveTest<ImageBloc
{
public override Task InitializeAsync()
{
FileSystem.AddFile(@"img/observability.png", "");
FileSystem.AddFile(@"docs/source/img/observability.png", "");
return base.InitializeAsync();
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Elastic.Markdown.Tests/Inline/InlneBaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ protected InlineTest(ITestOutputHelper output, [LanguageInjection("markdown")]st
public virtual async Task InitializeAsync()
{
Document = await File.ParseFullAsync(default);
Html = await File.CreateHtmlAsync(File.YamlFrontMatter, default);
Html = File.CreateHtml(Document);
}

public Task DisposeAsync() => Task.CompletedTask;
Expand Down

0 comments on commit 816c727

Please sign in to comment.