-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvers.go
More file actions
160 lines (142 loc) · 4.7 KB
/
vers.go
File metadata and controls
160 lines (142 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// 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
package vers
// Version is the library version.
const Version = "0.1.0"
// 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 Parse(versURI string) (*Range, error) {
return defaultParser.Parse(versURI)
}
// 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 ParseNative(constraint string, scheme string) (*Range, error) {
return defaultParser.ParseNative(constraint, scheme)
}
// 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 Satisfies(version, constraint, scheme string) (bool, error) {
var r *Range
var err error
if scheme == "" {
r, err = Parse(constraint)
} else {
r, err = ParseNative(constraint, scheme)
}
if err != nil {
return false, err
}
return r.Contains(version), nil
}
// Compare compares two version strings.
// Returns -1 if a < b, 0 if a == b, 1 if a > b.
func Compare(a, b string) int {
return CompareVersions(a, b)
}
// 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 HighestSatisfying(versions []string, constraint, scheme string) (string, error) {
var r *Range
var err error
if scheme == "" {
r, err = Parse(constraint)
} else {
r, err = ParseNative(constraint, scheme)
}
if err != nil {
return "", err
}
var best string
for _, v := range versions {
if !r.Contains(v) {
continue
}
if best == "" || CompareWithScheme(v, best, scheme) > 0 {
best = v
}
}
return best, nil
}
// Valid checks if a version string is valid.
func Valid(version string) bool {
_, err := ParseVersion(version)
return err == nil
}
// Normalize normalizes a version string to a consistent format.
func Normalize(version string) (string, error) {
v, err := ParseVersion(version)
if err != nil {
return "", err
}
return v.String(), nil
}
// Exact creates a range that matches only the specified version.
func Exact(version string) *Range {
return NewRange([]Interval{ExactInterval(version)})
}
// GreaterThan creates a range for versions greater than (or equal to) the specified version.
func GreaterThan(version string, inclusive bool) *Range {
return NewRange([]Interval{GreaterThanInterval(version, inclusive)})
}
// LessThan creates a range for versions less than (or equal to) the specified version.
func LessThan(version string, inclusive bool) *Range {
return NewRange([]Interval{LessThanInterval(version, inclusive)})
}
// Unbounded creates a range that matches all versions.
func Unbounded() *Range {
return NewRange([]Interval{UnboundedInterval()})
}
// Empty creates a range that matches no versions.
func Empty() *Range {
return NewRange([]Interval{EmptyInterval()})
}
// ToVersString converts a Range back to a vers URI string.
func ToVersString(r *Range, scheme string) string {
return defaultParser.ToVersString(r, scheme)
}
var defaultParser = NewParser()