From 82306a2c50f4d3df33d8ce62ca49628baf0cc3b7 Mon Sep 17 00:00:00 2001
From: Jesse Plamondon-Willard <github@jplamondonw.com>
Date: Wed, 27 Jun 2018 00:40:31 -0400
Subject: encapsulate mod DB a bit better for use outside SMAPI (#532)

---
 .../Framework/ModData/MetadataModel.cs             |  14 ++
 .../Framework/ModData/ModDataModel.cs              | 129 +++++++++++++++++
 .../Framework/ModData/ModDataRecord.cs             | 152 +++++++++------------
 .../ModData/ModDataRecordVersionedFields.cs        |  51 +++++++
 .../Framework/ModData/ModDatabase.cs               | 103 ++------------
 .../Framework/ModData/ParsedModDataRecord.cs       |  51 -------
 .../Framework/ModData/SMetadata.cs                 |  14 --
 7 files changed, 270 insertions(+), 244 deletions(-)
 create mode 100644 src/StardewModdingAPI.Toolkit/Framework/ModData/MetadataModel.cs
 create mode 100644 src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataModel.cs
 create mode 100644 src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs
 delete mode 100644 src/StardewModdingAPI.Toolkit/Framework/ModData/ParsedModDataRecord.cs
 delete mode 100644 src/StardewModdingAPI.Toolkit/Framework/ModData/SMetadata.cs

(limited to 'src/StardewModdingAPI.Toolkit/Framework/ModData')

diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/MetadataModel.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/MetadataModel.cs
new file mode 100644
index 00000000..ef6d4dd9
--- /dev/null
+++ b/src/StardewModdingAPI.Toolkit/Framework/ModData/MetadataModel.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace StardewModdingAPI.Toolkit.Framework.ModData
+{
+    /// <summary>The SMAPI predefined metadata.</summary>
+    internal class MetadataModel
+    {
+        /********
+        ** Accessors
+        ********/
+        /// <summary>Extra metadata about mods.</summary>
+        public IDictionary<string, ModDataModel> ModData { get; set; }
+    }
+}
diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataModel.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataModel.cs
new file mode 100644
index 00000000..e2b3ec1d
--- /dev/null
+++ b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataModel.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace StardewModdingAPI.Toolkit.Framework.ModData
+{
+    /// <summary>The raw mod metadata from SMAPI's internal mod list.</summary>
+    internal class ModDataModel
+    {
+        /*********
+        ** Accessors
+        *********/
+        /// <summary>The mod's current unique ID.</summary>
+        public string ID { get; set; }
+
+        /// <summary>The former mod IDs (if any).</summary>
+        /// <remarks>
+        /// This uses a custom format which uniquely identifies a mod across multiple versions and
+        /// supports matching other fields if no ID was specified. This doesn't include the latest
+        /// ID, if any. Format rules:
+        ///   1. If the mod's ID changed over time, multiple variants can be separated by the
+        ///      <c>|</c> character.
+        ///   2. Each variant can take one of two forms:
+        ///      - A simple string matching the mod's UniqueID value.
+        ///      - A JSON structure containing any of four manifest fields (ID, Name, Author, and
+        ///        EntryDll) to match.
+        /// </remarks>
+        public string FormerIDs { get; set; }
+
+        /// <summary>Maps local versions to a semantic version for update checks.</summary>
+        public IDictionary<string, string> MapLocalVersions { get; set; } = new Dictionary<string, string>();
+
+        /// <summary>Maps remote versions to a semantic version for update checks.</summary>
+        public IDictionary<string, string> MapRemoteVersions { get; set; } = new Dictionary<string, string>();
+
+        /// <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; }
+
+        /// <summary>The versioned field data.</summary>
+        /// <remarks>
+        /// This maps field names to values. This should be accessed via <see cref="GetFields"/>.
+        /// Format notes:
+        ///   - Each key consists of a field name prefixed with any combination of version range
+        ///     and <c>Default</c>, separated by pipes (whitespace trimmed). For example, <c>Name</c>
+        ///     will always override the name, <c>Default | Name</c> will only override a blank
+        ///     name, and <c>~1.1 | Default | Name</c> will override blank names up to version 1.1.
+        ///   - The version format is <c>min~max</c> (where either side can be blank for unbounded), or
+        ///     a single version number.
+        ///   - The field name itself corresponds to a <see cref="ModDataFieldKey"/> value.
+        /// </remarks>
+        public IDictionary<string, string> Fields { get; set; } = new Dictionary<string, string>();
+
+
+        /*********
+        ** Public methods
+        *********/
+        /// <summary>Get a parsed representation of the <see cref="Fields"/>.</summary>
+        public IEnumerable<ModDataField> GetFields()
+        {
+            foreach (KeyValuePair<string, string> pair in this.Fields)
+            {
+                // init fields
+                string packedKey = pair.Key;
+                string value = pair.Value;
+                bool isDefault = false;
+                ISemanticVersion lowerVersion = null;
+                ISemanticVersion upperVersion = null;
+
+                // parse
+                string[] parts = packedKey.Split('|').Select(p => p.Trim()).ToArray();
+                ModDataFieldKey fieldKey = (ModDataFieldKey)Enum.Parse(typeof(ModDataFieldKey), parts.Last(), ignoreCase: true);
+                foreach (string part in parts.Take(parts.Length - 1))
+                {
+                    // 'default'
+                    if (part.Equals("Default", StringComparison.InvariantCultureIgnoreCase))
+                    {
+                        isDefault = true;
+                        continue;
+                    }
+
+                    // version range
+                    if (part.Contains("~"))
+                    {
+                        string[] versionParts = part.Split(new[] { '~' }, 2);
+                        lowerVersion = versionParts[0] != "" ? new SemanticVersion(versionParts[0]) : null;
+                        upperVersion = versionParts[1] != "" ? new SemanticVersion(versionParts[1]) : null;
+                        continue;
+                    }
+
+                    // single version
+                    lowerVersion = new SemanticVersion(part);
+                    upperVersion = new SemanticVersion(part);
+                }
+
+                yield return new ModDataField(fieldKey, value, isDefault, lowerVersion, upperVersion);
+            }
+        }
+
+        /// <summary>Get the former mod IDs.</summary>
+        public IEnumerable<string> GetFormerIDs()
+        {
+            if (this.FormerIDs != null)
+            {
+                foreach (string id in this.FormerIDs.Split('|'))
+                    yield return id.Trim();
+            }
+        }
+
+
+        /*********
+        ** Private methods
+        *********/
+        /// <summary>The method invoked after JSON deserialisation.</summary>
+        /// <param name="context">The deserialisation context.</param>
+        [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;
+            }
+        }
+    }
+}
diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs
index 97ad0ca4..21c9cfca 100644
--- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs
+++ b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs
@@ -1,107 +1,66 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using System.Runtime.Serialization;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
 
 namespace StardewModdingAPI.Toolkit.Framework.ModData
 {
-    /// <summary>Raw mod metadata from SMAPI's internal mod list.</summary>
+    /// <summary>The parsed mod metadata from SMAPI's internal mod list.</summary>
     public class ModDataRecord
     {
-        /*********
-        ** Properties
-        *********/
-        /// <summary>This field stores properties that aren't mapped to another field before they're parsed into <see cref="Fields"/>.</summary>
-        [JsonExtensionData]
-        private IDictionary<string, JToken> ExtensionData;
-
-
         /*********
         ** Accessors
         *********/
+        /// <summary>The mod's default display name.</summary>
+        public string DisplayName { get; }
+
         /// <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>
-        /// This uses a custom format which uniquely identifies a mod across multiple versions and
-        /// supports matching other fields if no ID was specified. This doesn't include the latest
-        /// ID, if any. Format rules:
-        ///   1. If the mod's ID changed over time, multiple variants can be separated by the
-        ///      <c>|</c> character.
-        ///   2. Each variant can take one of two forms:
-        ///      - A simple string matching the mod's UniqueID value.
-        ///      - A JSON structure containing any of four manifest fields (ID, Name, Author, and
-        ///        EntryDll) to match.
-        /// </remarks>
-        public string FormerIDs { get; set; }
+        public string[] FormerIDs { get; }
 
         /// <summary>Maps local versions to a semantic version for update checks.</summary>
-        public IDictionary<string, string> MapLocalVersions { get; set; } = new Dictionary<string, string>();
+        public IDictionary<string, string> MapLocalVersions { get; }
 
         /// <summary>Maps remote versions to a semantic version for update checks.</summary>
-        public IDictionary<string, string> MapRemoteVersions { get; set; } = new Dictionary<string, string>();
+        public IDictionary<string, string> MapRemoteVersions { get; }
 
         /// <summary>The versioned field data.</summary>
-        /// <remarks>
-        /// This maps field names to values. This should be accessed via <see cref="GetFields"/>.
-        /// Format notes:
-        ///   - Each key consists of a field name prefixed with any combination of version range
-        ///     and <c>Default</c>, separated by pipes (whitespace trimmed). For example, <c>Name</c>
-        ///     will always override the name, <c>Default | Name</c> will only override a blank
-        ///     name, and <c>~1.1 | Default | Name</c> will override blank names up to version 1.1.
-        ///   - The version format is <c>min~max</c> (where either side can be blank for unbounded), or
-        ///     a single version number.
-        ///   - The field name itself corresponds to a <see cref="ModDataFieldKey"/> value.
-        /// </remarks>
-        public IDictionary<string, string> Fields { get; set; } = new Dictionary<string, string>();
+        public ModDataField[] Fields { get; }
 
 
         /*********
         ** Public methods
         *********/
-        /// <summary>Get a parsed representation of the <see cref="Fields"/>.</summary>
-        public IEnumerable<ModDataField> GetFields()
+        /// <summary>Construct an instance.</summary>
+        /// <param name="displayName">The mod's default display name.</param>
+        /// <param name="model">The raw data model.</param>
+        internal ModDataRecord(string displayName, ModDataModel model)
         {
-            foreach (KeyValuePair<string, string> pair in this.Fields)
-            {
-                // init fields
-                string packedKey = pair.Key;
-                string value = pair.Value;
-                bool isDefault = false;
-                ISemanticVersion lowerVersion = null;
-                ISemanticVersion upperVersion = null;
-
-                // parse
-                string[] parts = packedKey.Split('|').Select(p => p.Trim()).ToArray();
-                ModDataFieldKey fieldKey = (ModDataFieldKey)Enum.Parse(typeof(ModDataFieldKey), parts.Last(), ignoreCase: true);
-                foreach (string part in parts.Take(parts.Length - 1))
-                {
-                    // 'default'
-                    if (part.Equals("Default", StringComparison.InvariantCultureIgnoreCase))
-                    {
-                        isDefault = true;
-                        continue;
-                    }
-
-                    // version range
-                    if (part.Contains("~"))
-                    {
-                        string[] versionParts = part.Split(new[] { '~' }, 2);
-                        lowerVersion = versionParts[0] != "" ? new SemanticVersion(versionParts[0]) : null;
-                        upperVersion = versionParts[1] != "" ? new SemanticVersion(versionParts[1]) : null;
-                        continue;
-                    }
-
-                    // single version
-                    lowerVersion = new SemanticVersion(part);
-                    upperVersion = new SemanticVersion(part);
-                }
+            this.DisplayName = displayName;
+            this.ID = model.ID;
+            this.FormerIDs = model.GetFormerIDs().ToArray();
+            this.MapLocalVersions = new Dictionary<string, string>(model.MapLocalVersions, StringComparer.InvariantCultureIgnoreCase);
+            this.MapRemoteVersions = new Dictionary<string, string>(model.MapRemoteVersions, StringComparer.InvariantCultureIgnoreCase);
+            this.Fields = model.GetFields().ToArray();
+        }
 
-                yield return new ModDataField(fieldKey, value, isDefault, lowerVersion, upperVersion);
+        /// <summary>Get whether the mod has (or previously had) the given ID.</summary>
+        /// <param name="id">The mod ID.</param>
+        public bool HasID(string id)
+        {
+            // try main ID
+            if (this.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase))
+                return true;
+
+            // try former IDs
+            foreach (string formerID in this.FormerIDs)
+            {
+                if (formerID.Equals(id, StringComparison.InvariantCultureIgnoreCase))
+                    return true;
             }
+
+            return false;
         }
 
         /// <summary>Get a semantic local version for update checks.</summary>
@@ -127,20 +86,39 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
                 : version;
         }
 
-
-        /*********
-        ** Private methods
-        *********/
-        /// <summary>The method invoked after JSON deserialisation.</summary>
-        /// <param name="context">The deserialisation context.</param>
-        [OnDeserialized]
-        private void OnDeserialized(StreamingContext context)
+        /// <summary>Get a parsed representation of the <see cref="ModDataRecord.Fields"/> which match a given manifest.</summary>
+        /// <param name="manifest">The manifest to match.</param>
+        public ModDataRecordVersionedFields GetVersionedFields(IManifest manifest)
         {
-            if (this.ExtensionData != null)
+            ModDataRecordVersionedFields parsed = new ModDataRecordVersionedFields { DisplayName = this.DisplayName, DataRecord = this };
+            foreach (ModDataField field in this.Fields.Where(field => field.IsMatch(manifest)))
             {
-                this.Fields = this.ExtensionData.ToDictionary(p => p.Key, p => p.Value.ToString());
-                this.ExtensionData = null;
+                switch (field.Key)
+                {
+                    // update key
+                    case ModDataFieldKey.UpdateKey:
+                        parsed.UpdateKey = field.Value;
+                        break;
+
+                    // alternative URL
+                    case ModDataFieldKey.AlternativeUrl:
+                        parsed.AlternativeUrl = field.Value;
+                        break;
+
+                    // status
+                    case ModDataFieldKey.Status:
+                        parsed.Status = (ModStatus)Enum.Parse(typeof(ModStatus), field.Value, ignoreCase: true);
+                        parsed.StatusUpperVersion = field.UpperVersion;
+                        break;
+
+                    // status reason phrase
+                    case ModDataFieldKey.StatusReasonPhrase:
+                        parsed.StatusReasonPhrase = field.Value;
+                        break;
+                }
             }
+
+            return parsed;
         }
     }
 }
diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs
new file mode 100644
index 00000000..3601fc53
--- /dev/null
+++ b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs
@@ -0,0 +1,51 @@
+namespace StardewModdingAPI.Toolkit.Framework.ModData
+{
+    /// <summary>The versioned fields from a <see cref="ModDataRecord"/> for a specific manifest.</summary>
+    public class ModDataRecordVersionedFields
+    {
+        /*********
+        ** Accessors
+        *********/
+        /// <summary>The underlying data record.</summary>
+        public ModDataRecord DataRecord { get; set; }
+
+        /// <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 alternative URL the player can check for an updated version.</summary>
+        public string AlternativeUrl { 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; }
+
+        /// <summary>The upper version for which the <see cref="Status"/> applies (if any).</summary>
+        public ISemanticVersion StatusUpperVersion { get; set; }
+
+
+        /*********
+        ** Public methods
+        *********/
+        /// <summary>Get a semantic local version for update checks.</summary>
+        /// <param name="version">The remote version to normalise.</param>
+        public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version)
+        {
+            return this.DataRecord.GetLocalVersionForUpdateChecks(version);
+        }
+
+        /// <summary>Get a semantic remote version for update checks.</summary>
+        /// <param name="version">The remote version to normalise.</param>
+        public ISemanticVersion GetRemoteVersionForUpdateChecks(string version)
+        {
+            string rawVersion = this.DataRecord.GetRemoteVersionForUpdateChecks(version);
+            return rawVersion != null
+                ? new SemanticVersion(rawVersion)
+                : null;
+        }
+    }
+}
diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDatabase.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDatabase.cs
index c60d2bcb..a12e3c67 100644
--- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDatabase.cs
+++ b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDatabase.cs
@@ -11,7 +11,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
         ** Properties
         *********/
         /// <summary>The underlying mod data records indexed by default display name.</summary>
-        private readonly IDictionary<string, ModDataRecord> Records;
+        private readonly ModDataRecord[] Records;
 
         /// <summary>Get an update URL for an update key (if valid).</summary>
         private readonly Func<string, string> GetUpdateUrl;
@@ -22,63 +22,23 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
         *********/
         /// <summary>Construct an empty instance.</summary>
         public ModDatabase()
-        : this(new Dictionary<string, ModDataRecord>(), key => null) { }
+        : this(new ModDataRecord[0], key => null) { }
 
         /// <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(IDictionary<string, ModDataRecord> records, Func<string, string> getUpdateUrl)
+        public ModDatabase(IEnumerable<ModDataRecord> records, Func<string, string> getUpdateUrl)
         {
-            this.Records = records;
+            this.Records = records.ToArray();
             this.GetUpdateUrl = getUpdateUrl;
         }
 
-        /// <summary>Get a parsed representation of the <see cref="ModDataRecord.Fields"/> which match a given manifest.</summary>
-        /// <param name="manifest">The manifest to match.</param>
-        public ParsedModDataRecord GetParsed(IManifest manifest)
+        /// <summary>Get a mod data record.</summary>
+        /// <param name="modID">The unique mod ID.</param>
+        public ModDataRecord Get(string modID)
         {
-            // get raw record
-            if (!this.TryGetRaw(manifest?.UniqueID, out string displayName, out ModDataRecord record))
-                return null;
-
-            // parse fields
-            ParsedModDataRecord parsed = new ParsedModDataRecord { DisplayName = displayName, DataRecord = record };
-            foreach (ModDataField field in record.GetFields().Where(field => field.IsMatch(manifest)))
-            {
-                switch (field.Key)
-                {
-                    // update key
-                    case ModDataFieldKey.UpdateKey:
-                        parsed.UpdateKey = field.Value;
-                        break;
-
-                    // alternative URL
-                    case ModDataFieldKey.AlternativeUrl:
-                        parsed.AlternativeUrl = field.Value;
-                        break;
-
-                    // status
-                    case ModDataFieldKey.Status:
-                        parsed.Status = (ModStatus)Enum.Parse(typeof(ModStatus), field.Value, ignoreCase: true);
-                        parsed.StatusUpperVersion = field.UpperVersion;
-                        break;
-
-                    // status reason phrase
-                    case ModDataFieldKey.StatusReasonPhrase:
-                        parsed.StatusReasonPhrase = field.Value;
-                        break;
-                }
-            }
-
-            return parsed;
-        }
-
-        /// <summary>Get the display name for a given mod ID (if available).</summary>
-        /// <param name="id">The unique mod ID.</param>
-        public string GetDisplayNameFor(string id)
-        {
-            return this.TryGetRaw(id, out string displayName, out ModDataRecord _)
-                ? displayName
+            return !string.IsNullOrWhiteSpace(modID)
+                ? this.Records.FirstOrDefault(p => p.HasID(modID))
                 : null;
         }
 
@@ -86,55 +46,14 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
         /// <param name="id">The unique mod ID.</param>
         public string GetModPageUrlFor(string id)
         {
-            // get raw record
-            if (!this.TryGetRaw(id, out string _, out ModDataRecord record))
-                return null;
-
             // get update key
-            ModDataField updateKeyField = record.GetFields().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;
 
             // get update URL
             return this.GetUpdateUrl(updateKeyField.Value);
         }
-
-
-        /*********
-        ** Private models
-        *********/
-        /// <summary>Get a raw data record.</summary>
-        /// <param name="id">The mod ID to match.</param>
-        /// <param name="displayName">The mod's default display name.</param>
-        /// <param name="record">The raw mod record.</param>
-        private bool TryGetRaw(string id, out string displayName, out ModDataRecord record)
-        {
-            if (!string.IsNullOrWhiteSpace(id))
-            {
-                foreach (var entry in this.Records)
-                {
-                    displayName = entry.Key;
-                    record = entry.Value;
-
-                    // try main ID
-                    if (record.ID != null && record.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase))
-                        return true;
-
-                    // try former IDs
-                    if (record.FormerIDs != null)
-                    {
-                        foreach (string part in record.FormerIDs.Split('|'))
-                        {
-                            if (part.Trim().Equals(id, StringComparison.InvariantCultureIgnoreCase))
-                                return true;
-                        }
-                    }
-                }
-            }
-
-            displayName = null;
-            record = null;
-            return false;
-        }
     }
 }
diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ParsedModDataRecord.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ParsedModDataRecord.cs
deleted file mode 100644
index 74f11ea5..00000000
--- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ParsedModDataRecord.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-namespace StardewModdingAPI.Toolkit.Framework.ModData
-{
-    /// <summary>A parsed representation of the fields from a <see cref="ModDataRecord"/> for a specific manifest.</summary>
-    public class ParsedModDataRecord
-    {
-        /*********
-        ** Accessors
-        *********/
-        /// <summary>The underlying data record.</summary>
-        public ModDataRecord DataRecord { get; set; }
-
-        /// <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 alternative URL the player can check for an updated version.</summary>
-        public string AlternativeUrl { 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; }
-
-        /// <summary>The upper version for which the <see cref="Status"/> applies (if any).</summary>
-        public ISemanticVersion StatusUpperVersion { get; set; }
-
-
-        /*********
-        ** Public methods
-        *********/
-        /// <summary>Get a semantic local version for update checks.</summary>
-        /// <param name="version">The remote version to normalise.</param>
-        public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version)
-        {
-            return this.DataRecord.GetLocalVersionForUpdateChecks(version);
-        }
-
-        /// <summary>Get a semantic remote version for update checks.</summary>
-        /// <param name="version">The remote version to normalise.</param>
-        public ISemanticVersion GetRemoteVersionForUpdateChecks(string version)
-        {
-            string rawVersion = this.DataRecord.GetRemoteVersionForUpdateChecks(version);
-            return rawVersion != null
-                ? new SemanticVersion(rawVersion)
-                : null;
-        }
-    }
-}
diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/SMetadata.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/SMetadata.cs
deleted file mode 100644
index 9553cca9..00000000
--- a/src/StardewModdingAPI.Toolkit/Framework/ModData/SMetadata.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Collections.Generic;
-
-namespace StardewModdingAPI.Toolkit.Framework.ModData
-{
-    /// <summary>The SMAPI predefined metadata.</summary>
-    internal class SMetadata
-    {
-        /********
-        ** Accessors
-        ********/
-        /// <summary>Extra metadata about mods.</summary>
-        public IDictionary<string, ModDataRecord> ModData { get; set; }
-    }
-}
-- 
cgit