diff --git a/server.js b/server.js index 8f2ba95..0eb9acd 100644 --- a/server.js +++ b/server.js @@ -752,10 +752,11 @@ cache(function(data, match, sendBadge, request) { })); // Packagist version integration. -camp.route(/^\/packagist\/v\/(.*)\.(svg|png|gif|jpg|json)$/, +camp.route(/^\/packagist\/(v|vpre)\/(.*)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { - var userRepo = match[1]; // eg, `doctrine/orm`. - var format = match[2]; + var info = match[1]; // either `v` or `vpre`. + var userRepo = match[2]; // eg, `doctrine/orm`. + var format = match[3]; var apiUrl = 'https://packagist.org/packages/' + userRepo + '.json'; var badgeData = getBadgeData('packagist', data); request(apiUrl, function(err, res, buffer) { @@ -765,12 +766,44 @@ cache(function(data, match, sendBadge, request) { } try { var data = JSON.parse(buffer); - // Grab the latest stable version, or an unstable + var versions = Object.keys(data.package.versions); - var version = latestVersion(versions); - var vdata = versionColor(version); - badgeData.text[1] = vdata.version; - badgeData.colorscheme = vdata.color; + var stableVersion = latestVersion(versions); + var vdata = versionColor(stableVersion); + + var badgeText = null; + var badgeColor = null; + + switch (info) { + case 'v': + badgeText = vdata.version; + badgeColor = vdata.color; + break; + case 'vpre': + if (versions[0] !== undefined) { + + var unstableVersion = null; + for (var i = 0; i < versions.length; i++) { + var version = versions[i]; + + if (version.charAt(0) !== 'v') { + if (unstableVersion === null || (unstableVersion !== null && versionCompare(version, unstableVersion) > 0)) { + unstableVersion = version; + } + } + } + + badgeText = unstableVersion; + badgeColor = 'orange'; + } + break; + } + + if (badgeText !== null) { + badgeData.text[1] = badgeText; + badgeData.colorscheme = badgeColor; + } + sendBadge(format, badgeData); } catch(e) { badgeData.text[1] = 'invalid'; @@ -3091,3 +3124,120 @@ function latestVersion(versions) { } return version; } + +function versionCompare(v1, v2, operator) { + // discuss at: http://phpjs.org/functions/version_compare/ + // original by: Philippe Jausions (http://pear.php.net/user/jausions) + // original by: Aidan Lister (http://aidanlister.com/) + // reimplemented by: Kankrelune (http://www.webfaktory.info/) + // improved by: Brett Zamir (http://brett-zamir.me) + // improved by: Scott Baker + // improved by: Theriault + // example 1: version_compare('8.2.5rc', '8.2.5a'); + // returns 1: 1 + // example 2: version_compare('8.2.50', '8.2.52', '<'); + // returns 2: true + // example 3: version_compare('5.3.0-dev', '5.3.0'); + // returns 3: -1 + // example 4: version_compare('4.1.0.52','4.01.0.51'); + // returns 4: 1 + + this.php_js = this.php_js || {}; + this.php_js.ENV = this.php_js.ENV || {}; + // END REDUNDANT + // Important: compare must be initialized at 0. + var i = 0, + x = 0, + compare = 0, + // vm maps textual PHP versions to negatives so they're less than 0. + // PHP currently defines these as CASE-SENSITIVE. It is important to + // leave these as negatives so that they can come before numerical versions + // and as if no letters were there to begin with. + // (1alpha is < 1 and < 1.1 but > 1dev1) + // If a non-numerical value can't be mapped to this table, it receives + // -7 as its value. + vm = { + 'dev': -6, + 'alpha': -5, + 'a': -5, + 'beta': -4, + 'b': -4, + 'RC': -3, + 'rc': -3, + '#': -2, + 'p': 1, + 'pl': 1 + }, + // This function will be called to prepare each version argument. + // It replaces every _, -, and + with a dot. + // It surrounds any nonsequence of numbers/dots with dots. + // It replaces sequences of dots with a single dot. + // version_compare('4..0', '4.0') == 0 + // Important: A string of 0 length needs to be converted into a value + // even less than an unexisting value in vm (-7), hence [-8]. + // It's also important to not strip spaces because of this. + // version_compare('', ' ') == 1 + prepVersion = function (v) { + v = ('' + v) + .replace(/[_\-+]/g, '.'); + v = v.replace(/([^.\d]+)/g, '.$1.') + .replace(/\.{2,}/g, '.'); + return (!v.length ? [-8] : v.split('.')); + }; + // This converts a version component to a number. + // Empty component becomes 0. + // Non-numerical component becomes a negative number. + // Numerical component becomes itself as an integer. + numVersion = function (v) { + return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); + }; + v1 = prepVersion(v1); + v2 = prepVersion(v2); + x = Math.max(v1.length, v2.length); + for (i = 0; i < x; i++) { + if (v1[i] == v2[i]) { + continue; + } + v1[i] = numVersion(v1[i]); + v2[i] = numVersion(v2[i]); + if (v1[i] < v2[i]) { + compare = -1; + break; + } else if (v1[i] > v2[i]) { + compare = 1; + break; + } + } + if (!operator) { + return compare; + } + + // Important: operator is CASE-SENSITIVE. + // "No operator" seems to be treated as "<." + // Any other values seem to make the function return null. + switch (operator) { + case '>': + case 'gt': + return (compare > 0); + case '>=': + case 'ge': + return (compare >= 0); + case '<=': + case 'le': + return (compare <= 0); + case '==': + case '=': + case 'eq': + return (compare === 0); + case '<>': + case '!=': + case 'ne': + return (compare !== 0); + case '': + case '<': + case 'lt': + return (compare < 0); + default: + return null; + } +} diff --git a/try.html b/try.html index 51f83c5..da5225f 100644 --- a/try.html +++ b/try.html @@ -286,6 +286,10 @@ Pixel-perfect Retina-ready Fast Consistent Hackable
https://img.shields.io/packagist/v/symfony/symfony.svg
https://img.shields.io/packagist/vpre/symfony/symfony.svg
https://img.shields.io/cocoapods/v/AFNetworking.svg