vers

package module
v0.2.3 Latest Latest
Warning

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

Go to latest
Published: Feb 22, 2026 License: MIT Imports: 5 Imported by: 3

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")
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)
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"
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
Debian deb, debian >> 1.0, << 2.0, >= 1.0
RPM rpm >= 1.0, <= 2.0

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.1.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 Normalize

func Normalize(version string) (string, error)

Normalize normalizes a version string to a consistent format.

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.

Types

type Constraint

type Constraint struct {
	Operator string
	Version  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 (*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) 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) Contains

func (i Interval) Contains(version string) bool

Contains checks if the interval contains the given version.

func (Interval) Intersect

func (i Interval) Intersect(other Interval) Interval

Intersect returns the intersection of two intervals.

func (Interval) IsEmpty

func (i Interval) IsEmpty() bool

IsEmpty returns true if this interval matches no versions.

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) String

func (i Interval) String() string

String returns a string representation of the interval.

func (Interval) Union

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

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

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
}

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
  • deb/debian: >= 1.0, << 2.0
  • rpm: >= 1.0, <= 2.0

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) 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.

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