UNPKG

@technobuddha/library

Version:
452 lines (451 loc) 14.6 kB
"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;