Commit cd20683c authored by David Dollar's avatar David Dollar

vendor node-semver without submodule

parent 10549e6f
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
All rights reserved.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
semver(1) -- The semantic versioner for npm
===========================================
## Usage
$ npm install semver
semver.valid('1.2.3') // true
semver.valid('a.b.c') // false
semver.clean(' =v1.2.3 ') // '1.2.3'
semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
semver.gt('1.2.3', '9.8.7') // false
semver.lt('1.2.3', '9.8.7') // true
As a command-line utility:
$ semver -h
Usage: semver -v <version> [-r <range>]
Test if version(s) satisfy the supplied range(s),
and sort them.
Multiple versions or ranges may be supplied.
Program exits successfully if any valid version satisfies
all supplied ranges, and prints all satisfying versions.
If no versions are valid, or ranges are not satisfied,
then exits failure.
Versions are printed in ascending order, so supplying
multiple versions to the utility will just sort them.
## Versions
A version is the following things, in this order:
* a number (Major)
* a period
* a number (minor)
* a period
* a number (patch)
* OPTIONAL: a hyphen, followed by a number (build)
* OPTIONAL: a collection of pretty much any non-whitespace characters
(tag)
A leading `"="` or `"v"` character is stripped off and ignored.
## Comparisons
The ordering of versions is done using the following algorithm, given
two versions and asked to find the greater of the two:
* If the majors are numerically different, then take the one
with a bigger major number. `2.3.4 > 1.3.4`
* If the minors are numerically different, then take the one
with the bigger minor number. `2.3.4 > 2.2.4`
* If the patches are numerically different, then take the one with the
bigger patch number. `2.3.4 > 2.3.3`
* If only one of them has a build number, then take the one with the
build number. `2.3.4-0 > 2.3.4`
* If they both have build numbers, and the build numbers are numerically
different, then take the one with the bigger build number.
`2.3.4-10 > 2.3.4-9`
* If only one of them has a tag, then take the one without the tag.
`2.3.4 > 2.3.4-beta`
* If they both have tags, then take the one with the lexicographically
larger tag. `2.3.4-beta > 2.3.4-alpha`
* At this point, they're equal.
## Ranges
The following range styles are supported:
* `>1.2.3` Greater than a specific version.
* `<1.2.3` Less than
* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`
* `~1.2.3` := `>=1.2.3 <1.3.0`
* `~1.2` := `>=1.2.0 <2.0.0`
* `~1` := `>=1.0.0 <2.0.0`
* `1.2.x` := `>=1.2.0 <1.3.0`
* `1.x` := `>=1.0.0 <2.0.0`
Ranges can be joined with either a space (which implies "and") or a
`||` (which implies "or").
## Functions
* valid(v): Return the parsed version, or null if it's not valid.
* inc(v, release): Return the version incremented by the release type
(major, minor, patch, or build), or null if it's not valid.
### Comparison
* gt(v1, v2): `v1 > v2`
* gte(v1, v2): `v1 >= v2`
* lt(v1, v2): `v1 < v2`
* lte(v1, v2): `v1 <= v2`
* eq(v1, v2): `v1 == v2` This is true if they're logically equivalent,
even if they're not the exact same string. You already know how to
compare strings.
* neq(v1, v2): `v1 != v2` The opposite of eq.
* cmp(v1, comparator, v2): Pass in a comparison string, and it'll call
the corresponding function above. `"==="` and `"!=="` do simple
string comparison, but are included for completeness. Throws if an
invalid comparison string is provided.
* compare(v1, v2): Return 0 if v1 == v2, or 1 if v1 is greater, or -1 if
v2 is greater. Sorts in ascending order if passed to Array.sort().
* rcompare(v1, v2): The reverse of compare. Sorts an array of versions
in descending order when passed to Array.sort().
### Ranges
* validRange(range): Return the valid range or null if it's not valid
* satisfies(version, range): Return true if the version satisfies the
range.
* maxSatisfying(versions, range): Return the highest version in the list
that satisfies the range, or null if none of them do.
#!/usr/bin/env node
// Standalone semver comparison program.
// Exits successfully and prints matching version(s) if
// any supplied version is valid and passes all tests.
var argv = process.argv.slice(2)
, versions = []
, range = []
, gt = []
, lt = []
, eq = []
, semver = require("../semver")
main()
function main () {
if (!argv.length) return help()
while (argv.length) {
var a
switch (a = argv.shift()) {
case "-v": case "--version":
versions.push(argv.shift())
break
case "-r": case "--range":
range.push(argv.shift())
break
case "-h": case "--help": case "-?":
return help()
default:
versions.push(a)
break
}
}
versions = versions.filter(semver.valid)
for (var i = 0, l = range.length; i < l ; i ++) {
versions = versions.filter(function (v) {
return semver.satisfies(v, range[i])
})
if (!versions.length) return fail()
}
return success(versions)
}
function fail () { process.exit(1) }
function success () {
versions.sort(semver.compare)
.map(semver.clean)
.forEach(function (v,i,_) { console.log(v) })
}
function help () {
console.log(["Usage: semver -v <version> [-r <range>]"
,"Test if version(s) satisfy the supplied range(s),"
,"and sort them."
,""
,"Multiple versions or ranges may be supplied."
,""
,"Program exits successfully if any valid version satisfies"
,"all supplied ranges, and prints all satisfying versions."
,""
,"If no versions are valid, or ranges are not satisfied,"
,"then exits failure."
,""
,"Versions are printed in ascending order, so supplying"
,"multiple versions to the utility will just sort them."
].join("\n"))
}
{ "name" : "semver"
, "version" : "1.0.12"
, "description" : "The semantic version parser used by npm."
, "main" : "semver.js"
, "scripts" : { "test" : "tap test.js" }
, "devDependencies": { "tap" : "0.x >=0.0.4" }
, "license" :
{ "type" : "MIT"
, "url" : "https://github.com/isaacs/semver/raw/master/LICENSE" }
, "repository" : "git://github.com/isaacs/node-semver.git"
, "bin" : { "semver" : "./bin/semver" } }
;(function (exports) { // nothing in here is node-specific.
// See http://semver.org/
// This implementation is a *hair* less strict in that it allows
// v1.2.3 things, and also tags that don't begin with a char.
var semver = "\\s*[v=]*\\s*([0-9]+)" // major
+ "\\.([0-9]+)" // minor
+ "\\.([0-9]+)" // patch
+ "(-[0-9]+-?)?" // build
+ "([a-zA-Z-][a-zA-Z0-9-\.:]*)?" // tag
, exprComparator = "^((<|>)?=?)\s*("+semver+")$|^$"
, xRangePlain = "[v=]*([0-9]+|x|X|\\*)"
+ "(?:\\.([0-9]+|x|X|\\*)"
+ "(?:\\.([0-9]+|x|X|\\*)"
+ "([a-zA-Z-][a-zA-Z0-9-\.:]*)?)?)?"
, xRange = "((?:<|>)?=?)?\\s*" + xRangePlain
, exprSpermy = "(?:~>?)"+xRange
, expressions = exports.expressions =
{ parse : new RegExp("^\\s*"+semver+"\\s*$")
, parsePackage : new RegExp("^\\s*([^\/]+)[-@](" +semver+")\\s*$")
, parseRange : new RegExp(
"^\\s*(" + semver + ")\\s+-\\s+(" + semver + ")\\s*$")
, validComparator : new RegExp("^"+exprComparator+"$")
, parseXRange : new RegExp("^"+xRange+"$")
, parseSpermy : new RegExp("^"+exprSpermy+"$")
}
Object.getOwnPropertyNames(expressions).forEach(function (i) {
exports[i] = function (str) {
return ("" + (str || "")).match(expressions[i])
}
})
exports.rangeReplace = ">=$1 <=$7"
exports.clean = clean
exports.compare = compare
exports.satisfies = satisfies
exports.gt = gt
exports.gte = gte
exports.lt = lt
exports.lte = lte
exports.eq = eq
exports.neq = neq
exports.cmp = cmp
exports.inc = inc
exports.valid = valid
exports.validPackage = validPackage
exports.validRange = validRange
exports.maxSatisfying = maxSatisfying
exports.replaceStars = replaceStars
exports.toComparators = toComparators
function stringify (version) {
var v = version
return [v[1]||'', v[2]||'', v[3]||''].join(".") + (v[4]||'') + (v[5]||'')
}
function clean (version) {
version = exports.parse(version)
if (!version) return version
return stringify(version)
}
function valid (version) {
if (typeof version !== "string") return null
return exports.parse(version) && version.trim().replace(/^[v=]+/, '')
}
function validPackage (version) {
if (typeof version !== "string") return null
return version.match(expressions.parsePackage) && version.trim()
}
// range can be one of:
// "1.0.3 - 2.0.0" range, inclusive, like ">=1.0.3 <=2.0.0"
// ">1.0.2" like 1.0.3 - 9999.9999.9999
// ">=1.0.2" like 1.0.2 - 9999.9999.9999
// "<2.0.0" like 0.0.0 - 1.9999.9999
// ">1.0.2 <2.0.0" like 1.0.3 - 1.9999.9999
var starExpression = /(<|>)?=?\s*\*/g
, starReplace = ""
, compTrimExpression = new RegExp("((<|>)?=?)\\s*("
+semver+"|"+xRangePlain+")", "g")
, compTrimReplace = "$1$3"
function toComparators (range) {
var ret = (range || "").trim()
.replace(expressions.parseRange, exports.rangeReplace)
.replace(compTrimExpression, compTrimReplace)
.split(/\s+/)
.join(" ")
.split("||")
.map(function (orchunk) {
return orchunk
.split(" ")
.map(replaceXRanges)
.map(replaceSpermies)
.map(replaceStars)
.join(" ").trim()
})
.map(function (orchunk) {
return orchunk
.trim()
.split(/\s+/)
.filter(function (c) { return c.match(expressions.validComparator) })
})
.filter(function (c) { return c.length })
return ret
}
function replaceStars (stars) {
return stars.trim().replace(starExpression, starReplace)
}
// "2.x","2.x.x" --> ">=2.0.0- <2.1.0-"
// "2.3.x" --> ">=2.3.0- <2.4.0-"
function replaceXRanges (ranges) {
return ranges.split(/\s+/)
.map(replaceXRange)
.join(" ")
}
function replaceXRange (version) {
return version.trim().replace(expressions.parseXRange,
function (v, gtlt, M, m, p, t) {
var anyX = !M || M.toLowerCase() === "x" || M === "*"
|| !m || m.toLowerCase() === "x" || m === "*"
|| !p || p.toLowerCase() === "x" || p === "*"
, ret = v
if (gtlt && anyX) {
// just replace x'es with zeroes
;(!M || M === "*" || M.toLowerCase() === "x") && (M = 0)
;(!m || m === "*" || m.toLowerCase() === "x") && (m = 0)
;(!p || p === "*" || p.toLowerCase() === "x") && (p = 0)
ret = gtlt + M+"."+m+"."+p+"-"
} else if (!M || M === "*" || M.toLowerCase() === "x") {
ret = "*" // allow any
} else if (!m || m === "*" || m.toLowerCase() === "x") {
// append "-" onto the version, otherwise
// "1.x.x" matches "2.0.0beta", since the tag
// *lowers* the version value
ret = ">="+M+".0.0- <"+(+M+1)+".0.0-"
} else if (!p || p === "*" || p.toLowerCase() === "x") {
ret = ">="+M+"."+m+".0- <"+M+"."+(+m+1)+".0-"
}
//console.error("parseXRange", [].slice.call(arguments), ret)
return ret
})
}
// ~, ~> --> * (any, kinda silly)
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
function replaceSpermies (version) {
return version.trim().replace(expressions.parseSpermy,
function (v, gtlt, M, m, p, t) {
if (gtlt) throw new Error(
"Using '"+gtlt+"' with ~ makes no sense. Don't do it.")
if (!M || M.toLowerCase() === "x") {
return ""
}
// ~1 == >=1.0.0- <2.0.0-
if (!m || m.toLowerCase() === "x") {
return ">="+M+".0.0- <"+(+M+1)+".0.0-"
}
// ~1.2 == >=1.2.0- <1.3.0-
if (!p || p.toLowerCase() === "x") {
return ">="+M+"."+m+".0- <"+M+"."+(+m+1)+".0-"
}
// ~1.2.3 == >=1.2.3- <1.3.0-
t = t || "-"
return ">="+M+"."+m+"."+p+t+" <"+M+"."+(+m+1)+".0-"
})
}
function validRange (range) {
range = replaceStars(range)
var c = toComparators(range)
return (c.length === 0)
? null
: c.map(function (c) { return c.join(" ") }).join("||")
}
// returns the highest satisfying version in the list, or undefined
function maxSatisfying (versions, range) {
return versions
.filter(function (v) { return satisfies(v, range) })
.sort(compare)
.pop()
}
function satisfies (version, range) {
version = valid(version)
if (!version) return false
range = toComparators(range)
for (var i = 0, l = range.length ; i < l ; i ++) {
var ok = false
for (var j = 0, ll = range[i].length ; j < ll ; j ++) {
var r = range[i][j]
, gtlt = r.charAt(0) === ">" ? gt
: r.charAt(0) === "<" ? lt
: false
, eq = r.charAt(!!gtlt) === "="
, sub = (!!eq) + (!!gtlt)
if (!gtlt) eq = true
r = r.substr(sub)
r = (r === "") ? r : valid(r)
ok = (r === "") || (eq && r === version) || (gtlt && gtlt(version, r))
if (!ok) break
}
if (ok) return true
}
return false
}
// return v1 > v2 ? 1 : -1
function compare (v1, v2) {
var g = gt(v1, v2)
return g === null ? 0 : g ? 1 : -1
}
function rcompare (v1, v2) {
return compare(v2, v1)
}
function lt (v1, v2) { return gt(v2, v1) }
function gte (v1, v2) { return !lt(v1, v2) }
function lte (v1, v2) { return !gt(v1, v2) }
function eq (v1, v2) { return gt(v1, v2) === null }
function neq (v1, v2) { return gt(v1, v2) !== null }
function cmp (v1, c, v2) {
switch (c) {
case ">": return gt(v1, v2)
case "<": return lt(v1, v2)
case ">=": return gte(v1, v2)
case "<=": return lte(v1, v2)
case "==": return eq(v1, v2)
case "!=": return neq(v1, v2)
case "===": return v1 === v2
case "!==": return v1 !== v2
default: throw new Error("Y U NO USE VALID COMPARATOR!? "+c)
}
}
// return v1 > v2
function num (v) {
return v === undefined ? -1 : parseInt((v||"0").replace(/[^0-9]+/g, ''), 10)
}
function gt (v1, v2) {
v1 = exports.parse(v1)
v2 = exports.parse(v2)
if (!v1 || !v2) return false
for (var i = 1; i < 5; i ++) {
v1[i] = num(v1[i])
v2[i] = num(v2[i])
if (v1[i] > v2[i]) return true
else if (v1[i] !== v2[i]) return false
}
// no tag is > than any tag, or use lexicographical order.
var tag1 = v1[5] || ""
, tag2 = v2[5] || ""
// kludge: null means they were equal. falsey, and detectable.
// embarrassingly overclever, though, I know.
return tag1 === tag2 ? null
: !tag1 ? true
: !tag2 ? false
: tag1 > tag2
}
function inc (version, release) {
version = exports.parse(version)
if (!version) return null
var parsedIndexLookup =
{ 'major': 1
, 'minor': 2
, 'patch': 3
, 'build': 4 }
var incIndex = parsedIndexLookup[release]
if (incIndex === undefined) return null
var current = num(version[incIndex])
version[incIndex] = current === -1 ? 1 : current + 1
for (var i = incIndex + 1; i < 5; i ++) {
if (num(version[i]) !== -1) version[i] = "0"
}
if (version[4]) version[4] = "-" + version[4]
version[5] = ""
return stringify(version)
}
})(typeof exports === "object" ? exports : semver = {})
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment