summaryrefslogtreecommitdiff
path: root/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs')
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs105
1 files changed, 70 insertions, 35 deletions
diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
index da312471..f85e82e1 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
@@ -6,6 +6,7 @@ using System.Net;
using System.Threading.Tasks;
using HtmlAgilityPack;
using Pathoschild.Http.Client;
+using StardewModdingAPI.Toolkit.Framework.UpdateData;
namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
{
@@ -55,13 +56,33 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
if (betaVersion == stableVersion)
betaVersion = null;
- // find mod entries
- HtmlNodeCollection modNodes = doc.DocumentNode.SelectNodes("//table[@id='mod-list']//tr[@class='mod']");
- if (modNodes == null)
- throw new InvalidOperationException("Can't parse wiki compatibility list, no mods found.");
+ // parse mod data overrides
+ Dictionary<string, WikiDataOverrideEntry> overrides = new Dictionary<string, WikiDataOverrideEntry>(StringComparer.OrdinalIgnoreCase);
+ {
+ HtmlNodeCollection modNodes = doc.DocumentNode.SelectNodes("//table[@id='mod-overrides-list']//tr[@class='mod']");
+ if (modNodes == null)
+ throw new InvalidOperationException("Can't parse wiki compatibility list, no mod data overrides section found.");
+
+ foreach (var entry in this.ParseOverrideEntries(modNodes))
+ {
+ if (entry.Ids?.Any() != true || !entry.HasChanges)
+ continue;
+
+ foreach (string id in entry.Ids)
+ overrides[id] = entry;
+ }
+ }
+
+ // parse mod entries
+ WikiModEntry[] mods;
+ {
+ HtmlNodeCollection modNodes = doc.DocumentNode.SelectNodes("//table[@id='mod-list']//tr[@class='mod']");
+ if (modNodes == null)
+ throw new InvalidOperationException("Can't parse wiki compatibility list, no mods found.");
+ mods = this.ParseModEntries(modNodes, overrides).ToArray();
+ }
- // parse
- WikiModEntry[] mods = this.ParseEntries(modNodes).ToArray();
+ // build model
return new WikiModList
{
StableVersion = stableVersion,
@@ -82,7 +103,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
*********/
/// <summary>Parse valid mod compatibility entries.</summary>
/// <param name="nodes">The HTML compatibility entries.</param>
- private IEnumerable<WikiModEntry> ParseEntries(IEnumerable<HtmlNode> nodes)
+ /// <param name="overridesById">The mod data overrides to apply, if any.</param>
+ private IEnumerable<WikiModEntry> ParseModEntries(IEnumerable<HtmlNode> nodes, IDictionary<string, WikiDataOverrideEntry> overridesById)
{
foreach (HtmlNode node in nodes)
{
@@ -103,9 +125,6 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
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");
- string[] changeUpdateKeys = this.GetAttributeAsCsv(node, "data-change-update-keys");
// parse stable compatibility
WikiCompatibilityInfo compatibility = new WikiCompatibilityInfo
@@ -134,6 +153,11 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
}
}
+ // find data overrides
+ WikiDataOverrideEntry overrides = ids
+ .Select(id => overridesById.TryGetValue(id, out overrides) ? overrides : null)
+ .FirstOrDefault(p => p != null);
+
// yield model
yield return new WikiModEntry
{
@@ -154,14 +178,35 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
Warnings = warnings,
PullRequestUrl = pullRequestUrl,
DevNote = devNote,
- ChangeUpdateKeys = changeUpdateKeys,
- MapLocalVersions = mapLocalVersions,
- MapRemoteVersions = mapRemoteVersions,
+ Overrides = overrides,
Anchor = anchor
};
}
}
+ /// <summary>Parse valid mod data override entries.</summary>
+ /// <param name="nodes">The HTML mod data override entries.</param>
+ private IEnumerable<WikiDataOverrideEntry> ParseOverrideEntries(IEnumerable<HtmlNode> nodes)
+ {
+ foreach (HtmlNode node in nodes)
+ {
+ yield return new WikiDataOverrideEntry
+ {
+ Ids = this.GetAttributeAsCsv(node, "data-id"),
+ ChangeLocalVersions = this.GetAttributeAsChangeDescriptor(node, "data-local-version",
+ raw => SemanticVersion.TryParse(raw, out ISemanticVersion version) ? version.ToString() : raw
+ ),
+ ChangeRemoteVersions = this.GetAttributeAsChangeDescriptor(node, "data-remote-version",
+ raw => SemanticVersion.TryParse(raw, out ISemanticVersion version) ? version.ToString() : raw
+ ),
+
+ ChangeUpdateKeys = this.GetAttributeAsChangeDescriptor(node, "data-update-keys",
+ raw => UpdateKey.TryParse(raw, out UpdateKey key) ? key.ToString() : raw
+ )
+ };
+ }
+ }
+
/// <summary>Get an attribute value.</summary>
/// <param name="element">The element whose attributes to read.</param>
/// <param name="name">The attribute name.</param>
@@ -174,6 +219,18 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
return WebUtility.HtmlDecode(value);
}
+ /// <summary>Get an attribute value and parse it as a change descriptor.</summary>
+ /// <param name="element">The element whose attributes to read.</param>
+ /// <param name="name">The attribute name.</param>
+ /// <param name="formatValue">Format an raw entry value when applying changes.</param>
+ private ChangeDescriptor GetAttributeAsChangeDescriptor(HtmlNode element, string name, Func<string, string> formatValue)
+ {
+ string raw = this.GetAttribute(element, name);
+ return raw != null
+ ? ChangeDescriptor.Parse(raw, out _, formatValue)
+ : null;
+ }
+
/// <summary>Get an attribute value and parse it as a comma-delimited list of strings.</summary>
/// <param name="element">The element whose attributes to read.</param>
/// <param name="name">The attribute name.</param>
@@ -221,28 +278,6 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
return null;
}
- /// <summary>Get an attribute value and parse it as a version mapping.</summary>
- /// <param name="element">The element whose attributes to read.</param>
- /// <param name="name">The attribute name.</param>
- private IDictionary<string, string> GetAttributeAsVersionMapping(HtmlNode element, string name)
- {
- // get raw value
- string raw = this.GetAttribute(element, name);
- if (raw?.Contains("→") != true)
- return null;
-
- // parse
- // Specified on the wiki in the form "remote version → mapped version; another remote version → mapped version"
- IDictionary<string, string> map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- foreach (string pair in raw.Split(';'))
- {
- string[] versions = pair.Split('→');
- if (versions.Length == 2 && !string.IsNullOrWhiteSpace(versions[0]) && !string.IsNullOrWhiteSpace(versions[1]))
- map[versions[0].Trim()] = versions[1].Trim();
- }
- return map;
- }
-
/// <summary>Get the text of an element with the given class name.</summary>
/// <param name="container">The metadata container.</param>
/// <param name="className">The field name.</param>