summaryrefslogtreecommitdiff
path: root/src/SMAPI.Toolkit/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI.Toolkit/Framework')
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs22
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs16
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs12
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs4
-rw-r--r--src/SMAPI.Toolkit/Framework/SemanticVersionReader.cs126
5 files changed, 144 insertions, 36 deletions
diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs
index f1bcfccc..2f58a3f1 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs
@@ -1,5 +1,3 @@
-using System;
-
namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
{
/// <summary>Metadata about a mod.</summary>
@@ -17,26 +15,6 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>Optional extended data which isn't needed for update checks.</summary>
public ModExtendedMetadataModel Metadata { get; set; }
- /// <summary>The main version.</summary>
- [Obsolete]
- public ModEntryVersionModel Main { get; set; }
-
- /// <summary>The latest optional version, if newer than <see cref="Main"/>.</summary>
- [Obsolete]
- public ModEntryVersionModel Optional { get; set; }
-
- /// <summary>The latest unofficial version, if newer than <see cref="Main"/> and <see cref="Optional"/>.</summary>
- [Obsolete]
- public ModEntryVersionModel Unofficial { get; set; }
-
- /// <summary>The latest unofficial version for the current Stardew Valley or SMAPI beta, if any (see <see cref="HasBetaInfo"/>).</summary>
- [Obsolete]
- public ModEntryVersionModel UnofficialForBeta { get; set; }
-
- /// <summary>Whether a Stardew Valley or SMAPI beta which affects mod compatibility is in progress. If this is true, <see cref="UnofficialForBeta"/> should be used for beta versions of SMAPI instead of <see cref="Unofficial"/>.</summary>
- [Obsolete]
- public bool? HasBetaInfo { get; set; }
-
/// <summary>The errors that occurred while fetching update data.</summary>
public string[] Errors { get; set; } = new string[0];
}
diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs
index 4a697585..8c21e4e0 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs
@@ -55,7 +55,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>The latest unofficial version, if newer than <see cref="Main"/> and <see cref="Optional"/>.</summary>
public ModEntryVersionModel Unofficial { get; set; }
- /// <summary>The latest unofficial version for the current Stardew Valley or SMAPI beta, if any (see <see cref="HasBetaInfo"/>).</summary>
+ /// <summary>The latest unofficial version for the current Stardew Valley or SMAPI beta, if any.</summary>
public ModEntryVersionModel UnofficialForBeta { get; set; }
/****
@@ -84,6 +84,15 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>The beta game or SMAPI version which broke this mod, if applicable.</summary>
public string BetaBrokeIn { get; set; }
+ /****
+ ** Version mappings
+ ****/
+ /// <summary>Maps local versions to a semantic version for update checks.</summary>
+ public IDictionary<string, string> MapLocalVersions { get; set; }
+
+ /// <summary>Maps remote versions to a semantic version for update checks.</summary>
+ public IDictionary<string, string> MapRemoteVersions { get; set; }
+
/*********
** Public methods
@@ -127,13 +136,16 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
this.BetaCompatibilityStatus = wiki.BetaCompatibility?.Status;
this.BetaCompatibilitySummary = wiki.BetaCompatibility?.Summary;
this.BetaBrokeIn = wiki.BetaCompatibility?.BrokeIn;
+
+ this.MapLocalVersions = wiki.MapLocalVersions;
+ this.MapRemoteVersions = wiki.MapRemoteVersions;
}
// internal DB data
if (db != null)
{
this.ID = this.ID.Union(db.FormerIDs).ToArray();
- this.Name = this.Name ?? db.DisplayName;
+ this.Name ??= db.DisplayName;
}
}
diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
index 384f23fc..c829c0f4 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
@@ -102,6 +102,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
string anchor = this.GetAttribute(node, "id");
string contentPackFor = this.GetAttribute(node, "data-content-pack-for");
string devNote = this.GetAttribute(node, "data-dev-note");
+ string pullRequestUrl = this.GetAttribute(node, "data-pr");
IDictionary<string, string> mapLocalVersions = this.GetAttributeAsVersionMapping(node, "data-map-local-versions");
IDictionary<string, string> mapRemoteVersions = this.GetAttributeAsVersionMapping(node, "data-map-remote-versions");
@@ -132,15 +133,6 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
}
}
- // parse links
- List<Tuple<Uri, string>> metadataLinks = new List<Tuple<Uri, string>>();
- foreach (HtmlNode linkElement in node.Descendants("td").Last().Descendants("a").Skip(1)) // skip anchor link
- {
- string text = linkElement.InnerText.Trim();
- Uri url = new Uri(linkElement.GetAttributeValue("href", ""));
- metadataLinks.Add(Tuple.Create(url, text));
- }
-
// yield model
yield return new WikiModEntry
{
@@ -159,7 +151,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
Compatibility = compatibility,
BetaCompatibility = betaCompatibility,
Warnings = warnings,
- MetadataLinks = metadataLinks.ToArray(),
+ PullRequestUrl = pullRequestUrl,
DevNote = devNote,
MapLocalVersions = mapLocalVersions,
MapRemoteVersions = mapRemoteVersions,
diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs
index 931dcd43..474dce3d 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs
@@ -57,8 +57,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
/// <summary>The human-readable warnings for players about this mod.</summary>
public string[] Warnings { get; set; }
- /// <summary>Extra metadata links (usually for open pull requests).</summary>
- public Tuple<Uri, string>[] MetadataLinks { get; set; }
+ /// <summary>The URL of the pull request which submits changes for an unofficial update to the author, if any.</summary>
+ public string PullRequestUrl { get; set; }
/// <summary>Special notes intended for developers who maintain unofficial updates or submit pull requests. </summary>
public string DevNote { get; set; }
diff --git a/src/SMAPI.Toolkit/Framework/SemanticVersionReader.cs b/src/SMAPI.Toolkit/Framework/SemanticVersionReader.cs
new file mode 100644
index 00000000..489e1c4d
--- /dev/null
+++ b/src/SMAPI.Toolkit/Framework/SemanticVersionReader.cs
@@ -0,0 +1,126 @@
+namespace StardewModdingAPI.Toolkit.Framework
+{
+ /// <summary>Reads strings into a semantic version.</summary>
+ internal static class SemanticVersionReader
+ {
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Parse a semantic version string.</summary>
+ /// <param name="versionStr">The version string to parse.</param>
+ /// <param name="allowNonStandard">Whether to recognize non-standard semver extensions.</param>
+ /// <param name="major">The major version incremented for major API changes.</param>
+ /// <param name="minor">The minor version incremented for backwards-compatible changes.</param>
+ /// <param name="patch">The patch version for backwards-compatible fixes.</param>
+ /// <param name="platformRelease">The platform-specific version (if applicable).</param>
+ /// <param name="prereleaseTag">An optional prerelease tag.</param>
+ /// <param name="buildMetadata">Optional build metadata. This is ignored when determining version precedence.</param>
+ /// <returns>Returns whether the version was successfully parsed.</returns>
+ public static bool TryParse(string versionStr, bool allowNonStandard, out int major, out int minor, out int patch, out int platformRelease, out string prereleaseTag, out string buildMetadata)
+ {
+ // init
+ major = 0;
+ minor = 0;
+ patch = 0;
+ platformRelease = 0;
+ prereleaseTag = null;
+ buildMetadata = null;
+
+ // normalize
+ versionStr = versionStr?.Trim();
+ if (string.IsNullOrWhiteSpace(versionStr))
+ return false;
+ char[] raw = versionStr.ToCharArray();
+
+ // read major/minor version
+ int i = 0;
+ if (!TryParseVersionPart(raw, ref i, out major) || !TryParseLiteral(raw, ref i, '.') || !TryParseVersionPart(raw, ref i, out minor))
+ return false;
+
+ // read optional patch version
+ if (TryParseLiteral(raw, ref i, '.') && !TryParseVersionPart(raw, ref i, out patch))
+ return false;
+
+ // read optional non-standard platform release version
+ if (allowNonStandard && TryParseLiteral(raw, ref i, '.') && !TryParseVersionPart(raw, ref i, out platformRelease))
+ return false;
+
+ // read optional prerelease tag
+ if (TryParseLiteral(raw, ref i, '-') && !TryParseTag(raw, ref i, out prereleaseTag))
+ return false;
+
+ // read optional build tag
+ if (TryParseLiteral(raw, ref i, '+') && !TryParseTag(raw, ref i, out buildMetadata))
+ return false;
+
+ // validate
+ return i == versionStr.Length; // valid if we're at the end
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Try to parse the next characters in a queue as a numeric part.</summary>
+ /// <param name="raw">The raw characters to parse.</param>
+ /// <param name="index">The index of the next character to read.</param>
+ /// <param name="part">The parsed part.</param>
+ private static bool TryParseVersionPart(char[] raw, ref int index, out int part)
+ {
+ part = 0;
+
+ // take digits
+ string str = "";
+ for (int i = index; i < raw.Length && char.IsDigit(raw[i]); i++)
+ str += raw[i];
+
+ // validate
+ if (str.Length == 0)
+ return false;
+ if (str.Length > 1 && str[0] == '0')
+ return false; // can't have leading zeros
+
+ // parse
+ part = int.Parse(str);
+ index += str.Length;
+ return true;
+ }
+
+ /// <summary>Try to parse a literal character.</summary>
+ /// <param name="raw">The raw characters to parse.</param>
+ /// <param name="index">The index of the next character to read.</param>
+ /// <param name="ch">The expected character.</param>
+ private static bool TryParseLiteral(char[] raw, ref int index, char ch)
+ {
+ if (index >= raw.Length || raw[index] != ch)
+ return false;
+
+ index++;
+ return true;
+ }
+
+ /// <summary>Try to parse a tag.</summary>
+ /// <param name="raw">The raw characters to parse.</param>
+ /// <param name="index">The index of the next character to read.</param>
+ /// <param name="tag">The parsed tag.</param>
+ private static bool TryParseTag(char[] raw, ref int index, out string tag)
+ {
+ // read tag length
+ int length = 0;
+ for (int i = index; i < raw.Length && (char.IsLetterOrDigit(raw[i]) || raw[i] == '-' || raw[i] == '.'); i++)
+ length++;
+
+ // validate
+ if (length == 0)
+ {
+ tag = null;
+ return false;
+ }
+
+ // parse
+ tag = new string(raw, index, length);
+ index += length;
+ return true;
+ }
+ }
+}