diff --git a/src/Elastic.Markdown/Diagnostics/DiagnosticsChannel.cs b/src/Elastic.Markdown/Diagnostics/DiagnosticsChannel.cs index b58d5786c..8d9b3e46a 100644 --- a/src/Elastic.Markdown/Diagnostics/DiagnosticsChannel.cs +++ b/src/Elastic.Markdown/Diagnostics/DiagnosticsChannel.cs @@ -141,13 +141,16 @@ public virtual async Task StopAsync(CancellationToken cancellationToken) } - public void EmitError(string file, string message) + public void EmitError(string file, string message, Exception? e = null) { var d = new Diagnostic { Severity = Severity.Error, File = file, - Message = message, + Message = message + + (e != null ? Environment.NewLine + e : string.Empty) + + (e?.InnerException != null ? Environment.NewLine + e.InnerException : string.Empty), + }; Channel.Write(d); } diff --git a/src/Elastic.Markdown/IO/ConfigurationFile.cs b/src/Elastic.Markdown/IO/ConfigurationFile.cs index b819df015..11b8e6c47 100644 --- a/src/Elastic.Markdown/IO/ConfigurationFile.cs +++ b/src/Elastic.Markdown/IO/ConfigurationFile.cs @@ -23,11 +23,7 @@ public record ConfigurationFile : DocumentationFile public HashSet Files { get; } = new(StringComparer.OrdinalIgnoreCase); public HashSet ImplicitFolders { get; } = new(StringComparer.OrdinalIgnoreCase); public Glob[] Globs { get; } = []; - public HashSet ExternalLinkHosts { get; } = new(StringComparer.OrdinalIgnoreCase) - { - "elastic.co", - "github.com", - }; + public HashSet ExternalLinkHosts { get; } = new(StringComparer.OrdinalIgnoreCase) { "elastic.co", "github.com", }; private readonly Dictionary _substitutions = new(StringComparer.OrdinalIgnoreCase); public IReadOnlyDictionary Substitutions => _substitutions; @@ -57,41 +53,49 @@ public ConfigurationFile(IFileInfo sourceFile, IDirectoryInfo rootPath, BuildCon return; } - // Examine the stream - var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; - - foreach (var entry in mapping.Children) + try { - var key = ((YamlScalarNode)entry.Key).Value; - switch (key) - { - case "project": - Project = ReadString(entry); - break; - case "exclude": - Exclude = ReadStringArray(entry) - .Select(Glob.Parse) - .ToArray(); - break; - case "subs": - _substitutions = ReadDictionary(entry); - break; - case "external_hosts": - var hosts = ReadStringArray(entry) - .ToArray(); - foreach (var host in hosts) - ExternalLinkHosts.Add(host); - break; - case "toc": - var entries = ReadChildren(entry, string.Empty); + // Examine the stream + var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; - TableOfContents = entries; - break; - default: - EmitWarning($"{key} is not a known configuration", entry.Key); - break; + foreach (var entry in mapping.Children) + { + var key = ((YamlScalarNode)entry.Key).Value; + switch (key) + { + case "project": + Project = ReadString(entry); + break; + case "exclude": + Exclude = ReadStringArray(entry) + .Select(Glob.Parse) + .ToArray(); + break; + case "subs": + _substitutions = ReadDictionary(entry); + break; + case "external_hosts": + var hosts = ReadStringArray(entry) + .ToArray(); + foreach (var host in hosts) + ExternalLinkHosts.Add(host); + break; + case "toc": + var entries = ReadChildren(entry, string.Empty); + + TableOfContents = entries; + break; + default: + EmitWarning($"{key} is not a known configuration", entry.Key); + break; + } } } + catch (Exception e) + { + EmitError("Could not load docset.yml", e); + } + Globs = ImplicitFolders.Select(f => Glob.Parse($"{f}/*.md")).ToArray(); } @@ -100,8 +104,14 @@ private List ReadChildren(KeyValuePair entry, stri var entries = new List(); if (entry.Value is not YamlSequenceNode sequence) { - var key = ((YamlScalarNode)entry.Key).Value; - EmitWarning($"'{key}' is not an array"); + if (entry.Key is YamlScalarNode scalarKey) + { + var key = scalarKey.Value; + EmitWarning($"'{key}' is not an array"); + } + else + EmitWarning($"'{entry.Key}' is not an array"); + return entries; } @@ -159,10 +169,17 @@ private Dictionary ReadDictionary(KeyValuePair(StringComparer.OrdinalIgnoreCase); if (entry.Value is not YamlMappingNode mapping) { - var key = ((YamlScalarNode)entry.Key).Value; - EmitWarning($"'{key}' is not a dictionary"); + if (entry.Key is YamlScalarNode scalarKey) + { + var key = scalarKey.Value; + EmitWarning($"'{key}' is not a dictionary"); + } + else + EmitWarning($"'{entry.Key}' is not a dictionary"); + return dictionary; } + foreach (var entryValue in mapping.Children) { if (entryValue.Key is not YamlScalarNode scalar || scalar.Value is null) @@ -172,6 +189,7 @@ private Dictionary ReadDictionary(KeyValuePair ReadDictionary(KeyValuePair ReadDictionary(KeyValuePair private void EmitWarning(string message, YamlNode? node) => EmitWarning(message, node?.Start, node?.End, (node as YamlScalarNode)?.Value?.Length); + private void EmitError(string message, Exception e) => + _context.Collector.EmitError(_sourceFile.FullName, message, e); + private void EmitError(string message, Mark? start = null, Mark? end = null, int? length = null) { length ??= start.HasValue && end.HasValue ? (int)start.Value.Column - (int)end.Value.Column : null; @@ -269,4 +296,3 @@ private void EmitWarning(string message, Mark? start = null, Mark? end = null, i _context.Collector.Channel.Write(d); } } - diff --git a/src/Elastic.Markdown/IO/MarkdownFile.cs b/src/Elastic.Markdown/IO/MarkdownFile.cs index fe8b53944..3166b3bf6 100644 --- a/src/Elastic.Markdown/IO/MarkdownFile.cs +++ b/src/Elastic.Markdown/IO/MarkdownFile.cs @@ -23,6 +23,7 @@ public MarkdownFile(IFileInfo sourceFile, IDirectoryInfo rootPath, MarkdownParse : base(sourceFile, rootPath) { FileName = sourceFile.Name; + FilePath = sourceFile.FullName; UrlPathPrefix = context.UrlPathPrefix; MarkdownParser = parser; Collector = context.Collector; @@ -47,6 +48,7 @@ public string? NavigationTitle private readonly HashSet _additionalLabels = new(); public IReadOnlySet AdditionalLabels => _additionalLabels; + public string FilePath { get; } public string FileName { get; } public string Url => $"{UrlPathPrefix}/{RelativePath.Replace(".md", ".html")}"; @@ -75,7 +77,7 @@ private void ReadDocumentInstructions(MarkdownDocument document) if (document.FirstOrDefault() is YamlFrontMatterBlock yaml) { var raw = string.Join(Environment.NewLine, yaml.Lines.Lines); - YamlFrontMatter = YamlSerialization.Deserialize(raw); + YamlFrontMatter = ReadYamlFrontMatter(document, raw); Title = YamlFrontMatter.Title; NavigationTitle = YamlFrontMatter.NavigationTitle; } @@ -110,6 +112,19 @@ private void ReadDocumentInstructions(MarkdownDocument document) _instructionsParsed = true; } + private YamlFrontMatter ReadYamlFrontMatter(MarkdownDocument document, string raw) + { + try + { + return YamlSerialization.Deserialize(raw); + } + catch (Exception e) + { + Collector.EmitError(FilePath, "Failed to parse yaml front matter block.", e); + return new YamlFrontMatter(); + } + } + public string CreateHtml(MarkdownDocument document) => // var writer = new StringWriter();