acdream/src/AcDream.Core/Plugins/PluginManifest.cs
Erik 99d2702c13 refactor(core): harden PluginManifest error model
Addresses code quality review of c082ecf:
- Require takes a literal JSON field name, no more fragile PascalCase->camelCase transform
- Parse_MissingRequiredField_Throws asserts exact message, not substring
- Remove unused using System.Text.Json.Serialization
2026-04-10 09:33:00 +02:00

71 lines
2.1 KiB
C#

using System.Text.Json;
namespace AcDream.Core.Plugins;
public sealed record PluginManifest(
string Id,
string DisplayName,
string Version,
string EntryDll,
int ApiVersion,
IReadOnlyList<string> Dependencies)
{
public static PluginManifest Parse(string json)
{
PluginManifestDto? dto;
try
{
dto = JsonSerializer.Deserialize<PluginManifestDto>(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<string>());
}
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<string>? Dependencies { get; set; }
}
}
public sealed class PluginManifestException : Exception
{
public PluginManifestException(string message) : base(message) { }
public PluginManifestException(string message, Exception inner) : base(message, inner) { }
}