Copyright 2019 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
Package version handles version types.
package version

import (
	
	
	

	
)
Type defines the version types a module can have. This must be kept in sync with the 'version_type' database enum.
type Type string

TypeRelease is a normal release.
	TypeRelease = Type("release")
TypePrerelease is a version with a prerelease.
	TypePrerelease = Type("prerelease")
TypePseudo appears to have a prerelease of the form <commit date>-<commit hash>.
	TypePseudo = Type("pseudo")
)

func ( Type) () string {
	return string()
}

var pseudoVersionRE = regexp.MustCompile(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+incompatible)?$`)
IsPseudo reports whether a valid version v is a pseudo-version. Modified from src/cmd/go/internal/modfetch.
func ( string) bool {
	return strings.Count(, "-") >= 2 && pseudoVersionRE.MatchString()
}
IsIncompatible reports whether a valid version v is an incompatible version.
func ( string) bool {
	return strings.HasSuffix(, "+incompatible")
}
ParseType returns the Type of a given a version.
func ( string) (Type, error) {
	if !semver.IsValid() {
		return "", fmt.Errorf("ParseType(%q): invalid semver", )
	}

	switch {
	case IsPseudo():
		return TypePseudo, nil
	case semver.Prerelease() != "":
		return TypePrerelease, nil
	default:
		return TypeRelease, nil
	}
}
ForSorting returns a string that encodes version, so that comparing two such strings follows SemVer precedence, https://semver.org clause 11. It assumes version is valid. The returned string ends in '~' if and only if the version does not have a prerelease. For examples, see TestForSorting.
func ( string) string {
	 := make([]byte, 0, len())
	 := false // we are in the prerelease part
	 := false   // this part has a non-digit character
	 := 1          // skip 'v'
	 := len()
Add the semver component version[start:end] to the result.
	 := func( int) {
',' comes before '-' and all letters and digits, so it correctly imposes lexicographic ordering on the parts of the version.
			 = append(, ',')
		}
Prepending the largest printable character '~' to a non-numeric part, along with the fact that encoded numbers never begin with a '~', (see appendNumericPrefix), ensures the semver requirement that numeric identifiers always have lower precedence than non-numeric ones.
			 = append(, '~')
		} else {
			 = appendNumericPrefix(, -)
		}
		 = append(, [:]...)
		 =  + 1 // skip over separator character
		 = false
	}

:
	for ,  := range [:] {
		 :=  + 1
		switch {
		case  == '.': // end of a part
			()
		case  == '-': // first one is start of prerelease
			if ! {
				 = true
				()
			} else {
				 = true
			}
		case  == '+': // start of build; nothing after this matters
			 = 
			break 

		case  < '0' ||  > '9':
			 = true
		}
	}
	if  <  {
		()
	}
Make sure prereleases appear first.
		 = append(, '~')
	}
	return string()
}
appendNumericPrefix appends a string representing n to dst. n is the length of a digit string; the value we append is a prefix for the digit string s such that prefix1 + s1 < prefix2 + s2 if and only if the integer denoted by s1 is less than the one denoted by s2. In other words, prefix + s is a string that can be compared with other such strings while preserving the ordering of the numbers. If n==1, there is no prefix. (Single-digit numbers are unchanged.) Otherwise, the prefix is a sequence of lower-case letters encoding n. Examples: n prefix 1 <none> 2 a 27 z 28 za 53 zz 54 zza This encoding depends on the ASCII properties that: - digits are ordered numerically - letters are ordered alphabetically - digits order before letters (so "1" < "a10")
func ( []byte,  int) []byte {
	--
	for  := 0;  < /26; ++ {
		 = append(, 'z')
	}
	if  :=  % 26;  > 0 {
		 = append(, byte('a'+-1))
	}
	return 
}
Later reports whether v1 is later than v2, using semver but preferring release versions to pre-release versions, and both to pseudo-versions.
func (,  string) bool {
	 := semver.Prerelease() == ""
	 := semver.Prerelease() == ""
	if  &&  {
		return semver.Compare(, ) > 0
	}
	if  !=  {
		return 
Both are pre-release.
	 := IsPseudo()
	 := IsPseudo()
	if  ==  {
		return semver.Compare(, ) > 0
	}
	return !
}
Latest finds the latest version of a module using the same algorithm as the Go command. It prefers tagged release versions to tagged pre-release versions, and both of those to pseudo-versions. If versions is empty, Latest returns the empty string. hasGoMod should report whether the version it is given has a go.mod file. Latest returns the latest incompatible version only if the latest compatible version does not have a go.mod file. The meaning of latest is defined at https://golang.org/ref/mod#version-queries. That definition does not deal with retractions, or with a subtlety involving incompatible versions. The actual definition is embodied in the go command's queryMatcher.filterVersions method. This function is a re-implementation and specialization of that method at Go version 1.16 (https://go.googlesource.com/go/+/refs/tags/go1.16/src/cmd/go/internal/modload/query.go#441).
func ( []string,  func( string) (bool, error)) ( string,  error) {
	 := LatestOf()
	if  == "" {
		return "", nil
	}
If the latest is a compatible version, use it.
	if !IsIncompatible() {
		return , nil
The latest version is incompatible. If there is a go.mod file at the latest compatible tagged version, assume the module author has adopted proper versioning, and use that latest compatible version. Otherwise, use this incompatible version.
	 := LatestOf(RemoveIf(, func( string) bool { return IsIncompatible() || IsPseudo() }))
No compatible versions; use the latest (incompatible) version.
		return , nil
	}
	,  := ()
	if  != nil {
		return "", 
	}
	if  {
		return , nil
	}
	return , nil
}
LatestOf returns the latest version of a module from a list of versions, using the go command's definition of latest: semver is observed, except that release versions are preferred to prerelease, and both are preferred to pseudo-versions. If versions is empty, the empty string is returned.
func ( []string) string {
	if len() == 0 {
		return ""
	}
	 := [0]
	for ,  := range [1:] {
		if Later(, ) {
			 = 
		}
	}
	return 
}
RemoveIf returns a copy of s that omits all values for which f returns true.
func ( []string,  func(string) bool) []string {
	var  []string
	for ,  := range  {
		if !() {
			 = append(, )
		}
	}
	return