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 @@ -57,7 +57,7 @@ Project is not null
&& Project.Equals("Elastic documentation", StringComparison.OrdinalIgnoreCase);

public ConfigurationFile(BuildContext context)
: base(context.ConfigurationPath, context.DocumentationSourceDirectory)
: base(context.ConfigurationPath, context.DocumentationSourceDirectory, context.Git.RepositoryName)
{
_context = context;
ScopeDirectory = context.ConfigurationPath.Directory!;
Expand Down
32 changes: 21 additions & 11 deletions src/Elastic.Markdown/IO/DocumentationFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,37 @@

namespace Elastic.Markdown.IO;

public abstract record DocumentationFile(IFileInfo SourceFile, IDirectoryInfo RootPath)
public abstract record DocumentationFile
{
public string RelativePath { get; } = Path.GetRelativePath(RootPath.FullName, SourceFile.FullName);
public string RelativeFolder { get; } = Path.GetRelativePath(RootPath.FullName, SourceFile.Directory!.FullName);
protected DocumentationFile(IFileInfo sourceFile, IDirectoryInfo rootPath, string repository)
{
SourceFile = sourceFile;
RelativePath = Path.GetRelativePath(rootPath.FullName, SourceFile.FullName);
RelativeFolder = Path.GetRelativePath(rootPath.FullName, SourceFile.Directory!.FullName);
CrossLink = $"{repository}://{RelativePath.Replace('\\', '/')}";
}

public string RelativePath { get; }
public string RelativeFolder { get; }
public string CrossLink { get; }

/// Allows documentation files of non markdown origins to advertise as their markdown equivalent in links.json
public virtual string LinkReferenceRelativePath => RelativePath;

public IFileInfo SourceFile { get; }
}

public record ImageFile(IFileInfo SourceFile, IDirectoryInfo RootPath, string MimeType = "image/png")
: DocumentationFile(SourceFile, RootPath);
public record ImageFile(IFileInfo SourceFile, IDirectoryInfo RootPath, string Repository, string MimeType = "image/png")
: DocumentationFile(SourceFile, RootPath, Repository);

public record StaticFile(IFileInfo SourceFile, IDirectoryInfo RootPath)
: DocumentationFile(SourceFile, RootPath);
public record StaticFile(IFileInfo SourceFile, IDirectoryInfo RootPath, string Repository)
: DocumentationFile(SourceFile, RootPath, Repository);

public record ExcludedFile(IFileInfo SourceFile, IDirectoryInfo RootPath)
: DocumentationFile(SourceFile, RootPath);
public record ExcludedFile(IFileInfo SourceFile, IDirectoryInfo RootPath, string Repository)
: DocumentationFile(SourceFile, RootPath, Repository);

public record SnippetFile(IFileInfo SourceFile, IDirectoryInfo RootPath)
: DocumentationFile(SourceFile, RootPath)
public record SnippetFile(IFileInfo SourceFile, IDirectoryInfo RootPath, string Repository)
: DocumentationFile(SourceFile, RootPath, Repository)
{
private SnippetAnchors? Anchors { get; set; }
private bool _parsed;
Expand Down
83 changes: 73 additions & 10 deletions src/Elastic.Markdown/IO/DocumentationSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,46 @@ public interface INavigationLookups

public interface IPositionalNavigation
{
FrozenDictionary<string, INavigationItem> MarkdownNavigationLookup { get; }

MarkdownFile? GetPrevious(MarkdownFile current);
MarkdownFile? GetNext(MarkdownFile current);

INavigationItem[] GetParents(INavigationItem current)
{
var parents = new List<INavigationItem>();
var parent = current.Parent;
do
{
if (parent is null)
continue;
parents.Add(parent);
parent = parent.Parent;
} while (parent != null);

return [.. parents];
}
MarkdownFile[] GetParentMarkdownFiles(INavigationItem current)
{
var parents = new List<MarkdownFile>();
var navigationParents = GetParents(current);
foreach (var parent in navigationParents)
{
if (parent is FileNavigationItem f)
parents.Add(f.File);
if (parent is GroupNavigationItem { Group.Index: not null } g)
parents.Add(g.Group.Index);
if (parent is DocumentationGroup { Index: not null } dg)
parents.Add(dg.Index);
}
return [.. parents];
}
MarkdownFile[] GetParentMarkdownFiles(MarkdownFile file)
{
if (MarkdownNavigationLookup.TryGetValue(file.CrossLink, out var navigationItem))
return GetParentMarkdownFiles(navigationItem);
return [];
}
}

public record NavigationLookups : INavigationLookups
Expand Down Expand Up @@ -71,6 +109,8 @@ public class DocumentationSet : INavigationLookups, IPositionalNavigation

IReadOnlyCollection<IDocsBuilderExtension> INavigationLookups.EnabledExtensions => Configuration.EnabledExtensions;

public FrozenDictionary<string, INavigationItem> MarkdownNavigationLookup { get; }

// FrozenDictionary<Uri, TableOfContentsReference>? indexedTableOfContents = null
public DocumentationSet(
BuildContext build,
Expand Down Expand Up @@ -137,9 +177,32 @@ public DocumentationSet(

MarkdownFiles = markdownFiles.Where(f => f.NavigationIndex > -1).ToDictionary(i => i.NavigationIndex, i => i).ToFrozenDictionary();

MarkdownNavigationLookup = Tree.NavigationItems
.SelectMany(Pairs)
.ToDictionary(kv => kv.Item1, kv => kv.Item2)
.ToFrozenDictionary();

ValidateRedirectsExists();
}

public static (string, INavigationItem)[] Pairs(INavigationItem item)
{
if (item is FileNavigationItem f)
return [(f.File.CrossLink, item)];
if (item is GroupNavigationItem g)
{
var index = new List<(string, INavigationItem)>();
if (g.Group.Index is not null)
index.Add((g.Group.Index.CrossLink, g));

return index.Concat(g.Group.NavigationItems.SelectMany(Pairs).ToArray())
.DistinctBy(kv => kv.Item1)
.ToArray();
}

return [];
}

private DocumentationFile[] ScanDocumentationFiles(BuildContext build, IDirectoryInfo sourceDirectory) =>
[.. build.ReadFileSystem.Directory
.EnumerateFiles(sourceDirectory.FullName, "*.*", SearchOption.AllDirectories)
Expand All @@ -150,11 +213,11 @@ [.. build.ReadFileSystem.Directory
.Where(f => !Path.GetRelativePath(sourceDirectory.FullName, f.FullName).StartsWith('.'))
.Select<IFileInfo, DocumentationFile>(file => file.Extension switch
{
".jpg" => new ImageFile(file, SourceDirectory, "image/jpeg"),
".jpeg" => new ImageFile(file, SourceDirectory, "image/jpeg"),
".gif" => new ImageFile(file, SourceDirectory, "image/gif"),
".svg" => new ImageFile(file, SourceDirectory, "image/svg+xml"),
".png" => new ImageFile(file, SourceDirectory),
".jpg" => new ImageFile(file, SourceDirectory, build.Git.RepositoryName, "image/jpeg"),
".jpeg" => new ImageFile(file, SourceDirectory, build.Git.RepositoryName, "image/jpeg"),
".gif" => new ImageFile(file, SourceDirectory, build.Git.RepositoryName, "image/gif"),
".svg" => new ImageFile(file, SourceDirectory, build.Git.RepositoryName, "image/svg+xml"),
".png" => new ImageFile(file, SourceDirectory, build.Git.RepositoryName),
".md" => CreateMarkDownFile(file, build),
_ => DefaultFileHandling(file, sourceDirectory)
})];
Expand All @@ -167,7 +230,7 @@ private DocumentationFile DefaultFileHandling(IFileInfo file, IDirectoryInfo sou
if (documentationFile is not null)
return documentationFile;
}
return new ExcludedFile(file, sourceDirectory);
return new ExcludedFile(file, sourceDirectory, Build.Git.RepositoryName);
}

private void ValidateRedirectsExists()
Expand Down Expand Up @@ -265,15 +328,15 @@ private DocumentationFile CreateMarkDownFile(IFileInfo file, BuildContext contex
{
var relativePath = Path.GetRelativePath(SourceDirectory.FullName, file.FullName);
if (Configuration.Exclude.Any(g => g.IsMatch(relativePath)))
return new ExcludedFile(file, SourceDirectory);
return new ExcludedFile(file, SourceDirectory, context.Git.RepositoryName);

if (relativePath.Contains("_snippets"))
return new SnippetFile(file, SourceDirectory);
return new SnippetFile(file, SourceDirectory, context.Git.RepositoryName);

// we ignore files in folders that start with an underscore
var folder = Path.GetDirectoryName(relativePath);
if (folder is not null && (folder.Contains($"{Path.DirectorySeparatorChar}_", StringComparison.Ordinal) || folder.StartsWith('_')))
return new ExcludedFile(file, SourceDirectory);
return new ExcludedFile(file, SourceDirectory, context.Git.RepositoryName);

if (Configuration.Files.Contains(relativePath))
return ExtensionOrDefaultMarkdown();
Expand All @@ -282,7 +345,7 @@ private DocumentationFile CreateMarkDownFile(IFileInfo file, BuildContext contex
return ExtensionOrDefaultMarkdown();

context.EmitError(Configuration.SourceFile, $"Not linked in toc: {relativePath}");
return new ExcludedFile(file, SourceDirectory);
return new ExcludedFile(file, SourceDirectory, context.Git.RepositoryName);

MarkdownFile ExtensionOrDefaultMarkdown()
{
Expand Down
32 changes: 4 additions & 28 deletions src/Elastic.Markdown/IO/MarkdownFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public MarkdownFile(
BuildContext build,
DocumentationSet set
)
: base(sourceFile, rootPath)
: base(sourceFile, rootPath, build.Git.RepositoryName)
{
FileName = sourceFile.Name;
FilePath = sourceFile.FullName;
Expand All @@ -52,26 +52,21 @@ DocumentationSet set
//may be updated by DocumentationGroup.ProcessTocItems
//todo refactor mutability of MarkdownFile as a whole
ScopeDirectory = build.Configuration.ScopeDirectory;

NavigationRoot = set.Tree;
NavigationSource = set.Source;
}

public IDirectoryInfo ScopeDirectory { get; set; }

public INavigation NavigationRoot { get; set; }
public INavigationGroup NavigationRoot { get; set; }

public Uri NavigationSource { get; set; }

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

private DiagnosticsCollector Collector { get; }

public DocumentationGroup? Parent
{
get => FileName == "index.md" ? _parent?.Parent : _parent;
set => _parent = value;
}

public bool Hidden { get; internal set; }
public string? UrlPathPrefix { get; }
protected MarkdownParser MarkdownParser { get; }
Expand Down Expand Up @@ -135,8 +130,7 @@ public string Url
_url = DefaultUrlPath;
return _url;
}
var path = RelativePath;
var crossLink = new Uri($"{_set.Build.Git.RepositoryName}://{path}");
var crossLink = new Uri(CrossLink);
var uri = _set.LinkResolver.UriResolver.Resolve(crossLink, DefaultUrlPathSuffix);
_url = uri.AbsolutePath;
return _url;
Expand All @@ -146,26 +140,9 @@ public string Url

public int NavigationIndex { get; set; } = -1;

public string? GroupId { get; set; }

private bool _instructionsParsed;
private DocumentationGroup? _parent;
private string? _title;

public MarkdownFile[] YieldParents()
{
var parents = new List<MarkdownFile>();
var parent = Parent;
do
{
if (parent is { Index: not null } && parent.Index != this)
parents.Add(parent.Index);
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; }
Expand Down Expand Up @@ -367,5 +344,4 @@ public string CreateHtml(MarkdownDocument document)
_ = document.Remove(h1);
return document.ToHtml(MarkdownParser.Pipeline);
}

}
Loading
Loading