Context
Convert number to words, quite useful in the context of drafting contracts.
Metadata
{
"key": "number-to-words",
"name": "Number to Words",
"description": "Convert a number into words",
"developerEmail": "email@bryter.io",
"parameters": [
{
"name": "Number",
"type": "number",
"description": "The number to convert"
}
],
"result": {
"type": "text",
"description": "The number as words"
}
}
Action
function main(numberToConvert: number) {
const MAX_SAFE_INTEGER = 9007199254740991
function isSafeNumber(value: number) {
return typeof value === 'number' && Math.abs(value) <= MAX_SAFE_INTEGER
}
function isFinite(value: number) {
return !(typeof value !== 'number' || value !== value || value === Infinity || value === -Infinity)
}
const TEN = 10
const ONE_HUNDRED = 100
const ONE_THOUSAND = 1000
const ONE_MILLION = 1000000
const ONE_BILLION = 1000000000 // 1.000.000.000 (9)
const ONE_TRILLION = 1000000000000 // 1.000.000.000.000 (12)
const ONE_QUADRILLION = 1000000000000000 // 1.000.000.000.000.000 (15)
const MAX = 9007199254740992 // 9.007.199.254.740.992 (15)
const LESS_THAN_TWENTY = [
'zero',
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'ten',
'eleven',
'twelve',
'thirteen',
'fourteen',
'fifteen',
'sixteen',
'seventeen',
'eighteen',
'nineteen',
]
const TENTHS_LESS_THAN_HUNDRED = [
'zero',
'ten',
'twenty',
'thirty',
'forty',
'fifty',
'sixty',
'seventy',
'eighty',
'ninety',
]
function toWords(number: number) {
let num = number;
if (typeof number != 'number') {
num = parseInt(number, 10)
}
if (!isFinite(num)) {
return new TypeError(`Not a finite number: ${number} (${typeof number})`)
}
if (!isSafeNumber(num)) {
return new RangeError(`Input is not a safe number, it's either too large or too small.`)
}
const words = generateWords(num)
return words
}
function generateWords(number: number, words?: string[]): string {
let word = '';
let remainder = 0;
// We're done
if (number === 0) {
return !words ? 'zero' : words.join(' ').replace(/,$/, '')
}
// First run
if (!words) {
words = []
}
// If negative, prepend "minus"
if (number < 0) {
words.push('minus')
number = Math.abs(number)
}
if (number < 20) {
remainder = 0
word = LESS_THAN_TWENTY[number]
} else if (number < ONE_HUNDRED) {
remainder = number % TEN
word = TENTHS_LESS_THAN_HUNDRED[Math.floor(number / TEN)]
// In case of remainder, we need to handle it here to be able to add the "-"
if (remainder) {
word += '-' + LESS_THAN_TWENTY[remainder]
remainder = 0
}
} else if (number < ONE_THOUSAND) {
remainder = number % ONE_HUNDRED
word = generateWords(Math.floor(number / ONE_HUNDRED)) + ' hundred'
} else if (number < ONE_MILLION) {
remainder = number % ONE_THOUSAND
word = generateWords(Math.floor(number / ONE_THOUSAND)) + ' thousand,'
} else if (number < ONE_BILLION) {
remainder = number % ONE_MILLION
word = generateWords(Math.floor(number / ONE_MILLION)) + ' million,'
} else if (number < ONE_TRILLION) {
remainder = number % ONE_BILLION
word = generateWords(Math.floor(number / ONE_BILLION)) + ' billion,'
} else if (number < ONE_QUADRILLION) {
remainder = number % ONE_TRILLION
word = generateWords(Math.floor(number / ONE_TRILLION)) + ' trillion,'
} else if (number <= MAX) {
remainder = number % ONE_QUADRILLION
word = generateWords(Math.floor(number / ONE_QUADRILLION)) + ' quadrillion,'
}
words.push(word)
return generateWords(remainder, words)
}
return toWords(numberToConvert);
};