Files
shields/lib/text-formatters.js
Pyves 7039e68018 Consistent version formatting (#1246)
Provide greater consistency for badges related to versions. Fix #1181.

- the `version` function in `color-formatters` was previously returning the colour of the badge, but also its text with a leading _v_. It was broken down into two separate functions and the text formatting part was moved to `text-formatters`, where it really belongs.

- unit tests were added for these two functions in `color-formatters.spec` and `text-formatters.spec`, using Sazerac.

- as discussed in #1181, the leading _v_ was omitted  for _xxxx-yy-zz_ date patterns. Any future exceptions can easily be added to the `ignoredVersionPatterns` pattern.

- the badge colour was previously switched to orange if a hyphen was found in the version string. This didn't seem ideal, instead pattern matching is done to find keywords such as `beta`, `alpha` or `snapshot`. Of course, this list can easily be extended.

- all badges related to versions now use the `versionText` and `versionColor` functions. There are a few rare exceptions, for instance in cases where the data returned by the service's API allows to figure things out without relying on any parsing/pattern matching (eg. `badgeData.colorscheme = prerelease ? 'orange' : 'blue';`, where `prerelease` is determined from an API's response).
2017-11-11 17:54:38 -05:00

110 lines
2.7 KiB
JavaScript

/**
* Commonly-used functions for formatting text in badge labels. Includes
* ordinal numbers, currency codes, star ratings, versions, etc.
*/
'use strict';
const moment = require('moment');
moment().format();
function starRating(rating) {
const flooredRating = Math.floor(rating);
let stars = '';
while (stars.length < flooredRating) { stars += '★'; }
const decimal = rating - flooredRating;
if (decimal >= 0.875) { stars += '★'; }
else if (decimal >= 0.625) { stars += '¾'; }
else if (decimal >= 0.375) { stars += '½'; }
else if (decimal >= 0.125) { stars += '¼'; }
while (stars.length < 5) { stars += '☆'; }
return stars;
}
// Convert ISO 4217 code to unicode string.
function currencyFromCode(code) {
return ({
CNY: '¥',
EUR: '€',
GBP: '₤',
USD: '$',
})[code] || code;
}
function ordinalNumber(n) {
const s=['ᵗʰ','ˢᵗ','ⁿᵈ','ʳᵈ'], v=n%100;
return n+(s[(v-20)%10]||s[v]||s[0]);
}
// Given a number, string with appropriate unit in the metric system, SI.
// Note: numbers beyond the peta- cannot be represented as integers in JS.
const metricPrefix = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
const metricPower = metricPrefix
.map(function(a, i) { return Math.pow(1000, i + 1); });
function metric(n) {
for (let i = metricPrefix.length - 1; i >= 0; i--) {
const limit = metricPower[i];
if (n >= limit) {
n = Math.round(n / limit);
if (n < 1000) {
return '' + n + metricPrefix[i];
} else {
return '1' + metricPrefix[i + 1];
}
}
}
return '' + n;
}
// Remove the starting v in a string.
function omitv(version) {
if (version.charCodeAt(0) === 118) {
return version.slice(1);
}
return version;
}
// Add a starting v to the version unless:
// - it does not start with a digit
// - it is a date (yyyy-mm-dd)
const ignoredVersionPatterns = /^[^0-9]|[0-9]{4}-[0-9]{2}-[0-9]{2}/;
function addv(version) {
if (version.startsWith('v') || ignoredVersionPatterns.test(version)) {
return version;
} else {
return `v${version}`;
}
}
function maybePluralize(singular, countable, plural) {
plural = plural || `${singular}s`;
if (countable && countable.length === 1) {
return singular;
} else {
return plural;
}
}
function formatDate(d) {
const date = moment(d);
const dateString = date.calendar(null, {
lastDay: '[yesterday]',
sameDay: '[today]',
lastWeek: '[last] dddd',
sameElse: 'MMMM YYYY'
});
// Trim current year from date string
return dateString.replace(` ${moment().year()}`, '').toLowerCase();
}
module.exports = {
starRating,
currencyFromCode,
ordinalNumber,
metric,
omitv,
addv,
maybePluralize,
formatDate
};