enable nullable annotations in mod data models (#837)
This commit is contained in:
parent
0336fb2524
commit
761f2d952b
|
@ -145,7 +145,7 @@ namespace SMAPI.Tests.Core
|
|||
{
|
||||
// arrange
|
||||
Mock<IModMetadata> mock = this.GetMetadata("Mod A", Array.Empty<string>(), allowStatusChange: true);
|
||||
this.SetupMetadataForValidation(mock, new ModDataRecordVersionedFields
|
||||
this.SetupMetadataForValidation(mock, new ModDataRecordVersionedFields(this.GetModDataRecord())
|
||||
{
|
||||
Status = ModStatus.AssumeBroken
|
||||
});
|
||||
|
@ -216,9 +216,9 @@ namespace SMAPI.Tests.Core
|
|||
File.WriteAllText(Path.Combine(modFolder, manifest.EntryDll!), "");
|
||||
|
||||
// arrange
|
||||
Mock<IModMetadata> mock = new Mock<IModMetadata>(MockBehavior.Strict);
|
||||
Mock<IModMetadata> mock = new(MockBehavior.Strict);
|
||||
mock.Setup(p => p.Status).Returns(ModMetadataStatus.Found);
|
||||
mock.Setup(p => p.DataRecord).Returns(() => null);
|
||||
mock.Setup(p => p.DataRecord).Returns(this.GetModDataRecordVersionedFields());
|
||||
mock.Setup(p => p.Manifest).Returns(manifest);
|
||||
mock.Setup(p => p.DirectoryPath).Returns(modFolder);
|
||||
|
||||
|
@ -265,7 +265,7 @@ namespace SMAPI.Tests.Core
|
|||
public void ProcessDependencies_Skips_Failed()
|
||||
{
|
||||
// arrange
|
||||
Mock<IModMetadata> mock = new Mock<IModMetadata>(MockBehavior.Strict);
|
||||
Mock<IModMetadata> mock = new(MockBehavior.Strict);
|
||||
mock.Setup(p => p.Status).Returns(ModMetadataStatus.Failed);
|
||||
|
||||
// act
|
||||
|
@ -380,7 +380,7 @@ namespace SMAPI.Tests.Core
|
|||
Mock<IModMetadata> modA = this.GetMetadata("Mod A");
|
||||
Mock<IModMetadata> modB = this.GetMetadata("Mod B", dependencies: new[] { "Mod A" });
|
||||
Mock<IModMetadata> modC = this.GetMetadata("Mod C", dependencies: new[] { "Mod B" }, allowStatusChange: true);
|
||||
Mock<IModMetadata> modD = new Mock<IModMetadata>(MockBehavior.Strict);
|
||||
Mock<IModMetadata> modD = new(MockBehavior.Strict);
|
||||
modD.Setup(p => p.Manifest).Returns<IManifest>(null);
|
||||
modD.Setup(p => p.Status).Returns(ModMetadataStatus.Failed);
|
||||
|
||||
|
@ -516,8 +516,8 @@ namespace SMAPI.Tests.Core
|
|||
/// <param name="allowStatusChange">Whether the code being tested is allowed to change the mod status.</param>
|
||||
private Mock<IModMetadata> GetMetadata(IManifest manifest, bool allowStatusChange = false)
|
||||
{
|
||||
Mock<IModMetadata> mod = new Mock<IModMetadata>(MockBehavior.Strict);
|
||||
mod.Setup(p => p.DataRecord).Returns(() => null);
|
||||
Mock<IModMetadata> mod = new(MockBehavior.Strict);
|
||||
mod.Setup(p => p.DataRecord).Returns(this.GetModDataRecordVersionedFields());
|
||||
mod.Setup(p => p.Status).Returns(ModMetadataStatus.Found);
|
||||
mod.Setup(p => p.DisplayName).Returns(manifest.UniqueID);
|
||||
mod.Setup(p => p.Manifest).Returns(manifest);
|
||||
|
@ -538,11 +538,22 @@ namespace SMAPI.Tests.Core
|
|||
private void SetupMetadataForValidation(Mock<IModMetadata> mod, ModDataRecordVersionedFields? modRecord = null)
|
||||
{
|
||||
mod.Setup(p => p.Status).Returns(ModMetadataStatus.Found);
|
||||
mod.Setup(p => p.DataRecord).Returns(() => null);
|
||||
mod.Setup(p => p.Manifest).Returns(this.GetManifest());
|
||||
mod.Setup(p => p.DirectoryPath).Returns(Path.GetTempPath());
|
||||
mod.Setup(p => p.DataRecord).Returns(modRecord);
|
||||
mod.Setup(p => p.DataRecord).Returns(modRecord ?? this.GetModDataRecordVersionedFields());
|
||||
mod.Setup(p => p.GetUpdateKeys(It.IsAny<bool>())).Returns(Enumerable.Empty<UpdateKey>());
|
||||
}
|
||||
|
||||
/// <summary>Generate a default mod data record.</summary>
|
||||
private ModDataRecord GetModDataRecord()
|
||||
{
|
||||
return new("Default Display Name", new ModDataModel("Sample ID", null, ModWarning.None));
|
||||
}
|
||||
|
||||
/// <summary>Generate a default mod data versioned fields instance.</summary>
|
||||
private ModDataRecordVersionedFields GetModDataRecordVersionedFields()
|
||||
{
|
||||
return new ModDataRecordVersionedFields(this.GetModDataRecord());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StardewModdingAPI.Toolkit.Framework.ModData
|
||||
|
@ -11,6 +9,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
** Accessors
|
||||
********/
|
||||
/// <summary>Extra metadata about mods.</summary>
|
||||
public IDictionary<string, ModDataModel> ModData { get; set; }
|
||||
public IDictionary<string, ModDataModel> ModData { get; } = new Dictionary<string, ModDataModel>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace StardewModdingAPI.Toolkit.Framework.ModData
|
||||
|
@ -20,10 +18,10 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
public bool IsDefault { get; }
|
||||
|
||||
/// <summary>The lowest version in the range, or <c>null</c> for all past versions.</summary>
|
||||
public ISemanticVersion LowerVersion { get; }
|
||||
public ISemanticVersion? LowerVersion { get; }
|
||||
|
||||
/// <summary>The highest version in the range, or <c>null</c> for all future versions.</summary>
|
||||
public ISemanticVersion UpperVersion { get; }
|
||||
public ISemanticVersion? UpperVersion { get; }
|
||||
|
||||
|
||||
/*********
|
||||
|
@ -35,7 +33,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
/// <param name="isDefault">Whether this field should only be applied if it's not already set.</param>
|
||||
/// <param name="lowerVersion">The lowest version in the range, or <c>null</c> for all past versions.</param>
|
||||
/// <param name="upperVersion">The highest version in the range, or <c>null</c> for all future versions.</param>
|
||||
public ModDataField(ModDataFieldKey key, string value, bool isDefault, ISemanticVersion lowerVersion, ISemanticVersion upperVersion)
|
||||
public ModDataField(ModDataFieldKey key, string value, bool isDefault, ISemanticVersion? lowerVersion, ISemanticVersion? upperVersion)
|
||||
{
|
||||
this.Key = key;
|
||||
this.Value = value;
|
||||
|
@ -46,7 +44,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
|
||||
/// <summary>Get whether this data field applies for the given manifest.</summary>
|
||||
/// <param name="manifest">The mod manifest.</param>
|
||||
public bool IsMatch(IManifest manifest)
|
||||
public bool IsMatch(IManifest? manifest)
|
||||
{
|
||||
return
|
||||
manifest?.Version != null // ignore invalid manifest
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -16,7 +14,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
** Accessors
|
||||
*********/
|
||||
/// <summary>The mod's current unique ID.</summary>
|
||||
public string ID { get; set; }
|
||||
public string ID { get; }
|
||||
|
||||
/// <summary>The former mod IDs (if any).</summary>
|
||||
/// <remarks>
|
||||
|
@ -25,14 +23,14 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
/// ID, if any. If the mod's ID changed over time, multiple variants can be separated by the
|
||||
/// <c>|</c> character.
|
||||
/// </remarks>
|
||||
public string FormerIDs { get; set; }
|
||||
public string? FormerIDs { get; }
|
||||
|
||||
/// <summary>The mod warnings to suppress, even if they'd normally be shown.</summary>
|
||||
public ModWarning SuppressWarnings { get; set; }
|
||||
public ModWarning SuppressWarnings { get; }
|
||||
|
||||
/// <summary>This field stores properties that aren't mapped to another field before they're parsed into <see cref="Fields"/>.</summary>
|
||||
[JsonExtensionData]
|
||||
public IDictionary<string, JToken> ExtensionData { get; set; }
|
||||
public IDictionary<string, JToken> ExtensionData { get; } = new Dictionary<string, JToken>();
|
||||
|
||||
/// <summary>The versioned field data.</summary>
|
||||
/// <remarks>
|
||||
|
@ -52,6 +50,17 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="id">The mod's current unique ID.</param>
|
||||
/// <param name="formerIds">The former mod IDs (if any).</param>
|
||||
/// <param name="suppressWarnings">The mod warnings to suppress, even if they'd normally be shown.</param>
|
||||
public ModDataModel(string id, string? formerIds, ModWarning suppressWarnings)
|
||||
{
|
||||
this.ID = id;
|
||||
this.FormerIDs = formerIds;
|
||||
this.SuppressWarnings = suppressWarnings;
|
||||
}
|
||||
|
||||
/// <summary>Get a parsed representation of the <see cref="Fields"/>.</summary>
|
||||
public IEnumerable<ModDataField> GetFields()
|
||||
{
|
||||
|
@ -61,8 +70,8 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
string packedKey = pair.Key;
|
||||
string value = pair.Value;
|
||||
bool isDefault = false;
|
||||
ISemanticVersion lowerVersion = null;
|
||||
ISemanticVersion upperVersion = null;
|
||||
ISemanticVersion? lowerVersion = null;
|
||||
ISemanticVersion? upperVersion = null;
|
||||
|
||||
// parse
|
||||
string[] parts = packedKey.Split('|').Select(p => p.Trim()).ToArray();
|
||||
|
@ -113,11 +122,8 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
[OnDeserialized]
|
||||
private void OnDeserialized(StreamingContext context)
|
||||
{
|
||||
if (this.ExtensionData != null)
|
||||
{
|
||||
this.Fields = this.ExtensionData.ToDictionary(p => p.Key, p => p.Value.ToString());
|
||||
this.ExtensionData = null;
|
||||
}
|
||||
this.Fields = this.ExtensionData.ToDictionary(p => p.Key, p => p.Value.ToString());
|
||||
this.ExtensionData.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -22,7 +20,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
public string[] FormerIDs { get; }
|
||||
|
||||
/// <summary>The mod warnings to suppress, even if they'd normally be shown.</summary>
|
||||
public ModWarning SuppressWarnings { get; set; }
|
||||
public ModWarning SuppressWarnings { get; }
|
||||
|
||||
/// <summary>The versioned field data.</summary>
|
||||
public ModDataField[] Fields { get; }
|
||||
|
@ -72,9 +70,9 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
}
|
||||
|
||||
/// <summary>Get the default update key for this mod, if any.</summary>
|
||||
public string GetDefaultUpdateKey()
|
||||
public string? GetDefaultUpdateKey()
|
||||
{
|
||||
string updateKey = this.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey && p.IsDefault)?.Value;
|
||||
string? updateKey = this.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey && p.IsDefault)?.Value;
|
||||
return !string.IsNullOrWhiteSpace(updateKey)
|
||||
? updateKey
|
||||
: null;
|
||||
|
@ -84,7 +82,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
/// <param name="manifest">The manifest to match.</param>
|
||||
public ModDataRecordVersionedFields GetVersionedFields(IManifest manifest)
|
||||
{
|
||||
ModDataRecordVersionedFields parsed = new() { DisplayName = this.DisplayName, DataRecord = this };
|
||||
ModDataRecordVersionedFields parsed = new(this);
|
||||
foreach (ModDataField field in this.Fields.Where(field => field.IsMatch(manifest)))
|
||||
{
|
||||
switch (field.Key)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
namespace StardewModdingAPI.Toolkit.Framework.ModData
|
||||
{
|
||||
/// <summary>The versioned fields from a <see cref="ModDataRecord"/> for a specific manifest.</summary>
|
||||
|
@ -9,24 +7,32 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
** Accessors
|
||||
*********/
|
||||
/// <summary>The underlying data record.</summary>
|
||||
public ModDataRecord DataRecord { get; set; }
|
||||
public ModDataRecord DataRecord { get; }
|
||||
|
||||
/// <summary>The default mod name to display when the name isn't available (e.g. during dependency checks).</summary>
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
/// <summary>The update key to apply.</summary>
|
||||
public string UpdateKey { get; set; }
|
||||
/// <summary>The update key to apply (if any).</summary>
|
||||
public string? UpdateKey { get; set; }
|
||||
|
||||
/// <summary>The predefined compatibility status.</summary>
|
||||
public ModStatus Status { get; set; } = ModStatus.None;
|
||||
|
||||
/// <summary>A reason phrase for the <see cref="Status"/>, or <c>null</c> to use the default reason.</summary>
|
||||
public string StatusReasonPhrase { get; set; }
|
||||
public string? StatusReasonPhrase { get; set; }
|
||||
|
||||
/// <summary>Technical details shown in TRACE logs for the <see cref="Status"/>, or <c>null</c> to omit it.</summary>
|
||||
public string StatusReasonDetails { get; set; }
|
||||
public string? StatusReasonDetails { get; set; }
|
||||
|
||||
/// <summary>The upper version for which the <see cref="Status"/> applies (if any).</summary>
|
||||
public ISemanticVersion StatusUpperVersion { get; set; }
|
||||
public ISemanticVersion? StatusUpperVersion { get; set; }
|
||||
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="dataRecord">The underlying data record.</param>
|
||||
public ModDataRecordVersionedFields(ModDataRecord dataRecord)
|
||||
{
|
||||
this.DataRecord = dataRecord;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -16,7 +14,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
private readonly ModDataRecord[] Records;
|
||||
|
||||
/// <summary>Get an update URL for an update key (if valid).</summary>
|
||||
private readonly Func<string, string> GetUpdateUrl;
|
||||
private readonly Func<string, string?> GetUpdateUrl;
|
||||
|
||||
|
||||
/*********
|
||||
|
@ -29,7 +27,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="records">The underlying mod data records indexed by default display name.</param>
|
||||
/// <param name="getUpdateUrl">Get an update URL for an update key (if valid).</param>
|
||||
public ModDatabase(IEnumerable<ModDataRecord> records, Func<string, string> getUpdateUrl)
|
||||
public ModDatabase(IEnumerable<ModDataRecord> records, Func<string, string?> getUpdateUrl)
|
||||
{
|
||||
this.Records = records.ToArray();
|
||||
this.GetUpdateUrl = getUpdateUrl;
|
||||
|
@ -43,7 +41,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
|
||||
/// <summary>Get a mod data record.</summary>
|
||||
/// <param name="modID">The unique mod ID.</param>
|
||||
public ModDataRecord Get(string modID)
|
||||
public ModDataRecord? Get(string? modID)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(modID)
|
||||
? this.Records.FirstOrDefault(p => p.HasID(modID))
|
||||
|
@ -52,11 +50,11 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
|
|||
|
||||
/// <summary>Get the mod page URL for a mod (if available).</summary>
|
||||
/// <param name="id">The unique mod ID.</param>
|
||||
public string GetModPageUrlFor(string id)
|
||||
public string? GetModPageUrlFor(string? id)
|
||||
{
|
||||
// get update key
|
||||
ModDataRecord record = this.Get(id);
|
||||
ModDataField updateKeyField = record?.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey);
|
||||
ModDataRecord? record = this.Get(id);
|
||||
ModDataField? updateKeyField = record?.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey);
|
||||
if (updateKeyField == null)
|
||||
return null;
|
||||
|
||||
|
|
|
@ -2,4 +2,5 @@ using System.Runtime.CompilerServices;
|
|||
|
||||
[assembly: InternalsVisibleTo("StardewModdingAPI")]
|
||||
[assembly: InternalsVisibleTo("SMAPI.Installer")]
|
||||
[assembly: InternalsVisibleTo("SMAPI.Tests")]
|
||||
[assembly: InternalsVisibleTo("SMAPI.Web")]
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace StardewModdingAPI.Toolkit.Serialization.Models
|
|||
|
||||
/// <summary>Any manifest fields which didn't match a valid field.</summary>
|
||||
[JsonExtensionData]
|
||||
public IDictionary<string, object> ExtraFields { get; set; } = new Dictionary<string, object>();
|
||||
public IDictionary<string, object> ExtraFields { get; } = new Dictionary<string, object>();
|
||||
|
||||
|
||||
/*********
|
||||
|
|
Loading…
Reference in New Issue