diff --git a/src/Elastic.Markdown/Diagnostics/ProcessorDiagnosticExtensions.cs b/src/Elastic.Markdown/Diagnostics/ProcessorDiagnosticExtensions.cs index abcefd00d..ca97f6963 100644 --- a/src/Elastic.Markdown/Diagnostics/ProcessorDiagnosticExtensions.cs +++ b/src/Elastic.Markdown/Diagnostics/ProcessorDiagnosticExtensions.cs @@ -14,10 +14,36 @@ public static class ProcessorDiagnosticExtensions { private static string CreateExceptionMessage(string message, Exception? e) => message + (e != null ? Environment.NewLine + e : string.Empty); + public static void EmitError(this BlockProcessor processor, string message, int? line = null, int? column = null, int? length = null) => + processor.Emit(Severity.Error, message, line, column, length); + + public static void EmitWarning(this BlockProcessor processor, string message, int? line = null, int? column = null, int? length = null) => + processor.Emit(Severity.Warning, message, line, column, length); + + public static void EmitHint(this BlockProcessor processor, string message, int? line = null, int? column = null, int? length = null) => + processor.Emit(Severity.Hint, message, line, column, length); + + public static void Emit(this BlockProcessor processor, Severity severity, string message, int? line = null, int? column = null, int? length = null) + { + var context = processor.GetContext(); + if (context.SkipValidation) + return; + var d = new Diagnostic + { + Severity = severity, + File = processor.GetContext().MarkdownSourcePath.FullName, + Column = column ?? 1, + Line = line ?? processor.LineIndex + 1, + Message = message, + Length = length ?? processor.Line.Length + 1 + }; + context.Build.Collector.Write(d); + } + + public static void EmitError(this InlineProcessor processor, int line, int column, int length, string message) => processor.Emit(Severity.Error, line, column, length, message); - public static void EmitWarning(this InlineProcessor processor, int line, int column, int length, string message) => processor.Emit(Severity.Warning, line, column, length, message); diff --git a/src/Elastic.Markdown/Myst/InlineParsers/HeadingBlockWithSlugParser.cs b/src/Elastic.Markdown/Myst/InlineParsers/HeadingBlockWithSlugParser.cs index 236d4b8ab..ca767febc 100644 --- a/src/Elastic.Markdown/Myst/InlineParsers/HeadingBlockWithSlugParser.cs +++ b/src/Elastic.Markdown/Myst/InlineParsers/HeadingBlockWithSlugParser.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information using System.Text.RegularExpressions; +using Elastic.Markdown.Diagnostics; using Elastic.Markdown.Myst.Roles.Icons; using Markdig; using Markdig.Helpers; @@ -32,6 +33,7 @@ public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) { } public class HeadingBlockWithSlugParser : HeadingBlockParser { private static readonly Regex IconSyntax = IconParser.IconRegex(); + private static readonly Regex AppliesToSyntax = HeadingAppliesToParser.AppliesToSyntaxRegex(); public override bool Close(BlockProcessor processor, Block block) { @@ -39,6 +41,10 @@ public override bool Close(BlockProcessor processor, Block block) return base.Close(processor, block); var text = headingBlock.Lines.Lines[0].Slice.AsSpan(); + + if (AppliesToSyntax.IsMatch(text)) + processor.EmitWarning("Do not use inline 'applies_to' annotations with headings. Use a section 'applies_to' annotation instead."); + // Remove icon syntax from the heading text var cleanText = IconSyntax.Replace(text.ToString(), "").Trim(); headingBlock.SetData("header", cleanText); @@ -79,3 +85,9 @@ public static partial class HeadingAnchorParser [GeneratedRegex(@"\$\$\$[^\$]+\$\$\$", RegexOptions.IgnoreCase, "en-US")] public static partial Regex InlineAnchors(); } + +public static partial class HeadingAppliesToParser +{ + [GeneratedRegex(@"\{applies_to\}`[^`]*`", RegexOptions.Compiled)] + public static partial Regex AppliesToSyntaxRegex(); +}