// Copyright 2018 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 semver implements comparison of semantic version strings. // In this package, semantic version strings must begin with a leading "v", // as in "v1.0.0". // // The general form of a semantic version string accepted by this package is // // vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]] // // where square brackets indicate optional parts of the syntax; // MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros; // PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers // using only alphanumeric characters and hyphens; and // all-numeric PRERELEASE identifiers must not have leading zeros. // // This package follows Semantic Versioning 2.0.0 (see semver.org) // with two exceptions. First, it requires the "v" prefix. Second, it recognizes // vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes) // as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
package semver import // parsed returns the parsed form of a semantic version string. type parsed struct { major string minor string patch string short string prerelease string build string } // IsValid reports whether v is a valid semantic version string. func ( string) bool { , := parse() return } // Canonical returns the canonical formatting of the semantic version v. // It fills in any missing .MINOR or .PATCH and discards build metadata. // Two semantic versions compare equal only if their canonical formattings // are identical strings. // The canonical invalid semantic version is the empty string. func ( string) string { , := parse() if ! { return "" } if .build != "" { return [:len()-len(.build)] } if .short != "" { return + .short } return } // Major returns the major version prefix of the semantic version v. // For example, Major("v2.1.0") == "v2". // If v is an invalid semantic version string, Major returns the empty string. func ( string) string { , := parse() if ! { return "" } return [:1+len(.major)] } // MajorMinor returns the major.minor version prefix of the semantic version v. // For example, MajorMinor("v2.1.0") == "v2.1". // If v is an invalid semantic version string, MajorMinor returns the empty string. func ( string) string { , := parse() if ! { return "" } := 1 + len(.major) if := + 1 + len(.minor); <= len() && [] == '.' && [+1:] == .minor { return [:] } return [:] + "." + .minor } // Prerelease returns the prerelease suffix of the semantic version v. // For example, Prerelease("v2.1.0-pre+meta") == "-pre". // If v is an invalid semantic version string, Prerelease returns the empty string. func ( string) string { , := parse() if ! { return "" } return .prerelease } // Build returns the build suffix of the semantic version v. // For example, Build("v2.1.0+meta") == "+meta". // If v is an invalid semantic version string, Build returns the empty string. func ( string) string { , := parse() if ! { return "" } return .build } // Compare returns an integer comparing two versions according to // semantic version precedence. // The result will be 0 if v == w, -1 if v < w, or +1 if v > w. // // An invalid semantic version string is considered less than a valid one. // All invalid semantic version strings compare equal to each other. func (, string) int { , := parse() , := parse() if ! && ! { return 0 } if ! { return -1 } if ! { return +1 } if := compareInt(.major, .major); != 0 { return } if := compareInt(.minor, .minor); != 0 { return } if := compareInt(.patch, .patch); != 0 { return } return comparePrerelease(.prerelease, .prerelease) } // Max canonicalizes its arguments and then returns the version string // that compares greater. // // Deprecated: use Compare instead. In most cases, returning a canonicalized // version is not expected or desired. func (, string) string { = Canonical() = Canonical() if Compare(, ) > 0 { return } return } // ByVersion implements sort.Interface for sorting semantic version strings. type ByVersion []string func ( ByVersion) () int { return len() } func ( ByVersion) (, int) { [], [] = [], [] } func ( ByVersion) (, int) bool { := Compare([], []) if != 0 { return < 0 } return [] < [] } // Sort sorts a list of semantic version strings using ByVersion. func ( []string) { sort.Sort(ByVersion()) } func ( string) ( parsed, bool) { if == "" || [0] != 'v' { return } .major, , = parseInt([1:]) if ! { return } if == "" { .minor = "0" .patch = "0" .short = ".0.0" return } if [0] != '.' { = false return } .minor, , = parseInt([1:]) if ! { return } if == "" { .patch = "0" .short = ".0" return } if [0] != '.' { = false return } .patch, , = parseInt([1:]) if ! { return } if len() > 0 && [0] == '-' { .prerelease, , = parsePrerelease() if ! { return } } if len() > 0 && [0] == '+' { .build, , = parseBuild() if ! { return } } if != "" { = false return } = true return } func ( string) (, string, bool) { if == "" { return } if [0] < '0' || '9' < [0] { return } := 1 for < len() && '0' <= [] && [] <= '9' { ++ } if [0] == '0' && != 1 { return } return [:], [:], true } func ( string) (, string, bool) { // "A pre-release version MAY be denoted by appending a hyphen and // a series of dot separated identifiers immediately following the patch version. // Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. // Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes." if == "" || [0] != '-' { return } := 1 := 1 for < len() && [] != '+' { if !isIdentChar([]) && [] != '.' { return } if [] == '.' { if == || isBadNum([:]) { return } = + 1 } ++ } if == || isBadNum([:]) { return } return [:], [:], true } func ( string) (, string, bool) { if == "" || [0] != '+' { return } := 1 := 1 for < len() { if !isIdentChar([]) && [] != '.' { return } if [] == '.' { if == { return } = + 1 } ++ } if == { return } return [:], [:], true } func ( byte) bool { return 'A' <= && <= 'Z' || 'a' <= && <= 'z' || '0' <= && <= '9' || == '-' } func ( string) bool { := 0 for < len() && '0' <= [] && [] <= '9' { ++ } return == len() && > 1 && [0] == '0' } func ( string) bool { := 0 for < len() && '0' <= [] && [] <= '9' { ++ } return == len() } func (, string) int { if == { return 0 } if len() < len() { return -1 } if len() > len() { return +1 } if < { return -1 } else { return +1 } } func (, string) int { // "When major, minor, and patch are equal, a pre-release version has // lower precedence than a normal version. // Example: 1.0.0-alpha < 1.0.0. // Precedence for two pre-release versions with the same major, minor, // and patch version MUST be determined by comparing each dot separated // identifier from left to right until a difference is found as follows: // identifiers consisting of only digits are compared numerically and // identifiers with letters or hyphens are compared lexically in ASCII // sort order. Numeric identifiers always have lower precedence than // non-numeric identifiers. A larger set of pre-release fields has a // higher precedence than a smaller set, if all of the preceding // identifiers are equal. // Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < // 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0." if == { return 0 } if == "" { return +1 } if == "" { return -1 } for != "" && != "" { = [1:] // skip - or . = [1:] // skip - or . var , string , = nextIdent() , = nextIdent() if != { := isNum() := isNum() if != { if { return -1 } else { return +1 } } if { if len() < len() { return -1 } if len() > len() { return +1 } } if < { return -1 } else { return +1 } } } if == "" { return -1 } else { return +1 } } func ( string) (, string) { := 0 for < len() && [] != '.' { ++ } return [:], [:] }