summaryrefslogtreecommitdiff
path: root/src/SMAPI.Web/Controllers
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-04-12 19:15:39 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-04-12 19:15:39 -0400
commit0b48c1748b354458059c7607415288de072b01e9 (patch)
treef63fd950f565d363414eb692be9024895cdea174 /src/SMAPI.Web/Controllers
parent9fbed0fa1f28a9b0fe0b952a78b10e2d475adb03 (diff)
downloadSMAPI-0b48c1748b354458059c7607415288de072b01e9.tar.gz
SMAPI-0b48c1748b354458059c7607415288de072b01e9.tar.bz2
SMAPI-0b48c1748b354458059c7607415288de072b01e9.zip
enable nullable annotations in the web project & related code (#837)
Diffstat (limited to 'src/SMAPI.Web/Controllers')
-rw-r--r--src/SMAPI.Web/Controllers/IndexController.cs12
-rw-r--r--src/SMAPI.Web/Controllers/JsonValidatorController.cs46
-rw-r--r--src/SMAPI.Web/Controllers/LogParserController.cs6
-rw-r--r--src/SMAPI.Web/Controllers/ModsApiController.cs70
-rw-r--r--src/SMAPI.Web/Controllers/ModsController.cs7
5 files changed, 69 insertions, 72 deletions
diff --git a/src/SMAPI.Web/Controllers/IndexController.cs b/src/SMAPI.Web/Controllers/IndexController.cs
index f7834b9c..522d77cd 100644
--- a/src/SMAPI.Web/Controllers/IndexController.cs
+++ b/src/SMAPI.Web/Controllers/IndexController.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -59,8 +57,8 @@ namespace StardewModdingAPI.Web.Controllers
{
// choose versions
ReleaseVersion[] versions = await this.GetReleaseVersionsAsync();
- ReleaseVersion stableVersion = versions.LastOrDefault(version => !version.IsForDevs);
- ReleaseVersion stableVersionForDevs = versions.LastOrDefault(version => version.IsForDevs);
+ ReleaseVersion? stableVersion = versions.LastOrDefault(version => !version.IsForDevs);
+ ReleaseVersion? stableVersionForDevs = versions.LastOrDefault(version => version.IsForDevs);
// render view
IndexVersionModel stableVersionModel = stableVersion != null
@@ -91,7 +89,7 @@ namespace StardewModdingAPI.Web.Controllers
entry.AbsoluteExpiration = DateTimeOffset.UtcNow.Add(this.CacheTime);
// get latest stable release
- GitRelease release = await this.GitHub.GetLatestReleaseAsync(this.RepositoryName, includePrerelease: false);
+ GitRelease? release = await this.GitHub.GetLatestReleaseAsync(this.RepositoryName, includePrerelease: false);
// strip 'noinclude' blocks from release description
if (release != null)
@@ -113,7 +111,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <summary>Get a parsed list of SMAPI downloads for a release.</summary>
/// <param name="release">The GitHub release.</param>
- private IEnumerable<ReleaseVersion> ParseReleaseVersions(GitRelease release)
+ private IEnumerable<ReleaseVersion> ParseReleaseVersions(GitRelease? release)
{
if (release?.Assets == null)
yield break;
@@ -124,7 +122,7 @@ namespace StardewModdingAPI.Web.Controllers
continue;
Match match = Regex.Match(asset.FileName, @"SMAPI-(?<version>[\d\.]+(?:-.+)?)-installer(?<forDevs>-for-developers)?.zip");
- if (!match.Success || !SemanticVersion.TryParse(match.Groups["version"].Value, out ISemanticVersion version))
+ if (!match.Success || !SemanticVersion.TryParse(match.Groups["version"].Value, out ISemanticVersion? version))
continue;
bool isForDevs = match.Groups["forDevs"].Success;
diff --git a/src/SMAPI.Web/Controllers/JsonValidatorController.cs b/src/SMAPI.Web/Controllers/JsonValidatorController.cs
index 5791d834..e78aeeb6 100644
--- a/src/SMAPI.Web/Controllers/JsonValidatorController.cs
+++ b/src/SMAPI.Web/Controllers/JsonValidatorController.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.IO;
@@ -66,7 +64,7 @@ namespace StardewModdingAPI.Web.Controllers
[Route("json/{schemaName}")]
[Route("json/{schemaName}/{id}")]
[Route("json/{schemaName}/{id}/{operation}")]
- public async Task<ViewResult> Index(string schemaName = null, string id = null, string operation = null)
+ public async Task<ViewResult> Index(string? schemaName = null, string? id = null, string? operation = null)
{
// parse arguments
schemaName = this.NormalizeSchemaName(schemaName);
@@ -81,7 +79,7 @@ namespace StardewModdingAPI.Web.Controllers
return this.View("Index", result);
// fetch raw JSON
- StoredFileInfo file = await this.Storage.GetAsync(id, renew);
+ StoredFileInfo file = await this.Storage.GetAsync(id!, renew);
if (string.IsNullOrWhiteSpace(file.Content))
return this.View("Index", result.SetUploadError("The JSON file seems to be empty."));
result.SetContent(file.Content, expiry: file.Expiry, uploadWarning: file.Warning);
@@ -105,7 +103,7 @@ namespace StardewModdingAPI.Web.Controllers
}
catch (JsonReaderException ex)
{
- return this.View("Index", result.AddErrors(new JsonValidatorErrorModel(ex.LineNumber, ex.Path, ex.Message, ErrorType.None)));
+ return this.View("Index", result.AddErrors(new JsonValidatorErrorModel(ex.LineNumber, ex.Path!, ex.Message, ErrorType.None)));
}
// format JSON
@@ -121,7 +119,7 @@ namespace StardewModdingAPI.Web.Controllers
// load schema
JSchema schema;
{
- FileInfo schemaFile = this.FindSchemaFile(schemaName);
+ FileInfo? schemaFile = this.FindSchemaFile(schemaName);
if (schemaFile == null)
return this.View("Index", result.SetParseError($"Invalid schema '{schemaName}'."));
schema = JSchema.Parse(System.IO.File.ReadAllText(schemaFile.FullName));
@@ -144,7 +142,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <summary>Save raw JSON data.</summary>
[HttpPost, AllowLargePosts]
[Route("json")]
- public async Task<ActionResult> PostAsync(JsonValidatorRequestModel request)
+ public async Task<ActionResult> PostAsync(JsonValidatorRequestModel? request)
{
if (request == null)
return this.View("Index", this.GetModel(null, null, isEditView: true).SetUploadError("The request seems to be invalid."));
@@ -163,7 +161,7 @@ namespace StardewModdingAPI.Web.Controllers
return this.View("Index", this.GetModel(result.ID, schemaName, isEditView: true).SetContent(input, null).SetUploadError(result.UploadError));
// redirect to view
- return this.Redirect(this.Url.PlainAction("Index", "JsonValidator", new { schemaName, id = result.ID }));
+ return this.Redirect(this.Url.PlainAction("Index", "JsonValidator", new { schemaName, id = result.ID })!);
}
@@ -174,14 +172,14 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="pasteID">The stored file ID.</param>
/// <param name="schemaName">The schema name with which the JSON was validated.</param>
/// <param name="isEditView">Whether to show the edit view.</param>
- private JsonValidatorModel GetModel(string pasteID, string schemaName, bool isEditView)
+ private JsonValidatorModel GetModel(string? pasteID, string? schemaName, bool isEditView)
{
return new JsonValidatorModel(pasteID, schemaName, this.SchemaFormats, isEditView);
}
/// <summary>Get a normalized schema name, or the <see cref="DefaultSchemaID"/> if blank.</summary>
/// <param name="schemaName">The raw schema name to normalize.</param>
- private string NormalizeSchemaName(string schemaName)
+ private string NormalizeSchemaName(string? schemaName)
{
schemaName = schemaName?.Trim().ToLower();
return !string.IsNullOrWhiteSpace(schemaName)
@@ -191,7 +189,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <summary>Get the schema file given its unique ID.</summary>
/// <param name="id">The schema ID.</param>
- private FileInfo FindSchemaFile(string id)
+ private FileInfo? FindSchemaFile(string? id)
{
// normalize ID
id = id?.Trim().ToLower();
@@ -216,13 +214,13 @@ namespace StardewModdingAPI.Web.Controllers
// skip through transparent errors
if (this.IsTransparentError(error))
{
- foreach (var model in error.ChildErrors.SelectMany(this.GetErrorModels))
+ foreach (JsonValidatorErrorModel model in error.ChildErrors.SelectMany(this.GetErrorModels))
yield return model;
yield break;
}
// get message
- string message = this.GetOverrideError(error);
+ string? message = this.GetOverrideError(error);
if (message == null || message == this.TransparentToken)
message = this.FlattenErrorMessage(error);
@@ -236,7 +234,7 @@ namespace StardewModdingAPI.Web.Controllers
private string FlattenErrorMessage(ValidationError error, int indent = 0)
{
// get override
- string message = this.GetOverrideError(error);
+ string? message = this.GetOverrideError(error);
if (message != null && message != this.TransparentToken)
return message;
@@ -257,7 +255,7 @@ namespace StardewModdingAPI.Web.Controllers
break;
case ErrorType.Required:
- message = $"Missing required fields: {string.Join(", ", (List<string>)error.Value)}.";
+ message = $"Missing required fields: {string.Join(", ", (List<string>)error.Value!)}.";
break;
}
@@ -274,7 +272,7 @@ namespace StardewModdingAPI.Web.Controllers
if (!error.ChildErrors.Any())
return false;
- string @override = this.GetOverrideError(error);
+ string? @override = this.GetOverrideError(error);
return
@override == this.TransparentToken
|| (error.ErrorType == ErrorType.Then && @override == null);
@@ -282,18 +280,18 @@ namespace StardewModdingAPI.Web.Controllers
/// <summary>Get an override error from the JSON schema, if any.</summary>
/// <param name="error">The schema validation error.</param>
- private string GetOverrideError(ValidationError error)
+ private string? GetOverrideError(ValidationError error)
{
- string GetRawOverrideError()
+ string? GetRawOverrideError()
{
// get override errors
- IDictionary<string, string> errors = this.GetExtensionField<Dictionary<string, string>>(error.Schema, "@errorMessages");
+ IDictionary<string, string?>? errors = this.GetExtensionField<Dictionary<string, string?>>(error.Schema, "@errorMessages");
if (errors == null)
return null;
- errors = new Dictionary<string, string>(errors, StringComparer.OrdinalIgnoreCase);
+ errors = new Dictionary<string, string?>(errors, StringComparer.OrdinalIgnoreCase);
// match error by type and message
- foreach ((string target, string errorMessage) in errors)
+ foreach ((string target, string? errorMessage) in errors)
{
if (!target.Contains(":"))
continue;
@@ -304,7 +302,7 @@ namespace StardewModdingAPI.Web.Controllers
}
// match by type
- return errors.TryGetValue(error.ErrorType.ToString(), out string message)
+ return errors.TryGetValue(error.ErrorType.ToString(), out string? message)
? message?.Trim()
: null;
}
@@ -317,7 +315,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <typeparam name="T">The field type.</typeparam>
/// <param name="schema">The schema whose extension fields to search.</param>
/// <param name="key">The case-insensitive field key.</param>
- private T GetExtensionField<T>(JSchema schema, string key)
+ private T? GetExtensionField<T>(JSchema schema, string key)
{
foreach ((string curKey, JToken value) in schema.ExtensionData)
{
@@ -330,7 +328,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <summary>Format a schema value for display.</summary>
/// <param name="value">The value to format.</param>
- private string FormatValue(object value)
+ private string FormatValue(object? value)
{
return value switch
{
diff --git a/src/SMAPI.Web/Controllers/LogParserController.cs b/src/SMAPI.Web/Controllers/LogParserController.cs
index 93f2613e..33af5a81 100644
--- a/src/SMAPI.Web/Controllers/LogParserController.cs
+++ b/src/SMAPI.Web/Controllers/LogParserController.cs
@@ -69,7 +69,7 @@ namespace StardewModdingAPI.Web.Controllers
case LogViewFormat.RawDownload:
{
- string content = file.Error ?? file.Content;
+ string content = file.Error ?? file.Content ?? string.Empty;
return this.File(Encoding.UTF8.GetBytes(content), "plain/text", $"SMAPI log ({id}).txt");
}
@@ -97,7 +97,7 @@ namespace StardewModdingAPI.Web.Controllers
return this.View("Index", this.GetModel(null, uploadError: uploadResult.UploadError));
// redirect to view
- return this.Redirect(this.Url.PlainAction("Index", "LogParser", new { id = uploadResult.ID }));
+ return this.Redirect(this.Url.PlainAction("Index", "LogParser", new { id = uploadResult.ID })!);
}
@@ -109,7 +109,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="expiry">When the uploaded file will no longer be available.</param>
/// <param name="uploadWarning">A non-blocking warning while uploading the log.</param>
/// <param name="uploadError">An error which occurred while uploading the log.</param>
- private LogParserModel GetModel(string? pasteID, DateTime? expiry = null, string? uploadWarning = null, string? uploadError = null)
+ private LogParserModel GetModel(string? pasteID, DateTimeOffset? expiry = null, string? uploadWarning = null, string? uploadError = null)
{
Platform? platform = this.DetectClientPlatform();
diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs
index 3dc1e366..401bba4f 100644
--- a/src/SMAPI.Web/Controllers/ModsApiController.cs
+++ b/src/SMAPI.Web/Controllers/ModsApiController.cs
@@ -1,7 +1,6 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -78,7 +77,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="model">The mod search criteria.</param>
/// <param name="version">The requested API version.</param>
[HttpPost]
- public async Task<IEnumerable<ModEntryModel>> PostAsync([FromBody] ModSearchModel model, [FromRoute] string version)
+ public async Task<IEnumerable<ModEntryModel>> PostAsync([FromBody] ModSearchModel? model, [FromRoute] string version)
{
if (model?.Mods == null)
return Array.Empty<ModEntryModel>();
@@ -94,16 +93,16 @@ namespace StardewModdingAPI.Web.Controllers
continue;
// special case: if this is an update check for the official SMAPI repo, check the Nexus mod page for beta versions
- if (mod.ID == config.SmapiInfo.ID && mod.UpdateKeys?.Any(key => key == config.SmapiInfo.DefaultUpdateKey) == true && mod.InstalledVersion?.IsPrerelease() == true)
- mod.UpdateKeys = mod.UpdateKeys.Concat(config.SmapiInfo.AddBetaUpdateKeys).ToArray();
+ if (mod.ID == config.SmapiInfo.ID && mod.UpdateKeys.Any(key => key == config.SmapiInfo.DefaultUpdateKey) && mod.InstalledVersion?.IsPrerelease() == true)
+ mod.AddUpdateKeys(config.SmapiInfo.AddBetaUpdateKeys);
// fetch result
ModEntryModel result = await this.GetModData(mod, wikiData, model.IncludeExtendedMetadata, model.ApiVersion);
if (!model.IncludeExtendedMetadata && (model.ApiVersion == null || mod.InstalledVersion == null))
{
- var errors = new List<string>(result.Errors);
- errors.Add($"This API can't suggest an update because {nameof(model.ApiVersion)} or {nameof(mod.InstalledVersion)} are null, and you didn't specify {nameof(model.IncludeExtendedMetadata)} to get other info. See the SMAPI technical docs for usage.");
- result.Errors = errors.ToArray();
+ result.Errors = result.Errors
+ .Concat(new[] { $"This API can't suggest an update because {nameof(model.ApiVersion)} or {nameof(mod.InstalledVersion)} are null, and you didn't specify {nameof(model.IncludeExtendedMetadata)} to get other info. See the SMAPI technical docs for usage." })
+ .ToArray();
}
mods[mod.ID] = result;
@@ -123,26 +122,26 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param>
/// <param name="apiVersion">The SMAPI version installed by the player.</param>
/// <returns>Returns the mod data if found, else <c>null</c>.</returns>
- private async Task<ModEntryModel> GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata, ISemanticVersion apiVersion)
+ private async Task<ModEntryModel> GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata, ISemanticVersion? apiVersion)
{
// cross-reference data
- ModDataRecord record = this.ModDatabase.Get(search.ID);
- WikiModEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.OrdinalIgnoreCase));
+ ModDataRecord? record = this.ModDatabase.Get(search.ID);
+ WikiModEntry? wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.OrdinalIgnoreCase));
UpdateKey[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray();
- ModOverrideConfig overrides = this.Config.Value.ModOverrides.FirstOrDefault(p => p.ID.Equals(search.ID?.Trim(), StringComparison.OrdinalIgnoreCase));
+ ModOverrideConfig? overrides = this.Config.Value.ModOverrides.FirstOrDefault(p => p.ID.Equals(search.ID.Trim(), StringComparison.OrdinalIgnoreCase));
bool allowNonStandardVersions = overrides?.AllowNonStandardVersions ?? false;
// SMAPI versions with a '-beta' tag indicate major changes that may need beta mod versions.
// This doesn't apply to normal prerelease versions which have an '-alpha' tag.
- bool isSmapiBeta = apiVersion.IsPrerelease() && apiVersion.PrereleaseTag.StartsWith("beta");
+ bool isSmapiBeta = apiVersion != null && apiVersion.IsPrerelease() && apiVersion.PrereleaseTag.StartsWith("beta");
// get latest versions
- ModEntryModel result = new() { ID = search.ID };
+ ModEntryModel result = new(search.ID);
IList<string> errors = new List<string>();
- ModEntryVersionModel main = null;
- ModEntryVersionModel optional = null;
- ModEntryVersionModel unofficial = null;
- ModEntryVersionModel unofficialForBeta = null;
+ ModEntryVersionModel? main = null;
+ ModEntryVersionModel? optional = null;
+ ModEntryVersionModel? unofficial = null;
+ ModEntryVersionModel? unofficialForBeta = null;
foreach (UpdateKey updateKey in updateKeys)
{
// validate update key
@@ -162,9 +161,9 @@ namespace StardewModdingAPI.Web.Controllers
// handle versions
if (this.IsNewer(data.Version, main?.Version))
- main = new ModEntryVersionModel(data.Version, data.Url);
+ main = new ModEntryVersionModel(data.Version, data.Url!);
if (this.IsNewer(data.PreviewVersion, optional?.Version))
- optional = new ModEntryVersionModel(data.PreviewVersion, data.Url);
+ optional = new ModEntryVersionModel(data.PreviewVersion, data.Url!);
}
// get unofficial version
@@ -172,7 +171,7 @@ namespace StardewModdingAPI.Web.Controllers
unofficial = new ModEntryVersionModel(wikiEntry.Compatibility.UnofficialVersion, $"{this.Url.PlainAction("Index", "Mods", absoluteUrl: true)}#{wikiEntry.Anchor}");
// get unofficial version for beta
- if (wikiEntry?.HasBetaInfo == true)
+ if (wikiEntry is { HasBetaInfo: true })
{
if (wikiEntry.BetaCompatibility.Status == WikiCompatibilityStatus.Unofficial)
{
@@ -198,13 +197,13 @@ namespace StardewModdingAPI.Web.Controllers
if (overrides?.SetUrl != null)
{
if (main != null)
- main.Url = overrides.SetUrl;
+ main = new(main.Version, overrides.SetUrl);
if (optional != null)
- optional.Url = overrides.SetUrl;
+ optional = new(optional.Version, overrides.SetUrl);
}
// get recommended update (if any)
- ISemanticVersion installedVersion = this.ModSites.GetMappedVersion(search.InstalledVersion?.ToString(), wikiEntry?.Overrides?.ChangeLocalVersions, allowNonStandard: allowNonStandardVersions);
+ ISemanticVersion? installedVersion = this.ModSites.GetMappedVersion(search.InstalledVersion?.ToString(), wikiEntry?.Overrides?.ChangeLocalVersions, allowNonStandard: allowNonStandardVersions);
if (apiVersion != null && installedVersion != null)
{
// get newer versions
@@ -219,7 +218,7 @@ namespace StardewModdingAPI.Web.Controllers
updates.Add(unofficialForBeta);
// get newest version
- ModEntryVersionModel newest = null;
+ ModEntryVersionModel? newest = null;
foreach (ModEntryVersionModel update in updates)
{
if (newest == null || update.Version.IsNewerThan(newest.Version))
@@ -245,7 +244,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="currentVersion">The current semantic version.</param>
/// <param name="newVersion">The target semantic version.</param>
/// <param name="useBetaChannel">Whether the user enabled the beta channel and should be offered prerelease updates.</param>
- private bool IsRecommendedUpdate(ISemanticVersion currentVersion, ISemanticVersion newVersion, bool useBetaChannel)
+ private bool IsRecommendedUpdate(ISemanticVersion currentVersion, [NotNullWhen(true)] ISemanticVersion? newVersion, bool useBetaChannel)
{
return
newVersion != null
@@ -256,7 +255,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <summary>Get whether a <paramref name="current"/> version is newer than an <paramref name="other"/> version.</summary>
/// <param name="current">The current version.</param>
/// <param name="other">The other version.</param>
- private bool IsNewer(ISemanticVersion current, ISemanticVersion other)
+ private bool IsNewer([NotNullWhen(true)] ISemanticVersion? current, ISemanticVersion? other)
{
return current != null && (other == null || other.IsOlderThan(current));
}
@@ -265,17 +264,20 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="updateKey">The namespaced update key.</param>
/// <param name="allowNonStandardVersions">Whether to allow non-standard versions.</param>
/// <param name="mapRemoteVersions">The changes to apply to remote versions for update checks.</param>
- private async Task<ModInfoModel> GetInfoForUpdateKeyAsync(UpdateKey updateKey, bool allowNonStandardVersions, ChangeDescriptor mapRemoteVersions)
+ private async Task<ModInfoModel> GetInfoForUpdateKeyAsync(UpdateKey updateKey, bool allowNonStandardVersions, ChangeDescriptor? mapRemoteVersions)
{
+ if (!updateKey.LooksValid)
+ return new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, $"Invalid update key '{updateKey}'.");
+
// get mod page
IModPage page;
{
bool isCached =
- this.ModCache.TryGetMod(updateKey.Site, updateKey.ID, out Cached<IModPage> cachedMod)
+ this.ModCache.TryGetMod(updateKey.Site, updateKey.ID, out Cached<IModPage>? cachedMod)
&& !this.ModCache.IsStale(cachedMod.LastUpdated, cachedMod.Data.Status == RemoteModStatus.TemporaryError ? this.Config.Value.ErrorCacheMinutes : this.Config.Value.SuccessCacheMinutes);
if (isCached)
- page = cachedMod.Data;
+ page = cachedMod!.Data;
else
{
page = await this.ModSites.GetModPageAsync(updateKey);
@@ -291,7 +293,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="specifiedKeys">The specified update keys.</param>
/// <param name="record">The mod's entry in SMAPI's internal database.</param>
/// <param name="entry">The mod's entry in the wiki list.</param>
- private IEnumerable<UpdateKey> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry)
+ private IEnumerable<UpdateKey> GetUpdateKeys(string[]? specifiedKeys, ModDataRecord? record, WikiModEntry? entry)
{
// get unique update keys
List<UpdateKey> updateKeys = this.GetUnfilteredUpdateKeys(specifiedKeys, record, entry)
@@ -310,7 +312,7 @@ namespace StardewModdingAPI.Web.Controllers
// if the list has both an update key (like "Nexus:2400") and subkey (like "Nexus:2400@subkey") for the same page, the subkey takes priority
{
var removeKeys = new HashSet<UpdateKey>();
- foreach (var key in updateKeys)
+ foreach (UpdateKey key in updateKeys)
{
if (key.Subkey != null)
removeKeys.Add(new UpdateKey(key.Site, key.ID, null));
@@ -326,7 +328,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="specifiedKeys">The specified update keys.</param>
/// <param name="record">The mod's entry in SMAPI's internal database.</param>
/// <param name="entry">The mod's entry in the wiki list.</param>
- private IEnumerable<string> GetUnfilteredUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry)
+ private IEnumerable<string> GetUnfilteredUpdateKeys(string[]? specifiedKeys, ModDataRecord? record, WikiModEntry? entry)
{
// specified update keys
foreach (string key in specifiedKeys ?? Array.Empty<string>())
@@ -337,7 +339,7 @@ namespace StardewModdingAPI.Web.Controllers
// default update key
{
- string defaultKey = record?.GetDefaultUpdateKey();
+ string? defaultKey = record?.GetDefaultUpdateKey();
if (!string.IsNullOrWhiteSpace(defaultKey))
yield return defaultKey;
}
diff --git a/src/SMAPI.Web/Controllers/ModsController.cs b/src/SMAPI.Web/Controllers/ModsController.cs
index 5292e1ce..919afa5b 100644
--- a/src/SMAPI.Web/Controllers/ModsController.cs
+++ b/src/SMAPI.Web/Controllers/ModsController.cs
@@ -1,5 +1,4 @@
-#nullable disable
-
+using System;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc;
@@ -54,8 +53,8 @@ namespace StardewModdingAPI.Web.Controllers
public ModListModel FetchData()
{
// fetch cached data
- if (!this.Cache.TryGetWikiMetadata(out Cached<WikiMetadata> metadata))
- return new ModListModel();
+ if (!this.Cache.TryGetWikiMetadata(out Cached<WikiMetadata>? metadata))
+ return new ModListModel(null, null, Array.Empty<ModModel>(), lastUpdated: DateTimeOffset.UtcNow, isStale: true);
// build model
return new ModListModel(