Esempio n. 1
0
 /// <summary>
 /// Initializes a new valid <see cref="ParseResult"/>.
 /// </summary>
 /// <param name="result">The version bound.</param>
 /// <param name="isApproximated">Whether the version bound is an approximation.</param>
 /// <param name="fourthPartLost">Whether a 4th (or more) part (like in "1.2.3.4") has been ignored.</param>
 public ParseResult(SVersionBound result, bool isApproximated, bool fourthPartLost)
 {
     Result         = result;
     IsApproximated = isApproximated;
     FourthPartLost = fourthPartLost;
     Error          = null;
 }
Esempio n. 2
0
        /// <summary>
        /// Tries to parse a version bound: it is a <see cref="SVersion.TryParse(ref ReadOnlySpan{char}, bool, bool, bool)"/> that may be
        /// followed by an optional bracketed "[<see cref="TryParseLockAndMinQuality"/>]".
        /// The head is forwarded right after the match: on success, the head may be on any kind of character.
        /// </summary>
        /// <param name="head">The string to parse (leading and internal white spaces between tokens are skipped).</param>
        /// <param name="bound">The result. This is <see cref="SVersionBound.None"/> on error.</param>
        /// <param name="defaultLock">Default lock to apply if none is provided.</param>
        /// <param name="defaultQuality">Default quality to apply if none is provided.</param>
        /// <returns>True on success, false otherwise.</returns>
        public static bool TryParse(ref ReadOnlySpan <char> head, out SVersionBound bound, SVersionLock defaultLock = SVersionLock.None, PackageQuality defaultQuality = PackageQuality.None)
        {
            var sHead = head;

            bound = SVersionBound.None;
            var v = SVersion.TryParse(ref Trim(ref head), checkBuildMetaDataSyntax: false);

            if (!v.IsValid)
            {
                head = sHead;
                return(false);
            }
            SVersionLock   l = SVersionLock.None;
            PackageQuality q = PackageQuality.None;

            if (Trim(ref head).Length > 0 && TryMatch(ref head, '['))
            {
                // Allows empty []. Note that TryParseLockAndMinQuality calls Trim.
                TryParseLockAndMinQuality(ref head, out l, out q);
                // Match the closing ] if it's here. Ignores it if it's not here.
                if (Trim(ref head).Length > 0)
                {
                    TryMatch(ref head, ']');
                }
            }
            if (l == SVersionLock.None)
            {
                l = defaultLock;
            }
            if (q == PackageQuality.None)
            {
                q = defaultQuality;
            }
            bound = new SVersionBound(v, l, q);
            return(true);
        }
        static ParseResult TryMatchHeadRange(ref ReadOnlySpan <char> s, bool includePrerelease)
        {
            // Handling the marvelous "" (empty string), that is like '*'.
            if (s.Length == 0)
            {
                return(new ParseResult(new SVersionBound(_000Version, SVersionLock.None, includePrerelease ? PackageQuality.None : PackageQuality.Stable), isApproximated: !includePrerelease, false));
            }

            if (TryMatch(ref s, '>'))
            {
                bool isApproximated = !TryMatch(ref s, '=');
                return(TryMatchRangeAlone(ref Trim(ref s), SVersionLock.None, includePrerelease).Result.EnsureIsApproximated(isApproximated));
            }
            if (TryMatch(ref s, '<'))
            {
                if (TryMatch(ref s, '='))
                {
                    return(TryMatchRangeAlone(ref Trim(ref s), SVersionLock.Lock, includePrerelease).Result.EnsureIsApproximated(true));
                }
                // We totally ignore any '<'...
                var forget = TryMatchRangeAlone(ref Trim(ref s), SVersionLock.None, includePrerelease).Result;
                return(forget.Error != null ? forget : new ParseResult(SVersionBound.All.SetMinQuality(includePrerelease ? PackageQuality.CI : PackageQuality.Stable), true, forget.FourthPartLost));
            }
            if (TryMatch(ref s, '~'))
            {
                return(TryMatchRangeAlone(ref Trim(ref s), SVersionLock.LockMinor, includePrerelease).Result);
            }
            if (TryMatch(ref s, '^'))
            {
                var r = TryMatchRangeAlone(ref Trim(ref s), SVersionLock.LockMajor, includePrerelease);
                if (r.Result.Error == null)
                {
                    bool          noMoreApproximation = false;
                    SVersionBound v = r.Result.Result;
                    if (v.Base.Major == 0)
                    {
                        if (v.Lock == SVersionLock.LockMajor && !r.IsFloatingMinor)
                        {
                            v = v.SetLock(SVersionLock.LockMinor);
                            if (v.Base.Minor == 0 && v.Lock == SVersionLock.LockMinor)
                            {
                                v = v.SetLock(SVersionLock.LockPatch);
                                noMoreApproximation = true;
                            }
                        }
                    }
                    else
                    {
                        // Major != 0.
                        if (v.Lock > SVersionLock.LockMajor)
                        {
                            v = v.SetLock(SVersionLock.LockMajor);
                        }
                    }
                    r.Result = r.Result.SetResult(v);
                    if (noMoreApproximation)
                    {
                        r.Result = r.Result.ClearApproximated();
                    }
                }
                return(r.Result);
            }
            // '=' prefix is optional.
            if (TryMatch(ref s, '='))
            {
                Trim(ref s);
            }
            return(TryMatchRangeAlone(ref s, SVersionLock.Lock, includePrerelease).Result);
        }
Esempio n. 4
0
 /// <summary>
 /// Applies a new <see cref="Result"/> and returns this or a new result.
 /// </summary>
 /// <param name="result">The new result.</param>
 /// <returns>This or a new result.</returns>
 public ParseResult SetResult(SVersionBound result) => result.Equals(Result)
                                                             ? this
                                                             : new ParseResult(result, IsApproximated, FourthPartLost);
Esempio n. 5
0
 /// <summary>
 /// Tries to parse a version bound: it is a <see cref="SVersion.TryParse(ref ReadOnlySpan{char}, bool, bool, bool)"/> that may be
 /// followed by an optional bracketed "[<see cref="TryParseLockAndMinQuality"/>]".
 /// </summary>
 /// <param name="head">The string to parse (leading and internal white spaces between tokens are skipped).</param>
 /// <param name="bound">The result. This is <see cref="SVersionBound.None"/> on error.</param>
 /// <param name="defaultLock">The <see cref="SVersionLock"/> to use when no lock appears in the string to parse.</param>
 /// <param name="defaultQuality">The <see cref="PackageQuality"/> to use when no lock appears in the string to parse.</param>
 /// <returns>True on success, false otherwise.</returns>
 public static bool TryParse(ReadOnlySpan <char> head, out SVersionBound bound, SVersionLock defaultLock = SVersionLock.None, PackageQuality defaultQuality = PackageQuality.None) => TryParse(ref head, out bound, defaultLock, defaultQuality);
Esempio n. 6
0
 /// <summary>
 /// Initializes a new <see cref="ParseResult"/> on error.
 /// </summary>
 /// <param name="error">The error message.</param>
 public ParseResult(string error)
 {
     Result         = SVersionBound.None;
     IsApproximated = FourthPartLost = false;
     Error          = error ?? throw new ArgumentNullException(nameof(error));
 }