-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
Copy pathtext-formatters.js
170 lines (158 loc) · 4.87 KB
/
text-formatters.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/**
* Commonly-used functions for formatting text in badge labels. Includes
* ordinal numbers, currency codes, star ratings, versions, etc.
*
* @module
*/
/**
* Creates a string of stars and empty stars based on the rating.
* The number of stars is determined by the integer part of the rating.
* An additional star or a three-quarter star or a half star or a quarter star is added based on the decimal part of the rating.
* The remaining stars are empty stars until the maximum number of stars is reached.
*
* @param {number} rating - Current rating
* @param {number} [max] - Maximum rating
* @returns {string} A string of stars and empty stars
*/
function starRating(rating, max = 5) {
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 < max) {
stars += '☆'
}
return stars
}
/**
* Converts the ISO 4217 code to the corresponding currency symbol.
* If the the symbol for the code is not found, then the code itself is returned.
*
* @param {string} code - ISO 4217 code
* @returns {string} Currency symbol for the code
*/
function currencyFromCode(code) {
return (
{
CNY: '¥',
EUR: '€',
GBP: '₤',
USD: '$',
}[code] || code
)
}
/**
* Calculates the ordinal number of the given number.
* For example, if the input is 1, the output is “1ˢᵗ”.
*
* @param {number} n - Input number
* @returns {string} Ordinal number of the input number
*/
function ordinalNumber(n) {
const s = ['ᵗʰ', 'ˢᵗ', 'ⁿᵈ', 'ʳᵈ']
const v = n % 100
return n + (s[(v - 20) % 10] || s[v] || s[0])
}
const metricPrefix = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
const metricPower = metricPrefix.map((a, i) => Math.pow(1000, i + 1))
/**
* Given a number (positive or negative), returns a string with appropriate unit in the metric system, SI.
* Note: numbers beyond the peta- cannot be represented as integers in JS.
* For example, if you call metric(1000), it will return "1k", which means one kilo or one thousand.
*
* @param {number} n - Input number
* @returns {string} String with appropriate unit in the metric system, SI
*/
function metric(n) {
for (let i = metricPrefix.length - 1; i >= 0; i--) {
const limit = metricPower[i]
const absN = Math.abs(n)
if (absN >= limit) {
const scaledN = absN / limit
if (scaledN < 10) {
// For "small" numbers, display one decimal digit unless it is 0.
const oneDecimalN = scaledN.toFixed(1)
if (oneDecimalN.charAt(oneDecimalN.length - 1) !== '0') {
const res = `${oneDecimalN}${metricPrefix[i]}`
return n > 0 ? res : `-${res}`
}
}
const roundedN = Math.round(scaledN)
if (roundedN < 1000) {
const res = `${roundedN}${metricPrefix[i]}`
return n > 0 ? res : `-${res}`
} else {
const res = `1${metricPrefix[i + 1]}`
return n > 0 ? res : `-${res}`
}
}
}
return `${n}`
}
/**
* Remove the starting v in a string if it exists.
* For example, omitv("v1.2.3") returns "1.2.3", but omitv("hello") returns "hello".
*
* @param {string} version - Version string
* @returns {string} Version string without the starting v
*/
function omitv(version) {
if (version.charCodeAt(0) === 118) {
return version.slice(1)
}
return version
}
const ignoredVersionPatterns =
/^[^0-9]|[0-9]{4}-[0-9]{2}-[0-9]{2}|^[a-f0-9]{7,40}$/
/**
* Add a starting v to the version unless it doesn't starts with a digit, is a date (yyyy-mm-dd), or is a commit hash.
* For example, addv("1.2.3") returns "v1.2.3", but addv("hello"), addv("2021-10-31"), addv("abcdef1"), returns "hello", "2021-10-31", and "abcdef1" respectively.
*
* @param {string} version - Version string
* @returns {string} Version string with the starting v
*/
function addv(version) {
version = `${version}`
if (version.startsWith('v') || ignoredVersionPatterns.test(version)) {
return version
} else {
return `v${version}`
}
}
/**
* Returns a string that is either the singular or the plural form of a word,
* depending on the length of the countable parameter.
*
* @param {string} singular - Singular form of the word
* @param {string[]} countable - Array of values you want to count
* @param {string} plural - Plural form of the word
* @returns {string} Singular or plural form of the word
*/
function maybePluralize(singular, countable, plural) {
plural = plural || `${singular}s`
if (countable && countable.length === 1) {
return singular
} else {
return plural
}
}
export {
starRating,
currencyFromCode,
ordinalNumber,
metric,
omitv,
addv,
maybePluralize,
}