using System.Text.Json; namespace AcDream.Core.Plugins; public sealed record PluginManifest( string Id, string DisplayName, string Version, string EntryDll, int ApiVersion, IReadOnlyList Dependencies) { public static PluginManifest Parse(string json) { PluginManifestDto? dto; try { dto = JsonSerializer.Deserialize(json, JsonOptions); } catch (JsonException ex) { throw new PluginManifestException($"invalid json: {ex.Message}", ex); } if (dto is null) throw new PluginManifestException("manifest is empty"); Require(dto.Id, "id"); Require(dto.DisplayName, "displayName"); Require(dto.Version, "version"); Require(dto.EntryDll, "entryDll"); if (dto.ApiVersion <= 0) throw new PluginManifestException("apiVersion must be >= 1"); return new PluginManifest( dto.Id!, dto.DisplayName!, dto.Version!, dto.EntryDll!, dto.ApiVersion, dto.Dependencies ?? Array.Empty()); } private static void Require(string? value, string jsonFieldName) { if (string.IsNullOrWhiteSpace(value)) throw new PluginManifestException($"missing required field: {jsonFieldName}"); } private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, PropertyNameCaseInsensitive = true, }; private sealed class PluginManifestDto { public string? Id { get; set; } public string? DisplayName { get; set; } public string? Version { get; set; } public string? EntryDll { get; set; } public int ApiVersion { get; set; } public IReadOnlyList? Dependencies { get; set; } } } public sealed class PluginManifestException : Exception { public PluginManifestException(string message) : base(message) { } public PluginManifestException(string message, Exception inner) : base(message, inner) { } }