diff --git a/src/Elastic.Markdown/IO/MarkdownFile.cs b/src/Elastic.Markdown/IO/MarkdownFile.cs index 89ef23efb..c141126a9 100644 --- a/src/Elastic.Markdown/IO/MarkdownFile.cs +++ b/src/Elastic.Markdown/IO/MarkdownFile.cs @@ -70,7 +70,9 @@ public string? NavigationTitle public string FilePath { get; } public string FileName { get; } - public string Url => $"{UrlPathPrefix}/{RelativePath.Replace(".md", ".html")}"; + public string Url => Path.GetFileName(RelativePath) == "index.md" + ? $"{UrlPathPrefix}/{RelativePath.Remove(RelativePath.LastIndexOf("index.md", StringComparison.Ordinal), "index.md".Length)}" + : $"{UrlPathPrefix}/{RelativePath.Remove(RelativePath.LastIndexOf(".md", StringComparison.Ordinal), 3)}"; public int NavigationIndex { get; internal set; } = -1; diff --git a/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs b/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs index 0900fdcf4..c098ed70b 100644 --- a/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs +++ b/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs @@ -243,7 +243,11 @@ private static void UpdateLinkUrl(LinkInline link, string url, ParserContext con url = GetRootRelativePath(context, file); if (url.EndsWith(".md")) - url = Path.ChangeExtension(url, ".html"); + { + url = url.EndsWith("/index.md") + ? url.Remove(url.LastIndexOf("index.md", StringComparison.Ordinal), "index.md".Length) + : url.Remove(url.LastIndexOf(".md", StringComparison.Ordinal), ".md".Length); + } if (!string.IsNullOrWhiteSpace(url) && !string.IsNullOrWhiteSpace(urlPathPrefix)) url = $"{urlPathPrefix.TrimEnd('/')}{url}"; diff --git a/src/Elastic.Markdown/Slices/HtmlWriter.cs b/src/Elastic.Markdown/Slices/HtmlWriter.cs index 0616b769c..5332e8835 100644 --- a/src/Elastic.Markdown/Slices/HtmlWriter.cs +++ b/src/Elastic.Markdown/Slices/HtmlWriter.cs @@ -81,7 +81,25 @@ public async Task WriteAsync(IFileInfo outputFile, MarkdownFile markdown, Cancel outputFile.Directory.Create(); var rendered = await RenderLayout(markdown, ctx); - var path = Path.ChangeExtension(outputFile.FullName, ".html"); + string path; + if (outputFile.Name == "index.md") + { + path = Path.ChangeExtension(outputFile.FullName, ".html"); + } + else + { + var dir = outputFile.Directory is null + ? null + : Path.Combine(outputFile.Directory.FullName, Path.GetFileNameWithoutExtension(outputFile.Name)); + + if (dir is not null && !_writeFileSystem.Directory.Exists(dir)) + _writeFileSystem.Directory.CreateDirectory(dir); + + path = dir is null + ? Path.GetFileNameWithoutExtension(outputFile.Name) + ".html" + : Path.Combine(dir, "index.html"); + } + await _writeFileSystem.File.WriteAllTextAsync(path, rendered, ctx); } diff --git a/src/docs-builder/Http/DocumentationWebHost.cs b/src/docs-builder/Http/DocumentationWebHost.cs index ee5711d9e..8e1795b38 100644 --- a/src/docs-builder/Http/DocumentationWebHost.cs +++ b/src/docs-builder/Http/DocumentationWebHost.cs @@ -99,9 +99,18 @@ private void SetUpRoutes() private static async Task ServeDocumentationFile(ReloadableGeneratorState holder, string slug, Cancel ctx) { var generator = holder.Generator; - slug = slug.Replace(".html", ".md"); - if (!generator.DocumentationSet.FlatMappedFiles.TryGetValue(slug, out var documentationFile)) - return Results.NotFound(); + + // For now, the logic is backwards compatible. + // Hence, both http://localhost:5000/migration/versioning.html and http://localhost:5000/migration/versioning works, + // so it's easier to copy links from issues created during the bug bounty. + // However, we can remove this logic in the future and only support links without the .html extension. + var s = Path.GetExtension(slug) == string.Empty ? Path.Combine(slug, "index.md") : slug.Replace(".html", ".md"); + if (!generator.DocumentationSet.FlatMappedFiles.TryGetValue(s, out var documentationFile)) + { + s = Path.GetExtension(slug) == string.Empty ? slug + ".md" : s.Replace("/index.md", ".md"); + if (!generator.DocumentationSet.FlatMappedFiles.TryGetValue(s, out documentationFile)) + return Results.NotFound(); + } switch (documentationFile) { diff --git a/tests/Elastic.Markdown.Tests/Inline/AnchorLinkTests.cs b/tests/Elastic.Markdown.Tests/Inline/AnchorLinkTests.cs index a070dd9d1..2b6f9f236 100644 --- a/tests/Elastic.Markdown.Tests/Inline/AnchorLinkTests.cs +++ b/tests/Elastic.Markdown.Tests/Inline/AnchorLinkTests.cs @@ -76,7 +76,7 @@ [Sub Requirements](testing/req.md#sub-requirements) public void GeneratesHtml() => // language=html Html.Should().Contain( - """

Sub Requirements

""" + """

Sub Requirements

""" ); [Fact] @@ -94,7 +94,7 @@ [Sub Requirements](testing/req.md#new-reqs) public void GeneratesHtml() => // language=html Html.Should().Contain( - """

Sub Requirements

""" + """

Sub Requirements

""" ); [Fact] @@ -111,7 +111,7 @@ public class ExternalPageAnchorAutoTitleTests(ITestOutputHelper output) : Anchor public void GeneratesHtml() => // language=html Html.Should().Contain( - """

Special Requirements > Sub Requirements

""" + """

Special Requirements > Sub Requirements

""" ); [Fact] @@ -147,7 +147,7 @@ [Sub Requirements](testing/req.md#sub-requirements2) public void GeneratesHtml() => // language=html Html.Should().Contain( - """

Sub Requirements

""" + """

Sub Requirements

""" ); [Fact] @@ -166,7 +166,7 @@ [Heading inside dropdown](testing/req.md#heading-inside-dropdown) public void GeneratesHtml() => // language=html Html.Should().Contain( - """Heading inside dropdown""" + """Heading inside dropdown""" ); [Fact] public void HasError() => Collector.Diagnostics.Should().HaveCount(0); diff --git a/tests/Elastic.Markdown.Tests/Inline/DirectiveBlockLinkTests.cs b/tests/Elastic.Markdown.Tests/Inline/DirectiveBlockLinkTests.cs index 77f9e978a..2636cf368 100644 --- a/tests/Elastic.Markdown.Tests/Inline/DirectiveBlockLinkTests.cs +++ b/tests/Elastic.Markdown.Tests/Inline/DirectiveBlockLinkTests.cs @@ -67,7 +67,7 @@ [Sub Requirements](testing/req.md#hint_ref) public void GeneratesHtml() => // language=html Html.Should().Contain( - """

Sub Requirements

""" + """

Sub Requirements

""" ); [Fact] diff --git a/tests/Elastic.Markdown.Tests/Inline/InlineAnchorTests.cs b/tests/Elastic.Markdown.Tests/Inline/InlineAnchorTests.cs index 253b0bcf2..2c3d07103 100644 --- a/tests/Elastic.Markdown.Tests/Inline/InlineAnchorTests.cs +++ b/tests/Elastic.Markdown.Tests/Inline/InlineAnchorTests.cs @@ -203,7 +203,7 @@ [Sub Requirements](testing/req.md#custom-anchor) public void GeneratesHtml() => // language=html Html.Should().Contain( - """

Sub Requirements

""" + """

Sub Requirements

""" ); [Fact] diff --git a/tests/Elastic.Markdown.Tests/Inline/InlineLinkTests.cs b/tests/Elastic.Markdown.Tests/Inline/InlineLinkTests.cs index 1dd5d0723..8e2e3959e 100644 --- a/tests/Elastic.Markdown.Tests/Inline/InlineLinkTests.cs +++ b/tests/Elastic.Markdown.Tests/Inline/InlineLinkTests.cs @@ -58,7 +58,7 @@ public class LinkToPageTests(ITestOutputHelper output) : LinkTestBase(output, public void GeneratesHtml() => // language=html Html.Should().Contain( - """

Requirements

""" + """

Requirements

""" ); [Fact] @@ -81,7 +81,7 @@ public class InsertPageTitleTests(ITestOutputHelper output) : LinkTestBase(outpu public void GeneratesHtml() => // language=html Html.Should().Contain( - """

Special Requirements

""" + """

Special Requirements

""" ); [Fact] @@ -106,7 +106,7 @@ public class LinkReferenceTest(ITestOutputHelper output) : LinkTestBase(output, public void GeneratesHtml() => // language=html Html.Should().Contain( - """

test

""" + """

test

""" ); [Fact] @@ -132,6 +132,7 @@ public void GeneratesHtml() => // language=html Html.Should().Contain( // TODO: The link is not rendered correctly yet, will be fixed in a follow-up + """

test

""" ); @@ -225,10 +226,10 @@ public void GeneratesHtml() => Html.TrimEnd().Should().Be("""

Links:

""");