Skip to content

Commit 68342ce

Browse files
authored
Fix settings directive LLM markdown output (#2009)
1 parent 6688f0b commit 68342ce

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

src/Elastic.Markdown/Myst/Renderers/LlmMarkdown/LlmBlockRenderers.cs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
using Elastic.Markdown.Myst.Directives.Diagram;
1010
using Elastic.Markdown.Myst.Directives.Image;
1111
using Elastic.Markdown.Myst.Directives.Include;
12+
using Elastic.Markdown.Myst.Directives.Settings;
1213
using Markdig.Extensions.DefinitionLists;
1314
using Markdig.Extensions.Tables;
1415
using Markdig.Extensions.Yaml;
1516
using Markdig.Renderers;
1617
using Markdig.Syntax;
1718
using Markdig.Syntax.Inlines;
19+
using YamlDotNet.Core;
1820
using CodeBlock = Markdig.Syntax.CodeBlock;
1921

2022
namespace Elastic.Markdown.Myst.Renderers.LlmMarkdown;
@@ -388,6 +390,9 @@ protected override void Write(LlmMarkdownRenderer renderer, DirectiveBlock obj)
388390
case DiagramBlock diagramBlock:
389391
WriteDiagramBlock(renderer, diagramBlock);
390392
return;
393+
case SettingsBlock settingsBlock:
394+
WriteSettingsBlock(renderer, settingsBlock);
395+
return;
391396
}
392397

393398
// Ensure single empty line before directive
@@ -509,6 +514,99 @@ private void WriteIncludeBlock(LlmMarkdownRenderer renderer, IncludeBlock block)
509514
renderer.EnsureLine();
510515
}
511516

517+
private void WriteSettingsBlock(LlmMarkdownRenderer renderer, SettingsBlock block)
518+
{
519+
if (!block.Found || block.IncludePath is null)
520+
{
521+
var path = block.IncludePath ?? "(no path specified)";
522+
renderer.BuildContext.Collector.EmitError(
523+
block.IncludePath ?? string.Empty,
524+
$"Settings directive error: Could not resolve path '{path}'. Ensure the file exists and the path is correct.");
525+
return;
526+
}
527+
528+
var file = block.Build.ReadFileSystem.FileInfo.New(block.IncludePath);
529+
530+
// Check if file exists before attempting to read
531+
if (!file.Exists)
532+
{
533+
renderer.BuildContext.Collector.EmitError(
534+
block.IncludePath,
535+
$"Settings file not found: '{block.IncludePath}' does not exist. Check that the file path is correct and the file has been committed to the repository.");
536+
return;
537+
}
538+
539+
YamlSettings? settings;
540+
try
541+
{
542+
var yaml = file.FileSystem.File.ReadAllText(file.FullName);
543+
settings = YamlSerialization.Deserialize<YamlSettings>(yaml, block.Context.Build.ProductsConfiguration);
544+
}
545+
catch (FileNotFoundException e)
546+
{
547+
renderer.BuildContext.Collector.EmitError(
548+
block.IncludePath,
549+
$"Settings file not found: Unable to read '{block.IncludePath}'. The file may have been moved or deleted.",
550+
e);
551+
return;
552+
}
553+
catch (DirectoryNotFoundException e)
554+
{
555+
renderer.BuildContext.Collector.EmitError(
556+
block.IncludePath,
557+
$"Settings directory not found: The directory containing '{block.IncludePath}' does not exist. Check that the path is correct.",
558+
e);
559+
return;
560+
}
561+
catch (YamlException e)
562+
{
563+
renderer.BuildContext.Collector.EmitError(
564+
block.IncludePath,
565+
$"Invalid YAML in settings file: '{block.IncludePath}' contains invalid YAML syntax. Please check the file format matches the expected settings structure (groups, settings, etc.).",
566+
e.InnerException ?? e);
567+
return;
568+
}
569+
catch (Exception e)
570+
{
571+
renderer.BuildContext.Collector.EmitError(
572+
block.IncludePath,
573+
$"Failed to process settings file: Unable to parse '{block.IncludePath}'. Error: {e.Message}",
574+
e);
575+
return;
576+
}
577+
578+
renderer.EnsureBlockSpacing();
579+
580+
foreach (var group in settings.Groups)
581+
{
582+
renderer.WriteLine();
583+
renderer.Write("## ");
584+
renderer.WriteLine(group.Name ?? string.Empty);
585+
586+
foreach (var setting in group.Settings)
587+
{
588+
renderer.WriteLine();
589+
renderer.Write("#### ");
590+
renderer.WriteLine(setting.Name ?? string.Empty);
591+
592+
if (!string.IsNullOrEmpty(setting.Description))
593+
{
594+
var document = MarkdownParser.ParseMarkdownStringAsync(
595+
block.Build,
596+
block.Context,
597+
setting.Description,
598+
block.IncludeFrom,
599+
block.Context.YamlFrontMatter,
600+
MarkdownParser.Pipeline);
601+
_ = renderer.Render(document);
602+
renderer.EnsureBlockSpacing();
603+
}
604+
}
605+
}
606+
607+
renderer.EnsureLine();
608+
}
609+
512610
private static void WriteChildrenWithIndentation(LlmMarkdownRenderer renderer, Block container, string indent)
513611
{
514612
// Capture output and manually add indentation

tests/authoring/LlmMarkdown/LlmMarkdownOutput.fs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,3 +602,44 @@ sub:
602602
markdown |> convertsToNewLLM """
603603
## Hello, World!
604604
"""
605+
606+
type ``settings directive`` () =
607+
static let generator = Setup.Generate [
608+
Index """
609+
:::{settings} _settings/example-settings.yml
610+
:::
611+
"""
612+
File("_settings/example-settings.yml", """groups:
613+
- group: General settings
614+
settings:
615+
- setting: xpack.example.setting
616+
description: |
617+
This is a test setting with **bold** text and a [link](https://example.com).
618+
- setting: xpack.another.setting
619+
description: Another setting description.
620+
- group: Advanced settings
621+
settings:
622+
- setting: xpack.advanced.option
623+
description: An advanced option.
624+
""")
625+
]
626+
627+
[<Fact>]
628+
let ``renders settings as markdown headings`` () =
629+
generator |> convertsToNewLLM """
630+
## General settings
631+
632+
#### xpack.example.setting
633+
634+
This is a test setting with **bold** text and a [link](https://example.com).
635+
636+
#### xpack.another.setting
637+
638+
Another setting description.
639+
640+
## Advanced settings
641+
642+
#### xpack.advanced.option
643+
644+
An advanced option.
645+
"""

0 commit comments

Comments
 (0)