enable nullable annotations for semantic versions (#837)

This commit is contained in:
Jesse Plamondon-Willard 2022-04-07 00:56:00 -04:00
parent 3f9b412bed
commit ab6cf45b03
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
5 changed files with 91 additions and 75 deletions

View File

@ -1,5 +1,3 @@
#nullable disable
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -63,10 +61,10 @@ namespace SMAPI.Tests.Utilities
[TestCase("apple")] [TestCase("apple")]
[TestCase("-apple")] [TestCase("-apple")]
[TestCase("-5")] [TestCase("-5")]
public void Constructor_FromString_WithInvalidValues(string input) public void Constructor_FromString_WithInvalidValues(string? input)
{ {
if (input == null) if (input == null)
this.AssertAndLogException<ArgumentNullException>(() => new SemanticVersion(input)); this.AssertAndLogException<ArgumentNullException>(() => new SemanticVersion(input!));
else else
this.AssertAndLogException<FormatException>(() => new SemanticVersion(input)); this.AssertAndLogException<FormatException>(() => new SemanticVersion(input));
} }
@ -93,7 +91,7 @@ namespace SMAPI.Tests.Utilities
[TestCase("1.2.3.4-some-tag.4 ")] [TestCase("1.2.3.4-some-tag.4 ")]
public void Constructor_FromString_Standard_DisallowsNonStandardVersion(string input) public void Constructor_FromString_Standard_DisallowsNonStandardVersion(string input)
{ {
Assert.Throws<FormatException>(() => new SemanticVersion(input)); Assert.Throws<FormatException>(() => _ = new SemanticVersion(input));
} }
/// <summary>Assert the parsed version when constructed from standard parts.</summary> /// <summary>Assert the parsed version when constructed from standard parts.</summary>
@ -112,7 +110,7 @@ namespace SMAPI.Tests.Utilities
[TestCase(1, 2, 3, "some-tag.4 ", null, ExpectedResult = "1.2.3-some-tag.4")] [TestCase(1, 2, 3, "some-tag.4 ", null, ExpectedResult = "1.2.3-some-tag.4")]
[TestCase(1, 2, 3, "some-tag.4 ", "build.004", ExpectedResult = "1.2.3-some-tag.4+build.004")] [TestCase(1, 2, 3, "some-tag.4 ", "build.004", ExpectedResult = "1.2.3-some-tag.4+build.004")]
[TestCase(1, 2, 0, null, "3.4.5-build.004", ExpectedResult = "1.2.0+3.4.5-build.004")] [TestCase(1, 2, 0, null, "3.4.5-build.004", ExpectedResult = "1.2.0+3.4.5-build.004")]
public string Constructor_FromParts(int major, int minor, int patch, string prerelease, string build) public string Constructor_FromParts(int major, int minor, int patch, string? prerelease, string? build)
{ {
// act // act
ISemanticVersion version = new SemanticVersion(major, minor, patch, prerelease, build); ISemanticVersion version = new SemanticVersion(major, minor, patch, prerelease, build);
@ -222,11 +220,11 @@ namespace SMAPI.Tests.Utilities
// null // null
[TestCase("1.0.0", null, ExpectedResult = 1)] // null is always less than any value per CompareTo remarks [TestCase("1.0.0", null, ExpectedResult = 1)] // null is always less than any value per CompareTo remarks
public int CompareTo(string versionStrA, string versionStrB) public int CompareTo(string versionStrA, string? versionStrB)
{ {
// arrange // arrange
ISemanticVersion versionA = new SemanticVersion(versionStrA); ISemanticVersion versionA = new SemanticVersion(versionStrA);
ISemanticVersion versionB = versionStrB != null ISemanticVersion? versionB = versionStrB != null
? new SemanticVersion(versionStrB) ? new SemanticVersion(versionStrB)
: null; : null;
@ -270,11 +268,11 @@ namespace SMAPI.Tests.Utilities
// null // null
[TestCase("1.0.0", null, ExpectedResult = false)] // null is always less than any value per CompareTo remarks [TestCase("1.0.0", null, ExpectedResult = false)] // null is always less than any value per CompareTo remarks
public bool IsOlderThan(string versionStrA, string versionStrB) public bool IsOlderThan(string versionStrA, string? versionStrB)
{ {
// arrange // arrange
ISemanticVersion versionA = new SemanticVersion(versionStrA); ISemanticVersion versionA = new SemanticVersion(versionStrA);
ISemanticVersion versionB = versionStrB != null ISemanticVersion? versionB = versionStrB != null
? new SemanticVersion(versionStrB) ? new SemanticVersion(versionStrB)
: null; : null;
@ -319,11 +317,11 @@ namespace SMAPI.Tests.Utilities
// null // null
[TestCase("1.0.0", null, ExpectedResult = true)] // null is always less than any value per CompareTo remarks [TestCase("1.0.0", null, ExpectedResult = true)] // null is always less than any value per CompareTo remarks
public bool IsNewerThan(string versionStrA, string versionStrB) public bool IsNewerThan(string versionStrA, string? versionStrB)
{ {
// arrange // arrange
ISemanticVersion versionA = new SemanticVersion(versionStrA); ISemanticVersion versionA = new SemanticVersion(versionStrA);
ISemanticVersion versionB = versionStrB != null ISemanticVersion? versionB = versionStrB != null
? new SemanticVersion(versionStrB) ? new SemanticVersion(versionStrB)
: null; : null;
@ -356,13 +354,13 @@ namespace SMAPI.Tests.Utilities
[TestCase("1.0-beta.2", "1.0-beta.10", "1.0-beta.3", ExpectedResult = false)] [TestCase("1.0-beta.2", "1.0-beta.10", "1.0-beta.3", ExpectedResult = false)]
[TestCase("1.0-beta-2", "1.0-beta-10", "1.0-beta-3", ExpectedResult = false)] [TestCase("1.0-beta-2", "1.0-beta-10", "1.0-beta-3", ExpectedResult = false)]
[TestCase("1.0.0", "1.0.0", null, ExpectedResult = false)] // null is always less than any value per CompareTo remarks [TestCase("1.0.0", "1.0.0", null, ExpectedResult = false)] // null is always less than any value per CompareTo remarks
public bool IsBetween(string versionStr, string lowerStr, string upperStr) public bool IsBetween(string versionStr, string? lowerStr, string? upperStr)
{ {
// arrange // arrange
ISemanticVersion lower = lowerStr != null ISemanticVersion? lower = lowerStr != null
? new SemanticVersion(lowerStr) ? new SemanticVersion(lowerStr)
: null; : null;
ISemanticVersion upper = upperStr != null ISemanticVersion? upper = upperStr != null
? new SemanticVersion(upperStr) ? new SemanticVersion(upperStr)
: null; : null;
ISemanticVersion version = new SemanticVersion(versionStr); ISemanticVersion version = new SemanticVersion(versionStr);
@ -436,7 +434,7 @@ namespace SMAPI.Tests.Utilities
/// <param name="prerelease">The prerelease tag.</param> /// <param name="prerelease">The prerelease tag.</param>
/// <param name="build">The build metadata.</param> /// <param name="build">The build metadata.</param>
/// <param name="nonStandard">Whether the version should be marked as non-standard.</param> /// <param name="nonStandard">Whether the version should be marked as non-standard.</param>
private void AssertParts(ISemanticVersion version, int major, int minor, int patch, string prerelease, string build, bool nonStandard) private void AssertParts(ISemanticVersion version, int major, int minor, int patch, string? prerelease, string? build, bool nonStandard)
{ {
Assert.AreEqual(major, version.MajorVersion, "The major version doesn't match."); Assert.AreEqual(major, version.MajorVersion, "The major version doesn't match.");
Assert.AreEqual(minor, version.MinorVersion, "The minor version doesn't match."); Assert.AreEqual(minor, version.MinorVersion, "The minor version doesn't match.");
@ -449,9 +447,8 @@ namespace SMAPI.Tests.Utilities
/// <summary>Assert that the expected exception type is thrown, and log the action output and thrown exception.</summary> /// <summary>Assert that the expected exception type is thrown, and log the action output and thrown exception.</summary>
/// <typeparam name="T">The expected exception type.</typeparam> /// <typeparam name="T">The expected exception type.</typeparam>
/// <param name="action">The action which may throw the exception.</param> /// <param name="action">The action which may throw the exception.</param>
/// <param name="message">The message to log if the expected exception isn't thrown.</param>
[SuppressMessage("ReSharper", "UnusedParameter.Local", Justification = "The message argument is deliberately only used in precondition checks since this is an assertion method.")] [SuppressMessage("ReSharper", "UnusedParameter.Local", Justification = "The message argument is deliberately only used in precondition checks since this is an assertion method.")]
private void AssertAndLogException<T>(Func<object> action, string message = null) private void AssertAndLogException<T>(Func<object> action)
where T : Exception where T : Exception
{ {
this.AssertAndLogException<T>(() => this.AssertAndLogException<T>(() =>
@ -466,7 +463,7 @@ namespace SMAPI.Tests.Utilities
/// <param name="action">The action which may throw the exception.</param> /// <param name="action">The action which may throw the exception.</param>
/// <param name="message">The message to log if the expected exception isn't thrown.</param> /// <param name="message">The message to log if the expected exception isn't thrown.</param>
[SuppressMessage("ReSharper", "UnusedParameter.Local", Justification = "The message argument is deliberately only used in precondition checks since this is an assertion method.")] [SuppressMessage("ReSharper", "UnusedParameter.Local", Justification = "The message argument is deliberately only used in precondition checks since this is an assertion method.")]
private void AssertAndLogException<T>(Action action, string message = null) private void AssertAndLogException<T>(Action action, string? message = null)
where T : Exception where T : Exception
{ {
try try

View File

@ -1,5 +1,3 @@
#nullable disable
using System; using System;
namespace StardewModdingAPI namespace StardewModdingAPI
@ -20,10 +18,10 @@ namespace StardewModdingAPI
int PatchVersion { get; } int PatchVersion { get; }
/// <summary>An optional prerelease tag.</summary> /// <summary>An optional prerelease tag.</summary>
string PrereleaseTag { get; } string? PrereleaseTag { get; }
/// <summary>Optional build metadata. This is ignored when determining version precedence.</summary> /// <summary>Optional build metadata. This is ignored when determining version precedence.</summary>
string BuildMetadata { get; } string? BuildMetadata { get; }
/********* /*********
@ -34,32 +32,38 @@ namespace StardewModdingAPI
/// <summary>Get whether this version is older than the specified version.</summary> /// <summary>Get whether this version is older than the specified version.</summary>
/// <param name="other">The version to compare with this instance.</param> /// <param name="other">The version to compare with this instance.</param>
bool IsOlderThan(ISemanticVersion other); /// <remarks>Although the <paramref name="other"/> parameter is nullable, it isn't optional. A <c>null</c> version is considered earlier than every possible valid version, so passing <c>null</c> to <paramref name="other"/> will always return false.</remarks>
bool IsOlderThan(ISemanticVersion? other);
/// <summary>Get whether this version is older than the specified version.</summary> /// <summary>Get whether this version is older than the specified version.</summary>
/// <param name="other">The version to compare with this instance.</param> /// <param name="other">The version to compare with this instance. A null value is never older.</param>
/// <exception cref="FormatException">The specified version is not a valid semantic version.</exception> /// <exception cref="FormatException">The specified version is not a valid semantic version.</exception>
bool IsOlderThan(string other); /// <remarks>Although the <paramref name="other"/> parameter is nullable, it isn't optional. A <c>null</c> version is considered earlier than every possible valid version, so passing <c>null</c> to <paramref name="other"/> will always return false.</remarks>
bool IsOlderThan(string? other);
/// <summary>Get whether this version is newer than the specified version.</summary> /// <summary>Get whether this version is newer than the specified version.</summary>
/// <param name="other">The version to compare with this instance.</param> /// <param name="other">The version to compare with this instance. A null value is always older.</param>
bool IsNewerThan(ISemanticVersion other); /// <remarks>Although the <paramref name="other"/> parameter is nullable, it isn't optional. A <c>null</c> version is considered earlier than every possible valid version, so passing <c>null</c> to <paramref name="other"/> will always return true.</remarks>
bool IsNewerThan(ISemanticVersion? other);
/// <summary>Get whether this version is newer than the specified version.</summary> /// <summary>Get whether this version is newer than the specified version.</summary>
/// <param name="other">The version to compare with this instance.</param> /// <param name="other">The version to compare with this instance. A null value is always older.</param>
/// <exception cref="FormatException">The specified version is not a valid semantic version.</exception> /// <exception cref="FormatException">The specified version is not a valid semantic version.</exception>
bool IsNewerThan(string other); /// <remarks>Although the <paramref name="other"/> parameter is nullable, it isn't optional. A <c>null</c> version is considered earlier than every possible valid version, so passing <c>null</c> to <paramref name="other"/> will always return true.</remarks>
bool IsNewerThan(string? other);
/// <summary>Get whether this version is between two specified versions (inclusively).</summary> /// <summary>Get whether this version is between two specified versions (inclusively).</summary>
/// <param name="min">The minimum version.</param> /// <param name="min">The minimum version. A null value is always older.</param>
/// <param name="max">The maximum version.</param> /// <param name="max">The maximum version. A null value is never newer.</param>
bool IsBetween(ISemanticVersion min, ISemanticVersion max); /// <remarks>Although the <paramref name="min"/> and <paramref name="max"/> parameters are nullable, they are not optional. A <c>null</c> version is considered earlier than every possible valid version. For example, passing <c>null</c> to <paramref name="max"/> will always return false, since no valid version can be earlier than <c>null</c>.</remarks>
bool IsBetween(ISemanticVersion? min, ISemanticVersion? max);
/// <summary>Get whether this version is between two specified versions (inclusively).</summary> /// <summary>Get whether this version is between two specified versions (inclusively).</summary>
/// <param name="min">The minimum version.</param> /// <param name="min">The minimum version. A null value is always older.</param>
/// <param name="max">The maximum version.</param> /// <param name="max">The maximum version. A null value is never newer.</param>
/// <exception cref="FormatException">One of the specified versions is not a valid semantic version.</exception> /// <exception cref="FormatException">One of the specified versions is not a valid semantic version.</exception>
bool IsBetween(string min, string max); /// <remarks>Although the <paramref name="min"/> and <paramref name="max"/> parameters are nullable, they are not optional. A <c>null</c> version is considered earlier than every possible valid version. For example, passing <c>null</c> to <paramref name="max"/> will always return false, since no valid version can be earlier than <c>null</c>.</remarks>
bool IsBetween(string? min, string? max);
/// <summary>Get a string representation of the version.</summary> /// <summary>Get a string representation of the version.</summary>
string ToString(); string ToString();

View File

@ -1,6 +1,5 @@
#nullable disable
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using StardewModdingAPI.Toolkit.Framework; using StardewModdingAPI.Toolkit.Framework;
@ -40,10 +39,10 @@ namespace StardewModdingAPI.Toolkit
public int PlatformRelease { get; } public int PlatformRelease { get; }
/// <inheritdoc /> /// <inheritdoc />
public string PrereleaseTag { get; } public string? PrereleaseTag { get; }
/// <inheritdoc /> /// <inheritdoc />
public string BuildMetadata { get; } public string? BuildMetadata { get; }
/********* /*********
@ -56,7 +55,7 @@ namespace StardewModdingAPI.Toolkit
/// <param name="platformRelease">The platform-specific version (if applicable).</param> /// <param name="platformRelease">The platform-specific version (if applicable).</param>
/// <param name="prereleaseTag">An optional prerelease tag.</param> /// <param name="prereleaseTag">An optional prerelease tag.</param>
/// <param name="buildMetadata">Optional build metadata. This is ignored when determining version precedence.</param> /// <param name="buildMetadata">Optional build metadata. This is ignored when determining version precedence.</param>
public SemanticVersion(int major, int minor, int patch, int platformRelease = 0, string prereleaseTag = null, string buildMetadata = null) public SemanticVersion(int major, int minor, int patch, int platformRelease = 0, string? prereleaseTag = null, string? buildMetadata = null)
{ {
this.MajorVersion = major; this.MajorVersion = major;
this.MinorVersion = minor; this.MinorVersion = minor;
@ -106,7 +105,7 @@ namespace StardewModdingAPI.Toolkit
} }
/// <inheritdoc /> /// <inheritdoc />
public int CompareTo(ISemanticVersion other) public int CompareTo(ISemanticVersion? other)
{ {
return other == null return other == null
? 1 ? 1
@ -114,7 +113,7 @@ namespace StardewModdingAPI.Toolkit
} }
/// <inheritdoc /> /// <inheritdoc />
public bool Equals(ISemanticVersion other) public bool Equals(ISemanticVersion? other)
{ {
return other != null && this.CompareTo(other) == 0; return other != null && this.CompareTo(other) == 0;
} }
@ -126,15 +125,15 @@ namespace StardewModdingAPI.Toolkit
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsOlderThan(ISemanticVersion other) public bool IsOlderThan(ISemanticVersion? other)
{ {
return this.CompareTo(other) < 0; return this.CompareTo(other) < 0;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsOlderThan(string other) public bool IsOlderThan(string? other)
{ {
ISemanticVersion otherVersion = other != null ISemanticVersion? otherVersion = other != null
? new SemanticVersion(other, allowNonStandard: true) ? new SemanticVersion(other, allowNonStandard: true)
: null; : null;
@ -142,15 +141,15 @@ namespace StardewModdingAPI.Toolkit
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsNewerThan(ISemanticVersion other) public bool IsNewerThan(ISemanticVersion? other)
{ {
return this.CompareTo(other) > 0; return this.CompareTo(other) > 0;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsNewerThan(string other) public bool IsNewerThan(string? other)
{ {
ISemanticVersion otherVersion = other != null ISemanticVersion? otherVersion = other != null
? new SemanticVersion(other, allowNonStandard: true) ? new SemanticVersion(other, allowNonStandard: true)
: null; : null;
@ -158,18 +157,18 @@ namespace StardewModdingAPI.Toolkit
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsBetween(ISemanticVersion min, ISemanticVersion max) public bool IsBetween(ISemanticVersion? min, ISemanticVersion? max)
{ {
return this.CompareTo(min) >= 0 && this.CompareTo(max) <= 0; return this.CompareTo(min) >= 0 && this.CompareTo(max) <= 0;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsBetween(string min, string max) public bool IsBetween(string? min, string? max)
{ {
ISemanticVersion minVersion = min != null ISemanticVersion? minVersion = min != null
? new SemanticVersion(min, allowNonStandard: true) ? new SemanticVersion(min, allowNonStandard: true)
: null; : null;
ISemanticVersion maxVersion = max != null ISemanticVersion? maxVersion = max != null
? new SemanticVersion(max, allowNonStandard: true) ? new SemanticVersion(max, allowNonStandard: true)
: null; : null;
@ -199,7 +198,12 @@ namespace StardewModdingAPI.Toolkit
/// <param name="version">The version string.</param> /// <param name="version">The version string.</param>
/// <param name="parsed">The parsed representation.</param> /// <param name="parsed">The parsed representation.</param>
/// <returns>Returns whether parsing the version succeeded.</returns> /// <returns>Returns whether parsing the version succeeded.</returns>
public static bool TryParse(string version, out ISemanticVersion parsed) public static bool TryParse(string? version,
#if NET5_0_OR_GREATER
[NotNullWhen(true)]
#endif
out ISemanticVersion? parsed
)
{ {
return SemanticVersion.TryParse(version, allowNonStandard: false, out parsed); return SemanticVersion.TryParse(version, allowNonStandard: false, out parsed);
} }
@ -209,8 +213,19 @@ namespace StardewModdingAPI.Toolkit
/// <param name="allowNonStandard">Whether to allow non-standard extensions to semantic versioning.</param> /// <param name="allowNonStandard">Whether to allow non-standard extensions to semantic versioning.</param>
/// <param name="parsed">The parsed representation.</param> /// <param name="parsed">The parsed representation.</param>
/// <returns>Returns whether parsing the version succeeded.</returns> /// <returns>Returns whether parsing the version succeeded.</returns>
public static bool TryParse(string version, bool allowNonStandard, out ISemanticVersion parsed) public static bool TryParse(string? version, bool allowNonStandard,
#if NET5_0_OR_GREATER
[NotNullWhen(true)]
#endif
out ISemanticVersion? parsed
)
{ {
if (version == null)
{
parsed = null;
return false;
}
try try
{ {
parsed = new SemanticVersion(version, allowNonStandard); parsed = new SemanticVersion(version, allowNonStandard);
@ -229,7 +244,7 @@ namespace StardewModdingAPI.Toolkit
*********/ *********/
/// <summary>Get a normalized prerelease or build tag.</summary> /// <summary>Get a normalized prerelease or build tag.</summary>
/// <param name="tag">The tag to normalize.</param> /// <param name="tag">The tag to normalize.</param>
private string GetNormalizedTag(string tag) private string? GetNormalizedTag(string? tag)
{ {
tag = tag?.Trim(); tag = tag?.Trim();
return !string.IsNullOrWhiteSpace(tag) ? tag : null; return !string.IsNullOrWhiteSpace(tag) ? tag : null;
@ -241,7 +256,7 @@ namespace StardewModdingAPI.Toolkit
/// <param name="otherPatch">The patch version to compare with this instance.</param> /// <param name="otherPatch">The patch version to compare with this instance.</param>
/// <param name="otherPlatformRelease">The non-standard platform release to compare with this instance.</param> /// <param name="otherPlatformRelease">The non-standard platform release to compare with this instance.</param>
/// <param name="otherTag">The prerelease tag to compare with this instance.</param> /// <param name="otherTag">The prerelease tag to compare with this instance.</param>
private int CompareTo(int otherMajor, int otherMinor, int otherPatch, int otherPlatformRelease, string otherTag) private int CompareTo(int otherMajor, int otherMinor, int otherPatch, int otherPlatformRelease, string? otherTag)
{ {
const int same = 0; const int same = 0;
const int curNewer = 1; const int curNewer = 1;
@ -270,8 +285,8 @@ namespace StardewModdingAPI.Toolkit
return curOlder; return curOlder;
// compare two prerelease tag values // compare two prerelease tag values
string[] curParts = this.PrereleaseTag.Split('.', '-'); string[] curParts = this.PrereleaseTag?.Split('.', '-') ?? Array.Empty<string>();
string[] otherParts = otherTag.Split('.', '-'); string[] otherParts = otherTag?.Split('.', '-') ?? Array.Empty<string>();
int length = Math.Max(curParts.Length, otherParts.Length); int length = Math.Max(curParts.Length, otherParts.Length);
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {

View File

@ -73,5 +73,6 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=tilesheets/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=tilesheets/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=tilesheet_0027s/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=tilesheet_0027s/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unloadable/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=unloadable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=versioning/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=virally/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=virally/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary> </wpf:ResourceDictionary>

View File

@ -1,6 +1,5 @@
#nullable disable
using System; using System;
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace StardewModdingAPI namespace StardewModdingAPI
@ -28,10 +27,10 @@ namespace StardewModdingAPI
public int PatchVersion => this.Version.PatchVersion; public int PatchVersion => this.Version.PatchVersion;
/// <inheritdoc /> /// <inheritdoc />
public string PrereleaseTag => this.Version.PrereleaseTag; public string? PrereleaseTag => this.Version.PrereleaseTag;
/// <inheritdoc /> /// <inheritdoc />
public string BuildMetadata => this.Version.BuildMetadata; public string? BuildMetadata => this.Version.BuildMetadata;
/********* /*********
@ -43,7 +42,7 @@ namespace StardewModdingAPI
/// <param name="patchVersion">The patch version for backwards-compatible bug fixes.</param> /// <param name="patchVersion">The patch version for backwards-compatible bug fixes.</param>
/// <param name="prereleaseTag">An optional prerelease tag.</param> /// <param name="prereleaseTag">An optional prerelease tag.</param>
/// <param name="buildMetadata">Optional build metadata. This is ignored when determining version precedence.</param> /// <param name="buildMetadata">Optional build metadata. This is ignored when determining version precedence.</param>
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, string prereleaseTag = null, string buildMetadata = null) public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, string? prereleaseTag = null, string? buildMetadata = null)
: this(majorVersion, minorVersion, patchVersion, 0, prereleaseTag, buildMetadata) { } : this(majorVersion, minorVersion, patchVersion, 0, prereleaseTag, buildMetadata) { }
/// <summary>Construct an instance.</summary> /// <summary>Construct an instance.</summary>
@ -54,7 +53,7 @@ namespace StardewModdingAPI
/// <param name="platformRelease">The platform-specific version (if applicable).</param> /// <param name="platformRelease">The platform-specific version (if applicable).</param>
/// <param name="buildMetadata">Optional build metadata. This is ignored when determining version precedence.</param> /// <param name="buildMetadata">Optional build metadata. This is ignored when determining version precedence.</param>
[JsonConstructor] [JsonConstructor]
internal SemanticVersion(int majorVersion, int minorVersion, int patchVersion, int platformRelease, string prereleaseTag = null, string buildMetadata = null) internal SemanticVersion(int majorVersion, int minorVersion, int patchVersion, int platformRelease, string? prereleaseTag = null, string? buildMetadata = null)
: this(new Toolkit.SemanticVersion(majorVersion, minorVersion, patchVersion, platformRelease, prereleaseTag, buildMetadata)) { } : this(new Toolkit.SemanticVersion(majorVersion, minorVersion, patchVersion, platformRelease, prereleaseTag, buildMetadata)) { }
/// <summary>Construct an instance.</summary> /// <summary>Construct an instance.</summary>
@ -93,49 +92,49 @@ namespace StardewModdingAPI
/// <inheritdoc /> /// <inheritdoc />
/// <remarks>The implementation is defined by Semantic Version 2.0 (https://semver.org/).</remarks> /// <remarks>The implementation is defined by Semantic Version 2.0 (https://semver.org/).</remarks>
public int CompareTo(ISemanticVersion other) public int CompareTo(ISemanticVersion? other)
{ {
return this.Version.CompareTo(other); return this.Version.CompareTo(other);
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsOlderThan(ISemanticVersion other) public bool IsOlderThan(ISemanticVersion? other)
{ {
return this.Version.IsOlderThan(other); return this.Version.IsOlderThan(other);
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsOlderThan(string other) public bool IsOlderThan(string? other)
{ {
return this.Version.IsOlderThan(other); return this.Version.IsOlderThan(other);
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsNewerThan(ISemanticVersion other) public bool IsNewerThan(ISemanticVersion? other)
{ {
return this.Version.IsNewerThan(other); return this.Version.IsNewerThan(other);
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsNewerThan(string other) public bool IsNewerThan(string? other)
{ {
return this.Version.IsNewerThan(other); return this.Version.IsNewerThan(other);
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsBetween(ISemanticVersion min, ISemanticVersion max) public bool IsBetween(ISemanticVersion? min, ISemanticVersion? max)
{ {
return this.Version.IsBetween(min, max); return this.Version.IsBetween(min, max);
} }
/// <inheritdoc /> /// <inheritdoc />
public bool IsBetween(string min, string max) public bool IsBetween(string? min, string? max)
{ {
return this.Version.IsBetween(min, max); return this.Version.IsBetween(min, max);
} }
/// <inheritdoc /> /// <inheritdoc />
public bool Equals(ISemanticVersion other) public bool Equals(ISemanticVersion? other)
{ {
return other != null && this.CompareTo(other) == 0; return other != null && this.CompareTo(other) == 0;
} }
@ -156,9 +155,9 @@ namespace StardewModdingAPI
/// <param name="version">The version string.</param> /// <param name="version">The version string.</param>
/// <param name="parsed">The parsed representation.</param> /// <param name="parsed">The parsed representation.</param>
/// <returns>Returns whether parsing the version succeeded.</returns> /// <returns>Returns whether parsing the version succeeded.</returns>
public static bool TryParse(string version, out ISemanticVersion parsed) public static bool TryParse(string version, [NotNullWhen(true)] out ISemanticVersion? parsed)
{ {
if (Toolkit.SemanticVersion.TryParse(version, out ISemanticVersion versionImpl)) if (Toolkit.SemanticVersion.TryParse(version, out ISemanticVersion? versionImpl))
{ {
parsed = new SemanticVersion(versionImpl); parsed = new SemanticVersion(versionImpl);
return true; return true;