Files
shields/lib/php-version.js
Paul Melnikow 5a3516c687 Clean up some helpers (#1117)
Address comments from #1109 and make several code-quality fixes which were caught by a local run of eslint-config-standard.
2017-10-06 13:11:29 -04:00

176 lines
4.5 KiB
JavaScript

/**
* Utilities relating to PHP version numbers. This compares version numbers
* using the algorithm followed by Composer (see
* https://getcomposer.org/doc/04-schema.md#version).
*/
'use strict';
const {listCompare} = require('./version.js');
const {omitv} = require('./text-formatters.js');
// Return a negative value if v1 < v2,
// zero if v1 = v2,
// a positive value otherwise.
//
// See https://getcomposer.org/doc/04-schema.md#version
// and https://github.com/badges/shields/issues/319#issuecomment-74411045
function compare(v1, v2) {
// Omit the starting `v`.
const rawv1 = omitv(v1);
const rawv2 = omitv(v2);
let v1data, v2data;
try {
v1data = numberedVersionData(rawv1);
v2data = numberedVersionData(rawv2);
} catch(e) {
return asciiVersionCompare(rawv1, rawv2);
}
// Compare the numbered part (eg, 1.0.0 < 2.0.0).
const numbersCompare = listCompare(v1data.numbers, v2data.numbers);
if (numbersCompare !== 0) {
return numbersCompare;
}
// Compare the modifiers (eg, alpha < beta).
if (v1data.modifier < v2data.modifier) {
return -1;
} else if (v1data.modifier > v2data.modifier) {
return 1;
}
// Compare the modifier counts (eg, alpha1 < alpha3).
if (v1data.modifierCount < v2data.modifierCount) {
return -1;
} else if (v1data.modifierCount > v2data.modifierCount) {
return 1;
}
return 0;
}
exports.compare = compare;
function latest(versions) {
let latest = versions[0];
for (let i = 1; i < versions.length; i++) {
if (compare(latest, versions[i]) < 0) {
latest = versions[i];
}
}
return latest;
}
exports.latest = latest;
// Whether a version is stable.
function isStable(version) {
const rawVersion = omitv(version);
let versionData;
try {
versionData = numberedVersionData(rawVersion);
} catch(e) {
return false;
}
// normal or patch
return (versionData.modifier === 3) || (versionData.modifier === 4);
}
exports.isStable = isStable;
// === Private helper functions ===
// Return a negative value if v1 < v2,
// zero if v1 = v2, a positive value otherwise.
function asciiVersionCompare(v1, v2) {
if (v1 < v2) {
return -1;
} else if (v1 > v2) {
return 1;
} else {
return 0;
}
}
// Take a version without the starting v.
// eg, '1.0.x-beta'
// Return { numbers: [1,0,something big], modifier: 2, modifierCount: 1 }
function numberedVersionData(version) {
// A version has a numbered part and a modifier part
// (eg, 1.0.0-patch, 2.0.x-dev).
const parts = version.split('-');
const numbered = parts[0];
// Aliases that get caught here.
if (numbered === 'dev') {
return {
numbers: parts[1],
modifier: 5,
modifierCount: 1,
};
}
let modifierLevel = 3;
let modifierLevelCount = 0;
if (parts.length > 1) {
const modifier = parts[parts.length - 1];
const firstLetter = modifier.charCodeAt(0);
let modifierLevelCountString;
// Modifiers: alpha < beta < RC < normal < patch < dev
if (firstLetter === 97) { // a
modifierLevel = 0;
if (/^alpha/.test(modifier)) {
modifierLevelCountString = + (modifier.slice(5));
} else {
modifierLevelCountString = + (modifier.slice(1));
}
} else if (firstLetter === 98) { // b
modifierLevel = 1;
if (/^beta/.test(modifier)) {
modifierLevelCountString = + (modifier.slice(4));
} else {
modifierLevelCountString = + (modifier.slice(1));
}
} else if (firstLetter === 82) { // R
modifierLevel = 2;
modifierLevelCountString = + (modifier.slice(2));
} else if (firstLetter === 112) { // p
modifierLevel = 4;
if (/^patch/.test(modifier)) {
modifierLevelCountString = + (modifier.slice(5));
} else {
modifierLevelCountString = + (modifier.slice(1));
}
} else if (firstLetter === 100) { // d
modifierLevel = 5;
if (/^dev/.test(modifier)) {
modifierLevelCountString = + (modifier.slice(3));
} else {
modifierLevelCountString = + (modifier.slice(1));
}
}
// If we got the empty string, it defaults to a modifier count of 1.
if (!modifierLevelCountString) {
modifierLevelCount = 1;
} else {
modifierLevelCount = + modifierLevelCountString;
}
}
// Try to convert to a list of numbers.
function toNum (s) {
let n = +s;
if (Number.isNaN(n)) {
n = 0xffffffff;
}
return n;
}
const numberList = numbered.split('.').map(toNum);
return {
numbers: numberList,
modifier: modifierLevel,
modifierCount: modifierLevelCount,
};
}