digit-to-words-nepali
Version:
A comprehensive TypeScript library for converting numbers to words in English and Nepali languages. Supports numbers up to 10^39 (Adanta Singhar), currency formatting, decimal handling with individual digit pronunciation, and BigInt. Zero dependencies, fu
161 lines (160 loc) • 6.43 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.digitToEnglishWords = exports.EnglishConverter = void 0;
const baseConverter_1 = require("./baseConverter");
const validationUtils_1 = require("../utils/validationUtils");
const scaleMappings_1 = require("../mappings/scaleMappings");
const numberMappings_1 = require("../mappings/numberMappings");
const cacheUtils_1 = require("../utils/cacheUtils");
const converterFactory_1 = require("../utils/converterFactory");
/**
* EnglishConverter
* Converts numbers to English words with support for currency, decimals, and custom mappings.
* Optimized for readability, maintainability, and performance.
*/
class EnglishConverter extends baseConverter_1.BaseConverter {
constructor() {
super();
this.wordCache = (0, numberMappings_1.createNumberWordMap)();
this.scales = scaleMappings_1.englishScaleMappings;
}
/**
* Convert decimal digits individually to English words.
* @param decimal - The decimal string (e.g., "33")
* @param config - Conversion configuration
* @returns Array of individual digit words
*/
convertDecimalDigitsIndividually(decimal, config) {
const digits = decimal.split('');
const words = [];
for (const digit of digits) {
const digitNum = parseInt(digit);
words.push(this.getWordMapping(digitNum, 'en'));
}
return words;
}
/**
* Convert a number to English words.
* @param num - The number to convert
* @param config - Conversion configuration (all fields required)
*/
convert(num, config) {
this.setCustomMappings(config);
// Validate input
if (!(0, validationUtils_1.isValidNumber)(num)) {
throw new Error('Input must contain only valid digits');
}
// Use cache if no custom mappings
const hasCustomMappings = Object.keys(config.units).length > 0 || Object.keys(config.scales).length > 0;
if (!hasCustomMappings) {
const cacheKey = {
value: num.toString(),
lang: config.lang,
isCurrency: config.isCurrency,
includeDecimal: config.includeDecimal,
individualDecimalDigits: config.individualDecimalDigits,
currency: config.currency,
decimalSuffix: config.decimalSuffix,
currencyDecimalSuffix: config.currencyDecimalSuffix
};
const cachedResult = cacheUtils_1.conversionCache.get(cacheKey);
if (cachedResult)
return cachedResult;
}
// Split number into integer and decimal parts
const { integer, decimal } = (0, validationUtils_1.splitNumber)(num);
const words = [];
// Integer part conversion
if (integer === 0n) {
words.push(this.getWordMapping(0, 'en'));
}
else {
this.processLargeNumber(integer, words, config);
}
// Decimal part conversion
if (config.includeDecimal && decimal) {
words.push(config.isCurrency ? config.currencyDecimalSuffix : config.decimalSuffix);
const decimalNum = parseInt(decimal);
if (decimalNum === 0) {
words.push(this.getWordMapping(0, 'en'));
}
else {
// Use individual digits for non-currency or when explicitly configured
if (config.individualDecimalDigits) {
const individualDigits = this.convertDecimalDigitsIndividually(decimal, config);
words.push(...individualDigits);
}
else {
words.push(this.getWordMapping(decimalNum, 'en'));
}
}
}
// Add currency prefix if needed
if (config.isCurrency) {
words.unshift(config.currency);
}
const result = {
words,
meta: {
originalNumber: num.toString(),
language: 'en',
isCurrency: config.isCurrency
}
};
// Store in cache if no custom mappings
if (!hasCustomMappings) {
const cacheKey = {
value: num.toString(),
lang: config.lang,
isCurrency: config.isCurrency,
includeDecimal: config.includeDecimal,
individualDecimalDigits: config.individualDecimalDigits,
currency: config.currency,
decimalSuffix: config.decimalSuffix,
currencyDecimalSuffix: config.currencyDecimalSuffix
};
cacheUtils_1.conversionCache.set(cacheKey, result);
}
return result;
}
processNumber(num, words, config) {
for (const scale of this.scales) {
if (num >= scale.value) {
const quotient = num / scale.value;
num = num % scale.value;
if (quotient > 0n) {
this.processNumber(quotient, words, config);
words.push(this.getScaleName(scale.value, 'en'));
}
}
}
if (num > 0n && num <= 99n) {
words.push(this.getWordMapping(Number(num), 'en'));
}
}
}
exports.EnglishConverter = EnglishConverter;
const digitToEnglishWords = (num, config = {}) => {
// Use the singleton pattern via factory
const converter = converterFactory_1.ConverterFactory.getInstance('EnglishConverter', () => new EnglishConverter());
// Default English language settings
const defaultConfig = {
lang: 'en',
isCurrency: false,
includeDecimal: true,
individualDecimalDigits: true, // Default to individual digits
currency: 'Dollars',
decimalSuffix: 'point',
currencyDecimalSuffix: 'cents',
units: {},
scales: {},
...config
};
// Override individualDecimalDigits based on currency setting if not explicitly set
if (config.individualDecimalDigits === undefined) {
defaultConfig.individualDecimalDigits = !defaultConfig.isCurrency;
}
const result = converter.convert(num, defaultConfig);
return result.words.filter((word) => word !== '').join(' ').trim();
};
exports.digitToEnglishWords = digitToEnglishWords;