Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading