Skip to content

Commit 5c4c9f6

Browse files
committed
Close #2 Also, docs.
1 parent a685e01 commit 5c4c9f6

2 files changed

Lines changed: 128 additions & 7 deletions

File tree

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,35 @@ The following range styles are supported:
8484

8585
Ranges can be joined with either a space (which implies "and") or a
8686
`||` (which implies "or").
87+
88+
## Functions
89+
90+
* valid(v): Return the parsed version, or null if it's not valid.
91+
92+
### Comparison
93+
94+
* gt(v1, v2): `v1 > v2`
95+
* gte(v1, v2): `v1 >= v2`
96+
* lt(v1, v2): `v1 < v2`
97+
* lte(v1, v2): `v1 <= v2`
98+
* eq(v1, v2): `v1 == v2` This is true if they're logically equivalent,
99+
even if they're not the exact same string. You already know how to
100+
compare strings.
101+
* neq(v1, v2): `v1 != v2` The opposite of eq.
102+
* cmp(v1, comparator, v2): Pass in a comparison string, and it'll call
103+
the corresponding function above. `"==="` and `"!=="` do simple
104+
string comparison, but are included for completeness. Throws if an
105+
invalid comparison string is provided.
106+
* compare(v1, v2): Return 0 if v1 == v2, or 1 if v1 is greater, or -1 if
107+
v2 is greater. Sorts in ascending order if passed to Array.sort().
108+
* rcompare(v1, v2): The reverse of compare. Sorts an array of versions
109+
in descending order when passed to Array.sort().
110+
111+
112+
### Ranges
113+
114+
* validRange(range): Return the valid range or null if it's not valid
115+
* satisfies(version, range): Return true if the version satisfies the
116+
range.
117+
* maxSatisfying(versions, range): Return the highest version in the list
118+
that satisfies the range, or null if none of them do.

semver.js

Lines changed: 96 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// This implementation is a *hair* less strict in that it allows
44
// v1.2.3 things, and also tags that don't begin with a char.
55

6-
var semver = "[v=]*([0-9]+)" // major
6+
var semver = "\\s*[v=]*\\s*([0-9]+)" // major
77
+ "\\.([0-9]+)" // minor
88
+ "\\.([0-9]+)" // patch
99
+ "(-[0-9]+-?)?" // build
@@ -30,7 +30,13 @@ exports.clean = clean
3030
exports.compare = compare
3131
exports.satisfies = satisfies
3232
exports.gt = gt
33+
exports.gte = gte
3334
exports.lt = lt
35+
exports.lte = lte
36+
exports.eq = eq
37+
exports.neq = neq
38+
exports.cmp = cmp
39+
3440
exports.valid = valid
3541
exports.validPackage = validPackage
3642
exports.validRange = validRange
@@ -41,9 +47,11 @@ function clean (ver) {
4147
if (!v) return v
4248
return [v[1]||'', v[2]||'', v[3]||''].join(".") + (v[4]||'') + (v[5]||'')
4349
}
50+
4451
function valid (version) {
4552
return exports.parse(version) && version.trim().replace(/^[v=]+/, '')
4653
}
54+
4755
function validPackage (version) {
4856
return version.match(expressions.parsePackage) && version.trim()
4957
}
@@ -97,6 +105,7 @@ function replaceXRanges (ranges) {
97105
.map(replaceXRange)
98106
.join(" ")
99107
}
108+
100109
function replaceXRange (version) {
101110
return version.trim().replace(expressions.parseXRange,
102111
function (v, gtlt, M, m, p) {
@@ -191,10 +200,32 @@ function satisfies (version, range) {
191200

192201
// return v1 > v2 ? 1 : -1
193202
function compare (v1, v2) {
194-
return v1 === v2 ? 0 : gt(v1, v2) ? 1 : -1
203+
var g = gt(v1, v2)
204+
return g === null ? 0 : g ? 1 : -1
205+
}
206+
207+
function rcompare (v1, v2) {
208+
return compare(v2, v1)
195209
}
196210

197211
function lt (v1, v2) { return gt(v2, v1) }
212+
function gte (v1, v2) { return !lt(v1, v2) }
213+
function lte (v1, v2) { return !gt(v1, v2) }
214+
function eq (v1, v2) { return gt(v1, v2) === null }
215+
function neq (v1, v2) { return gt(v1, v2) !== null }
216+
function cmp (v1, c, v2) {
217+
switch (c) {
218+
case ">": return gt(v1, v2)
219+
case "<": return lt(v1, v2)
220+
case ">=": return gte(v1, v2)
221+
case "<=": return lte(v1, v2)
222+
case "==": return eq(v1, v2)
223+
case "!=": return neq(v1, v2)
224+
case "===": return v1 === v2
225+
case "!==": return v1 !== v2
226+
default: throw new Error("Y U NO USE VALID COMPARATOR!? "+c)
227+
}
228+
}
198229

199230
// return v1 > v2
200231
function num (v) {
@@ -214,7 +245,13 @@ function gt (v1, v2) {
214245
// no tag is > than any tag, or use lexicographical order.
215246
var tag1 = v1[5] || ""
216247
, tag2 = v2[5] || ""
217-
return !!tag2 && (!tag1 || tag1 > tag2)
248+
249+
// kludge: null means they were equal. falsey, and detectable.
250+
// embarrassingly overclever, though, I know.
251+
return tag1 === tag2 ? null
252+
: !tag1 ? true
253+
: !tag2 ? false
254+
: tag1 > tag2
218255
}
219256

220257
if (module === require.main) { // tests below
@@ -243,11 +280,63 @@ var assert = require("assert")
243280
, ["1.2.3-4-foo", "1.2.3"]
244281
, ["1.2.3-5", "1.2.3-5-foo"]
245282
, ["1.2.3-5", "1.2.3-4"]
283+
, ["1.2.3-5-foo", "1.2.3-5-Foo"]
284+
].forEach(function (v) {
285+
var v0 = v[0]
286+
, v1 = v[1]
287+
assert.ok(gt(v0, v1), "gt('"+v0+"', '"+v1+"')")
288+
assert.ok(lt(v1, v0), "lt('"+v1+"', '"+v0+"')")
289+
assert.ok(!gt(v1, v0), "!gt('"+v1+"', '"+v0+"')")
290+
assert.ok(!lt(v0, v1), "!lt('"+v0+"', '"+v1+"')")
291+
assert.ok(eq(v0, v0), "eq('"+v0+"', '"+v0+"')")
292+
assert.ok(eq(v1, v1), "eq('"+v1+"', '"+v1+"')")
293+
assert.ok(neq(v0, v1), "neq('"+v0+"', '"+v1+"')")
294+
assert.ok(cmp(v1, "==", v1), "cmp("+v1+"=="+v1+")")
295+
assert.ok(cmp(v0, ">=", v1), "cmp("+v0+"<="+v1+")")
296+
assert.ok(cmp(v1, "<=", v0), "cmp("+v1+">="+v0+")")
297+
assert.ok(cmp(v0, "!=", v1), "cmp("+v0+"!="+v1+")")
298+
})
299+
300+
// equality tests
301+
; [ ["1.2.3", "v1.2.3"]
302+
, ["1.2.3", "=1.2.3"]
303+
, ["1.2.3", "v 1.2.3"]
304+
, ["1.2.3", "= 1.2.3"]
305+
, ["1.2.3", " v1.2.3"]
306+
, ["1.2.3", " =1.2.3"]
307+
, ["1.2.3", " v 1.2.3"]
308+
, ["1.2.3", " = 1.2.3"]
309+
, ["1.2.3-0", "v1.2.3-0"]
310+
, ["1.2.3-0", "=1.2.3-0"]
311+
, ["1.2.3-0", "v 1.2.3-0"]
312+
, ["1.2.3-0", "= 1.2.3-0"]
313+
, ["1.2.3-0", " v1.2.3-0"]
314+
, ["1.2.3-0", " =1.2.3-0"]
315+
, ["1.2.3-0", " v 1.2.3-0"]
316+
, ["1.2.3-0", " = 1.2.3-0"]
317+
, ["1.2.3-01", "v1.2.3-1"]
318+
, ["1.2.3-01", "=1.2.3-1"]
319+
, ["1.2.3-01", "v 1.2.3-1"]
320+
, ["1.2.3-01", "= 1.2.3-1"]
321+
, ["1.2.3-01", " v1.2.3-1"]
322+
, ["1.2.3-01", " =1.2.3-1"]
323+
, ["1.2.3-01", " v 1.2.3-1"]
324+
, ["1.2.3-01", " = 1.2.3-1"]
325+
, ["1.2.3beta", "v1.2.3beta"]
326+
, ["1.2.3beta", "=1.2.3beta"]
327+
, ["1.2.3beta", "v 1.2.3beta"]
328+
, ["1.2.3beta", "= 1.2.3beta"]
329+
, ["1.2.3beta", " v1.2.3beta"]
330+
, ["1.2.3beta", " =1.2.3beta"]
331+
, ["1.2.3beta", " v 1.2.3beta"]
332+
, ["1.2.3beta", " = 1.2.3beta"]
246333
].forEach(function (v) {
247-
assert.ok(gt(v[0], v[1]), "gt('"+v[0]+"', '"+v[1]+"')")
248-
assert.ok(lt(v[1], v[0]), "lt('"+v[1]+"', '"+v[0]+"')")
249-
assert.ok(!gt(v[1], v[0]), "!gt('"+v[1]+"', '"+v[0]+"')")
250-
assert.ok(!lt(v[0], v[1]), "!lt('"+v[0]+"', '"+v[1]+"')")
334+
var v0 = v[0]
335+
, v1 = v[1]
336+
assert.ok(eq(v0, v1), "eq('"+v0+"', '"+v1+"')")
337+
assert.ok(eq(v0, v1), "eq('"+v0+"', '"+v1+"')")
338+
assert.ok(eq(v0, v1), "eq('"+v0+"', '"+v1+"')")
339+
assert.ok(eq(v0, v1), "eq('"+v0+"', '"+v1+"')")
251340
})
252341

253342

0 commit comments

Comments
 (0)