import path from 'path'; interface Voice { directory: string; extension: string; } type Voices = { [name: string]: Voice }; const LINES = { NEGATIVE: 'negative', POINT: 'point', ZERO: 'zero', ONE: 'one', TWO: 'two', THREE: 'three', FOUR: 'four', FIVE: 'five', SIX: 'six', SEVEN: 'seven', EIGHT: 'eight', NINE: 'nine', TEN: 'ten', ELEVEN: 'eleven', TWELVE: 'twelve', THIRTEEN: 'thirteen', FIFTEEN: 'fifteen', TEEN: 'teen', TWENTY: 'twenty', THIRTY: 'thirty', FORTY: 'forty', FIFTY: 'fifty', SIXTY: 'sixty', SEVENTY: 'seventy', EIGHTY: 'eighty', NINETY: 'ninety', HUNDRED: 'hundred', THOUSAND: 'thousand', MILLION: 'million', BILLION: 'billion', TRILLION: 'trillion' } function formatNumber(num: number): string { const parts = num.toString().split("."); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); return parts.join("."); } function digitByDigit(str: string): string[] { const tokens: string[] = []; const input = str.replaceAll(',', ''); const map = [ LINES.ZERO, LINES.ONE, LINES.TWO, LINES.THREE, LINES.FOUR, LINES.FIVE, LINES.SIX, LINES.SEVEN, LINES.EIGHT, LINES.NINE ] for (let i = 0; i < input.length; i++) { tokens.push(map[parseInt(input.charAt(i))]); } return tokens; } function tens(str: string): string[] { if (str === '0') { return [LINES.ZERO]; } const tokens: string[] = []; const num = parseInt(str); const map = { '2': LINES.TWENTY, '3': LINES.THIRTY, '4': LINES.FORTY, '5': LINES.FIFTY, '6': LINES.SIXTY, '7': LINES.SEVENTY, '8': LINES.EIGHTY, '9': LINES.NINETY }; const ones = str.charAt(str.length - 1); if (num === 0) { return []; } else if (num >= 20) { tokens.push(map[str.charAt(0)]); if (ones !== '0') { tokens.push(...digitByDigit(ones)); } } else if (num < 10) { tokens.push(...digitByDigit(ones)); } else { const weirdoNumberMap = [ [LINES.TEN], [LINES.ELEVEN], [LINES.TWELVE], [LINES.THIRTEEN], [LINES.FOUR, LINES.TEEN], [LINES.FIFTEEN], [LINES.SIX, LINES.TEEN], [LINES.SEVEN, LINES.TEEN], [LINES.EIGHT, LINES.TEEN], [LINES.NINE, LINES.TEEN], ] tokens.push(...weirdoNumberMap[num - 10]); } return tokens; } function hundreds(str: string): string[] { const tokens: string[] = []; if (str.length === 3 && str.charAt(0) !== '0') { tokens.push(...digitByDigit(str.charAt(0))); tokens.push(LINES.HUNDRED); str = str.substring(1); } tokens.push(...tens(str)); return tokens; } function integer(str: string): string[] { const tokens: string[] = []; const numGroups = str.split(','); const seperators = [LINES.TRILLION, LINES.BILLION, LINES.MILLION, LINES.THOUSAND]; if (numGroups.length > 5) { return digitByDigit(str); } seperators.splice(0, seperators.length - numGroups.length + 1); numGroups.forEach(g => { if (g !== '000') { tokens.push(...hundreds(g)); } if (seperators.length === 0) { return; } const sep = seperators.shift(); if (g !== '000') { tokens.push(sep); } }); return tokens; } function voiceLines(voice: Voice, num: number): string[] { if (Math.abs(num) > 999999999999999 || isNaN(num)) { return []; } const tokens: string[] = []; const str = formatNumber(num); const parts = str.split('.'); if (parts[0].startsWith('-')) { tokens.push(LINES.NEGATIVE); parts[0] = parts[0].substring(1); } tokens.push(...integer(parts[0])); if (parts.length > 1) { tokens.push(LINES.POINT); tokens.push(...digitByDigit(parts[1])); } return tokens.map(l => path.join(voice.directory, `${l}${voice.extension.length > 0 && voice.extension.charAt(0) !== '.' ? '.' : ''}${voice.extension}`)); } export default voiceLines; export { voiceLines, LINES }; export type { Voice, Voices };