Skip to content

Commit

Permalink
Navigation powered by docset.yml (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mpdreamz authored Nov 12, 2024
1 parent 2b862bc commit f86d89e
Show file tree
Hide file tree
Showing 13 changed files with 130 additions and 129 deletions.
12 changes: 6 additions & 6 deletions docs/source/docset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ exclude:
- '_*.md'
toc:
- file: index.md
- folder: markup
- folder: elastic
children:
- file: index.md
Expand All @@ -13,6 +12,10 @@ toc:
- folder: search-labs
children:
- file: index.md
- file: install.md
children:
- file: install/cloud.md
- file: install/docker.md
- file: chat.md
children:
- file: chat/req.md
Expand All @@ -21,12 +24,9 @@ toc:
children:
- file: search/req.md
- file: search/setup.md
- file: install.md
children:
- file: install/cloud.md
- file: install/docker.md
- folder: markup
- folder: nested
children:
- folder: content
- file: index.md
- folder: versioning
- folder: versioning
74 changes: 32 additions & 42 deletions src/Elastic.Markdown/IO/ConfigurationFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class ConfigurationFile : DocumentationFile
public IReadOnlyCollection<ITocItem> TableOfContents { get; } = [];

public HashSet<string> Files { get; } = new(StringComparer.OrdinalIgnoreCase);
public HashSet<string> Folders { get; } = new(StringComparer.OrdinalIgnoreCase);
public HashSet<string> ImplicitFolders { get; } = new(StringComparer.OrdinalIgnoreCase);
public Glob[] Globs { get; } = [];

public ConfigurationFile(IFileInfo sourceFile, IDirectoryInfo rootPath, BuildContext context)
Expand Down Expand Up @@ -72,7 +72,7 @@ public ConfigurationFile(IFileInfo sourceFile, IDirectoryInfo rootPath, BuildCon
break;
}
}
Globs = Folders.Select(f=> Glob.Parse($"{f}/*.md")).ToArray();
Globs = ImplicitFolders.Select(f=> Glob.Parse($"{f}/*.md")).ToArray();
}

private List<ITocItem> ReadChildren(KeyValuePair<YamlNode, YamlNode> entry, string parentPath)
Expand All @@ -99,18 +99,19 @@ private List<ITocItem> ReadChildren(KeyValuePair<YamlNode, YamlNode> entry, stri
{
string? file = null;
string? folder = null;
var found = false;
var fileFound = false;
var folderFound = false;
IReadOnlyCollection<ITocItem>? children = null;
foreach (var entry in tocEntry.Children)
{
var key = ((YamlScalarNode)entry.Key).Value;
switch (key)
{
case "file":
file = ReadFile(entry, parentPath);
file = ReadFile(entry, parentPath, out fileFound);
break;
case "folder":
folder = ReadString(entry);
folder = ReadFolder(entry, parentPath, out folderFound);
parentPath += $"/{folder}";
break;
case "children":
Expand All @@ -120,30 +121,47 @@ private List<ITocItem> ReadChildren(KeyValuePair<YamlNode, YamlNode> entry, stri
}

if (file is not null)
return new TocFile(file, found, children ?? []);
return new TocFile($"{parentPath}/{file}".TrimStart('/'), fileFound, children ?? []);

if (folder is not null)
{
if (children is null)
Folders.Add(parentPath.TrimStart('/'));
ImplicitFolders.Add(parentPath.TrimStart('/'));

return new TocFolder(folder, children ?? []);
return new TocFolder($"{parentPath}".TrimStart('/'), folderFound, children ?? []);
}

return null;
}

private string? ReadFile(KeyValuePair<YamlNode, YamlNode> entry, string parentPath)
private string? ReadFolder(KeyValuePair<YamlNode, YamlNode> entry, string parentPath, out bool found)
{
var file = ReadString(entry);
if (file is not null)
found = false;
var folder = ReadString(entry);
if (folder is not null)
{
var path = Path.Combine(_rootPath.FullName, parentPath.TrimStart('/'), file);
if (!_context.ReadFileSystem.FileInfo.New(path).Exists)
EmitError($"File '{path}' does not exist", entry.Key);
var path = Path.Combine(_rootPath.FullName, parentPath.TrimStart('/'), folder);
if (!_context.ReadFileSystem.DirectoryInfo.New(path).Exists)
EmitError($"Directory '{path}' does not exist", entry.Key);
else
found = true;
}
return folder;
}

private string? ReadFile(KeyValuePair<YamlNode, YamlNode> entry, string parentPath, out bool found)
{
found = false;
var file = ReadString(entry);
if (file is null) return null;

var path = Path.Combine(_rootPath.FullName, parentPath.TrimStart('/'), file);
if (!_context.ReadFileSystem.FileInfo.New(path).Exists)
EmitError($"File '{path}' does not exist", entry.Key);
else
found = true;
Files.Add((parentPath + "/" + file).TrimStart('/'));

return file;
}

Expand Down Expand Up @@ -210,31 +228,3 @@ private void EmitWarning(string message, Mark? start = null, Mark? end = null, i
}
}

public interface ITocItem;

public record TocFile(string Path, bool Found, IReadOnlyCollection<ITocItem> Children) : ITocItem;

public record TocFolder(string Path, IReadOnlyCollection<ITocItem> Children) : ITocItem;


/*
exclude:
- notes.md
- '**ignore.md'
toc:
- file: index.md
- file: config.md
- file: search.md
children:
- file: search-part2.md
- folder: search
- folder: my-folder1
exclude:
- '_*.md'
- folder: my-folder2
children:
- file: subpath/file.md
- file: file.md
- pattern: *.md
- folder: sub/folder
*/
1 change: 1 addition & 0 deletions src/Elastic.Markdown/IO/DocumentationFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public abstract class DocumentationFile(IFileInfo sourceFile, IDirectoryInfo roo
{
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")));
Expand Down
99 changes: 51 additions & 48 deletions src/Elastic.Markdown/IO/DocumentationFolder.cs
Original file line number Diff line number Diff line change
@@ -1,82 +1,85 @@
// 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 Markdig.Helpers;

namespace Elastic.Markdown.IO;

public class DocumentationFolder
{
public MarkdownFile? Index { get; }
private MarkdownFile[] Files { get; }
private DocumentationFolder[] Nested { get; }

public OrderedList<MarkdownFile> FilesInOrder { get; private set; }
public OrderedList<DocumentationFolder> GroupsInOrder { get; private set; }
public List<MarkdownFile> FilesInOrder { get; } = new();
public List<DocumentationFolder> GroupsInOrder { get; } = new();

private HashSet<MarkdownFile> OwnFiles { get; }

public int Level { get; }
public string? FolderName { get; }

public DocumentationFolder(Dictionary<string, MarkdownFile[]> markdownFiles, int level, string folderName)
public DocumentationFolder(IReadOnlyCollection<ITocItem> toc,
IDictionary<string, DocumentationFile> lookup,
IDictionary<string, DocumentationFile[]> folderLookup,
int level = 0,
MarkdownFile? index = null)
{
Level = level;
FolderName = folderName;

var files = markdownFiles
.Where(k => k.Key.EndsWith(".md")).SelectMany(g => g.Value)
.Where(file => file.ParentFolders.Count == level)
.ToArray();


Files = files
.Where(file => file.FileName != "index.md")
.ToArray();

FilesInOrder = new OrderedList<MarkdownFile>(Files);

Index = files.FirstOrDefault(f => f.FileName == "index.md");
Index = index;

var newLevel = level + 1;
var groups = new List<DocumentationFolder>();
foreach (var kv in markdownFiles.Where(kv=> !kv.Key.EndsWith(".md")))
foreach (var tocItem in toc)
{
var folder = kv.Key;
var folderFiles = kv.Value
.Where(file => file.ParentFolders.Count > level)
.Where(file => file.ParentFolders[level] == folder).ToArray();
var mapped = folderFiles
.GroupBy(file =>
{
var path = file.ParentFolders.Count > newLevel ? file.ParentFolders[newLevel] : file.FileName;
return path;
})
.ToDictionary(k => k.Key, v => v.ToArray());
var documentationGroup = new DocumentationFolder(mapped, newLevel, folder);
groups.Add(documentationGroup);
if (tocItem is TocFile file)
{
if (!lookup.TryGetValue(file.Path, out var d) || d is not MarkdownFile md)
continue;

if (file.Children.Count > 0 && d is MarkdownFile virtualIndex)
{
var group = new DocumentationFolder(file.Children, lookup, folderLookup, level + 1, virtualIndex);
GroupsInOrder.Add(group);
continue;
}

FilesInOrder.Add(md);
if (file.Path.EndsWith("index.md") && d is MarkdownFile i)
Index ??= i;
}
else if (tocItem is TocFolder folder)
{
var children = folder.Children;
if (children.Count == 0
&& folderLookup.TryGetValue(folder.Path, out var documentationFiles))
{
children = documentationFiles
.Select(d => new TocFile(d.RelativePath, true, []))
.ToArray();
}

var group = new DocumentationFolder(children, lookup, folderLookup, level + 1);
GroupsInOrder.Add(group);
}
}
Nested = groups.ToArray();
GroupsInOrder = new OrderedList<DocumentationFolder>(Nested);

Index ??= FilesInOrder.FirstOrDefault();
if (Index != null)
FilesInOrder = FilesInOrder.Except(new[] { Index }).ToList();
OwnFiles = [..FilesInOrder];
}

public bool HoldsCurrent(MarkdownFile current) =>
Index == current || Files.Contains(current) || Nested.Any(n => n.HoldsCurrent(current));
Index == current || OwnFiles.Contains(current) || GroupsInOrder.Any(n => n.HoldsCurrent(current));

private bool _resolved;

public async Task Resolve(Cancel ctx = default)
{
if (_resolved) return;

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

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

var fileList = new OrderedList<MarkdownFile>();
var groupList = new OrderedList<DocumentationFolder>();


FilesInOrder = fileList;
GroupsInOrder = groupList;
_resolved = true;
}
}
15 changes: 4 additions & 11 deletions src/Elastic.Markdown/IO/DocumentationSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,14 @@ public DocumentationSet(IDirectoryInfo? sourcePath, IDirectoryInfo? outputPath,

.ToList();


LastWrite = Files.Max(f => f.SourceFile.LastWriteTimeUtc);

FlatMappedFiles = Files.ToDictionary(file => file.RelativePath, file => file);
var folderFiles = Files
.GroupBy(file => file.RelativeFolder)
.ToDictionary(g=>g.Key, g=>g.ToArray());

var markdownFiles = Files.OfType<MarkdownFile>()
.Where(file => !file.RelativePath.StartsWith("_"))
.GroupBy(file =>
{
var path = file.ParentFolders.Count >= 1 ? file.ParentFolders[0] : file.FileName;
return path;
})
.ToDictionary(k => k.Key, v => v.ToArray());

Tree = new DocumentationFolder(markdownFiles, 0, "");
Tree = new DocumentationFolder(Configuration.TableOfContents, FlatMappedFiles, folderFiles);
}

private DocumentationFile CreateMarkDownFile(IFileInfo file, BuildContext context)
Expand Down
11 changes: 11 additions & 0 deletions src/Elastic.Markdown/IO/ITocItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// 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

namespace Elastic.Markdown.IO;

public interface ITocItem;

public record TocFile(string Path, bool Found, IReadOnlyCollection<ITocItem> Children) : ITocItem;

public record TocFolder(string Path, bool Found, IReadOnlyCollection<ITocItem> Children) : ITocItem;
2 changes: 1 addition & 1 deletion src/Elastic.Markdown/Slices/HtmlWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public async Task<string> RenderLayout(MarkdownFile markdown, Cancel ctx = defau
PageTocItems = markdown.TableOfContents,
Tree = DocumentationSet.Tree,
CurrentDocument = markdown,
Navigation = navigationHtml,
NavigationHtml = navigationHtml,
UrlPathPrefix = markdown.UrlPathPrefix
});
return await slice.RenderAsync(cancellationToken: ctx);
Expand Down
2 changes: 1 addition & 1 deletion src/Elastic.Markdown/Slices/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
PageTocItems = Model.PageTocItems,
Tree = Model.Tree,
CurrentDocument = Model.CurrentDocument,
Navigation = Model.Navigation,
NavigationHtml = Model.NavigationHtml,
UrlPathPrefix = Model.UrlPathPrefix,
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/Elastic.Markdown/Slices/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</div>
</div>
<div class="sy-page sy-container flex mx-auto">
@(new HtmlString(Model.Navigation))
@(new HtmlString(Model.NavigationHtml))
@*@(await RenderPartialAsync(Elastic.Markdown.Slices.Layout._TocTree.Create(Model)))*@
@(await RenderPartialAsync(_TableOfContents.Create(Model)))
<main class="sy-main w-full max-sm:max-w-full print:pt-6">
Expand Down
4 changes: 2 additions & 2 deletions src/Elastic.Markdown/Slices/_ViewModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class IndexViewModel
public required DocumentationFolder Tree { get; init; }
public required IReadOnlyCollection<PageTocItem> PageTocItems { get; init; }
public required MarkdownFile CurrentDocument { get; init; }
public required string Navigation { get; init; }
public required string NavigationHtml { get; init; }
public required string? UrlPathPrefix { get; init; }
}

Expand All @@ -22,7 +22,7 @@ public class LayoutViewModel
public required IReadOnlyCollection<PageTocItem> PageTocItems { get; init; }
public required DocumentationFolder Tree { get; init; }
public required MarkdownFile CurrentDocument { get; init; }
public required string Navigation { get; set; }
public required string NavigationHtml { get; set; }
public required string? UrlPathPrefix { get; set; }


Expand Down
Loading

0 comments on commit f86d89e

Please sign in to comment.