Files
shields/lib/php-version.js
Paul Melnikow 83ac6ff1b3 Enforce use of template literals (#2242)
This is consistent with what we're pretty much already doing, and saves us from making the request during code review.

These were all autofixed and most of them seem easier to read. Some in the legacy services should be rewritten in more legible forms during refactor (ie using intermediate variables, or using request’s qs option). There are some in helper functions and elsewhere that should get rewritten separately. I don't want to change them in this PR because the changes will get lost in this diff, though we could identify them here and fix them before or just after.
2018-11-02 17:11:44 -04:00

247 lines
6.1 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 { promisify } = require('util')
const request = require('request')
const uniq = require('lodash.uniq')
const { listCompare } = require('./version')
const { omitv } = require('./text-formatters')
const { regularUpdate } = require('./regular-update')
// 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,
}
}
// 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
}
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
}
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
}
function minorVersion(version) {
const result = version.match(/^(\d+)(?:\.(\d+))?(?:\.(\d+))?/)
if (result === null) {
return ''
}
return `${result[1]}.${result[2] ? result[2] : '0'}`
}
function versionReduction(versions, phpReleases) {
if (!versions.length) {
return ''
}
// versions intersect
versions = uniq(versions)
.sort()
.filter(n => phpReleases.includes(n))
// nothing to reduction
if (versions.length < 2) {
return versions.length ? versions[0] : ''
}
const first = phpReleases.indexOf(versions[0])
const last = phpReleases.indexOf(versions[versions.length - 1])
// no missed versions
if (first + versions.length - 1 === last) {
if (last === phpReleases.length - 1) {
return `>= ${versions[0][2] === '0' ? versions[0][0] : versions[0]}` // 7.0 -> 7
}
return `${versions[0]} - ${versions[versions.length - 1]}`
}
return versions.join(', ')
}
function getPhpReleases(githubApiProvider) {
return promisify(regularUpdate)({
url: '/repos/php/php-src/git/refs/tags',
intervalMillis: 24 * 3600 * 1000, // 1 day
scraper: tags =>
uniq(
tags
// only releases
.filter(
tag => tag.ref.match(/^refs\/tags\/php-\d+\.\d+\.\d+$/) != null
)
// get minor version of release
.map(tag => tag.ref.match(/^refs\/tags\/php-(\d+\.\d+)\.\d+$/)[1])
),
request: (url, options, cb) =>
githubApiProvider.request(request, url, {}, cb),
})
}
module.exports = {
compare,
latest,
isStable,
minorVersion,
versionReduction,
getPhpReleases,
}