Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge remote-tracking branch 'origin/versions'

  • Loading branch information...
commit a5ee40ad2753639854f6676ea7248d4981f6d635 2 parents 4a8eff9 + 1d061d0
@hone hone authored
View
27 README.md
@@ -29,6 +29,24 @@ Example usage:
The buildpack will detect your app as Node.js if it has the file `package.json` in the root. It will use NPM to install your dependencies, and vendors a version of the Node.js runtime into your slug. The `node_modules` directory will be cached between builds to allow for faster NPM install time.
+Node.js and npm versions
+------------------------
+
+You can specify the versions of Node.js and npm your application requires using `package.json`
+
+ {
+ "name": "myapp",
+ "engines": {
+ "node": ">=0.4.7 <0.7.0",
+ "npm": ">=1.0.0"
+ }
+ }
+
+To list the available versions of Node.js and npm, see these manifests:
+
+http://heroku-buildpack-nodejs.s3.amazonaws.com/manifest.nodejs
+http://heroku-buildpack-nodejs.s3.amazonaws.com/manifest.npm
+
Hacking
-------
@@ -36,20 +54,19 @@ To use this buildpack, fork it on Github. Push up changes to your fork, then cr
To change the vendored binaries for Node.js, NPM, and SCons, use the helper scripts in the `support/` subdirectory. You'll need an S3-enabled AWS account and a bucket to store your binaries in.
-For example, you can change the vendored version of Node.js to v0.5.8.
+For example, you can change the default version of Node.js to v0.6.7.
First you'll need to build a Heroku-compatible version of Node.js:
$ export AWS_ID=xxx AWS_SECRET=yyy S3_BUCKET=zzz
$ s3 create $S3_BUCKET
- $ support/package_node 0.5.8
+ $ support/package_nodejs 0.6.7
Open `bin/compile` in your editor, and change the following lines:
- NODE_VERSION="0.5.8"
-
+ DEFAULT_NODE_VERSION="0.6.7"
S3_BUCKET=zzz
Commit and push the changes to your buildpack to your Github fork, then push your sample app to Heroku to test. You should see:
- -----> Vendoring node 0.5.8
+ -----> Vendoring node 0.6.7
View
129 bin/compile
@@ -1,7 +1,32 @@
#!/usr/bin/env bash
# bin/compile <build-dir> <cache-dir>
-mktmpdir() {
+# fail fast
+set -e
+
+# debug
+# set -x
+
+# clean up leaking environment
+unset GIT_DIR
+
+# config
+SCONS_VERSION="1.2.0"
+S3_BUCKET="heroku-buildpack-nodejs"
+
+# parse and derive params
+BUILD_DIR=$1
+CACHE_DIR=$2
+LP_DIR=`cd $(dirname $0); cd ..; pwd`
+CACHE_STORE_DIR="$CACHE_DIR/node_modules/$NPM_VERSION"
+CACHE_TARGET_DIR="$BUILD_DIR/node_modules"
+
+function error() {
+ echo " ! $*"
+ exit 1
+}
+
+function mktmpdir() {
dir=$(mktemp -t node-$1-XXXX)
rm -rf $dir
mkdir -p $dir
@@ -16,8 +41,10 @@ function indent() {
esac
}
-run_npm() {
+function run_npm() {
command="$1"
+
+ cd $BUILD_DIR
HOME="$BUILD_DIR" $VENDORED_NODE/bin/node $VENDORED_NPM/cli.js $command 2>&1 | indent
if [ "${PIPESTATUS[*]}" != "0 0" ]; then
@@ -26,21 +53,76 @@ run_npm() {
fi
}
-# clean up leaking environment
-unset GIT_DIR
+function manifest_versions() {
+ curl "http://${S3_BUCKET}.s3.amazonaws.com/manifest.${1}" -s -o - | tr -s '\n' ' '
+}
-# config
-NODE_VERSION="0.4.7"
-NPM_VERSION="1.0.94"
-SCONS_VERSION="1.2.0"
-S3_BUCKET="heroku-buildpack-nodejs"
+function resolve_version() {
+ available_versions="$1"
+ requested_version="$2"
+ default_version="$3"
+
+ if [ "$2" == "" ]; then
+ echo $3
+ else
+ args=""
+ for version in $available_versions; do args="${args} -v \"${version}\""; done
+ for version in $requested_version; do args="${args} -r \"${version}\""; done
+ eval $bootstrap_node/bin/node $LP_DIR/vendor/node-semver/bin/semver ${args} | tail -n1
+ fi
+}
-# parse and derive params
-BUILD_DIR=$1
-CACHE_DIR=$2
-LP_DIR=`cd $(dirname $0); cd ..; pwd`
-CACHE_STORE_DIR="$CACHE_DIR/node_modules/$NPM_VERSION"
-CACHE_TARGET_DIR="$BUILD_DIR/node_modules"
+function package_engine_version() {
+ version=$(cat $BUILD_DIR/package.json | $bootstrap_node/bin/node $LP_DIR/vendor/json/json engines.$1 2>/dev/null)
+ if [ $? == 0 ]; then
+ echo $version
+ fi
+}
+
+function package_resolve_version() {
+ engine="$1"
+ resolved_version=$(resolve_version "${engine_versions[$engine]}" "${engine_requests[$engine]}" "${engine_defaults[$engine]}")
+
+ if [ "${resolved_version}" == "" ]; then
+ error "Requested engine $engine version ${engine_requests[$engine]} does not match available versions: ${engine_versions[$engine]}"
+ else
+ echo $resolved_version
+ fi
+}
+
+function package_download() {
+ engine="$1"
+ version="$2"
+ location="$3"
+
+ mkdir -p $location
+ package="http://${S3_BUCKET}.s3.amazonaws.com/$engine-$version.tgz"
+ curl $package -s -o - | tar xzf - -C $location
+}
+
+bootstrap_node=$(mktmpdir bootstrap_node)
+package_download "nodejs" "0.4.7" $bootstrap_node
+
+# make some associative arrays
+declare -A engine_versions
+declare -A engine_defaults
+declare -A engine_requests
+
+engine_defaults["node"]="0.4.7"
+engine_defaults["npm"]="1.0.94"
+
+engine_versions["node"]=$(manifest_versions "nodejs")
+engine_requests["node"]=$(package_engine_version "node")
+
+engine_versions["npm"]=$(manifest_versions "npm")
+engine_requests["npm"]=$(package_engine_version "npm")
+
+echo "-----> Resolving engine versions"
+NODE_VERSION=$(package_resolve_version "node")
+echo "Using Node.js version: ${NODE_VERSION}" | indent
+
+NPM_VERSION=$(package_resolve_version "npm")
+echo "Using npm version: ${NPM_VERSION}" | indent
# s3 packages
NODE_PACKAGE="http://${S3_BUCKET}.s3.amazonaws.com/nodejs-${NODE_VERSION}.tgz"
@@ -54,13 +136,13 @@ VENDORED_SCONS="$(mktmpdir scons)"
# download and unpack packages
echo "-----> Fetching Node.js binaries"
-mkdir -p $VENDORED_NODE && curl $NODE_PACKAGE -s -o - | tar xzf - -C $VENDORED_NODE
-mkdir -p $VENDORED_NPM && curl $NPM_PACKAGE -s -o - | tar xzf - -C $VENDORED_NPM
-mkdir -p $VENDORED_SCONS && curl $SCONS_PACKAGE -s -o - | tar xzf - -C $VENDORED_SCONS
+package_download "nodejs" "${NODE_VERSION}" "${VENDORED_NODE}"
+package_download "npm" "${NPM_VERSION}" "${VENDORED_NPM}"
+package_download "scons" "${SCONS_VERSION}" "${VENDORED_SCONS}"
# vendor node into the slug
PATH="$BUILD_DIR/bin:$PATH"
-echo "-----> Vendoring node $NODE_VERSION"
+echo "-----> Vendoring node into slug"
mkdir -p "$BUILD_DIR/bin"
cp "$VENDORED_NODE/bin/node" "$BUILD_DIR/bin/node"
@@ -93,12 +175,9 @@ if [ -d $CACHE_STORE_DIR ]; then
fi
# install dependencies with npm
-echo "-----> Installing dependencies with npm $NPM_VERSION"
-
-cd $BUILD_DIR
-run_npm install
-run_npm rebuild
-
+echo "-----> Installing dependencies with npm"
+run_npm "install"
+run_npm "rebuild"
echo "Dependencies installed" | indent
# repack cache with new assets
View
11 support/aws/s3
@@ -117,14 +117,17 @@ s3_curl() {
# $2 = remote bucket.
# $3 = remote name
# $4 = local name.
+ # $5 = mime type
local bucket remote date sig md5 arg inout headers
# header handling is kinda fugly, but it works.
bucket="${2:+/${2}}/" # slashify the bucket
remote="$(urlenc "${3}")" # if you don't, strange things may happen.
stdopts="--connect-timeout 10 --fail --silent"
+ mime="${5}"
[[ $CURL_S3_DEBUG == true ]] && stdopts="${stdopts} --show-error --fail"
case "${1}" in
GET) arg="-o" inout="${4:--}" # stdout if no $4
+ headers[${#headers[@]}]="x-amz-acl: public-read"
;;
PUT) [[ ${2} ]] || die "PUT can has bucket?"
if [[ ! ${3} ]]; then
@@ -135,6 +138,9 @@ s3_curl() {
arg="-T" inout="${4}"
headers[${#headers[@]}]="x-amz-acl: public-read"
headers[${#headers[@]}]="Expect: 100-continue"
+ if [ "$mime" != "" ]; then
+ headers[${#headers[@]}]="Content-Type: $mime"
+ fi
else
die "Cannot write non-existing file ${4}"
fi
@@ -145,7 +151,7 @@ s3_curl() {
*) die "Unknown verb ${1}. It probably would not have worked anyways." ;;
esac
date="$(TZ=UTC date '+%a, %e %b %Y %H:%M:%S %z')"
- sig=$(s3_signature_string ${1} "${date}" "${bucket}" "${remote}" "${md5}" "" "x-amz-acl:public-read")
+ sig=$(s3_signature_string ${1} "${date}" "${bucket}" "${remote}" "${md5}" "${mime}" "x-amz-acl:public-read")
headers[${#headers[@]}]="Authorization: AWS ${AWS_ID}:${sig}"
headers[${#headers[@]}]="Date: ${date}"
@@ -159,7 +165,8 @@ s3_put() {
# $1 = remote bucket to put it into
# $2 = remote name to put
# $3 = file to put. This must be present if $2 is.
- s3_curl PUT "${1}" "${2}" "${3:-${2}}"
+ # $4 = mime type
+ s3_curl PUT "${1}" "${2}" "${3:-${2}}" "${4}"
return $?
}
View
44 support/manifest
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+set -e
+
+manifest_type="$1"
+
+if [ "$manifest_type" == "" ]; then
+ echo "usage: $0 <nodejs|npm>"
+ exit 1
+fi
+
+if [ "$AWS_ID" == "" ]; then
+ echo "must set AWS_ID"
+ exit 1
+fi
+
+if [ "$AWS_SECRET" == "" ]; then
+ echo "must set AWS_SECRET"
+ exit 1
+fi
+
+if [ "$S3_BUCKET" == "" ]; then
+ echo "must set S3_BUCKET"
+ exit 1
+fi
+
+basedir="$( cd -P "$( dirname "$0" )" && pwd )"
+
+# make a temp directory
+tempdir="$( mktemp -t node_XXXX )"
+rm -rf $tempdir
+mkdir -p $tempdir
+pushd $tempdir
+
+# generate manifest
+$basedir/aws/s3 ls $S3_BUCKET \
+ | grep "^${manifest_type}" \
+ | sed -e "s/${manifest_type}-\([0-9.]*\)\\.tgz/\\1/" \
+ | awk 'BEGIN {FS="."} {printf("%03d.%03d.%03d %s\n",$1,$2,$3,$0)}' | sort -r | cut -d" " -f2 \
+ > manifest.${manifest_type}
+
+# upload manifest to s3
+$basedir/aws/s3 put $S3_BUCKET \
+ manifest.${manifest_type} "" "text/plain"
View
11 support/package_node → support/package_nodejs
@@ -30,14 +30,14 @@ basedir="$( cd -P "$( dirname "$0" )" && pwd )"
tempdir="$( mktemp -t node_XXXX )"
rm -rf $tempdir
mkdir -p $tempdir
-pushd $tempdir
+cd $tempdir
# download and extract node
-curl http://nodejs.org/dist/node-v${node_version}.tar.gz -o node.tgz
+curl http://nodejs.org/dist/v${node_version}/node-v${node_version}.tar.gz -o node.tgz
tar xzvf node.tgz
# go into node dir
-pushd node-v${node_version}
+cd node-v${node_version}
# build and package nodejs for heroku
vulcan build -v -o $tempdir/node-${node_version}.tgz
@@ -47,7 +47,7 @@ $basedir/aws/s3 put $S3_BUCKET \
nodejs-${node_version}.tgz $tempdir/node-${node_version}.tgz
# go into scons
-pushd tools/scons
+cd tools/scons
# package scons
scons_version=$(ls | grep "scons-local" | cut -d- -f3)
@@ -56,3 +56,6 @@ tar czvf $tempdir/scons-${scons_version}.tgz *
# upload scons to s3
$basedir/aws/s3 put $S3_BUCKET \
scons-${scons_version}.tgz $tempdir/scons-${scons_version}.tgz
+
+# generate manifest
+$basedir/manifest nodejs
View
3  support/package_npm
@@ -48,3 +48,6 @@ tar czvf $tempdir/npm-${npm_version}.tgz *
# upload npm to s3
$basedir/aws/s3 put $S3_BUCKET \
npm-${npm_version}.tgz $tempdir/npm-${npm_version}.tgz
+
+# generate manifest
+$basedir/manifest npm
View
2  vendor/README
@@ -0,0 +1,2 @@
+json: https://github.com/trentm/json
+node-semver: http://github.com/isaacs/node-semver
View
640 vendor/json/json
@@ -0,0 +1,640 @@
+#!/usr/bin/env node
+//
+// json -- pipe in your JSON for nicer output and for extracting data bits
+//
+// See <https://github.com/trentm/json>.
+//
+
+var VERSION = "2.0.4";
+
+var util = require('util');
+var pathlib = require('path');
+var runInNewContext = require('vm').runInNewContext;
+var warn = console.warn;
+
+
+
+//--- exports for module usage
+
+exports.main = main;
+exports.getVersion = getVersion;
+exports.parseLookup = parseLookup;
+
+// As an exported API, these are still experimental:
+exports.lookupDatum = lookupDatum;
+exports.printDatum = printDatum;
+
+
+
+//---- globals and constants
+
+// Output modes.
+var OM_JSONY = 1;
+var OM_JSON = 2;
+var OM_INSPECT = 3;
+var OM_COMPACT = 4;
+var OM_FROM_NAME = {
+ "jsony": OM_JSONY,
+ "json": OM_JSON,
+ "inspect": OM_INSPECT,
+ "compact": OM_COMPACT
+}
+
+
+
+//---- support functions
+
+function getVersion() {
+ return VERSION;
+}
+
+function isArray(ar) {
+ return ar instanceof Array ||
+ Array.isArray(ar) ||
+ (ar && ar !== Object.prototype && isArray(ar.__proto__));
+}
+
+function printHelp() {
+ util.puts("Usage:");
+ util.puts(" <something generating JSON on stdout> | json [OPTIONS] [LOOKUPS...]");
+ util.puts("");
+ util.puts("Pipe in your JSON for nicer output or supply one or more `LOOKUPS`");
+ util.puts("to extract a subset of the JSON. HTTP header blocks (as from `curl -i`)");
+ util.puts("are skipped by default.");
+ util.puts("");
+ util.puts("Auto-arrayification:");
+ util.puts(" Adjacent objects or arrays are 'arrayified'. To attempt to avoid");
+ util.puts(" false positives inside JSON strings, *adjacent* elements must");
+ util.puts(" have either no whitespace separation or at least a newline");
+ util.puts(" separation.");
+ util.puts("");
+ util.puts("Examples:");
+ util.puts(" # pretty printing");
+ util.puts(" $ curl -s http://search.twitter.com/search.json?q=node.js | json");
+ util.puts("");
+ util.puts(" # lookup fields");
+ util.puts(" $ curl -s http://search.twitter.com/search.json?q=node.js | json results[0]");
+ util.puts(" {");
+ util.puts(" \"created_at\": \"Tue, 08 Nov 2011 19:07:25 +0000\",");
+ util.puts(" \"from_user\": \"im2b\",");
+ util.puts(" ...");
+ util.puts("");
+ util.puts(" # array processing");
+ util.puts(" $ curl -s http://search.twitter.com/search.json?q=node.js | json results \\");
+ util.puts(" json -a from_user");
+ util.puts(" im2b");
+ util.puts(" myalltop_paul");
+ util.puts(" ...");
+ util.puts("");
+ util.puts(" # auto-arrayification")
+ util.puts(" $ echo '{\"a\":1}{\"b\":2}' | json -o json-0");
+ util.puts(" [{\"a\":1},{\"b\":2}]");
+ util.puts(" $ echo '[1,2][3,4]' | json -o json-0");
+ util.puts(" [{\"a\":1},{\"b\":2}]");
+ util.puts("");
+ util.puts("Options:");
+ util.puts(" -h, --help print this help info and exit");
+ util.puts(" --version print version of this command and exit");
+ util.puts(" -q, --quiet don't warn if input isn't valid JSON");
+ util.puts("");
+ util.puts(" -H drop any HTTP header block (as from `curl -i ...`)");
+ util.puts(" -a, --array process input as an array of separate inputs");
+ util.puts(" and output in tabular form");
+ util.puts(" -d DELIM delimiter string for tabular output (default is ' ')");
+ util.puts("");
+ util.puts(" -o, --output MODE Specify an output mode. One of");
+ util.puts(" jsony (default): JSON with string quotes elided");
+ util.puts(" json: JSON output, 2-space indent");
+ util.puts(" json-N: JSON output, N-space indent, e.g. 'json-4'");
+ util.puts(" inspect: node.js `util.inspect` output");
+ util.puts(" -i shortcut for `-o inspect`");
+ util.puts(" -j shortcut for `-o json`");
+ util.puts("");
+ util.puts("See <https://github.com/trentm/json> for more complete docs.");
+}
+
+
+/**
+ * Parse the command-line options and arguments into an object.
+ *
+ * {
+ * 'args': [...] // arguments
+ * 'help': true, // true if '-h' option given
+ * // etc.
+ * }
+ *
+ * @return {Object} The parsed options. `.args` is the argument list.
+ * @throws {Error} If there is an error parsing argv.
+ */
+function parseArgv(argv) {
+ var parsed = {
+ args: [],
+ help: false,
+ quiet: false,
+ dropHeaders: false,
+ outputMode: OM_JSONY,
+ jsonIndent: 2,
+ delim: ' '
+ };
+
+ // Turn '-iH' into '-i -H', except for argument-accepting options.
+ var args = argv.slice(2); // drop ['node', 'scriptname']
+ var newArgs = [];
+ var optTakesArg = {'d': true, 'o': true};
+ for (var i = 0; i < args.length; i++) {
+ if (args[i].charAt(0) === "-" && args[i].charAt(1) !== '-' && args[i].length > 2) {
+ var splitOpts = args[i].slice(1).split("");
+ for (var j = 0; j < splitOpts.length; j++) {
+ newArgs.push('-' + splitOpts[j])
+ if (optTakesArg[splitOpts[j]]) {
+ var optArg = splitOpts.slice(j+1).join("");
+ if (optArg.length) {
+ newArgs.push(optArg);
+ }
+ break;
+ }
+ }
+ } else {
+ newArgs.push(args[i]);
+ }
+ }
+ args = newArgs;
+
+ endOfOptions = false;
+ while (args.length > 0) {
+ var arg = args.shift();
+ switch(arg) {
+ case "--":
+ endOfOptions = true;
+ break;
+ case "-h": // display help and exit
+ case "--help":
+ parsed.help = true;
+ break;
+ case "--version":
+ parsed.version = true;
+ break;
+ case "-q":
+ case "--quiet":
+ parsed.quiet = true;
+ break;
+ case "-H": // drop any headers
+ parsed.dropHeaders = true;
+ break;
+ case "-o":
+ case "--output":
+ var name = args.shift();
+ var idx = name.lastIndexOf('-');
+ if (idx !== -1) {
+ var indent = Number(name.slice(idx+1));
+ if (! isNaN(indent)) {
+ parsed.jsonIndent = indent;
+ name = name.slice(0, idx);
+ }
+ }
+ parsed.outputMode = OM_FROM_NAME[name];
+ if (parsed.outputMode === undefined) {
+ throw new Error("unknown output mode: '"+name+"'");
+ }
+ break;
+ case "-i": // output with util.inspect
+ parsed.outputMode = OM_INSPECT;
+ break;
+ case "-j": // output with JSON.stringify
+ parsed.outputMode = OM_JSON;
+ break;
+ case "-a":
+ case "--array":
+ parsed.array = true;
+ break;
+ case "-d":
+ parsed.delim = args.shift();
+ break;
+ default: // arguments
+ if (!endOfOptions && arg.length > 0 && arg[0] === '-') {
+ throw new Error("unknown option '"+arg+"'");
+ }
+ parsed.args.push(arg);
+ break;
+ }
+ }
+ //TODO: '--' handling and error on a first arg that looks like an option.
+
+ return parsed;
+}
+
+
+
+function isInteger(s) {
+ return (s.search(/^-?[0-9]+$/) == 0);
+}
+
+
+// Parse a lookup string into a list of lookup bits. E.g.:
+// "a.b.c" -> ["a","b","c"]
+// "b['a']" -> ["b","['a']"]
+function parseLookup(lookup) {
+ //var debug = console.warn;
+ var debug = function () {};
+
+ var bits = [];
+ debug("\n*** "+lookup+" ***")
+
+ bits = [];
+ var bit = "";
+ var states = [null];
+ var escaped = false;
+ var ch = null;
+ for (var i=0; i < lookup.length; ++i) {
+ var escaped = (!escaped && ch === '\\');
+ var ch = lookup[i];
+ debug("-- i="+i+", ch="+JSON.stringify(ch)+" escaped="+JSON.stringify(escaped))
+ debug("states: "+JSON.stringify(states))
+
+ if (escaped) {
+ bit += ch;
+ continue;
+ }
+
+ switch (states[states.length-1]) {
+ case null:
+ switch (ch) {
+ case '"':
+ case "'":
+ states.push(ch);
+ bit += ch;
+ break;
+ case '[':
+ states.push(ch);
+ if (bit !== "") {
+ bits.push(bit);
+ bit = ""
+ }
+ bit += ch;
+ break;
+ case '.':
+ if (bit !== "") {
+ bits.push(bit);
+ bit = ""
+ }
+ break;
+ default:
+ bit += ch;
+ break;
+ }
+ break;
+
+ case '[':
+ bit += ch;
+ switch (ch) {
+ case '"':
+ case "'":
+ case '[':
+ states.push(ch);
+ break;
+ case ']':
+ states.pop();
+ if (states[states.length-1] === null) {
+ bits.push(bit);
+ bit = ""
+ }
+ break;
+ }
+ break;
+
+ case '"':
+ bit += ch;
+ switch (ch) {
+ case '"':
+ states.pop();
+ if (states[states.length-1] === null) {
+ bits.push(bit);
+ bit = ""
+ }
+ break;
+ }
+ break;
+
+ case "'":
+ bit += ch;
+ switch (ch) {
+ case "'":
+ states.pop();
+ if (states[states.length-1] === null) {
+ bits.push(bit);
+ bit = ""
+ }
+ break;
+ }
+ break;
+ }
+ debug("bit: "+JSON.stringify(bit))
+ debug("bits: "+JSON.stringify(bits))
+ }
+
+ if (bit !== "") {
+ bits.push(bit);
+ bit = ""
+ }
+
+ debug(JSON.stringify(lookup)+" -> "+JSON.stringify(bits))
+ return bits
+}
+
+
+/**
+ * Parse the given stdin input into:
+ * {
+ * "error": ... error object if there was an error ...,
+ * "datum": ... parsed object if content was JSON ...
+ * }
+ */
+function parseInput(buffer) {
+ try {
+ return {datum: JSON.parse(buffer)};
+ } catch(e) {
+ // Special case: Auto-arrayification of unjoined list of objects:
+ // {"one": 1}{"two": 2}
+ // and auto-concatenation of unjoined list of arrays:
+ // ["a", "b"]["c", "d"]
+ //
+ // This can be nice to process a stream of JSON objects generated from
+ // multiple calls to another tool or `cat *.json | json`.
+ //
+ // Rules:
+ // - Only JS objects and arrays. Don't see strong need for basic
+ // JS types right now and this limitation simplifies.
+ // - The break between JS objects has to include a newline:
+ // {"one": 1}
+ // {"two": 2}
+ // or no spaces at all:
+ // {"one": 1}{"two": 2}
+ // I.e., not this:
+ // {"one": 1} {"two": 2}
+ // This condition should be fine for typical use cases and ensures
+ // no false matches inside JS strings.
+ var newBuffer = buffer;
+ [/(})\s*\n\s*({)/g, /(})({")/g].forEach(function (pat) {
+ newBuffer = newBuffer.replace(pat, "$1,\n$2");
+ });
+ [/(\])\s*\n\s*(\[)/g, /(\])(\[)/g].forEach(function (pat) {
+ newBuffer = newBuffer.replace(pat, ",\n");
+ });
+ if (buffer !== newBuffer) {
+ newBuffer = newBuffer.trim();
+ if (newBuffer[0] !== '[') {
+ newBuffer = '[\n' + newBuffer;
+ }
+ if (newBuffer.slice(-1) !== ']') {
+ newBuffer = newBuffer + '\n]\n';
+ }
+ try {
+ return {datum: JSON.parse(newBuffer)};
+ } catch (e2) {
+ }
+ }
+
+ return {error: e}
+ }
+}
+
+
+/**
+ * Apply a lookup to the given datum.
+ *
+ * @argument datum {Object}
+ * @argument lookup {Array} The parsed lookup (from
+ * `parseLookup(<string>)`). Might be empty.
+ * @returns {Object} The result of the lookup.
+ */
+function lookupDatum(datum, lookup) {
+ // Put it back together with some convenience transformations.
+ var lookupCode = "";
+ var isJSIdentifier = /^[$A-Za-z_][0-9A-Za-z_]*$/;
+ for (var i=0; i < lookup.length; i++) {
+ var bit = lookup[i];
+ if (bit[0] === '[') {
+ lookupCode += bit;
+ } else if (! isJSIdentifier.exec(lookup[i])) {
+ // Allow a non-JS-indentifier token, e.g. `json foo-bar`.
+ lookupCode += '["' + lookup[i].replace('"', '\\"') + '"]';
+ } else {
+ lookupCode += '.' + lookup[i];
+ }
+ }
+ return runInNewContext("(" + JSON.stringify(datum) + ")" + lookupCode);
+}
+
+
+
+/**
+ * Print out a single result, considering input options.
+ */
+function printDatum(datum, opts, sep, alwaysPrintSep) {
+ var output = null;
+ switch (opts.outputMode) {
+ case OM_INSPECT:
+ output = util.inspect(datum, false, Infinity, true);
+ break;
+ case OM_JSON:
+ if (typeof datum !== 'undefined') {
+ output = JSON.stringify(datum, null, opts.jsonIndent);
+ }
+ break;
+ case OM_COMPACT:
+ // Dev Note: A still relatively experimental attempt at a more
+ // compact ouput somewhat a la Python's repr of a dict. I.e. try to
+ // fit elements on one line as much as reasonable.
+ if (datum === undefined) {
+ // pass
+ } else if (isArray(datum)) {
+ var bits = ['[\n'];
+ datum.forEach(function (d) {
+ bits.push(' ')
+ bits.push(JSON.stringify(d, null, 0).replace(/,"(?![,:])/g, ', "'));
+ bits.push(',\n');
+ });
+ bits.push(bits.pop().slice(0, -2) + '\n') // drop last comma
+ bits.push(']');
+ output = bits.join('');
+ } else {
+ output = JSON.stringify(datum, null, 0);
+ }
+ break;
+ case OM_JSONY:
+ if (typeof datum === 'string') {
+ output = datum;
+ } else if (typeof datum !== 'undefined') {
+ output = JSON.stringify(datum, null, opts.jsonIndent);
+ }
+ break;
+ default:
+ throw new Error("unknown output mode: "+opts.outputMode);
+ }
+ if (output && output.length) {
+ emit(output);
+ emit(sep);
+ } else if (alwaysPrintSep) {
+ emit(sep);
+ }
+}
+
+
+var stdoutFlushed = true;
+function emit(s) {
+ // TODO:PERF If this is try/catch is too slow (too granular): move up to
+ // mainline and be sure to only catch this particular error.
+ try {
+ stdoutFlushed = process.stdout.write(s);
+ } catch (e) {
+ // Handle any exceptions in stdout writing in the "error" event above.
+ }
+}
+
+process.stdout.on("error", function (err) {
+ if (err.code === "EPIPE") {
+ // Pass. See <https://github.com/trentm/json/issues/9>.
+ } else {
+ warn(err)
+ drainStdoutAndExit(1);
+ }
+});
+
+
+/**
+ * A hacked up version of "process.exit" that will first drain stdout
+ * before exiting. *WARNING: This doesn't stop event processing.* IOW,
+ * callers have to be careful that code following this call isn't
+ * accidentally executed.
+ *
+ * In node v0.6 "process.stdout and process.stderr are blocking when they
+ * refer to regular files or TTY file descriptors." However, this hack might
+ * still be necessary in a shell pipeline.
+ */
+function drainStdoutAndExit(code) {
+ process.stdout.on('drain', function () {
+ process.exit(code);
+ });
+ if (stdoutFlushed) {
+ process.exit(code);
+ }
+}
+
+
+
+//---- mainline
+
+function main(argv) {
+ var opts;
+ try {
+ opts = parseArgv(argv);
+ } catch (e) {
+ warn("json: error: %s", e.message)
+ return drainStdoutAndExit(1);
+ }
+ //warn(opts);
+ if (opts.help) {
+ printHelp();
+ return;
+ }
+ if (opts.version) {
+ util.puts("json " + getVersion());
+ return;
+ }
+ var lookupStrs = opts.args;
+ //XXX ditch this hack
+ if (lookupStrs.length == 0) {
+ lookupStrs.push("");
+ }
+
+ var buffer = "";
+
+ var stdin = process.openStdin();
+ stdin.setEncoding('utf8');
+ stdin.on('data', function (chunk) {
+ buffer += chunk;
+ });
+
+ stdin.on('end', function () {
+ // Take off a leading HTTP header if any and pass it through.
+ while (true) {
+ if (buffer.slice(0,5) === "HTTP/") {
+ var index = buffer.indexOf('\r\n\r\n');
+ var sepLen = 4;
+ if (index == -1) {
+ index = buffer.indexOf('\n\n');
+ sepLen = 2;
+ }
+ if (index != -1) {
+ if (! opts.dropHeaders) {
+ emit(buffer.slice(0, index+sepLen));
+ }
+ var is100Continue = (buffer.slice(0, 21) === "HTTP/1.1 100 Continue");
+ buffer = buffer.slice(index+sepLen);
+ if (is100Continue) {
+ continue;
+ }
+ }
+ }
+ break;
+ }
+
+ // Expect the remainder to be JSON.
+ if (! buffer.length) {
+ return;
+ }
+ var input = parseInput(buffer); // -> {datum: <input object>, error: <error object>}
+ if (input.error) {
+ // Doesn't look like JSON. Just print it out and move on.
+ if (! opts.quiet) {
+ warn("json: error: doesn't look like JSON: %s (input='%s')",
+ input.error, JSON.stringify(buffer));
+ }
+ emit(buffer);
+ if (buffer.length && buffer[buffer.length-1] !== "\n") {
+ emit('\n');
+ }
+ return drainStdoutAndExit(1);
+ }
+
+ // Process and output the input JSON.
+ var lookups = lookupStrs.map(parseLookup);
+ var results = [];
+ if (opts.array) {
+ var data = (isArray(input.datum) ? input.datum : [input.datum]);
+ if (lookups.length === 0) {
+ results = input.datum;
+ } else {
+ for (var j=0; j < data.length; j++) {
+ var result = [];
+ for (var i=0; i < lookups.length; i++) {
+ result.push(lookupDatum(data[j], lookups[i]));
+ }
+ results.push(result);
+ }
+ }
+ results.forEach(function (row) {
+ var c;
+ for (c = 0; c < row.length-1; c++) {
+ printDatum(row[c], opts, opts.delim, true);
+ }
+ printDatum(row[c], opts, '\n', true);
+ });
+ } else {
+ if (lookups.length === 0) {
+ results = input.datum;
+ } else {
+ for (var i=0; i < lookups.length; i++) {
+ results.push(lookupDatum(input.datum, lookups[i]));
+ }
+ }
+ results.forEach(function (r) {
+ printDatum(r, opts, '\n', false);
+ });
+ }
+ });
+}
+
+if (require.main === module) {
+ main(process.argv);
+}
View
23 vendor/node-semver/LICENSE
@@ -0,0 +1,23 @@
+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.
View
119 vendor/node-semver/README.md
@@ -0,0 +1,119 @@
+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.
View
71 vendor/node-semver/bin/semver
@@ -0,0 +1,71 @@
+#!/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"))
+}
+
+
View
11 vendor/node-semver/package.json
@@ -0,0 +1,11 @@
+{ "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" } }
View
304 vendor/node-semver/semver.js
@@ -0,0 +1,304 @@
+;(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 = {})
View
397 vendor/node-semver/test.js
@@ -0,0 +1,397 @@
+var tap = require("tap")
+ , test = tap.test
+ , semver = require("./semver.js")
+ , eq = semver.eq
+ , gt = semver.gt
+ , lt = semver.lt
+ , neq = semver.neq
+ , cmp = semver.cmp
+ , gte = semver.gte
+ , lte = semver.lte
+ , satisfies = semver.satisfies
+ , validRange = semver.validRange
+ , inc = semver.inc
+ , replaceStars = semver.replaceStars
+ , toComparators = semver.toComparators
+
+tap.plan(8)
+
+test("\ncomparison tests", function (t) {
+; [ ["0.0.0", "0.0.0foo"]
+ , ["0.0.1", "0.0.0"]
+ , ["1.0.0", "0.9.9"]
+ , ["0.10.0", "0.9.0"]
+ , ["0.99.0", "0.10.0"]
+ , ["2.0.0", "1.2.3"]
+ , ["v0.0.0", "0.0.0foo"]
+ , ["v0.0.1", "0.0.0"]
+ , ["v1.0.0", "0.9.9"]
+ , ["v0.10.0", "0.9.0"]
+ , ["v0.99.0", "0.10.0"]
+ , ["v2.0.0", "1.2.3"]
+ , ["0.0.0", "v0.0.0foo"]
+ , ["0.0.1", "v0.0.0"]
+ , ["1.0.0", "v0.9.9"]
+ , ["0.10.0", "v0.9.0"]
+ , ["0.99.0", "v0.10.0"]
+ , ["2.0.0", "v1.2.3"]
+ , ["1.2.3", "1.2.3-asdf"]
+ , ["1.2.3-4", "1.2.3"]
+ , ["1.2.3-4-foo", "1.2.3"]
+ , ["1.2.3-5", "1.2.3-5-foo"]
+ , ["1.2.3-5", "1.2.3-4"]
+ , ["1.2.3-5-foo", "1.2.3-5-Foo"]
+ ].forEach(function (v) {
+ var v0 = v[0]
+ , v1 = v[1]
+ t.ok(gt(v0, v1), "gt('"+v0+"', '"+v1+"')")
+ t.ok(lt(v1, v0), "lt('"+v1+"', '"+v0+"')")
+ t.ok(!gt(v1, v0), "!gt('"+v1+"', '"+v0+"')")
+ t.ok(!lt(v0, v1), "!lt('"+v0+"', '"+v1+"')")
+ t.ok(eq(v0, v0), "eq('"+v0+"', '"+v0+"')")
+ t.ok(eq(v1, v1), "eq('"+v1+"', '"+v1+"')")
+ t.ok(neq(v0, v1), "neq('"+v0+"', '"+v1+"')")
+ t.ok(cmp(v1, "==", v1), "cmp('"+v1+"' == '"+v1+"')")
+ t.ok(cmp(v0, ">=", v1), "cmp('"+v0+"' >= '"+v1+"')")
+ t.ok(cmp(v1, "<=", v0), "cmp('"+v1+"' <= '"+v0+"')")
+ t.ok(cmp(v0, "!=", v1), "cmp('"+v0+"' != '"+v1+"')")
+ })
+ t.end()
+})
+
+test("\nequality tests", function (t) {
+; [ ["1.2.3", "v1.2.3"]
+ , ["1.2.3", "=1.2.3"]
+ , ["1.2.3", "v 1.2.3"]
+ , ["1.2.3", "= 1.2.3"]
+ , ["1.2.3", " v1.2.3"]
+ , ["1.2.3", " =1.2.3"]
+ , ["1.2.3", " v 1.2.3"]
+ , ["1.2.3", " = 1.2.3"]
+ , ["1.2.3-0", "v1.2.3-0"]
+ , ["1.2.3-0", "=1.2.3-0"]
+ , ["1.2.3-0", "v 1.2.3-0"]
+ , ["1.2.3-0", "= 1.2.3-0"]
+ , ["1.2.3-0", " v1.2.3-0"]
+ , ["1.2.3-0", " =1.2.3-0"]
+ , ["1.2.3-0", " v 1.2.3-0"]
+ , ["1.2.3-0", " = 1.2.3-0"]
+ , ["1.2.3-01", "v1.2.3-1"]
+ , ["1.2.3-01", "=1.2.3-1"]
+ , ["1.2.3-01", "v 1.2.3-1"]
+ , ["1.2.3-01", "= 1.2.3-1"]
+ , ["1.2.3-01", " v1.2.3-1"]
+ , ["1.2.3-01", " =1.2.3-1"]
+ , ["1.2.3-01", " v 1.2.3-1"]
+ , ["1.2.3-01", " = 1.2.3-1"]
+ , ["1.2.3beta", "v1.2.3beta"]
+ , ["1.2.3beta", "=1.2.3beta"]
+ , ["1.2.3beta", "v 1.2.3beta"]
+ , ["1.2.3beta", "= 1.2.3beta"]
+ , ["1.2.3beta", " v1.2.3beta"]
+ , ["1.2.3beta", " =1.2.3beta"]
+ , ["1.2.3beta", " v 1.2.3beta"]
+ , ["1.2.3beta", " = 1.2.3beta"]
+ ].forEach(function (v) {
+ var v0 = v[0]
+ , v1 = v[1]
+ t.ok(eq(v0, v1), "eq('"+v0+"', '"+v1+"')")
+ t.ok(!neq(v0, v1), "!neq('"+v0+"', '"+v1+"')")
+ t.ok(cmp(v0, "==", v1), "cmp("+v0+"=="+v1+")")
+ t.ok(!cmp(v0, "!=", v1), "!cmp("+v0+"!="+v1+")")
+ t.ok(!cmp(v0, "===", v1), "!cmp("+v0+"==="+v1+")")
+ t.ok(cmp(v0, "!==", v1), "cmp("+v0+"!=="+v1+")")
+ t.ok(!gt(v0, v1), "!gt('"+v0+"', '"+v1+"')")
+ t.ok(gte(v0, v1), "gte('"+v0+"', '"+v1+"')")
+ t.ok(!lt(v0, v1), "!lt('"+v0+"', '"+v1+"')")
+ t.ok(lte(v0, v1), "lte('"+v0+"', '"+v1+"')")
+ })
+ t.end()
+})
+
+
+test("\nrange tests", function (t) {
+; [ ["1.0.0 - 2.0.0", "1.2.3"]
+ , ["1.0.0", "1.0.0"]
+ , [">=*", "0.2.4"]
+ , ["", "1.0.0"]
+ , ["*", "1.2.3"]
+ , ["*", "v1.2.3-foo"]
+ , [">=1.0.0", "1.0.0"]
+ , [">=1.0.0", "1.0.1"]
+ , [">=1.0.0", "1.1.0"]
+ , [">1.0.0", "1.0.1"]
+ , [">1.0.0", "1.1.0"]
+ , ["<=2.0.0", "2.0.0"]
+ , ["<=2.0.0", "1.9999.9999"]
+ , ["<=2.0.0", "0.2.9"]
+ , ["<2.0.0", "1.9999.9999"]
+ , ["<2.0.0", "0.2.9"]
+ , [">= 1.0.0", "1.0.0"]
+ , [">= 1.0.0", "1.0.1"]
+ , [">= 1.0.0", "1.1.0"]
+ , ["> 1.0.0", "1.0.1"]
+ , ["> 1.0.0", "1.1.0"]
+ , ["<= 2.0.0", "2.0.0"]
+ , ["<= 2.0.0", "1.9999.9999"]
+ , ["<= 2.0.0", "0.2.9"]
+ , ["< 2.0.0", "1.9999.9999"]
+ , ["<\t2.0.0", "0.2.9"]
+ , [">=0.1.97", "v0.1.97"]
+ , [">=0.1.97", "0.1.97"]
+ , ["0.1.20 || 1.2.4", "1.2.4"]
+ , [">=0.2.3 || <0.0.1", "0.0.0"]
+ , [">=0.2.3 || <0.0.1", "0.2.3"]
+ , [">=0.2.3 || <0.0.1", "0.2.4"]
+ , ["||", "1.3.4"]
+ , ["2.x.x", "2.1.3"]
+ , ["1.2.x", "1.2.3"]
+ , ["1.2.x || 2.x", "2.1.3"]
+ , ["1.2.x || 2.x", "1.2.3"]
+ , ["x", "1.2.3"]
+ , ["2.*.*", "2.1.3"]
+ , ["1.2.*", "1.2.3"]
+ , ["1.2.* || 2.*", "2.1.3"]
+ , ["1.2.* || 2.*", "1.2.3"]
+ , ["*", "1.2.3"]
+ , ["2", "2.1.2"]
+ , ["2.3", "2.3.1"]
+ , ["~2.4", "2.4.0"] // >=2.4.0 <2.5.0
+ , ["~2.4", "2.4.5"]
+ , ["~>3.2.1", "3.2.2"] // >=3.2.1 <3.3.0
+ , ["~1", "1.2.3"] // >=1.0.0 <2.0.0
+ , ["~>1", "1.2.3"]
+ , ["~> 1", "1.2.3"]
+ , ["~1.0", "1.0.2"] // >=1.0.0 <1.1.0
+ , ["~ 1.0", "1.0.2"]
+ , [">=1", "1.0.0"]
+ , [">= 1", "1.0.0"]
+ , ["<1.2", "1.1.1"]
+ , ["< 1.2", "1.1.1"]
+ , ["1", "1.0.0beta"]
+ , ["~v0.5.4-pre", "0.5.5"]
+ , ["~v0.5.4-pre", "0.5.4"]
+ ].forEach(function (v) {
+ t.ok(satisfies(v[1], v[0]), v[0]+" satisfied by "+v[1])
+ })
+ t.end()
+})
+
+test("\nnegative range tests", function (t) {
+; [ ["1.0.0 - 2.0.0", "2.2.3"]
+ , ["1.0.0", "1.0.1"]
+ , [">=1.0.0", "0.0.0"]
+ , [">=1.0.0", "0.0.1"]
+ , [">=1.0.0", "0.1.0"]
+ , [">1.0.0", "0.0.1"]
+ , [">1.0.0", "0.1.0"]
+ , ["<=2.0.0", "3.0.0"]
+ , ["<=2.0.0", "2.9999.9999"]
+ , ["<=2.0.0", "2.2.9"]
+ , ["<2.0.0", "2.9999.9999"]
+ , ["<2.0.0", "2.2.9"]
+ , [">=0.1.97", "v0.1.93"]
+ , [">=0.1.97", "0.1.93"]
+ , ["0.1.20 || 1.2.4", "1.2.3"]
+ , [">=0.2.3 || <0.0.1", "0.0.3"]
+ , [">=0.2.3 || <0.0.1", "0.2.2"]
+ , ["2.x.x", "1.1.3"]
+ , ["2.x.x", "3.1.3"]
+ , ["1.2.x", "1.3.3"]
+ , ["1.2.x || 2.x", "3.1.3"]
+ , ["1.2.x || 2.x", "1.1.3"]
+ , ["2.*.*", "1.1.3"]
+ , ["2.*.*", "3.1.3"]
+ , ["1.2.*", "1.3.3"]
+ , ["1.2.* || 2.*", "3.1.3"]
+ , ["1.2.* || 2.*", "1.1.3"]
+ , ["2", "1.1.2"]
+ , ["2.3", "2.4.1"]
+ , ["~2.4", "2.5.0"] // >=2.4.0 <2.5.0
+ , ["~2.4", "2.3.9"]
+ , ["~>3.2.1", "3.3.2"] // >=3.2.1 <3.3.0
+ , ["~>3.2.1", "3.2.0"] // >=3.2.1 <3.3.0
+ , ["~1", "0.2.3"] // >=1.0.0 <2.0.0
+ , ["~>1", "2.2.3"]
+ , ["~1.0", "1.1.0"] // >=1.0.0 <1.1.0
+ , ["<1", "1.0.0"]
+ , [">=1.2", "1.1.1"]
+ , ["1", "2.0.0beta"]
+ , ["~v0.5.4-beta", "0.5.4-alpha"]
+ , ["<1", "1.0.0beta"]
+ , ["< 1", "1.0.0beta"]
+ ].forEach(function (v) {
+ t.ok(!satisfies(v[1], v[0]), v[0]+" not satisfied by "+v[1])
+ })
+ t.end()
+})
+
+test("\nincrement versions test", function (t) {
+; [ [ "1.2.3", "major", "2.0.0" ]
+ , [ "1.2.3", "minor", "1.3.0" ]
+ , [ "1.2.3", "patch", "1.2.4" ]
+ , [ "1.2.3", "build", "1.2.3-1" ]
+ , [ "1.2.3-4", "build", "1.2.3-5" ]
+ , [ "1.2.3tag", "major", "2.0.0" ]
+ , [ "1.2.3-tag", "major", "2.0.0" ]
+ , [ "1.2.3tag", "build", "1.2.3-1" ]
+ , [ "1.2.3-tag", "build", "1.2.3-1" ]
+ , [ "1.2.3-4-tag", "build", "1.2.3-5" ]
+ , [ "1.2.3-4tag", "build", "1.2.3-5" ]
+ , [ "1.2.3", "fake", null ]
+ , [ "fake", "major", null ]
+ ].forEach(function (v) {
+ t.equal(inc(v[0], v[1]), v[2], "inc("+v[0]+", "+v[1]+") === "+v[2])
+ })
+
+ t.end()
+})
+
+test("\nreplace stars test", function (t) {
+; [ [ "", "" ]
+ , [ "*", "" ]
+ , [ "> *", "" ]
+ , [ "<*", "" ]
+ , [ " >= *", "" ]
+ , [ "* || 1.2.3", " || 1.2.3" ]
+ ].forEach(function (v) {
+ t.equal(replaceStars(v[0]), v[1], "replaceStars("+v[0]+") === "+v[1])
+ })
+
+ t.end()
+})
+
+test("\nvalid range test", function (t) {
+; [ ["1.0.0 - 2.0.0", ">=1.0.0 <=2.0.0"]
+ , ["1.0.0", "1.0.0"]
+ , [">=*", ""]
+ , ["", ""]
+ , ["*", ""]
+ , ["*", ""]
+ , [">=1.0.0", ">=1.0.0"]
+ , [">1.0.0", ">1.0.0"]
+ , ["<=2.0.0", "<=2.0.0"]
+ , ["1", ">=1.0.0- <2.0.0-"]
+ , ["<=2.0.0", "<=2.0.0"]
+ , ["<=2.0.0", "<=2.0.0"]
+ , ["<2.0.0", "<2.0.0"]
+ , ["<2.0.0", "<2.0.0"]
+ , [">= 1.0.0", ">=1.0.0"]
+ , [">= 1.0.0", ">=1.0.0"]
+ , [">= 1.0.0", ">=1.0.0"]
+ , ["> 1.0.0", ">1.0.0"]
+ , ["> 1.0.0", ">1.0.0"]
+ , ["<= 2.0.0", "<=2.0.0"]
+ , ["<= 2.0.0", "<=2.0.0"]
+ , ["<= 2.0.0", "<=2.0.0"]
+ , ["< 2.0.0", "<2.0.0"]
+ , ["< 2.0.0", "<2.0.0"]
+ , [">=0.1.97", ">=0.1.97"]
+ , [">=0.1.97", ">=0.1.97"]
+ , ["0.1.20 || 1.2.4", "0.1.20||1.2.4"]
+ , [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"]
+ , [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"]
+ , [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"]
+ , ["||", "||"]
+ , ["2.x.x", ">=2.0.0- <3.0.0-"]
+ , ["1.2.x", ">=1.2.0- <1.3.0-"]
+ , ["1.2.x || 2.x", ">=1.2.0- <1.3.0-||>=2.0.0- <3.0.0-"]
+ , ["1.2.x || 2.x", ">=1.2.0- <1.3.0-||>=2.0.0- <3.0.0-"]
+ , ["x", ""]
+ , ["2.*.*", null]
+ , ["1.2.*", null]
+ , ["1.2.* || 2.*", null]
+ , ["1.2.* || 2.*", null]
+ , ["*", ""]
+ , ["2", ">=2.0.0- <3.0.0-"]
+ , ["2.3", ">=2.3.0- <2.4.0-"]
+ , ["~2.4", ">=2.4.0- <2.5.0-"]
+ , ["~2.4", ">=2.4.0- <2.5.0-"]
+ , ["~>3.2.1", ">=3.2.1- <3.3.0-"]
+ , ["~1", ">=1.0.0- <2.0.0-"]
+ , ["~>1", ">=1.0.0- <2.0.0-"]
+ , ["~> 1", ">=1.0.0- <2.0.0-"]
+ , ["~1.0", ">=1.0.0- <1.1.0-"]
+ , ["~ 1.0", ">=1.0.0- <1.1.0-"]
+ , ["<1", "<1.0.0-"]
+ , ["< 1", "<1.0.0-"]
+ , [">=1", ">=1.0.0-"]
+ , [">= 1", ">=1.0.0-"]
+ , ["<1.2", "<1.2.0-"]
+ , ["< 1.2", "<1.2.0-"]
+ , ["1", ">=1.0.0- <2.0.0-"]
+ ].forEach(function (v) {
+ t.equal(validRange(v[0]), v[1], "validRange("+v[0]+") === "+v[1])
+ })
+
+ t.end()
+})
+
+test("\ncomparators test", function (t) {
+; [ ["1.0.0 - 2.0.0", [[">=1.0.0", "<=2.0.0"]] ]
+ , ["1.0.0", [["1.0.0"]] ]
+ , [">=*", [[">=0.0.0-"]] ]
+ , ["", [[""]]]
+ , ["*", [[""]] ]
+ , ["*", [[""]] ]
+ , [">=1.0.0", [[">=1.0.0"]] ]
+ , [">=1.0.0", [[">=1.0.0"]] ]
+ , [">=1.0.0", [[">=1.0.0"]] ]
+ , [">1.0.0", [[">1.0.0"]] ]
+ , [">1.0.0", [[">1.0.0"]] ]
+ , ["<=2.0.0", [["<=2.0.0"]] ]
+ , ["1", [[">=1.0.0-", "<2.0.0-"]] ]
+ , ["<=2.0.0", [["<=2.0.0"]] ]
+ , ["<=2.0.0", [["<=2.0.0"]] ]
+ , ["<2.0.0", [["<2.0.0"]] ]
+ , ["<2.0.0", [["<2.0.0"]] ]
+ , [">= 1.0.0", [[">=1.0.0"]] ]
+ , [">= 1.0.0", [[">=1.0.0"]] ]
+ , [">= 1.0.0", [[">=1.0.0"]] ]
+ , ["> 1.0.0", [[">1.0.0"]] ]
+ , ["> 1.0.0", [[">1.0.0"]] ]
+ , ["<= 2.0.0", [["<=2.0.0"]] ]
+ , ["<= 2.0.0", [["<=2.0.0"]] ]
+ , ["<= 2.0.0", [["<=2.0.0"]] ]
+ , ["< 2.0.0", [["<2.0.0"]] ]
+ , ["<\t2.0.0", [["<2.0.0"]] ]
+ , [">=0.1.97", [[">=0.1.97"]] ]
+ , [">=0.1.97", [[">=0.1.97"]] ]
+ , ["0.1.20 || 1.2.4", [["0.1.20"], ["1.2.4"]] ]
+ , [">=0.2.3 || <0.0.1", [[">=0.2.3"], ["<0.0.1"]] ]
+ , [">=0.2.3 || <0.0.1", [[">=0.2.3"], ["<0.0.1"]] ]
+ , [">=0.2.3 || <0.0.1", [[">=0.2.3"], ["<0.0.1"]] ]
+ , ["||", [[""], [""]] ]
+ , ["2.x.x", [[">=2.0.0-", "<3.0.0-"]] ]
+ , ["1.2.x", [[">=1.2.0-", "<1.3.0-"]] ]
+ , ["1.2.x || 2.x", [[">=1.2.0-", "<1.3.0-"], [">=2.0.0-", "<3.0.0-"]] ]
+ , ["1.2.x || 2.x", [[">=1.2.0-", "<1.3.0-"], [">=2.0.0-", "<3.0.0-"]] ]
+ , ["x", [[""]] ]
+ , ["2.*.*", [[">=2.0.0-", "<3.0.0-"]] ]
+ , ["1.2.*", [[">=1.2.0-", "<1.3.0-"]] ]
+ , ["1.2.* || 2.*", [[">=1.2.0-", "<1.3.0-"], [">=2.0.0-", "<3.0.0-"]] ]
+ , ["1.2.* || 2.*", [[">=1.2.0-", "<1.3.0-"], [">=2.0.0-", "<3.0.0-"]] ]
+ , ["*", [[""]] ]
+ , ["2", [[">=2.0.0-", "<3.0.0-"]] ]
+ , ["2.3", [[">=2.3.0-", "<2.4.0-"]] ]
+ , ["~2.4", [[">=2.4.0-", "<2.5.0-"]] ]
+ , ["~2.4", [[">=2.4.0-", "<2.5.0-"]] ]
+ , ["~>3.2.1", [[">=3.2.1-", "<3.3.0-"]] ]
+ , ["~1", [[">=1.0.0-", "<2.0.0-"]] ]
+ , ["~>1", [[">=1.0.0-", "<2.0.0-"]] ]
+ , ["~> 1", [[">=1.0.0-", "<2.0.0-"]] ]
+ , ["~1.0", [[">=1.0.0-", "<1.1.0-"]] ]
+ , ["~ 1.0", [[">=1.0.0-", "<1.1.0-"]] ]
+ , ["<1", [["<1.0.0-"]] ]
+ , ["< 1", [["<1.0.0-"]] ]
+ , [">=1", [[">=1.0.0-"]] ]
+ , [">= 1", [[">=1.0.0-"]] ]
+ , ["<1.2", [["<1.2.0-"]] ]
+ , ["< 1.2", [["<1.2.0-"]] ]
+ , ["1", [[">=1.0.0-", "<2.0.0-"]] ]
+ ].forEach(function (v) {
+ t.equivalent(toComparators(v[0]), v[1], "toComparators("+v[0]+") === "+JSON.stringify(v[1]))
+ })
+
+ t.end()
+})
Please sign in to comment.
Something went wrong with that request. Please try again.