Skip to content

Commit 53fd0b2

Browse files
authored
Add infrastructure and diagnostics for unsupported directives (#57)
1 parent f880e6d commit 53fd0b2

39 files changed

+338
-92
lines changed

src/Elastic.Markdown/Diagnostics/DiagnosticsChannel.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public void TryComplete(Exception? exception = null)
2929
_ctxSource.Cancel();
3030
}
3131

32+
public ValueTask<bool> WaitToWrite() => _channel.Writer.WaitToWriteAsync();
33+
3234
public void Write(Diagnostic diagnostic)
3335
{
3436
var written = _channel.Writer.TryWrite(diagnostic);
@@ -84,10 +86,18 @@ public class DiagnosticsCollector(ILoggerFactory loggerFactory, IReadOnlyCollect
8486

8587
public async Task StartAsync(Cancel ctx)
8688
{
89+
await Channel.WaitToWrite();
8790
while (!Channel.CancellationToken.IsCancellationRequested)
8891
{
89-
while (await Channel.Reader.WaitToReadAsync(Channel.CancellationToken))
90-
Drain();
92+
try
93+
{
94+
while (await Channel.Reader.WaitToReadAsync(Channel.CancellationToken))
95+
Drain();
96+
}
97+
catch
98+
{
99+
//ignore
100+
}
91101
}
92102
Drain();
93103

src/Elastic.Markdown/Diagnostics/ProcessorDiagnosticExtensions.cs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public static class ProcessorDiagnosticExtensions
1212
{
1313
public static void EmitError(this InlineProcessor processor, int line, int column, int length, string message)
1414
{
15+
var context = processor.GetContext();
16+
if (context.SkipValidation) return;
1517
var d = new Diagnostic
1618
{
1719
Severity = Severity.Error,
@@ -21,6 +23,53 @@ public static void EmitError(this InlineProcessor processor, int line, int colum
2123
Message = message,
2224
Length = length
2325
};
24-
processor.GetBuildContext().Collector.Channel.Write(d);
26+
context.Build.Collector.Channel.Write(d);
27+
}
28+
29+
30+
public static void EmitWarning(this BlockProcessor processor, int line, int column, int length, string message)
31+
{
32+
var context = processor.GetContext();
33+
if (context.SkipValidation) return;
34+
var d = new Diagnostic
35+
{
36+
Severity = Severity.Warning,
37+
File = processor.GetContext().Path.FullName,
38+
Column = column,
39+
Line = line,
40+
Message = message,
41+
Length = length
42+
};
43+
context.Build.Collector.Channel.Write(d);
44+
}
45+
46+
public static void EmitError(this ParserContext context, int line, int column, int length, string message)
47+
{
48+
if (context.SkipValidation) return;
49+
var d = new Diagnostic
50+
{
51+
Severity = Severity.Error,
52+
File = context.Path.FullName,
53+
Column = column,
54+
Line = line,
55+
Message = message,
56+
Length = length
57+
};
58+
context.Build.Collector.Channel.Write(d);
59+
}
60+
61+
public static void EmitWarning(this ParserContext context, int line, int column, int length, string message)
62+
{
63+
if (context.SkipValidation) return;
64+
var d = new Diagnostic
65+
{
66+
Severity = Severity.Warning,
67+
File = context.Path.FullName,
68+
Column = column,
69+
Line = line,
70+
Message = message,
71+
Length = length
72+
};
73+
context.Build.Collector.Channel.Write(d);
2574
}
2675
}

src/Elastic.Markdown/Myst/Directives/AdmonitionBlock.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public string Title
2525
}
2626
}
2727

28-
public override void FinalizeAndValidate()
28+
public override void FinalizeAndValidate(ParserContext context)
2929
{
3030
Classes = Properties.GetValueOrDefault("class");
3131
CrossReferenceName = Properties.GetValueOrDefault("name");
@@ -38,9 +38,9 @@ public class DropdownBlock(DirectiveBlockParser parser, Dictionary<string, strin
3838
: AdmonitionBlock(parser, "admonition", properties)
3939
{
4040
// ReSharper disable once RedundantOverriddenMember
41-
public override void FinalizeAndValidate()
41+
public override void FinalizeAndValidate(ParserContext context)
4242
{
43-
base.FinalizeAndValidate();
43+
base.FinalizeAndValidate(context);
4444
Classes = $"dropdown {Classes}";
4545
}
4646
}

src/Elastic.Markdown/Myst/Directives/CardBlock.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class CardBlock(DirectiveBlockParser parser, Dictionary<string, string> p
1414

1515
public string? Footer { get; set; }
1616

17-
public override void FinalizeAndValidate()
17+
public override void FinalizeAndValidate(ParserContext context)
1818
{
1919
Title = Arguments;
2020
Link = Properties.GetValueOrDefault("link");

src/Elastic.Markdown/Myst/Directives/CodeBlock.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public string Language
2020
}
2121
}
2222

23-
public override void FinalizeAndValidate()
23+
public override void FinalizeAndValidate(ParserContext context)
2424
{
2525
Caption = Properties.GetValueOrDefault("caption");
2626
CrossReferenceName = Properties.GetValueOrDefault("name");

src/Elastic.Markdown/Myst/Directives/DirectiveBlock.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ public abstract class DirectiveBlock(DirectiveBlockParser parser, Dictionary<str
6666
/// <summary>
6767
/// Allows blocks to finalize setting properties once fully parsed
6868
/// </summary>
69-
public abstract void FinalizeAndValidate();
69+
/// <param name="context"></param>
70+
public abstract void FinalizeAndValidate(ParserContext context);
7071

7172
protected void ParseBool(string key, Action<bool> setter)
7273
{

src/Elastic.Markdown/Myst/Directives/DirectiveBlockParser.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// This file is licensed under the BSD-Clause 2 license.
66
// See the license.txt file in the project root for more information.
77

8+
using System.Collections.Frozen;
89
using Markdig.Parsers;
910
using Markdig.Syntax;
1011
using static System.StringSplitOptions;
@@ -37,6 +38,20 @@ public DirectiveBlockParser()
3738

3839
private readonly string[] _codeBlocks = [ "code", "code-block", "sourcecode"];
3940

41+
private readonly FrozenDictionary<string, int> _unsupportedBlocks = new Dictionary<string, int>
42+
{
43+
{ "bibliography", 5 },
44+
{ "blockquote", 6 },
45+
{ "csv-table", 9 },
46+
{ "iframe", 14 },
47+
{ "list-table", 17 },
48+
{ "myst", 22 },
49+
{ "topic", 24 },
50+
{ "exercise", 30 },
51+
{ "solution", 31 },
52+
{ "toctree", 32 },
53+
}.ToFrozenDictionary();
54+
4055
protected override DirectiveBlock CreateFencedBlock(BlockProcessor processor)
4156
{
4257
_admonitionData = new Dictionary<string, string>();
@@ -108,14 +123,18 @@ protected override DirectiveBlock CreateFencedBlock(BlockProcessor processor)
108123
if (info.IndexOf($"{{{code}}}") > 0)
109124
return new CodeBlock(this, code, _admonitionData);
110125
}
126+
// TODO alternate lookup .NET 9
127+
var directive = info.ToString().Trim(['{', '}', '`']);
128+
if (_unsupportedBlocks.TryGetValue(directive, out var issueId))
129+
return new UnsupportedDirectiveBlock(this, directive, _admonitionData, issueId);
111130

112131
return new UnknownDirectiveBlock(this, info.ToString(), _admonitionData);
113132
}
114133

115134
public override bool Close(BlockProcessor processor, Block block)
116135
{
117136
if (block is DirectiveBlock directiveBlock)
118-
directiveBlock.FinalizeAndValidate();
137+
directiveBlock.FinalizeAndValidate(processor.GetContext());
119138

120139

121140
if (block is not TocTreeBlock toc)

src/Elastic.Markdown/Myst/Directives/ImageBlock.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public class ImageBlock(DirectiveBlockParser parser, Dictionary<string, string>
5656

5757
public string ImageUrl { get; private set; } = default!;
5858

59-
public override void FinalizeAndValidate()
59+
public override void FinalizeAndValidate(ParserContext context)
6060
{
6161
ImageUrl = Arguments ?? string.Empty; //todo validate
6262
Classes = Properties.GetValueOrDefault("class");

src/Elastic.Markdown/Myst/Directives/IncludeBlock.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class IncludeBlock(DirectiveBlockParser parser, Dictionary<string, string
2828

2929
//TODO add all options from
3030
//https://mystmd.org/guide/directives#directive-include
31-
public override void FinalizeAndValidate()
31+
public override void FinalizeAndValidate(ParserContext context)
3232
{
3333
var includePath = Arguments; //todo validate
3434
Literal |= bool.TryParse(Properties.GetValueOrDefault("literal"), out var b) && b;

src/Elastic.Markdown/Myst/Directives/MermaidBlock.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Elastic.Markdown.Myst.Directives;
66
public class MermaidBlock(DirectiveBlockParser parser, Dictionary<string, string> properties)
77
: DirectiveBlock(parser, properties)
88
{
9-
public override void FinalizeAndValidate()
9+
public override void FinalizeAndValidate(ParserContext context)
1010
{
1111
}
1212
}

0 commit comments

Comments
 (0)