using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace ShrinkModFramework { /// Maven 风格区间/并集;裸版本表示最低版本。版本比较沿用框架规则,数字尾部零等价。 public sealed class ShrinkModVersionRange { private readonly List> _ranges = new(); private ShrinkModVersionRange() { } public static ShrinkModVersionRange Parse(string expression) { var result = new ShrinkModVersionRange(); if (string.IsNullOrWhiteSpace(expression)) return result; var text = expression.Trim(); if (text[0] != '[' && text[0] != '(') { ValidateVersion(text); result._ranges.Add(version => ShrinkVersionUtility.Compare(version, text) >= 0); return result; } while (text.Length > 0) { var end = text.IndexOfAny(new[] { ']', ')' }); if (end < 0 || (text[0] != '[' && text[0] != '(')) throw Invalid(expression); var lowerInclusive = text[0] == '['; var upperInclusive = text[end] == ']'; var bounds = text.Substring(1, end - 1).Split(','); string lower, upper; if (bounds.Length == 1) { if (!lowerInclusive || !upperInclusive) throw Invalid(expression); lower = upper = bounds[0].Trim(); ValidateVersion(lower); } else if (bounds.Length == 2) { lower = bounds[0].Trim(); upper = bounds[1].Trim(); if (lower.Length > 0) ValidateVersion(lower); if (upper.Length > 0) ValidateVersion(upper); if ((lower.Length == 0 && lowerInclusive) || (upper.Length == 0 && upperInclusive)) throw Invalid(expression); if (lower.Length > 0 && upper.Length > 0) { var comparison = ShrinkVersionUtility.Compare(lower, upper); if (comparison > 0 || (comparison == 0 && (!lowerInclusive || !upperInclusive))) throw Invalid(expression); } } else throw Invalid(expression); result._ranges.Add(version => (lower.Length == 0 || (lowerInclusive ? ShrinkVersionUtility.Compare(version, lower) >= 0 : ShrinkVersionUtility.Compare(version, lower) > 0)) && (upper.Length == 0 || (upperInclusive ? ShrinkVersionUtility.Compare(version, upper) <= 0 : ShrinkVersionUtility.Compare(version, upper) < 0))); text = text.Substring(end + 1).Trim(); if (text.Length == 0) break; if (text[0] != ',' || text.Length == 1) throw Invalid(expression); text = text.Substring(1).Trim(); if (text.Length == 0) throw Invalid(expression); } return result; } public bool Contains(string version) { ValidateVersion(version); return _ranges.Count == 0 || _ranges.Any(range => range(version)); } private static void ValidateVersion(string version) { if (string.IsNullOrWhiteSpace(version) || !Regex.IsMatch(version, @"^[0-9]+(?:[.][0-9]+)*(?:[-+][A-Za-z0-9.-]+)?$")) throw Invalid(version); } private static FormatException Invalid(string value) => new FormatException($"Invalid mod version range: '{value}'."); } }