using System.Text.Json; using System.Text.Json.Serialization; 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, nameof(dto.Id)); Require(dto.DisplayName, nameof(dto.DisplayName)); Require(dto.Version, nameof(dto.Version)); Require(dto.EntryDll, nameof(dto.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 fieldName) { if (string.IsNullOrWhiteSpace(value)) throw new PluginManifestException( $"missing required field: {char.ToLowerInvariant(fieldName[0])}{fieldName[1..]}"); } 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) { } }