Normalize scalar frontmatter lists
PR and Push Build/Test / build-and-test (push) Successful in 8m49s

This commit is contained in:
2026-06-11 16:00:05 +02:00
parent bd786426bf
commit b22754ce5d
10 changed files with 131 additions and 17 deletions
@@ -0,0 +1,24 @@
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace MeetingAssistant.MeetingNotes;
internal static class FrontmatterYamlDeserializer
{
public static IDeserializer Create()
{
return new DeserializerBuilder()
.WithTypeConverter(new ScalarStringListYamlTypeConverter())
.IgnoreUnmatchedProperties()
.Build();
}
public static IDeserializer CreateWithUnderscoredNaming()
{
return new DeserializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.WithTypeConverter(new ScalarStringListYamlTypeConverter())
.IgnoreUnmatchedProperties()
.Build();
}
}
@@ -16,9 +16,7 @@ public sealed class MarkdownMeetingNoteStore : IMeetingNoteStore
{
this.options = options.Value;
this.logger = logger;
yamlDeserializer = new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.Build();
yamlDeserializer = FrontmatterYamlDeserializer.Create();
}
public async Task<MeetingNote> SaveAsync(MeetingNote note, CancellationToken cancellationToken)
@@ -0,0 +1,38 @@
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace MeetingAssistant.MeetingNotes;
internal sealed class ScalarStringListYamlTypeConverter : IYamlTypeConverter
{
public bool Accepts(Type type)
{
return type == typeof(List<string>);
}
public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
if (parser.TryConsume<Scalar>(out var scalar))
{
return string.IsNullOrWhiteSpace(scalar.Value)
? []
: new List<string> { scalar.Value };
}
var values = new List<string>();
parser.Consume<SequenceStart>();
while (!parser.TryConsume<SequenceEnd>(out _))
{
var item = parser.Consume<Scalar>();
values.Add(item.Value);
}
return values;
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
serializer(value, typeof(IEnumerable<string>));
}
}
@@ -7,9 +7,7 @@ public sealed record BoundMeetingProject(string Name, string Path);
public sealed class BoundMeetingProjectResolver
{
private static readonly IDeserializer YamlDeserializer = new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.Build();
private static readonly IDeserializer YamlDeserializer = FrontmatterYamlDeserializer.Create();
private readonly MeetingAssistantOptions options;
@@ -5,9 +5,7 @@ namespace MeetingAssistant.Summary;
internal static class MeetingSummaryFrontmatterFactory
{
private static readonly IDeserializer YamlDeserializer = new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.Build();
private static readonly IDeserializer YamlDeserializer = FrontmatterYamlDeserializer.Create();
public static async Task<MeetingArtifactFrontmatter> CreateAsync(
MeetingSessionArtifacts artifacts,
@@ -7,9 +7,7 @@ namespace MeetingAssistant.Summary;
public sealed class MeetingSummaryTools
{
private static readonly IDeserializer YamlDeserializer = new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.Build();
private static readonly IDeserializer YamlDeserializer = FrontmatterYamlDeserializer.Create();
private readonly MeetingSessionArtifacts artifacts;
private readonly MeetingAssistantOptions options;
@@ -12,16 +12,12 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace MeetingAssistant.Workflow;
public sealed class WorkflowRulesEditorTools
{
private static readonly IDeserializer YamlDeserializer = new DeserializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build();
private static readonly IDeserializer YamlDeserializer = FrontmatterYamlDeserializer.CreateWithUnderscoredNaming();
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
{
WriteIndented = true