From 6eea48463da8118d82b1e1a4928d69f8a7f822e0 Mon Sep 17 00:00:00 2001 From: Colleen McGinnis Date: Mon, 25 Aug 2025 12:30:12 -0500 Subject: [PATCH 1/2] warn when heading contains inline applies_to --- .../Myst/InlineParsers/HeadingBlockWithSlugParser.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Elastic.Markdown/Myst/InlineParsers/HeadingBlockWithSlugParser.cs b/src/Elastic.Markdown/Myst/InlineParsers/HeadingBlockWithSlugParser.cs index 236d4b8ab..079fac530 100644 --- a/src/Elastic.Markdown/Myst/InlineParsers/HeadingBlockWithSlugParser.cs +++ b/src/Elastic.Markdown/Myst/InlineParsers/HeadingBlockWithSlugParser.cs @@ -29,9 +29,10 @@ public void Setup(MarkdownPipelineBuilder pipeline) => public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) { } } -public class HeadingBlockWithSlugParser : HeadingBlockParser +public partial 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 +40,9 @@ 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.GetContext().Build.Collector.EmitWarning(processor.GetContext().MarkdownSourcePath, "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 +83,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(); +} From 9b0b60e07580be3e6634c2914ebed452d11e83b9 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 26 Aug 2025 18:36:37 +0200 Subject: [PATCH 2/2] update emit warning to use block processor to have sane defaults for peeking into the file for error localization --- .../ProcessorDiagnosticExtensions.cs | 28 ++++++++++++++++++- .../HeadingBlockWithSlugParser.cs | 6 ++-- 2 files changed, 31 insertions(+), 3 deletions(-) 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 079fac530..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; @@ -29,7 +30,7 @@ public void Setup(MarkdownPipelineBuilder pipeline) => public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) { } } -public partial class HeadingBlockWithSlugParser : HeadingBlockParser +public class HeadingBlockWithSlugParser : HeadingBlockParser { private static readonly Regex IconSyntax = IconParser.IconRegex(); private static readonly Regex AppliesToSyntax = HeadingAppliesToParser.AppliesToSyntaxRegex(); @@ -40,8 +41,9 @@ 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.GetContext().Build.Collector.EmitWarning(processor.GetContext().MarkdownSourcePath, "Do not use inline 'applies_to' annotations with headings. Use a section 'applies_to' annotation instead."); + 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();