namespace LehrerApp.Templating; public static class TemplateMetadataKeys { public const string Language = "language"; public const string ReportType = "report-type"; } public static class TemplateMetadataText { public const string FileName = "metadata.txt"; public static Dictionary Parse(string source) { var result = new Dictionary(StringComparer.OrdinalIgnoreCase); var lines = source.Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n').Split('\n'); for (var index = 0; index < lines.Length; index++) { var line = lines[index].Trim(); if (line.Length == 0 || line.StartsWith('#')) continue; var separator = line.IndexOf('='); if (separator < 1) throw new InvalidDataException($"Metadatenzeile {index + 1} muss Schlüssel=Wert enthalten."); var key = line[..separator].Trim(); var value = line[(separator + 1)..].Trim(); Validate(key, value); if (!result.TryAdd(key, value)) throw new InvalidDataException($"Metadatenschlüssel „{key}“ ist mehrfach vorhanden."); } return result; } public static string Serialize(IReadOnlyDictionary metadata) { if (metadata.Count == 0) return ""; var lines = new List(metadata.Count); foreach (var (key, value) in metadata.OrderBy(x => x.Key, StringComparer.OrdinalIgnoreCase)) { Validate(key, value); lines.Add($"{key.Trim()}={value.Trim()}"); } return string.Join('\n', lines) + "\n"; } private static void Validate(string key, string value) { if (string.IsNullOrWhiteSpace(key)) throw new InvalidDataException("Ein Metadatenschlüssel darf nicht leer sein."); if (key.Contains('=') || key.Contains('\n') || key.Contains('\r')) throw new InvalidDataException($"Metadatenschlüssel „{key}“ enthält ein unzulässiges Zeichen."); if (value.Contains('\n') || value.Contains('\r')) throw new InvalidDataException($"Metadatenwert für „{key}“ darf nur eine Zeile umfassen."); } }