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
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,12 @@ public void CreateNavigationItem(
List<DocumentationGroup> groups,
List<INavigationItem> navigationItems,
int depth,
bool inNav,
ref int fileIndex,
int index)
{
var detectionRulesFolder = (RulesFolderReference)tocItem;
var children = detectionRulesFolder.Children;
var group = new DocumentationGroup(Build, lookups with { TableOfContents = children }, ref fileIndex, depth + 1, inNav)
{
Parent = parent
};
var group = new DocumentationGroup(Build, lookups with { TableOfContents = children }, ref fileIndex, depth + 1, null, parent);
groups.Add(group);
navigationItems.Add(new GroupNavigation(index, depth, group));
}
Expand Down
1 change: 0 additions & 1 deletion src/Elastic.Markdown/Extensions/IDocsBuilderExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ void CreateNavigationItem(
List<DocumentationGroup> groups,
List<INavigationItem> navigationItems,
int depth,
bool inNav,
ref int fileIndex,
int index
);
Expand Down
49 changes: 8 additions & 41 deletions src/Elastic.Markdown/Helpers/Htmx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,62 +9,29 @@ namespace Elastic.Markdown.Helpers;

public static class Htmx
{
public static string GetHxSelectOob(FeatureFlags features, string? pathPrefix, string currentUrl, string targetUrl)
public static string GetHxSelectOob(bool hasSameTopLevelGroup)
{
if (features.IsPrimaryNavEnabled && currentUrl == pathPrefix + "/")
return "#main-container,#primary-nav,#secondary-nav";

var selectTargets = "#primary-nav,#secondary-nav,#content-container,#toc-nav";
if (!HasSameTopLevelGroup(pathPrefix, currentUrl, targetUrl) && features.IsPrimaryNavEnabled)
var selectTargets = "#content-container,#toc-nav";
if (!hasSameTopLevelGroup)
selectTargets += ",#pages-nav";
return selectTargets;
}

public static bool HasSameTopLevelGroup(string? pathPrefix, string currentUrl, string targetUrl)
{
if (string.IsNullOrEmpty(targetUrl) || string.IsNullOrEmpty(currentUrl))
return false;
var startIndex = pathPrefix?.Length ?? 0;

if (currentUrl.Length < startIndex)
throw new InvalidUrlException("Unexpected current URL", currentUrl, startIndex);

if (targetUrl.Length < startIndex)
throw new InvalidUrlException("Unexpected target URL", targetUrl, startIndex);

var currentSegments = GetSegments(currentUrl[startIndex..].Trim('/'));
var targetSegments = GetSegments(targetUrl[startIndex..].Trim('/'));
return currentSegments.Length >= 1 && targetSegments.Length >= 1 && currentSegments[0] == targetSegments[0];
}

public static string GetPreload() => "true";

public static string GetHxSwap() => "none";
public static string GetHxPushUrl() => "true";
public static string GetHxIndicator() => "#htmx-indicator";
private static string GetHxSwap() => "none";
private static string GetHxPushUrl() => "true";
private static string GetHxIndicator() => "#htmx-indicator";

private static string[] GetSegments(string url) => url.Split('/');

public static string GetHxAttributes(FeatureFlags features, string? pathPrefix, string currentUrl, string targetUrl)
public static string GetHxAttributes(string targetUrl, bool hasSameTopLevelGroup)
{
var attributes = new StringBuilder();
_ = attributes.Append($" hx-get={targetUrl}");
_ = attributes.Append($" hx-select-oob={GetHxSelectOob(features, pathPrefix, currentUrl, targetUrl)}");
_ = attributes.Append($" hx-select-oob={GetHxSelectOob(hasSameTopLevelGroup)}");
_ = attributes.Append($" hx-swap={GetHxSwap()}");
_ = attributes.Append($" hx-push-url={GetHxPushUrl()}");
_ = attributes.Append($" hx-indicator={GetHxIndicator()}");
_ = attributes.Append($" preload={GetPreload()}");
return attributes.ToString();
}
}


internal sealed class InvalidUrlException : ArgumentException
{
public InvalidUrlException(string message, string url, int startIndex)
: base($"{message} (Url: {url}, StartIndex: {startIndex})")
{
Data["Url"] = url;
Data["StartIndex"] = startIndex;
}
}
6 changes: 3 additions & 3 deletions src/Elastic.Markdown/IO/Configuration/ITocItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public interface ITocItem
public record FileReference(ITableOfContentsScope TableOfContentsScope, string Path, bool Found, bool Hidden, IReadOnlyCollection<ITocItem> Children)
: ITocItem;

public record FolderReference(ITableOfContentsScope TableOfContentsScope, string Path, bool Found, bool InNav, IReadOnlyCollection<ITocItem> Children)
public record FolderReference(ITableOfContentsScope TableOfContentsScope, string Path, bool Found, IReadOnlyCollection<ITocItem> Children)
: ITocItem;

public record TocReference(ITableOfContentsScope TableOfContentsScope, string Path, bool Found, bool InNav, IReadOnlyCollection<ITocItem> Children)
: FolderReference(TableOfContentsScope, Path, Found, InNav, Children);
public record TocReference(ITableOfContentsScope TableOfContentsScope, string Path, bool Found, IReadOnlyCollection<ITocItem> Children)
: FolderReference(TableOfContentsScope, Path, Found, Children);
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.IO.Abstractions;
using System.Runtime.InteropServices;
using Elastic.Markdown.Extensions.DetectionRules;
using Elastic.Markdown.IO.Navigation;
using YamlDotNet.RepresentationModel;

namespace Elastic.Markdown.IO.Configuration;
Expand Down Expand Up @@ -81,7 +82,6 @@ public IReadOnlyCollection<ITocItem> ReadChildren(YamlStreamReader reader, KeyVa
var folderFound = false;
var detectionRulesFound = false;
var hiddenFile = false;
var inNav = false;
IReadOnlyCollection<ITocItem>? children = null;
foreach (var entry in tocEntry.Children)
{
Expand All @@ -91,10 +91,6 @@ public IReadOnlyCollection<ITocItem> ReadChildren(YamlStreamReader reader, KeyVa
case "toc":
toc = ReadNestedToc(reader, entry, parentPath, out fileFound);
break;
case "in_nav":
if (!bool.TryParse(reader.ReadString(entry), out inNav))
throw new ArgumentException("in_nav must be a boolean");
break;
case "hidden":
case "file":
hiddenFile = key == "hidden";
Expand Down Expand Up @@ -122,7 +118,7 @@ public IReadOnlyCollection<ITocItem> ReadChildren(YamlStreamReader reader, KeyVa
foreach (var f in toc.Files)
_ = Files.Add(f);

return [new TocReference(this, $"{parentPath}".TrimStart(Path.DirectorySeparatorChar), folderFound, inNav, toc.TableOfContents)];
return [new TocReference(this, $"{parentPath}".TrimStart(Path.DirectorySeparatorChar), folderFound, toc.TableOfContents)];
}

if (file is not null)
Expand Down Expand Up @@ -151,7 +147,7 @@ public IReadOnlyCollection<ITocItem> ReadChildren(YamlStreamReader reader, KeyVa
if (children is null)
_ = _configuration.ImplicitFolders.Add(parentPath.TrimStart(Path.DirectorySeparatorChar));

return [new FolderReference(this, $"{parentPath}".TrimStart(Path.DirectorySeparatorChar), folderFound, inNav, children ?? [])];
return [new FolderReference(this, $"{parentPath}".TrimStart(Path.DirectorySeparatorChar), folderFound, children ?? [])];
}

return null;
Expand Down
7 changes: 1 addition & 6 deletions src/Elastic.Markdown/IO/DocumentationSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
using Elastic.Markdown.CrossLinks;
using Elastic.Markdown.Diagnostics;
using Elastic.Markdown.Extensions;
using Elastic.Markdown.Extensions.DetectionRules;
using Elastic.Markdown.IO.Configuration;
using Elastic.Markdown.IO.Discovery;
using Elastic.Markdown.IO.Navigation;
using Elastic.Markdown.Myst;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -111,10 +109,7 @@ public DocumentationSet(BuildContext build, ILoggerFactory logger, ICrossLinkRes
FilesGroupedByFolder = FilesGroupedByFolder
};

Tree = new DocumentationGroup(Build, lookups, false, ref fileIndex)
{
Parent = null
};
Tree = new DocumentationGroup(Build, lookups, ref fileIndex);

var markdownFiles = Files.OfType<MarkdownFile>().ToArray();

Expand Down
26 changes: 7 additions & 19 deletions src/Elastic.Markdown/IO/MarkdownFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

namespace Elastic.Markdown.IO;

public record MarkdownFile : DocumentationFile
public record MarkdownFile : DocumentationFile, INavigationScope, ITableOfContentsScope
{
private string? _navigationTitle;

Expand Down Expand Up @@ -49,8 +49,13 @@ DocumentationSet set
//may be updated by DocumentationGroup.ProcessTocItems
//todo refactor mutability of MarkdownFile as a whole
ScopeDirectory = build.Configuration.ScopeDirectory;
RootNavigation = set.Tree;
}

public IDirectoryInfo ScopeDirectory { get; set; }

public INavigation RootNavigation { get; set; }

public string Id { get; } = Guid.NewGuid().ToString("N")[..8];

private DiagnosticsCollector Collector { get; }
Expand Down Expand Up @@ -130,28 +135,10 @@ public MarkdownFile[] YieldParents()
return [.. parents];
}

public string[] YieldParentGroups()
{
var parents = new List<string>();
if (GroupId is not null)
parents.Add(GroupId);
var parent = Parent;
do
{
if (parent is not null)
parents.Add(parent.Id);
parent = parent?.Parent;
} while (parent != null);

return [.. parents];
}

/// this get set by documentationset when validating redirects
/// because we need to minimally parse to see the anchors anchor validation is deferred.
public IReadOnlyDictionary<string, string?>? AnchorRemapping { get; set; }

public IDirectoryInfo ScopeDirectory { get; set; }

private void ValidateAnchorRemapping()
{
if (AnchorRemapping is null)
Expand Down Expand Up @@ -343,4 +330,5 @@ public string CreateHtml(MarkdownDocument document)
_ = document.Remove(h1);
return document.ToHtml(MarkdownParser.Pipeline);
}

}
66 changes: 40 additions & 26 deletions src/Elastic.Markdown/IO/Navigation/DocumentationGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
// 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 System.Text.RegularExpressions;
using Elastic.Markdown.Diagnostics;
using Elastic.Markdown.Extensions;
using Elastic.Markdown.Extensions.DetectionRules;
using Elastic.Markdown.IO.Configuration;

namespace Elastic.Markdown.IO.Navigation;
Expand All @@ -28,10 +24,25 @@ public record FileNavigation(int Order, int Depth, MarkdownFile File) : INavigat
public string Id { get; } = File.Id;
}

public class DocumentationGroup
public interface INavigation
{
string Id { get; }
IReadOnlyCollection<INavigationItem> NavigationItems { get; }
int Depth { get; }
string? IndexFileName { get; }
}

public interface INavigationScope
{
INavigation RootNavigation { get; }
}

public class DocumentationGroup : INavigation
{
public string Id { get; } = Guid.NewGuid().ToString("N")[..8];

public string NavigationRootId { get; }

public MarkdownFile? Index { get; set; }

private IReadOnlyCollection<MarkdownFile> FilesInOrder { get; }
Expand All @@ -40,18 +51,14 @@ public class DocumentationGroup

public IReadOnlyCollection<INavigationItem> NavigationItems { get; }

public required DocumentationGroup? Parent { get; init; }
public string? IndexFileName => Index?.FileName;

public int Depth { get; }

public bool InNav { get; }
public DocumentationGroup? Parent { get; }

public DocumentationGroup(
BuildContext context,
NavigationLookups lookups,
bool inNav,
ref int fileIndex)
: this(context, lookups, ref fileIndex, depth: 0, inNav)
public DocumentationGroup(BuildContext context, NavigationLookups lookups, ref int fileIndex)
: this(context, lookups, ref fileIndex, depth: 0, null, null)
{
}

Expand All @@ -60,15 +67,21 @@ internal DocumentationGroup(
NavigationLookups lookups,
ref int fileIndex,
int depth,
bool inNav,
MarkdownFile? index = null)
DocumentationGroup? topLevelGroup,
DocumentationGroup? parent,
MarkdownFile? index = null
)
{
Depth = depth;
Index = ProcessTocItems(context, index, lookups, depth, ref fileIndex, out var groups, out var files, out var navigationItems);
Parent = parent;
topLevelGroup ??= this;
if (parent?.Depth == 0)
topLevelGroup = this;
NavigationRootId = topLevelGroup.Id;
Index = ProcessTocItems(context, topLevelGroup, index, lookups, depth, ref fileIndex, out var groups, out var files, out var navigationItems);
if (Index is not null)
Index.GroupId = Id;

InNav = inNav;
GroupsInOrder = groups;
FilesInOrder = files;
NavigationItems = navigationItems;
Expand All @@ -79,6 +92,7 @@ internal DocumentationGroup(

private MarkdownFile? ProcessTocItems(
BuildContext context,
DocumentationGroup topLevelGroup,
MarkdownFile? configuredIndex,
NavigationLookups lookups,
int depth,
Expand Down Expand Up @@ -117,20 +131,20 @@ internal DocumentationGroup(
var navigationIndex = Interlocked.Increment(ref fileIndex);
md.NavigationIndex = navigationIndex;
md.ScopeDirectory = file.TableOfContentsScope.ScopeDirectory;
md.RootNavigation = topLevelGroup;

foreach (var extension in context.Configuration.EnabledExtensions)
extension.Visit(d, tocItem);


if (file.Children.Count > 0 && d is MarkdownFile virtualIndex)
{
if (file.Hidden)
context.EmitError(context.ConfigurationPath, $"The following file is hidden but has children: {file.Path}");
var group = new DocumentationGroup(
context, lookups with { TableOfContents = file.Children }, ref fileIndex, depth + 1, InNav, virtualIndex)
{
Parent = this
};
context, lookups with
{
TableOfContents = file.Children
}, ref fileIndex, depth + 1, topLevelGroup, this, virtualIndex);
groups.Add(group);
navigationItems.Add(new GroupNavigation(index, depth, group));
continue;
Expand Down Expand Up @@ -159,10 +173,10 @@ .. documentationFiles
];
}

var group = new DocumentationGroup(context, lookups with { TableOfContents = children }, ref fileIndex, depth + 1, folder.InNav)
var group = new DocumentationGroup(context, lookups with
{
Parent = this
};
TableOfContents = children
}, ref fileIndex, depth + 1, topLevelGroup, this);
groups.Add(group);
navigationItems.Add(new GroupNavigation(index, depth, group));
}
Expand All @@ -171,7 +185,7 @@ .. documentationFiles
foreach (var extension in lookups.EnabledExtensions)
{
if (extension.InjectsIntoNavigation(tocItem))
extension.CreateNavigationItem(this, tocItem, lookups, groups, navigationItems, depth, false, ref fileIndex, index);
extension.CreateNavigationItem(this, tocItem, lookups, groups, navigationItems, depth, ref fileIndex, index);
}
}
}
Expand Down
Loading
Loading