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
20 changes: 7 additions & 13 deletions src/Elastic.Markdown/Exporters/LlmMarkdownExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.IO.Compression;
using System.Text;
using Elastic.Documentation.Configuration;
using Elastic.Documentation.Configuration.Products;
using Elastic.Markdown.Helpers;
using Markdig.Syntax;

Expand Down Expand Up @@ -113,21 +114,11 @@ private string CreateLlmContentWithMetadata(MarkdownExportFileContext context, s
if (!string.IsNullOrEmpty(sourceFile.Url))
_ = metadata.AppendLine($"url: {context.BuildContext.CanonicalBaseUrl?.Scheme}://{context.BuildContext.CanonicalBaseUrl?.Host}{sourceFile.Url}");

var configProducts = context.BuildContext.ProductsConfiguration.Products.Select(p =>
{
if (context.BuildContext.ProductsConfiguration.Products.TryGetValue(p.Value.Id, out var product))
return product;
throw new ArgumentException($"Invalid product id: {p.Value.Id}");
});
var frontMatterProducts = sourceFile.YamlFrontMatter?.Products ?? [];
var allProducts = frontMatterProducts
.Union(configProducts)
.Distinct()
.ToList();
if (allProducts.Count > 0)
var pageProducts = GetPageProducts(sourceFile.YamlFrontMatter?.Products);
if (pageProducts.Count > 0)
{
_ = metadata.AppendLine("products:");
foreach (var item in allProducts.Select(p => p.DisplayName).Order())
foreach (var item in pageProducts.Select(p => p.DisplayName).Order())
_ = metadata.AppendLine($" - {item}");
}

Expand All @@ -138,6 +129,9 @@ private string CreateLlmContentWithMetadata(MarkdownExportFileContext context, s

return metadata.ToString();
}

private static List<Product> GetPageProducts(IReadOnlyCollection<Product>? frontMatterProducts) =>
frontMatterProducts?.ToList() ?? [];
}

public static class LlmMarkdownExporterExtensions
Expand Down
20 changes: 6 additions & 14 deletions src/Elastic.Markdown/HtmlWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Text.Json;
using Elastic.Documentation;
using Elastic.Documentation.Configuration.LegacyUrlMappings;
using Elastic.Documentation.Configuration.Products;
using Elastic.Documentation.Configuration.Versions;
using Elastic.Documentation.Site.FileProviders;
using Elastic.Documentation.Site.Navigation;
Expand Down Expand Up @@ -86,19 +87,7 @@ private async Task<RenderResult> RenderLayout(MarkdownFile markdown, MarkdownDoc
var siteName = DocumentationSet.Tree.Index.Title ?? "Elastic Documentation";
var legacyPages = LegacyUrlMapper.MapLegacyUrl(markdown.YamlFrontMatter?.MappedPages);

var configProducts = DocumentationSet.Context.ProductsConfiguration.Products.Select(p =>
{
if (DocumentationSet.Context.ProductsConfiguration.Products.TryGetValue(p.Value.Id, out var product))
return product;
throw new ArgumentException($"Invalid product id: {p.Value.Id}");
});

var frontMatterProducts = markdown.YamlFrontMatter?.Products ?? [];

var allProducts = frontMatterProducts
.Union(configProducts)
.Distinct()
.ToHashSet();
var pageProducts = GetPageProducts(markdown.YamlFrontMatter?.Products);

string? allVersionsUrl = null;

Expand Down Expand Up @@ -153,7 +142,7 @@ private async Task<RenderResult> RenderLayout(MarkdownFile markdown, MarkdownDoc
AllVersionsUrl = allVersionsUrl,
LegacyPages = legacyPages?.ToArray(),
VersionDropdownItems = VersionDropDownItemViewModel.FromLegacyPageMappings(legacyPages?.ToArray()),
Products = allProducts,
Products = pageProducts,
VersionsConfig = DocumentationSet.Context.VersionsConfiguration,
StructuredBreadcrumbsJson = structuredBreadcrumbsJsonString
});
Expand Down Expand Up @@ -229,6 +218,9 @@ public async Task<MarkdownDocument> WriteAsync(IDirectoryInfo outBaseDir, IFileI
return document;
}

private static HashSet<Product> GetPageProducts(IReadOnlyCollection<Product>? frontMatterProducts) =>
frontMatterProducts?.ToHashSet() ?? [];

}

public record RenderResult
Expand Down
1 change: 0 additions & 1 deletion src/infra/docs-lambda-index-publisher/lambda.DockerFile
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,3 @@ RUN arch=$TARGETARCH \
&& echo $TARGETOS-$arch > /tmp/rid

RUN dotnet publish src/infra/docs-lambda-index-publisher -r linux-x64 -c Release

87 changes: 87 additions & 0 deletions tests/authoring/FrontMatter/ProductsFrontMatter.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// 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

module ``AuthoringTests``.``frontmatter``.``products frontmatter``

open Swensen.Unquote
open Xunit
open authoring
open JetBrains.Annotations

let frontMatter ([<LanguageInjection("yaml")>]m: string) =
Setup.Document $"""---
{m}
---
# Test Page

This is a test page with products frontmatter.
"""

type ``products frontmatter in HTML`` () =
static let markdownWithProducts = frontMatter """
products:
- id: elasticsearch
- id: ecctl
"""

[<Fact>]
let ``includes products meta tags when products are specified`` () =
markdownWithProducts |> converts "index.md" |> containsHtml """
<meta class="elastic" name="product_name" content="Elasticsearch,Elastic Cloud Control ECCTL"/>
<meta name="DC.subject" content="Elasticsearch,Elastic Cloud Control ECCTL"/>
"""

[<Fact>]
let ``does not include products meta tags when no products are specified`` () =
let markdownWithoutProducts = Setup.Document """
# Test Page

This is a test page without products frontmatter.
"""
// When there are no products, no product-related meta tags should be rendered at all
let results = markdownWithoutProducts.Value
let defaultFile = results.MarkdownResults |> Seq.find (fun r -> r.File.RelativePath = "index.md")
let html = defaultFile.Html

// Verify that product meta tags are NOT present in the HTML
test <@ not (html.Contains("product_name")) @>
test <@ not (html.Contains("DC.subject")) @>

type ``products frontmatter in LLM Markdown`` () =
static let markdownWithProducts = frontMatter """
products:
- id: elasticsearch
- id: ecctl
"""

static let markdownWithoutProducts = Setup.Document """
# Test Page

This is a test page without products frontmatter.
"""

[<Fact>]
let ``includes products in frontmatter when products are specified`` () =
// Test that the products frontmatter is correctly processed by checking the file
let results = markdownWithProducts.Value
let defaultFile = results.MarkdownResults |> Seq.find (fun r -> r.File.RelativePath = "index.md")

// Test that the file has the correct products
test <@ defaultFile.File.YamlFrontMatter <> null @>
test <@ defaultFile.File.YamlFrontMatter.Products <> null @>

Check warning on line 72 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 72 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 72 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 72 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 72 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 72 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 72 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / integration

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 72 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / integration

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.
test <@ defaultFile.File.YamlFrontMatter.Products.Count = 2 @>

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Nullness warning: The types 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product>' and 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product> | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Nullness warning: The types 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product>' and 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product> | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Nullness warning: The types 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product>' and 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product> | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Nullness warning: The types 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product>' and 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product> | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Nullness warning: The types 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product>' and 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product> | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Nullness warning: The types 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product>' and 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product> | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / integration

Nullness warning: The types 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product>' and 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product> | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / integration

Nullness warning: The types 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product>' and 'System.Collections.Generic.IReadOnlyCollection<Elastic.Documentation.Configuration.Products.Product> | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / integration

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 73 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / integration

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

// Test that the products are correctly identified
let productIds = defaultFile.File.YamlFrontMatter.Products |> Seq.map (fun p -> p.Id) |> Set.ofSeq

Check warning on line 76 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 76 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 76 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.

Check warning on line 76 in tests/authoring/FrontMatter/ProductsFrontMatter.fs

View workflow job for this annotation

GitHub Actions / integration

Nullness warning: The types 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter' and 'Elastic.Markdown.Myst.FrontMatter.YamlFrontMatter | null' do not have compatible nullability.
test <@ productIds.Contains("elasticsearch") @>
test <@ productIds.Contains("ecctl") @>

[<Fact>]
let ``does not include products in frontmatter when no products are specified`` () =
// Test that pages without products frontmatter don't have products
let results = markdownWithoutProducts.Value
let defaultFile = results.MarkdownResults |> Seq.find (fun r -> r.File.RelativePath = "index.md")

// Test that the file has no products
test <@ defaultFile.File.YamlFrontMatter = null || defaultFile.File.YamlFrontMatter.Products = null || defaultFile.File.YamlFrontMatter.Products.Count = 0 @>
1 change: 1 addition & 0 deletions tests/authoring/authoring.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@
<Compile Include="Directives\IncludeBlocks.fs" />
<Compile Include="Linters\WhiteSpaceNormalizers.fs" />
<Compile Include="LlmMarkdown\LlmMarkdownOutput.fs" />
<Compile Include="FrontMatter\ProductsFrontMatter.fs" />
</ItemGroup>
</Project>
Loading