vers

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 7 Imported by: 4

README

vers

A Go implementation of the VERS specification for version range parsing and comparison across package ecosystems.

Installation

go get github.com/git-pkgs/vers

Usage

Parse VERS URIs

The VERS URI format provides a universal way to express version ranges:

package main

import (
    "fmt"
    "github.com/git-pkgs/vers"
)

func main() {
    // Parse a VERS URI
    r, _ := vers.Parse("vers:npm/>=1.0.0|<2.0.0")

    fmt.Println(r.Contains("1.5.0"))  // true
    fmt.Println(r.Contains("2.0.0"))  // false
    fmt.Println(r.Contains("0.9.0"))  // false
}
Parse Native Package Manager Syntax

Each package ecosystem has its own version constraint syntax. This library parses them all:

// npm: caret, tilde, x-ranges, hyphen ranges
r, _ := vers.ParseNative("^1.2.3", "npm")
r, _ = vers.ParseNative("~1.2.3", "npm")
r, _ = vers.ParseNative("1.0.0 - 2.0.0", "npm")
r, _ = vers.ParseNative(">=1.0.0 <2.0.0", "npm")

// Ruby gems: pessimistic operator
r, _ = vers.ParseNative("~> 1.2", "gem")
r, _ = vers.ParseNative(">= 1.0, < 2.0", "gem")

// Python: compatible release, exclusions
r, _ = vers.ParseNative("~=1.4.2", "pypi")
r, _ = vers.ParseNative(">=1.0.0,<2.0.0,!=1.5.0", "pypi")

// Maven/NuGet: bracket notation
r, _ = vers.ParseNative("[1.0,2.0)", "maven")
r, _ = vers.ParseNative("[1.0,)", "maven")

// Cargo: same syntax as npm
r, _ = vers.ParseNative("^1.2.3", "cargo")

// Go: comma-separated constraints
r, _ = vers.ParseNative(">=1.0.0,<2.0.0", "go")

// Debian: >> and << operators
r, _ = vers.ParseNative(">> 1.0", "deb")

// RPM
r, _ = vers.ParseNative(">= 1.0", "rpm")

// Conan, OpenSSL, and Nginx
r, _ = vers.ParseNative("^1.2", "conan")
r, _ = vers.ParseNative("1.1.1w, 3.0.0", "openssl")
r, _ = vers.ParseNative("0.8.40+", "nginx")
Check Version Satisfaction
// Using VERS URI (empty scheme)
ok, _ := vers.Satisfies("1.5.0", "vers:npm/>=1.0.0|<2.0.0", "")
fmt.Println(ok)  // true

// Using native syntax
ok, _ = vers.Satisfies("1.5.0", "^1.0.0", "npm")
fmt.Println(ok)  // true
Compare Versions
vers.Compare("1.2.3", "1.2.4")  // -1 (a < b)
vers.Compare("2.0.0", "1.9.9")  // 1  (a > b)
vers.Compare("1.0.0", "1.0.0")  // 0  (equal)

// Prerelease versions sort before stable
vers.Compare("1.0.0", "1.0.0-alpha")  // 1 (stable > prerelease)

// Use ecosystem-specific ordering where versions are not SemVer
vers.CompareWithScheme("1.0~rc1", "1.0", "deb")  // -1
vers.CompareWithScheme("1.0.beta1", "1.0", "gem") // -1
Version Validation and Normalization
vers.Valid("1.2.3")        // true
vers.Valid("invalid")      // false

v, _ := vers.Normalize("1")      // "1.0.0"
v, _ = vers.Normalize("1.2")     // "1.2.0"
v, _ = vers.Normalize("1.2.3")   // "1.2.3"

vers.ValidWithScheme("1:2.3.4-1", "deb") // true
v, _ = vers.NormalizeWithScheme("01!02.0RC1", "pypi") // "1!2.0rc1"
Create Ranges Programmatically
// Exact version
r := vers.Exact("1.2.3")

// Greater/less than
r = vers.GreaterThan("1.0.0", true)   // >=1.0.0
r = vers.GreaterThan("1.0.0", false)  // >1.0.0
r = vers.LessThan("2.0.0", false)     // <2.0.0

// Unbounded (matches all)
r = vers.Unbounded()

// Combine ranges
r1, _ := vers.ParseNative(">=1.0.0", "npm")
r2, _ := vers.ParseNative("<2.0.0", "npm")
intersection := r1.Intersect(r2)  // >=1.0.0 AND <2.0.0
union := r1.Union(r2)             // >=1.0.0 OR <2.0.0

// Add exclusions
r = r.Exclude("1.5.0")
Convert Back to VERS URI
r, _ := vers.ParseNative("^1.2.3", "npm")
uri := vers.ToVersString(r, "npm")
// vers:npm/>=1.2.3|<2.0.0

// Unbounded range
r = vers.Unbounded()
uri = vers.ToVersString(r, "npm")
// vers:npm/*

Supported Ecosystems

Ecosystem Scheme Example Syntax
npm npm ^1.2.3, ~1.2.3, >=1.0.0 <2.0.0, 1.x, 1.0.0 - 2.0.0
RubyGems gem, rubygems ~> 1.2, >= 1.0, < 2.0
PyPI pypi ~=1.4.2, >=1.0.0,<2.0.0, !=1.5.0
Maven maven [1.0,2.0), (1.0,2.0], [1.0,), [1.0]
NuGet nuget Same as Maven
Cargo cargo Same as npm
Go go, golang >=1.0.0,<2.0.0
Hex hex, elixir ~> 1.2, >= 1.0 and < 2.0
Debian deb, debian >> 1.0, << 2.0, >= 1.0
RPM rpm >= 1.0, <= 2.0
Conan conan ^1.2, ~1.2, >1 <2, `
OpenSSL openssl 1.1.1w, 1.1.1w, 3.0.0
Nginx nginx 0.8.40+, 0.7.52-0.8.39

Version comparison additionally supports semver, apk/alpine, alpm, gentoo, intdot, lexicographic, and datetime.

Development

Run Tests
go test ./...
Run Tests with Verbose Output
go test -v ./...
Run Specific Tests
go test -v -run TestParseNpmRange
Check Test Coverage
go test -cover ./...
Generate Coverage Report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
Run Benchmarks
go test -bench=. -benchmem

Run specific benchmarks:

go test -bench=BenchmarkContains -benchmem

License

MIT

Documentation

Overview

Package vers provides version range parsing and comparison according to the VERS specification.

VERS (Version Range Specification) is a universal format for expressing version ranges across different package ecosystems. This package supports parsing vers URIs, native package manager syntax, and provides version comparison functionality.

Quick Start:

// Parse a vers URI
r, _ := vers.Parse("vers:npm/>=1.2.3|<2.0.0")
r.Contains("1.5.0") // true

// Parse native package manager syntax
r, _ = vers.ParseNative("^1.2.3", "npm")

// Check if version satisfies constraint
vers.Satisfies("1.5.0", ">=1.0.0,<2.0.0", "npm") // true

// Compare versions
vers.Compare("1.2.3", "1.2.4") // -1

See https://github.com/package-url/purl-spec/blob/main/VERSION-RANGE-SPEC.rst

Index

Constants

View Source
const Version = "0.3.0"

Version is the library version.

Variables

View Source
var SemanticVersionRegex = regexp.MustCompile(`^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([^+]+))?(?:\+(.+))?$`)

SemanticVersionRegex matches semantic version strings (with optional v prefix).

View Source
var ValidOperators = []string{"=", "!=", "<", "<=", ">", ">="}

Valid constraint operators.

Functions

func Compare

func Compare(a, b string) int

Compare compares two version strings. Returns -1 if a < b, 0 if a == b, 1 if a > b.

func CompareVersions

func CompareVersions(a, b string) int

CompareVersions compares two version strings. Returns -1 if a < b, 0 if a == b, 1 if a > b.

func CompareWithScheme added in v0.2.0

func CompareWithScheme(a, b, scheme string) int

CompareWithScheme compares two version strings using scheme-specific rules. Returns -1 if a < b, 0 if a == b, 1 if a > b.

func HighestSatisfying added in v0.2.6

func HighestSatisfying(versions []string, constraint, scheme string) (string, error)

HighestSatisfying returns the highest version in versions that satisfies constraint under the given scheme. Versions that fail to parse are skipped. Returns ("", nil) when no version in the list satisfies the constraint — a non-nil error is reserved for a constraint that itself fails to parse.

Common shape for package-manager resolvers: fetch the list of available versions from the registry, then pick the highest one that still satisfies the user's manifest constraint.

If scheme is empty, constraint is parsed as a vers URI.

func Normalize

func Normalize(version string) (string, error)

Normalize normalizes a version string to a consistent format.

func NormalizeWithScheme added in v0.3.0

func NormalizeWithScheme(version, scheme string) (string, error)

NormalizeWithScheme normalizes a version without discarding scheme-specific components. Schemes without a canonical text form are validated and trimmed.

func Satisfies

func Satisfies(version, constraint, scheme string) (bool, error)

Satisfies checks if a version satisfies a constraint.

If scheme is empty, constraint is parsed as a vers URI. Otherwise, constraint is parsed as native package manager syntax.

func ToVersString

func ToVersString(r *Range, scheme string) string

ToVersString converts a Range back to a vers URI string.

func Valid

func Valid(version string) bool

Valid checks if a version string is valid.

func ValidWithScheme added in v0.3.0

func ValidWithScheme(version, scheme string) bool

ValidWithScheme checks whether a version is valid for the given scheme.

Types

type Constraint

type Constraint struct {
	Operator string
	Version  string
	Scheme   string
}

Constraint represents a single version constraint (e.g., ">=1.2.3").

func ParseConstraint

func ParseConstraint(s string) (*Constraint, error)

ParseConstraint parses a constraint string into a Constraint.

func ParseConstraintWithScheme added in v0.3.0

func ParseConstraintWithScheme(s, scheme string) (*Constraint, error)

ParseConstraintWithScheme parses a constraint using scheme-specific comparison rules.

func (*Constraint) IsExclusion

func (c *Constraint) IsExclusion() bool

IsExclusion returns true if this is an exclusion constraint (!=).

func (*Constraint) Satisfies

func (c *Constraint) Satisfies(version string) bool

Satisfies checks if a version satisfies this constraint.

func (*Constraint) SatisfiesWithScheme added in v0.3.0

func (c *Constraint) SatisfiesWithScheme(version, scheme string) bool

SatisfiesWithScheme checks the constraint using the specified version scheme.

func (*Constraint) String

func (c *Constraint) String() string

String returns the constraint as a string.

func (*Constraint) ToInterval

func (c *Constraint) ToInterval() (Interval, bool)

ToInterval converts this constraint to an interval. Returns nil for exclusion constraints (!=).

type Interval

type Interval struct {
	Min          string
	Max          string
	MinInclusive bool
	MaxInclusive bool
}

Interval represents a mathematical interval of versions. For example, [1.0.0, 2.0.0) represents versions from 1.0.0 (inclusive) to 2.0.0 (exclusive).

func EmptyInterval

func EmptyInterval() Interval

EmptyInterval creates an interval that matches no versions.

func ExactInterval

func ExactInterval(version string) Interval

ExactInterval creates an interval that matches exactly one version.

func GreaterThanInterval

func GreaterThanInterval(version string, inclusive bool) Interval

GreaterThanInterval creates an interval for versions greater than the given version.

func LessThanInterval

func LessThanInterval(version string, inclusive bool) Interval

LessThanInterval creates an interval for versions less than the given version.

func NewInterval

func NewInterval(min, max string, minInclusive, maxInclusive bool) Interval

NewInterval creates a new interval with the given bounds.

func UnboundedInterval

func UnboundedInterval() Interval

UnboundedInterval creates an interval that matches all versions.

func (Interval) Adjacent

func (i Interval) Adjacent(other Interval) bool

Adjacent returns true if the two intervals are adjacent (can be merged).

func (Interval) AdjacentWithScheme added in v0.3.0

func (i Interval) AdjacentWithScheme(other Interval, scheme string) bool

AdjacentWithScheme reports adjacency under a version scheme.

func (Interval) Contains

func (i Interval) Contains(version string) bool

Contains checks if the interval contains the given version.

func (Interval) ContainsWithScheme added in v0.3.0

func (i Interval) ContainsWithScheme(version, scheme string) bool

ContainsWithScheme checks containment under a version scheme.

func (Interval) Intersect

func (i Interval) Intersect(other Interval) Interval

Intersect returns the intersection of two intervals.

func (Interval) IntersectWithScheme added in v0.3.0

func (i Interval) IntersectWithScheme(other Interval, scheme string) Interval

IntersectWithScheme returns the intersection under a version scheme.

func (Interval) IsEmpty

func (i Interval) IsEmpty() bool

IsEmpty returns true if this interval matches no versions.

func (Interval) IsEmptyWithScheme added in v0.3.0

func (i Interval) IsEmptyWithScheme(scheme string) bool

IsEmptyWithScheme reports whether the interval is empty under a version scheme.

func (Interval) IsUnbounded

func (i Interval) IsUnbounded() bool

IsUnbounded returns true if this interval matches all versions.

func (Interval) Overlaps

func (i Interval) Overlaps(other Interval) bool

Overlaps returns true if the two intervals overlap.

func (Interval) OverlapsWithScheme added in v0.3.0

func (i Interval) OverlapsWithScheme(other Interval, scheme string) bool

OverlapsWithScheme reports overlap under a version scheme.

func (Interval) String

func (i Interval) String() string

String returns a string representation of the interval.

func (Interval) StringWithScheme added in v0.3.0

func (i Interval) StringWithScheme(scheme string) string

StringWithScheme formats the interval under a version scheme.

func (Interval) Union

func (i Interval) Union(other Interval) *Interval

Union returns the union of two intervals, or nil if they cannot be merged.

func (Interval) UnionWithScheme added in v0.3.0

func (i Interval) UnionWithScheme(other Interval, scheme string) *Interval

UnionWithScheme returns the union under a version scheme.

type Parser

type Parser struct{}

Parser handles parsing of vers URIs and native package manager syntax.

func NewParser

func NewParser() *Parser

NewParser creates a new Parser.

func (*Parser) Parse

func (p *Parser) Parse(versURI string) (*Range, error)

Parse parses a vers URI string into a Range.

func (*Parser) ParseNative

func (p *Parser) ParseNative(constraint string, scheme string) (*Range, error)

ParseNative parses a native package manager version range into a Range.

func (*Parser) ToVersString

func (p *Parser) ToVersString(r *Range, scheme string) string

ToVersString converts a Range back to a vers URI string.

type Range

type Range struct {
	Intervals  []Interval
	Exclusions []string // Versions to exclude (from != constraints)
	// RawConstraints stores the original constraints for VERS output (not merged)
	RawConstraints []Interval
	// Scheme is the versioning scheme this range was parsed under.
	// It selects the comparison rules used by Contains. Empty means generic.
	Scheme string
}

Range represents a version range as a collection of intervals. Multiple intervals represent a union (OR) of ranges.

func Empty

func Empty() *Range

Empty creates a range that matches no versions.

func Exact

func Exact(version string) *Range

Exact creates a range that matches only the specified version.

func GreaterThan

func GreaterThan(version string, inclusive bool) *Range

GreaterThan creates a range for versions greater than (or equal to) the specified version.

func LessThan

func LessThan(version string, inclusive bool) *Range

LessThan creates a range for versions less than (or equal to) the specified version.

func NewRange

func NewRange(intervals []Interval) *Range

NewRange creates a new Range from intervals.

func Parse

func Parse(versURI string) (*Range, error)

Parse parses a vers URI string into a Range.

The vers URI format is: vers:<scheme>/<constraints> For example: vers:npm/>=1.2.3|<2.0.0

Use vers:<scheme>/* for an unbounded range that matches all versions.

func ParseNative

func ParseNative(constraint string, scheme string) (*Range, error)

ParseNative parses a native package manager version range into a Range.

Supported schemes:

  • npm: ^1.2.3, ~1.2.3, 1.2.3 - 2.0.0, >=1.0.0 <2.0.0, ||
  • gem/rubygems: ~> 1.2, >= 1.0, < 2.0
  • pypi: >=1.0,<2.0, ~=1.4.2, !=1.5.0
  • maven: [1.0,2.0), (1.0,2.0], [1.0,)
  • nuget: [1.0,2.0), (1.0,2.0]
  • cargo: ^1.2.3, ~1.2.3, >=1.0.0, <2.0.0
  • go: >=1.0.0, <2.0.0
  • hex/elixir: ~> 1.2, >= 1.0 and < 2.0
  • deb/debian: >= 1.0, << 2.0
  • rpm: >= 1.0, <= 2.0
  • conan: ^1.2, ~1.2, >1 <2, ||
  • openssl: exact versions, optionally comma-separated
  • nginx: 0.8.40+, 0.7.52-0.8.39

func Unbounded

func Unbounded() *Range

Unbounded creates a range that matches all versions.

func (*Range) Contains

func (r *Range) Contains(version string) bool

Contains checks if the range contains the given version.

func (*Range) Exclude

func (r *Range) Exclude(version string) *Range

Exclude returns a new Range that excludes the given version.

func (*Range) Intersect

func (r *Range) Intersect(other *Range) *Range

Intersect returns a new Range that is the intersection of this range and another.

func (*Range) IntersectChecked added in v0.3.0

func (r *Range) IntersectChecked(other *Range) (*Range, error)

IntersectChecked returns the intersection of ranges that use compatible schemes.

func (*Range) IsEmpty

func (r *Range) IsEmpty() bool

IsEmpty returns true if this range matches no versions.

func (*Range) IsUnbounded

func (r *Range) IsUnbounded() bool

IsUnbounded returns true if this range matches all versions.

func (*Range) String

func (r *Range) String() string

String returns a string representation of the range.

func (*Range) Union

func (r *Range) Union(other *Range) *Range

Union returns a new Range that is the union of this range and another.

func (*Range) UnionChecked added in v0.3.0

func (r *Range) UnionChecked(other *Range) (*Range, error)

UnionChecked returns the union of ranges that use compatible schemes.

type VersionInfo

type VersionInfo struct {
	Major      int
	Minor      int
	Patch      int
	Prerelease string
	Build      string
	Original   string
}

VersionInfo represents a parsed version with its components.

func ParseVersion

func ParseVersion(s string) (*VersionInfo, error)

ParseVersion parses a version string into its components.

func (*VersionInfo) Compare

func (v *VersionInfo) Compare(other *VersionInfo) int

Compare compares this version to another. Returns -1 if v < other, 0 if v == other, 1 if v > other.

func (*VersionInfo) IncrementMajor

func (v *VersionInfo) IncrementMajor() *VersionInfo

IncrementMajor returns a new version with major incremented.

func (*VersionInfo) IncrementMinor

func (v *VersionInfo) IncrementMinor() *VersionInfo

IncrementMinor returns a new version with minor incremented.

func (*VersionInfo) IncrementPatch

func (v *VersionInfo) IncrementPatch() *VersionInfo

IncrementPatch returns a new version with patch incremented.

func (*VersionInfo) IsPrerelease

func (v *VersionInfo) IsPrerelease() bool

IsPrerelease returns true if this is a prerelease version.

func (*VersionInfo) IsStable

func (v *VersionInfo) IsStable() bool

IsStable returns true if this is a stable release (no prerelease).

func (*VersionInfo) String

func (v *VersionInfo) String() string

String returns the normalized version string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL