@technobuddha/library
Version:
A large library of useful functions
452 lines (451 loc) • 14.6 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.summarize = exports.orderOfMagnitude = exports.cardinal = void 0;
var isFinite_1 = __importDefault(require("lodash/isFinite"));
var isNaN_1 = __importDefault(require("lodash/isNaN"));
var constants_1 = require("../constants");
var ones = ['zero',
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'ten',
'eleven',
'twelve',
'thirteen',
'fourteen',
'fifteen',
'sixteen',
'seventeen',
'eighteen',
'nineteen'];
var tens = ['twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
var ZERO = 0;
var TEN = 10;
var TWENTY = 20;
var ONE_HUNDRED = 100;
/**
* Convert a number into text (the cardinal number)
*
* @remark There is no limit to the numbers that can be expressed, however Javascript/Typescript can only represent numbers
* up to uncentillions (1e308).
*
* @param input The number
* @param __namedParameters see {@link Options}
* @returns The number spelled out
*
* @default groups Infinity
* @default digits false
* @default and (empty)
* @default hyphen (space)
*/
function cardinal(input, _a) {
var _b;
if (_a === void 0) { _a = {}; }
var _c = _a.groups, groups = _c === void 0 ? Infinity : _c, _d = _a.digits, digits = _d === void 0 ? false : _d, options = __rest(_a, ["groups", "digits"]);
var words = [];
if (isNaN_1.default(input)) {
words.push('not a number');
}
else {
if (input < ZERO) {
words.push('negative');
input = -input;
}
if (isFinite_1.default(input)) {
if (input === 0) {
words.push(ones[0]);
}
else {
var _e = breakdown(input, groups), mantissa = _e.mantissa, exponent = _e.exponent;
while (Number.parseInt(mantissa, 10) > 0 && exponent >= 0 && groups-- > 0) {
var word = void 0;
var quantity = void 0;
(_b = illion(mantissa, exponent), quantity = _b.quantity, mantissa = _b.mantissa, exponent = _b.exponent, word = _b.word);
if (quantity) {
if (digits)
words.push(quantity.toString());
else
words.push(ordinal1000(quantity, options));
if (word)
words.push(word);
}
}
}
}
else {
words.push('infinity');
}
}
return words.flat().join(constants_1.space);
}
exports.cardinal = cardinal;
function breakdown(value, groups) {
var _a;
var _b = __read(value.toExponential(15).split('e'), 2), m = _b[0], e = _b[1]; // - 1 because toExponential returns 1 digit before the decimal point
var mantissa = m.replace('.', constants_1.empty);
var exponent = Number.parseInt(e, 10); // number of digits = (exponent + 1)
var groupCount = Math.floor(exponent / 3) + 1;
if (groupCount > groups) {
var digits = (groupCount * 3) - (2 - exponent % 3);
if (digits < 16) {
(_a = __read(value.toExponential(digits - 2).split('e'), 2), m = _a[0], e = _a[1]);
mantissa = m.replace('.', constants_1.empty);
exponent = Number.parseInt(e, 10);
}
}
return { mantissa: mantissa, exponent: exponent };
}
function ordinal1000(input, _a) {
var and = _a.and, _b = _a.hyphen, hyphen = _b === void 0 ? constants_1.space : _b;
var words = [];
if (input >= ONE_HUNDRED) {
words.push(ones[Math.floor(input / ONE_HUNDRED)], 'hundred');
input = input % ONE_HUNDRED;
if (and && input > ZERO)
words.push(and);
}
if (input > ZERO) {
if (input < TWENTY)
words.push(ones[input]);
else if (input % TEN === ZERO)
words.push(tens[Math.floor(input / TEN) - 2]);
else
words.push(tens[Math.floor(input / TEN) - 2] + hyphen + ones[input % TEN]);
}
return words;
}
function illion(mantissa, exponent) {
var factor = Math.floor((exponent - 3) / 3);
var quantity = 0;
switch (exponent - ((factor * 3) + 3)) {
case 0:
quantity = Number.parseInt(mantissa.slice(0, 1), 10);
mantissa = mantissa.slice(1);
exponent -= 1;
break;
case 1:
quantity = Number.parseInt(mantissa.slice(0, 2), 10);
mantissa = mantissa.slice(2);
exponent -= 2;
break;
case 2:
quantity = Number.parseInt(mantissa.slice(0, 3), 10);
mantissa = mantissa.slice(3);
exponent -= 3;
break;
}
if (factor < 0)
return { quantity: quantity, mantissa: mantissa, exponent: exponent, word: null };
if (factor === 0)
return { quantity: quantity, mantissa: mantissa, exponent: exponent, word: 'thousand' };
var word = 'on';
while (factor > 0) {
var a = false; // ones; use the prefixed form; tens change end from 'i' to 'a'
var s = false; // ones: tre => tres; se => ses
var x = false; // ones: tre => tres; se => sex
var m = false; // ones: septe = septem; nove => novem
var n = false; // ones: septe = septen; nove => noven
var factor0 = Math.floor(factor / 1) % 10;
var factor1 = Math.floor(factor / 10) % 10;
var factor2 = Math.floor(factor / 100) % 10;
word = "lli" + word;
// hundreds
switch (factor2) {
case 1:
word = "centi" + word;
a = true;
s = false;
x = true;
m = false;
n = true;
break;
case 2:
word = "ducenti" + word;
a = true;
s = false;
x = false;
m = false;
n = true;
break;
case 3:
word = "trecenti" + word;
a = true;
s = true;
x = false;
m = false;
n = true;
break;
case 4:
word = "quadringenti" + word;
a = true;
s = true;
x = false;
m = false;
n = true;
break;
case 5:
word = "quingenti" + word;
a = true;
s = true;
x = false;
m = false;
n = true;
break;
case 6:
word = "sescenti" + word;
a = true;
s = false;
x = false;
m = false;
n = true;
break;
case 7:
word = "septingenti" + word;
a = true;
s = false;
x = false;
m = false;
n = true;
break;
case 8:
word = "octingenti" + word;
a = true;
s = false;
x = true;
m = true;
n = false;
break;
case 9:
word = "nongenti" + word;
a = true;
s = false;
x = false;
m = false;
n = false;
break;
}
// tens
switch (factor1) {
case 1:
word = "deci" + word;
a = true;
s = false;
x = false;
m = false;
n = true;
break;
case 2:
word = "viginti" + word;
a = true;
s = true;
x = false;
m = true;
n = false;
break;
case 3:
word = (a ? 'triginta' : 'triginti') + word;
a = true;
s = true;
x = false;
m = false;
n = true;
break;
case 4:
word = (a ? 'quadraginta' : 'quadraginti') + word;
a = true;
s = true;
x = false;
m = false;
n = true;
break;
case 5:
word = (a ? 'quinquaginta' : 'quinquaginti') + word;
a = true;
s = true;
x = false;
m = false;
n = true;
break;
case 6:
word = (a ? 'sexaginta' : 'sexaginti') + word;
a = true;
s = false;
x = false;
m = false;
n = false;
break;
case 7:
word = (a ? 'septuaginta' : 'septuaginti') + word;
a = true;
s = false;
x = false;
m = false;
n = true;
break;
case 8:
word = (a ? 'octoginta' : 'octoginti') + word;
a = true;
s = false;
x = true;
m = true;
n = false;
break;
case 9:
word = (a ? 'nonaginta' : 'nonginti') + word;
a = true;
s = false;
x = false;
m = false;
n = false;
break;
}
// ones
if (a) {
switch (factor0) {
case 1:
word = "un" + word;
break;
case 2:
word = "duo" + word;
break;
case 3:
word = (s ? 'tres' : x ? 'tres' : 'tre') + word;
break;
case 4:
word = "quattuor" + word;
break;
case 5:
word = "quinqua" + word;
break;
case 6:
word = (s ? 'ses' : x ? 'sex' : 'se') + word;
break;
case 7:
word = (n ? 'septen' : m ? 'septem' : 'septe') + word;
break;
case 8:
word = "octo" + word;
break;
case 9:
word = (n ? 'noven' : m ? 'novem' : 'nove') + word;
break;
}
}
else {
switch (factor0) {
case 0:
word = "ni" + word;
break;
case 1:
word = "mi" + word;
break;
case 2:
word = "bi" + word;
break;
case 3:
word = "tri" + word;
break;
case 4:
word = "quadri" + word;
break;
case 5:
word = "quniti" + word;
break;
case 6:
word = "sexti" + word;
break;
case 7:
word = "septi" + word;
break;
case 8:
word = "octi" + word;
break;
case 9:
word = "noni" + word;
break;
}
}
factor = Math.floor(factor / 1000);
}
return { quantity: quantity, mantissa: mantissa, exponent: exponent, word: word };
}
/**
* Get the spelled out word for an exponent
*
* @remarks This is only using the exponent, There is no limit to the numbers this function can represents, however Javascript/Typescript can only represent
* numbers up to 1e308, which limits the numbers that this method can represent to 10^10^308 which is really really big.
*
* @example 6 is "million"
* @example 303 is "centillion"
* @param exponent The exponent to convert
* @returns Order of Magnitude as text
*/
function orderOfMagnitude(exponent) {
return illion('000', exponent).word;
}
exports.orderOfMagnitude = orderOfMagnitude;
/**
* Get a short description of a number
*
* @remarks this is a shortcut to calling cardinal with options {groups: 1, digits: true}
*
* @example 1000000 "1 million"
* @example 101323847382459 "101 trillion"
*
* @param input number to convert
* @param options see {@link OptionsIllion}
* @return number as text
*/
function summarize(input, options) {
if (options === void 0) { options = {}; }
return cardinal(input, __assign({ groups: 1, digits: true }, options));
}
exports.summarize = summarize;
exports.default = cardinal;