Skip to content

Commit 73de9d8

Browse files
committed
Add absolute URLs generation
1 parent f5abcde commit 73de9d8

File tree

2 files changed

+53
-24
lines changed

2 files changed

+53
-24
lines changed

src/tooling/docs-assembler/Cli/RepositoryCommands.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ private static async Task EnhanceLlmsTxtFile(AssembleContext context, GlobalNavi
293293
return; // No llms.txt file to enhance
294294

295295
var existingContent = await File.ReadAllTextAsync(llmsTxtPath, ctx);
296-
var navigationSections = enhancer.GenerateNavigationSections(navigation);
296+
var navigationSections = await enhancer.GenerateNavigationSectionsAsync(navigation);
297297

298298
// Append the navigation sections to the existing boilerplate
299299
var enhancedContent = existingContent + Environment.NewLine + navigationSections;

src/tooling/docs-assembler/Navigation/LlmsNavigationEnhancer.cs

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
// See the LICENSE file in the project root for more information
44

55
using System.Text;
6+
using Documentation.Assembler;
67
using Elastic.Documentation.Site.Navigation;
8+
using Elastic.Markdown;
79
using Elastic.Markdown.IO;
810
using Elastic.Markdown.IO.Navigation;
911

@@ -14,7 +16,7 @@ namespace Documentation.Assembler.Navigation;
1416
/// </summary>
1517
public class LlmsNavigationEnhancer
1618
{
17-
public string GenerateNavigationSections(GlobalNavigation navigation)
19+
public async Task<string> GenerateNavigationSectionsAsync(GlobalNavigation navigation)
1820
{
1921
var content = new StringBuilder();
2022

@@ -39,8 +41,8 @@ public string GenerateNavigationSections(GlobalNavigation navigation)
3941
foreach (var child in firstLevelChildren)
4042
{
4143
var title = child.NavigationTitle;
42-
var url = ConvertToMarkdownUrl(child.Url);
43-
var description = GetDescription(child);
44+
var url = ConvertToAbsoluteMarkdownUrl(child.Url);
45+
var description = await GetDescriptionAsync(child);
4446

4547
_ = !string.IsNullOrEmpty(description)
4648
? content.AppendLine($"* [{title}]({url}): {description}")
@@ -87,35 +89,62 @@ private static List<INavigationItem> GetFirstLevelChildren(DocumentationGroup gr
8789
return children;
8890
}
8991

90-
private static string ConvertToMarkdownUrl(string url)
92+
private static string ConvertToAbsoluteMarkdownUrl(string url)
9193
{
9294
// Convert HTML URLs to .md URLs for LLM consumption
93-
// e.g., "/docs/solutions/search/" -> "/solutions/search.md"
95+
// e.g., "/docs/solutions/search/" -> "https://www.elastic.co/docs/solutions/search.md"
9496
var cleanUrl = url.TrimStart('/');
9597

96-
// Remove "docs/" prefix if present
97-
if (cleanUrl.StartsWith("docs/"))
98-
cleanUrl = cleanUrl.Substring(5);
98+
// Remove "docs/" prefix if present for the markdown filename
99+
var markdownPath = cleanUrl;
100+
if (markdownPath.StartsWith("docs/"))
101+
markdownPath = markdownPath.Substring(5);
99102

100103
// Convert directory URLs to .md files
101-
if (cleanUrl.EndsWith('/'))
102-
cleanUrl = cleanUrl.TrimEnd('/') + ".md";
103-
else if (!cleanUrl.EndsWith(".md"))
104-
cleanUrl += ".md";
105-
106-
return "/" + cleanUrl;
104+
if (markdownPath.EndsWith('/'))
105+
markdownPath = markdownPath.TrimEnd('/') + ".md";
106+
else if (!markdownPath.EndsWith(".md"))
107+
markdownPath += ".md";
108+
109+
// Make absolute URL using the canonical base URL (always https://www.elastic.co for production)
110+
var baseUrl = "https://www.elastic.co";
111+
return $"{baseUrl}/docs/{markdownPath}";
107112
}
108113

109-
private static string? GetDescription(INavigationItem navigationItem) => navigationItem switch
114+
private static async Task<string?> GetDescriptionAsync(INavigationItem navigationItem)
110115
{
111-
// For file navigation items, extract from frontmatter
112-
FileNavigationItem fileItem when fileItem.Model is MarkdownFile markdownFile
113-
=> markdownFile.YamlFrontMatter?.Description,
116+
var descriptionGenerator = new DescriptionGenerator();
117+
118+
return navigationItem switch
119+
{
120+
// For file navigation items, extract from frontmatter or generate
121+
FileNavigationItem fileItem when fileItem.Model is MarkdownFile markdownFile =>
122+
await GetDescriptionFromMarkdownFileAsync(markdownFile, descriptionGenerator),
114123

115-
// For documentation groups, try to get from index file
116-
DocumentationGroup group when group.Index is MarkdownFile indexFile
117-
=> indexFile.YamlFrontMatter?.Description,
124+
// For documentation groups, try to get from index file
125+
DocumentationGroup group when group.Index is MarkdownFile indexFile =>
126+
await GetDescriptionFromMarkdownFileAsync(indexFile, descriptionGenerator),
118127

119-
_ => null
120-
};
128+
_ => null
129+
};
130+
}
131+
132+
private static async Task<string?> GetDescriptionFromMarkdownFileAsync(MarkdownFile markdownFile, DescriptionGenerator descriptionGenerator)
133+
{
134+
// First try frontmatter description
135+
if (!string.IsNullOrEmpty(markdownFile.YamlFrontMatter?.Description))
136+
return markdownFile.YamlFrontMatter.Description;
137+
138+
// Fallback to generating description from content
139+
try
140+
{
141+
var document = await markdownFile.MinimalParseAsync(default);
142+
return descriptionGenerator.GenerateDescription(document);
143+
}
144+
catch
145+
{
146+
// If parsing fails, return null (no description)
147+
return null;
148+
}
149+
}
121150
}

0 commit comments

Comments
 (0)