summaryrefslogtreecommitdiff
path: root/src/SMAPI.Toolkit/Framework
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-11-10 23:27:38 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-11-10 23:27:38 -0500
commit346fddda670704c1458e42104ee7405fc1de7ccc (patch)
treef84d2f8915b1c9ccb90a5dbf0de48a9f85c4b18b /src/SMAPI.Toolkit/Framework
parent55eec58eafb9ba07f3e8b0a1c8394cb114de17a0 (diff)
downloadSMAPI-346fddda670704c1458e42104ee7405fc1de7ccc.tar.gz
SMAPI-346fddda670704c1458e42104ee7405fc1de7ccc.tar.bz2
SMAPI-346fddda670704c1458e42104ee7405fc1de7ccc.zip
move validation logic out of Manifest model
This avoids tightly coupling higher logic to the implementation class, since we can validate the interface.
Diffstat (limited to 'src/SMAPI.Toolkit/Framework')
-rw-r--r--src/SMAPI.Toolkit/Framework/ManifestValidator.cs101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/SMAPI.Toolkit/Framework/ManifestValidator.cs b/src/SMAPI.Toolkit/Framework/ManifestValidator.cs
new file mode 100644
index 00000000..62cfd8e9
--- /dev/null
+++ b/src/SMAPI.Toolkit/Framework/ManifestValidator.cs
@@ -0,0 +1,101 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using StardewModdingAPI.Toolkit.Utilities;
+
+namespace StardewModdingAPI.Toolkit.Framework
+{
+ /// <summary>Validates manifest fields.</summary>
+ public static class ManifestValidator
+ {
+ /// <summary>Try to validate a manifest's fields. Fails if any invalid field is found.</summary>
+ /// <param name="manifest">The manifest to validate.</param>
+ /// <param name="error">The error message to display to the user.</param>
+ /// <returns>Returns whether the manifest was validated successfully.</returns>
+ public static bool TryValidate(IManifest manifest, out string error)
+ {
+ // validate DLL / content pack fields
+ bool hasDll = !string.IsNullOrWhiteSpace(manifest.EntryDll);
+ bool isContentPack = manifest.ContentPackFor != null;
+
+ // validate field presence
+ if (!hasDll && !isContentPack)
+ {
+ error = $"manifest has no {nameof(IManifest.EntryDll)} or {nameof(IManifest.ContentPackFor)} field; must specify one.";
+ return false;
+ }
+ if (hasDll && isContentPack)
+ {
+ error = $"manifest sets both {nameof(IManifest.EntryDll)} and {nameof(IManifest.ContentPackFor)}, which are mutually exclusive.";
+ return false;
+ }
+
+ // validate DLL filename format
+ if (hasDll && manifest.EntryDll!.Intersect(Path.GetInvalidFileNameChars()).Any())
+ {
+ error = $"manifest has invalid filename '{manifest.EntryDll}' for the EntryDLL field.";
+ return false;
+ }
+
+ // validate content pack ID
+ else if (isContentPack && string.IsNullOrWhiteSpace(manifest.ContentPackFor!.UniqueID))
+ {
+ error = $"manifest declares {nameof(IManifest.ContentPackFor)} without its required {nameof(IManifestContentPackFor.UniqueID)} field.";
+ return false;
+ }
+
+ // validate required fields
+ {
+ List<string> missingFields = new List<string>(3);
+
+ if (string.IsNullOrWhiteSpace(manifest.Name))
+ missingFields.Add(nameof(IManifest.Name));
+ if (manifest.Version == null || manifest.Version.ToString() == "0.0.0")
+ missingFields.Add(nameof(IManifest.Version));
+ if (string.IsNullOrWhiteSpace(manifest.UniqueID))
+ missingFields.Add(nameof(IManifest.UniqueID));
+
+ if (missingFields.Any())
+ {
+ error = $"manifest is missing required fields ({string.Join(", ", missingFields)}).";
+ return false;
+ }
+ }
+
+ // validate ID format
+ if (!PathUtilities.IsSlug(manifest.UniqueID))
+ {
+ error = "manifest specifies an invalid ID (IDs must only contain letters, numbers, underscores, periods, or hyphens).";
+ return false;
+ }
+
+ // validate dependencies
+ foreach (IManifestDependency? dependency in manifest.Dependencies)
+ {
+ // null dependency
+ if (dependency == null)
+ {
+ error = $"manifest has a null entry under {nameof(IManifest.Dependencies)}.";
+ return false;
+ }
+
+ // missing ID
+ if (string.IsNullOrWhiteSpace(dependency.UniqueID))
+ {
+ error = $"manifest has a {nameof(IManifest.Dependencies)} entry with no {nameof(IManifestDependency.UniqueID)} field.";
+ return false;
+ }
+
+ // invalid ID
+ if (!PathUtilities.IsSlug(dependency.UniqueID))
+ {
+ error = $"manifest has a {nameof(IManifest.Dependencies)} entry with an invalid {nameof(IManifestDependency.UniqueID)} field (IDs must only contain letters, numbers, underscores, periods, or hyphens).";
+ return false;
+ }
+ }
+
+ error = "";
+ return true;
+ }
+ }
+}