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
7 changes: 5 additions & 2 deletions src/Elastic.Markdown/DocumentationGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public interface IDocumentationFileOutputProvider
public class DocumentationGenerator
{
private readonly IDocumentationFileOutputProvider? _documentationFileOutputProvider;
private readonly IConversionCollector? _conversionCollector;
private readonly ILogger _logger;
private readonly IFileSystem _writeFileSystem;
private readonly IDocumentationFileExporter _documentationFileExporter;
Expand All @@ -46,6 +47,7 @@ public DocumentationGenerator(
)
{
_documentationFileOutputProvider = documentationFileOutputProvider;
_conversionCollector = conversionCollector;
_writeFileSystem = docSet.Build.WriteFileSystem;
_logger = logger.CreateLogger(nameof(DocumentationGenerator));

Expand All @@ -55,7 +57,8 @@ public DocumentationGenerator(
HtmlWriter = new HtmlWriter(DocumentationSet, _writeFileSystem, new DescriptionGenerator());
_documentationFileExporter =
documentationExporter
?? new DocumentationFileExporter(docSet.Build.ReadFileSystem, _writeFileSystem, HtmlWriter, conversionCollector);
?? docSet.Build.Configuration.EnabledExtensions.FirstOrDefault(e => e.FileExporter != null)?.FileExporter
?? new DocumentationFileExporter(docSet.Build.ReadFileSystem, _writeFileSystem);

_logger.LogInformation("Created documentation set for: {DocumentationSetName}", DocumentationSet.Name);
_logger.LogInformation("Source directory: {SourcePath} Exists: {SourcePathExists}", docSet.SourceDirectory, docSet.SourceDirectory.Exists);
Expand Down Expand Up @@ -205,7 +208,7 @@ private async Task ProcessFile(HashSet<string> offendingFiles, DocumentationFile
//TODO send file to OutputFile() so we can validate its scope is defined in navigation.yml
var outputFile = OutputFile(file.RelativePath);
if (outputFile is not null)
await _documentationFileExporter.ProcessFile(file, outputFile, token);
await _documentationFileExporter.ProcessFile(Context, file, outputFile, HtmlWriter, _conversionCollector, token);
}

private IFileInfo? OutputFile(string relativePath)
Expand Down
18 changes: 12 additions & 6 deletions src/Elastic.Markdown/Exporters/DocumentationFileExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,19 @@ public interface IDocumentationFileExporter
/// Used in documentation state to ensure we break the build cache if a different exporter is chosen
string Name { get; }

Task ProcessFile(DocumentationFile file, IFileInfo outputFile, Cancel token);
Task ProcessFile(BuildContext context, DocumentationFile file, IFileInfo outputFile, HtmlWriter htmlWriter, IConversionCollector? conversionCollector,
Cancel token);

Task CopyEmbeddedResource(IFileInfo outputFile, Stream resourceStream, Cancel ctx);
}

public abstract class DocumentationFileExporterBase(IFileSystem readFileSystem, IFileSystem writeFileSystem) : IDocumentationFileExporter
{
public abstract string Name { get; }
public abstract Task ProcessFile(DocumentationFile file, IFileInfo outputFile, Cancel token);

public abstract Task ProcessFile(BuildContext context, DocumentationFile file, IFileInfo outputFile, HtmlWriter htmlWriter,
IConversionCollector? conversionCollector,
Cancel token);

protected async Task CopyFileFsAware(DocumentationFile file, IFileInfo outputFile, Cancel ctx)
{
Expand All @@ -47,14 +51,16 @@ public async Task CopyEmbeddedResource(IFileInfo outputFile, Stream resourceStre

public class DocumentationFileExporter(
IFileSystem readFileSystem,
IFileSystem writeFileSystem,
HtmlWriter htmlWriter,
IConversionCollector? conversionCollector
IFileSystem writeFileSystem
) : DocumentationFileExporterBase(readFileSystem, writeFileSystem)
{
public override string Name { get; } = nameof(DocumentationFileExporter);

public override async Task ProcessFile(DocumentationFile file, IFileInfo outputFile, Cancel token)
public override async Task ProcessFile(BuildContext context, DocumentationFile file,
IFileInfo outputFile,
HtmlWriter htmlWriter,
IConversionCollector? conversionCollector,
Cancel token)
{
if (file is MarkdownFile markdown)
await htmlWriter.WriteAsync(outputFile, markdown, conversionCollector, token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@

using System.IO.Abstractions;
using Elastic.Markdown.IO;
using Elastic.Markdown.Slices;

namespace Elastic.Markdown.Exporters;

public class NoopDocumentationFileExporter : IDocumentationFileExporter
{
public string Name { get; } = nameof(NoopDocumentationFileExporter);
public Task ProcessFile(DocumentationFile file, IFileInfo outputFile, Cancel token) => Task.CompletedTask;

public Task ProcessFile(BuildContext context, DocumentationFile file, IFileInfo outputFile, HtmlWriter htmlWriter,
IConversionCollector? conversionCollector, Cancel token) =>
Task.CompletedTask;

public Task CopyEmbeddedResource(IFileInfo outputFile, Stream resourceStream, Cancel ctx) => Task.CompletedTask;
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public record DetectionRule
public required string Type { get; init; }
public required string? Language { get; init; }
public required string[]? Indices { get; init; }
public required string RunsEvery { get; init; }
public required string? RunsEvery { get; init; }
public required string? IndicesFromDateMath { get; init; }
public required string MaximumAlertsPerExecution { get; init; }
public required string[]? References { get; init; }
Expand Down Expand Up @@ -108,7 +108,7 @@ public static DetectionRule From(IFileInfo source)
Query = TryGetString(rule, "query"),
Note = TryGetString(rule, "note"),
Name = rule.GetString("name"),
RunsEvery = "?",
RunsEvery = TryGetString(rule, "interval"),
MaximumAlertsPerExecution = "?",
Version = "?",
Threats = threats
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public record DetectionRuleFile : MarkdownFile
{
public DetectionRule? Rule { get; set; }

public override string LinkReferenceRelativePath { get; }

public IFileInfo RuleSourceMarkdownPath { get; }

public DetectionRuleFile(
IFileInfo sourceFile,
IDirectoryInfo rootPath,
Expand All @@ -21,6 +25,25 @@ public DetectionRuleFile(
DocumentationSet set
) : base(sourceFile, rootPath, parser, build, set)
{
RuleSourceMarkdownPath = SourcePath(sourceFile, build);
LinkReferenceRelativePath = Path.GetRelativePath(build.DocumentationSourceDirectory.FullName, RuleSourceMarkdownPath.FullName);
}

private static IFileInfo SourcePath(IFileInfo rulePath, BuildContext build)
{
var relative = Path.GetRelativePath(build.DocumentationCheckoutDirectory!.FullName, rulePath.FullName);
var newPath = Path.Combine(build.DocumentationSourceDirectory.FullName, relative);
var md = Path.ChangeExtension(newPath, ".md");
return rulePath.FileSystem.FileInfo.New(md);
}

public static IFileInfo OutputPath(IFileInfo rulePath, BuildContext build)
{
var relative = Path.GetRelativePath(build.DocumentationOutputDirectory.FullName, rulePath.FullName);
if (relative.StartsWith("../"))
relative = relative[3..];
var newPath = Path.Combine(build.DocumentationOutputDirectory.FullName, relative);
return rulePath.FileSystem.FileInfo.New(newPath);
}

protected override string RelativePathUrl => RelativePath.AsSpan().TrimStart("../").ToString();
Expand All @@ -29,14 +52,14 @@ protected override Task<MarkdownDocument> GetMinimalParseDocumentAsync(Cancel ct
{
Title = Rule?.Name;
var markdown = GetMarkdown();
var document = MarkdownParser.MinimalParseStringAsync(markdown, SourceFile, null);
var document = MarkdownParser.MinimalParseStringAsync(markdown, RuleSourceMarkdownPath, null);
return Task.FromResult(document);
}

protected override Task<MarkdownDocument> GetParseDocumentAsync(Cancel ctx)
{
var markdown = GetMarkdown();
var document = MarkdownParser.ParseStringAsync(markdown, SourceFile, null);
var document = MarkdownParser.ParseStringAsync(markdown, RuleSourceMarkdownPath, null);
return Task.FromResult(document);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information

using System.IO.Abstractions;
using Elastic.Markdown.Exporters;
using Elastic.Markdown.Helpers;
using Elastic.Markdown.IO;
using Elastic.Markdown.IO.Configuration;
Expand All @@ -16,6 +17,8 @@ public class DetectionRulesDocsBuilderExtension(BuildContext build) : IDocsBuild

public bool InjectsIntoNavigation(ITocItem tocItem) => false;

public IDocumentationFileExporter? FileExporter { get; } = new RuleDocumentationFileExporter(build.ReadFileSystem, build.WriteFileSystem);

public void CreateNavigationItem(
DocumentationGroup? parent,
ITocItem tocItem,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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 Elastic.Markdown.Exporters;
using Elastic.Markdown.IO;
using Elastic.Markdown.Slices;

namespace Elastic.Markdown.Extensions.DetectionRules;

public class RuleDocumentationFileExporter(IFileSystem readFileSystem, IFileSystem writeFileSystem)
: DocumentationFileExporterBase(readFileSystem, writeFileSystem)
{
public override string Name { get; } = nameof(RuleDocumentationFileExporter);

public override async Task ProcessFile(BuildContext context, DocumentationFile file, IFileInfo outputFile, HtmlWriter htmlWriter,
IConversionCollector? conversionCollector, Cancel token)
{
if (file is DetectionRuleFile df)
await htmlWriter.WriteAsync(DetectionRuleFile.OutputPath(outputFile, context), df, conversionCollector, token);
else if (file is MarkdownFile markdown)
await htmlWriter.WriteAsync(outputFile, markdown, conversionCollector, token);
else
{
if (outputFile.Directory is { Exists: false })
outputFile.Directory.Create();
await CopyFileFsAware(file, outputFile, token);
}
}
}
3 changes: 3 additions & 0 deletions src/Elastic.Markdown/Extensions/IDocsBuilderExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information

using System.IO.Abstractions;
using Elastic.Markdown.Exporters;
using Elastic.Markdown.IO;
using Elastic.Markdown.IO.Configuration;
using Elastic.Markdown.IO.Navigation;
Expand All @@ -11,6 +12,8 @@ namespace Elastic.Markdown.Extensions;

public interface IDocsBuilderExtension
{
IDocumentationFileExporter? FileExporter { get; }

/// Inject items into the current navigation
void CreateNavigationItem(
DocumentationGroup? parent,
Expand Down
3 changes: 3 additions & 0 deletions src/Elastic.Markdown/IO/DocumentationFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public abstract record DocumentationFile(IFileInfo SourceFile, IDirectoryInfo Ro
public string RelativePath { get; } = Path.GetRelativePath(RootPath.FullName, SourceFile.FullName);
public string RelativeFolder { get; } = Path.GetRelativePath(RootPath.FullName, SourceFile.Directory!.FullName);

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

}

public record ImageFile(IFileInfo SourceFile, IDirectoryInfo RootPath, string MimeType = "image/png")
Expand Down
6 changes: 3 additions & 3 deletions src/Elastic.Markdown/IO/State/LinkReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ public static LinkReference Create(DocumentationSet set)
var redirects = set.Configuration.Redirects;
var crossLinks = set.Build.Collector.CrossLinks.ToHashSet().ToArray();
var links = set.MarkdownFiles.Values
.Select(m => (m.RelativePath, File: m))
.Select(m => (m.LinkReferenceRelativePath, File: m))
.ToDictionary(k => RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? k.RelativePath.Replace('\\', '/')
: k.RelativePath, v =>
? k.LinkReferenceRelativePath.Replace('\\', '/')
: k.LinkReferenceRelativePath, v =>
{
var anchors = v.File.Anchors.Count == 0 ? null : v.File.Anchors.ToArray();
return new LinkMetadata { Anchors = anchors, Hidden = v.File.Hidden };
Expand Down
Loading