bangla-stdlib 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constants/numerals.ts","../src/constants/months.ts","../src/constants/weekdays.ts","../src/constants/seasons.ts","../src/number/toBangla.ts","../src/number/fromBangla.ts","../src/number/toWords.ts","../src/number/formatWithUnits.ts","../src/number/formatNumber.ts","../src/number/validate.ts","../src/number/utils.ts","../src/currency/formatCurrency.ts","../src/currency/parseCurrency.ts","../src/currency/validate.ts","../src/currency/utils.ts","../src/month/toBanglaMonth.ts","../src/month/fromBanglaMonth.ts","../src/month/getMonthName.ts","../src/date/validate.ts","../src/month/validate.ts","../src/month/utils.ts","../src/weekday/toBanglaWeekday.ts","../src/weekday/fromBanglaWeekday.ts","../src/weekday/getWeekdayName.ts","../src/weekday/validate.ts","../src/weekday/utils.ts","../src/date/formatDate.ts","../src/date/parseDate.ts","../src/date/utils.ts","../src/season/getSeasonFromMonth.ts","../src/calendar/fromBengali.ts","../src/calendar/getBengaliDate.ts","../src/calendar/validate.ts","../src/calendar/utils.ts","../src/calendar/toBengali.ts","../src/season/getSeason.ts","../src/season/validate.ts","../src/season/utils.ts","../src/ordinal/toOrdinal.ts","../src/ordinal/validate.ts","../src/ordinal/utils.ts","../src/time/formatTime.ts","../src/time/relativeTime.ts","../src/time/validate.ts","../src/time/utils.ts","../src/phone/formatPhone.ts","../src/phone/validatePhone.ts","../src/phone/utils.ts","../src/utils/validateBangla.ts","../src/utils/isBanglaDigit.ts","../src/utils/isBanglaText.ts","../src/utils/utils.ts"],"sourcesContent":["export * from './constants';\nexport * from './number';\nexport * from './currency';\nexport * from './date';\nexport * from './month';\nexport * from './weekday';\nexport * from './season';\nexport * from './ordinal';\nexport * from './time';\nexport * from './calendar';\nexport * from './phone';\nexport * from './utils';\n","export const BANGLA_DIGITS = ['০', '১', '২', '৩', '৪', '৫', '৬', '৭', '৮', '৯'] as const;\n\nexport const ENGLISH_DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] as const;\n","export const BANGLA_MONTHS = [\n 'বৈশাখ',\n 'জ্যৈষ্ঠ',\n 'আষাঢ়',\n 'শ্রাবণ',\n 'ভাদ্র',\n 'আশ্বিন',\n 'কার্তিক',\n 'অগ্রহায়ণ',\n 'পৌষ',\n 'মাঘ',\n 'ফাল্গুন',\n 'চৈত্র',\n] as const;\n","export const BANGLA_WEEKDAYS = [\n 'রবিবার',\n 'সোমবার',\n 'মঙ্গলবার',\n 'বুধবার',\n 'বৃহস্পতিবার',\n 'শুক্রবার',\n 'শনিবার',\n] as const;\n","export const BANGLA_SEASONS = ['গ্রীষ্ম', 'বর্ষা', 'শরৎ', 'হেমন্ত', 'শীত', 'বসন্ত'] as const;\n","import { BANGLA_DIGITS, ENGLISH_DIGITS } from '../constants';\n\n/**\n * Converts English/Arabic digits to Bangla digits.\n *\n * This function converts numbers (or numeric strings) from English/Arabic numerals (0-9)\n * to their Bangla equivalents (০-৯). It preserves the structure of the number including\n * decimal points and negative signs.\n *\n * @param input - A number or numeric string to convert\n * @returns The number with Bangla digits\n * @throws {TypeError} If input is null, undefined, not finite, or an unsafe integer\n * @throws {Error} If input contains invalid characters, multiple decimals, or scientific notation\n *\n * @example\n * Basic conversion:\n * ```typescript\n * toBanglaNumber(123); // '১২৩'\n * toBanglaNumber('456'); // '৪৫৬'\n * ```\n *\n * @example\n * Decimal numbers:\n * ```typescript\n * toBanglaNumber(123.456); // '১২৩.৪৫৬'\n * toBanglaNumber('99.99'); // '৯৯.৯৯'\n * ```\n *\n * @example\n * Negative numbers:\n * ```typescript\n * toBanglaNumber(-123); // '-১২৩'\n * toBanglaNumber('-456.78'); // '-৪৫৬.৭৮'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * toBanglaNumber(NaN); // throws TypeError: Input must be a finite number\n * toBanglaNumber(Infinity); // throws TypeError: Input must be a finite number\n * toBanglaNumber('abc'); // throws Error: Invalid character in number: a\n * toBanglaNumber('১২৩'); // throws Error: Input already contains Bangla digits\n * toBanglaNumber('12.34.56'); // throws Error: Multiple decimal points\n * toBanglaNumber(1e100); // throws TypeError: Input must be a safe integer\n * ```\n */\nexport function toBanglaNumber(input: number | string): string {\n if (input === null || input === undefined) {\n throw new TypeError('Invalid input');\n }\n\n const value = String(input).trim();\n\n if (value === '') {\n throw new Error('Empty input');\n }\n\n // Reject scientific notation\n if (/[eE]/.test(value)) {\n throw new Error('Scientific notation not supported');\n }\n\n // Explicit numeric validation (VERY important)\n if (typeof input === 'number') {\n if (!Number.isFinite(input)) {\n throw new TypeError('Input must be a finite number');\n }\n // Reject scientific notation (check if number is exactly a power of 10 >= 1e5)\n // This catches cases like 1e5, 1e6, etc. that are commonly written in scientific notation\n // We check if the number is exactly 10^N where N >= 5\n if (Number.isInteger(input) && Math.abs(input) >= 1e5) {\n const absInput = Math.abs(input);\n // Check if it's exactly a power of 10 (10^N)\n const log10 = Math.log10(absInput);\n if (Number.isInteger(log10) && log10 >= 5) {\n throw new Error('Scientific notation not supported');\n }\n }\n // Reject unsafe integers (only check if it's an integer)\n if (Number.isInteger(input) && !Number.isSafeInteger(input)) {\n throw new TypeError('Input must be a safe integer');\n }\n }\n\n // Reject Bangla digits already present\n if (/[০-৯]/.test(value)) {\n throw new Error('Input already contains Bangla digits');\n }\n\n let hasDecimal = false;\n let hasDigit = false;\n let result = '';\n\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n\n if (char === '.') {\n if (hasDecimal) {\n throw new Error('Multiple decimal points');\n }\n hasDecimal = true;\n result += '.';\n continue;\n }\n\n if (char === '-') {\n if (i !== 0) {\n throw new Error('Invalid minus position');\n }\n result += '-';\n continue;\n }\n\n const index = ENGLISH_DIGITS.indexOf(char as any);\n if (index !== -1) {\n hasDigit = true;\n result += BANGLA_DIGITS[index];\n continue;\n }\n\n throw new Error(`Invalid character in number: ${char}`);\n }\n\n if (!hasDigit) {\n throw new Error('No digits found');\n }\n\n if (hasDecimal) {\n if (value.startsWith('.') || value.startsWith('-.')) {\n throw new Error('Decimal must have leading digit');\n }\n if (value.endsWith('.')) {\n throw new Error('Decimal must have trailing digit');\n }\n }\n\n return result;\n}\n","import { BANGLA_DIGITS, ENGLISH_DIGITS } from '../constants';\n\n/**\n * Converts Bangla digits to a JavaScript number.\n *\n * This function parses a string containing Bangla numerals (০-৯) and converts it\n * to a JavaScript number. It supports decimals and negative numbers.\n *\n * @param input - A string containing Bangla digits\n * @returns The parsed JavaScript number\n * @throws {TypeError} If input is not a string or cannot be parsed to a finite number\n * @throws {Error} If input is empty, contains invalid characters, or has multiple decimals\n *\n * @example\n * Basic conversion:\n * ```typescript\n * fromBanglaNumber('১২৩'); // 123\n * fromBanglaNumber('৪৫৬'); // 456\n * ```\n *\n * @example\n * Decimal numbers:\n * ```typescript\n * fromBanglaNumber('১২৩.৪৫৬'); // 123.456\n * fromBanglaNumber('৯৯.৯৯'); // 99.99\n * ```\n *\n * @example\n * Negative numbers:\n * ```typescript\n * fromBanglaNumber('-১২৩'); // -123\n * fromBanglaNumber('-৪৫৬.৭৮'); // -456.78\n * ```\n *\n * @example\n * Round-trip conversion:\n * ```typescript\n * const original = 123.45;\n * const bangla = toBanglaNumber(original); // '১২৩.৪৫'\n * const converted = fromBanglaNumber(bangla); // 123.45\n * console.log(original === converted); // true\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * fromBanglaNumber(123); // throws TypeError: Input must be a string\n * fromBanglaNumber(''); // throws Error: Empty input\n * fromBanglaNumber('abc'); // throws Error: Invalid Bangla digit: a\n * fromBanglaNumber('১২৩.৪৫.৬৭'); // throws Error: Multiple decimal points\n * fromBanglaNumber('.৫'); // throws Error: Decimal must have leading digit\n * ```\n */\nexport function fromBanglaNumber(input: string): number {\n if (typeof input !== 'string') {\n throw new TypeError('Input must be a string');\n }\n\n const value = input.trim();\n\n if (value === '') {\n throw new Error('Empty input');\n }\n\n let hasDecimal = false;\n let hasDigit = false;\n let result = '';\n\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n\n if (char === '.') {\n if (hasDecimal) {\n throw new Error('Multiple decimal points');\n }\n hasDecimal = true;\n result += '.';\n continue;\n }\n\n if (char === '-') {\n if (i !== 0) {\n throw new Error('Invalid minus position');\n }\n result += '-';\n continue;\n }\n\n const index = BANGLA_DIGITS.indexOf(char as any);\n if (index !== -1) {\n hasDigit = true;\n result += ENGLISH_DIGITS[index];\n continue;\n }\n\n throw new Error(`Invalid Bangla digit: ${char}`);\n }\n\n if (!hasDigit) {\n throw new Error('No digits found');\n }\n\n if (hasDecimal) {\n if (value.startsWith('.') || value.startsWith('-.')) {\n throw new Error('Decimal must have leading digit');\n }\n if (value.endsWith('.')) {\n throw new Error('Decimal must have trailing digit');\n }\n }\n\n const parsed = Number(result);\n if (!Number.isFinite(parsed)) {\n throw new TypeError('Failed to parse Bangla number');\n }\n\n return parsed;\n}\n","/**\n * Converts a number to its word representation in Bangla.\n *\n * This function converts integers to their Bangla word form following Bangladesh\n * linguistic conventions. It supports numbers from -99,999,999,999 to 99,999,999,999\n * (just under 100 billion).\n *\n * **Supported Range:** -99,999,999,999 to 99,999,999,999\n *\n * **Special Cases:** The function uses linguistically correct Bangla spellings for\n * certain compound numbers:\n * - 23 → \"তেইশ\" (not \"বিশ তিন\")\n * - 34 → \"চৌত্রিশ\" (not \"তিরিশ চার\")\n * - 56 → \"ছাপ্পান্ন\" (not \"পঞ্চাশ ছয়\")\n *\n * @param number - The integer to convert (must be within supported range)\n * @returns The number in Bangla words\n * @throws {Error} If the number exceeds 99,999,999,999 (100 billion or more)\n *\n * @example\n * Basic numbers:\n * ```typescript\n * toWords(0); // 'শূন্য'\n * toWords(5); // 'পাঁচ'\n * toWords(15); // 'পনেরো'\n * toWords(42); // 'চল্লিশ দুই'\n * ```\n *\n * @example\n * Special compound numbers:\n * ```typescript\n * toWords(23); // 'তেইশ'\n * toWords(34); // 'চৌত্রিশ'\n * toWords(56); // 'ছাপ্পান্ন'\n * ```\n *\n * @example\n * Hundreds and thousands:\n * ```typescript\n * toWords(100); // 'একশত'\n * toWords(250); // 'দুইশত পঞ্চাশ'\n * toWords(1000); // 'এক হাজার'\n * toWords(1500); // 'এক হাজার পাঁচশত'\n * toWords(12345); // 'বারো হাজার তিনশত পঁয়তাল্লিশ'\n * ```\n *\n * @example\n * Lakhs and crores (Indian numbering):\n * ```typescript\n * toWords(100000); // 'এক লক্ষ'\n * toWords(1500000); // 'পনেরো লক্ষ'\n * toWords(10000000); // 'এক কোটি'\n * toWords(50000000); // 'পাঁচ কোটি'\n * ```\n *\n * @example\n * Large numbers:\n * ```typescript\n * toWords(1000000000); // 'এক হাজার কোটি' (1 billion)\n * toWords(10000000000); // 'দশ হাজার কোটি' (10 billion)\n * toWords(99999999999); // Maximum supported number\n * ```\n *\n * @example\n * Negative numbers:\n * ```typescript\n * toWords(-5); // 'ঋণাত্মক পাঁচ'\n * toWords(-1000); // 'ঋণাত্মক এক হাজার'\n * toWords(-50000); // 'ঋণাত্মক পঞ্চাশ হাজার'\n * ```\n *\n * @example\n * Error case:\n * ```typescript\n * toWords(100000000000); // throws Error: Number too large to convert to words\n * ```\n *\n * @example\n * Practical usage (invoices, checks):\n * ```typescript\n * const amount = 45000;\n * const words = toWords(amount);\n * console.log(`Amount in words: ${words} টাকা`);\n * // \"Amount in words: পঁয়তাল্লিশ হাজার টাকা\"\n * ```\n */\nexport function toWords(number: number): string {\n if (number === 0) {\n return 'শূন্য';\n }\n\n if (number < 0) {\n return 'ঋণাত্মক ' + toWords(-number);\n }\n\n if (number < 100) {\n return convertBelowHundred(number);\n }\n\n if (number < 1000) {\n return convertBelowThousand(number);\n }\n\n if (number < 100000) {\n return convertBelowLakh(number);\n }\n\n if (number < 10000000) {\n return convertBelowCrore(number);\n }\n\n if (number < 1000000000) {\n return convertBelowArab(number);\n }\n\n if (number < 100000000000) {\n return convertBelowKharab(number);\n }\n\n throw new Error('Number too large to convert to words');\n}\n\nfunction convertBelowHundred(n: number): string {\n const ones = [\n '',\n 'এক',\n 'দুই',\n 'তিন',\n 'চার',\n 'পাঁচ',\n 'ছয়',\n 'সাত',\n 'আট',\n 'নয়',\n 'দশ',\n 'এগারো',\n 'বারো',\n 'তেরো',\n 'চৌদ্দ',\n 'পনেরো',\n 'ষোল',\n 'সতেরো',\n 'আঠারো',\n 'ঊনিশ',\n 'বিশ',\n ];\n\n const tens = ['', '', 'কুড়ি', 'তিরিশ', 'চল্লিশ', 'পঞ্চাশ', 'ষাট', 'সত্তর', 'আশি', 'নব্বই'];\n\n if (n === 0) {\n return '';\n }\n\n if (n < 20) {\n return ones[n];\n }\n\n // Special cases for compound numbers\n if (n === 23) {\n return 'তেইশ';\n }\n if (n === 34) {\n return 'চৌত্রিশ';\n }\n if (n === 56) {\n return 'ছাপ্পান্ন';\n }\n\n const ten = Math.floor(n / 10);\n const one = n % 10;\n\n if (one === 0) {\n return tens[ten];\n }\n\n return tens[ten] + ' ' + ones[one];\n}\n\nfunction convertBelowThousand(n: number): string {\n const hundred = Math.floor(n / 100);\n const remainder = n % 100;\n\n let result = '';\n\n if (hundred > 0) {\n if (hundred === 1) {\n result = 'একশত';\n } else {\n result = convertBelowHundred(hundred) + 'শত';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowHundred(remainder);\n }\n\n return result;\n}\n\nfunction convertBelowLakh(n: number): string {\n const thousand = Math.floor(n / 1000);\n const remainder = n % 1000;\n\n let result = '';\n\n if (thousand > 0) {\n if (thousand === 1) {\n result = 'এক হাজার';\n } else {\n result = convertBelowThousand(thousand) + ' হাজার';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowThousand(remainder);\n }\n\n return result;\n}\n\nfunction convertBelowCrore(n: number): string {\n const lakh = Math.floor(n / 100000);\n const remainder = n % 100000;\n\n let result = '';\n\n if (lakh > 0) {\n if (lakh === 1) {\n result = 'এক লক্ষ';\n } else {\n result = convertBelowThousand(lakh) + ' লক্ষ';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowLakh(remainder);\n }\n\n return result;\n}\n\nfunction convertBelowArab(n: number): string {\n const crore = Math.floor(n / 10000000);\n const remainder = n % 10000000;\n\n let result = '';\n\n if (crore > 0) {\n if (crore === 1) {\n result = 'এক কোটি';\n } else {\n result = convertBelowThousand(crore) + ' কোটি';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowCrore(remainder);\n }\n\n return result;\n}\n\nfunction convertBelowKharab(n: number): string {\n const arab = Math.floor(n / 1000000000);\n const remainder = n % 1000000000;\n\n let result = '';\n\n if (arab > 0) {\n if (arab === 1) {\n result = 'এক হাজার কোটি';\n } else {\n result = convertBelowThousand(arab) + ' হাজার কোটি';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowArab(remainder);\n }\n\n return result;\n}\n","import { toBanglaNumber } from './toBangla';\n\n/**\n * Formats large numbers with Bengali unit names (হাজার, লক্ষ, কোটি).\n *\n * This function simplifies large numbers by expressing them in common Bengali units:\n * - হাজার (Thousand): 1,000\n * - লক্ষ (Lakh): 100,000\n * - কোটি (Crore): 10,000,000\n *\n * The function automatically selects the most appropriate unit based on the number's magnitude.\n *\n * @param number - The number to format\n * @param options - Formatting options\n * @param options.precision - Number of decimal places to show (default: 2)\n * @param options.useBanglaDigits - Whether to use Bangla digits (default: true)\n * @returns Formatted string with unit\n *\n * @example\n * Basic usage with default options:\n * ```typescript\n * formatWithUnits(5000); // '৫ হাজার'\n * formatWithUnits(150000); // '১.৫ লক্ষ'\n * formatWithUnits(25000000); // '২.৫ কোটি'\n * ```\n *\n * @example\n * With English digits:\n * ```typescript\n * formatWithUnits(5000, { useBanglaDigits: false }); // '5 হাজার'\n * formatWithUnits(150000, { useBanglaDigits: false }); // '1.5 লক্ষ'\n * formatWithUnits(25000000, { useBanglaDigits: false }); // '2.5 কোটি'\n * ```\n *\n * @example\n * Custom precision:\n * ```typescript\n * formatWithUnits(1234567, { precision: 0 }); // '১ লক্ষ' (rounded)\n * formatWithUnits(1234567, { precision: 1 }); // '১২.৩ লক্ষ'\n * formatWithUnits(1234567, { precision: 3 }); // '১২.৩৪৬ লক্ষ'\n * ```\n *\n * @example\n * Negative numbers:\n * ```typescript\n * formatWithUnits(-50000); // '-৫ হাজার'\n * formatWithUnits(-1500000); // '-১৫ লক্ষ'\n * ```\n *\n * @example\n * Numbers below 1,000 (no unit):\n * ```typescript\n * formatWithUnits(500); // '৫০০'\n * formatWithUnits(999); // '৯৯৯'\n * ```\n *\n * @example\n * Practical usage (UI display):\n * ```typescript\n * const views = 1250000;\n * const formatted = formatWithUnits(views);\n * console.log(`${formatted} ভিউ`); // '১২.৫ লক্ষ ভিউ'\n *\n * const price = 15000;\n * const formatted2 = formatWithUnits(price);\n * console.log(`৳ ${formatted2}`); // '৳ ১৫ হাজার'\n * ```\n */\nexport function formatWithUnits(\n number: number,\n options: {\n precision?: number;\n useBanglaDigits?: boolean;\n } = {}\n): string {\n const { precision = 2, useBanglaDigits = true } = options;\n\n if (number === 0) {\n return useBanglaDigits ? '০' : '0';\n }\n\n const absNumber = Math.abs(number);\n const sign = number < 0 ? '-' : '';\n\n let value: number;\n let unit: string;\n\n if (absNumber >= 10000000) {\n // কোটি (Crore)\n value = absNumber / 10000000;\n unit = 'কোটি';\n } else if (absNumber >= 100000) {\n // লক্ষ (Lakh)\n value = absNumber / 100000;\n unit = 'লক্ষ';\n } else if (absNumber >= 1000) {\n // হাজার (Thousand)\n value = absNumber / 1000;\n unit = 'হাজার';\n } else {\n // No unit needed\n const formatted = useBanglaDigits ? toBanglaNumber(absNumber) : absNumber.toString();\n return sign + formatted;\n }\n\n const rounded = Number(value.toFixed(precision));\n const formatted = useBanglaDigits ? toBanglaNumber(rounded) : rounded.toString();\n\n return sign + formatted + ' ' + unit;\n}\n","import { toBanglaNumber } from './toBangla';\n\nexport interface FormatNumberOptions {\n /** Whether to use Bangla digits (default: true) */\n useBanglaDigits?: boolean;\n /** Separator character for thousands (default: ',') */\n separator?: string;\n}\n\n/**\n * Formats a number with comma separators using Indian/Bangla numbering system\n * Pattern: rightmost 3 digits, then groups of 2 digits\n * @param number - The number to format\n * @param options - Formatting options\n * @returns Formatted number string\n * @example\n * formatNumber(1234567) // '12,34,567'\n * formatNumber(1234567.89) // '12,34,567.89'\n * formatNumber(1234567, { useBanglaDigits: false }) // '12,34,567'\n */\nexport function formatNumber(number: number | string, options: FormatNumberOptions = {}): string {\n const { useBanglaDigits = true, separator = ',' } = options;\n\n const numStr = typeof number === 'string' ? number : number.toString();\n const [integerPart, decimalPart] = numStr.split('.');\n\n // Convert to Bangla digits if needed\n let formattedInteger = integerPart;\n if (useBanglaDigits) {\n formattedInteger = toBanglaNumber(integerPart);\n }\n\n // Format integer part with separators using Indian/Bangla numbering system\n // Pattern: rightmost 3 digits, then groups of 2 digits\n const formatted = formatIntegerPart(formattedInteger, separator);\n\n // Handle decimal part\n if (decimalPart !== undefined) {\n const formattedDecimal = useBanglaDigits ? toBanglaNumber(decimalPart) : decimalPart;\n return `${formatted}.${formattedDecimal}`;\n }\n\n return formatted;\n}\n\n/**\n * Formats integer part with Indian/Bangla numbering system separators\n * Pattern: rightmost 3 digits, then groups of 2 digits\n */\nfunction formatIntegerPart(integerPart: string, separator: string): string {\n // Handle negative sign separately\n const isNegative = integerPart.startsWith('-');\n const absolutePart = isNegative ? integerPart.slice(1) : integerPart;\n const len = absolutePart.length;\n\n if (len <= 3) {\n return integerPart; // Return as-is (preserving minus if present)\n }\n\n // Take rightmost 3 digits\n const rightmost3 = absolutePart.slice(-3);\n const remaining = absolutePart.slice(0, -3);\n\n // Group remaining digits in groups of 2 from right\n const groups: string[] = [];\n for (let i = remaining.length; i > 0; i -= 2) {\n const start = Math.max(0, i - 2);\n groups.unshift(remaining.slice(start, i));\n }\n\n const formatted = `${groups.join(separator)}${separator}${rightmost3}`;\n return isNegative ? `-${formatted}` : formatted;\n}\n","import { BANGLA_DIGITS, ENGLISH_DIGITS } from '../constants';\n\n/**\n * Validates if a string contains a valid Bangla number.\n *\n * This function checks if the input string represents a valid Bangla number\n * without throwing errors, making it ideal for form validation.\n *\n * @param input - The string to validate\n * @returns true if the string is a valid Bangla number, false otherwise\n *\n * @example\n * ```typescript\n * isValidBanglaNumber('১২৩'); // true\n * isValidBanglaNumber('১২৩.৪৫'); // true\n * isValidBanglaNumber('-১২৩'); // true\n * isValidBanglaNumber('123'); // false (English digits)\n * isValidBanglaNumber('১২৩abc'); // false (invalid characters)\n * isValidBanglaNumber(''); // false (empty)\n * ```\n */\nexport function isValidBanglaNumber(input: string): boolean {\n if (typeof input !== 'string') {\n return false;\n }\n\n const value = input.trim();\n\n if (value === '') {\n return false;\n }\n\n let hasDecimal = false;\n let hasDigit = false;\n\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n\n // Check for decimal point\n if (char === '.') {\n if (hasDecimal) {\n return false; // Multiple decimal points\n }\n hasDecimal = true;\n continue;\n }\n\n // Check for minus sign\n if (char === '-') {\n if (i !== 0) {\n return false; // Minus must be at start\n }\n continue;\n }\n\n // Check if it's a valid Bangla digit\n const index = BANGLA_DIGITS.indexOf(char as any);\n if (index !== -1) {\n hasDigit = true;\n continue;\n }\n\n // Invalid character found\n return false;\n }\n\n // Must have at least one digit\n if (!hasDigit) {\n return false;\n }\n\n // Validate decimal placement\n if (hasDecimal) {\n if (value.startsWith('.') || value.startsWith('-.')) {\n return false; // Decimal must have leading digit\n }\n if (value.endsWith('.')) {\n return false; // Decimal must have trailing digit\n }\n }\n\n return true;\n}\n\n/**\n * Validates if a number or string can be converted to a Bangla number.\n *\n * This function checks if the input can be safely processed by `toBanglaNumber()`\n * without throwing errors.\n *\n * @param input - The number or string to validate\n * @returns true if the input can be converted to Bangla, false otherwise\n *\n * @example\n * ```typescript\n * isValidNumber(123); // true\n * isValidNumber('123'); // true\n * isValidNumber('123.45'); // true\n * isValidNumber(-123); // true\n * isValidNumber(NaN); // false\n * isValidNumber(Infinity); // false\n * isValidNumber('abc'); // false\n * isValidNumber('১২৩'); // false (already Bangla)\n * isValidNumber(1e100); // false (unsafe integer)\n * ```\n */\nexport function isValidNumber(input: number | string): boolean {\n if (input === null || input === undefined) {\n return false;\n }\n\n const value = String(input).trim();\n\n if (value === '') {\n return false;\n }\n\n // Reject scientific notation\n if (/[eE]/.test(value)) {\n return false;\n }\n\n // Validate number type inputs\n if (typeof input === 'number') {\n if (!Number.isFinite(input)) {\n return false;\n }\n\n // Reject unsafe integers\n if (Number.isInteger(input) && !Number.isSafeInteger(input)) {\n return false;\n }\n\n // Reject scientific notation (powers of 10 >= 1e5)\n if (Number.isInteger(input) && Math.abs(input) >= 1e5) {\n const absInput = Math.abs(input);\n const log10 = Math.log10(absInput);\n if (Number.isInteger(log10) && log10 >= 5) {\n return false;\n }\n }\n }\n\n // Reject if already contains Bangla digits\n if (/[০-৯]/.test(value)) {\n return false;\n }\n\n let hasDecimal = false;\n let hasDigit = false;\n\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n\n // Check for decimal point\n if (char === '.') {\n if (hasDecimal) {\n return false; // Multiple decimal points\n }\n hasDecimal = true;\n continue;\n }\n\n // Check for minus sign\n if (char === '-') {\n if (i !== 0) {\n return false; // Minus must be at start\n }\n continue;\n }\n\n // Check if it's a valid English digit\n const index = ENGLISH_DIGITS.indexOf(char as any);\n if (index !== -1) {\n hasDigit = true;\n continue;\n }\n\n // Invalid character found\n return false;\n }\n\n // Must have at least one digit\n if (!hasDigit) {\n return false;\n }\n\n // Validate decimal placement\n if (hasDecimal) {\n if (value.startsWith('.') || value.startsWith('-.')) {\n return false; // Decimal must have leading digit\n }\n if (value.endsWith('.')) {\n return false; // Decimal must have trailing digit\n }\n }\n\n return true;\n}\n\n/**\n * Validates if a number can be converted to Bangla words.\n *\n * The `toWords()` function supports numbers from -99,999,999,999 to 99,999,999,999\n * (just under 100 billion). This function checks if a number is within that range.\n *\n * @param input - The number to validate\n * @returns true if the number can be converted to words, false otherwise\n *\n * @example\n * ```typescript\n * isValidNumberForWords(123); // true\n * isValidNumberForWords(99999999999); // true (max supported)\n * isValidNumberForWords(100000000000); // false (too large)\n * isValidNumberForWords(-99999999999); // true\n * isValidNumberForWords(123.45); // false (decimals not supported)\n * isValidNumberForWords(NaN); // false\n * ```\n */\nexport function isValidNumberForWords(input: number): boolean {\n if (typeof input !== 'number') {\n return false;\n }\n\n if (!Number.isFinite(input)) {\n return false;\n }\n\n if (!Number.isInteger(input)) {\n return false; // toWords only supports integers\n }\n\n // toWords supports up to 99,999,999,999 (just under 100 billion)\n const MAX_SUPPORTED = 99999999999;\n const MIN_SUPPORTED = -99999999999;\n\n return input >= MIN_SUPPORTED && input <= MAX_SUPPORTED;\n}\n\n/**\n * Validates if a number can be converted to ordinal form.\n *\n * The `toOrdinal()` function only supports positive integers.\n *\n * @param input - The number to validate\n * @returns true if the number can be converted to ordinal, false otherwise\n *\n * @example\n * ```typescript\n * isValidNumberForOrdinal(1); // true\n * isValidNumberForOrdinal(100); // true\n * isValidNumberForOrdinal(0); // false\n * isValidNumberForOrdinal(-1); // false\n * isValidNumberForOrdinal(1.5); // false (decimals not supported)\n * ```\n */\nexport function isValidNumberForOrdinal(input: number): boolean {\n if (typeof input !== 'number') {\n return false;\n }\n\n if (!Number.isFinite(input)) {\n return false;\n }\n\n if (!Number.isInteger(input)) {\n return false;\n }\n\n return input > 0;\n}\n\n/**\n * Sanitizes user input for number conversion.\n *\n * This function cleans common user input issues like:\n * - Extra whitespace\n * - Comma separators (1,234 -> 1234)\n * - Leading/trailing zeros (when appropriate)\n *\n * Note: This does NOT validate the input. Use `isValidNumber()` after sanitization\n * to check if the result is valid.\n *\n * @param input - The string to sanitize\n * @returns Sanitized string\n *\n * @example\n * ```typescript\n * sanitizeNumberInput(' 123 '); // '123'\n * sanitizeNumberInput('1,234.56'); // '1234.56'\n * sanitizeNumberInput('১,২৩৪'); // '১২৩৪'\n * sanitizeNumberInput('০০১২৩'); // '০০১২৩' (preserves leading zeros)\n * ```\n */\nexport function sanitizeNumberInput(input: string): string {\n if (typeof input !== 'string') {\n return '';\n }\n\n // Trim whitespace\n let result = input.trim();\n\n // Remove comma separators (both English and Bangla)\n result = result.replace(/,/g, '');\n result = result.replace(/৳/g, ''); // Remove Taka symbol if present\n\n // Trim again after removing symbols\n return result.trim();\n}\n","import { toBanglaNumber } from './toBangla';\nimport { fromBanglaNumber } from './fromBangla';\nimport { formatNumber } from './formatNumber';\nimport { toWords } from './toWords';\nimport { sanitizeNumberInput } from './validate';\n\n/**\n * Result of a batch conversion operation.\n */\nexport interface BatchConversionResult {\n /** Successfully converted values */\n success: Array<{ input: number | string; output: string }>;\n /** Failed conversions with error messages */\n errors: Array<{ input: number | string; error: string }>;\n}\n\n/**\n * Converts multiple numbers to Bangla in a single operation.\n *\n * This function processes an array of numbers/strings and converts them to Bangla,\n * collecting both successful conversions and errors. This is useful for batch\n * processing where you want to continue even if some inputs fail.\n *\n * @param inputs - Array of numbers or strings to convert\n * @returns Object containing successful conversions and errors\n *\n * @example\n * ```typescript\n * const results = batchToBanglaNumber([123, '456', 'invalid', 789]);\n * console.log(results.success);\n * // [\n * // { input: 123, output: '১২৩' },\n * // { input: '456', output: '৪৫৬' },\n * // { input: 789, output: '৭৮৯' }\n * // ]\n * console.log(results.errors);\n * // [{ input: 'invalid', error: 'Invalid character in number: i' }]\n * ```\n */\nexport function batchToBanglaNumber(\n inputs: Array<number | string>\n): BatchConversionResult {\n const success: Array<{ input: number | string; output: string }> = [];\n const errors: Array<{ input: number | string; error: string }> = [];\n\n for (const input of inputs) {\n try {\n const output = toBanglaNumber(input);\n success.push({ input, output });\n } catch (error) {\n errors.push({\n input,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return { success, errors };\n}\n\n/**\n * Converts multiple Bangla numbers to JavaScript numbers in a single operation.\n *\n * @param inputs - Array of Bangla number strings to convert\n * @returns Object containing successful conversions and errors\n *\n * @example\n * ```typescript\n * const results = batchFromBanglaNumber(['১২৩', '৪৫৬', 'invalid']);\n * console.log(results.success);\n * // [\n * // { input: '১২৩', output: 123 },\n * // { input: '৪৫৬', output: 456 }\n * // ]\n * console.log(results.errors);\n * // [{ input: 'invalid', error: 'Invalid Bangla digit: i' }]\n * ```\n */\nexport function batchFromBanglaNumber(\n inputs: string[]\n): { success: Array<{ input: string; output: number }>; errors: Array<{ input: string; error: string }> } {\n const success: Array<{ input: string; output: number }> = [];\n const errors: Array<{ input: string; error: string }> = [];\n\n for (const input of inputs) {\n try {\n const output = fromBanglaNumber(input);\n success.push({ input, output });\n } catch (error) {\n errors.push({\n input,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return { success, errors };\n}\n\n/**\n * Safely converts a number to Bangla with a fallback value.\n *\n * This is useful in UI contexts where you want to always display something,\n * even if the conversion fails.\n *\n * @param input - The number or string to convert\n * @param fallback - Value to return if conversion fails (default: '')\n * @returns Bangla number string or fallback value\n *\n * @example\n * ```typescript\n * safeToBanglaNumber(123); // '১২৩'\n * safeToBanglaNumber(NaN, '---'); // '---'\n * safeToBanglaNumber(Infinity, 'N/A'); // 'N/A'\n * ```\n */\nexport function safeToBanglaNumber(\n input: number | string,\n fallback: string = ''\n): string {\n try {\n return toBanglaNumber(input);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely converts a Bangla number to a JavaScript number with a fallback.\n *\n * @param input - The Bangla number string to convert\n * @param fallback - Value to return if conversion fails (default: 0)\n * @returns JavaScript number or fallback value\n *\n * @example\n * ```typescript\n * safeFromBanglaNumber('১২৩'); // 123\n * safeFromBanglaNumber('invalid', -1); // -1\n * ```\n */\nexport function safeFromBanglaNumber(\n input: string,\n fallback: number = 0\n): number {\n try {\n return fromBanglaNumber(input);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Parses user input with sanitization and conversion to Bangla.\n *\n * This function combines sanitization and conversion in a single step,\n * making it ideal for processing form inputs or user-entered data.\n *\n * @param input - The user input string to parse\n * @returns Bangla number string\n * @throws Error if the sanitized input is invalid\n *\n * @example\n * ```typescript\n * parseAndConvertToBangla(' 1,234.56 '); // '১২৩৪.৫৬'\n * parseAndConvertToBangla('৳ 1,000'); // '১০০০'\n * parseAndConvertToBangla('invalid'); // throws Error\n * ```\n */\nexport function parseAndConvertToBangla(input: string): string {\n const sanitized = sanitizeNumberInput(input);\n return toBanglaNumber(sanitized);\n}\n\n/**\n * Formats a number with comma separators and optionally converts to Bangla.\n *\n * This is a convenience function that combines formatting and digit conversion.\n *\n * @param input - The number to format\n * @param useBanglaDigits - Whether to use Bangla digits (default: true)\n * @param separator - Separator character (default: ',')\n * @returns Formatted number string\n *\n * @example\n * ```typescript\n * formatAndConvert(1234567); // '১২,৩৪,৫৬৭'\n * formatAndConvert(1234567, false); // '12,34,567'\n * formatAndConvert(1234567, true, ' '); // '১২ ৩৪ ৫৬৭'\n * ```\n */\nexport function formatAndConvert(\n input: number,\n useBanglaDigits: boolean = true,\n separator: string = ','\n): string {\n return formatNumber(input, { useBanglaDigits, separator });\n}\n\n/**\n * Converts a number to its word representation and also provides the Bangla digit form.\n *\n * This is useful when you want to display both forms, such as on checks or invoices.\n *\n * @param input - The number to convert\n * @returns Object with both word and digit representations\n *\n * @example\n * ```typescript\n * const result = convertToWordsAndDigits(123);\n * console.log(result.words); // 'এক শত তেইশ'\n * console.log(result.digits); // '১২৩'\n *\n * // Useful for invoices:\n * const amount = convertToWordsAndDigits(1500);\n * console.log(`Amount: ${amount.digits} (${amount.words} টাকা)`);\n * // Amount: ১৫০০ (এক হাজার পাঁচ শত টাকা)\n * ```\n */\nexport function convertToWordsAndDigits(input: number): {\n words: string;\n digits: string;\n} {\n return {\n words: toWords(input),\n digits: toBanglaNumber(input),\n };\n}\n\n/**\n * Range validation: checks if a number is within a specified range.\n *\n * This is useful for form validation or business logic where numbers\n * must fall within certain bounds.\n *\n * @param value - The number to check\n * @param min - Minimum allowed value (inclusive)\n * @param max - Maximum allowed value (inclusive)\n * @returns true if value is within range, false otherwise\n *\n * @example\n * ```typescript\n * isNumberInRange(50, 0, 100); // true\n * isNumberInRange(150, 0, 100); // false\n * isNumberInRange(-5, 0, 100); // false\n * ```\n */\nexport function isNumberInRange(value: number, min: number, max: number): boolean {\n if (!Number.isFinite(value)) {\n return false;\n }\n return value >= min && value <= max;\n}\n\n/**\n * Truncates a number to a specified number of decimal places without rounding.\n *\n * Unlike toFixed(), this function truncates rather than rounds.\n *\n * @param value - The number to truncate\n * @param decimals - Number of decimal places to keep (default: 2)\n * @returns Truncated number\n *\n * @example\n * ```typescript\n * truncateDecimals(123.456789, 2); // 123.45\n * truncateDecimals(123.999, 1); // 123.9 (not 124.0)\n * truncateDecimals(100, 2); // 100\n * ```\n */\nexport function truncateDecimals(value: number, decimals: number = 2): number {\n const multiplier = Math.pow(10, decimals);\n return Math.trunc(value * multiplier) / multiplier;\n}\n","import { toBanglaNumber } from '../number';\n\n/**\n * Formats a number as Bangladeshi Taka currency in Bangla.\n *\n * This function converts numeric currency amounts to Bengali format with\n * the Taka symbol (৳) and/or word (টাকা). Amounts are automatically formatted\n * to 2 decimal places.\n *\n * **Currency Symbol:** ৳ (Taka sign)\n * **Currency Word:** টাকা (Taka)\n *\n * @param amount - The amount to format (number or string)\n * @param options - Formatting options\n * @param options.includeSymbol - Include the ৳ symbol (default: true)\n * @param options.includeWord - Include the word \"টাকা\" (default: false)\n * @returns Formatted currency string in Bangla\n * @throws {Error} If amount is NaN or cannot be parsed\n *\n * @example\n * Basic formatting with symbol (default):\n * ```typescript\n * formatCurrency(1234.56);\n * // '৳ ১২৩৪.৫৬'\n *\n * formatCurrency(100);\n * // '৳ ১০০.০০'\n *\n * formatCurrency('999.99');\n * // '৳ ৯৯৯.৯৯'\n * ```\n *\n * @example\n * Without symbol:\n * ```typescript\n * formatCurrency(1234.56, { includeSymbol: false });\n * // '১২৩৪.৫৬'\n *\n * formatCurrency(500, { includeSymbol: false });\n * // '৫০০.০০'\n * ```\n *\n * @example\n * With word \"টাকা\":\n * ```typescript\n * formatCurrency(100, { includeWord: true });\n * // '৳ ১০০.০০ টাকা'\n *\n * formatCurrency(1000, { includeWord: true });\n * // '৳ ১০০০.০০ টাকা'\n *\n * formatCurrency(50, { includeSymbol: false, includeWord: true });\n * // '৫০.০০ টাকা'\n * ```\n *\n * @example\n * Large amounts:\n * ```typescript\n * formatCurrency(1000000);\n * // '৳ ১০০০০০০.০০'\n *\n * formatCurrency(50000000, { includeWord: true });\n * // '৳ ৫০০০০০০০.০০ টাকা'\n * ```\n *\n * @example\n * Small and zero amounts:\n * ```typescript\n * formatCurrency(0);\n * // '৳ ০.০০'\n *\n * formatCurrency(0.5);\n * // '৳ ০.৫০'\n *\n * formatCurrency(0.01);\n * // '৳ ০.০১'\n * ```\n *\n * @example\n * Negative amounts (debits):\n * ```typescript\n * formatCurrency(-100);\n * // '৳ -১০০.০০'\n *\n * formatCurrency(-1234.56, { includeWord: true });\n * // '৳ -১২৩৪.৫৬ টাকা'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * formatCurrency('invalid');\n * // throws Error: Invalid amount\n *\n * formatCurrency(NaN);\n * // throws Error: Invalid amount\n * ```\n */\nexport function formatCurrency(\n amount: number | string,\n options: {\n includeSymbol?: boolean;\n includeWord?: boolean;\n } = {}\n): string {\n const { includeSymbol = true, includeWord = false } = options;\n const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;\n\n if (Number.isNaN(numAmount)) {\n throw new Error('Invalid amount');\n }\n\n const banglaAmount = toBanglaNumber(numAmount.toFixed(2));\n const parts: string[] = [];\n\n if (includeSymbol) {\n parts.push('৳');\n }\n\n parts.push(banglaAmount);\n\n if (includeWord) {\n parts.push('টাকা');\n }\n\n return parts.join(' ');\n}\n\n","import { fromBanglaNumber } from '../number';\n\n/**\n * Parses a Bangla currency string to a number.\n *\n * This function extracts numeric values from Bengali currency strings,\n * automatically removing currency symbols (৳) and words (টাকা).\n * It supports various formatting styles commonly used in Bangladesh.\n *\n * **Recognized Elements:**\n * - Currency symbol: ৳\n * - Currency word: টাকা\n * - Bangla digits: ০-৯\n *\n * @param currencyString - The currency string to parse\n * @returns The numeric amount as a JavaScript number\n *\n * @example\n * With symbol:\n * ```typescript\n * parseCurrency('৳ ১২৩৪.৫৬');\n * // 1234.56\n *\n * parseCurrency('৳১০০');\n * // 100\n *\n * parseCurrency('৳ ১০০.৫০');\n * // 100.5\n * ```\n *\n * @example\n * With word \"টাকা\":\n * ```typescript\n * parseCurrency('১০০.০০ টাকা');\n * // 100\n *\n * parseCurrency('১০০ টাকা');\n * // 100\n *\n * parseCurrency('৫০০ টাকা');\n * // 500\n * ```\n *\n * @example\n * With both symbol and word:\n * ```typescript\n * parseCurrency('৳ ১০০.০০ টাকা');\n * // 100\n *\n * parseCurrency('৳ ৫০০ টাকা');\n * // 500\n * ```\n *\n * @example\n * Without symbol or word (plain Bangla numbers):\n * ```typescript\n * parseCurrency('১০০');\n * // 100\n *\n * parseCurrency('১২৩৪.৫৬');\n * // 1234.56\n *\n * parseCurrency('৫০০');\n * // 500\n * ```\n *\n * @example\n * With whitespace and formatting:\n * ```typescript\n * parseCurrency(' ৳ ১০০ ');\n * // 100\n *\n * parseCurrency('৳ ১০০.৫০ টাকা');\n * // 100.5\n * ```\n *\n * @example\n * Large amounts:\n * ```typescript\n * parseCurrency('৳ ১০০০০০০.০০');\n * // 1000000\n *\n * parseCurrency('৫০০০০০০০ টাকা');\n * // 50000000\n * ```\n *\n * @example\n * Negative amounts:\n * ```typescript\n * parseCurrency('৳ -১০০.০০');\n * // -100\n *\n * parseCurrency('-৫০০ টাকা');\n * // -500\n * ```\n */\nexport function parseCurrency(currencyString: string): number {\n // Remove currency symbols and words\n let cleaned = currencyString\n .replace(/৳/g, '')\n .replace(/টাকা/g, '')\n .trim();\n\n // Remove any extra whitespace\n cleaned = cleaned.replace(/\\s+/g, '');\n\n return fromBanglaNumber(cleaned);\n}\n\n","/**\n * Checks if a value is a valid currency amount.\n *\n * Valid currency amounts must be finite numbers (can be negative for debits).\n *\n * @param value - The value to check\n * @returns true if the value is a valid currency amount\n *\n * @example\n * ```typescript\n * isValidCurrency(100); // true\n * isValidCurrency(1234.56); // true\n * isValidCurrency(-50); // true (negative amounts allowed)\n * isValidCurrency(0); // true\n * isValidCurrency(NaN); // false\n * isValidCurrency(Infinity); // false\n * isValidCurrency('100' as any); // false\n * ```\n */\nexport function isValidCurrency(value: number): boolean {\n return typeof value === 'number' && !isNaN(value) && isFinite(value);\n}\n\n/**\n * Checks if a string appears to be a Bangla currency format.\n *\n * This function checks if the string contains the Taka symbol (৳)\n * or the word \"টাকা\", or contains Bangla digits.\n *\n * @param value - The string to check\n * @returns true if the string appears to be Bangla currency\n *\n * @example\n * ```typescript\n * isBanglaCurrency('৳ ১২৩৪.৫৬'); // true\n * isBanglaCurrency('১০০ টাকা'); // true\n * isBanglaCurrency('৳১২৩৪'); // true\n * isBanglaCurrency('১২৩৪.৫৬'); // true (has Bangla digits)\n * isBanglaCurrency('1234.56'); // false\n * isBanglaCurrency('hello'); // false\n * ```\n */\nexport function isBanglaCurrency(value: string): boolean {\n if (typeof value !== 'string' || !value.trim()) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Check for currency symbol or word\n if (trimmed.includes('৳') || trimmed.includes('টাকা')) {\n return true;\n }\n\n // Check for Bangla digits\n const banglaDigitPattern = /[০-৯]/;\n return banglaDigitPattern.test(trimmed);\n}\n\n/**\n * Checks if a currency amount is positive (greater than 0).\n *\n * @param value - The currency amount to check\n * @returns true if the amount is positive\n *\n * @example\n * ```typescript\n * isPositiveAmount(100); // true\n * isPositiveAmount(0.01); // true\n * isPositiveAmount(0); // false\n * isPositiveAmount(-50); // false\n * ```\n */\nexport function isPositiveAmount(value: number): boolean {\n return isValidCurrency(value) && value > 0;\n}\n\n/**\n * Checks if a currency amount is negative (less than 0).\n *\n * @param value - The currency amount to check\n * @returns true if the amount is negative\n *\n * @example\n * ```typescript\n * isNegativeAmount(-100); // true\n * isNegativeAmount(-0.01); // true\n * isNegativeAmount(0); // false\n * isNegativeAmount(50); // false\n * ```\n */\nexport function isNegativeAmount(value: number): boolean {\n return isValidCurrency(value) && value < 0;\n}\n\n/**\n * Checks if a currency amount is zero.\n *\n * @param value - The currency amount to check\n * @returns true if the amount is exactly zero\n *\n * @example\n * ```typescript\n * isZeroAmount(0); // true\n * isZeroAmount(-0); // true\n * isZeroAmount(0.00); // true\n * isZeroAmount(0.01); // false\n * isZeroAmount(100); // false\n * ```\n */\nexport function isZeroAmount(value: number): boolean {\n return isValidCurrency(value) && value === 0;\n}\n\n/**\n * Sanitizes currency input to ensure it's a valid number.\n *\n * This function:\n * - Converts string numbers to floats\n * - Removes common currency symbols and whitespace from strings\n * - Returns null for invalid inputs\n *\n * @param value - The input value to sanitize\n * @returns Sanitized number or null if invalid\n *\n * @example\n * ```typescript\n * sanitizeCurrencyInput('1234.56'); // 1234.56\n * sanitizeCurrencyInput('৳ 100'); // '৳ 100' (as string, needs parseCurrency)\n * sanitizeCurrencyInput(500); // 500\n * sanitizeCurrencyInput('invalid'); // null\n * sanitizeCurrencyInput(NaN); // null\n * ```\n */\nexport function sanitizeCurrencyInput(value: any): number | string | null {\n // Handle number input\n if (typeof value === 'number') {\n if (isNaN(value) || !isFinite(value)) {\n return null;\n }\n return value;\n }\n\n // Handle string input\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') {\n return null;\n }\n\n // If it contains Bangla currency symbols/digits, return as-is for parseCurrency\n if (isBanglaCurrency(trimmed)) {\n return trimmed;\n }\n\n // Try to parse as regular number\n const parsed = parseFloat(trimmed);\n if (isNaN(parsed)) {\n return null;\n }\n return parsed;\n }\n\n return null;\n}\n\n/**\n * Checks if a currency amount is within a valid range.\n *\n * @param value - The currency amount to check\n * @param min - Minimum value (inclusive)\n * @param max - Maximum value (inclusive)\n * @returns true if the amount is within the range\n *\n * @example\n * ```typescript\n * isCurrencyInRange(50, 0, 100); // true\n * isCurrencyInRange(100, 0, 100); // true\n * isCurrencyInRange(150, 0, 100); // false\n * isCurrencyInRange(-50, 0, 100); // false\n * ```\n */\nexport function isCurrencyInRange(value: number, min: number, max: number): boolean {\n if (!isValidCurrency(value) || !isValidCurrency(min) || !isValidCurrency(max)) {\n return false;\n }\n\n if (min > max) {\n return false;\n }\n\n return value >= min && value <= max;\n}\n\n/**\n * Checks if a currency string has the Taka symbol (৳).\n *\n * @param value - The currency string to check\n * @returns true if the string contains ৳\n *\n * @example\n * ```typescript\n * hasTakaSymbol('৳ ১০০'); // true\n * hasTakaSymbol('৳১০০'); // true\n * hasTakaSymbol('১০০ টাকা'); // false\n * hasTakaSymbol('100'); // false\n * ```\n */\nexport function hasTakaSymbol(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n return value.includes('৳');\n}\n\n/**\n * Checks if a currency string has the word \"টাকা\".\n *\n * @param value - The currency string to check\n * @returns true if the string contains টাকা\n *\n * @example\n * ```typescript\n * hasTakaWord('১০০ টাকা'); // true\n * hasTakaWord('৳ ১০০ টাকা'); // true\n * hasTakaWord('৳ ১০০'); // false\n * hasTakaWord('100'); // false\n * ```\n */\nexport function hasTakaWord(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n return value.includes('টাকা');\n}\n","import { formatCurrency } from './formatCurrency';\nimport { parseCurrency } from './parseCurrency';\nimport { isValidCurrency, sanitizeCurrencyInput } from './validate';\n\n/**\n * Safely formats a currency amount with a fallback value.\n *\n * Unlike formatCurrency, this function doesn't throw errors for invalid inputs.\n * Instead, it returns the fallback value.\n *\n * @param amount - The amount to format\n * @param options - Formatting options\n * @param fallback - Value to return if formatting fails (default: '')\n * @returns Formatted currency string or fallback value\n *\n * @example\n * ```typescript\n * safeFormatCurrency(1234.56); // '৳ ১২৩৪.৫৬'\n * safeFormatCurrency(NaN); // ''\n * safeFormatCurrency(Infinity, {}, 'N/A'); // 'N/A'\n * safeFormatCurrency(100, { includeWord: true }); // '৳ ১০০.০০ টাকা'\n * ```\n */\nexport function safeFormatCurrency(\n amount: number | string,\n options: {\n includeSymbol?: boolean;\n includeWord?: boolean;\n } = {},\n fallback: string = ''\n): string {\n try {\n const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;\n if (!isValidCurrency(numAmount)) {\n return fallback;\n }\n return formatCurrency(amount, options);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely parses a currency string with a fallback value.\n *\n * @param currencyString - The currency string to parse\n * @param fallback - Value to return if parsing fails (default: 0)\n * @returns Parsed amount or fallback value\n *\n * @example\n * ```typescript\n * safeParseCurrency('৳ ১২৩৪.৫৬'); // 1234.56\n * safeParseCurrency('invalid'); // 0\n * safeParseCurrency('invalid', -1); // -1\n * ```\n */\nexport function safeParseCurrency(currencyString: string, fallback: number = 0): number {\n try {\n const result = parseCurrency(currencyString);\n if (!isValidCurrency(result)) {\n return fallback;\n }\n return result;\n } catch {\n return fallback;\n }\n}\n\n/**\n * Formats an array of currency amounts.\n *\n * @param amounts - Array of amounts to format\n * @param options - Formatting options\n * @returns Array of formatted currency strings (invalid amounts are skipped)\n *\n * @example\n * ```typescript\n * batchFormatCurrency([100, 200, 300]);\n * // ['৳ ১০০.০০', '৳ ২০০.০০', '৳ ৩০০.০০']\n *\n * batchFormatCurrency([100, NaN, 200], { includeWord: true });\n * // ['৳ ১০০.০০ টাকা', '৳ ২০০.০০ টাকা']\n * ```\n */\nexport function batchFormatCurrency(\n amounts: number[],\n options: {\n includeSymbol?: boolean;\n includeWord?: boolean;\n } = {}\n): string[] {\n return amounts\n .filter(amount => isValidCurrency(amount))\n .map(amount => formatCurrency(amount, options));\n}\n\n/**\n * Rounds a currency amount to a specified number of decimal places.\n *\n * @param amount - The amount to round\n * @param decimals - Number of decimal places (default: 2)\n * @returns Rounded amount\n *\n * @example\n * ```typescript\n * roundCurrency(123.456); // 123.46\n * roundCurrency(123.454); // 123.45\n * roundCurrency(123.456, 1); // 123.5\n * roundCurrency(123, 2); // 123.00\n * ```\n */\nexport function roundCurrency(amount: number, decimals: number = 2): number {\n if (!isValidCurrency(amount)) {\n throw new Error('Invalid currency amount');\n }\n\n const multiplier = Math.pow(10, decimals);\n return Math.round(amount * multiplier) / multiplier;\n}\n\n/**\n * Calculates the sum of multiple currency amounts.\n *\n * @param amounts - Array of amounts to sum\n * @returns Total sum rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * sumCurrency([100, 200, 300]); // 600\n * sumCurrency([123.45, 67.89]); // 191.34\n * sumCurrency([10.1, 20.2, 30.3]); // 60.6\n * ```\n */\nexport function sumCurrency(amounts: number[]): number {\n const validAmounts = amounts.filter(amount => isValidCurrency(amount));\n const sum = validAmounts.reduce((acc, amount) => acc + amount, 0);\n return roundCurrency(sum, 2);\n}\n\n/**\n * Calculates the difference between two currency amounts.\n *\n * @param amount1 - First amount\n * @param amount2 - Second amount\n * @returns Difference (amount1 - amount2) rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * subtractCurrency(200, 100); // 100\n * subtractCurrency(150.75, 50.25); // 100.50\n * subtractCurrency(100, 200); // -100\n * ```\n */\nexport function subtractCurrency(amount1: number, amount2: number): number {\n if (!isValidCurrency(amount1) || !isValidCurrency(amount2)) {\n throw new Error('Invalid currency amounts');\n }\n\n return roundCurrency(amount1 - amount2, 2);\n}\n\n/**\n * Multiplies a currency amount by a factor.\n *\n * @param amount - The amount to multiply\n * @param factor - Multiplication factor\n * @returns Product rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * multiplyCurrency(100, 2); // 200\n * multiplyCurrency(123.45, 1.5); // 185.18\n * multiplyCurrency(99.99, 0.5); // 50.00\n * ```\n */\nexport function multiplyCurrency(amount: number, factor: number): number {\n if (!isValidCurrency(amount) || !isValidCurrency(factor)) {\n throw new Error('Invalid currency amount or factor');\n }\n\n return roundCurrency(amount * factor, 2);\n}\n\n/**\n * Divides a currency amount by a divisor.\n *\n * @param amount - The amount to divide\n * @param divisor - Division divisor (must not be zero)\n * @returns Quotient rounded to 2 decimal places\n * @throws {Error} If divisor is zero\n *\n * @example\n * ```typescript\n * divideCurrency(200, 2); // 100\n * divideCurrency(100, 3); // 33.33\n * divideCurrency(150, 4); // 37.50\n * divideCurrency(100, 0); // throws Error\n * ```\n */\nexport function divideCurrency(amount: number, divisor: number): number {\n if (!isValidCurrency(amount) || !isValidCurrency(divisor)) {\n throw new Error('Invalid currency amount or divisor');\n }\n\n if (divisor === 0) {\n throw new Error('Cannot divide by zero');\n }\n\n return roundCurrency(amount / divisor, 2);\n}\n\n/**\n * Calculates a percentage of a currency amount.\n *\n * @param amount - The base amount\n * @param percentage - Percentage (e.g., 15 for 15%)\n * @returns Calculated percentage amount rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * calculatePercentage(1000, 15); // 150 (15% of 1000)\n * calculatePercentage(200, 10); // 20 (10% of 200)\n * calculatePercentage(99.99, 5); // 5.00 (5% of 99.99)\n * ```\n */\nexport function calculatePercentage(amount: number, percentage: number): number {\n if (!isValidCurrency(amount) || !isValidCurrency(percentage)) {\n throw new Error('Invalid currency amount or percentage');\n }\n\n return roundCurrency((amount * percentage) / 100, 2);\n}\n\n/**\n * Applies a discount percentage to a currency amount.\n *\n * @param amount - The original amount\n * @param discountPercent - Discount percentage (e.g., 10 for 10% off)\n * @returns Amount after discount rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * applyDiscount(1000, 10); // 900 (10% off)\n * applyDiscount(500, 25); // 375 (25% off)\n * applyDiscount(199.99, 15); // 169.99 (15% off)\n * ```\n */\nexport function applyDiscount(amount: number, discountPercent: number): number {\n const discount = calculatePercentage(amount, discountPercent);\n return subtractCurrency(amount, discount);\n}\n\n/**\n * Adds tax percentage to a currency amount.\n *\n * @param amount - The base amount\n * @param taxPercent - Tax percentage (e.g., 15 for 15% tax)\n * @returns Amount after tax rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * addTax(1000, 15); // 1150 (15% VAT)\n * addTax(500, 10); // 550 (10% tax)\n * addTax(99.99, 5); // 104.99 (5% tax)\n * ```\n */\nexport function addTax(amount: number, taxPercent: number): number {\n const tax = calculatePercentage(amount, taxPercent);\n return roundCurrency(amount + tax, 2);\n}\n\n/**\n * Splits a currency amount into equal parts.\n *\n * @param amount - The total amount to split\n * @param parts - Number of parts to split into\n * @returns Array of split amounts (last part may differ slightly due to rounding)\n *\n * @example\n * ```typescript\n * splitAmount(100, 3); // [33.33, 33.33, 33.34]\n * splitAmount(150, 2); // [75.00, 75.00]\n * splitAmount(10, 4); // [2.50, 2.50, 2.50, 2.50]\n * ```\n */\nexport function splitAmount(amount: number, parts: number): number[] {\n if (!isValidCurrency(amount)) {\n throw new Error('Invalid currency amount');\n }\n\n if (!Number.isInteger(parts) || parts < 1) {\n throw new Error('Parts must be a positive integer');\n }\n\n const perPart = divideCurrency(amount, parts);\n const result: number[] = Array(parts - 1).fill(perPart);\n\n // Calculate the last part to ensure sum equals original amount\n const sumSoFar = sumCurrency(result);\n const lastPart = subtractCurrency(amount, sumSoFar);\n\n result.push(lastPart);\n return result;\n}\n\n/**\n * Compares two currency amounts.\n *\n * @param amount1 - First amount\n * @param amount2 - Second amount\n * @returns -1 if amount1 < amount2, 0 if equal, 1 if amount1 > amount2\n *\n * @example\n * ```typescript\n * compareCurrency(100, 200); // -1\n * compareCurrency(200, 100); // 1\n * compareCurrency(100, 100); // 0\n * compareCurrency(100.001, 100.002); // -1\n * ```\n */\nexport function compareCurrency(amount1: number, amount2: number): number {\n if (!isValidCurrency(amount1) || !isValidCurrency(amount2)) {\n throw new Error('Invalid currency amounts');\n }\n\n const rounded1 = roundCurrency(amount1, 2);\n const rounded2 = roundCurrency(amount2, 2);\n\n if (rounded1 < rounded2) return -1;\n if (rounded1 > rounded2) return 1;\n return 0;\n}\n\n/**\n * Gets the absolute value of a currency amount.\n *\n * @param amount - The amount\n * @returns Absolute value\n *\n * @example\n * ```typescript\n * getAbsoluteAmount(-100); // 100\n * getAbsoluteAmount(100); // 100\n * getAbsoluteAmount(-50.75); // 50.75\n * ```\n */\nexport function getAbsoluteAmount(amount: number): number {\n if (!isValidCurrency(amount)) {\n throw new Error('Invalid currency amount');\n }\n\n return Math.abs(amount);\n}\n\n/**\n * Converts between positive and negative amounts.\n *\n * @param amount - The amount to negate\n * @returns Negated amount\n *\n * @example\n * ```typescript\n * negateAmount(100); // -100\n * negateAmount(-100); // 100\n * negateAmount(0); // 0\n * ```\n */\nexport function negateAmount(amount: number): number {\n if (!isValidCurrency(amount)) {\n throw new Error('Invalid currency amount');\n }\n\n return -amount;\n}\n\n/**\n * Parses and formats currency in one step.\n *\n * This combines sanitization, validation, and formatting.\n *\n * @param value - Input value (number, string, or currency string)\n * @param options - Formatting options\n * @returns Formatted currency string\n * @throws {Error} If value cannot be parsed as valid currency\n *\n * @example\n * ```typescript\n * parseAndFormatCurrency('1234.56'); // '৳ ১২৩৪.৫৬'\n * parseAndFormatCurrency(' 500 ', { includeWord: true }); // '৳ ৫০০.০০ টাকা'\n * parseAndFormatCurrency(100); // '৳ ১০০.০০'\n * parseAndFormatCurrency('invalid'); // throws Error\n * ```\n */\nexport function parseAndFormatCurrency(\n value: any,\n options: {\n includeSymbol?: boolean;\n includeWord?: boolean;\n } = {}\n): string {\n const sanitized = sanitizeCurrencyInput(value);\n\n if (sanitized === null) {\n throw new Error('Invalid currency input');\n }\n\n // If sanitized is a string (Bangla currency), parse it first\n if (typeof sanitized === 'string') {\n const parsed = parseCurrency(sanitized);\n return formatCurrency(parsed, options);\n }\n\n // Otherwise it's already a number\n return formatCurrency(sanitized, options);\n}\n","import { BANGLA_MONTHS } from '../constants';\n\n/**\n * Converts a month number (1-12) to Bangla month name.\n *\n * This function maps standard month numbers to Bengali calendar month names.\n * The Bengali calendar has 12 months, each with its traditional name.\n *\n * **Month Mapping:**\n * 1. বৈশাখ (Boishakh)\n * 2. জ্যৈষ্ঠ (Jyoishtho)\n * 3. আষাঢ় (Asharh)\n * 4. শ্রাবণ (Srabon)\n * 5. ভাদ্র (Bhadro)\n * 6. আশ্বিন (Ashwin)\n * 7. কার্তিক (Kartik)\n * 8. অগ্রহায়ণ (Ogrohayon)\n * 9. পৌষ (Poush)\n * 10. মাঘ (Magh)\n * 11. ফাল্গুন (Falgun)\n * 12. চৈত্র (Choitro)\n *\n * @param monthNumber - Month number (1-12)\n * @returns Bangla month name\n * @throws {Error} If month number is not between 1 and 12\n *\n * @example\n * First three months:\n * ```typescript\n * toBanglaMonth(1); // 'বৈশাখ'\n * toBanglaMonth(2); // 'জ্যৈষ্ঠ'\n * toBanglaMonth(3); // 'আষাঢ়'\n * ```\n *\n * @example\n * Mid-year months:\n * ```typescript\n * toBanglaMonth(6); // 'আশ্বিন'\n * toBanglaMonth(7); // 'কার্তিক'\n * toBanglaMonth(8); // 'অগ্রহায়ণ'\n * ```\n *\n * @example\n * Last month:\n * ```typescript\n * toBanglaMonth(12); // 'চৈত্র'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * toBanglaMonth(0); // throws Error: Month number must be between 1 and 12\n * toBanglaMonth(13); // throws Error: Month number must be between 1 and 12\n * toBanglaMonth(-1); // throws Error: Month number must be between 1 and 12\n * ```\n *\n * @example\n * Practical usage (dropdown options):\n * ```typescript\n * const months = Array.from({ length: 12 }, (_, i) => ({\n * value: i + 1,\n * label: toBanglaMonth(i + 1)\n * }));\n * // [{ value: 1, label: 'বৈশাখ' }, { value: 2, label: 'জ্যৈষ্ঠ' }, ...]\n * ```\n */\nexport function toBanglaMonth(monthNumber: number): string {\n if (monthNumber < 1 || monthNumber > 12) {\n throw new Error('Month number must be between 1 and 12');\n }\n\n return BANGLA_MONTHS[monthNumber - 1];\n}\n\n","import { BANGLA_MONTHS } from '../constants';\n\n/**\n * Converts a Bangla month name to month number (1-12).\n *\n * This function performs the reverse operation of toBanglaMonth,\n * converting Bengali month names to their numeric equivalents.\n *\n * **Valid Month Names:**\n * - বৈশাখ → 1\n * - জ্যৈষ্ঠ → 2\n * - আষাঢ় → 3\n * - শ্রাবণ → 4\n * - ভাদ্র → 5\n * - আশ্বিন → 6\n * - কার্তিক → 7\n * - অগ্রহায়ণ → 8\n * - পৌষ → 9\n * - মাঘ → 10\n * - ফাল্গুন → 11\n * - চৈত্র → 12\n *\n * @param monthName - Bangla month name\n * @returns Month number (1-12)\n * @throws {Error} If month name is not a valid Bangla month\n *\n * @example\n * First quarter months:\n * ```typescript\n * fromBanglaMonth('বৈশাখ'); // 1\n * fromBanglaMonth('জ্যৈষ্ঠ'); // 2\n * fromBanglaMonth('আষাঢ়'); // 3\n * ```\n *\n * @example\n * Mid-year months:\n * ```typescript\n * fromBanglaMonth('আশ্বিন'); // 6\n * fromBanglaMonth('কার্তিক'); // 7\n * fromBanglaMonth('অগ্রহায়ণ'); // 8\n * ```\n *\n * @example\n * Last month:\n * ```typescript\n * fromBanglaMonth('চৈত্র'); // 12\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * fromBanglaMonth('invalid');\n * // throws Error: Invalid Bangla month name: invalid\n *\n * fromBanglaMonth('January');\n * // throws Error: Invalid Bangla month name: January\n * ```\n *\n * @example\n * Practical usage (form parsing):\n * ```typescript\n * const userInput = 'পৌষ';\n * const monthNumber = fromBanglaMonth(userInput); // 9\n *\n * // Use with Date object\n * const date = new Date(2024, monthNumber - 1, 15);\n * ```\n */\nexport function fromBanglaMonth(monthName: string): number {\n const index = BANGLA_MONTHS.indexOf(monthName as any);\n\n if (index === -1) {\n throw new Error(`Invalid Bangla month name: ${monthName}`);\n }\n\n return index + 1;\n}\n\n","import { toBanglaMonth } from './toBanglaMonth';\n\n/**\n * Gets the Bangla month name from a Date object.\n *\n * This function extracts the month from a JavaScript Date object and\n * converts it to the corresponding Bangla month name. Note that this\n * uses a direct 1:1 mapping (JS month + 1 = Bangla month number).\n *\n * **Note:** This is a simplified mapping. For accurate Bengali calendar\n * conversions, use the calendar module which accounts for Bengali new year\n * and proper date calculations.\n *\n * @param date - Date object\n * @returns Bangla month name\n *\n * @example\n * Getting month name from current date:\n * ```typescript\n * const today = new Date();\n * const monthName = getMonthName(today);\n * console.log(`Current month: ${monthName}`);\n * ```\n *\n * @example\n * Getting month name from specific dates:\n * ```typescript\n * const jan = new Date(2024, 0, 15); // January\n * getMonthName(jan); // 'বৈশাখ'\n *\n * const june = new Date(2024, 5, 15); // June\n * getMonthName(june); // 'আশ্বিন'\n *\n * const dec = new Date(2024, 11, 31); // December\n * getMonthName(dec); // 'চৈত্র'\n * ```\n *\n * @example\n * Practical usage (display):\n * ```typescript\n * const appointment = new Date(2024, 3, 20);\n * const monthName = getMonthName(appointment);\n * console.log(`Appointment in ${monthName}`); // 'Appointment in শ্রাবণ'\n * ```\n */\nexport function getMonthName(date: Date): string {\n // JavaScript months are 0-indexed (0-11), Bangla months are 1-indexed (1-12)\n // We need to convert: JS month 0 (Jan) = Bangla month 10 (পৌষ), etc.\n // This is a simplified mapping - actual conversion would need Bengali calendar logic\n // For now, we'll use a direct 1:1 mapping where JS month + 1 = Bangla month\n // Note: This is a placeholder - proper implementation would require Bengali calendar conversion\n const jsMonth = date.getMonth() + 1;\n return toBanglaMonth(jsMonth);\n}\n\n","/**\n * Validation utilities for date formatting and parsing operations.\n *\n * This module provides validation functions for Date objects and date strings\n * used in Bangla date formatting and parsing.\n *\n * @module date/validate\n */\n\n/**\n * Checks if a value is a valid Date object.\n *\n * A valid Date object must be an instance of Date and not represent\n * an Invalid Date (i.e., created from invalid input like new Date('invalid')).\n *\n * @param date - Value to validate\n * @returns true if valid Date object, false otherwise\n *\n * @example\n * Valid dates:\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate(new Date(2024, 0, 15)); // true\n * isValidDate(new Date('2024-01-15')); // true\n * ```\n *\n * @example\n * Invalid dates:\n * ```typescript\n * isValidDate(new Date('invalid')); // false\n * isValidDate(new Date('not-a-date')); // false\n * isValidDate('2024-01-15' as any); // false (string, not Date)\n * isValidDate(1705276800000 as any); // false (timestamp, not Date)\n * isValidDate(null as any); // false\n * ```\n */\nexport function isValidDate(date: Date): boolean {\n return date instanceof Date && !isNaN(date.getTime());\n}\n\n/**\n * Checks if a string is a valid Bengali date format.\n *\n * Valid formats include:\n * - \"১৫ বৈশাখ ১৪৩১\" (with Bengali digits and month name)\n * - \"১৫ বৈশাখ\" (without year)\n * - \"15 বৈশাখ 1431\" (with English digits and month name)\n * - \"১৫/০৪/২০২৪\" or \"১৫-০৪-২০২৪\" (Bengali digits with separators)\n * - \"15/04/2024\" or \"15-04-2024\" (English digits with separators)\n *\n * @param dateString - String to validate\n * @returns true if string matches a valid Bengali date format, false otherwise\n *\n * @example\n * Valid formats:\n * ```typescript\n * isValidBengaliDateString('১৫ বৈশাখ ১৪৩১'); // true\n * isValidBengaliDateString('১৫ বৈশাখ'); // true\n * isValidBengaliDateString('15 বৈশাখ 1431'); // true\n * isValidBengaliDateString('১৫/০৪/২০২৪'); // true\n * isValidBengaliDateString('15-04-2024'); // true\n * ```\n *\n * @example\n * Invalid formats:\n * ```typescript\n * isValidBengaliDateString('invalid'); // false\n * isValidBengaliDateString('2024-01-15'); // false (ISO format not supported)\n * isValidBengaliDateString(''); // false\n * isValidBengaliDateString(' '); // false\n * ```\n */\nexport function isValidBengaliDateString(dateString: string): boolean {\n if (typeof dateString !== 'string' || dateString.trim() === '') {\n return false;\n }\n\n const cleaned = dateString.trim().replace(/\\s+/g, ' ');\n\n // Reject ISO format (YYYY-MM-DD or YYYY/MM/DD)\n if (/^\\d{4}[\\-\\/]\\d{1,2}[\\-\\/]\\d{1,2}$/.test(cleaned)) {\n return false;\n }\n\n // Format: \"১৫ বৈশাখ ১৪৩১\" or \"১৫ বৈশাখ\" or \"15 বৈশাখ 1431\"\n const monthNamePattern =\n /^(\\d+|[০-৯]+)\\s+(বৈশাখ|জ্যৈষ্ঠ|আষাঢ়|শ্রাবণ|ভাদ্র|আশ্বিন|কার্তিক|অগ্রহায়ণ|পৌষ|মাঘ|ফাল্গুন|চৈত্র)(?:\\s+(\\d+|[০-৯]+))?$/;\n\n // Format: \"১৫/০৪/২০২৪\" or \"১৫-০৪-২০২৪\" or \"15/04/2024\" or \"15-04-2024\" (DD/MM/YYYY)\n const separatorPattern = /^(\\d{1,2}|[০-৯]{1,2})[\\/\\-](\\d{1,2}|[০-৯]{1,2})[\\/\\-](\\d{2,4}|[০-৯]{2,4})$/;\n\n return monthNamePattern.test(cleaned) || separatorPattern.test(cleaned);\n}\n\n/**\n * Checks if a string contains Bengali digits.\n *\n * Bengali digits: ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯\n *\n * @param text - String to check\n * @returns true if string contains at least one Bengali digit, false otherwise\n *\n * @example\n * Strings with Bengali digits:\n * ```typescript\n * hasBengaliDigits('১৫'); // true\n * hasBengaliDigits('১৫ বৈশাখ'); // true\n * hasBengaliDigits('Today is ১৫ বৈশাখ'); // true\n * hasBengaliDigits('১'); // true\n * ```\n *\n * @example\n * Strings without Bengali digits:\n * ```typescript\n * hasBengaliDigits('15'); // false\n * hasBengaliDigits('বৈশাখ'); // false\n * hasBengaliDigits(''); // false\n * hasBengaliDigits('hello'); // false\n * ```\n */\nexport function hasBengaliDigits(text: string): boolean {\n if (typeof text !== 'string') {\n return false;\n }\n return /[০-৯]/.test(text);\n}\n\n/**\n * Checks if a string contains a Bengali month name.\n *\n * Valid month names:\n * বৈশাখ, জ্যৈষ্ঠ, আষাঢ়, শ্রাবণ, ভাদ্র, আশ্বিন,\n * কার্তিক, অগ্রহায়ণ, পৌষ, মাঘ, ফাল্গুন, চৈত্র\n *\n * @param text - String to check\n * @returns true if string contains a Bengali month name, false otherwise\n *\n * @example\n * Strings with month names:\n * ```typescript\n * hasBengaliMonth('১৫ বৈশাখ ১৪৩১'); // true\n * hasBengaliMonth('বৈশাখ'); // true\n * hasBengaliMonth('Today is বৈশাখ month'); // true\n * hasBengaliMonth('চৈত্র'); // true\n * ```\n *\n * @example\n * Strings without month names:\n * ```typescript\n * hasBengaliMonth('১৫/০৪/২০২৪'); // false\n * hasBengaliMonth('15'); // false\n * hasBengaliMonth('January'); // false\n * hasBengaliMonth(''); // false\n * ```\n */\nexport function hasBengaliMonth(text: string): boolean {\n if (typeof text !== 'string') {\n return false;\n }\n const monthPattern = /(বৈশাখ|জ্যৈষ্ঠ|আষাঢ়|শ্রাবণ|ভাদ্র|আশ্বিন|কার্তিক|অগ্রহায়ণ|পৌষ|মাঘ|ফাল্গুন|চৈত্র)/;\n return monthPattern.test(text);\n}\n\n/**\n * Sanitizes a Date object, returning null if invalid.\n *\n * This function validates a Date object and returns it if valid,\n * or null if it's not a valid Date.\n *\n * @param date - Date object to sanitize\n * @returns The Date object if valid, null otherwise\n *\n * @example\n * Valid dates:\n * ```typescript\n * sanitizeDate(new Date(2024, 0, 15));\n * // Date object for 2024-01-15\n *\n * sanitizeDate(new Date());\n * // Current date\n * ```\n *\n * @example\n * Invalid dates:\n * ```typescript\n * sanitizeDate(new Date('invalid')); // null\n * sanitizeDate('2024-01-15' as any); // null\n * sanitizeDate(null as any); // null\n * ```\n *\n * @example\n * Practical usage:\n * ```typescript\n * function formatUserDate(userInput: any): string {\n * const validDate = sanitizeDate(userInput);\n * if (validDate) {\n * return formatDate(validDate);\n * }\n * return 'Invalid date';\n * }\n * ```\n */\nexport function sanitizeDate(date: Date): Date | null {\n if (!isValidDate(date)) {\n return null;\n }\n return date;\n}\n","import { BANGLA_MONTHS } from '../constants';\n\n/**\n * Checks if a month number is valid (1-12).\n *\n * @param monthNumber - The month number to check\n * @returns true if the month number is between 1 and 12 (inclusive)\n *\n * @example\n * ```typescript\n * isValidMonthNumber(1); // true\n * isValidMonthNumber(12); // true\n * isValidMonthNumber(0); // false\n * isValidMonthNumber(13); // false\n * isValidMonthNumber(1.5); // false (not an integer)\n * ```\n */\nexport function isValidMonthNumber(monthNumber: number): boolean {\n return (\n typeof monthNumber === 'number' &&\n Number.isInteger(monthNumber) &&\n monthNumber >= 1 &&\n monthNumber <= 12\n );\n}\n\n/**\n * Checks if a string is a valid Bangla month name.\n *\n * Valid Bangla month names:\n * - বৈশাখ (Boishakh)\n * - জ্যৈষ্ঠ (Jyoishtho)\n * - আষাঢ় (Asharh)\n * - শ্রাবণ (Srabon)\n * - ভাদ্র (Bhadro)\n * - আশ্বিন (Ashwin)\n * - কার্তিক (Kartik)\n * - অগ্রহায়ণ (Ogrohayon)\n * - পৌষ (Poush)\n * - মাঘ (Magh)\n * - ফাল্গুন (Falgun)\n * - চৈত্র (Choitro)\n *\n * @param monthName - The month name to check\n * @returns true if the name is a valid Bangla month name\n *\n * @example\n * ```typescript\n * isValidBanglaMonth('বৈশাখ'); // true\n * isValidBanglaMonth('চৈত্র'); // true\n * isValidBanglaMonth(' বৈশাখ '); // true (handles whitespace)\n * isValidBanglaMonth('January'); // false\n * isValidBanglaMonth('invalid'); // false\n * ```\n */\nexport function isValidBanglaMonth(monthName: string): boolean {\n if (typeof monthName !== 'string') {\n return false;\n }\n\n const trimmed = monthName.trim();\n return BANGLA_MONTHS.includes(trimmed as any);\n}\n\n// Re-export isValidDate from date module to avoid duplication\nexport { isValidDate } from '../date/validate';\n\n/**\n * Sanitizes month number input.\n *\n * This function:\n * - Converts string numbers to integers\n * - Rounds decimal numbers to integers\n * - Returns null for invalid inputs\n *\n * @param value - The input value to sanitize\n * @returns Sanitized month number (1-12) or null if invalid\n *\n * @example\n * ```typescript\n * sanitizeMonthNumber('5'); // 5\n * sanitizeMonthNumber(3.7); // 4\n * sanitizeMonthNumber(3.2); // 3\n * sanitizeMonthNumber('invalid'); // null\n * sanitizeMonthNumber(0); // null\n * sanitizeMonthNumber(13); // null\n * ```\n */\nexport function sanitizeMonthNumber(value: any): number | null {\n // Try to convert string to number\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') {\n return null;\n }\n const parsed = Number(trimmed);\n if (isNaN(parsed)) {\n return null;\n }\n value = parsed;\n }\n\n // Must be a number at this point\n if (typeof value !== 'number' || isNaN(value) || !isFinite(value)) {\n return null;\n }\n\n // Round to integer\n const rounded = Math.round(value);\n\n // Must be valid month number\n if (rounded < 1 || rounded > 12) {\n return null;\n }\n\n return rounded;\n}\n\n/**\n * Sanitizes Bangla month name input.\n *\n * This function trims whitespace and validates the month name.\n *\n * @param value - The input value to sanitize\n * @returns Sanitized Bangla month name or null if invalid\n *\n * @example\n * ```typescript\n * sanitizeBanglaMonth(' বৈশাখ '); // 'বৈশাখ'\n * sanitizeBanglaMonth('চৈত্র'); // 'চৈত্র'\n * sanitizeBanglaMonth('invalid'); // null\n * sanitizeBanglaMonth(''); // null\n * ```\n */\nexport function sanitizeBanglaMonth(value: any): string | null {\n if (typeof value !== 'string') {\n return null;\n }\n\n const trimmed = value.trim();\n\n if (trimmed === '' || !isValidBanglaMonth(trimmed)) {\n return null;\n }\n\n return trimmed;\n}\n","import { BANGLA_MONTHS } from '../constants';\nimport { toBanglaMonth } from './toBanglaMonth';\nimport { fromBanglaMonth } from './fromBanglaMonth';\nimport { isValidMonthNumber, isValidBanglaMonth, sanitizeMonthNumber } from './validate';\n\n/**\n * Safely converts a month number to Bangla month name with a fallback.\n *\n * @param monthNumber - Month number (1-12)\n * @param fallback - Value to return if conversion fails (default: '')\n * @returns Bangla month name or fallback value\n *\n * @example\n * ```typescript\n * safeToBanglaMonth(1); // 'বৈশাখ'\n * safeToBanglaMonth(12); // 'চৈত্র'\n * safeToBanglaMonth(0); // ''\n * safeToBanglaMonth(13, 'N/A'); // 'N/A'\n * ```\n */\nexport function safeToBanglaMonth(monthNumber: number, fallback: string = ''): string {\n try {\n if (!isValidMonthNumber(monthNumber)) {\n return fallback;\n }\n return toBanglaMonth(monthNumber);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely converts a Bangla month name to month number with a fallback.\n *\n * @param monthName - Bangla month name\n * @param fallback - Value to return if conversion fails (default: 0)\n * @returns Month number (1-12) or fallback value\n *\n * @example\n * ```typescript\n * safeFromBanglaMonth('বৈশাখ'); // 1\n * safeFromBanglaMonth('চৈত্র'); // 12\n * safeFromBanglaMonth('invalid'); // 0\n * safeFromBanglaMonth('invalid', -1); // -1\n * ```\n */\nexport function safeFromBanglaMonth(monthName: string, fallback: number = 0): number {\n try {\n if (!isValidBanglaMonth(monthName)) {\n return fallback;\n }\n return fromBanglaMonth(monthName);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Gets all Bangla month names as an array.\n *\n * @returns Array of all 12 Bangla month names\n *\n * @example\n * ```typescript\n * const months = getAllMonths();\n * // ['বৈশাখ', 'জ্যৈষ্ঠ', 'আষাঢ়', 'শ্রাবণ', 'ভাদ্র', 'আশ্বিন',\n * // 'কার্তিক', 'অগ্রহায়ণ', 'পৌষ', 'মাঘ', 'ফাল্গুন', 'চৈত্র']\n *\n * // Use for dropdown options\n * months.forEach((month, index) => {\n * console.log(`${index + 1}: ${month}`);\n * });\n * ```\n */\nexport function getAllMonths(): string[] {\n return [...BANGLA_MONTHS];\n}\n\n/**\n * Gets the next month in the Bangla calendar.\n *\n * @param currentMonth - Current month number or Bangla month name\n * @returns Next month number or name (wraps from 12 to 1)\n * @throws {Error} If current month is invalid\n *\n * @example\n * ```typescript\n * getNextMonth(1); // 2\n * getNextMonth(12); // 1 (wraps around)\n * getNextMonth('বৈশাখ'); // 'জ্যৈষ্ঠ'\n * getNextMonth('চৈত্র'); // 'বৈশাখ' (wraps around)\n * ```\n */\nexport function getNextMonth(currentMonth: number | string): number | string {\n if (typeof currentMonth === 'number') {\n if (!isValidMonthNumber(currentMonth)) {\n throw new Error('Invalid month number');\n }\n return currentMonth === 12 ? 1 : currentMonth + 1;\n } else {\n if (!isValidBanglaMonth(currentMonth)) {\n throw new Error('Invalid Bangla month name');\n }\n const monthNum = fromBanglaMonth(currentMonth);\n const nextNum = monthNum === 12 ? 1 : monthNum + 1;\n return toBanglaMonth(nextNum);\n }\n}\n\n/**\n * Gets the previous month in the Bangla calendar.\n *\n * @param currentMonth - Current month number or Bangla month name\n * @returns Previous month number or name (wraps from 1 to 12)\n * @throws {Error} If current month is invalid\n *\n * @example\n * ```typescript\n * getPreviousMonth(2); // 1\n * getPreviousMonth(1); // 12 (wraps around)\n * getPreviousMonth('জ্যৈষ্ঠ'); // 'বৈশাখ'\n * getPreviousMonth('বৈশাখ'); // 'চৈত্র' (wraps around)\n * ```\n */\nexport function getPreviousMonth(currentMonth: number | string): number | string {\n if (typeof currentMonth === 'number') {\n if (!isValidMonthNumber(currentMonth)) {\n throw new Error('Invalid month number');\n }\n return currentMonth === 1 ? 12 : currentMonth - 1;\n } else {\n if (!isValidBanglaMonth(currentMonth)) {\n throw new Error('Invalid Bangla month name');\n }\n const monthNum = fromBanglaMonth(currentMonth);\n const prevNum = monthNum === 1 ? 12 : monthNum - 1;\n return toBanglaMonth(prevNum);\n }\n}\n\n/**\n * Gets a range of months between start and end (inclusive).\n *\n * @param start - Starting month (number or name)\n * @param end - Ending month (number or name)\n * @returns Array of month numbers or names\n * @throws {Error} If start or end are invalid\n *\n * @example\n * ```typescript\n * getMonthRange(1, 3);\n * // [1, 2, 3]\n *\n * getMonthRange('বৈশাখ', 'আষাঢ়');\n * // ['বৈশাখ', 'জ্যৈষ্ঠ', 'আষাঢ়']\n *\n * getMonthRange(11, 2); // Wraps around\n * // [11, 12, 1, 2]\n * ```\n */\nexport function getMonthRange(start: number | string, end: number | string): (number | string)[] {\n const isNumber = typeof start === 'number';\n\n let startNum: number;\n let endNum: number;\n\n if (isNumber) {\n if (!isValidMonthNumber(start as number) || !isValidMonthNumber(end as number)) {\n throw new Error('Invalid month numbers');\n }\n startNum = start as number;\n endNum = end as number;\n } else {\n if (!isValidBanglaMonth(start as string) || !isValidBanglaMonth(end as string)) {\n throw new Error('Invalid Bangla month names');\n }\n startNum = fromBanglaMonth(start as string);\n endNum = fromBanglaMonth(end as string);\n }\n\n const result: (number | string)[] = [];\n let current = startNum;\n\n while (true) {\n if (isNumber) {\n result.push(current);\n } else {\n result.push(toBanglaMonth(current));\n }\n\n if (current === endNum) {\n break;\n }\n\n current = current === 12 ? 1 : current + 1;\n\n // Safety check to prevent infinite loop\n if (result.length > 12) {\n break;\n }\n }\n\n return result;\n}\n\n/**\n * Checks if a given month is within a range.\n *\n * @param month - Month to check (number or name)\n * @param start - Range start (number or name)\n * @param end - Range end (number or name)\n * @returns true if month is within the range\n *\n * @example\n * ```typescript\n * isMonthInRange(2, 1, 3); // true\n * isMonthInRange('জ্যৈষ্ঠ', 'বৈশাখ', 'আষাঢ়'); // true\n * isMonthInRange(5, 1, 3); // false\n * isMonthInRange(1, 11, 2); // true (wraps around)\n * ```\n */\nexport function isMonthInRange(\n month: number | string,\n start: number | string,\n end: number | string\n): boolean {\n try {\n const range = getMonthRange(start, end);\n return range.includes(month);\n } catch {\n return false;\n }\n}\n\n/**\n * Compares two months.\n *\n * @param month1 - First month (number or name)\n * @param month2 - Second month (number or name)\n * @returns -1 if month1 comes before month2, 0 if equal, 1 if month1 comes after month2\n * @throws {Error} If months are invalid\n *\n * @example\n * ```typescript\n * compareMonths(1, 2); // -1\n * compareMonths(5, 3); // 1\n * compareMonths(3, 3); // 0\n * compareMonths('বৈশাখ', 'জ্যৈষ্ঠ'); // -1\n * ```\n */\nexport function compareMonths(month1: number | string, month2: number | string): number {\n let num1: number;\n let num2: number;\n\n if (typeof month1 === 'number') {\n if (!isValidMonthNumber(month1)) {\n throw new Error('Invalid month1');\n }\n num1 = month1;\n } else {\n if (!isValidBanglaMonth(month1)) {\n throw new Error('Invalid month1');\n }\n num1 = fromBanglaMonth(month1);\n }\n\n if (typeof month2 === 'number') {\n if (!isValidMonthNumber(month2)) {\n throw new Error('Invalid month2');\n }\n num2 = month2;\n } else {\n if (!isValidBanglaMonth(month2)) {\n throw new Error('Invalid month2');\n }\n num2 = fromBanglaMonth(month2);\n }\n\n if (num1 < num2) return -1;\n if (num1 > num2) return 1;\n return 0;\n}\n\n/**\n * Gets the month index (0-11) for a given month.\n *\n * This is useful for JavaScript Date operations where months are 0-indexed.\n *\n * @param month - Month number (1-12) or Bangla month name\n * @returns Month index (0-11)\n * @throws {Error} If month is invalid\n *\n * @example\n * ```typescript\n * getMonthIndex(1); // 0\n * getMonthIndex(12); // 11\n * getMonthIndex('বৈশাখ'); // 0\n * getMonthIndex('চৈত্র'); // 11\n * ```\n */\nexport function getMonthIndex(month: number | string): number {\n if (typeof month === 'number') {\n if (!isValidMonthNumber(month)) {\n throw new Error('Invalid month number');\n }\n return month - 1;\n } else {\n if (!isValidBanglaMonth(month)) {\n throw new Error('Invalid Bangla month name');\n }\n return fromBanglaMonth(month) - 1;\n }\n}\n\n/**\n * Gets the month number from a 0-based index.\n *\n * @param index - Month index (0-11)\n * @returns Month number (1-12)\n * @throws {Error} If index is out of range\n *\n * @example\n * ```typescript\n * getMonthFromIndex(0); // 1\n * getMonthFromIndex(11); // 12\n * getMonthFromIndex(5); // 6\n * ```\n */\nexport function getMonthFromIndex(index: number): number {\n if (!Number.isInteger(index) || index < 0 || index > 11) {\n throw new Error('Index must be between 0 and 11');\n }\n return index + 1;\n}\n\n/**\n * Parses and converts to Bangla month in one step.\n *\n * @param value - Input value (number, string number, or already Bangla month name)\n * @returns Bangla month name\n * @throws {Error} If value cannot be parsed as a valid month\n *\n * @example\n * ```typescript\n * parseAndConvertToMonth('1'); // 'বৈশাখ'\n * parseAndConvertToMonth(5); // 'ভাদ্র'\n * parseAndConvertToMonth(' 3 '); // 'আষাঢ়'\n * parseAndConvertToMonth('বৈশাখ'); // 'বৈশাখ' (already Bangla)\n * parseAndConvertToMonth('invalid'); // throws Error\n * ```\n */\nexport function parseAndConvertToMonth(value: any): string {\n // If it's already a valid Bangla month name, return it\n if (typeof value === 'string' && isValidBanglaMonth(value.trim())) {\n return value.trim();\n }\n\n // Try to sanitize as month number\n const sanitized = sanitizeMonthNumber(value);\n if (sanitized === null) {\n throw new Error('Invalid month input');\n }\n\n return toBanglaMonth(sanitized);\n}\n\n/**\n * Batch converts month numbers to Bangla month names.\n *\n * @param monthNumbers - Array of month numbers\n * @returns Array of Bangla month names (invalid months are skipped)\n *\n * @example\n * ```typescript\n * batchToBanglaMonth([1, 2, 3]);\n * // ['বৈশাখ', 'জ্যৈষ্ঠ', 'আষাঢ়']\n *\n * batchToBanglaMonth([1, 13, 3, 0, 5]);\n * // ['বৈশাখ', 'আষাঢ়', 'ভাদ্র'] (invalid months skipped)\n * ```\n */\nexport function batchToBanglaMonth(monthNumbers: number[]): string[] {\n return monthNumbers\n .filter(num => isValidMonthNumber(num))\n .map(num => toBanglaMonth(num));\n}\n\n/**\n * Creates a month mapping object.\n *\n * @returns Object mapping month numbers to Bangla month names\n *\n * @example\n * ```typescript\n * const mapping = getMonthMapping();\n * console.log(mapping[1]); // 'বৈশাখ'\n * console.log(mapping[12]); // 'চৈত্র'\n * ```\n */\nexport function getMonthMapping(): Record<number, string> {\n const mapping: Record<number, string> = {};\n for (let i = 1; i <= 12; i++) {\n mapping[i] = toBanglaMonth(i);\n }\n return mapping;\n}\n","import { BANGLA_WEEKDAYS } from '../constants';\n\n/**\n * Converts a weekday number to its Bangla weekday name.\n *\n * This function converts JavaScript weekday numbers (0-6, where 0 = Sunday) to their\n * corresponding Bangla weekday names. This matches the convention used by JavaScript's\n * `Date.getDay()` method.\n *\n * **Weekday Mapping:**\n * - 0 → রবিবার (Sunday)\n * - 1 → সোমবার (Monday)\n * - 2 → মঙ্গলবার (Tuesday)\n * - 3 → বুধবার (Wednesday)\n * - 4 → বৃহস্পতিবার (Thursday)\n * - 5 → শুক্রবার (Friday)\n * - 6 → শনিবার (Saturday)\n *\n * @param weekdayNumber - Weekday number (0-6, where 0 = Sunday)\n * @returns Bangla weekday name\n * @throws {Error} If weekdayNumber is not between 0 and 6\n *\n * @example\n * Basic conversion:\n * ```typescript\n * toBanglaWeekday(0); // 'রবিবার' (Sunday)\n * toBanglaWeekday(1); // 'সোমবার' (Monday)\n * toBanglaWeekday(6); // 'শনিবার' (Saturday)\n * ```\n *\n * @example\n * With Date object:\n * ```typescript\n * const today = new Date();\n * const weekdayNumber = today.getDay();\n * const banglaWeekday = toBanglaWeekday(weekdayNumber);\n * console.log(`Today is ${banglaWeekday}`);\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * toBanglaWeekday(7); // throws Error: Weekday number must be between 0 and 6\n * toBanglaWeekday(-1); // throws Error: Weekday number must be between 0 and 6\n * ```\n *\n * @example\n * Calendar generation:\n * ```typescript\n * const weekdays = [0, 1, 2, 3, 4, 5, 6].map(day => toBanglaWeekday(day));\n * console.log(weekdays);\n * // ['রবিবার', 'সোমবার', 'মঙ্গলবার', 'বুধবার', 'বৃহস্পতিবার', 'শুক্রবার', 'শনিবার']\n * ```\n */\nexport function toBanglaWeekday(weekdayNumber: number): string {\n if (weekdayNumber < 0 || weekdayNumber > 6) {\n throw new Error('Weekday number must be between 0 and 6');\n }\n\n return BANGLA_WEEKDAYS[weekdayNumber];\n}\n\n","import { BANGLA_WEEKDAYS } from '../constants';\n\n/**\n * Converts a Bangla weekday name to its corresponding weekday number.\n *\n * This function performs the reverse operation of `toBanglaWeekday()`, converting\n * Bangla weekday names to JavaScript weekday numbers (0-6). The conversion is\n * case-sensitive and requires exact matches.\n *\n * **Weekday Mapping:**\n * - রবিবার → 0 (Sunday)\n * - সোমবার → 1 (Monday)\n * - মঙ্গলবার → 2 (Tuesday)\n * - বুধবার → 3 (Wednesday)\n * - বৃহস্পতিবার → 4 (Thursday)\n * - শুক্রবার → 5 (Friday)\n * - শনিবার → 6 (Saturday)\n *\n * @param weekdayName - Bangla weekday name (case-sensitive)\n * @returns Weekday number (0-6, where 0 = Sunday)\n * @throws {Error} If weekdayName is not a valid Bangla weekday name\n *\n * @example\n * Basic conversion:\n * ```typescript\n * fromBanglaWeekday('রবিবার'); // 0 (Sunday)\n * fromBanglaWeekday('সোমবার'); // 1 (Monday)\n * fromBanglaWeekday('শনিবার'); // 6 (Saturday)\n * ```\n *\n * @example\n * Round-trip conversion:\n * ```typescript\n * const original = 3;\n * const bangla = toBanglaWeekday(original); // 'বুধবার'\n * const converted = fromBanglaWeekday(bangla); // 3\n * console.log(original === converted); // true\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * fromBanglaWeekday('invalid'); // throws Error: Invalid Bangla weekday name: invalid\n * fromBanglaWeekday(''); // throws Error: Invalid Bangla weekday name:\n * fromBanglaWeekday('রবিবার'); // throws Error (case-sensitive)\n * ```\n *\n * @example\n * Finding weekday index:\n * ```typescript\n * const userInput = 'শুক্রবার';\n * const dayIndex = fromBanglaWeekday(userInput);\n * if (dayIndex === 5 || dayIndex === 6) {\n * console.log('This is a weekend day!');\n * }\n * ```\n */\nexport function fromBanglaWeekday(weekdayName: string): number {\n const index = BANGLA_WEEKDAYS.indexOf(weekdayName as any);\n\n if (index === -1) {\n throw new Error(`Invalid Bangla weekday name: ${weekdayName}`);\n }\n\n return index;\n}\n\n","import { toBanglaWeekday } from './toBanglaWeekday';\n\n/**\n * Gets the Bangla weekday name from a Date object.\n *\n * This is a convenience function that combines `Date.getDay()` with `toBanglaWeekday()`\n * to directly get the Bangla weekday name from a Date object in a single call.\n *\n * @param date - JavaScript Date object\n * @returns Bangla weekday name for the given date\n * @throws {Error} If the date's weekday number is invalid (this should never happen with valid Date objects)\n *\n * @example\n * Basic usage:\n * ```typescript\n * const today = new Date();\n * const weekday = getWeekdayName(today);\n * console.log(`আজ ${weekday}`); // e.g., \"আজ শুক্রবার\"\n * ```\n *\n * @example\n * Specific date:\n * ```typescript\n * const date = new Date('2024-01-07'); // Sunday\n * getWeekdayName(date); // 'রবিবার'\n *\n * const date2 = new Date('2024-01-08'); // Monday\n * getWeekdayName(date2); // 'সোমবার'\n * ```\n *\n * @example\n * Formatting date displays:\n * ```typescript\n * const event = {\n * date: new Date('2024-12-25'),\n * name: 'Special Event'\n * };\n *\n * const weekday = getWeekdayName(event.date);\n * console.log(`${event.name} is on ${weekday}`);\n * // \"Special Event is on বুধবার\"\n * ```\n *\n * @example\n * Calendar rendering:\n * ```typescript\n * const dates = [\n * new Date('2024-01-01'),\n * new Date('2024-01-02'),\n * new Date('2024-01-03'),\n * ];\n *\n * dates.forEach(date => {\n * console.log(`${date.toLocaleDateString()}: ${getWeekdayName(date)}`);\n * });\n * ```\n */\nexport function getWeekdayName(date: Date): string {\n const weekdayNumber = date.getDay();\n return toBanglaWeekday(weekdayNumber);\n}\n\n","import { BANGLA_WEEKDAYS } from '../constants';\n\n/**\n * Validates if a value is a valid weekday number (0-6).\n *\n * This function checks if the input is a number between 0-6 (inclusive),\n * where 0 represents Sunday and 6 represents Saturday, matching JavaScript's\n * Date.getDay() convention.\n *\n * @param value - The value to validate\n * @returns true if the value is a valid weekday number, false otherwise\n *\n * @example\n * ```typescript\n * isValidWeekdayNumber(0); // true (Sunday)\n * isValidWeekdayNumber(6); // true (Saturday)\n * isValidWeekdayNumber(3); // true (Wednesday)\n * isValidWeekdayNumber(7); // false (out of range)\n * isValidWeekdayNumber(-1); // false (out of range)\n * isValidWeekdayNumber('0'); // false (not a number)\n * isValidWeekdayNumber(NaN); // false\n * ```\n */\nexport function isValidWeekdayNumber(value: any): boolean {\n if (typeof value !== 'number') {\n return false;\n }\n\n if (!Number.isFinite(value)) {\n return false;\n }\n\n if (!Number.isInteger(value)) {\n return false;\n }\n\n return value >= 0 && value <= 6;\n}\n\n/**\n * Validates if a value is a valid Bangla weekday name.\n *\n * This function checks if the input is one of the seven Bangla weekday names.\n * The check is case-sensitive and requires exact matches.\n *\n * **Valid names**:\n * - রবিবার (Sunday)\n * - সোমবার (Monday)\n * - মঙ্গলবার (Tuesday)\n * - বুধবার (Wednesday)\n * - বৃহস্পতিবার (Thursday)\n * - শুক্রবার (Friday)\n * - শনিবার (Saturday)\n *\n * @param value - The value to validate\n * @returns true if the value is a valid Bangla weekday name, false otherwise\n *\n * @example\n * ```typescript\n * isValidBanglaWeekday('রবিবার'); // true\n * isValidBanglaWeekday('সোমবার'); // true\n * isValidBanglaWeekday('শনিবার'); // true\n * isValidBanglaWeekday('invalid'); // false\n * isValidBanglaWeekday(''); // false\n * isValidBanglaWeekday(123); // false\n * ```\n */\nexport function isValidBanglaWeekday(value: any): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n\n const trimmed = value.trim();\n\n if (trimmed === '') {\n return false;\n }\n\n return BANGLA_WEEKDAYS.includes(trimmed as any);\n}\n\n/**\n * Validates if a value is a valid Date object for weekday extraction.\n *\n * This function checks if the input is a valid Date object that can be used\n * with `getWeekdayName()`.\n *\n * @param value - The value to validate\n * @returns true if the value is a valid Date object, false otherwise\n *\n * @example\n * ```typescript\n * isValidDateForWeekday(new Date()); // true\n * isValidDateForWeekday(new Date('2024-01-07')); // true\n * isValidDateForWeekday(new Date('invalid')); // false (Invalid Date)\n * isValidDateForWeekday('2024-01-07'); // false (string, not Date)\n * isValidDateForWeekday(123); // false\n * isValidDateForWeekday(null); // false\n * ```\n */\nexport function isValidDateForWeekday(value: any): boolean {\n if (!(value instanceof Date)) {\n return false;\n }\n\n // Check if the date is valid (not Invalid Date)\n return !isNaN(value.getTime());\n}\n\n/**\n * Sanitizes weekday name input by trimming whitespace.\n *\n * This function cleans user input for weekday name lookups by removing\n * leading and trailing whitespace.\n *\n * @param input - The weekday name string to sanitize\n * @returns Sanitized weekday name\n *\n * @example\n * ```typescript\n * sanitizeWeekdayInput(' রবিবার '); // 'রবিবার'\n * sanitizeWeekdayInput('সোমবার'); // 'সোমবার'\n * sanitizeWeekdayInput(' মঙ্গলবার\\n'); // 'মঙ্গলবার'\n * ```\n */\nexport function sanitizeWeekdayInput(input: string): string {\n if (typeof input !== 'string') {\n return '';\n }\n\n return input.trim();\n}\n","import { toBanglaWeekday } from './toBanglaWeekday';\nimport { fromBanglaWeekday } from './fromBanglaWeekday';\nimport { sanitizeWeekdayInput } from './validate';\n\n/**\n * Checks if a weekday number represents a weekend day.\n *\n * In Bangladesh, weekends are Friday (5) and Saturday (6).\n * This follows the common work week convention where Friday is the main holiday.\n *\n * @param weekdayNumber - Weekday number (0-6, where 0 = Sunday)\n * @returns true if the day is a weekend (Friday or Saturday), false otherwise\n *\n * @example\n * ```typescript\n * isWeekend(5); // true (Friday)\n * isWeekend(6); // true (Saturday)\n * isWeekend(0); // false (Sunday)\n * isWeekend(3); // false (Wednesday)\n * ```\n */\nexport function isWeekend(weekdayNumber: number): boolean {\n if (weekdayNumber < 0 || weekdayNumber > 6) {\n throw new Error('Weekday number must be between 0 and 6');\n }\n\n // Bangladesh weekend: Friday (5) and Saturday (6)\n return weekdayNumber === 5 || weekdayNumber === 6;\n}\n\n/**\n * Checks if a Bangla weekday name represents a weekend day.\n *\n * @param weekdayName - Bangla weekday name\n * @returns true if the day is a weekend (শুক্রবার or শনিবার), false otherwise\n *\n * @example\n * ```typescript\n * isBanglaWeekend('শুক্রবার'); // true\n * isBanglaWeekend('শনিবার'); // true\n * isBanglaWeekend('রবিবার'); // false\n * ```\n */\nexport function isBanglaWeekend(weekdayName: string): boolean {\n const weekdayNumber = fromBanglaWeekday(weekdayName);\n return isWeekend(weekdayNumber);\n}\n\n/**\n * Gets the next weekday number in sequence.\n *\n * This function returns the next day of the week, wrapping from Saturday (6)\n * back to Sunday (0).\n *\n * @param weekdayNumber - Current weekday number (0-6)\n * @returns Next weekday number (0-6)\n *\n * @example\n * ```typescript\n * getNextWeekday(0); // 1 (Sunday → Monday)\n * getNextWeekday(5); // 6 (Friday → Saturday)\n * getNextWeekday(6); // 0 (Saturday → Sunday, wraps around)\n * ```\n */\nexport function getNextWeekday(weekdayNumber: number): number {\n if (weekdayNumber < 0 || weekdayNumber > 6) {\n throw new Error('Weekday number must be between 0 and 6');\n }\n\n return (weekdayNumber + 1) % 7;\n}\n\n/**\n * Gets the previous weekday number in sequence.\n *\n * This function returns the previous day of the week, wrapping from Sunday (0)\n * back to Saturday (6).\n *\n * @param weekdayNumber - Current weekday number (0-6)\n * @returns Previous weekday number (0-6)\n *\n * @example\n * ```typescript\n * getPreviousWeekday(1); // 0 (Monday → Sunday)\n * getPreviousWeekday(0); // 6 (Sunday → Saturday, wraps around)\n * getPreviousWeekday(6); // 5 (Saturday → Friday)\n * ```\n */\nexport function getPreviousWeekday(weekdayNumber: number): number {\n if (weekdayNumber < 0 || weekdayNumber > 6) {\n throw new Error('Weekday number must be between 0 and 6');\n }\n\n return (weekdayNumber - 1 + 7) % 7;\n}\n\n/**\n * Gets the Bangla weekday name for the next day.\n *\n * Convenience function that combines `getNextWeekday()` with `toBanglaWeekday()`.\n *\n * @param weekdayNumber - Current weekday number (0-6)\n * @returns Bangla name of the next weekday\n *\n * @example\n * ```typescript\n * getNextBanglaWeekday(0); // 'সোমবার' (Sunday → Monday)\n * getNextBanglaWeekday(6); // 'রবিবার' (Saturday → Sunday)\n * ```\n */\nexport function getNextBanglaWeekday(weekdayNumber: number): string {\n const nextDay = getNextWeekday(weekdayNumber);\n return toBanglaWeekday(nextDay);\n}\n\n/**\n * Gets the Bangla weekday name for the previous day.\n *\n * Convenience function that combines `getPreviousWeekday()` with `toBanglaWeekday()`.\n *\n * @param weekdayNumber - Current weekday number (0-6)\n * @returns Bangla name of the previous weekday\n *\n * @example\n * ```typescript\n * getPreviousBanglaWeekday(1); // 'রবিবার' (Monday → Sunday)\n * getPreviousBanglaWeekday(0); // 'শনিবার' (Sunday → Saturday)\n * ```\n */\nexport function getPreviousBanglaWeekday(weekdayNumber: number): string {\n const prevDay = getPreviousWeekday(weekdayNumber);\n return toBanglaWeekday(prevDay);\n}\n\n/**\n * Parses user input with sanitization and converts to weekday number.\n *\n * This function combines sanitization (trimming) and conversion to weekday number,\n * making it ideal for processing form inputs or user-entered weekday names.\n *\n * @param input - The user input weekday name to parse\n * @returns Weekday number (0-6)\n * @throws Error if the sanitized input is not a valid weekday name\n *\n * @example\n * ```typescript\n * parseWeekdayInput(' রবিবার '); // 0\n * parseWeekdayInput('সোমবার'); // 1\n * parseWeekdayInput('শনিবার \\n'); // 6\n * parseWeekdayInput('invalid'); // throws Error\n * ```\n */\nexport function parseWeekdayInput(input: string): number {\n const sanitized = sanitizeWeekdayInput(input);\n return fromBanglaWeekday(sanitized);\n}\n\n/**\n * Safely converts a weekday number to Bangla with a fallback value.\n *\n * This is useful in UI contexts where you want to always display something,\n * even if the conversion fails.\n *\n * @param weekdayNumber - The weekday number to convert\n * @param fallback - Value to return if conversion fails (default: '')\n * @returns Bangla weekday name or fallback value\n *\n * @example\n * ```typescript\n * safeToBanglaWeekday(0); // 'রবিবার'\n * safeToBanglaWeekday(7, '---'); // '---' (out of range)\n * safeToBanglaWeekday(-1, 'N/A'); // 'N/A' (out of range)\n * ```\n */\nexport function safeToBanglaWeekday(weekdayNumber: number, fallback: string = ''): string {\n try {\n return toBanglaWeekday(weekdayNumber);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely converts a Bangla weekday name to number with a fallback.\n *\n * @param weekdayName - The Bangla weekday name to convert\n * @param fallback - Value to return if conversion fails (default: -1)\n * @returns Weekday number or fallback value\n *\n * @example\n * ```typescript\n * safeFromBanglaWeekday('রবিবার'); // 0\n * safeFromBanglaWeekday('invalid', -1); // -1\n * safeFromBanglaWeekday('', 99); // 99\n * ```\n */\nexport function safeFromBanglaWeekday(weekdayName: string, fallback: number = -1): number {\n try {\n return fromBanglaWeekday(weekdayName);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Gets all Bangla weekday names as an array.\n *\n * Returns a copy of the weekday names array for iteration or display purposes.\n * The array starts with Sunday (রবিবার) at index 0.\n *\n * @returns Array of all Bangla weekday names\n *\n * @example\n * ```typescript\n * const weekdays = getAllBanglaWeekdays();\n * console.log(weekdays[0]); // 'রবিবার'\n * console.log(weekdays.length); // 7\n *\n * // Use for dropdown/select options\n * weekdays.forEach((day, index) => {\n * console.log(`${index}: ${day}`);\n * });\n * ```\n */\nexport function getAllBanglaWeekdays(): string[] {\n return [\n 'রবিবার',\n 'সোমবার',\n 'মঙ্গলবার',\n 'বুধবার',\n 'বৃহস্পতিবার',\n 'শুক্রবার',\n 'শনিবার',\n ];\n}\n\n/**\n * Calculates the number of days between two weekday numbers.\n *\n * This function calculates the shortest distance between two weekdays,\n * considering the circular nature of the week.\n *\n * @param from - Starting weekday number (0-6)\n * @param to - Target weekday number (0-6)\n * @returns Number of days to go forward from 'from' to reach 'to' (0-6)\n *\n * @example\n * ```typescript\n * getDaysBetween(0, 3); // 3 (Sunday to Wednesday)\n * getDaysBetween(5, 1); // 3 (Friday to Monday, forward)\n * getDaysBetween(6, 0); // 1 (Saturday to Sunday)\n * getDaysBetween(3, 3); // 0 (same day)\n * ```\n */\nexport function getDaysBetween(from: number, to: number): number {\n if (from < 0 || from > 6 || to < 0 || to > 6) {\n throw new Error('Weekday numbers must be between 0 and 6');\n }\n\n return (to - from + 7) % 7;\n}\n","import { toBanglaNumber } from '../number';\nimport { getMonthName } from '../month';\nimport { getWeekdayName } from '../weekday';\n\n/**\n * Formats a Gregorian date with Bangla digits, month names, and weekdays.\n *\n * This function formats a standard JavaScript Date object using Bengali digits,\n * Bengali month names (based on Gregorian calendar), and Bengali weekday names.\n *\n * **Note:** This uses a simplified 1:1 mapping where Gregorian month corresponds\n * directly to a Bengali month name (January = বৈশাখ, etc.). For accurate Bengali\n * calendar conversion, use the `calendar` module's `getBengaliDate` function.\n *\n * **Output Formats:**\n * - Long (default): \"day month year\" or \"weekday day month year\"\n * - Short: Combines day and month in one part\n *\n * **Weekday Names:**\n * - রবিবার (Robibar) - Sunday\n * - সোমবার (Sombar) - Monday\n * - মঙ্গলবার (Mongolbar) - Tuesday\n * - বুধবার (Budhbar) - Wednesday\n * - বৃহস্পতিবার (Brihaspotibar) - Thursday\n * - শুক্রবার (Shukrobar) - Friday\n * - শনিবার (Shonibar) - Saturday\n *\n * @param date - Date object to format\n * @param options - Formatting options\n * @param options.includeWeekday - Include weekday name (default: false)\n * @param options.includeYear - Include year (default: true)\n * @param options.format - Format style: 'short' or 'long' (default: 'long')\n * @returns Formatted date string in Bangla\n *\n * @example\n * Basic formatting (with year):\n * ```typescript\n * formatDate(new Date(2024, 0, 15));\n * // \"১৫ বৈশাখ ২০২৪\"\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * formatDate(new Date(2024, 0, 15), { includeYear: false });\n * // \"১৫ বৈশাখ\"\n * ```\n *\n * @example\n * With weekday:\n * ```typescript\n * formatDate(new Date(2024, 0, 15), { includeWeekday: true });\n * // \"সোমবার ১৫ বৈশাখ ২০২৪\" (if Jan 15, 2024 is Monday)\n * ```\n *\n * @example\n * Short format:\n * ```typescript\n * formatDate(new Date(2024, 0, 15), { format: 'short' });\n * // \"১৫ বৈশাখ ২০২৪\"\n * ```\n *\n * @example\n * All options combined:\n * ```typescript\n * formatDate(\n * new Date(2024, 0, 15),\n * { includeWeekday: true, includeYear: false, format: 'short' }\n * );\n * // \"সোমবার ১৫ বৈশাখ\"\n * ```\n *\n * @example\n * Display current date:\n * ```typescript\n * const today = formatDate(new Date(), { includeWeekday: true });\n * console.log(`আজ: ${today}`);\n * // \"আজ: মঙ্গলবার ৭ পৌষ ২০২৫\" (example)\n * ```\n *\n * @example\n * Event list formatting:\n * ```typescript\n * const events = [\n * new Date(2024, 3, 14),\n * new Date(2024, 11, 16),\n * new Date(2025, 1, 21)\n * ];\n * events.forEach(event => {\n * console.log(formatDate(event, { includeWeekday: true, includeYear: false }));\n * });\n * // \"রবিবার ১৪ শ্রাবণ\"\n * // \"সোমবার ১৬ চৈত্র\"\n * // \"শুক্রবার ২১ জ্যৈষ্ঠ\"\n * ```\n */\nexport function formatDate(\n date: Date,\n options: {\n includeWeekday?: boolean;\n includeYear?: boolean;\n format?: 'short' | 'long';\n } = {}\n): string {\n const {\n includeWeekday = false,\n includeYear = true,\n format = 'long',\n } = options;\n\n const parts: string[] = [];\n\n if (includeWeekday) {\n const weekday = getWeekdayName(date);\n parts.push(weekday);\n }\n\n const day = toBanglaNumber(date.getDate());\n const month = getMonthName(date);\n const year = includeYear ? toBanglaNumber(date.getFullYear()) : null;\n\n if (format === 'short') {\n parts.push(`${day} ${month}`);\n } else {\n parts.push(day, month);\n }\n\n if (year) {\n parts.push(year);\n }\n\n return parts.join(' ');\n}\n\n","import { fromBanglaNumber } from '../number';\nimport { fromBanglaMonth } from '../month';\n\n/**\n * Parses a Bengali formatted date string into a JavaScript Date object.\n *\n * This function supports multiple Bengali date formats with both Bengali\n * and English digits. It handles month names and separator-based formats.\n *\n * **Supported Formats:**\n * 1. Month name format: \"day month [year]\"\n * - \"১৫ বৈশাখ ১৪৩১\" (Bengali digits)\n * - \"15 বৈশাখ 1431\" (English digits)\n * - \"১৫ বৈশাখ\" (without year, uses current year)\n *\n * 2. Separator format: \"day/month/year\" or \"day-month-year\"\n * - \"১৫/০৪/২০২৪\" (Bengali digits with slash)\n * - \"15-04-2024\" (English digits with dash)\n * - \"১৫/০৪/২০২৪\" (mixed Bengali/English)\n *\n * **Note:** This parses to Gregorian dates with Bengali formatting.\n * For Bengali calendar date parsing, use the `calendar` module's `fromBengali` function.\n *\n * @param dateString - Bengali formatted date string\n * @returns JavaScript Date object\n * @throws {Error} If the date string cannot be parsed\n *\n * @example\n * Month name format with Bengali digits:\n * ```typescript\n * parseDate('১৫ বৈশাখ ১৪৩১');\n * // Date object for the 15th day of month 1 (Boishakh) in year 1431\n * ```\n *\n * @example\n * Month name format with English digits:\n * ```typescript\n * parseDate('15 বৈশাখ 1431');\n * // Date object for the 15th day of month 1 in year 1431\n * ```\n *\n * @example\n * Without year (uses current year):\n * ```typescript\n * parseDate('১৫ বৈশাখ');\n * // Date object for 15 Boishakh of current year\n * ```\n *\n * @example\n * Separator format with Bengali digits:\n * ```typescript\n * parseDate('১৫/০৪/২০২৪');\n * // Date object for April 15, 2024\n * ```\n *\n * @example\n * Separator format with English digits:\n * ```typescript\n * parseDate('15-04-2024');\n * // Date object for April 15, 2024\n * ```\n *\n * @example\n * All month names:\n * ```typescript\n * parseDate('১ বৈশাখ ১৪৩১'); // Boishakh (month 1)\n * parseDate('১ জ্যৈষ্ঠ ১৪৩১'); // Joishtho (month 2)\n * parseDate('১ আষাঢ় ১৪৩১'); // Asharh (month 3)\n * parseDate('১ শ্রাবণ ১৪৩১'); // Srabon (month 4)\n * parseDate('১ ভাদ্র ১৪৩১'); // Bhadro (month 5)\n * parseDate('১ আশ্বিন ১৪৩১'); // Ashwin (month 6)\n * parseDate('১ কার্তিক ১৪৩১'); // Kartik (month 7)\n * parseDate('১ অগ্রহায়ণ ১৪৩১'); // Agrahayan (month 8)\n * parseDate('১ পৌষ ১৪৩১'); // Poush (month 9)\n * parseDate('১ মাঘ ১৪৩১'); // Magh (month 10)\n * parseDate('১ ফাল্গুন ১৪৩১'); // Falgun (month 11)\n * parseDate('১ চৈত্র ১৪৩১'); // Chaitra (month 12)\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * parseDate('invalid');\n * // throws Error: Unable to parse date string: invalid\n *\n * parseDate('2024-01-15');\n * // throws Error: Unable to parse date string: 2024-01-15\n * // (ISO format not supported)\n *\n * parseDate('');\n * // throws Error: Unable to parse date string:\n * ```\n *\n * @example\n * Practical usage (form handling):\n * ```typescript\n * try {\n * const userInput = '১৫ বৈশাখ ১৪৩১';\n * const date = parseDate(userInput);\n * console.log('Parsed date:', date);\n * } catch (error) {\n * console.error('Invalid date format');\n * }\n * ```\n *\n * @example\n * Parse and format back:\n * ```typescript\n * const original = '১৫ বৈশাখ ১৪৩১';\n * const parsed = parseDate(original);\n * const formatted = formatDate(parsed);\n * // formatted should match original format\n * ```\n */\nexport function parseDate(dateString: string): Date {\n // Remove extra whitespace\n const cleaned = dateString.trim().replace(/\\s+/g, ' ');\n\n // Try format: \"১৫ বৈশাখ ২০২৪\" or \"১৫ বৈশাখ\"\n const monthNameMatch = cleaned.match(\n /^(\\d+|[০-৯]+)\\s+(বৈশাখ|জ্যৈষ্ঠ|আষাঢ়|শ্রাবণ|ভাদ্র|আশ্বিন|কার্তিক|অগ্রহায়ণ|পৌষ|মাঘ|ফাল্গুন|চৈত্র)(?:\\s+(\\d+|[০-৯]+))?$/\n );\n\n if (monthNameMatch) {\n const dayStr = monthNameMatch[1];\n const monthName = monthNameMatch[2];\n const yearStr = monthNameMatch[3];\n\n const day = /[০-৯]/.test(dayStr) ? fromBanglaNumber(dayStr) : parseInt(dayStr, 10);\n const month = fromBanglaMonth(monthName);\n const year = yearStr\n ? /[০-৯]/.test(yearStr)\n ? fromBanglaNumber(yearStr)\n : parseInt(yearStr, 10)\n : new Date().getFullYear();\n\n // Note: This is a simplified conversion\n // For accurate Bengali calendar conversion, use the calendar module\n return new Date(year, month - 1, day);\n }\n\n // Try format: \"১৫/০৪/২০২৪\" or \"১৫-০৪-২০২৪\"\n const separatorMatch = cleaned.match(/^(\\d+|[০-৯]+)[\\/\\-](\\d+|[০-৯]+)[\\/\\-](\\d+|[০-৯]+)$/);\n\n if (separatorMatch) {\n const dayStr = separatorMatch[1];\n const monthStr = separatorMatch[2];\n const yearStr = separatorMatch[3];\n\n const day = /[০-৯]/.test(dayStr) ? fromBanglaNumber(dayStr) : parseInt(dayStr, 10);\n const month = /[০-৯]/.test(monthStr) ? fromBanglaNumber(monthStr) : parseInt(monthStr, 10);\n const year = /[০-৯]/.test(yearStr) ? fromBanglaNumber(yearStr) : parseInt(yearStr, 10);\n\n return new Date(year, month - 1, day);\n }\n\n throw new Error(`Unable to parse date string: ${dateString}`);\n}\n","/**\n * Utility functions for date formatting and parsing operations.\n *\n * This module provides helper functions for working with Bangla date formatting,\n * including safe conversions, date comparisons, and formatting utilities.\n *\n * @module date/utils\n */\n\nimport { formatDate } from './formatDate';\nimport { parseDate } from './parseDate';\nimport { isValidDate, isValidBengaliDateString } from './validate';\n\n/**\n * Safely formats a date with fallback value.\n *\n * Unlike formatDate, this function doesn't throw on invalid dates.\n * Returns a fallback string for invalid inputs.\n *\n * @param date - Date object to format\n * @param options - Formatting options\n * @param fallback - Fallback string if formatting fails (default: empty string)\n * @returns Formatted date string or fallback\n *\n * @example\n * Valid dates:\n * ```typescript\n * safeFormatDate(new Date(2024, 0, 15));\n * // \"১৫ বৈশাখ ২০২৪\" (example - depends on conversion)\n * ```\n *\n * @example\n * Invalid dates with fallback:\n * ```typescript\n * safeFormatDate(new Date('invalid'), {}, 'তারিখ নেই');\n * // \"তারিখ নেই\"\n *\n * safeFormatDate(null as any, {}, 'N/A');\n * // \"N/A\"\n * ```\n *\n * @example\n * Default fallback:\n * ```typescript\n * safeFormatDate(new Date('invalid'));\n * // \"\"\n * ```\n */\nexport function safeFormatDate(\n date: Date,\n options?: {\n includeWeekday?: boolean;\n includeYear?: boolean;\n format?: 'short' | 'long';\n },\n fallback: string = ''\n): string {\n try {\n if (!isValidDate(date)) {\n return fallback;\n }\n return formatDate(date, options);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely parses a Bengali date string with fallback.\n *\n * Unlike parseDate, this function doesn't throw on invalid strings.\n * Returns a fallback Date for invalid inputs.\n *\n * @param dateString - Bengali date string to parse\n * @param fallback - Fallback Date if parsing fails (default: current date)\n * @returns Parsed Date object or fallback\n *\n * @example\n * Valid date strings:\n * ```typescript\n * safeParseDate('১৫ বৈশাখ ১৪৩১');\n * // Date object for the parsed date\n * ```\n *\n * @example\n * Invalid strings with fallback:\n * ```typescript\n * const fallbackDate = new Date(2024, 0, 1);\n * safeParseDate('invalid', fallbackDate);\n * // Returns fallbackDate\n *\n * safeParseDate('not a date', fallbackDate);\n * // Returns fallbackDate\n * ```\n */\nexport function safeParseDate(dateString: string, fallback?: Date): Date {\n try {\n return parseDate(dateString);\n } catch {\n return fallback || new Date();\n }\n}\n\n/**\n * Formats today's date in Bangla.\n *\n * Convenience function that formats the current date.\n *\n * @param options - Formatting options\n * @returns Formatted current date string\n *\n * @example\n * ```typescript\n * formatToday();\n * // \"৭ বৈশাখ ২০২৫\" (example for current date)\n * ```\n *\n * @example\n * With weekday:\n * ```typescript\n * formatToday({ includeWeekday: true });\n * // \"মঙ্গলবার ৭ বৈশাখ ২০২৫\" (example)\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * formatToday({ includeYear: false });\n * // \"৭ বৈশাখ\"\n * ```\n */\nexport function formatToday(options?: {\n includeWeekday?: boolean;\n includeYear?: boolean;\n format?: 'short' | 'long';\n}): string {\n return formatDate(new Date(), options);\n}\n\n/**\n * Formats an array of dates in Bangla.\n *\n * @param dates - Array of Date objects\n * @param options - Formatting options\n * @returns Array of formatted date strings\n *\n * @example\n * ```typescript\n * const dates = [\n * new Date(2024, 0, 15),\n * new Date(2024, 1, 20),\n * new Date(2024, 2, 25)\n * ];\n * batchFormatDates(dates);\n * // [\"১৫ বৈশাখ ২০২৪\", \"২০ জ্যৈষ্ঠ ২০২৪\", \"২৫ আষাঢ় ২০২৪\"] (examples)\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * batchFormatDates(dates, { includeYear: false });\n * // [\"১৫ বৈশাখ\", \"২০ জ্যৈষ্ঠ\", \"২৫ আষাঢ়\"]\n * ```\n */\nexport function batchFormatDates(\n dates: Date[],\n options?: {\n includeWeekday?: boolean;\n includeYear?: boolean;\n format?: 'short' | 'long';\n }\n): string[] {\n return dates.map(date => safeFormatDate(date, options));\n}\n\n/**\n * Parses an array of Bengali date strings.\n *\n * @param dateStrings - Array of Bengali date strings\n * @returns Array of Date objects\n *\n * @example\n * ```typescript\n * const dateStrings = [\n * '১৫ বৈশাখ ১৪৩১',\n * '২০ জ্যৈষ্ঠ ১৪৩১',\n * '১৫/০৪/২০২৪'\n * ];\n * const dates = batchParseDates(dateStrings);\n * // Array of Date objects\n * ```\n *\n * @example\n * Handling invalid dates:\n * ```typescript\n * const mixed = ['১৫ বৈশাখ ১৪৩১', 'invalid'];\n * const dates = batchParseDates(mixed);\n * // First element: parsed Date, second element: current Date (fallback)\n * ```\n */\nexport function batchParseDates(dateStrings: string[]): Date[] {\n return dateStrings.map(str => safeParseDate(str));\n}\n\n/**\n * Checks if a date string can be parsed.\n *\n * @param dateString - String to check\n * @returns true if string can be parsed, false otherwise\n *\n * @example\n * Valid strings:\n * ```typescript\n * canParseBengaliDate('১৫ বৈশাখ ১৪৩১'); // true\n * canParseBengaliDate('১৫/০৪/২০২৪'); // true\n * canParseBengaliDate('15 বৈশাখ 1431'); // true\n * ```\n *\n * @example\n * Invalid strings:\n * ```typescript\n * canParseBengaliDate('invalid'); // false\n * canParseBengaliDate('2024-01-15'); // false\n * canParseBengaliDate(''); // false\n * ```\n */\nexport function canParseBengaliDate(dateString: string): boolean {\n return isValidBengaliDateString(dateString);\n}\n\n/**\n * Compares two dates.\n *\n * @param date1 - First date\n * @param date2 - Second date\n * @returns -1 if date1 < date2, 0 if equal, 1 if date1 > date2\n *\n * @example\n * First date is earlier:\n * ```typescript\n * compareDates(new Date(2024, 0, 10), new Date(2024, 0, 15));\n * // -1\n * ```\n *\n * @example\n * Dates are equal:\n * ```typescript\n * const date = new Date(2024, 0, 15);\n * compareDates(date, new Date(date));\n * // 0\n * ```\n *\n * @example\n * First date is later:\n * ```typescript\n * compareDates(new Date(2024, 0, 20), new Date(2024, 0, 15));\n * // 1\n * ```\n */\nexport function compareDates(date1: Date, date2: Date): -1 | 0 | 1 {\n if (!isValidDate(date1) || !isValidDate(date2)) {\n throw new Error('Invalid date');\n }\n\n const time1 = date1.getTime();\n const time2 = date2.getTime();\n\n if (time1 < time2) return -1;\n if (time1 > time2) return 1;\n return 0;\n}\n\n/**\n * Checks if a date is today.\n *\n * @param date - Date to check\n * @returns true if date is today, false otherwise\n *\n * @example\n * ```typescript\n * isToday(new Date());\n * // true\n *\n * isToday(new Date(2024, 0, 1));\n * // false (unless today is 2024-01-01)\n * ```\n */\nexport function isToday(date: Date): boolean {\n if (!isValidDate(date)) {\n return false;\n }\n\n const today = new Date();\n return (\n date.getDate() === today.getDate() &&\n date.getMonth() === today.getMonth() &&\n date.getFullYear() === today.getFullYear()\n );\n}\n\n/**\n * Checks if a date is in the past.\n *\n * @param date - Date to check\n * @returns true if date is before now, false otherwise\n *\n * @example\n * ```typescript\n * isPast(new Date(2020, 0, 1));\n * // true\n *\n * isPast(new Date(2030, 0, 1));\n * // false\n * ```\n */\nexport function isPast(date: Date): boolean {\n if (!isValidDate(date)) {\n return false;\n }\n\n return date.getTime() < Date.now();\n}\n\n/**\n * Checks if a date is in the future.\n *\n * @param date - Date to check\n * @returns true if date is after now, false otherwise\n *\n * @example\n * ```typescript\n * isFuture(new Date(2030, 0, 1));\n * // true\n *\n * isFuture(new Date(2020, 0, 1));\n * // false\n * ```\n */\nexport function isFuture(date: Date): boolean {\n if (!isValidDate(date)) {\n return false;\n }\n\n return date.getTime() > Date.now();\n}\n\n/**\n * Gets the difference in days between two dates.\n *\n * @param date1 - First date\n * @param date2 - Second date\n * @returns Number of days between dates (date2 - date1)\n *\n * @example\n * ```typescript\n * const date1 = new Date(2024, 0, 1);\n * const date2 = new Date(2024, 0, 11);\n * getDaysDifference(date1, date2);\n * // 10\n * ```\n *\n * @example\n * Negative difference:\n * ```typescript\n * const date1 = new Date(2024, 0, 11);\n * const date2 = new Date(2024, 0, 1);\n * getDaysDifference(date1, date2);\n * // -10\n * ```\n */\nexport function getDaysDifference(date1: Date, date2: Date): number {\n if (!isValidDate(date1) || !isValidDate(date2)) {\n throw new Error('Invalid date');\n }\n\n const diffTime = date2.getTime() - date1.getTime();\n return Math.floor(diffTime / (1000 * 60 * 60 * 24));\n}\n\n/**\n * Adds days to a date.\n *\n * @param date - Starting date\n * @param days - Number of days to add (can be negative)\n * @returns New Date object\n *\n * @example\n * Adding days:\n * ```typescript\n * const date = new Date(2024, 0, 1);\n * addDays(date, 10);\n * // Date for 2024-01-11\n * ```\n *\n * @example\n * Subtracting days:\n * ```typescript\n * const date = new Date(2024, 0, 11);\n * addDays(date, -10);\n * // Date for 2024-01-01\n * ```\n */\nexport function addDays(date: Date, days: number): Date {\n if (!isValidDate(date)) {\n throw new Error('Invalid date');\n }\n\n const result = new Date(date);\n result.setDate(result.getDate() + days);\n return result;\n}\n\n/**\n * Checks if a date is in a range (inclusive).\n *\n * @param date - Date to check\n * @param start - Start of range (inclusive)\n * @param end - End of range (inclusive)\n * @returns true if date is in range, false otherwise\n *\n * @example\n * Date within range:\n * ```typescript\n * isDateInRange(\n * new Date(2024, 0, 15),\n * new Date(2024, 0, 10),\n * new Date(2024, 0, 20)\n * );\n * // true\n * ```\n *\n * @example\n * Date on boundary:\n * ```typescript\n * isDateInRange(\n * new Date(2024, 0, 10),\n * new Date(2024, 0, 10),\n * new Date(2024, 0, 20)\n * );\n * // true\n * ```\n *\n * @example\n * Date outside range:\n * ```typescript\n * isDateInRange(\n * new Date(2024, 0, 25),\n * new Date(2024, 0, 10),\n * new Date(2024, 0, 20)\n * );\n * // false\n * ```\n */\nexport function isDateInRange(date: Date, start: Date, end: Date): boolean {\n if (!isValidDate(date) || !isValidDate(start) || !isValidDate(end)) {\n return false;\n }\n\n return compareDates(date, start) >= 0 && compareDates(date, end) <= 0;\n}\n","import { BANGLA_SEASONS } from '../constants';\n\n/**\n * Gets the Bangla season name from a Bengali month number.\n *\n * This function maps Bengali month numbers (1-12) to their corresponding seasons\n * according to the traditional Bengali calendar system.\n *\n * **Month to Season Mapping:**\n * - Months 1-2 (বৈশাখ-জ্যৈষ্ঠ) → গ্রীষ্ম (Summer)\n * - Months 3-5 (আষাঢ়-শ্রাবণ-ভাদ্র) → বর্ষা (Monsoon)\n * - Months 6-7 (আশ্বিন-কার্তিক) → শরৎ (Autumn)\n * - Month 8 (অগ্রহায়ণ) → হেমন্ত (Late Autumn)\n * - Months 9-10 (পৌষ-মাঘ) → শীত (Winter)\n * - Months 11-12 (ফাল্গুন-চৈত্র) → বসন্ত (Spring)\n *\n * @param monthNumber - Bengali month number (1-12)\n * @returns Bangla season name\n * @throws {Error} If monthNumber is not between 1 and 12\n *\n * @example\n * Basic usage:\n * ```typescript\n * getSeasonFromMonth(1); // 'গ্রীষ্ম' (বৈশাখ - Summer)\n * getSeasonFromMonth(4); // 'বর্ষা' (শ্রাবণ - Monsoon)\n * getSeasonFromMonth(8); // 'হেমন্ত' (অগ্রহায়ণ - Late Autumn)\n * getSeasonFromMonth(12); // 'বসন্ত' (চৈত্র - Spring)\n * ```\n *\n * @example\n * All months mapped to seasons:\n * ```typescript\n * // Summer months\n * getSeasonFromMonth(1); // 'গ্রীষ্ম' (Boishakh)\n * getSeasonFromMonth(2); // 'গ্রীষ্ম' (Joishtho)\n *\n * // Monsoon months\n * getSeasonFromMonth(3); // 'বর্ষা' (Asharh)\n * getSeasonFromMonth(4); // 'বর্ষা' (Shrabon)\n * getSeasonFromMonth(5); // 'বর্ষা' (Bhadro)\n *\n * // Autumn months\n * getSeasonFromMonth(6); // 'শরৎ' (Ashwin)\n * getSeasonFromMonth(7); // 'শরৎ' (Kartik)\n *\n * // Late Autumn\n * getSeasonFromMonth(8); // 'হেমন্ত' (Ogrohayon)\n *\n * // Winter months\n * getSeasonFromMonth(9); // 'শীত' (Poush)\n * getSeasonFromMonth(10); // 'শীত' (Magh)\n *\n * // Spring months\n * getSeasonFromMonth(11); // 'বসন্ত' (Falgun)\n * getSeasonFromMonth(12); // 'বসন্ত' (Choitro)\n * ```\n *\n * @example\n * Error handling:\n * ```typescript\n * getSeasonFromMonth(0); // throws Error: Month number must be between 1 and 12\n * getSeasonFromMonth(13); // throws Error: Month number must be between 1 and 12\n * ```\n *\n * @example\n * Use in calendar application:\n * ```typescript\n * const bengaliMonths = [\n * 'বৈশাখ', 'জ্যৈষ্ঠ', 'আষাঢ়', 'শ্রাবণ', 'ভাদ্র', 'আশ্বিন',\n * 'কার্তিক', 'অগ্রহায়ণ', 'পৌষ', 'মাঘ', 'ফাল্গুন', 'চৈত্র'\n * ];\n *\n * for (let month = 1; month <= 12; month++) {\n * const monthName = bengaliMonths[month - 1];\n * const season = getSeasonFromMonth(month);\n * console.log(`${monthName} - ${season}`);\n * }\n * ```\n */\nexport function getSeasonFromMonth(monthNumber: number): string {\n if (monthNumber < 1 || monthNumber > 12) {\n throw new Error('Month number must be between 1 and 12');\n }\n\n // Mapping based on Bengali calendar:\n // গ্রীষ্ম (Summer): বৈশাখ-জ্যৈষ্ঠ (1-2)\n // বর্ষা (Monsoon): আষাঢ়-ভাদ্র (3-5)\n // শরৎ (Autumn): আশ্বিন-কার্তিক (6-7)\n // হেমন্ত (Late Autumn): অগ্রহায়ণ (8)\n // শীত (Winter): পৌষ-মাঘ (9-10)\n // বসন্ত (Spring): ফাল্গুন-চৈত্র (11-12)\n\n if (monthNumber >= 1 && monthNumber <= 2) {\n return BANGLA_SEASONS[0]; // গ্রীষ্ম\n } else if (monthNumber >= 3 && monthNumber <= 5) {\n return BANGLA_SEASONS[1]; // বর্ষা\n } else if (monthNumber >= 6 && monthNumber <= 7) {\n return BANGLA_SEASONS[2]; // শরৎ\n } else if (monthNumber === 8) {\n return BANGLA_SEASONS[3]; // হেমন্ত\n } else if (monthNumber >= 9 && monthNumber <= 10) {\n return BANGLA_SEASONS[4]; // শীত\n } else {\n return BANGLA_SEASONS[5]; // বসন্ত\n }\n}\n\n","import { getBengaliMonthLengths } from './utils';\n\n/**\n * Converts a Bengali calendar date to Gregorian date.\n *\n * This function performs the reverse operation of toBengali, converting\n * from the Bengali calendar to the Gregorian calendar. It accurately\n * handles month boundaries, year transitions, and leap years.\n *\n * **Input Format:**\n * - year: Bengali year (positive integer)\n * - month: Bengali month (1-12)\n * - day: Day of month (1-31, depending on month)\n *\n * **Bengali to Gregorian Mapping:**\n * - Bengali year + 593 or 594 = Gregorian year (depends on date)\n * - 1 Boishakh (Bengali New Year) = April 14 (Gregorian)\n *\n * @param bengaliDate - Bengali date object with year, month, and day properties\n * @returns Gregorian Date object\n * @throws {Error} If the Bengali date is invalid\n *\n * @example\n * Bengali New Year to Gregorian:\n * ```typescript\n * fromBengali({ year: 1431, month: 1, day: 1 });\n * // Date object for April 14, 2024 (Pohela Boishakh)\n * ```\n *\n * @example\n * Mid-year conversions:\n * ```typescript\n * fromBengali({ year: 1431, month: 6, day: 15 });\n * // Date object for October 1, 2024 (approx - Ashwin)\n *\n * fromBengali({ year: 1431, month: 9, day: 1 });\n * // Date object for December 16, 2024 (approx - Poush)\n * ```\n *\n * @example\n * End of year:\n * ```typescript\n * fromBengali({ year: 1431, month: 12, day: 30 });\n * // Date object for April 13, 2025 (last day before new year)\n * ```\n *\n * @example\n * Practical usage (event scheduling):\n * ```typescript\n * const bengaliEvent = { year: 1431, month: 1, day: 1 };\n * const gregorianDate = fromBengali(bengaliEvent);\n * console.log(`Event date: ${gregorianDate.toLocaleDateString()}`);\n * // \"Event date: 4/14/2024\"\n * ```\n *\n * @example\n * Leap year handling:\n * ```typescript\n * // Falgun 30 in a leap year\n * fromBengali({ year: 1427, month: 11, day: 30 });\n * // Valid conversion (2020 is a leap year)\n *\n * // Falgun 30 in a non-leap year would be invalid\n * // (month 11 only has 29 days in non-leap years)\n * ```\n *\n * @example\n * Round-trip conversion:\n * ```typescript\n * const original = new Date(2024, 6, 15);\n * const bengali = toBengali(original);\n * const converted = fromBengali(bengali);\n * // converted should equal original date\n * ```\n */\nexport function fromBengali(b: { year: number; month: number; day: number }): Date {\n const { year, month, day } = b;\n\n const monthLengths = getBengaliMonthLengths(year);\n\n // --- Validation ---\n if (month < 1 || month > 12) {\n throw new Error('Invalid Bengali month');\n }\n if (day < 1 || day > monthLengths[month - 1]) {\n throw new Error('Invalid Bengali day for given month');\n }\n\n /**\n * 1 Boishakh anchor (Bangladesh Revised Calendar)\n * Bengali year + 593 = Gregorian year of Boishakh\n */\n const gYear = year + 593;\n const boishakh1 = new Date(Date.UTC(gYear, 3, 14)); // April 14\n\n /**\n * Days since 1 Boishakh\n */\n let daysOffset = 0;\n\n // Full months before current month\n for (let m = 1; m < month; m++) {\n daysOffset += monthLengths[m - 1];\n }\n\n // Days inside current month\n daysOffset += day - 1;\n\n return new Date(boishakh1.getTime() + daysOffset * 86400000);\n}\n","import { toBengali } from './toBengali';\nimport { toBanglaNumber } from '../number';\nimport { toBanglaMonth } from '../month';\n\n/**\n * Formats a Gregorian date as a Bengali calendar date string with Bengali text.\n *\n * This function converts a Gregorian date to the Bengali calendar and formats it\n * with Bengali digits and month names. It's ideal for displaying dates in\n * Bengali cultural contexts.\n *\n * **Output Format:**\n * - Default: \"day month year\" (e.g., \"১৫ বৈশাখ ১৪৩১\")\n * - With weekday: \"weekday day month year\" (e.g., \"রবিবার ১৫ বৈশাখ ১৪৩১\")\n * - Without year: \"day month\" (e.g., \"১৫ বৈশাখ\")\n *\n * **Weekday Names:**\n * - রবিবার (Robibar) - Sunday\n * - সোমবার (Sombar) - Monday\n * - মঙ্গলবার (Mongolbar) - Tuesday\n * - বুধবার (Budhbar) - Wednesday\n * - বৃহস্পতিবার (Brihaspotibar) - Thursday\n * - শুক্রবার (Shukrobar) - Friday\n * - শনিবার (Shonibar) - Saturday\n *\n * @param date - Gregorian Date object to format\n * @param options - Formatting options\n * @param options.includeYear - Include Bengali year in output (default: true)\n * @param options.includeWeekday - Include weekday name in output (default: false)\n * @returns Formatted Bengali date string\n *\n * @example\n * Basic formatting (with year):\n * ```typescript\n * getBengaliDate(new Date(2024, 3, 14));\n * // \"১ বৈশাখ ১৪৩১\" (Pohela Boishakh 1431)\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * getBengaliDate(new Date(2024, 3, 14), { includeYear: false });\n * // \"১ বৈশাখ\"\n * ```\n *\n * @example\n * With weekday:\n * ```typescript\n * getBengaliDate(new Date(2024, 3, 14), { includeWeekday: true });\n * // \"রবিবার ১ বৈশাখ ১৪৩১\" (if April 14, 2024 is Sunday)\n * ```\n *\n * @example\n * With weekday, without year:\n * ```typescript\n * getBengaliDate(\n * new Date(2024, 3, 14),\n * { includeWeekday: true, includeYear: false }\n * );\n * // \"রবিবার ১ বৈশাখ\"\n * ```\n *\n * @example\n * Display current date in Bengali:\n * ```typescript\n * const today = new Date();\n * const bengaliToday = getBengaliDate(today, { includeWeekday: true });\n * console.log(`আজ: ${bengaliToday}`);\n * // \"আজ: মঙ্গলবার ২৪ পৌষ ১৪৩১\" (example)\n * ```\n *\n * @example\n * Birthday display:\n * ```typescript\n * const birthday = new Date(2024, 6, 15);\n * const bengaliBirthday = getBengaliDate(birthday);\n * console.log(`জন্মদিন: ${bengaliBirthday}`);\n * // \"জন্মদিন: ১ শ্রাবণ ১৪৩১\" (example)\n * ```\n *\n * @example\n * Event calendar:\n * ```typescript\n * const events = [\n * new Date(2024, 3, 14),\n * new Date(2024, 11, 16),\n * new Date(2025, 1, 21)\n * ];\n * events.forEach(event => {\n * console.log(getBengaliDate(event, { includeWeekday: true }));\n * });\n * // \"রবিবার ১ বৈশাখ ১৪৩১\"\n * // \"সোমবার ২ পৌষ ১৪৩১\"\n * // \"শুক্রবার ৯ ফাল্গুন ১৪৩১\"\n * ```\n */\nexport function getBengaliDate(\n date: Date,\n options: {\n includeYear?: boolean;\n includeWeekday?: boolean;\n } = {}\n): string {\n const { includeYear = true, includeWeekday = false } = options;\n const bengali = toBengali(date);\n\n const weekdays = ['রবিবার', 'সোমবার', 'মঙ্গলবার', 'বুধবার', 'বৃহস্পতিবার', 'শুক্রবার', 'শনিবার'];\n\n const parts: string[] = [\n ...(includeWeekday ? [weekdays[date.getDay()]] : []),\n toBanglaNumber(bengali.day),\n toBanglaMonth(bengali.month),\n ...(includeYear ? [toBanglaNumber(bengali.year)] : []),\n ];\n\n return parts.join(' ');\n}\n","/**\n * Validation utilities for Bengali calendar operations.\n *\n * This module provides non-throwing validation functions for Bengali calendar dates.\n * All validators return boolean values or null for sanitization functions.\n *\n * @module calendar/validate\n */\n\nimport { getBengaliMonthLengths } from './utils';\n\n/**\n * Checks if a year is a valid Bengali calendar year.\n *\n * Valid Bengali years are positive integers. The Bengali calendar\n * is typically 593-594 years behind the Gregorian calendar.\n *\n * @param year - Year to validate\n * @returns true if year is a valid Bengali year, false otherwise\n *\n * @example\n * Valid years:\n * ```typescript\n * isValidBengaliYear(1431); // true\n * isValidBengaliYear(1400); // true\n * isValidBengaliYear(1); // true\n * ```\n *\n * @example\n * Invalid years:\n * ```typescript\n * isValidBengaliYear(0); // false\n * isValidBengaliYear(-10); // false\n * isValidBengaliYear(1431.5); // false\n * isValidBengaliYear('1431' as any); // false\n * ```\n */\nexport function isValidBengaliYear(year: number): boolean {\n return typeof year === 'number' && Number.isInteger(year) && year > 0 && isFinite(year);\n}\n\n/**\n * Checks if a month is a valid Bengali calendar month (1-12).\n *\n * Bengali calendar has 12 months:\n * 1=বৈশাখ, 2=জ্যৈষ্ঠ, 3=আষাঢ়, 4=শ্রাবণ, 5=ভাদ্র, 6=আশ্বিন,\n * 7=কার্তিক, 8=অগ্রহায়ণ, 9=পৌষ, 10=মাঘ, 11=ফাল্গুন, 12=চৈত্র\n *\n * @param month - Month to validate (1-12)\n * @returns true if month is valid, false otherwise\n *\n * @example\n * Valid months:\n * ```typescript\n * isValidBengaliMonth(1); // true (Boishakh)\n * isValidBengaliMonth(6); // true (Ashwin)\n * isValidBengaliMonth(12); // true (Chaitra)\n * ```\n *\n * @example\n * Invalid months:\n * ```typescript\n * isValidBengaliMonth(0); // false\n * isValidBengaliMonth(13); // false\n * isValidBengaliMonth(6.5); // false\n * ```\n */\nexport function isValidBengaliMonth(month: number): boolean {\n return typeof month === 'number' && Number.isInteger(month) && month >= 1 && month <= 12;\n}\n\n/**\n * Checks if a day is valid for a given Bengali month and year.\n *\n * Bengali calendar month lengths:\n * - Months 1-5 (বৈশাখ-ভাদ্র): 31 days\n * - Months 6-10 (আশ্বিন-মাঘ): 30 days\n * - Month 11 (ফাল্গুন): 29 or 30 days (depends on Gregorian leap year)\n * - Month 12 (চৈত্র): 30 days\n *\n * @param day - Day to validate\n * @param month - Bengali month (1-12)\n * @param year - Bengali year\n * @returns true if day is valid for the given month/year, false otherwise\n *\n * @example\n * Valid days:\n * ```typescript\n * isValidBengaliDay(15, 1, 1431); // true (Boishakh has 31 days)\n * isValidBengaliDay(31, 1, 1431); // true (last day of Boishakh)\n * isValidBengaliDay(30, 6, 1431); // true (Ashwin has 30 days)\n * ```\n *\n * @example\n * Invalid days:\n * ```typescript\n * isValidBengaliDay(32, 1, 1431); // false (Boishakh has only 31 days)\n * isValidBengaliDay(31, 6, 1431); // false (Ashwin has only 30 days)\n * isValidBengaliDay(0, 1, 1431); // false (day must be >= 1)\n * isValidBengaliDay(15.5, 1, 1431); // false (must be integer)\n * ```\n *\n * @example\n * Leap year handling:\n * ```typescript\n * // 1427 Bengali corresponds to 2020 Gregorian (leap year)\n * isValidBengaliDay(30, 11, 1427); // true (Falgun has 30 days in leap year)\n *\n * // 1428 Bengali corresponds to 2021 Gregorian (not leap year)\n * isValidBengaliDay(30, 11, 1428); // false (Falgun has only 29 days)\n * isValidBengaliDay(29, 11, 1428); // true\n * ```\n */\nexport function isValidBengaliDay(day: number, month: number, year: number): boolean {\n if (\n typeof day !== 'number' ||\n !Number.isInteger(day) ||\n day < 1 ||\n !isValidBengaliMonth(month) ||\n !isValidBengaliYear(year)\n ) {\n return false;\n }\n\n const monthLengths = getBengaliMonthLengths(year);\n return day <= monthLengths[month - 1];\n}\n\n/**\n * Checks if a Bengali date object is valid.\n *\n * A valid Bengali date object must have valid year, month, and day properties\n * that form a valid date combination.\n *\n * @param date - Bengali date object with year, month, day properties\n * @returns true if the date object is valid, false otherwise\n *\n * @example\n * Valid dates:\n * ```typescript\n * isValidBengaliDate({ year: 1431, month: 1, day: 1 }); // true\n * isValidBengaliDate({ year: 1431, month: 6, day: 15 }); // true\n * isValidBengaliDate({ year: 1431, month: 12, day: 30 }); // true\n * ```\n *\n * @example\n * Invalid dates:\n * ```typescript\n * isValidBengaliDate({ year: 1431, month: 13, day: 1 }); // false (invalid month)\n * isValidBengaliDate({ year: 1431, month: 1, day: 32 }); // false (day > 31)\n * isValidBengaliDate({ year: 0, month: 1, day: 1 }); // false (invalid year)\n * isValidBengaliDate({ year: 1431, month: 6, day: 31 }); // false (Ashwin has only 30 days)\n * ```\n *\n * @example\n * Type validation:\n * ```typescript\n * isValidBengaliDate({ year: 1431, month: 1 } as any); // false (missing day)\n * isValidBengaliDate({ year: '1431', month: 1, day: 1 } as any); // false (year not number)\n * isValidBengaliDate(null as any); // false\n * ```\n */\nexport function isValidBengaliDate(date: { year: number; month: number; day: number }): boolean {\n if (!date || typeof date !== 'object') {\n return false;\n }\n\n const { year, month, day } = date;\n\n return (\n isValidBengaliYear(year) && isValidBengaliMonth(month) && isValidBengaliDay(day, month, year)\n );\n}\n\n/**\n * Sanitizes a Bengali date object, returning null if invalid.\n *\n * This function validates all components of a Bengali date and returns\n * the date object if valid, or null if any component is invalid.\n *\n * @param date - Bengali date object to sanitize\n * @returns The date object if valid, null otherwise\n *\n * @example\n * Valid dates:\n * ```typescript\n * sanitizeBengaliDate({ year: 1431, month: 1, day: 1 });\n * // { year: 1431, month: 1, day: 1 }\n *\n * sanitizeBengaliDate({ year: 1431, month: 6, day: 15 });\n * // { year: 1431, month: 6, day: 15 }\n * ```\n *\n * @example\n * Invalid dates:\n * ```typescript\n * sanitizeBengaliDate({ year: 1431, month: 13, day: 1 }); // null\n * sanitizeBengaliDate({ year: 1431, month: 1, day: 32 }); // null\n * sanitizeBengaliDate({ year: 0, month: 1, day: 1 }); // null\n * sanitizeBengaliDate(null as any); // null\n * ```\n *\n * @example\n * Practical usage (form validation):\n * ```typescript\n * const userInput = { year: 1431, month: 1, day: 15 };\n * const validDate = sanitizeBengaliDate(userInput);\n *\n * if (validDate) {\n * console.log('Valid date:', validDate);\n * } else {\n * console.log('Invalid date provided');\n * }\n * ```\n */\nexport function sanitizeBengaliDate(date: {\n year: number;\n month: number;\n day: number;\n}): { year: number; month: number; day: number } | null {\n if (!isValidBengaliDate(date)) {\n return null;\n }\n return date;\n}\n","/**\n * Utility functions for Bengali calendar operations.\n *\n * This module provides helper functions for working with Bengali calendar dates,\n * including safe conversions, date arithmetic, comparisons, and formatting utilities.\n *\n * @module calendar/utils\n */\n\nimport { toBengali } from './toBengali';\nimport { fromBengali } from './fromBengali';\nimport { getBengaliDate } from './getBengaliDate';\nimport { isValidBengaliDate, isValidBengaliYear, isValidBengaliMonth } from './validate';\n\n/**\n * Safely converts a Gregorian date to Bengali date with fallback.\n *\n * Unlike toBengali, this function doesn't throw on invalid dates.\n * Returns a fallback date object for invalid inputs.\n *\n * @param date - Gregorian Date object\n * @param fallback - Fallback value if conversion fails\n * @returns Bengali date object or fallback\n *\n * @example\n * Valid dates:\n * ```typescript\n * const bengaliDate = safeToBengali(new Date(2024, 0, 15));\n * // { year: 1430, month: 10, day: 2 }\n * ```\n *\n * @example\n * Invalid dates with fallback:\n * ```typescript\n * safeToBengali(new Date('invalid'), { year: 1431, month: 1, day: 1 });\n * // { year: 1431, month: 1, day: 1 }\n *\n * safeToBengali(null as any, { year: 1431, month: 1, day: 1 });\n * // { year: 1431, month: 1, day: 1 }\n * ```\n *\n * @example\n * Default fallback (current Bengali date):\n * ```typescript\n * safeToBengali(new Date('invalid'));\n * // Returns current Bengali date\n * ```\n */\nexport function safeToBengali(\n date: Date,\n fallback?: { year: number; month: number; day: number }\n): { year: number; month: number; day: number } {\n try {\n if (!(date instanceof Date) || isNaN(date.getTime())) {\n return fallback || toBengali(new Date());\n }\n return toBengali(date);\n } catch {\n return fallback || toBengali(new Date());\n }\n}\n\n/**\n * Safely converts a Bengali date to Gregorian date with fallback.\n *\n * Unlike fromBengali, this function doesn't throw on invalid dates.\n * Returns a fallback Date object for invalid inputs.\n *\n * @param bengaliDate - Bengali date object with year, month, day\n * @param fallback - Fallback Date if conversion fails (default: current date)\n * @returns Gregorian Date object or fallback\n *\n * @example\n * Valid conversions:\n * ```typescript\n * safeFromBengali({ year: 1431, month: 1, day: 1 });\n * // Date object for 2024-04-14\n * ```\n *\n * @example\n * Invalid dates with fallback:\n * ```typescript\n * const fallbackDate = new Date(2024, 0, 1);\n * safeFromBengali({ year: 1431, month: 13, day: 1 }, fallbackDate);\n * // Returns fallbackDate\n *\n * safeFromBengali({ year: 0, month: 1, day: 1 }, fallbackDate);\n * // Returns fallbackDate\n * ```\n */\nexport function safeFromBengali(\n bengaliDate: { year: number; month: number; day: number },\n fallback?: Date\n): Date {\n try {\n if (!isValidBengaliDate(bengaliDate)) {\n return fallback || new Date();\n }\n return fromBengali(bengaliDate);\n } catch {\n return fallback || new Date();\n }\n}\n\n/**\n * Gets the number of days in a Bengali month.\n *\n * Bengali calendar month lengths:\n * - Months 1-5: 31 days\n * - Months 6-10: 30 days\n * - Month 11: 29 or 30 days (depends on leap year)\n * - Month 12: 30 days\n *\n * @param month - Bengali month (1-12)\n * @param year - Bengali year (for leap year calculation)\n * @returns Number of days in the month, or 0 if invalid\n *\n * @example\n * First five months (31 days):\n * ```typescript\n * getBengaliMonthDays(1, 1431); // 31 (Boishakh)\n * getBengaliMonthDays(2, 1431); // 31 (Joishtho)\n * getBengaliMonthDays(5, 1431); // 31 (Bhadro)\n * ```\n *\n * @example\n * Months 6-10 and 12 (30 days):\n * ```typescript\n * getBengaliMonthDays(6, 1431); // 30 (Ashwin)\n * getBengaliMonthDays(10, 1431); // 30 (Magh)\n * getBengaliMonthDays(12, 1431); // 30 (Chaitra)\n * ```\n *\n * @example\n * Falgun (month 11) - leap year handling:\n * ```typescript\n * getBengaliMonthDays(11, 1427); // 30 (2020 is leap year)\n * getBengaliMonthDays(11, 1428); // 29 (2021 is not leap year)\n * ```\n *\n * @example\n * Invalid inputs:\n * ```typescript\n * getBengaliMonthDays(0, 1431); // 0\n * getBengaliMonthDays(13, 1431); // 0\n * ```\n */\nexport function getBengaliMonthDays(month: number, year: number): number {\n if (!isValidBengaliMonth(month) || !isValidBengaliYear(year)) {\n return 0;\n }\n\n const monthLengths = getBengaliMonthLengths(year);\n return monthLengths[month - 1];\n}\n\n/**\n * Adds days to a Bengali date.\n *\n * This function properly handles month and year boundaries, including\n * varying month lengths and leap years.\n *\n * @param bengaliDate - Starting Bengali date\n * @param days - Number of days to add (can be negative to subtract)\n * @returns New Bengali date object\n *\n * @example\n * Adding days within same month:\n * ```typescript\n * addDaysToBengaliDate({ year: 1431, month: 1, day: 10 }, 5);\n * // { year: 1431, month: 1, day: 15 }\n * ```\n *\n * @example\n * Adding days across months:\n * ```typescript\n * addDaysToBengaliDate({ year: 1431, month: 1, day: 30 }, 5);\n * // { year: 1431, month: 2, day: 4 } (crosses to Joishtho)\n * ```\n *\n * @example\n * Adding days across years:\n * ```typescript\n * addDaysToBengaliDate({ year: 1431, month: 12, day: 29 }, 5);\n * // { year: 1432, month: 1, day: 3 } (crosses to new year)\n * ```\n *\n * @example\n * Subtracting days:\n * ```typescript\n * addDaysToBengaliDate({ year: 1431, month: 2, day: 5 }, -10);\n * // { year: 1431, month: 1, day: 26 }\n * ```\n */\nexport function addDaysToBengaliDate(\n bengaliDate: { year: number; month: number; day: number },\n days: number\n): { year: number; month: number; day: number } {\n if (!isValidBengaliDate(bengaliDate)) {\n throw new Error('Invalid Bengali date');\n }\n\n // Convert to Gregorian, add days, convert back\n const gregorianDate = fromBengali(bengaliDate);\n const newDate = new Date(gregorianDate.getTime() + days * 86400000);\n return toBengali(newDate);\n}\n\n/**\n * Calculates the difference in days between two Bengali dates.\n *\n * The result is positive if the second date is later, negative if earlier.\n *\n * @param date1 - First Bengali date\n * @param date2 - Second Bengali date\n * @returns Number of days between dates (date2 - date1)\n *\n * @example\n * Difference within same month:\n * ```typescript\n * const diff = getBengaliDateDifference(\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 15 }\n * );\n * // 5\n * ```\n *\n * @example\n * Difference across months:\n * ```typescript\n * const diff = getBengaliDateDifference(\n * { year: 1431, month: 1, day: 1 },\n * { year: 1431, month: 2, day: 1 }\n * );\n * // 31 (Boishakh has 31 days)\n * ```\n *\n * @example\n * Negative difference (earlier date):\n * ```typescript\n * const diff = getBengaliDateDifference(\n * { year: 1431, month: 1, day: 15 },\n * { year: 1431, month: 1, day: 10 }\n * );\n * // -5\n * ```\n *\n * @example\n * Across years:\n * ```typescript\n * const diff = getBengaliDateDifference(\n * { year: 1431, month: 1, day: 1 },\n * { year: 1432, month: 1, day: 1 }\n * );\n * // 366 (days in Bengali year 1431)\n * ```\n */\nexport function getBengaliDateDifference(\n date1: { year: number; month: number; day: number },\n date2: { year: number; month: number; day: number }\n): number {\n if (!isValidBengaliDate(date1) || !isValidBengaliDate(date2)) {\n throw new Error('Invalid Bengali date');\n }\n\n const gregorian1 = fromBengali(date1);\n const gregorian2 = fromBengali(date2);\n\n return Math.floor((gregorian2.getTime() - gregorian1.getTime()) / 86400000);\n}\n\n/**\n * Compares two Bengali dates.\n *\n * @param date1 - First Bengali date\n * @param date2 - Second Bengali date\n * @returns -1 if date1 < date2, 0 if equal, 1 if date1 > date2\n *\n * @example\n * First date is earlier:\n * ```typescript\n * compareBengaliDates(\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 15 }\n * ); // -1\n * ```\n *\n * @example\n * Dates are equal:\n * ```typescript\n * compareBengaliDates(\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 10 }\n * ); // 0\n * ```\n *\n * @example\n * First date is later:\n * ```typescript\n * compareBengaliDates(\n * { year: 1431, month: 2, day: 1 },\n * { year: 1431, month: 1, day: 31 }\n * ); // 1\n * ```\n */\nexport function compareBengaliDates(\n date1: { year: number; month: number; day: number },\n date2: { year: number; month: number; day: number }\n): -1 | 0 | 1 {\n if (!isValidBengaliDate(date1) || !isValidBengaliDate(date2)) {\n throw new Error('Invalid Bengali date');\n }\n\n if (date1.year !== date2.year) {\n return date1.year < date2.year ? -1 : 1;\n }\n if (date1.month !== date2.month) {\n return date1.month < date2.month ? -1 : 1;\n }\n if (date1.day !== date2.day) {\n return date1.day < date2.day ? -1 : 1;\n }\n return 0;\n}\n\n/**\n * Checks if a Bengali date is in a range (inclusive).\n *\n * @param date - Bengali date to check\n * @param start - Start of range (inclusive)\n * @param end - End of range (inclusive)\n * @returns true if date is in range, false otherwise\n *\n * @example\n * Date within range:\n * ```typescript\n * isBengaliDateInRange(\n * { year: 1431, month: 1, day: 15 },\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 20 }\n * ); // true\n * ```\n *\n * @example\n * Date on boundaries:\n * ```typescript\n * isBengaliDateInRange(\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 20 }\n * ); // true (start boundary)\n * ```\n *\n * @example\n * Date outside range:\n * ```typescript\n * isBengaliDateInRange(\n * { year: 1431, month: 2, day: 1 },\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 20 }\n * ); // false\n * ```\n */\nexport function isBengaliDateInRange(\n date: { year: number; month: number; day: number },\n start: { year: number; month: number; day: number },\n end: { year: number; month: number; day: number }\n): boolean {\n if (!isValidBengaliDate(date) || !isValidBengaliDate(start) || !isValidBengaliDate(end)) {\n return false;\n }\n\n return compareBengaliDates(date, start) >= 0 && compareBengaliDates(date, end) <= 0;\n}\n\n/**\n * Gets the first day of a Bengali month.\n *\n * @param month - Bengali month (1-12)\n * @param year - Bengali year\n * @returns Bengali date object for the first day of the month\n *\n * @example\n * ```typescript\n * getFirstDayOfBengaliMonth(1, 1431);\n * // { year: 1431, month: 1, day: 1 }\n *\n * getFirstDayOfBengaliMonth(6, 1431);\n * // { year: 1431, month: 6, day: 1 }\n * ```\n */\nexport function getFirstDayOfBengaliMonth(\n month: number,\n year: number\n): { year: number; month: number; day: number } {\n if (!isValidBengaliMonth(month) || !isValidBengaliYear(year)) {\n throw new Error('Invalid month or year');\n }\n\n return { year, month, day: 1 };\n}\n\n/**\n * Gets the last day of a Bengali month.\n *\n * @param month - Bengali month (1-12)\n * @param year - Bengali year\n * @returns Bengali date object for the last day of the month\n *\n * @example\n * Months with 31 days:\n * ```typescript\n * getLastDayOfBengaliMonth(1, 1431);\n * // { year: 1431, month: 1, day: 31 } (Boishakh)\n * ```\n *\n * @example\n * Months with 30 days:\n * ```typescript\n * getLastDayOfBengaliMonth(6, 1431);\n * // { year: 1431, month: 6, day: 30 } (Ashwin)\n * ```\n *\n * @example\n * Falgun with leap year:\n * ```typescript\n * getLastDayOfBengaliMonth(11, 1427);\n * // { year: 1427, month: 11, day: 30 } (leap year)\n *\n * getLastDayOfBengaliMonth(11, 1428);\n * // { year: 1428, month: 11, day: 29 } (non-leap year)\n * ```\n */\nexport function getLastDayOfBengaliMonth(\n month: number,\n year: number\n): { year: number; month: number; day: number } {\n if (!isValidBengaliMonth(month) || !isValidBengaliYear(year)) {\n throw new Error('Invalid month or year');\n }\n\n const days = getBengaliMonthDays(month, year);\n return { year, month, day: days };\n}\n\n/**\n * Checks if a Bengali year is a leap year.\n *\n * Bengali leap years correspond to Gregorian leap years.\n * The Bengali calendar adjusts Falgun (month 11) from 29 to 30 days in leap years.\n *\n * @param year - Bengali year\n * @returns true if leap year, false otherwise\n *\n * @example\n * Leap years:\n * ```typescript\n * isBengaliLeapYear(1427); // true (corresponds to 2020, a leap year)\n * isBengaliLeapYear(1420); // true (corresponds to 2013... wait, let me recalculate)\n * ```\n *\n * @example\n * Non-leap years:\n * ```typescript\n * isBengaliLeapYear(1428); // false (corresponds to 2021)\n * isBengaliLeapYear(1429); // false (corresponds to 2022)\n * ```\n */\nexport function isBengaliLeapYear(year: number): boolean {\n if (!isValidBengaliYear(year)) {\n return false;\n }\n\n const gregorianYear = year + 593;\n return (gregorianYear % 4 === 0 && gregorianYear % 100 !== 0) || gregorianYear % 400 === 0;\n}\n\n/**\n * Formats a Bengali date as a string with Bengali digits.\n *\n * This is a convenience wrapper around getBengaliDate.\n *\n * @param bengaliDate - Bengali date object\n * @param options - Formatting options\n * @returns Formatted Bengali date string\n *\n * @example\n * Basic formatting:\n * ```typescript\n * formatBengaliDate({ year: 1431, month: 1, day: 15 });\n * // \"১৫ বৈশাখ ১৪৩১\"\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * formatBengaliDate(\n * { year: 1431, month: 1, day: 15 },\n * { includeYear: false }\n * );\n * // \"১৫ বৈশাখ\"\n * ```\n *\n * @example\n * With weekday:\n * ```typescript\n * formatBengaliDate(\n * { year: 1431, month: 1, day: 1 },\n * { includeWeekday: true }\n * );\n * // \"রবিবার ১ বৈশাখ ১৪৩১\" (if 1 Boishakh 1431 is a Sunday)\n * ```\n */\nexport function formatBengaliDate(\n bengaliDate: { year: number; month: number; day: number },\n options?: { includeYear?: boolean; includeWeekday?: boolean }\n): string {\n if (!isValidBengaliDate(bengaliDate)) {\n throw new Error('Invalid Bengali date');\n }\n\n const gregorianDate = fromBengali(bengaliDate);\n return getBengaliDate(gregorianDate, options);\n}\n\n/**\n * Gets the current date in Bengali calendar.\n *\n * @returns Current Bengali date object\n *\n * @example\n * ```typescript\n * const today = getCurrentBengaliDate();\n * // { year: 1431, month: 9, day: 24 } (example for 2025-01-07)\n * ```\n */\nexport function getCurrentBengaliDate(): { year: number; month: number; day: number } {\n return toBengali(new Date());\n}\n\n/**\n * Batch converts an array of Gregorian dates to Bengali dates.\n *\n * @param dates - Array of Gregorian Date objects\n * @returns Array of Bengali date objects\n *\n * @example\n * ```typescript\n * const dates = [\n * new Date(2024, 3, 14),\n * new Date(2024, 3, 15),\n * new Date(2024, 3, 16)\n * ];\n * const bengaliDates = batchToBengali(dates);\n * // [\n * // { year: 1431, month: 1, day: 1 },\n * // { year: 1431, month: 1, day: 2 },\n * // { year: 1431, month: 1, day: 3 }\n * // ]\n * ```\n */\nexport function batchToBengali(dates: Date[]): Array<{ year: number; month: number; day: number }> {\n return dates.map((date) => safeToBengali(date));\n}\n\n/**\n * Gets the month lengths for a given Bengali year.\n */\nexport function getBengaliMonthLengths(year: number): number[] {\n const gregorianYear = year + 593;\n const isLeapYear =\n (gregorianYear % 4 === 0 && gregorianYear % 100 !== 0) || gregorianYear % 400 === 0;\n\n return [\n 31, // Boishakh\n 31, // Joishtho\n 31, // Asharh\n 31, // Srabon\n 31, // Bhadro\n 30, // Ashwin\n 30, // Kartik\n 30, // Agrahayan\n 30, // Poush\n 30, // Magh\n isLeapYear ? 30 : 29, // Falgun\n 30, // Chaitra\n ];\n}\n","import { getBengaliMonthLengths } from './utils';\n\n/**\n * Converts a Gregorian date to Bengali calendar date.\n *\n * This function performs accurate conversion from the Gregorian calendar\n * to the Bengali calendar (also known as Bangla calendar or Bengali calendar).\n * The Bengali calendar year is typically 593-594 years behind the Gregorian calendar.\n *\n * **Bengali Calendar System:**\n * - New Year (Pohela Boishakh): April 14 (Gregorian)\n * - 12 months with varying lengths (31, 30, or 29/30 days)\n * - Leap year adjustment in Falgun (month 11)\n *\n * **Month Names:**\n * 1. বৈশাখ (Boishakh) - 31 days\n * 2. জ্যৈষ্ঠ (Joishtho) - 31 days\n * 3. আষাঢ় (Asharh) - 31 days\n * 4. শ্রাবণ (Srabon) - 31 days\n * 5. ভাদ্র (Bhadro) - 31 days\n * 6. আশ্বিন (Ashwin) - 30 days\n * 7. কার্তিক (Kartik) - 30 days\n * 8. অগ্রহায়ণ (Agrahayan) - 30 days\n * 9. পৌষ (Poush) - 30 days\n * 10. মাঘ (Magh) - 30 days\n * 11. ফাল্গুন (Falgun) - 29 or 30 days (leap year dependent)\n * 12. চৈত্র (Chaitra) - 30 days\n *\n * @param date - Gregorian Date object to convert\n * @returns Bengali date object with year, month (1-12), and day properties\n *\n * @example\n * Bengali New Year (Pohela Boishakh):\n * ```typescript\n * toBengali(new Date(2024, 3, 14)); // April 14, 2024\n * // { year: 1431, month: 1, day: 1 }\n * ```\n *\n * @example\n * Mid-year dates:\n * ```typescript\n * toBengali(new Date(2024, 6, 15)); // July 15, 2024\n * // { year: 1431, month: 4, day: 1 } (approx - Srabon)\n *\n * toBengali(new Date(2024, 11, 31)); // December 31, 2024\n * // { year: 1431, month: 9, day: 17 } (approx - Poush)\n * ```\n *\n * @example\n * Before Bengali New Year (same Gregorian year):\n * ```typescript\n * toBengali(new Date(2024, 0, 15)); // January 15, 2024\n * // { year: 1430, month: 10, day: 2 } (approx - Magh)\n * ```\n *\n * @example\n * Practical usage:\n * ```typescript\n * const today = new Date();\n * const bengaliDate = toBengali(today);\n * console.log(`${bengaliDate.day}/${bengaliDate.month}/${bengaliDate.year}`);\n * // \"24/9/1431\" (example)\n * ```\n *\n * @example\n * Leap year handling:\n * ```typescript\n * // 2020 is a leap year, affecting Falgun (month 11)\n * toBengali(new Date(2021, 2, 14)); // March 14, 2021\n * // Month 11 (Falgun) will have 30 days in Bengali year 1427\n * ```\n */\nexport function toBengali(date: Date): {\n year: number;\n month: number;\n day: number;\n} {\n // Normalize to UTC (timezone-safe)\n const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));\n\n const gYear = d.getUTCFullYear();\n const gMonth = d.getUTCMonth() + 1; // 1–12\n const gDay = d.getUTCDate();\n\n /**\n * Fixed anchor dates (Bangladesh Govt standard)\n * These MUST stay aligned every year\n */\n const FIXED_ANCHORS = [\n { gMonth: 1, gDay: 14, bMonth: 10 }, // 1 Magh\n { gMonth: 2, gDay: 14, bMonth: 11 }, // 1 Falgun\n { gMonth: 3, gDay: 15, bMonth: 12 }, // 1 Chaitra\n { gMonth: 4, gDay: 14, bMonth: 1 }, // 1 Boishakh\n ];\n\n // Determine Bengali year\n const isBeforeBoishakh = gMonth < 4 || (gMonth === 4 && gDay < 14);\n\n const bengaliYear = gYear - (isBeforeBoishakh ? 594 : 593);\n\n // Check if today is a fixed anchor\n for (const a of FIXED_ANCHORS) {\n if (gMonth === a.gMonth && gDay === a.gDay) {\n return {\n year: bengaliYear,\n month: a.bMonth,\n day: 1,\n };\n }\n }\n\n /**\n * Find the most recent anchor before today\n */\n let anchor = FIXED_ANCHORS[3]; // default: 1 Boishakh\n let anchorYear = gYear;\n\n for (let i = FIXED_ANCHORS.length - 1; i >= 0; i--) {\n const a = FIXED_ANCHORS[i];\n if (gMonth > a.gMonth || (gMonth === a.gMonth && gDay > a.gDay)) {\n anchor = a;\n break;\n }\n }\n\n // If we're before Jan 14, anchor is previous year's Boishakh\n if (gMonth === 1 && gDay < 14) {\n anchor = FIXED_ANCHORS[3]; // Boishakh\n anchorYear--;\n }\n\n const anchorDate = new Date(Date.UTC(anchorYear, anchor.gMonth - 1, anchor.gDay));\n\n const daysSinceAnchor = Math.floor((d.getTime() - anchorDate.getTime()) / 86400000);\n\n const monthLengths = getBengaliMonthLengths(bengaliYear);\n\n let monthIndex = anchor.bMonth - 1;\n let remaining = daysSinceAnchor;\n\n while (remaining >= monthLengths[monthIndex]) {\n remaining -= monthLengths[monthIndex];\n monthIndex = (monthIndex + 1) % 12;\n }\n\n return {\n year: bengaliYear,\n month: monthIndex + 1,\n day: remaining + 1,\n };\n}\n","import { getSeasonFromMonth } from './getSeasonFromMonth';\nimport { toBengali } from '../calendar/toBengali';\n\n/**\n * Gets the Bangla season name from a Date object.\n *\n * This function determines the current Bengali season based on the Bengali month of the given date.\n * It follows the traditional Bengali calendar system which divides the year into six seasons.\n *\n * **Bengali Seasons (ঋতু):**\n * - গ্রীষ্ম (Grisshô - Summer): months 1-2 (বৈশাখ-জ্যৈষ্ঠ)\n * - বর্ষা (Bôrsha - Monsoon): months 3-5 (আষাঢ়-শ্রাবণ-ভাদ্র)\n * - শরৎ (Shôrôt - Autumn): months 6-7 (আশ্বিন-কার্তিক)\n * - হেমন্ত (Hemonto - Late Autumn): month 8 (অগ্রহায়ণ)\n * - শীত (Sheet - Winter): months 9-10 (পৌষ-মাঘ)\n * - বসন্ত (Bôshonto - Spring): months 11-12 (ফাল্গুন-চৈত্র)\n *\n * @param date - JavaScript Date object\n * @returns Bangla season name\n *\n * @example\n * Basic usage:\n * ```typescript\n * const date1 = new Date('2024-04-15'); // Bengali month 1 (Boishakh)\n * getSeason(date1); // 'গ্রীষ্ম'\n *\n * const date2 = new Date('2024-07-15'); // Bengali month 4 (Monsoon period)\n * getSeason(date2); // 'বর্ষা'\n * ```\n *\n * @example\n * All seasons throughout the year:\n * ```typescript\n * getSeason(new Date('2024-04-15')); // 'গ্রীষ্ম' (Summer - Boishakh)\n * getSeason(new Date('2024-07-15')); // 'বর্ষা' (Monsoon - Srabon)\n * getSeason(new Date('2024-10-15')); // 'শরৎ' (Autumn - Kartik)\n * getSeason(new Date('2024-11-15')); // 'হেমন্ত' (Late Autumn - Agrahayan)\n * getSeason(new Date('2024-01-07')); // 'শীত' (Winter - Poush)\n * getSeason(new Date('2024-03-15')); // 'বসন্ত' (Spring - Falgun)\n * ```\n *\n * @example\n * Current season:\n * ```typescript\n * const today = new Date();\n * const currentSeason = getSeason(today);\n * console.log(`বর্তমান ঋতু: ${currentSeason}`);\n * // Output example: \"বর্তমান ঋতু: শীত\"\n * ```\n *\n * @example\n * Season-specific content:\n * ```typescript\n * const date = new Date();\n * const season = getSeason(date);\n *\n * const greetings: Record<string, string> = {\n * 'গ্রীষ্ম': 'গ্রীষ্মের শুভেচ্ছা!',\n * 'বর্ষা': 'বর্ষার শুভেচ্ছা!',\n * 'শরৎ': 'শরতের শুভেচ্ছা!',\n * 'হেমন্ত': 'হেমন্তের শুভেচ্ছা!',\n * 'শীত': 'শীতের শুভেচ্ছা!',\n * 'বসন্ত': 'বসন্তের শুভেচ্ছা!'\n * };\n *\n * console.log(greetings[season]);\n * ```\n */\nexport function getSeason(date: Date): string {\n const bengaliDate = toBengali(date);\n return getSeasonFromMonth(bengaliDate.month);\n}\n\n","import { BANGLA_SEASONS } from '../constants';\n\n/**\n * Validates if a value is a valid month number (1-12).\n *\n * This function checks if the input is an integer between 1 and 12 (inclusive),\n * representing January through December.\n *\n * @param value - The value to validate\n * @returns true if the value is a valid month number, false otherwise\n *\n * @example\n * ```typescript\n * isValidMonth(1); // true (January)\n * isValidMonth(12); // true (December)\n * isValidMonth(6); // true (June)\n * isValidMonth(0); // false (out of range)\n * isValidMonth(13); // false (out of range)\n * isValidMonth('6'); // false (not a number)\n * isValidMonth(6.5); // false (not an integer)\n * ```\n */\nexport function isValidMonth(value: any): boolean {\n if (typeof value !== 'number') {\n return false;\n }\n\n if (!Number.isFinite(value)) {\n return false;\n }\n\n if (!Number.isInteger(value)) {\n return false;\n }\n\n return value >= 1 && value <= 12;\n}\n\n/**\n * Validates if a value is a valid Bangla season name.\n *\n * This function checks if the input is one of the six Bangla season names.\n * The check is case-sensitive and requires exact matches.\n *\n * **Valid season names:**\n * - গ্রীষ্ম (Summer)\n * - বর্ষা (Monsoon)\n * - শরৎ (Autumn)\n * - হেমন্ত (Late Autumn)\n * - শীত (Winter)\n * - বসন্ত (Spring)\n *\n * @param value - The value to validate\n * @returns true if the value is a valid Bangla season name, false otherwise\n *\n * @example\n * ```typescript\n * isValidSeasonName('গ্রীষ্ম'); // true\n * isValidSeasonName('বর্ষা'); // true\n * isValidSeasonName('বসন্ত'); // true\n * isValidSeasonName('invalid'); // false\n * isValidSeasonName(''); // false\n * isValidSeasonName(123); // false\n * ```\n */\nexport function isValidSeasonName(value: any): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n\n const trimmed = value.trim();\n\n if (trimmed === '') {\n return false;\n }\n\n return BANGLA_SEASONS.includes(trimmed as any);\n}\n\n/**\n * Validates if a value is a valid Date object for season determination.\n *\n * @param value - The value to validate\n * @returns true if the value is a valid Date object, false otherwise\n *\n * @example\n * ```typescript\n * isValidDateForSeason(new Date()); // true\n * isValidDateForSeason(new Date('2024-01-07')); // true\n * isValidDateForSeason(new Date('invalid')); // false\n * isValidDateForSeason('2024-01-07'); // false (string, not Date)\n * ```\n */\nexport function isValidDateForSeason(value: any): boolean {\n if (!(value instanceof Date)) {\n return false;\n }\n\n return !isNaN(value.getTime());\n}\n","import { BANGLA_SEASONS } from '../constants';\nimport { getSeason } from './getSeason';\nimport { getSeasonFromMonth } from './getSeasonFromMonth';\n\n/**\n * Gets all Bangla season names as an array.\n *\n * Returns the six Bangla seasons in order:\n * গ্রীষ্ম, বর্ষা, শরৎ, হেমন্ত, শীত, বসন্ত\n *\n * @returns Array of all Bangla season names\n *\n * @example\n * ```typescript\n * const seasons = getAllSeasons();\n * console.log(seasons);\n * // ['গ্রীষ্ম', 'বর্ষা', 'শরৎ', 'হেমন্ত', 'শীত', 'বসন্ত']\n *\n * // Use for dropdown/select options\n * seasons.forEach((season, index) => {\n * console.log(`${index + 1}: ${season}`);\n * });\n * ```\n */\nexport function getAllSeasons(): string[] {\n return ['গ্রীষ্ম', 'বর্ষা', 'শরৎ', 'হেমন্ত', 'শীত', 'বসন্ত'];\n}\n\n/**\n * Gets the month numbers for a given season.\n *\n * This function returns an array of month numbers (1-12) that belong to\n * the specified season in the Bengali calendar system.\n *\n * **Season to Month Mapping:**\n * - গ্রীষ্ম (Summer): months 1-2 (বৈশাখ-জ্যৈষ্ঠ)\n * - বর্ষা (Monsoon): months 3-5 (আষাঢ়-শ্রাবণ-ভাদ্র)\n * - শরৎ (Autumn): months 6-7 (আশ্বিন-কার্তিক)\n * - হেমন্ত (Late Autumn): month 8 (অগ্রহায়ণ)\n * - শীত (Winter): months 9-10 (পৌষ-মাঘ)\n * - বসন্ত (Spring): months 11-12 (ফাল্গুন-চৈত্র)\n *\n * @param seasonName - Bangla season name\n * @returns Array of month numbers for the season\n * @throws {Error} If season name is invalid\n *\n * @example\n * ```typescript\n * getSeasonMonths('গ্রীষ্ম'); // [1, 2]\n * getSeasonMonths('বর্ষা'); // [3, 4, 5]\n * getSeasonMonths('শরৎ'); // [6, 7]\n * getSeasonMonths('হেমন্ত'); // [8]\n * getSeasonMonths('শীত'); // [9, 10]\n * getSeasonMonths('বসন্ত'); // [11, 12]\n * ```\n */\nexport function getSeasonMonths(seasonName: string): number[] {\n const seasonMap: Record<string, number[]> = {\n 'গ্রীষ্ম': [1, 2],\n 'বর্ষা': [3, 4, 5],\n 'শরৎ': [6, 7],\n 'হেমন্ত': [8],\n 'শীত': [9, 10],\n 'বসন্ত': [11, 12],\n };\n\n const months = seasonMap[seasonName];\n if (!months) {\n throw new Error(`Invalid season name: ${seasonName}`);\n }\n\n return months;\n}\n\n/**\n * Gets the season index (0-5) for a given season name.\n *\n * @param seasonName - Bangla season name\n * @returns Season index (0-5), or -1 if invalid\n *\n * @example\n * ```typescript\n * getSeasonIndex('গ্রীষ্ম'); // 0\n * getSeasonIndex('বর্ষা'); // 1\n * getSeasonIndex('বসন্ত'); // 5\n * getSeasonIndex('invalid'); // -1\n * ```\n */\nexport function getSeasonIndex(seasonName: string): number {\n return BANGLA_SEASONS.indexOf(seasonName as any);\n}\n\n/**\n * Gets the season name by index (0-5).\n *\n * @param index - Season index (0-5)\n * @returns Bangla season name\n * @throws {Error} If index is out of range\n *\n * @example\n * ```typescript\n * getSeasonByIndex(0); // 'গ্রীষ্ম'\n * getSeasonByIndex(1); // 'বর্ষা'\n * getSeasonByIndex(5); // 'বসন্ত'\n * getSeasonByIndex(6); // throws Error\n * ```\n */\nexport function getSeasonByIndex(index: number): string {\n if (index < 0 || index > 5) {\n throw new Error('Season index must be between 0 and 5');\n }\n\n return BANGLA_SEASONS[index];\n}\n\n/**\n * Checks if a given month belongs to a specific season.\n *\n * @param monthNumber - Month number (1-12)\n * @param seasonName - Bangla season name\n * @returns true if the month belongs to the season, false otherwise\n *\n * @example\n * ```typescript\n * isMonthInSeason(1, 'গ্রীষ্ম'); // true\n * isMonthInSeason(3, 'বর্ষা'); // true\n * isMonthInSeason(1, 'শীত'); // false\n * ```\n */\nexport function isMonthInSeason(monthNumber: number, seasonName: string): boolean {\n if (monthNumber < 1 || monthNumber > 12) {\n return false;\n }\n\n try {\n const months = getSeasonMonths(seasonName);\n return months.includes(monthNumber);\n } catch {\n return false;\n }\n}\n\n/**\n * Gets the next season in the cycle.\n *\n * @param currentSeason - Current Bangla season name\n * @returns Next season name\n * @throws {Error} If current season name is invalid\n *\n * @example\n * ```typescript\n * getNextSeason('গ্রীষ্ম'); // 'বর্ষা'\n * getNextSeason('শীত'); // 'বসন্ত'\n * getNextSeason('বসন্ত'); // 'গ্রীষ্ম' (wraps around)\n * ```\n */\nexport function getNextSeason(currentSeason: string): string {\n const index = getSeasonIndex(currentSeason);\n if (index === -1) {\n throw new Error(`Invalid season name: ${currentSeason}`);\n }\n\n const nextIndex = (index + 1) % 6;\n return BANGLA_SEASONS[nextIndex];\n}\n\n/**\n * Gets the previous season in the cycle.\n *\n * @param currentSeason - Current Bangla season name\n * @returns Previous season name\n * @throws {Error} If current season name is invalid\n *\n * @example\n * ```typescript\n * getPreviousSeason('বর্ষা'); // 'গ্রীষ্ম'\n * getPreviousSeason('বসন্ত'); // 'শীত'\n * getPreviousSeason('গ্রীষ্ম'); // 'বসন্ত' (wraps around)\n * ```\n */\nexport function getPreviousSeason(currentSeason: string): string {\n const index = getSeasonIndex(currentSeason);\n if (index === -1) {\n throw new Error(`Invalid season name: ${currentSeason}`);\n }\n\n const prevIndex = (index - 1 + 6) % 6;\n return BANGLA_SEASONS[prevIndex];\n}\n\n/**\n * Safely gets season from a Date object with a fallback value.\n *\n * @param date - Date object\n * @param fallback - Value to return if getting season fails\n * @returns Season name or fallback value\n *\n * @example\n * ```typescript\n * safeGetSeason(new Date('2024-01-15')); // 'গ্রীষ্ম'\n * safeGetSeason(new Date('invalid'), 'N/A'); // 'N/A'\n * ```\n */\nexport function safeGetSeason(date: Date, fallback: string = ''): string {\n // Check if date is valid first\n if (!(date instanceof Date) || isNaN(date.getTime())) {\n return fallback;\n }\n\n try {\n return getSeason(date);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely gets season from a month number with a fallback value.\n *\n * @param monthNumber - Month number (1-12)\n * @param fallback - Value to return if getting season fails\n * @returns Season name or fallback value\n *\n * @example\n * ```typescript\n * safeGetSeasonFromMonth(1); // 'গ্রীষ্ম'\n * safeGetSeasonFromMonth(13, 'N/A'); // 'N/A'\n * ```\n */\nexport function safeGetSeasonFromMonth(monthNumber: number, fallback: string = ''): string {\n try {\n return getSeasonFromMonth(monthNumber);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Gets the current season based on current date.\n *\n * @returns Current Bangla season name\n *\n * @example\n * ```typescript\n * const currentSeason = getCurrentSeason();\n * console.log(`বর্তমান ঋতু: ${currentSeason}`);\n * ```\n */\nexport function getCurrentSeason(): string {\n return getSeason(new Date());\n}\n\n/**\n * Checks if two dates are in the same season.\n *\n * @param date1 - First date\n * @param date2 - Second date\n * @returns true if both dates are in the same season\n *\n * @example\n * ```typescript\n * const date1 = new Date('2024-01-15'); // গ্রীষ্ম\n * const date2 = new Date('2024-02-20'); // গ্রীষ্ম\n * const date3 = new Date('2024-03-15'); // বর্ষা\n *\n * isSameSeason(date1, date2); // true\n * isSameSeason(date1, date3); // false\n * ```\n */\nexport function isSameSeason(date1: Date, date2: Date): boolean {\n const season1 = getSeason(date1);\n const season2 = getSeason(date2);\n return season1 === season2;\n}\n\n/**\n * Gets season information including name, months, and description.\n *\n * @param seasonName - Bangla season name\n * @returns Object with season details\n * @throws {Error} If season name is invalid\n *\n * @example\n * ```typescript\n * const info = getSeasonInfo('গ্রীষ্ম');\n * console.log(info);\n * // {\n * // name: 'গ্রীষ্ম',\n * // months: [1, 2],\n * // index: 0,\n * // monthNames: ['বৈশাখ', 'জ্যৈষ্ঠ']\n * // }\n * ```\n */\nexport function getSeasonInfo(seasonName: string): {\n name: string;\n months: number[];\n index: number;\n monthNames: string[];\n} {\n const index = getSeasonIndex(seasonName);\n if (index === -1) {\n throw new Error(`Invalid season name: ${seasonName}`);\n }\n\n const months = getSeasonMonths(seasonName);\n\n const monthNameMap: Record<number, string> = {\n 1: 'বৈশাখ',\n 2: 'জ্যৈষ্ঠ',\n 3: 'আষাঢ়',\n 4: 'শ্রাবণ',\n 5: 'ভাদ্র',\n 6: 'আশ্বিন',\n 7: 'কার্তিক',\n 8: 'অগ্রহায়ণ',\n 9: 'পৌষ',\n 10: 'মাঘ',\n 11: 'ফাল্গুন',\n 12: 'চৈত্র',\n };\n\n const monthNames = months.map(m => monthNameMap[m]);\n\n return {\n name: seasonName,\n months,\n index,\n monthNames,\n };\n}\n","import { toBanglaNumber } from '../number';\n\n/**\n * Converts a positive integer to its ordinal form in Bangla.\n *\n * This function converts numbers to ordinal representations following Bangla\n * linguistic conventions. It includes special ordinal forms for numbers 1-25\n * and multiples of 10 up to 100. For other numbers, it appends the \"তম\" suffix\n * to the Bangla number.\n *\n * **Note:** Only positive integers are supported. Zero and negative numbers will throw an error.\n *\n * **Special Ordinals:** Numbers 1-25, 30, 40, 50, 60, 70, 80, 90, 100 have\n * dedicated ordinal forms (e.g., প্রথম, দ্বিতীয়, তৃতীয়, etc.)\n *\n * **General Pattern:** Other numbers use the pattern: [Bangla number] + \"তম\"\n * (e.g., ২৬তম, ৩৫তম, ১০১তম)\n *\n * @param number - The positive integer to convert (must be > 0)\n * @returns The ordinal form in Bangla\n * @throws {Error} If the number is less than 1 (zero or negative)\n *\n * @example\n * First few ordinals (special forms):\n * ```typescript\n * toOrdinal(1); // 'প্রথম' (first)\n * toOrdinal(2); // 'দ্বিতীয়' (second)\n * toOrdinal(3); // 'তৃতীয়' (third)\n * toOrdinal(4); // 'চতুর্থ' (fourth)\n * toOrdinal(5); // 'পঞ্চম' (fifth)\n * toOrdinal(10); // 'দশম' (tenth)\n * ```\n *\n * @example\n * Teen ordinals (11-20):\n * ```typescript\n * toOrdinal(11); // 'একাদশ' (eleventh)\n * toOrdinal(15); // 'পঞ্চদশ' (fifteenth)\n * toOrdinal(20); // 'বিংশ' (twentieth)\n * ```\n *\n * @example\n * Extended special forms (21-25):\n * ```typescript\n * toOrdinal(21); // 'একবিংশ'\n * toOrdinal(22); // 'দ্বাবিংশ'\n * toOrdinal(25); // 'পঞ্চবিংশ'\n * ```\n *\n * @example\n * Multiples of 10:\n * ```typescript\n * toOrdinal(30); // 'ত্রিংশ'\n * toOrdinal(50); // 'পঞ্চাশত্তম'\n * toOrdinal(100); // 'শততম'\n * ```\n *\n * @example\n * General pattern with \"তম\" suffix:\n * ```typescript\n * toOrdinal(26); // '২৬তম'\n * toOrdinal(35); // '৩৫তম'\n * toOrdinal(101); // '১০১তম'\n * toOrdinal(1000); // '১০০০তম'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * toOrdinal(0); // throws Error: Number must be greater than 0\n * toOrdinal(-5); // throws Error: Number must be greater than 0\n * ```\n *\n * @example\n * Practical usage (lists, rankings):\n * ```typescript\n * const rank = 3;\n * const ordinal = toOrdinal(rank);\n * console.log(`${ordinal} স্থান`); // 'তৃতীয় স্থান' (third place)\n *\n * const chapter = 15;\n * console.log(`${toOrdinal(chapter)} অধ্যায়`); // 'পঞ্চদশ অধ্যায়' (fifteenth chapter)\n * ```\n */\nexport function toOrdinal(number: number): string {\n if (number < 1) {\n throw new Error('Number must be greater than 0');\n }\n\n // Special cases for first few ordinals\n const specialOrdinals: Record<number, string> = {\n 1: 'প্রথম',\n 2: 'দ্বিতীয়',\n 3: 'তৃতীয়',\n 4: 'চতুর্থ',\n 5: 'পঞ্চম',\n 6: 'ষষ্ঠ',\n 7: 'সপ্তম',\n 8: 'অষ্টম',\n 9: 'নবম',\n 10: 'দশম',\n 11: 'একাদশ',\n 12: 'দ্বাদশ',\n 13: 'ত্রয়োদশ',\n 14: 'চতুর্দশ',\n 15: 'পঞ্চদশ',\n 16: 'ষোড়শ',\n 17: 'সপ্তদশ',\n 18: 'অষ্টাদশ',\n 19: 'ঊনবিংশ',\n 20: 'বিংশ',\n 21: 'একবিংশ',\n 22: 'দ্বাবিংশ',\n 23: 'ত্রয়োবিংশ',\n 24: 'চতুর্বিংশ',\n 25: 'পঞ্চবিংশ',\n 30: 'ত্রিংশ',\n 40: 'চত্বারিংশ',\n 50: 'পঞ্চাশত্তম',\n 60: 'ষষ্টিতম',\n 70: 'সপ্ততিতম',\n 80: 'অশীতিতম',\n 90: 'নবতিতম',\n 100: 'শততম',\n };\n\n if (specialOrdinals[number]) {\n return specialOrdinals[number];\n }\n\n // For other numbers, append \"তম\" (tom) suffix\n const banglaNumber = toBanglaNumber(number);\n return `${banglaNumber}তম`;\n}\n\n","/**\n * Checks if a number is valid for ordinal conversion.\n *\n * Valid ordinal numbers must be positive integers (1 or greater).\n *\n * @param value - The value to check\n * @returns true if the value is a valid positive integer for ordinals\n *\n * @example\n * ```typescript\n * isValidOrdinal(1); // true\n * isValidOrdinal(100); // true\n * isValidOrdinal(0); // false\n * isValidOrdinal(-5); // false\n * isValidOrdinal(1.5); // false\n * isValidOrdinal('5' as any); // false\n * ```\n */\nexport function isValidOrdinal(value: number): boolean {\n return typeof value === 'number' &&\n !isNaN(value) &&\n isFinite(value) &&\n Number.isInteger(value) &&\n value >= 1;\n}\n\n/**\n * Checks if a string appears to be a Bangla ordinal.\n *\n * This function checks if the string contains Bangla ordinal keywords\n * or ends with the ordinal suffix \"তম\".\n *\n * @param value - The string to check\n * @returns true if the string appears to be a Bangla ordinal\n *\n * @example\n * ```typescript\n * isBanglaOrdinal('প্রথম'); // true\n * isBanglaOrdinal('দ্বিতীয়'); // true\n * isBanglaOrdinal('২৬তম'); // true\n * isBanglaOrdinal('১০০তম'); // true\n * isBanglaOrdinal('hello'); // false\n * isBanglaOrdinal('123'); // false\n * ```\n */\nexport function isBanglaOrdinal(value: string): boolean {\n if (typeof value !== 'string' || !value.trim()) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Check for common ordinal keywords\n const ordinalKeywords = [\n 'প্রথম', 'দ্বিতীয়', 'তৃতীয়', 'চতুর্থ', 'পঞ্চম',\n 'ষষ্ঠ', 'সপ্তম', 'অষ্টম', 'নবম', 'দশম',\n 'একাদশ', 'দ্বাদশ', 'ত্রয়োদশ', 'চতুর্দশ', 'পঞ্চদশ',\n 'ষোড়শ', 'সপ্তদশ', 'অষ্টাদশ', 'ঊনবিংশ', 'বিংশ',\n 'একবিংশ', 'দ্বাবিংশ', 'ত্রয়োবিংশ', 'চতুর্বিংশ', 'পঞ্চবিংশ',\n 'ত্রিংশ', 'চত্বারিংশ', 'পঞ্চাশত্তম', 'ষষ্টিতম', 'সপ্ততিতম',\n 'অশীতিতম', 'নবতিতম', 'শততম'\n ];\n\n // Check if it's a known ordinal keyword\n if (ordinalKeywords.includes(trimmed)) {\n return true;\n }\n\n // Check if it ends with \"তম\" suffix\n return trimmed.endsWith('তম');\n}\n\n/**\n * Checks if a number has a special ordinal form.\n *\n * Returns true if the number has a dedicated ordinal word\n * (1-25, 30, 40, 50, 60, 70, 80, 90, 100).\n *\n * @param value - The number to check\n * @returns true if the number has a special ordinal form\n *\n * @example\n * ```typescript\n * hasSpecialOrdinal(1); // true (প্রথম)\n * hasSpecialOrdinal(15); // true (পঞ্চদশ)\n * hasSpecialOrdinal(100); // true (শততম)\n * hasSpecialOrdinal(26); // false (uses ২৬তম pattern)\n * hasSpecialOrdinal(35); // false (uses ৩৫তম pattern)\n * ```\n */\nexport function hasSpecialOrdinal(value: number): boolean {\n if (!isValidOrdinal(value)) {\n return false;\n }\n\n const specialNumbers = [\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n 21, 22, 23, 24, 25,\n 30, 40, 50, 60, 70, 80, 90, 100\n ];\n\n return specialNumbers.includes(value);\n}\n\n/**\n * Sanitizes ordinal input to ensure it's a valid positive integer.\n *\n * This function:\n * - Converts string numbers to integers\n * - Rounds decimal numbers to integers\n * - Returns null for invalid inputs\n *\n * @param value - The input value to sanitize\n * @returns Sanitized positive integer or null if invalid\n *\n * @example\n * ```typescript\n * sanitizeOrdinalInput('5'); // 5\n * sanitizeOrdinalInput(3.7); // 4\n * sanitizeOrdinalInput(3.2); // 3\n * sanitizeOrdinalInput('invalid'); // null\n * sanitizeOrdinalInput(-5); // null\n * sanitizeOrdinalInput(0); // null\n * ```\n */\nexport function sanitizeOrdinalInput(value: any): number | null {\n // Try to convert string to number\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') {\n return null;\n }\n const parsed = Number(trimmed);\n if (isNaN(parsed)) {\n return null;\n }\n value = parsed;\n }\n\n // Must be a number at this point\n if (typeof value !== 'number' || isNaN(value) || !isFinite(value)) {\n return null;\n }\n\n // Round to integer\n const rounded = Math.round(value);\n\n // Must be positive\n if (rounded < 1) {\n return null;\n }\n\n return rounded;\n}\n\n/**\n * Checks if a number is in the range for special ordinals.\n *\n * Special ordinals range from 1 to 100 (with specific numbers having\n * dedicated ordinal forms).\n *\n * @param value - The number to check\n * @returns true if the number is in the special ordinals range\n *\n * @example\n * ```typescript\n * isInSpecialOrdinalRange(1); // true\n * isInSpecialOrdinalRange(50); // true\n * isInSpecialOrdinalRange(100); // true\n * isInSpecialOrdinalRange(101); // false\n * isInSpecialOrdinalRange(0); // false\n * ```\n */\nexport function isInSpecialOrdinalRange(value: number): boolean {\n return isValidOrdinal(value) && value >= 1 && value <= 100;\n}\n","import { toOrdinal } from './toOrdinal';\nimport { isValidOrdinal, sanitizeOrdinalInput } from './validate';\n\n/**\n * Safely converts a number to ordinal with a fallback value.\n *\n * Unlike toOrdinal, this function doesn't throw errors for invalid inputs.\n * Instead, it returns the fallback value.\n *\n * @param number - The number to convert\n * @param fallback - Value to return if conversion fails (default: '')\n * @returns Ordinal string or fallback value\n *\n * @example\n * ```typescript\n * safeToOrdinal(5); // 'পঞ্চম'\n * safeToOrdinal(0); // ''\n * safeToOrdinal(-5, 'N/A'); // 'N/A'\n * safeToOrdinal(1.5, '---'); // '---'\n * ```\n */\nexport function safeToOrdinal(number: number, fallback: string = ''): string {\n try {\n if (!isValidOrdinal(number)) {\n return fallback;\n }\n return toOrdinal(number);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Converts an array of numbers to ordinals.\n *\n * This function processes multiple numbers at once, converting each to\n * its ordinal form. Invalid numbers are skipped.\n *\n * @param numbers - Array of numbers to convert\n * @returns Array of ordinal strings (invalid numbers are skipped)\n *\n * @example\n * ```typescript\n * batchToOrdinal([1, 2, 3, 4, 5]);\n * // ['প্রথম', 'দ্বিতীয়', 'তৃতীয়', 'চতুর্থ', 'পঞ্চম']\n *\n * batchToOrdinal([1, -5, 3, 0, 5]);\n * // ['প্রথম', 'তৃতীয়', 'পঞ্চম'] (invalid numbers skipped)\n *\n * batchToOrdinal([10, 20, 30]);\n * // ['দশম', 'বিংশ', 'ত্রিংশ']\n * ```\n */\nexport function batchToOrdinal(numbers: number[]): string[] {\n return numbers\n .filter(num => isValidOrdinal(num))\n .map(num => toOrdinal(num));\n}\n\n/**\n * Parses and converts input to ordinal in one step.\n *\n * This function sanitizes the input (handling strings, decimals) and\n * then converts to ordinal.\n *\n * @param value - Input value (number or string)\n * @returns Ordinal string\n * @throws {Error} If input cannot be sanitized to a valid positive integer\n *\n * @example\n * ```typescript\n * parseAndConvertToOrdinal('5'); // 'পঞ্চম'\n * parseAndConvertToOrdinal(3.7); // 'চতুর্থ' (rounds to 4)\n * parseAndConvertToOrdinal(3.2); // 'তৃতীয়' (rounds to 3)\n * parseAndConvertToOrdinal('10'); // 'দশম'\n * parseAndConvertToOrdinal('invalid'); // throws Error\n * ```\n */\nexport function parseAndConvertToOrdinal(value: any): string {\n const sanitized = sanitizeOrdinalInput(value);\n if (sanitized === null) {\n throw new Error('Invalid input for ordinal conversion');\n }\n return toOrdinal(sanitized);\n}\n\n/**\n * Gets all special ordinal numbers and their forms.\n *\n * Returns an array of objects containing the number and its ordinal form\n * for all numbers that have special ordinal representations.\n *\n * @returns Array of {number, ordinal} pairs for special ordinals\n *\n * @example\n * ```typescript\n * const specials = getSpecialOrdinals();\n * // [\n * // { number: 1, ordinal: 'প্রথম' },\n * // { number: 2, ordinal: 'দ্বিতীয়' },\n * // { number: 3, ordinal: 'তৃতীয়' },\n * // ...\n * // { number: 100, ordinal: 'শততম' }\n * // ]\n *\n * specials.forEach(({ number, ordinal }) => {\n * console.log(`${number}: ${ordinal}`);\n * });\n * ```\n */\nexport function getSpecialOrdinals(): Array<{ number: number; ordinal: string }> {\n const specialNumbers = [\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n 21, 22, 23, 24, 25,\n 30, 40, 50, 60, 70, 80, 90, 100\n ];\n\n return specialNumbers.map(number => ({\n number,\n ordinal: toOrdinal(number)\n }));\n}\n\n/**\n * Creates a sequence of ordinals from start to end (inclusive).\n *\n * @param start - Starting number (must be >= 1)\n * @param end - Ending number (must be >= start)\n * @returns Array of ordinal strings\n * @throws {Error} If start or end are invalid\n *\n * @example\n * ```typescript\n * getOrdinalSequence(1, 5);\n * // ['প্রথম', 'দ্বিতীয়', 'তৃতীয়', 'চতুর্থ', 'পঞ্চম']\n *\n * getOrdinalSequence(10, 13);\n * // ['দশম', 'একাদশ', 'দ্বাদশ', 'ত্রয়োদশ']\n *\n * getOrdinalSequence(98, 102);\n * // ['৯৮তম', '৯৯তম', 'শততম', '১০১তম', '১০২তম']\n * ```\n */\nexport function getOrdinalSequence(start: number, end: number): string[] {\n if (!isValidOrdinal(start) || !isValidOrdinal(end)) {\n throw new Error('Start and end must be positive integers');\n }\n\n if (start > end) {\n throw new Error('Start must be less than or equal to end');\n }\n\n const sequence: string[] = [];\n for (let i = start; i <= end; i++) {\n sequence.push(toOrdinal(i));\n }\n\n return sequence;\n}\n\n/**\n * Formats a number with ordinal for display.\n *\n * This function combines the number (in digits) with its ordinal form,\n * useful for rankings, positions, or lists.\n *\n * @param number - The number to format\n * @param options - Formatting options\n * @param options.separator - Separator between number and ordinal (default: ' ')\n * @param options.showNumber - Whether to show the number (default: true)\n * @returns Formatted ordinal string\n * @throws {Error} If number is invalid\n *\n * @example\n * ```typescript\n * formatOrdinal(1);\n * // '1 প্রথম'\n *\n * formatOrdinal(5, { separator: ': ' });\n * // '5: পঞ্চম'\n *\n * formatOrdinal(10, { showNumber: false });\n * // 'দশম'\n *\n * formatOrdinal(26);\n * // '26 ২৬তম'\n * ```\n */\nexport function formatOrdinal(\n number: number,\n options: {\n separator?: string;\n showNumber?: boolean;\n } = {}\n): string {\n const { separator = ' ', showNumber = true } = options;\n\n const ordinal = toOrdinal(number);\n\n if (!showNumber) {\n return ordinal;\n }\n\n return `${number}${separator}${ordinal}`;\n}\n\n/**\n * Checks if a given ordinal is in special form or suffix form.\n *\n * @param number - The number to check\n * @returns 'special' for dedicated forms, 'suffix' for \"তম\" pattern\n * @throws {Error} If number is invalid\n *\n * @example\n * ```typescript\n * getOrdinalType(1); // 'special'\n * getOrdinalType(15); // 'special'\n * getOrdinalType(100); // 'special'\n * getOrdinalType(26); // 'suffix'\n * getOrdinalType(101); // 'suffix'\n * ```\n */\nexport function getOrdinalType(number: number): 'special' | 'suffix' {\n if (!isValidOrdinal(number)) {\n throw new Error('Number must be a valid positive integer');\n }\n\n const ordinal = toOrdinal(number);\n\n // If it ends with \"তম\" and contains Bangla digits, it's a suffix form\n if (ordinal.endsWith('তম') && /[০-৯]/.test(ordinal)) {\n return 'suffix';\n }\n\n return 'special';\n}\n\n/**\n * Gets the ordinal for a ranking or position.\n *\n * This is a convenience function specifically designed for rankings,\n * competitions, or lists.\n *\n * @param position - The position/rank (1-based)\n * @param suffix - Optional suffix to append (e.g., 'স্থান', 'পুরস্কার')\n * @returns Formatted ranking string\n * @throws {Error} If position is invalid\n *\n * @example\n * ```typescript\n * getRanking(1); // 'প্রথম'\n * getRanking(1, 'স্থান'); // 'প্রথম স্থান'\n * getRanking(3, 'পুরস্কার'); // 'তৃতীয় পুরস্কার'\n * getRanking(10, 'শ্রেণী'); // 'দশম শ্রেণী'\n * ```\n */\nexport function getRanking(position: number, suffix?: string): string {\n const ordinal = toOrdinal(position);\n\n if (suffix) {\n return `${ordinal} ${suffix}`;\n }\n\n return ordinal;\n}\n\n/**\n * Compares two numbers and returns which is earlier in ordinal sequence.\n *\n * @param num1 - First number\n * @param num2 - Second number\n * @returns -1 if num1 comes first, 1 if num2 comes first, 0 if equal\n *\n * @example\n * ```typescript\n * compareOrdinals(1, 2); // -1 (প্রথম comes before দ্বিতীয়)\n * compareOrdinals(5, 3); // 1 (পঞ্চম comes after তৃতীয়)\n * compareOrdinals(10, 10); // 0 (same position)\n * ```\n */\nexport function compareOrdinals(num1: number, num2: number): number {\n if (!isValidOrdinal(num1) || !isValidOrdinal(num2)) {\n throw new Error('Both numbers must be valid positive integers');\n }\n\n if (num1 < num2) return -1;\n if (num1 > num2) return 1;\n return 0;\n}\n\n/**\n * Gets the next ordinal in sequence.\n *\n * @param current - Current number\n * @returns Next ordinal string\n * @throws {Error} If current is invalid\n *\n * @example\n * ```typescript\n * getNextOrdinal(1); // 'দ্বিতীয়'\n * getNextOrdinal(9); // 'দশম'\n * getNextOrdinal(99); // 'শততম'\n * getNextOrdinal(100); // '১০১তম'\n * ```\n */\nexport function getNextOrdinal(current: number): string {\n if (!isValidOrdinal(current)) {\n throw new Error('Current must be a valid positive integer');\n }\n\n return toOrdinal(current + 1);\n}\n\n/**\n * Gets the previous ordinal in sequence.\n *\n * @param current - Current number\n * @returns Previous ordinal string\n * @throws {Error} If current is invalid or if current is 1\n *\n * @example\n * ```typescript\n * getPreviousOrdinal(2); // 'প্রথম'\n * getPreviousOrdinal(10); // 'নবম'\n * getPreviousOrdinal(100); // '৯৯তম'\n * getPreviousOrdinal(1); // throws Error (no previous ordinal)\n * ```\n */\nexport function getPreviousOrdinal(current: number): string {\n if (!isValidOrdinal(current)) {\n throw new Error('Current must be a valid positive integer');\n }\n\n if (current === 1) {\n throw new Error('No previous ordinal for 1 (প্রথম is the first)');\n }\n\n return toOrdinal(current - 1);\n}\n\n/**\n * Creates an ordinal map for a list of items.\n *\n * This function is useful for adding ordinal numbers to a list of items.\n *\n * @param items - Array of items\n * @param startFrom - Starting position (default: 1)\n * @returns Array of objects with position, ordinal, and item\n *\n * @example\n * ```typescript\n * const winners = ['আলী', 'বাবলু', 'চান্দু'];\n * const ranked = createOrdinalList(winners);\n * // [\n * // { position: 1, ordinal: 'প্রথম', item: 'আলী' },\n * // { position: 2, ordinal: 'দ্বিতীয়', item: 'বাবলু' },\n * // { position: 3, ordinal: 'তৃতীয়', item: 'চান্দু' }\n * // ]\n *\n * const chapters = ['ভূমিকা', 'মূল অংশ', 'উপসংহার'];\n * const numbered = createOrdinalList(chapters);\n * numbered.forEach(({ ordinal, item }) => {\n * console.log(`${ordinal} অধ্যায়: ${item}`);\n * });\n * ```\n */\nexport function createOrdinalList<T>(\n items: T[],\n startFrom: number = 1\n): Array<{ position: number; ordinal: string; item: T }> {\n if (!isValidOrdinal(startFrom)) {\n throw new Error('startFrom must be a valid positive integer');\n }\n\n return items.map((item, index) => {\n const position = startFrom + index;\n return {\n position,\n ordinal: toOrdinal(position),\n item\n };\n });\n}\n","import { toBanglaNumber } from '../number';\n\n/**\n * Formats a time in Bangla with customizable options.\n *\n * This function converts time to Bangla digits and supports both 12-hour and 24-hour formats.\n * It can accept either a Date object or a time string in HH:mm or HH:mm:ss format.\n *\n * **12-Hour Format Periods:**\n * - রাত (night): 12:00 AM - 11:59 PM when hour is 0\n * - সকাল (morning): 1:00 AM - 11:59 AM\n * - দুপুর (noon): 12:00 PM - 12:59 PM\n * - বিকাল (afternoon/evening): 1:00 PM - 11:59 PM\n *\n * @param date - Date object or time string (HH:mm or HH:mm:ss format)\n * @param options - Formatting options\n * @param options.includeSeconds - Whether to include seconds in output (default: false)\n * @param options.use12Hour - Whether to use 12-hour format with Bangla period (default: false)\n * @returns Formatted time string in Bangla\n * @throws {Error} If time string format is invalid\n *\n * @example\n * Basic 24-hour format:\n * ```typescript\n * formatTime(new Date('2024-01-07T14:30:00')); // '১৪:৩০'\n * formatTime('14:30'); // '১৪:৩০'\n * formatTime('09:15'); // '০৯:১৫'\n * ```\n *\n * @example\n * With seconds:\n * ```typescript\n * formatTime('14:30:45', { includeSeconds: true }); // '১৪:৩০:৪৫'\n * formatTime(new Date('2024-01-07T09:15:30'), { includeSeconds: true }); // '০৯:১৫:৩০'\n * ```\n *\n * @example\n * 12-hour format with Bangla periods:\n * ```typescript\n * formatTime('09:30', { use12Hour: true }); // '০৯:৩০ সকাল'\n * formatTime('14:30', { use12Hour: true }); // '০২:৩০ বিকাল'\n * formatTime('12:00', { use12Hour: true }); // '১২:০০ দুপুর'\n * formatTime('00:00', { use12Hour: true }); // '১২:০০ রাত'\n * ```\n *\n * @example\n * Combining options:\n * ```typescript\n * formatTime('14:30:45', { use12Hour: true, includeSeconds: true }); // '০২:৩০:৪৫ বিকাল'\n * formatTime('09:15:30', { use12Hour: true, includeSeconds: true }); // '০৯:১৫:৩০ সকাল'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * formatTime('invalid'); // throws Error: Invalid time string format\n * formatTime('25:00'); // throws Error: Invalid time string format\n * formatTime('12:70'); // throws Error: Invalid time string format\n * ```\n *\n * @example\n * Real-world usage:\n * ```typescript\n * const event = {\n * name: 'Team Meeting',\n * time: new Date('2024-01-07T10:30:00')\n * };\n *\n * const formattedTime = formatTime(event.time, { use12Hour: true });\n * console.log(`${event.name}: ${formattedTime}`);\n * // Output: \"Team Meeting: ১০:৩০ সকাল\"\n * ```\n */\nexport function formatTime(\n date: Date | string,\n options: {\n includeSeconds?: boolean;\n use12Hour?: boolean;\n } = {}\n): string {\n const { includeSeconds = false, use12Hour = false } = options;\n\n let hours: number;\n let minutes: number;\n let seconds: number;\n\n if (typeof date === 'string') {\n const timeParts = date.split(':');\n hours = parseInt(timeParts[0], 10);\n minutes = parseInt(timeParts[1], 10);\n seconds = timeParts[2] ? parseInt(timeParts[2], 10) : 0;\n\n if (Number.isNaN(hours) || Number.isNaN(minutes)) {\n throw new Error('Invalid time string format. Use HH:mm or HH:mm:ss');\n }\n } else {\n hours = date.getHours();\n minutes = date.getMinutes();\n seconds = date.getSeconds();\n }\n\n let displayHours = hours;\n let period = '';\n\n if (use12Hour) {\n if (hours === 0) {\n displayHours = 12;\n period = 'রাত';\n } else if (hours < 12) {\n period = 'সকাল';\n } else if (hours === 12) {\n period = 'দুপুর';\n } else {\n displayHours = hours - 12;\n period = 'বিকাল';\n }\n }\n\n // Pad with leading zeros for consistent formatting\n const banglaHours = toBanglaNumber(displayHours.toString().padStart(2, '0'));\n const banglaMinutes = toBanglaNumber(minutes.toString().padStart(2, '0'));\n const parts: string[] = [banglaHours, banglaMinutes];\n\n if (includeSeconds) {\n const banglaSeconds = toBanglaNumber(seconds.toString().padStart(2, '0'));\n parts.push(banglaSeconds);\n }\n\n const timeString = parts.join(':');\n\n if (period) {\n return `${timeString} ${period}`;\n }\n\n return timeString;\n}\n\n","import { toBanglaNumber } from '../number';\n\n/**\n * Formats a date as relative time in Bangla.\n *\n * This function converts a date to a human-readable relative time string in Bangla,\n * such as \"৫ মিনিট আগে\" (5 minutes ago) or \"আগামীকাল\" (tomorrow).\n *\n * **Time Units (from smallest to largest):**\n * - Seconds: < 60 seconds\n * - Minutes: < 60 minutes\n * - Hours: < 24 hours\n * - Days: Named days (আজ, গতকাল, আগামীকাল, etc.) and day counts\n * - Weeks: < 30 days\n * - Months: < 365 days\n * - Years: >= 365 days\n *\n * **Special Day Names:**\n * - আজ (today): Same calendar day\n * - গতকাল (yesterday): 1 day ago\n * - আগামীকাল (tomorrow): 1 day from now\n * - গত পরশু (day before yesterday): 2 days ago\n * - পরশু (day after tomorrow): 2 days from now\n *\n * @param date - The date to format\n * @param baseDate - Base date for comparison (defaults to current date/time)\n * @returns Relative time string in Bangla\n *\n * @example\n * Immediate time:\n * ```typescript\n * const now = new Date();\n * relativeTime(now, now); // 'এখন'\n * ```\n *\n * @example\n * Recent past (seconds and minutes):\n * ```typescript\n * const now = new Date();\n * const fiveSecondsAgo = new Date(now.getTime() - 5000);\n * relativeTime(fiveSecondsAgo, now); // '৫ সেকেন্ড আগে'\n *\n * const tenMinutesAgo = new Date(now.getTime() - 10 * 60 * 1000);\n * relativeTime(tenMinutesAgo, now); // '১০ মিনিট আগে'\n * ```\n *\n * @example\n * Hours:\n * ```typescript\n * const now = new Date();\n * const twoHoursAgo = new Date(now.getTime() - 2 * 60 * 60 * 1000);\n * relativeTime(twoHoursAgo, now); // '২ ঘণ্টা আগে'\n *\n * const threeHoursLater = new Date(now.getTime() + 3 * 60 * 60 * 1000);\n * relativeTime(threeHoursLater, now); // '৩ ঘণ্টা পরে'\n * ```\n *\n * @example\n * Named days:\n * ```typescript\n * const today = new Date('2024-01-07');\n * const yesterday = new Date('2024-01-06');\n * const tomorrow = new Date('2024-01-08');\n *\n * relativeTime(yesterday, today); // 'গতকাল'\n * relativeTime(tomorrow, today); // 'আগামীকাল'\n * relativeTime(new Date('2024-01-05'), today); // 'গত পরশু'\n * relativeTime(new Date('2024-01-09'), today); // 'পরশু'\n * ```\n *\n * @example\n * Days, weeks, months:\n * ```typescript\n * const now = new Date();\n * const threeDaysAgo = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000);\n * relativeTime(threeDaysAgo, now); // '৩ দিন আগে'\n *\n * const twoWeeksAgo = new Date(now.getTime() - 14 * 24 * 60 * 60 * 1000);\n * relativeTime(twoWeeksAgo, now); // '২ সপ্তাহ আগে'\n *\n * const threeMonthsAgo = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);\n * relativeTime(threeMonthsAgo, now); // '৩ মাস আগে'\n * ```\n *\n * @example\n * Years:\n * ```typescript\n * const now = new Date();\n * const oneYearAgo = new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000);\n * relativeTime(oneYearAgo, now); // '১ বছর আগে'\n * ```\n *\n * @example\n * Real-world usage (social media post):\n * ```typescript\n * const postDate = new Date('2024-01-07T10:30:00');\n * const currentDate = new Date('2024-01-07T11:15:00');\n *\n * const timeAgo = relativeTime(postDate, currentDate);\n * console.log(`Posted ${timeAgo}`); // \"Posted ৪৫ মিনিট আগে\"\n * ```\n */\nexport function relativeTime(\n date: Date,\n baseDate: Date = new Date()\n): string {\n const diffMs = date.getTime() - baseDate.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const absDiffHours = Math.abs(diffHours);\n\n // Check if dates are on the same calendar day\n const baseDay = new Date(baseDate);\n baseDay.setHours(0, 0, 0, 0);\n const targetDay = new Date(date);\n targetDay.setHours(0, 0, 0, 0);\n const diffDays = Math.floor(\n (targetDay.getTime() - baseDay.getTime()) / (1000 * 60 * 60 * 24)\n );\n\n // If time difference is less than 24 hours, prioritize hours/minutes/seconds\n // over day names (even if it crosses a day boundary)\n if (absDiffHours < 24) {\n if (diffSeconds === 0) {\n return 'এখন';\n }\n\n if (Math.abs(diffSeconds) < 60) {\n if (diffSeconds < 0) {\n return `${toBanglaNumber(Math.abs(diffSeconds))} সেকেন্ড আগে`;\n } else {\n return `${toBanglaNumber(diffSeconds)} সেকেন্ড পরে`;\n }\n }\n\n if (Math.abs(diffMinutes) < 60) {\n if (diffMinutes < 0) {\n return `${toBanglaNumber(Math.abs(diffMinutes))} মিনিট আগে`;\n } else {\n return `${toBanglaNumber(diffMinutes)} মিনিট পরে`;\n }\n }\n\n if (diffHours < 0) {\n return `${toBanglaNumber(Math.abs(diffHours))} ঘণ্টা আগে`;\n } else {\n return `${toBanglaNumber(diffHours)} ঘণ্টা পরে`;\n }\n }\n\n // Yesterday/Tomorrow\n if (diffDays === -1) {\n return 'গতকাল';\n }\n\n if (diffDays === 1) {\n return 'আগামীকাল';\n }\n\n // Day before yesterday / Day after tomorrow\n if (diffDays === -2) {\n return 'গত পরশু';\n }\n\n if (diffDays === 2) {\n return 'পরশু';\n }\n\n // Days ago/from now\n if (diffDays < 0) {\n if (Math.abs(diffDays) < 7) {\n return `${toBanglaNumber(Math.abs(diffDays))} দিন আগে`;\n } else if (Math.abs(diffDays) < 30) {\n const weeks = Math.floor(Math.abs(diffDays) / 7);\n return `${toBanglaNumber(weeks)} সপ্তাহ আগে`;\n } else if (Math.abs(diffDays) < 365) {\n const months = Math.floor(Math.abs(diffDays) / 30);\n return `${toBanglaNumber(months)} মাস আগে`;\n } else {\n const years = Math.floor(Math.abs(diffDays) / 365);\n return `${toBanglaNumber(years)} বছর আগে`;\n }\n } else {\n if (diffDays < 7) {\n return `${toBanglaNumber(diffDays)} দিন পরে`;\n } else if (diffDays < 30) {\n const weeks = Math.floor(diffDays / 7);\n return `${toBanglaNumber(weeks)} সপ্তাহ পরে`;\n } else if (diffDays < 365) {\n const months = Math.floor(diffDays / 30);\n return `${toBanglaNumber(months)} মাস পরে`;\n } else {\n const years = Math.floor(diffDays / 365);\n return `${toBanglaNumber(years)} বছর পরে`;\n }\n }\n}\n\n/**\n * Gets relative day names in Bangla.\n *\n * This function returns special Bangla day names for dates within a 2-day range\n * from the base date. Returns an empty string for dates outside this range.\n *\n * **Supported Day Names:**\n * - আজ (today): Same calendar day\n * - গতকাল (yesterday): 1 day before\n * - আগামীকাল (tomorrow): 1 day after\n * - গত পরশু (day before yesterday): 2 days before\n * - পরশু (day after tomorrow): 2 days after\n *\n * @param date - The date to check\n * @param baseDate - Base date for comparison (defaults to current date)\n * @returns Day name in Bangla, or empty string if outside range\n *\n * @example\n * Basic usage:\n * ```typescript\n * const today = new Date('2024-01-07');\n *\n * relativeDay(today, today); // 'আজ'\n * relativeDay(new Date('2024-01-06'), today); // 'গতকাল'\n * relativeDay(new Date('2024-01-08'), today); // 'আগামীকাল'\n * relativeDay(new Date('2024-01-05'), today); // 'গত পরশু'\n * relativeDay(new Date('2024-01-09'), today); // 'পরশু'\n * ```\n *\n * @example\n * Outside range:\n * ```typescript\n * const today = new Date('2024-01-07');\n * relativeDay(new Date('2024-01-04'), today); // '' (3 days ago, outside range)\n * relativeDay(new Date('2024-01-10'), today); // '' (3 days from now, outside range)\n * ```\n *\n * @example\n * Calendar widget usage:\n * ```typescript\n * const dates = [\n * new Date('2024-01-05'),\n * new Date('2024-01-06'),\n * new Date('2024-01-07'),\n * new Date('2024-01-08'),\n * new Date('2024-01-09'),\n * ];\n *\n * const today = new Date('2024-01-07');\n * dates.forEach(date => {\n * const dayName = relativeDay(date, today);\n * console.log(dayName || date.toLocaleDateString());\n * });\n * // Output:\n * // \"গত পরশু\"\n * // \"গতকাল\"\n * // \"আজ\"\n * // \"আগামীকাল\"\n * // \"পরশু\"\n * ```\n */\nexport function relativeDay(\n date: Date,\n baseDate: Date = new Date()\n): string {\n const today = new Date(baseDate);\n today.setHours(0, 0, 0, 0);\n\n const targetDate = new Date(date);\n targetDate.setHours(0, 0, 0, 0);\n\n const diffDays = Math.floor(\n (targetDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)\n );\n\n if (diffDays === 0) {\n return 'আজ';\n } else if (diffDays === -1) {\n return 'গতকাল';\n } else if (diffDays === 1) {\n return 'আগামীকাল';\n } else if (diffDays === -2) {\n return 'গত পরশু';\n } else if (diffDays === 2) {\n return 'পরশু';\n }\n\n return '';\n}\n\n\n","import { isValidDate } from '../date/validate';\n\n/**\n * Validates if a string represents a valid time format.\n *\n * This function checks if the input is a valid time string in HH:mm or HH:mm:ss format.\n * It validates both the format and the actual time values (hours 0-23, minutes/seconds 0-59).\n *\n * @param value - The value to validate\n * @returns true if the value is a valid time string, false otherwise\n *\n * @example\n * ```typescript\n * isValidTimeString('14:30'); // true\n * isValidTimeString('09:15:45'); // true\n * isValidTimeString('23:59'); // true\n * isValidTimeString('00:00'); // true\n * isValidTimeString('24:00'); // false (hour out of range)\n * isValidTimeString('12:60'); // false (minute out of range)\n * isValidTimeString('invalid'); // false\n * isValidTimeString('12'); // false (missing minutes)\n * ```\n */\nexport function isValidTimeString(value: any): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n\n const trimmed = value.trim();\n\n if (trimmed === '') {\n return false;\n }\n\n // Match HH:mm or HH:mm:ss format\n const timePattern = /^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/;\n const match = trimmed.match(timePattern);\n\n if (!match) {\n return false;\n }\n\n const hours = parseInt(match[1], 10);\n const minutes = parseInt(match[2], 10);\n const seconds = match[3] ? parseInt(match[3], 10) : 0;\n\n // Validate ranges\n if (hours < 0 || hours > 23) {\n return false;\n }\n\n if (minutes < 0 || minutes > 59) {\n return false;\n }\n\n if (seconds < 0 || seconds > 59) {\n return false;\n }\n\n return true;\n}\n\n// isValidDate is imported from date/validate for internal use\n// and re-exported to maintain API compatibility\nexport { isValidDate };\n\n/**\n * Validates if a value can be used for time formatting.\n *\n * This function checks if the input is either a valid Date object or a valid time string.\n *\n * @param value - The value to validate\n * @returns true if the value can be formatted as time, false otherwise\n *\n * @example\n * ```typescript\n * isValidTimeInput(new Date()); // true\n * isValidTimeInput('14:30'); // true\n * isValidTimeInput('09:15:45'); // true\n * isValidTimeInput('invalid'); // false\n * isValidTimeInput(123); // false\n * ```\n */\nexport function isValidTimeInput(value: any): boolean {\n return isValidDate(value) || isValidTimeString(value);\n}\n\n/**\n * Validates if a time string has seconds component.\n *\n * @param timeString - The time string to check\n * @returns true if the time string includes seconds, false otherwise\n *\n * @example\n * ```typescript\n * hasSeconds('14:30:45'); // true\n * hasSeconds('14:30'); // false\n * ```\n */\nexport function hasSeconds(timeString: string): boolean {\n if (!isValidTimeString(timeString)) {\n return false;\n }\n\n const parts = timeString.trim().split(':');\n return parts.length === 3;\n}\n\n/**\n * Sanitizes time string input by trimming whitespace.\n *\n * @param input - The time string to sanitize\n * @returns Sanitized time string\n *\n * @example\n * ```typescript\n * sanitizeTimeInput(' 14:30 '); // '14:30'\n * sanitizeTimeInput('09:15:45 '); // '09:15:45'\n * ```\n */\nexport function sanitizeTimeInput(input: string): string {\n if (typeof input !== 'string') {\n return '';\n }\n\n return input.trim();\n}\n","import { formatTime } from './formatTime';\nimport { relativeTime } from './relativeTime';\nimport { sanitizeTimeInput } from './validate';\n\n/**\n * Parses a time string and returns hours, minutes, and seconds.\n *\n * @param timeString - Time string in HH:mm or HH:mm:ss format\n * @returns Object with hours, minutes, and seconds\n * @throws Error if the time string is invalid\n *\n * @example\n * ```typescript\n * parseTime('14:30'); // { hours: 14, minutes: 30, seconds: 0 }\n * parseTime('09:15:45'); // { hours: 9, minutes: 15, seconds: 45 }\n * parseTime('23:59:59'); // { hours: 23, minutes: 59, seconds: 59 }\n * ```\n */\nexport function parseTime(timeString: string): {\n hours: number;\n minutes: number;\n seconds: number;\n} {\n const sanitized = sanitizeTimeInput(timeString);\n const timeParts = sanitized.split(':');\n\n const hours = parseInt(timeParts[0], 10);\n const minutes = parseInt(timeParts[1], 10);\n const seconds = timeParts[2] ? parseInt(timeParts[2], 10) : 0;\n\n if (Number.isNaN(hours) || Number.isNaN(minutes)) {\n throw new Error('Invalid time string format. Use HH:mm or HH:mm:ss');\n }\n\n if (hours < 0 || hours > 23) {\n throw new Error('Hours must be between 0 and 23');\n }\n\n if (minutes < 0 || minutes > 59) {\n throw new Error('Minutes must be between 0 and 59');\n }\n\n if (seconds < 0 || seconds > 59) {\n throw new Error('Seconds must be between 0 and 59');\n }\n\n return { hours, minutes, seconds };\n}\n\n/**\n * Converts a time string to total seconds since midnight.\n *\n * @param timeString - Time string in HH:mm or HH:mm:ss format\n * @returns Total seconds since midnight\n *\n * @example\n * ```typescript\n * timeToSeconds('01:00'); // 3600\n * timeToSeconds('01:30'); // 5400\n * timeToSeconds('12:00:00'); // 43200\n * ```\n */\nexport function timeToSeconds(timeString: string): number {\n const { hours, minutes, seconds } = parseTime(timeString);\n return hours * 3600 + minutes * 60 + seconds;\n}\n\n/**\n * Converts seconds since midnight to a time string.\n *\n * @param totalSeconds - Total seconds since midnight\n * @returns Time string in HH:mm:ss format\n *\n * @example\n * ```typescript\n * secondsToTime(3600); // '01:00:00'\n * secondsToTime(5400); // '01:30:00'\n * secondsToTime(43200); // '12:00:00'\n * ```\n */\nexport function secondsToTime(totalSeconds: number): string {\n if (totalSeconds < 0 || totalSeconds >= 86400) {\n throw new Error('Seconds must be between 0 and 86399');\n }\n\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds\n .toString()\n .padStart(2, '0')}`;\n}\n\n/**\n * Compares two time strings and returns -1, 0, or 1.\n *\n * @param time1 - First time string\n * @param time2 - Second time string\n * @returns -1 if time1 < time2, 0 if equal, 1 if time1 > time2\n *\n * @example\n * ```typescript\n * compareTimes('09:00', '10:00'); // -1\n * compareTimes('14:30', '14:30'); // 0\n * compareTimes('18:00', '12:00'); // 1\n * ```\n */\nexport function compareTimes(time1: string, time2: string): number {\n const seconds1 = timeToSeconds(time1);\n const seconds2 = timeToSeconds(time2);\n\n if (seconds1 < seconds2) return -1;\n if (seconds1 > seconds2) return 1;\n return 0;\n}\n\n/**\n * Checks if a time string falls within a given time range.\n *\n * @param time - Time to check\n * @param startTime - Start of range (inclusive)\n * @param endTime - End of range (inclusive)\n * @returns true if time is within range, false otherwise\n *\n * @example\n * ```typescript\n * isTimeInRange('10:00', '09:00', '11:00'); // true\n * isTimeInRange('08:00', '09:00', '11:00'); // false\n * isTimeInRange('09:00', '09:00', '11:00'); // true (inclusive)\n * ```\n */\nexport function isTimeInRange(time: string, startTime: string, endTime: string): boolean {\n const timeSeconds = timeToSeconds(time);\n const startSeconds = timeToSeconds(startTime);\n const endSeconds = timeToSeconds(endTime);\n\n return timeSeconds >= startSeconds && timeSeconds <= endSeconds;\n}\n\n/**\n * Adds a duration (in minutes) to a time string.\n *\n * @param timeString - Starting time\n * @param minutes - Minutes to add (can be negative to subtract)\n * @returns New time string\n *\n * @example\n * ```typescript\n * addMinutesToTime('10:00', 30); // '10:30:00'\n * addMinutesToTime('10:30', 45); // '11:15:00'\n * addMinutesToTime('10:00', -15); // '09:45:00'\n * ```\n */\nexport function addMinutesToTime(timeString: string, minutes: number): string {\n const totalSeconds = timeToSeconds(timeString);\n let newSeconds = totalSeconds + minutes * 60;\n\n // Handle wraparound for negative times or times beyond 24 hours\n newSeconds = ((newSeconds % 86400) + 86400) % 86400;\n\n return secondsToTime(newSeconds);\n}\n\n/**\n * Calculates the difference in minutes between two times.\n *\n * @param time1 - First time string\n * @param time2 - Second time string\n * @returns Difference in minutes (time2 - time1)\n *\n * @example\n * ```typescript\n * timeDifferenceMinutes('09:00', '10:30'); // 90\n * timeDifferenceMinutes('10:30', '09:00'); // -90\n * timeDifferenceMinutes('09:00', '09:00'); // 0\n * ```\n */\nexport function timeDifferenceMinutes(time1: string, time2: string): number {\n const seconds1 = timeToSeconds(time1);\n const seconds2 = timeToSeconds(time2);\n return Math.floor((seconds2 - seconds1) / 60);\n}\n\n/**\n * Safely formats time with a fallback value.\n *\n * @param date - Date or time string to format\n * @param options - Formatting options\n * @param fallback - Value to return if formatting fails\n * @returns Formatted time or fallback value\n *\n * @example\n * ```typescript\n * safeFormatTime(new Date(), { use12Hour: true }); // '১০:৩০ সকাল'\n * safeFormatTime('invalid', {}, '---'); // '---'\n * ```\n */\nexport function safeFormatTime(\n date: Date | string,\n options: { includeSeconds?: boolean; use12Hour?: boolean } = {},\n fallback: string = ''\n): string {\n try {\n return formatTime(date, options);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely gets relative time with a fallback value.\n *\n * @param date - Date to format\n * @param baseDate - Base date for comparison\n * @param fallback - Value to return if formatting fails\n * @returns Relative time string or fallback value\n *\n * @example\n * ```typescript\n * const now = new Date();\n * safeRelativeTime(now); // 'এখন'\n * safeRelativeTime(new Date('invalid'), now, 'N/A'); // 'N/A'\n * ```\n */\nexport function safeRelativeTime(\n date: Date,\n baseDate: Date = new Date(),\n fallback: string = ''\n): string {\n try {\n return relativeTime(date, baseDate);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Gets the time of day period in Bangla.\n *\n * This function returns the appropriate Bangla time period based on the hour:\n * - রাত (night): 00:00 - 05:59\n * - সকাল (morning): 06:00 - 11:59\n * - দুপুর (afternoon/noon): 12:00 - 14:59\n * - বিকাল (evening): 15:00 - 17:59\n * - সন্ধ্যা (dusk): 18:00 - 19:59\n * - রাত (night): 20:00 - 23:59\n *\n * @param date - Date object or time string\n * @returns Time period in Bangla\n *\n * @example\n * ```typescript\n * getTimePeriod('08:00'); // 'সকাল'\n * getTimePeriod('14:30'); // 'দুপুর'\n * getTimePeriod('18:00'); // 'সন্ধ্যা'\n * getTimePeriod('22:00'); // 'রাত'\n * ```\n */\nexport function getTimePeriod(date: Date | string): string {\n let hours: number;\n\n if (typeof date === 'string') {\n const { hours: h } = parseTime(date);\n hours = h;\n } else {\n hours = date.getHours();\n }\n\n if (hours >= 0 && hours < 6) {\n return 'রাত';\n } else if (hours >= 6 && hours < 12) {\n return 'সকাল';\n } else if (hours >= 12 && hours < 15) {\n return 'দুপুর';\n } else if (hours >= 15 && hours < 18) {\n return 'বিকাল';\n } else if (hours >= 18 && hours < 20) {\n return 'সন্ধ্যা';\n } else {\n return 'রাত';\n }\n}\n\n/**\n * Gets current time in Bangla format.\n *\n * @param options - Formatting options\n * @returns Current time in Bangla\n *\n * @example\n * ```typescript\n * getCurrentTimeBangla(); // '১৪:৩০'\n * getCurrentTimeBangla({ use12Hour: true }); // '০২:৩০ দুপুর'\n * getCurrentTimeBangla({ includeSeconds: true }); // '১৪:৩০:৪৫'\n * ```\n */\nexport function getCurrentTimeBangla(\n options: { includeSeconds?: boolean; use12Hour?: boolean } = {}\n): string {\n return formatTime(new Date(), options);\n}\n\n/**\n * Checks if two dates are on the same day.\n *\n * @param date1 - First date\n * @param date2 - Second date\n * @returns true if both dates are on the same calendar day\n *\n * @example\n * ```typescript\n * const date1 = new Date('2024-01-07T10:00:00');\n * const date2 = new Date('2024-01-07T15:00:00');\n * isSameDay(date1, date2); // true\n *\n * const date3 = new Date('2024-01-08T10:00:00');\n * isSameDay(date1, date3); // false\n * ```\n */\nexport function isSameDay(date1: Date, date2: Date): boolean {\n return (\n date1.getFullYear() === date2.getFullYear() &&\n date1.getMonth() === date2.getMonth() &&\n date1.getDate() === date2.getDate()\n );\n}\n","import { toBanglaNumber } from '../number';\n\n/**\n * Formats a Bangladeshi phone number with various formatting options.\n *\n * This function takes a Bangladeshi phone number in any valid format and\n * returns it formatted according to the specified options. It supports\n * different formatting styles, country code inclusion, and Bangla digit conversion.\n *\n * **Format Options:**\n * - `spaced` (default): 017 1234 5678\n * - `dashed`: 017-1234-5678\n * - `compact`: 01712345678\n *\n * @param phoneNumber - Phone number to format (with or without country code)\n * @param options - Formatting options\n * @param options.includeCountryCode - Add +880 country code (default: false)\n * @param options.useBanglaDigits - Convert digits to Bangla numerals (default: false)\n * @param options.format - Format style: 'spaced', 'dashed', or 'compact' (default: 'spaced')\n * @returns Formatted phone number\n * @throws {Error} If phone number has invalid length\n *\n * @example\n * Basic formatting (default spaced format):\n * ```typescript\n * formatPhone('01712345678');\n * // '017 1234 5678'\n *\n * formatPhone('+8801712345678');\n * // '017 1234 5678'\n *\n * formatPhone('017 1234 5678');\n * // '017 1234 5678'\n * ```\n *\n * @example\n * Different format styles:\n * ```typescript\n * formatPhone('01712345678', { format: 'dashed' });\n * // '017-1234-5678'\n *\n * formatPhone('01712345678', { format: 'compact' });\n * // '01712345678'\n *\n * formatPhone('01712345678', { format: 'spaced' });\n * // '017 1234 5678'\n * ```\n *\n * @example\n * With country code:\n * ```typescript\n * formatPhone('01712345678', { includeCountryCode: true });\n * // '+880 017 1234 5678'\n *\n * formatPhone('01712345678', {\n * includeCountryCode: true,\n * format: 'dashed'\n * });\n * // '+880 017-1234-5678'\n * ```\n *\n * @example\n * With Bangla digits:\n * ```typescript\n * formatPhone('01712345678', { useBanglaDigits: true });\n * // '০১৭ ১২৩৪ ৫৬৭৮'\n *\n * formatPhone('01712345678', {\n * useBanglaDigits: true,\n * format: 'dashed'\n * });\n * // '০১৭-১২৩৪-৫৬৭৮'\n *\n * formatPhone('01712345678', {\n * useBanglaDigits: true,\n * includeCountryCode: true\n * });\n * // '+৮৮০ ০১৭ ১২৩৪ ৫৬৭৮'\n * ```\n *\n * @example\n * All options combined:\n * ```typescript\n * formatPhone('8801712345678', {\n * includeCountryCode: true,\n * useBanglaDigits: true,\n * format: 'dashed'\n * });\n * // '+৮৮০ ০১৭-১২৩৪-৫৬৭৮'\n * ```\n */\nexport function formatPhone(\n phoneNumber: string,\n options: {\n includeCountryCode?: boolean;\n useBanglaDigits?: boolean;\n format?: 'spaced' | 'dashed' | 'compact';\n } = {}\n): string {\n const { includeCountryCode = false, useBanglaDigits = false, format = 'spaced' } = options;\n\n // Remove all non-digit characters\n const digits = phoneNumber.replace(/\\D/g, '');\n\n // Remove country code if present\n let number = digits;\n if (digits.startsWith('880')) {\n number = digits.slice(3);\n } else if (digits.startsWith('+880')) {\n number = digits.slice(4);\n }\n\n // Validate length (Bangladeshi mobile numbers are 11 digits with country code, 10 without)\n if (number.length !== 10 && number.length !== 11) {\n throw new Error('Invalid Bangladeshi phone number length');\n }\n\n // Format: 01X-XXXX-XXXX or 01X XXXX XXXX\n let formatted = '';\n if (number.length === 11) {\n // Includes leading 0\n formatted = `${number.slice(0, 3)} ${number.slice(3, 7)} ${number.slice(7)}`;\n } else {\n // 10 digits\n formatted = `0${number.slice(0, 2)} ${number.slice(2, 6)} ${number.slice(6)}`;\n }\n\n if (format === 'dashed') {\n formatted = formatted.replace(/\\s/g, '-');\n } else if (format === 'compact') {\n formatted = formatted.replace(/\\s/g, '');\n }\n\n if (includeCountryCode) {\n formatted = '+880 ' + formatted;\n }\n\n if (useBanglaDigits) {\n formatted = toBanglaNumber(formatted.replace(/\\s|-/g, ''));\n // Re-add formatting\n if (format === 'spaced') {\n formatted = `${formatted.slice(0, 3)} ${formatted.slice(3, 7)} ${formatted.slice(7)}`;\n } else if (format === 'dashed') {\n formatted = `${formatted.slice(0, 3)}-${formatted.slice(3, 7)}-${formatted.slice(7)}`;\n }\n if (includeCountryCode) {\n formatted = '+৮৮০ ' + formatted;\n }\n }\n\n return formatted;\n}\n","/**\n * Validates a Bangladeshi phone number.\n *\n * This function checks if the input is a valid Bangladeshi mobile phone number.\n * It supports numbers with or without country code (+880 or 880) and validates\n * against recognized operator codes.\n *\n * **Valid Operator Codes:**\n * - 013 (Grameenphone)\n * - 014 (Banglalink)\n * - 015 (Teletalk)\n * - 016 (Airtel)\n * - 017 (Grameenphone)\n * - 018 (Robi)\n * - 019 (Banglalink)\n *\n * @param phoneNumber - Phone number string to validate\n * @returns true if valid Bangladeshi phone number, false otherwise\n *\n * @example\n * Valid phone numbers:\n * ```typescript\n * validatePhone('01712345678'); // true\n * validatePhone('+8801712345678'); // true\n * validatePhone('8801712345678'); // true\n * validatePhone('017 1234 5678'); // true\n * validatePhone('017-1234-5678'); // true\n * ```\n *\n * @example\n * Invalid phone numbers:\n * ```typescript\n * validatePhone('0171234567'); // false (too short)\n * validatePhone('017123456789'); // false (too long)\n * validatePhone('01212345678'); // false (invalid operator code)\n * validatePhone('1712345678'); // false (missing leading 0)\n * ```\n */\nexport function validatePhone(phoneNumber: string): boolean {\n // Remove all non-digit characters\n const digits = phoneNumber.replace(/\\D/g, '');\n\n // Check if it starts with country code\n let number = digits;\n if (digits.startsWith('880')) {\n number = digits.slice(3);\n } else if (digits.startsWith('+880')) {\n number = digits.slice(4);\n }\n\n // Bangladeshi mobile numbers should be 10 digits (without country code)\n // or 11 digits (with leading 0)\n if (number.length !== 10 && number.length !== 11) {\n return false;\n }\n\n // Should start with 01 (for mobile)\n if (!number.startsWith('01') && number.length === 11) {\n return false;\n }\n\n if (number.length === 10 && !number.startsWith('1')) {\n return false;\n }\n\n // Valid operator codes: 013, 014, 015, 016, 017, 018, 019\n const operatorCode = number.length === 11 ? number.slice(0, 3) : '0' + number.slice(0, 2);\n const validCodes = ['013', '014', '015', '016', '017', '018', '019'];\n\n return validCodes.includes(operatorCode);\n}\n\n/**\n * Validates a Bangladeshi operator code.\n *\n * @param operatorCode - Three-digit operator code (013-019)\n * @returns true if valid operator code, false otherwise\n *\n * @example\n * ```typescript\n * isValidOperatorCode('017'); // true\n * isValidOperatorCode('018'); // true\n * isValidOperatorCode('012'); // false (not a valid operator)\n * isValidOperatorCode('020'); // false (out of range)\n * ```\n */\nexport function isValidOperatorCode(operatorCode: string): boolean {\n const validCodes = ['013', '014', '015', '016', '017', '018', '019'];\n return validCodes.includes(operatorCode);\n}\n\n/**\n * Checks if a phone number has a country code.\n *\n * @param phoneNumber - Phone number string\n * @returns true if phone number includes country code\n *\n * @example\n * ```typescript\n * hasCountryCode('+8801712345678'); // true\n * hasCountryCode('8801712345678'); // true\n * hasCountryCode('01712345678'); // false\n * ```\n */\nexport function hasCountryCode(phoneNumber: string): boolean {\n const trimmed = phoneNumber.trim();\n return trimmed.startsWith('+880') || trimmed.startsWith('880');\n}\n\n/**\n * Sanitizes a phone number by removing non-digit characters.\n *\n * This function cleans user input by removing spaces, dashes, parentheses,\n * and other non-digit characters (except the leading + for country code).\n *\n * @param phoneNumber - Phone number string to sanitize\n * @returns Sanitized phone number string\n *\n * @example\n * ```typescript\n * sanitizePhoneNumber('017 1234 5678'); // '01712345678'\n * sanitizePhoneNumber('017-1234-5678'); // '01712345678'\n * sanitizePhoneNumber('+880 171 234 5678'); // '+88001712345678'\n * sanitizePhoneNumber('(017) 1234-5678'); // '01712345678'\n * ```\n */\nexport function sanitizePhoneNumber(phoneNumber: string): string {\n if (typeof phoneNumber !== 'string') {\n return '';\n }\n\n let sanitized = phoneNumber.trim();\n\n // Preserve leading + if present\n const hasPlus = sanitized.startsWith('+');\n\n // Remove all non-digit characters\n sanitized = sanitized.replace(/\\D/g, '');\n\n // Re-add the + if it was there\n if (hasPlus) {\n sanitized = '+' + sanitized;\n }\n\n return sanitized;\n}\n\n/**\n * Checks if a phone number string contains only valid characters.\n *\n * Valid characters are: digits (0-9), spaces, dashes, parentheses, and + for country code.\n *\n * @param phoneNumber - Phone number string to check\n * @returns true if contains only valid characters\n *\n * @example\n * ```typescript\n * isValidPhoneFormat('017 1234 5678'); // true\n * isValidPhoneFormat('017-1234-5678'); // true\n * isValidPhoneFormat('+880 171 234 5678'); // true\n * isValidPhoneFormat('017abc5678'); // false\n * ```\n */\nexport function isValidPhoneFormat(phoneNumber: string): boolean {\n if (typeof phoneNumber !== 'string') {\n return false;\n }\n\n // Valid characters: digits, spaces, dashes, parentheses, plus sign\n const validPattern = /^[\\d\\s\\-()+ ]+$/;\n return validPattern.test(phoneNumber.trim());\n}\n","import { formatPhone } from './formatPhone';\nimport { validatePhone, sanitizePhoneNumber } from './validatePhone';\n\n/**\n * Operator information for Bangladeshi mobile networks.\n */\nexport interface OperatorInfo {\n code: string;\n name: string;\n nameBangla: string;\n}\n\n/**\n * Parsed phone number information.\n */\nexport interface ParsedPhoneNumber {\n original: string;\n countryCode: string;\n operatorCode: string;\n number: string;\n fullNumber: string;\n}\n\n/**\n * Gets the mobile operator name from a phone number.\n *\n * This function identifies the mobile network operator based on the\n * three-digit operator code (013-019).\n *\n * **Operator Mapping:**\n * - 013, 017 → Grameenphone (গ্রামীণফোন)\n * - 014, 019 → Banglalink (বাংলালিংক)\n * - 015 → Teletalk (টেলিটক)\n * - 016 → Airtel (এয়ারটেল)\n * - 018 → Robi (রবি)\n *\n * @param phoneNumber - Bangladeshi phone number\n * @returns Operator information or null if invalid\n *\n * @example\n * ```typescript\n * getOperator('01712345678');\n * // { code: '017', name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' }\n *\n * getOperator('01812345678');\n * // { code: '018', name: 'Robi', nameBangla: 'রবি' }\n *\n * getOperator('invalid'); // null\n * ```\n */\nexport function getOperator(phoneNumber: string): OperatorInfo | null {\n if (!validatePhone(phoneNumber)) {\n return null;\n }\n\n const digits = phoneNumber.replace(/\\D/g, '');\n let number = digits;\n\n // Remove country code if present\n if (digits.startsWith('880')) {\n number = digits.slice(3);\n }\n\n // Get operator code\n const operatorCode = number.length === 11 ? number.slice(0, 3) : '0' + number.slice(0, 2);\n\n const operatorMap: Record<string, { name: string; nameBangla: string }> = {\n '013': { name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' },\n '014': { name: 'Banglalink', nameBangla: 'বাংলালিংক' },\n '015': { name: 'Teletalk', nameBangla: 'টেলিটক' },\n '016': { name: 'Airtel', nameBangla: 'এয়ারটেল' },\n '017': { name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' },\n '018': { name: 'Robi', nameBangla: 'রবি' },\n '019': { name: 'Banglalink', nameBangla: 'বাংলালিংক' },\n };\n\n const operator = operatorMap[operatorCode];\n if (!operator) {\n return null;\n }\n\n return {\n code: operatorCode,\n ...operator,\n };\n}\n\n/**\n * Parses a phone number into its components.\n *\n * @param phoneNumber - Phone number to parse\n * @returns Parsed phone number components\n * @throws {Error} If phone number is invalid\n *\n * @example\n * ```typescript\n * parsePhoneNumber('01712345678');\n * // {\n * // original: '01712345678',\n * // countryCode: '880',\n * // operatorCode: '017',\n * // number: '12345678',\n * // fullNumber: '01712345678'\n * // }\n *\n * parsePhoneNumber('+8801812345678');\n * // {\n * // original: '+8801812345678',\n * // countryCode: '880',\n * // operatorCode: '018',\n * // number: '12345678',\n * // fullNumber: '01812345678'\n * // }\n * ```\n */\nexport function parsePhoneNumber(phoneNumber: string): ParsedPhoneNumber {\n if (!validatePhone(phoneNumber)) {\n throw new Error('Invalid phone number');\n }\n\n const original = phoneNumber;\n const digits = phoneNumber.replace(/\\D/g, '');\n\n let number = digits;\n const countryCode = '880';\n\n // Remove country code if present\n if (digits.startsWith('880')) {\n number = digits.slice(3);\n }\n\n // Ensure it has leading 0\n if (number.length === 10) {\n number = '0' + number;\n }\n\n const operatorCode = number.slice(0, 3);\n const subscriberNumber = number.slice(3);\n\n return {\n original,\n countryCode,\n operatorCode,\n number: subscriberNumber,\n fullNumber: number,\n };\n}\n\n/**\n * Normalizes a phone number to standard format (11 digits with leading 0).\n *\n * This function converts any valid Bangladeshi phone number format to\n * the standard 11-digit format with leading 0 (e.g., 01712345678).\n *\n * @param phoneNumber - Phone number to normalize\n * @returns Normalized phone number\n * @throws {Error} If phone number is invalid\n *\n * @example\n * ```typescript\n * normalizePhoneNumber('017 1234 5678'); // '01712345678'\n * normalizePhoneNumber('+8801712345678'); // '01712345678'\n * normalizePhoneNumber('8801712345678'); // '01712345678'\n * normalizePhoneNumber('1712345678'); // '01712345678'\n * ```\n */\nexport function normalizePhoneNumber(phoneNumber: string): string {\n const parsed = parsePhoneNumber(phoneNumber);\n return parsed.fullNumber;\n}\n\n/**\n * Adds country code to a phone number.\n *\n * @param phoneNumber - Phone number (with or without country code)\n * @param format - Format style ('plus' or 'plain')\n * @returns Phone number with country code\n * @throws {Error} If phone number is invalid\n *\n * @example\n * ```typescript\n * addCountryCode('01712345678'); // '+8801712345678'\n * addCountryCode('01712345678', 'plain'); // '8801712345678'\n * addCountryCode('+8801712345678'); // '+8801712345678' (already has it)\n * ```\n */\nexport function addCountryCode(\n phoneNumber: string,\n format: 'plus' | 'plain' = 'plus'\n): string {\n const normalized = normalizePhoneNumber(phoneNumber);\n\n // Remove leading 0 for international format\n const withoutLeadingZero = normalized.slice(1);\n\n if (format === 'plus') {\n return `+880${withoutLeadingZero}`;\n } else {\n return `880${withoutLeadingZero}`;\n }\n}\n\n/**\n * Removes country code from a phone number.\n *\n * @param phoneNumber - Phone number (with or without country code)\n * @returns Phone number without country code (11 digits with leading 0)\n * @throws {Error} If phone number is invalid\n *\n * @example\n * ```typescript\n * removeCountryCode('+8801712345678'); // '01712345678'\n * removeCountryCode('8801712345678'); // '01712345678'\n * removeCountryCode('01712345678'); // '01712345678' (already without it)\n * ```\n */\nexport function removeCountryCode(phoneNumber: string): string {\n return normalizePhoneNumber(phoneNumber);\n}\n\n/**\n * Safely formats a phone number with a fallback value.\n *\n * @param phoneNumber - Phone number to format\n * @param options - Formatting options\n * @param fallback - Value to return if formatting fails\n * @returns Formatted phone number or fallback value\n *\n * @example\n * ```typescript\n * safeFormatPhone('01712345678', { format: 'spaced' }); // '017 1234 5678'\n * safeFormatPhone('invalid', {}, '---'); // '---'\n * ```\n */\nexport function safeFormatPhone(\n phoneNumber: string,\n options: {\n includeCountryCode?: boolean;\n useBanglaDigits?: boolean;\n format?: 'spaced' | 'dashed' | 'compact';\n } = {},\n fallback: string = ''\n): string {\n try {\n return formatPhone(phoneNumber, options);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Checks if two phone numbers are the same.\n *\n * This function normalizes both numbers and compares them, so it correctly\n * identifies the same number in different formats.\n *\n * @param phone1 - First phone number\n * @param phone2 - Second phone number\n * @returns true if both numbers are the same\n *\n * @example\n * ```typescript\n * isSameNumber('01712345678', '+8801712345678'); // true\n * isSameNumber('017 1234 5678', '017-1234-5678'); // true\n * isSameNumber('01712345678', '01812345678'); // false\n * ```\n */\nexport function isSameNumber(phone1: string, phone2: string): boolean {\n try {\n const normalized1 = normalizePhoneNumber(phone1);\n const normalized2 = normalizePhoneNumber(phone2);\n return normalized1 === normalized2;\n } catch {\n return false;\n }\n}\n\n/**\n * Gets all valid operator codes.\n *\n * @returns Array of valid operator codes\n *\n * @example\n * ```typescript\n * const codes = getAllOperatorCodes();\n * // ['013', '014', '015', '016', '017', '018', '019']\n * ```\n */\nexport function getAllOperatorCodes(): string[] {\n return ['013', '014', '015', '016', '017', '018', '019'];\n}\n\n/**\n * Gets all operators with their information.\n *\n * @returns Array of operator information\n *\n * @example\n * ```typescript\n * const operators = getAllOperators();\n * operators.forEach(op => {\n * console.log(`${op.code}: ${op.name} (${op.nameBangla})`);\n * });\n * ```\n */\nexport function getAllOperators(): OperatorInfo[] {\n return [\n { code: '013', name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' },\n { code: '014', name: 'Banglalink', nameBangla: 'বাংলালিংক' },\n { code: '015', name: 'Teletalk', nameBangla: 'টেলিটক' },\n { code: '016', name: 'Airtel', nameBangla: 'এয়ারটেল' },\n { code: '017', name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' },\n { code: '018', name: 'Robi', nameBangla: 'রবি' },\n { code: '019', name: 'Banglalink', nameBangla: 'বাংলালিংক' },\n ];\n}\n\n/**\n * Parses and formats a phone number in one step.\n *\n * This combines sanitization, validation, and formatting into a single operation.\n *\n * @param phoneNumber - Raw phone number input\n * @param options - Formatting options\n * @returns Formatted phone number\n * @throws {Error} If phone number is invalid after sanitization\n *\n * @example\n * ```typescript\n * parseAndFormat(' 017 1234 5678 ', { format: 'dashed' });\n * // '017-1234-5678'\n *\n * parseAndFormat('+880 171 234 5678', { includeCountryCode: false });\n * // '017 1234 5678'\n * ```\n */\nexport function parseAndFormat(\n phoneNumber: string,\n options: {\n includeCountryCode?: boolean;\n useBanglaDigits?: boolean;\n format?: 'spaced' | 'dashed' | 'compact';\n } = {}\n): string {\n const sanitized = sanitizePhoneNumber(phoneNumber);\n return formatPhone(sanitized, options);\n}\n","/**\n * Validates if a string contains ONLY Bengali/Bangla characters and whitespace.\n *\n * This function checks if the entire string consists exclusively of characters\n * from the Bengali Unicode range (U+0980 to U+09FF) and whitespace.\n * It returns false if any non-Bengali, non-whitespace character is present.\n *\n * **Use Cases:**\n * - Form validation (ensuring pure Bengali input)\n * - Content filtering (verifying Bengali-only text)\n * - Data validation (checking text purity)\n *\n * **Allowed Characters:**\n * - Bengali consonants, vowels, diacritics\n * - Bengali digits (০-৯)\n * - Bengali punctuation\n * - Whitespace (spaces, tabs, newlines)\n *\n * **Not Allowed:**\n * - English letters (a-z, A-Z)\n * - English digits (0-9)\n * - Special characters not in Bengali range\n * - Emojis or other Unicode characters\n *\n * @param text - String to validate\n * @returns true if string contains only Bengali characters and whitespace, false otherwise\n *\n * @example\n * Valid pure Bengali text:\n * ```typescript\n * validateBangla('বাংলা'); // true\n * validateBangla('শুভ সকাল'); // true\n * validateBangla('১২৩ টাকা'); // true\n * validateBangla('হ্যালো ওয়ার্ল্ড'); // true\n * ```\n *\n * @example\n * Invalid mixed content:\n * ```typescript\n * validateBangla('Hello বাংলা'); // false (contains English)\n * validateBangla('বাংলা 123'); // false (contains English digits)\n * validateBangla('Test'); // false (English only)\n * validateBangla('বাংলা!'); // false (contains non-Bengali punctuation)\n * ```\n *\n * @example\n * Whitespace handling:\n * ```typescript\n * validateBangla('বাংলা ভাষা'); // true (space allowed)\n * validateBangla(' বাংলা '); // true (spaces allowed)\n * validateBangla(' '); // true (whitespace only)\n * ```\n *\n * @example\n * Empty string:\n * ```typescript\n * validateBangla(''); // false\n * ```\n *\n * @example\n * Form validation:\n * ```typescript\n * function validateBengaliName(name: string): boolean {\n * return validateBangla(name) && name.trim().length > 0;\n * }\n *\n * validateBengaliName('মাহমুদ'); // true\n * validateBengaliName('Mahmud'); // false\n * ```\n */\nexport function validateBangla(text: string): boolean {\n const banglaRegex = /^[\\u0980-\\u09FF\\s]+$/;\n return banglaRegex.test(text);\n}\n","/**\n * Checks if a character is a Bengali digit.\n *\n * Bengali digits range from ০ (0) to ৯ (9).\n * This function checks if the input string contains at least one Bengali digit.\n *\n * **Bengali Digits:**\n * - ০ (shunno) - 0\n * - ১ (ek) - 1\n * - ২ (dui) - 2\n * - ৩ (tin) - 3\n * - ৪ (char) - 4\n * - ৫ (pach) - 5\n * - ৬ (choy) - 6\n * - ৭ (saat) - 7\n * - ৮ (aat) - 8\n * - ৯ (noy) - 9\n *\n * @param char - Character or string to check\n * @returns true if contains at least one Bengali digit, false otherwise\n *\n * @example\n * Single Bengali digits:\n * ```typescript\n * isBanglaDigit('০'); // true\n * isBanglaDigit('৫'); // true\n * isBanglaDigit('৯'); // true\n * ```\n *\n * @example\n * Multiple Bengali digits:\n * ```typescript\n * isBanglaDigit('১২৩'); // true\n * isBanglaDigit('৪৫৬'); // true\n * ```\n *\n * @example\n * Mixed content:\n * ```typescript\n * isBanglaDigit('১৫ দিন'); // true\n * isBanglaDigit('বয়স: ২৫'); // true\n * ```\n *\n * @example\n * English digits:\n * ```typescript\n * isBanglaDigit('0'); // false\n * isBanglaDigit('5'); // false\n * isBanglaDigit('123'); // false\n * ```\n *\n * @example\n * Non-digit characters:\n * ```typescript\n * isBanglaDigit('abc'); // false\n * isBanglaDigit('বাংলা'); // false\n * isBanglaDigit(''); // false\n * ```\n */\nexport function isBanglaDigit(char: string): boolean {\n return /[০-৯]/.test(char);\n}\n","/**\n * Checks if a string contains Bengali/Bangla characters.\n *\n * This function tests if the input string contains at least one character\n * from the Bengali Unicode range (U+0980 to U+09FF), which includes:\n * - Bengali consonants (ক খ গ ঘ ঙ চ ছ জ ঝ ঞ etc.)\n * - Bengali vowels (অ আ ই ঈ উ ঊ etc.)\n * - Bengali vowel diacritics (া ি ী ু ূ etc.)\n * - Bengali digits (০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯)\n * - Bengali punctuation and symbols\n *\n * @param text - String to check\n * @returns true if contains at least one Bengali character, false otherwise\n *\n * @example\n * Pure Bengali text:\n * ```typescript\n * isBanglaText('বাংলা'); // true\n * isBanglaText('হ্যালো'); // true\n * isBanglaText('শুভ সকাল'); // true\n * ```\n *\n * @example\n * Bengali digits:\n * ```typescript\n * isBanglaText('১২৩'); // true\n * isBanglaText('৫০০'); // true\n * ```\n *\n * @example\n * Mixed Bengali and English:\n * ```typescript\n * isBanglaText('Hello বাংলা'); // true\n * isBanglaText('Price: ১০০ টাকা'); // true\n * isBanglaText('Test ১২৩'); // true\n * ```\n *\n * @example\n * English only:\n * ```typescript\n * isBanglaText('Hello'); // false\n * isBanglaText('123'); // false\n * isBanglaText('Test'); // false\n * ```\n *\n * @example\n * Empty or special characters:\n * ```typescript\n * isBanglaText(''); // false\n * isBanglaText(' '); // false\n * isBanglaText('123 abc'); // false\n * ```\n */\nexport function isBanglaText(text: string): boolean {\n // Bangla Unicode range: U+0980 to U+09FF\n const banglaRegex = /[\\u0980-\\u09FF]/;\n return banglaRegex.test(text);\n}\n","/**\n * General utility functions for Bengali/Bangla text operations.\n *\n * This module provides helper functions for working with Bengali text,\n * including counting, detecting, sanitizing, and analyzing Bengali content.\n *\n * @module utils/utils\n */\n\nimport { isBanglaDigit } from './isBanglaDigit';\n\n/**\n * Counts the number of Bengali characters in a string.\n *\n * This function counts characters from the Bengali Unicode range (U+0980 to U+09FF),\n * excluding whitespace and non-Bengali characters.\n *\n * @param text - String to analyze\n * @returns Number of Bengali characters\n *\n * @example\n * Pure Bengali text:\n * ```typescript\n * countBengaliCharacters('বাংলা'); // 5\n * countBengaliCharacters('হ্যালো'); // 6\n * ```\n *\n * @example\n * Mixed content:\n * ```typescript\n * countBengaliCharacters('Hello বাংলা'); // 5\n * countBengaliCharacters('১২৩ টাকা'); // 6\n * ```\n *\n * @example\n * With whitespace:\n * ```typescript\n * countBengaliCharacters('শুভ সকাল'); // 8 (spaces not counted)\n * ```\n */\nexport function countBengaliCharacters(text: string): number {\n const bengaliChars = text.match(/[\\u0980-\\u09FF]/g);\n return bengaliChars ? bengaliChars.length : 0;\n}\n\n/**\n * Counts the number of Bengali digits in a string.\n *\n * Bengali digits: ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯\n *\n * @param text - String to analyze\n * @returns Number of Bengali digits\n *\n * @example\n * ```typescript\n * countBengaliDigits('১২৩'); // 3\n * countBengaliDigits('মূল্য: ১০০ টাকা'); // 3\n * countBengaliDigits('Hello 123'); // 0 (English digits not counted)\n * ```\n */\nexport function countBengaliDigits(text: string): number {\n const bengaliDigits = text.match(/[০-৯]/g);\n return bengaliDigits ? bengaliDigits.length : 0;\n}\n\n/**\n * Checks if a string contains mixed Bengali and non-Bengali content.\n *\n * Returns true if the string has both Bengali characters and non-Bengali\n * alphanumeric characters.\n *\n * @param text - String to check\n * @returns true if content is mixed, false otherwise\n *\n * @example\n * Mixed content:\n * ```typescript\n * isMixedContent('Hello বাংলা'); // true\n * isMixedContent('বাংলা 123'); // true\n * isMixedContent('Price: ১০০ taka'); // true\n * ```\n *\n * @example\n * Pure content:\n * ```typescript\n * isMixedContent('বাংলা'); // false (pure Bengali)\n * isMixedContent('Hello'); // false (pure English)\n * isMixedContent('১২৩'); // false (Bengali digits only)\n * ```\n */\nexport function isMixedContent(text: string): boolean {\n const hasBengali = /[\\u0980-\\u09FF]/.test(text);\n const hasNonBengali = /[a-zA-Z0-9]/.test(text);\n return hasBengali && hasNonBengali;\n}\n\n/**\n * Extracts only Bengali characters from a string.\n *\n * Removes all non-Bengali characters, keeping only characters\n * from the Bengali Unicode range (U+0980 to U+09FF).\n *\n * @param text - String to extract from\n * @param preserveWhitespace - Whether to preserve whitespace (default: false)\n * @returns String containing only Bengali characters\n *\n * @example\n * Extract from mixed content:\n * ```typescript\n * extractBengaliChars('Hello বাংলা World'); // 'বাংলা'\n * extractBengaliChars('Price: ১০০ taka'); // '১০০'\n * extractBengaliChars('123 বাংলা 456'); // 'বাংলা'\n * ```\n *\n * @example\n * With whitespace preservation:\n * ```typescript\n * extractBengaliChars('Hello বাংলা ভাষা', true); // 'বাংলা ভাষা'\n * extractBengaliChars('Test ১২৩ টাকা', true); // '১২৩ টাকা'\n * ```\n *\n * @example\n * Pure Bengali text:\n * ```typescript\n * extractBengaliChars('বাংলা'); // 'বাংলা' (unchanged)\n * ```\n */\nexport function extractBengaliChars(text: string, preserveWhitespace: boolean = false): string {\n if (preserveWhitespace) {\n return text.replace(/[^\\u0980-\\u09FF\\s]/g, '').trim();\n }\n return text.replace(/[^\\u0980-\\u09FF]/g, '');\n}\n\n/**\n * Removes all Bengali characters from a string.\n *\n * Keeps only non-Bengali characters, removing everything from\n * the Bengali Unicode range.\n *\n * @param text - String to process\n * @returns String with Bengali characters removed\n *\n * @example\n * ```typescript\n * removeBengaliChars('Hello বাংলা World'); // 'Hello World'\n * removeBengaliChars('Price: ১০০ taka'); // 'Price: taka'\n * removeBengaliChars('১২৩ টাকা'); // ' '\n * ```\n */\nexport function removeBengaliChars(text: string): string {\n return text.replace(/[\\u0980-\\u09FF]/g, '');\n}\n\n/**\n * Gets the percentage of Bengali characters in a string.\n *\n * Calculates what percentage of the total non-whitespace characters\n * are Bengali characters.\n *\n * @param text - String to analyze\n * @returns Percentage (0-100) of Bengali characters\n *\n * @example\n * ```typescript\n * getBengaliPercentage('বাংলা'); // 100\n * getBengaliPercentage('Hello'); // 0\n * getBengaliPercentage('Hello বাংলা'); // 50 (5 of 10 chars)\n * getBengaliPercentage(''); // 0\n * ```\n */\nexport function getBengaliPercentage(text: string): number {\n const withoutWhitespace = text.replace(/\\s/g, '');\n if (withoutWhitespace.length === 0) {\n return 0;\n }\n\n const bengaliCount = countBengaliCharacters(text);\n return Math.round((bengaliCount / withoutWhitespace.length) * 100);\n}\n\n/**\n * Checks if text is primarily Bengali (more than 50% Bengali characters).\n *\n * @param text - String to check\n * @returns true if more than 50% is Bengali, false otherwise\n *\n * @example\n * ```typescript\n * isPrimarilyBengali('বাংলা'); // true (100%)\n * isPrimarilyBengali('বাংলা ভাষা hello'); // true (>50%)\n * isPrimarilyBengali('Hello বাংলা world test'); // false (<50%)\n * isPrimarilyBengali('Hello'); // false (0%)\n * ```\n */\nexport function isPrimarilyBengali(text: string): boolean {\n return getBengaliPercentage(text) > 50;\n}\n\n/**\n * Sanitizes Bengali text by removing non-Bengali characters.\n *\n * If fallback is provided, returns fallback when result would be empty.\n *\n * @param text - Text to sanitize\n * @param preserveWhitespace - Preserve whitespace (default: true)\n * @param fallback - Fallback value if result is empty (default: empty string)\n * @returns Sanitized Bengali text or fallback\n *\n * @example\n * ```typescript\n * sanitizeBengaliText('Hello বাংলা World'); // 'বাংলা'\n * sanitizeBengaliText('Test 123 টাকা'); // 'টাকা'\n * sanitizeBengaliText('বাংলা ভাষা'); // 'বাংলা ভাষা'\n * ```\n *\n * @example\n * With fallback:\n * ```typescript\n * sanitizeBengaliText('Hello World', true, 'N/A'); // 'N/A'\n * sanitizeBengaliText('123', false, 'নেই'); // 'নেই'\n * ```\n */\nexport function sanitizeBengaliText(\n text: string,\n preserveWhitespace: boolean = true,\n fallback: string = ''\n): string {\n const result = extractBengaliChars(text, preserveWhitespace);\n return result.length > 0 ? result : fallback;\n}\n\n/**\n * Checks if all digits in a string are Bengali digits.\n *\n * Returns true if string contains digits and all digits are Bengali.\n * Returns false if contains English digits or no digits at all.\n *\n * @param text - String to check\n * @returns true if all digits are Bengali, false otherwise\n *\n * @example\n * All Bengali digits:\n * ```typescript\n * hasOnlyBengaliDigits('১২৩'); // true\n * hasOnlyBengaliDigits('মূল্য: ১০০'); // true\n * hasOnlyBengaliDigits('বাংলা'); // false (no digits)\n * ```\n *\n * @example\n * Mixed or English digits:\n * ```typescript\n * hasOnlyBengaliDigits('123'); // false (English digits)\n * hasOnlyBengaliDigits('১২3'); // false (mixed)\n * hasOnlyBengaliDigits('Price: 100'); // false\n * ```\n */\nexport function hasOnlyBengaliDigits(text: string): boolean {\n const hasDigits = /\\d|[০-৯]/.test(text);\n if (!hasDigits) {\n return false;\n }\n\n const hasEnglishDigits = /\\d/.test(text);\n return !hasEnglishDigits && isBanglaDigit(text);\n}\n\n/**\n * Normalizes whitespace in Bengali text.\n *\n * Replaces multiple consecutive whitespaces with a single space\n * and trims leading/trailing whitespace.\n *\n * @param text - Text to normalize\n * @returns Text with normalized whitespace\n *\n * @example\n * ```typescript\n * normalizeWhitespace('বাংলা ভাষা'); // 'বাংলা ভাষা'\n * normalizeWhitespace(' শুভ সকাল '); // 'শুভ সকাল'\n * normalizeWhitespace('হ্যালো\\n\\nওয়ার্ল্ড'); // 'হ্যালো ওয়ার্ল্ড'\n * ```\n */\nexport function normalizeWhitespace(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\n}\n\n/**\n * Splits text into Bengali and non-Bengali parts.\n *\n * Returns an object with separate strings for Bengali and non-Bengali content.\n *\n * @param text - Text to split\n * @returns Object with bengali and nonBengali strings\n *\n * @example\n * ```typescript\n * splitBengaliContent('Hello বাংলা World');\n * // { bengali: 'বাংলা', nonBengali: 'Hello World' }\n *\n * splitBengaliContent('Price: ১০০ taka');\n * // { bengali: '১০০', nonBengali: 'Price: taka' }\n * ```\n */\nexport function splitBengaliContent(text: string): { bengali: string; nonBengali: string } {\n return {\n bengali: extractBengaliChars(text, true).trim(),\n nonBengali: removeBengaliChars(text).trim(),\n };\n}\n\n/**\n * Checks if a string contains any Bengali consonants.\n *\n * Bengali consonants: ক খ গ ঘ ঙ চ ছ জ ঝ ঞ ট ঠ ড ঢ ণ ত থ দ ধ ন প ফ ব ভ ম য র ল শ ষ স হ ড় ঢ় য় ৎ\n *\n * @param text - Text to check\n * @returns true if contains Bengali consonants, false otherwise\n *\n * @example\n * ```typescript\n * hasBengaliConsonants('বাংলা'); // true\n * hasBengaliConsonants('আই'); // false (vowels only)\n * hasBengaliConsonants('১২৩'); // false (digits only)\n * hasBengaliConsonants('Hello'); // false\n * ```\n */\nexport function hasBengaliConsonants(text: string): boolean {\n // Bengali consonants range: U+0995 to U+09B9, plus additional consonants\n const consonantRegex = /[ক-হড়ঢ়য়ৎ]/;\n return consonantRegex.test(text);\n}\n\n/**\n * Checks if a string contains any Bengali vowels (independent or diacritics).\n *\n * Bengali vowels: অ আ ই ঈ উ ঊ ঋ ৠ ঌ ৡ এ ঐ ও ঔ\n * Bengali vowel diacritics: া ি ী ু ূ ৃ ৄ ে ৈ ো ৌ\n *\n * @param text - Text to check\n * @returns true if contains Bengali vowels, false otherwise\n *\n * @example\n * ```typescript\n * hasBengaliVowels('আম'); // true\n * hasBengaliVowels('বাংলা'); // true (has vowel diacritics)\n * hasBengaliVowels('ক'); // false (consonant only)\n * hasBengaliVowels('123'); // false\n * ```\n */\nexport function hasBengaliVowels(text: string): boolean {\n // Independent vowels: U+0985 to U+0994\n // Vowel diacritics: U+09BE to U+09CC\n const vowelRegex = /[অ-ঔা-ৌ]/;\n return vowelRegex.test(text);\n}\n"],"mappings":"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","names":["index_exports","__export","BANGLA_DIGITS","BANGLA_MONTHS","BANGLA_SEASONS","BANGLA_WEEKDAYS","ENGLISH_DIGITS","addCountryCode","addDays","addDaysToBengaliDate","addMinutesToTime","addTax","applyDiscount","batchFormatCurrency","batchFormatDates","batchFromBanglaNumber","batchParseDates","batchToBanglaMonth","batchToBanglaNumber","batchToBengali","batchToOrdinal","calculatePercentage","canParseBengaliDate","compareBengaliDates","compareCurrency","compareDates","compareMonths","compareOrdinals","compareTimes","convertToWordsAndDigits","countBengaliCharacters","countBengaliDigits","createOrdinalList","divideCurrency","extractBengaliChars","formatAndConvert","formatBengaliDate","formatCurrency","formatDate","formatNumber","formatOrdinal","formatPhone","formatTime","formatToday","formatWithUnits","fromBanglaMonth","fromBanglaNumber","fromBanglaWeekday","fromBengali","getAbsoluteAmount","getAllBanglaWeekdays","getAllMonths","getAllOperatorCodes","getAllOperators","getAllSeasons","getBengaliDate","getBengaliDateDifference","getBengaliMonthDays","getBengaliMonthLengths","getBengaliPercentage","getCurrentBengaliDate","getCurrentSeason","getCurrentTimeBangla","getDaysBetween","getDaysDifference","getFirstDayOfBengaliMonth","getLastDayOfBengaliMonth","getMonthFromIndex","getMonthIndex","getMonthMapping","getMonthName","getMonthRange","getNextBanglaWeekday","getNextMonth","getNextOrdinal","getNextSeason","getNextWeekday","getOperator","getOrdinalSequence","getOrdinalType","getPreviousBanglaWeekday","getPreviousMonth","getPreviousOrdinal","getPreviousSeason","getPreviousWeekday","getRanking","getSeason","getSeasonByIndex","getSeasonFromMonth","getSeasonIndex","getSeasonInfo","getSeasonMonths","getSpecialOrdinals","getTimePeriod","getWeekdayName","hasBengaliConsonants","hasBengaliDigits","hasBengaliMonth","hasBengaliVowels","hasCountryCode","hasOnlyBengaliDigits","hasSeconds","hasSpecialOrdinal","hasTakaSymbol","hasTakaWord","isBanglaCurrency","isBanglaDigit","isBanglaOrdinal","isBanglaText","isBanglaWeekend","isBengaliDateInRange","isBengaliLeapYear","isCurrencyInRange","isDateInRange","isFuture","isInSpecialOrdinalRange","isMixedContent","isMonthInRange","isMonthInSeason","isNegativeAmount","isNumberInRange","isPast","isPositiveAmount","isPrimarilyBengali","isSameDay","isSameNumber","isSameSeason","isTimeInRange","isToday","isValidBanglaMonth","isValidBanglaNumber","isValidBanglaWeekday","isValidBengaliDate","isValidBengaliDateString","isValidBengaliDay","isValidBengaliMonth","isValidBengaliYear","isValidCurrency","isValidDate","isValidDateForSeason","isValidDateForWeekday","isValidMonth","isValidMonthNumber","isValidNumber","isValidNumberForOrdinal","isValidNumberForWords","isValidOperatorCode","isValidOrdinal","isValidPhoneFormat","isValidSeasonName","isValidTimeInput","isValidTimeString","isValidWeekdayNumber","isWeekend","isZeroAmount","multiplyCurrency","negateAmount","normalizePhoneNumber","normalizeWhitespace","parseAndConvertToBangla","parseAndConvertToMonth","parseAndConvertToOrdinal","parseAndFormat","parseAndFormatCurrency","parseCurrency","parseDate","parsePhoneNumber","parseTime","parseWeekdayInput","relativeDay","relativeTime","removeBengaliChars","removeCountryCode","roundCurrency","safeFormatCurrency","safeFormatDate","safeFormatPhone","safeFormatTime","safeFromBanglaMonth","safeFromBanglaNumber","safeFromBanglaWeekday","safeFromBengali","safeGetSeason","safeGetSeasonFromMonth","safeParseCurrency","safeParseDate","safeRelativeTime","safeToBanglaMonth","safeToBanglaNumber","safeToBanglaWeekday","safeToBengali","safeToOrdinal","sanitizeBanglaMonth","sanitizeBengaliDate","sanitizeBengaliText","sanitizeCurrencyInput","sanitizeDate","sanitizeMonthNumber","sanitizeNumberInput","sanitizeOrdinalInput","sanitizePhoneNumber","sanitizeTimeInput","sanitizeWeekdayInput","secondsToTime","splitAmount","splitBengaliContent","subtractCurrency","sumCurrency","timeDifferenceMinutes","timeToSeconds","toBanglaMonth","toBanglaNumber","toBanglaWeekday","toBengali","toOrdinal","toWords","truncateDecimals","validateBangla","validatePhone","__toCommonJS","BANGLA_DIGITS","ENGLISH_DIGITS","BANGLA_MONTHS","BANGLA_WEEKDAYS","BANGLA_SEASONS","toBanglaNumber","input","value","absInput","log10","hasDecimal","hasDigit","result","i","char","index","ENGLISH_DIGITS","BANGLA_DIGITS","__name","fromBanglaNumber","input","value","hasDecimal","hasDigit","result","i","char","index","BANGLA_DIGITS","ENGLISH_DIGITS","parsed","__name","toWords","number","convertBelowHundred","convertBelowThousand","convertBelowLakh","convertBelowCrore","convertBelowArab","convertBelowKharab","__name","n","ones","tens","ten","one","hundred","remainder","result","thousand","lakh","crore","arab","formatWithUnits","number","options","precision","useBanglaDigits","absNumber","sign","value","unit","formatted","toBanglaNumber","rounded","__name","formatNumber","number","options","useBanglaDigits","separator","numStr","integerPart","decimalPart","formattedInteger","toBanglaNumber","formatted","formatIntegerPart","formattedDecimal","__name","isNegative","absolutePart","rightmost3","remaining","groups","i","start","isValidBanglaNumber","input","value","hasDecimal","hasDigit","char","BANGLA_DIGITS","__name","isValidNumber","absInput","log10","ENGLISH_DIGITS","isValidNumberForWords","isValidNumberForOrdinal","sanitizeNumberInput","result","batchToBanglaNumber","inputs","success","errors","input","output","toBanglaNumber","error","__name","batchFromBanglaNumber","fromBanglaNumber","safeToBanglaNumber","fallback","safeFromBanglaNumber","parseAndConvertToBangla","sanitized","sanitizeNumberInput","formatAndConvert","useBanglaDigits","separator","formatNumber","convertToWordsAndDigits","toWords","isNumberInRange","value","min","max","truncateDecimals","decimals","multiplier","formatCurrency","amount","options","includeSymbol","includeWord","numAmount","banglaAmount","toBanglaNumber","parts","__name","parseCurrency","currencyString","cleaned","fromBanglaNumber","__name","isValidCurrency","value","__name","isBanglaCurrency","trimmed","isPositiveAmount","isNegativeAmount","isZeroAmount","sanitizeCurrencyInput","parsed","isCurrencyInRange","min","max","hasTakaSymbol","hasTakaWord","safeFormatCurrency","amount","options","fallback","numAmount","isValidCurrency","formatCurrency","__name","safeParseCurrency","currencyString","result","parseCurrency","batchFormatCurrency","amounts","roundCurrency","decimals","multiplier","sumCurrency","sum","acc","subtractCurrency","amount1","amount2","multiplyCurrency","factor","divideCurrency","divisor","calculatePercentage","percentage","applyDiscount","discountPercent","discount","addTax","taxPercent","tax","splitAmount","parts","perPart","sumSoFar","lastPart","compareCurrency","rounded1","rounded2","getAbsoluteAmount","negateAmount","parseAndFormatCurrency","value","sanitized","sanitizeCurrencyInput","parsed","toBanglaMonth","monthNumber","BANGLA_MONTHS","__name","fromBanglaMonth","monthName","index","BANGLA_MONTHS","__name","getMonthName","date","jsMonth","toBanglaMonth","__name","isValidDate","date","__name","isValidBengaliDateString","dateString","cleaned","monthNamePattern","separatorPattern","hasBengaliDigits","text","hasBengaliMonth","sanitizeDate","isValidMonthNumber","monthNumber","__name","isValidBanglaMonth","monthName","trimmed","BANGLA_MONTHS","sanitizeMonthNumber","value","parsed","rounded","sanitizeBanglaMonth","safeToBanglaMonth","monthNumber","fallback","isValidMonthNumber","toBanglaMonth","__name","safeFromBanglaMonth","monthName","isValidBanglaMonth","fromBanglaMonth","getAllMonths","BANGLA_MONTHS","getNextMonth","currentMonth","monthNum","nextNum","getPreviousMonth","prevNum","getMonthRange","start","end","isNumber","startNum","endNum","result","current","isMonthInRange","month","compareMonths","month1","month2","num1","num2","getMonthIndex","getMonthFromIndex","index","parseAndConvertToMonth","value","sanitized","sanitizeMonthNumber","batchToBanglaMonth","monthNumbers","num","getMonthMapping","mapping","i","toBanglaWeekday","weekdayNumber","BANGLA_WEEKDAYS","__name","fromBanglaWeekday","weekdayName","index","BANGLA_WEEKDAYS","__name","getWeekdayName","date","weekdayNumber","toBanglaWeekday","__name","isValidWeekdayNumber","value","__name","isValidBanglaWeekday","trimmed","BANGLA_WEEKDAYS","isValidDateForWeekday","sanitizeWeekdayInput","input","isWeekend","weekdayNumber","__name","isBanglaWeekend","weekdayName","fromBanglaWeekday","getNextWeekday","getPreviousWeekday","getNextBanglaWeekday","nextDay","toBanglaWeekday","getPreviousBanglaWeekday","prevDay","parseWeekdayInput","input","sanitized","sanitizeWeekdayInput","safeToBanglaWeekday","fallback","safeFromBanglaWeekday","getAllBanglaWeekdays","getDaysBetween","from","to","formatDate","date","options","includeWeekday","includeYear","format","parts","weekday","getWeekdayName","day","toBanglaNumber","month","getMonthName","year","__name","parseDate","dateString","cleaned","monthNameMatch","dayStr","monthName","yearStr","day","fromBanglaNumber","month","fromBanglaMonth","year","separatorMatch","monthStr","__name","safeFormatDate","date","options","fallback","isValidDate","formatDate","__name","safeParseDate","dateString","parseDate","formatToday","batchFormatDates","dates","batchParseDates","dateStrings","str","canParseBengaliDate","isValidBengaliDateString","compareDates","date1","date2","time1","time2","isToday","today","isPast","isFuture","getDaysDifference","diffTime","addDays","days","result","isDateInRange","start","end","getSeasonFromMonth","monthNumber","BANGLA_SEASONS","__name","fromBengali","b","year","month","day","monthLengths","getBengaliMonthLengths","gYear","boishakh1","daysOffset","m","__name","getBengaliDate","date","options","includeYear","includeWeekday","bengali","toBengali","toBanglaNumber","toBanglaMonth","__name","isValidBengaliYear","year","__name","isValidBengaliMonth","month","isValidBengaliDay","day","monthLengths","getBengaliMonthLengths","isValidBengaliDate","date","sanitizeBengaliDate","safeToBengali","date","fallback","toBengali","__name","safeFromBengali","bengaliDate","isValidBengaliDate","fromBengali","getBengaliMonthDays","month","year","isValidBengaliMonth","isValidBengaliYear","getBengaliMonthLengths","addDaysToBengaliDate","days","gregorianDate","newDate","getBengaliDateDifference","date1","date2","gregorian1","gregorian2","compareBengaliDates","isBengaliDateInRange","start","end","getFirstDayOfBengaliMonth","getLastDayOfBengaliMonth","isBengaliLeapYear","gregorianYear","formatBengaliDate","options","getBengaliDate","getCurrentBengaliDate","batchToBengali","dates","toBengali","date","d","gYear","gMonth","gDay","FIXED_ANCHORS","isBeforeBoishakh","bengaliYear","a","anchor","anchorYear","i","anchorDate","daysSinceAnchor","monthLengths","getBengaliMonthLengths","monthIndex","remaining","__name","getSeason","date","bengaliDate","toBengali","getSeasonFromMonth","__name","isValidMonth","value","__name","isValidSeasonName","trimmed","BANGLA_SEASONS","isValidDateForSeason","getAllSeasons","__name","getSeasonMonths","seasonName","months","getSeasonIndex","BANGLA_SEASONS","getSeasonByIndex","index","isMonthInSeason","monthNumber","getNextSeason","currentSeason","nextIndex","getPreviousSeason","prevIndex","safeGetSeason","date","fallback","getSeason","safeGetSeasonFromMonth","getSeasonFromMonth","getCurrentSeason","isSameSeason","date1","date2","season1","season2","getSeasonInfo","monthNameMap","monthNames","m","toOrdinal","number","specialOrdinals","toBanglaNumber","__name","isValidOrdinal","value","__name","isBanglaOrdinal","trimmed","hasSpecialOrdinal","sanitizeOrdinalInput","parsed","rounded","isInSpecialOrdinalRange","safeToOrdinal","number","fallback","isValidOrdinal","toOrdinal","__name","batchToOrdinal","numbers","num","parseAndConvertToOrdinal","value","sanitized","sanitizeOrdinalInput","getSpecialOrdinals","getOrdinalSequence","start","end","sequence","i","formatOrdinal","options","separator","showNumber","ordinal","getOrdinalType","getRanking","position","suffix","compareOrdinals","num1","num2","getNextOrdinal","current","getPreviousOrdinal","createOrdinalList","items","startFrom","item","index","formatTime","date","options","includeSeconds","use12Hour","hours","minutes","seconds","timeParts","displayHours","period","banglaHours","toBanglaNumber","banglaMinutes","parts","banglaSeconds","timeString","__name","relativeTime","date","baseDate","diffMs","diffSeconds","diffMinutes","diffHours","absDiffHours","baseDay","targetDay","diffDays","toBanglaNumber","weeks","months","years","__name","relativeDay","today","targetDate","isValidTimeString","value","trimmed","timePattern","match","hours","minutes","seconds","__name","isValidTimeInput","value","isValidDate","isValidTimeString","__name","hasSeconds","timeString","sanitizeTimeInput","input","parseTime","timeString","timeParts","sanitizeTimeInput","hours","minutes","seconds","__name","timeToSeconds","secondsToTime","totalSeconds","compareTimes","time1","time2","seconds1","seconds2","isTimeInRange","time","startTime","endTime","timeSeconds","startSeconds","endSeconds","addMinutesToTime","newSeconds","timeDifferenceMinutes","safeFormatTime","date","options","fallback","formatTime","safeRelativeTime","baseDate","relativeTime","getTimePeriod","h","getCurrentTimeBangla","isSameDay","date1","date2","formatPhone","phoneNumber","options","includeCountryCode","useBanglaDigits","format","digits","number","formatted","toBanglaNumber","__name","validatePhone","phoneNumber","digits","number","operatorCode","__name","isValidOperatorCode","hasCountryCode","trimmed","sanitizePhoneNumber","sanitized","hasPlus","isValidPhoneFormat","getOperator","phoneNumber","validatePhone","digits","number","operatorCode","operator","__name","parsePhoneNumber","original","countryCode","subscriberNumber","normalizePhoneNumber","addCountryCode","format","withoutLeadingZero","removeCountryCode","safeFormatPhone","options","fallback","formatPhone","isSameNumber","phone1","phone2","normalized1","normalized2","getAllOperatorCodes","getAllOperators","parseAndFormat","sanitized","sanitizePhoneNumber","validateBangla","text","__name","isBanglaDigit","char","__name","isBanglaText","text","__name","countBengaliCharacters","text","bengaliChars","__name","countBengaliDigits","bengaliDigits","isMixedContent","hasBengali","hasNonBengali","extractBengaliChars","preserveWhitespace","removeBengaliChars","getBengaliPercentage","withoutWhitespace","bengaliCount","isPrimarilyBengali","sanitizeBengaliText","fallback","result","hasOnlyBengaliDigits","isBanglaDigit","normalizeWhitespace","splitBengaliContent","hasBengaliConsonants","hasBengaliVowels"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/constants/numerals.ts","../src/constants/months.ts","../src/constants/weekdays.ts","../src/constants/seasons.ts","../src/number/toBangla.ts","../src/number/fromBangla.ts","../src/number/toWords.ts","../src/number/formatWithUnits.ts","../src/number/formatNumber.ts","../src/number/validate.ts","../src/number/utils.ts","../src/currency/formatCurrency.ts","../src/currency/parseCurrency.ts","../src/currency/validate.ts","../src/currency/utils.ts","../src/month/toBanglaMonth.ts","../src/month/fromBanglaMonth.ts","../src/month/getMonthName.ts","../src/date/validate.ts","../src/month/validate.ts","../src/month/utils.ts","../src/weekday/toBanglaWeekday.ts","../src/weekday/fromBanglaWeekday.ts","../src/weekday/getWeekdayName.ts","../src/weekday/validate.ts","../src/weekday/utils.ts","../src/date/formatDate.ts","../src/date/parseDate.ts","../src/date/utils.ts","../src/season/getSeasonFromMonth.ts","../src/calendar/fromBengali.ts","../src/calendar/getBengaliDate.ts","../src/calendar/validate.ts","../src/calendar/utils.ts","../src/calendar/toBengali.ts","../src/season/getSeason.ts","../src/season/validate.ts","../src/season/utils.ts","../src/ordinal/toOrdinal.ts","../src/ordinal/validate.ts","../src/ordinal/utils.ts","../src/time/formatTime.ts","../src/time/relativeTime.ts","../src/time/validate.ts","../src/time/utils.ts","../src/phone/formatPhone.ts","../src/phone/validatePhone.ts","../src/phone/utils.ts","../src/utils/validateBangla.ts","../src/utils/isBanglaDigit.ts","../src/utils/isBanglaText.ts","../src/utils/utils.ts"],"sourcesContent":["export * from './constants';\nexport * from './number';\nexport * from './currency';\nexport * from './date';\nexport * from './month';\nexport * from './weekday';\nexport * from './season';\nexport * from './ordinal';\nexport * from './time';\nexport * from './calendar';\nexport * from './phone';\nexport * from './utils';\n","export const BANGLA_DIGITS = ['০', '১', '২', '৩', '৪', '৫', '৬', '৭', '৮', '৯'] as const;\n\nexport const ENGLISH_DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] as const;\n","export const BANGLA_MONTHS = [\n 'বৈশাখ',\n 'জ্যৈষ্ঠ',\n 'আষাঢ়',\n 'শ্রাবণ',\n 'ভাদ্র',\n 'আশ্বিন',\n 'কার্তিক',\n 'অগ্রহায়ণ',\n 'পৌষ',\n 'মাঘ',\n 'ফাল্গুন',\n 'চৈত্র',\n] as const;\n","export const BANGLA_WEEKDAYS = [\n 'রবিবার',\n 'সোমবার',\n 'মঙ্গলবার',\n 'বুধবার',\n 'বৃহস্পতিবার',\n 'শুক্রবার',\n 'শনিবার',\n] as const;\n","export const BANGLA_SEASONS = ['গ্রীষ্ম', 'বর্ষা', 'শরৎ', 'হেমন্ত', 'শীত', 'বসন্ত'] as const;\n","import { BANGLA_DIGITS, ENGLISH_DIGITS } from '../constants';\n\n/**\n * Converts English/Arabic digits to Bangla digits.\n *\n * This function converts numbers (or numeric strings) from English/Arabic numerals (0-9)\n * to their Bangla equivalents (০-৯). It preserves the structure of the number including\n * decimal points and negative signs.\n *\n * @param input - A number or numeric string to convert\n * @returns The number with Bangla digits\n * @throws {TypeError} If input is null, undefined, not finite, or an unsafe integer\n * @throws {Error} If input contains invalid characters, multiple decimals, or scientific notation\n *\n * @example\n * Basic conversion:\n * ```typescript\n * toBanglaNumber(123); // '১২৩'\n * toBanglaNumber('456'); // '৪৫৬'\n * ```\n *\n * @example\n * Decimal numbers:\n * ```typescript\n * toBanglaNumber(123.456); // '১২৩.৪৫৬'\n * toBanglaNumber('99.99'); // '৯৯.৯৯'\n * ```\n *\n * @example\n * Negative numbers:\n * ```typescript\n * toBanglaNumber(-123); // '-১২৩'\n * toBanglaNumber('-456.78'); // '-৪৫৬.৭৮'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * toBanglaNumber(NaN); // throws TypeError: Input must be a finite number\n * toBanglaNumber(Infinity); // throws TypeError: Input must be a finite number\n * toBanglaNumber('abc'); // throws Error: Invalid character in number: a\n * toBanglaNumber('১২৩'); // throws Error: Input already contains Bangla digits\n * toBanglaNumber('12.34.56'); // throws Error: Multiple decimal points\n * toBanglaNumber(1e100); // throws TypeError: Input must be a safe integer\n * ```\n */\nexport function toBanglaNumber(input: number | string): string {\n if (input === null || input === undefined) {\n throw new TypeError('Invalid input');\n }\n\n const value = String(input).trim();\n\n if (value === '') {\n throw new Error('Empty input');\n }\n\n // Reject scientific notation\n if (/[eE]/.test(value)) {\n throw new Error('Scientific notation not supported');\n }\n\n // Explicit numeric validation (VERY important)\n if (typeof input === 'number') {\n if (!Number.isFinite(input)) {\n throw new TypeError('Input must be a finite number');\n }\n // Reject scientific notation (check if number is exactly a power of 10 >= 1e5)\n // This catches cases like 1e5, 1e6, etc. that are commonly written in scientific notation\n // We check if the number is exactly 10^N where N >= 5\n if (Number.isInteger(input) && Math.abs(input) >= 1e5) {\n const absInput = Math.abs(input);\n // Check if it's exactly a power of 10 (10^N)\n const log10 = Math.log10(absInput);\n if (Number.isInteger(log10) && log10 >= 5) {\n throw new Error('Scientific notation not supported');\n }\n }\n // Reject unsafe integers (only check if it's an integer)\n if (Number.isInteger(input) && !Number.isSafeInteger(input)) {\n throw new TypeError('Input must be a safe integer');\n }\n }\n\n // Reject Bangla digits already present\n if (/[০-৯]/.test(value)) {\n throw new Error('Input already contains Bangla digits');\n }\n\n let hasDecimal = false;\n let hasDigit = false;\n let result = '';\n\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n\n if (char === '.') {\n if (hasDecimal) {\n throw new Error('Multiple decimal points');\n }\n hasDecimal = true;\n result += '.';\n continue;\n }\n\n if (char === '-') {\n if (i !== 0) {\n throw new Error('Invalid minus position');\n }\n result += '-';\n continue;\n }\n\n const index = ENGLISH_DIGITS.indexOf(char as any);\n if (index !== -1) {\n hasDigit = true;\n result += BANGLA_DIGITS[index];\n continue;\n }\n\n throw new Error(`Invalid character in number: ${char}`);\n }\n\n if (!hasDigit) {\n throw new Error('No digits found');\n }\n\n if (hasDecimal) {\n if (value.startsWith('.') || value.startsWith('-.')) {\n throw new Error('Decimal must have leading digit');\n }\n if (value.endsWith('.')) {\n throw new Error('Decimal must have trailing digit');\n }\n }\n\n return result;\n}\n","import { BANGLA_DIGITS, ENGLISH_DIGITS } from '../constants';\n\n/**\n * Converts Bangla digits to a JavaScript number.\n *\n * This function parses a string containing Bangla numerals (০-৯) and converts it\n * to a JavaScript number. It supports decimals and negative numbers.\n *\n * @param input - A string containing Bangla digits\n * @returns The parsed JavaScript number\n * @throws {TypeError} If input is not a string or cannot be parsed to a finite number\n * @throws {Error} If input is empty, contains invalid characters, or has multiple decimals\n *\n * @example\n * Basic conversion:\n * ```typescript\n * fromBanglaNumber('১২৩'); // 123\n * fromBanglaNumber('৪৫৬'); // 456\n * ```\n *\n * @example\n * Decimal numbers:\n * ```typescript\n * fromBanglaNumber('১২৩.৪৫৬'); // 123.456\n * fromBanglaNumber('৯৯.৯৯'); // 99.99\n * ```\n *\n * @example\n * Negative numbers:\n * ```typescript\n * fromBanglaNumber('-১২৩'); // -123\n * fromBanglaNumber('-৪৫৬.৭৮'); // -456.78\n * ```\n *\n * @example\n * Round-trip conversion:\n * ```typescript\n * const original = 123.45;\n * const bangla = toBanglaNumber(original); // '১২৩.৪৫'\n * const converted = fromBanglaNumber(bangla); // 123.45\n * console.log(original === converted); // true\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * fromBanglaNumber(123); // throws TypeError: Input must be a string\n * fromBanglaNumber(''); // throws Error: Empty input\n * fromBanglaNumber('abc'); // throws Error: Invalid Bangla digit: a\n * fromBanglaNumber('১২৩.৪৫.৬৭'); // throws Error: Multiple decimal points\n * fromBanglaNumber('.৫'); // throws Error: Decimal must have leading digit\n * ```\n */\nexport function fromBanglaNumber(input: string): number {\n if (typeof input !== 'string') {\n throw new TypeError('Input must be a string');\n }\n\n const value = input.trim();\n\n if (value === '') {\n throw new Error('Empty input');\n }\n\n let hasDecimal = false;\n let hasDigit = false;\n let result = '';\n\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n\n if (char === '.') {\n if (hasDecimal) {\n throw new Error('Multiple decimal points');\n }\n hasDecimal = true;\n result += '.';\n continue;\n }\n\n if (char === '-') {\n if (i !== 0) {\n throw new Error('Invalid minus position');\n }\n result += '-';\n continue;\n }\n\n const index = BANGLA_DIGITS.indexOf(char as any);\n if (index !== -1) {\n hasDigit = true;\n result += ENGLISH_DIGITS[index];\n continue;\n }\n\n throw new Error(`Invalid Bangla digit: ${char}`);\n }\n\n if (!hasDigit) {\n throw new Error('No digits found');\n }\n\n if (hasDecimal) {\n if (value.startsWith('.') || value.startsWith('-.')) {\n throw new Error('Decimal must have leading digit');\n }\n if (value.endsWith('.')) {\n throw new Error('Decimal must have trailing digit');\n }\n }\n\n const parsed = Number(result);\n if (!Number.isFinite(parsed)) {\n throw new TypeError('Failed to parse Bangla number');\n }\n\n return parsed;\n}\n","/**\n * Converts a number to its word representation in Bangla.\n *\n * This function converts integers to their Bangla word form following Bangladesh\n * linguistic conventions. It supports numbers from -99,999,999,999 to 99,999,999,999\n * (just under 100 billion).\n *\n * **Supported Range:** -99,999,999,999 to 99,999,999,999\n *\n * **Special Cases:** The function uses linguistically correct Bangla spellings for\n * certain compound numbers:\n * - 23 → \"তেইশ\" (not \"বিশ তিন\")\n * - 34 → \"চৌত্রিশ\" (not \"তিরিশ চার\")\n * - 56 → \"ছাপ্পান্ন\" (not \"পঞ্চাশ ছয়\")\n *\n * @param number - The integer to convert (must be within supported range)\n * @returns The number in Bangla words\n * @throws {Error} If the number exceeds 99,999,999,999 (100 billion or more)\n *\n * @example\n * Basic numbers:\n * ```typescript\n * toWords(0); // 'শূন্য'\n * toWords(5); // 'পাঁচ'\n * toWords(15); // 'পনেরো'\n * toWords(42); // 'চল্লিশ দুই'\n * ```\n *\n * @example\n * Special compound numbers:\n * ```typescript\n * toWords(23); // 'তেইশ'\n * toWords(34); // 'চৌত্রিশ'\n * toWords(56); // 'ছাপ্পান্ন'\n * ```\n *\n * @example\n * Hundreds and thousands:\n * ```typescript\n * toWords(100); // 'একশত'\n * toWords(250); // 'দুইশত পঞ্চাশ'\n * toWords(1000); // 'এক হাজার'\n * toWords(1500); // 'এক হাজার পাঁচশত'\n * toWords(12345); // 'বারো হাজার তিনশত পঁয়তাল্লিশ'\n * ```\n *\n * @example\n * Lakhs and crores (Indian numbering):\n * ```typescript\n * toWords(100000); // 'এক লক্ষ'\n * toWords(1500000); // 'পনেরো লক্ষ'\n * toWords(10000000); // 'এক কোটি'\n * toWords(50000000); // 'পাঁচ কোটি'\n * ```\n *\n * @example\n * Large numbers:\n * ```typescript\n * toWords(1000000000); // 'এক হাজার কোটি' (1 billion)\n * toWords(10000000000); // 'দশ হাজার কোটি' (10 billion)\n * toWords(99999999999); // Maximum supported number\n * ```\n *\n * @example\n * Negative numbers:\n * ```typescript\n * toWords(-5); // 'ঋণাত্মক পাঁচ'\n * toWords(-1000); // 'ঋণাত্মক এক হাজার'\n * toWords(-50000); // 'ঋণাত্মক পঞ্চাশ হাজার'\n * ```\n *\n * @example\n * Error case:\n * ```typescript\n * toWords(100000000000); // throws Error: Number too large to convert to words\n * ```\n *\n * @example\n * Practical usage (invoices, checks):\n * ```typescript\n * const amount = 45000;\n * const words = toWords(amount);\n * console.log(`Amount in words: ${words} টাকা`);\n * // \"Amount in words: পঁয়তাল্লিশ হাজার টাকা\"\n * ```\n */\nexport function toWords(number: number): string {\n if (number === 0) {\n return 'শূন্য';\n }\n\n if (number < 0) {\n return 'ঋণাত্মক ' + toWords(-number);\n }\n\n if (number < 100) {\n return convertBelowHundred(number);\n }\n\n if (number < 1000) {\n return convertBelowThousand(number);\n }\n\n if (number < 100000) {\n return convertBelowLakh(number);\n }\n\n if (number < 10000000) {\n return convertBelowCrore(number);\n }\n\n if (number < 1000000000) {\n return convertBelowArab(number);\n }\n\n if (number < 100000000000) {\n return convertBelowKharab(number);\n }\n\n throw new Error('Number too large to convert to words');\n}\n\nfunction convertBelowHundred(n: number): string {\n const ones = [\n '',\n 'এক',\n 'দুই',\n 'তিন',\n 'চার',\n 'পাঁচ',\n 'ছয়',\n 'সাত',\n 'আট',\n 'নয়',\n 'দশ',\n 'এগারো',\n 'বারো',\n 'তেরো',\n 'চৌদ্দ',\n 'পনেরো',\n 'ষোল',\n 'সতেরো',\n 'আঠারো',\n 'ঊনিশ',\n 'বিশ',\n ];\n\n const tens = ['', '', 'কুড়ি', 'তিরিশ', 'চল্লিশ', 'পঞ্চাশ', 'ষাট', 'সত্তর', 'আশি', 'নব্বই'];\n\n if (n === 0) {\n return '';\n }\n\n if (n < 20) {\n return ones[n];\n }\n\n // Special cases for compound numbers\n if (n === 23) {\n return 'তেইশ';\n }\n if (n === 34) {\n return 'চৌত্রিশ';\n }\n if (n === 56) {\n return 'ছাপ্পান্ন';\n }\n\n const ten = Math.floor(n / 10);\n const one = n % 10;\n\n if (one === 0) {\n return tens[ten];\n }\n\n return tens[ten] + ' ' + ones[one];\n}\n\nfunction convertBelowThousand(n: number): string {\n const hundred = Math.floor(n / 100);\n const remainder = n % 100;\n\n let result = '';\n\n if (hundred > 0) {\n if (hundred === 1) {\n result = 'একশত';\n } else {\n result = convertBelowHundred(hundred) + 'শত';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowHundred(remainder);\n }\n\n return result;\n}\n\nfunction convertBelowLakh(n: number): string {\n const thousand = Math.floor(n / 1000);\n const remainder = n % 1000;\n\n let result = '';\n\n if (thousand > 0) {\n if (thousand === 1) {\n result = 'এক হাজার';\n } else {\n result = convertBelowThousand(thousand) + ' হাজার';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowThousand(remainder);\n }\n\n return result;\n}\n\nfunction convertBelowCrore(n: number): string {\n const lakh = Math.floor(n / 100000);\n const remainder = n % 100000;\n\n let result = '';\n\n if (lakh > 0) {\n if (lakh === 1) {\n result = 'এক লক্ষ';\n } else {\n result = convertBelowThousand(lakh) + ' লক্ষ';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowLakh(remainder);\n }\n\n return result;\n}\n\nfunction convertBelowArab(n: number): string {\n const crore = Math.floor(n / 10000000);\n const remainder = n % 10000000;\n\n let result = '';\n\n if (crore > 0) {\n if (crore === 1) {\n result = 'এক কোটি';\n } else {\n result = convertBelowThousand(crore) + ' কোটি';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowCrore(remainder);\n }\n\n return result;\n}\n\nfunction convertBelowKharab(n: number): string {\n const arab = Math.floor(n / 1000000000);\n const remainder = n % 1000000000;\n\n let result = '';\n\n if (arab > 0) {\n if (arab === 1) {\n result = 'এক হাজার কোটি';\n } else {\n result = convertBelowThousand(arab) + ' হাজার কোটি';\n }\n }\n\n if (remainder > 0) {\n result += (result ? ' ' : '') + convertBelowArab(remainder);\n }\n\n return result;\n}\n","import { toBanglaNumber } from './toBangla';\n\n/**\n * Formats large numbers with Bengali unit names (হাজার, লক্ষ, কোটি).\n *\n * This function simplifies large numbers by expressing them in common Bengali units:\n * - হাজার (Thousand): 1,000\n * - লক্ষ (Lakh): 100,000\n * - কোটি (Crore): 10,000,000\n *\n * The function automatically selects the most appropriate unit based on the number's magnitude.\n *\n * @param number - The number to format\n * @param options - Formatting options\n * @param options.precision - Number of decimal places to show (default: 2)\n * @param options.useBanglaDigits - Whether to use Bangla digits (default: true)\n * @returns Formatted string with unit\n *\n * @example\n * Basic usage with default options:\n * ```typescript\n * formatWithUnits(5000); // '৫ হাজার'\n * formatWithUnits(150000); // '১.৫ লক্ষ'\n * formatWithUnits(25000000); // '২.৫ কোটি'\n * ```\n *\n * @example\n * With English digits:\n * ```typescript\n * formatWithUnits(5000, { useBanglaDigits: false }); // '5 হাজার'\n * formatWithUnits(150000, { useBanglaDigits: false }); // '1.5 লক্ষ'\n * formatWithUnits(25000000, { useBanglaDigits: false }); // '2.5 কোটি'\n * ```\n *\n * @example\n * Custom precision:\n * ```typescript\n * formatWithUnits(1234567, { precision: 0 }); // '১ লক্ষ' (rounded)\n * formatWithUnits(1234567, { precision: 1 }); // '১২.৩ লক্ষ'\n * formatWithUnits(1234567, { precision: 3 }); // '১২.৩৪৬ লক্ষ'\n * ```\n *\n * @example\n * Negative numbers:\n * ```typescript\n * formatWithUnits(-50000); // '-৫ হাজার'\n * formatWithUnits(-1500000); // '-১৫ লক্ষ'\n * ```\n *\n * @example\n * Numbers below 1,000 (no unit):\n * ```typescript\n * formatWithUnits(500); // '৫০০'\n * formatWithUnits(999); // '৯৯৯'\n * ```\n *\n * @example\n * Practical usage (UI display):\n * ```typescript\n * const views = 1250000;\n * const formatted = formatWithUnits(views);\n * console.log(`${formatted} ভিউ`); // '১২.৫ লক্ষ ভিউ'\n *\n * const price = 15000;\n * const formatted2 = formatWithUnits(price);\n * console.log(`৳ ${formatted2}`); // '৳ ১৫ হাজার'\n * ```\n */\nexport function formatWithUnits(\n number: number,\n options: {\n precision?: number;\n useBanglaDigits?: boolean;\n } = {}\n): string {\n const { precision = 2, useBanglaDigits = true } = options;\n\n if (number === 0) {\n return useBanglaDigits ? '০' : '0';\n }\n\n const absNumber = Math.abs(number);\n const sign = number < 0 ? '-' : '';\n\n let value: number;\n let unit: string;\n\n if (absNumber >= 10000000) {\n // কোটি (Crore)\n value = absNumber / 10000000;\n unit = 'কোটি';\n } else if (absNumber >= 100000) {\n // লক্ষ (Lakh)\n value = absNumber / 100000;\n unit = 'লক্ষ';\n } else if (absNumber >= 1000) {\n // হাজার (Thousand)\n value = absNumber / 1000;\n unit = 'হাজার';\n } else {\n // No unit needed\n const formatted = useBanglaDigits ? toBanglaNumber(absNumber) : absNumber.toString();\n return sign + formatted;\n }\n\n const rounded = Number(value.toFixed(precision));\n const formatted = useBanglaDigits ? toBanglaNumber(rounded) : rounded.toString();\n\n return sign + formatted + ' ' + unit;\n}\n","import { toBanglaNumber } from './toBangla';\n\nexport interface FormatNumberOptions {\n /** Whether to use Bangla digits (default: true) */\n useBanglaDigits?: boolean;\n /** Separator character for thousands (default: ',') */\n separator?: string;\n}\n\n/**\n * Formats a number with comma separators using Indian/Bangla numbering system\n * Pattern: rightmost 3 digits, then groups of 2 digits\n * @param number - The number to format\n * @param options - Formatting options\n * @returns Formatted number string\n * @example\n * formatNumber(1234567) // '12,34,567'\n * formatNumber(1234567.89) // '12,34,567.89'\n * formatNumber(1234567, { useBanglaDigits: false }) // '12,34,567'\n */\nexport function formatNumber(number: number | string, options: FormatNumberOptions = {}): string {\n const { useBanglaDigits = true, separator = ',' } = options;\n\n const numStr = typeof number === 'string' ? number : number.toString();\n const [integerPart, decimalPart] = numStr.split('.');\n\n // Convert to Bangla digits if needed\n let formattedInteger = integerPart;\n if (useBanglaDigits) {\n formattedInteger = toBanglaNumber(integerPart);\n }\n\n // Format integer part with separators using Indian/Bangla numbering system\n // Pattern: rightmost 3 digits, then groups of 2 digits\n const formatted = formatIntegerPart(formattedInteger, separator);\n\n // Handle decimal part\n if (decimalPart !== undefined) {\n const formattedDecimal = useBanglaDigits ? toBanglaNumber(decimalPart) : decimalPart;\n return `${formatted}.${formattedDecimal}`;\n }\n\n return formatted;\n}\n\n/**\n * Formats integer part with Indian/Bangla numbering system separators\n * Pattern: rightmost 3 digits, then groups of 2 digits\n */\nfunction formatIntegerPart(integerPart: string, separator: string): string {\n // Handle negative sign separately\n const isNegative = integerPart.startsWith('-');\n const absolutePart = isNegative ? integerPart.slice(1) : integerPart;\n const len = absolutePart.length;\n\n if (len <= 3) {\n return integerPart; // Return as-is (preserving minus if present)\n }\n\n // Take rightmost 3 digits\n const rightmost3 = absolutePart.slice(-3);\n const remaining = absolutePart.slice(0, -3);\n\n // Group remaining digits in groups of 2 from right\n const groups: string[] = [];\n for (let i = remaining.length; i > 0; i -= 2) {\n const start = Math.max(0, i - 2);\n groups.unshift(remaining.slice(start, i));\n }\n\n const formatted = `${groups.join(separator)}${separator}${rightmost3}`;\n return isNegative ? `-${formatted}` : formatted;\n}\n","import { BANGLA_DIGITS, ENGLISH_DIGITS } from '../constants';\n\n/**\n * Validates if a string contains a valid Bangla number.\n *\n * This function checks if the input string represents a valid Bangla number\n * without throwing errors, making it ideal for form validation.\n *\n * @param input - The string to validate\n * @returns true if the string is a valid Bangla number, false otherwise\n *\n * @example\n * ```typescript\n * isValidBanglaNumber('১২৩'); // true\n * isValidBanglaNumber('১২৩.৪৫'); // true\n * isValidBanglaNumber('-১২৩'); // true\n * isValidBanglaNumber('123'); // false (English digits)\n * isValidBanglaNumber('১২৩abc'); // false (invalid characters)\n * isValidBanglaNumber(''); // false (empty)\n * ```\n */\nexport function isValidBanglaNumber(input: string): boolean {\n if (typeof input !== 'string') {\n return false;\n }\n\n const value = input.trim();\n\n if (value === '') {\n return false;\n }\n\n let hasDecimal = false;\n let hasDigit = false;\n\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n\n // Check for decimal point\n if (char === '.') {\n if (hasDecimal) {\n return false; // Multiple decimal points\n }\n hasDecimal = true;\n continue;\n }\n\n // Check for minus sign\n if (char === '-') {\n if (i !== 0) {\n return false; // Minus must be at start\n }\n continue;\n }\n\n // Check if it's a valid Bangla digit\n const index = BANGLA_DIGITS.indexOf(char as any);\n if (index !== -1) {\n hasDigit = true;\n continue;\n }\n\n // Invalid character found\n return false;\n }\n\n // Must have at least one digit\n if (!hasDigit) {\n return false;\n }\n\n // Validate decimal placement\n if (hasDecimal) {\n if (value.startsWith('.') || value.startsWith('-.')) {\n return false; // Decimal must have leading digit\n }\n if (value.endsWith('.')) {\n return false; // Decimal must have trailing digit\n }\n }\n\n return true;\n}\n\n/**\n * Validates if a number or string can be converted to a Bangla number.\n *\n * This function checks if the input can be safely processed by `toBanglaNumber()`\n * without throwing errors.\n *\n * @param input - The number or string to validate\n * @returns true if the input can be converted to Bangla, false otherwise\n *\n * @example\n * ```typescript\n * isValidNumber(123); // true\n * isValidNumber('123'); // true\n * isValidNumber('123.45'); // true\n * isValidNumber(-123); // true\n * isValidNumber(NaN); // false\n * isValidNumber(Infinity); // false\n * isValidNumber('abc'); // false\n * isValidNumber('১২৩'); // false (already Bangla)\n * isValidNumber(1e100); // false (unsafe integer)\n * ```\n */\nexport function isValidNumber(input: number | string): boolean {\n if (input === null || input === undefined) {\n return false;\n }\n\n const value = String(input).trim();\n\n if (value === '') {\n return false;\n }\n\n // Reject scientific notation\n if (/[eE]/.test(value)) {\n return false;\n }\n\n // Validate number type inputs\n if (typeof input === 'number') {\n if (!Number.isFinite(input)) {\n return false;\n }\n\n // Reject unsafe integers\n if (Number.isInteger(input) && !Number.isSafeInteger(input)) {\n return false;\n }\n\n // Reject scientific notation (powers of 10 >= 1e5)\n if (Number.isInteger(input) && Math.abs(input) >= 1e5) {\n const absInput = Math.abs(input);\n const log10 = Math.log10(absInput);\n if (Number.isInteger(log10) && log10 >= 5) {\n return false;\n }\n }\n }\n\n // Reject if already contains Bangla digits\n if (/[০-৯]/.test(value)) {\n return false;\n }\n\n let hasDecimal = false;\n let hasDigit = false;\n\n for (let i = 0; i < value.length; i++) {\n const char = value[i];\n\n // Check for decimal point\n if (char === '.') {\n if (hasDecimal) {\n return false; // Multiple decimal points\n }\n hasDecimal = true;\n continue;\n }\n\n // Check for minus sign\n if (char === '-') {\n if (i !== 0) {\n return false; // Minus must be at start\n }\n continue;\n }\n\n // Check if it's a valid English digit\n const index = ENGLISH_DIGITS.indexOf(char as any);\n if (index !== -1) {\n hasDigit = true;\n continue;\n }\n\n // Invalid character found\n return false;\n }\n\n // Must have at least one digit\n if (!hasDigit) {\n return false;\n }\n\n // Validate decimal placement\n if (hasDecimal) {\n if (value.startsWith('.') || value.startsWith('-.')) {\n return false; // Decimal must have leading digit\n }\n if (value.endsWith('.')) {\n return false; // Decimal must have trailing digit\n }\n }\n\n return true;\n}\n\n/**\n * Validates if a number can be converted to Bangla words.\n *\n * The `toWords()` function supports numbers from -99,999,999,999 to 99,999,999,999\n * (just under 100 billion). This function checks if a number is within that range.\n *\n * @param input - The number to validate\n * @returns true if the number can be converted to words, false otherwise\n *\n * @example\n * ```typescript\n * isValidNumberForWords(123); // true\n * isValidNumberForWords(99999999999); // true (max supported)\n * isValidNumberForWords(100000000000); // false (too large)\n * isValidNumberForWords(-99999999999); // true\n * isValidNumberForWords(123.45); // false (decimals not supported)\n * isValidNumberForWords(NaN); // false\n * ```\n */\nexport function isValidNumberForWords(input: number): boolean {\n if (typeof input !== 'number') {\n return false;\n }\n\n if (!Number.isFinite(input)) {\n return false;\n }\n\n if (!Number.isInteger(input)) {\n return false; // toWords only supports integers\n }\n\n // toWords supports up to 99,999,999,999 (just under 100 billion)\n const MAX_SUPPORTED = 99999999999;\n const MIN_SUPPORTED = -99999999999;\n\n return input >= MIN_SUPPORTED && input <= MAX_SUPPORTED;\n}\n\n/**\n * Validates if a number can be converted to ordinal form.\n *\n * The `toOrdinal()` function only supports positive integers.\n *\n * @param input - The number to validate\n * @returns true if the number can be converted to ordinal, false otherwise\n *\n * @example\n * ```typescript\n * isValidNumberForOrdinal(1); // true\n * isValidNumberForOrdinal(100); // true\n * isValidNumberForOrdinal(0); // false\n * isValidNumberForOrdinal(-1); // false\n * isValidNumberForOrdinal(1.5); // false (decimals not supported)\n * ```\n */\nexport function isValidNumberForOrdinal(input: number): boolean {\n if (typeof input !== 'number') {\n return false;\n }\n\n if (!Number.isFinite(input)) {\n return false;\n }\n\n if (!Number.isInteger(input)) {\n return false;\n }\n\n return input > 0;\n}\n\n/**\n * Sanitizes user input for number conversion.\n *\n * This function cleans common user input issues like:\n * - Extra whitespace\n * - Comma separators (1,234 -> 1234)\n * - Leading/trailing zeros (when appropriate)\n *\n * Note: This does NOT validate the input. Use `isValidNumber()` after sanitization\n * to check if the result is valid.\n *\n * @param input - The string to sanitize\n * @returns Sanitized string\n *\n * @example\n * ```typescript\n * sanitizeNumberInput(' 123 '); // '123'\n * sanitizeNumberInput('1,234.56'); // '1234.56'\n * sanitizeNumberInput('১,২৩৪'); // '১২৩৪'\n * sanitizeNumberInput('০০১২৩'); // '০০১২৩' (preserves leading zeros)\n * ```\n */\nexport function sanitizeNumberInput(input: string): string {\n if (typeof input !== 'string') {\n return '';\n }\n\n // Trim whitespace\n let result = input.trim();\n\n // Remove comma separators (both English and Bangla)\n result = result.replace(/,/g, '');\n result = result.replace(/৳/g, ''); // Remove Taka symbol if present\n\n // Trim again after removing symbols\n return result.trim();\n}\n","import { toBanglaNumber } from './toBangla';\nimport { fromBanglaNumber } from './fromBangla';\nimport { formatNumber } from './formatNumber';\nimport { toWords } from './toWords';\nimport { sanitizeNumberInput } from './validate';\n\n/**\n * Result of a batch conversion operation.\n */\nexport interface BatchConversionResult {\n /** Successfully converted values */\n success: Array<{ input: number | string; output: string }>;\n /** Failed conversions with error messages */\n errors: Array<{ input: number | string; error: string }>;\n}\n\n/**\n * Converts multiple numbers to Bangla in a single operation.\n *\n * This function processes an array of numbers/strings and converts them to Bangla,\n * collecting both successful conversions and errors. This is useful for batch\n * processing where you want to continue even if some inputs fail.\n *\n * @param inputs - Array of numbers or strings to convert\n * @returns Object containing successful conversions and errors\n *\n * @example\n * ```typescript\n * const results = batchToBanglaNumber([123, '456', 'invalid', 789]);\n * console.log(results.success);\n * // [\n * // { input: 123, output: '১২৩' },\n * // { input: '456', output: '৪৫৬' },\n * // { input: 789, output: '৭৮৯' }\n * // ]\n * console.log(results.errors);\n * // [{ input: 'invalid', error: 'Invalid character in number: i' }]\n * ```\n */\nexport function batchToBanglaNumber(\n inputs: Array<number | string>\n): BatchConversionResult {\n const success: Array<{ input: number | string; output: string }> = [];\n const errors: Array<{ input: number | string; error: string }> = [];\n\n for (const input of inputs) {\n try {\n const output = toBanglaNumber(input);\n success.push({ input, output });\n } catch (error) {\n errors.push({\n input,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return { success, errors };\n}\n\n/**\n * Converts multiple Bangla numbers to JavaScript numbers in a single operation.\n *\n * @param inputs - Array of Bangla number strings to convert\n * @returns Object containing successful conversions and errors\n *\n * @example\n * ```typescript\n * const results = batchFromBanglaNumber(['১২৩', '৪৫৬', 'invalid']);\n * console.log(results.success);\n * // [\n * // { input: '১২৩', output: 123 },\n * // { input: '৪৫৬', output: 456 }\n * // ]\n * console.log(results.errors);\n * // [{ input: 'invalid', error: 'Invalid Bangla digit: i' }]\n * ```\n */\nexport function batchFromBanglaNumber(\n inputs: string[]\n): { success: Array<{ input: string; output: number }>; errors: Array<{ input: string; error: string }> } {\n const success: Array<{ input: string; output: number }> = [];\n const errors: Array<{ input: string; error: string }> = [];\n\n for (const input of inputs) {\n try {\n const output = fromBanglaNumber(input);\n success.push({ input, output });\n } catch (error) {\n errors.push({\n input,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return { success, errors };\n}\n\n/**\n * Safely converts a number to Bangla with a fallback value.\n *\n * This is useful in UI contexts where you want to always display something,\n * even if the conversion fails.\n *\n * @param input - The number or string to convert\n * @param fallback - Value to return if conversion fails (default: '')\n * @returns Bangla number string or fallback value\n *\n * @example\n * ```typescript\n * safeToBanglaNumber(123); // '১২৩'\n * safeToBanglaNumber(NaN, '---'); // '---'\n * safeToBanglaNumber(Infinity, 'N/A'); // 'N/A'\n * ```\n */\nexport function safeToBanglaNumber(\n input: number | string,\n fallback: string = ''\n): string {\n try {\n return toBanglaNumber(input);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely converts a Bangla number to a JavaScript number with a fallback.\n *\n * @param input - The Bangla number string to convert\n * @param fallback - Value to return if conversion fails (default: 0)\n * @returns JavaScript number or fallback value\n *\n * @example\n * ```typescript\n * safeFromBanglaNumber('১২৩'); // 123\n * safeFromBanglaNumber('invalid', -1); // -1\n * ```\n */\nexport function safeFromBanglaNumber(\n input: string,\n fallback: number = 0\n): number {\n try {\n return fromBanglaNumber(input);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Parses user input with sanitization and conversion to Bangla.\n *\n * This function combines sanitization and conversion in a single step,\n * making it ideal for processing form inputs or user-entered data.\n *\n * @param input - The user input string to parse\n * @returns Bangla number string\n * @throws Error if the sanitized input is invalid\n *\n * @example\n * ```typescript\n * parseAndConvertToBangla(' 1,234.56 '); // '১২৩৪.৫৬'\n * parseAndConvertToBangla('৳ 1,000'); // '১০০০'\n * parseAndConvertToBangla('invalid'); // throws Error\n * ```\n */\nexport function parseAndConvertToBangla(input: string): string {\n const sanitized = sanitizeNumberInput(input);\n return toBanglaNumber(sanitized);\n}\n\n/**\n * Formats a number with comma separators and optionally converts to Bangla.\n *\n * This is a convenience function that combines formatting and digit conversion.\n *\n * @param input - The number to format\n * @param useBanglaDigits - Whether to use Bangla digits (default: true)\n * @param separator - Separator character (default: ',')\n * @returns Formatted number string\n *\n * @example\n * ```typescript\n * formatAndConvert(1234567); // '১২,৩৪,৫৬৭'\n * formatAndConvert(1234567, false); // '12,34,567'\n * formatAndConvert(1234567, true, ' '); // '১২ ৩৪ ৫৬৭'\n * ```\n */\nexport function formatAndConvert(\n input: number,\n useBanglaDigits: boolean = true,\n separator: string = ','\n): string {\n return formatNumber(input, { useBanglaDigits, separator });\n}\n\n/**\n * Converts a number to its word representation and also provides the Bangla digit form.\n *\n * This is useful when you want to display both forms, such as on checks or invoices.\n *\n * @param input - The number to convert\n * @returns Object with both word and digit representations\n *\n * @example\n * ```typescript\n * const result = convertToWordsAndDigits(123);\n * console.log(result.words); // 'এক শত তেইশ'\n * console.log(result.digits); // '১২৩'\n *\n * // Useful for invoices:\n * const amount = convertToWordsAndDigits(1500);\n * console.log(`Amount: ${amount.digits} (${amount.words} টাকা)`);\n * // Amount: ১৫০০ (এক হাজার পাঁচ শত টাকা)\n * ```\n */\nexport function convertToWordsAndDigits(input: number): {\n words: string;\n digits: string;\n} {\n return {\n words: toWords(input),\n digits: toBanglaNumber(input),\n };\n}\n\n/**\n * Range validation: checks if a number is within a specified range.\n *\n * This is useful for form validation or business logic where numbers\n * must fall within certain bounds.\n *\n * @param value - The number to check\n * @param min - Minimum allowed value (inclusive)\n * @param max - Maximum allowed value (inclusive)\n * @returns true if value is within range, false otherwise\n *\n * @example\n * ```typescript\n * isNumberInRange(50, 0, 100); // true\n * isNumberInRange(150, 0, 100); // false\n * isNumberInRange(-5, 0, 100); // false\n * ```\n */\nexport function isNumberInRange(value: number, min: number, max: number): boolean {\n if (!Number.isFinite(value)) {\n return false;\n }\n return value >= min && value <= max;\n}\n\n/**\n * Truncates a number to a specified number of decimal places without rounding.\n *\n * Unlike toFixed(), this function truncates rather than rounds.\n *\n * @param value - The number to truncate\n * @param decimals - Number of decimal places to keep (default: 2)\n * @returns Truncated number\n *\n * @example\n * ```typescript\n * truncateDecimals(123.456789, 2); // 123.45\n * truncateDecimals(123.999, 1); // 123.9 (not 124.0)\n * truncateDecimals(100, 2); // 100\n * ```\n */\nexport function truncateDecimals(value: number, decimals: number = 2): number {\n const multiplier = Math.pow(10, decimals);\n return Math.trunc(value * multiplier) / multiplier;\n}\n","import { toBanglaNumber } from '../number';\n\n/**\n * Formats a number as Bangladeshi Taka currency in Bangla.\n *\n * This function converts numeric currency amounts to Bengali format with\n * the Taka symbol (৳) and/or word (টাকা). Amounts are automatically formatted\n * to 2 decimal places.\n *\n * **Currency Symbol:** ৳ (Taka sign)\n * **Currency Word:** টাকা (Taka)\n *\n * @param amount - The amount to format (number or string)\n * @param options - Formatting options\n * @param options.includeSymbol - Include the ৳ symbol (default: true)\n * @param options.includeWord - Include the word \"টাকা\" (default: false)\n * @returns Formatted currency string in Bangla\n * @throws {Error} If amount is NaN or cannot be parsed\n *\n * @example\n * Basic formatting with symbol (default):\n * ```typescript\n * formatCurrency(1234.56);\n * // '৳ ১২৩৪.৫৬'\n *\n * formatCurrency(100);\n * // '৳ ১০০.০০'\n *\n * formatCurrency('999.99');\n * // '৳ ৯৯৯.৯৯'\n * ```\n *\n * @example\n * Without symbol:\n * ```typescript\n * formatCurrency(1234.56, { includeSymbol: false });\n * // '১২৩৪.৫৬'\n *\n * formatCurrency(500, { includeSymbol: false });\n * // '৫০০.০০'\n * ```\n *\n * @example\n * With word \"টাকা\":\n * ```typescript\n * formatCurrency(100, { includeWord: true });\n * // '৳ ১০০.০০ টাকা'\n *\n * formatCurrency(1000, { includeWord: true });\n * // '৳ ১০০০.০০ টাকা'\n *\n * formatCurrency(50, { includeSymbol: false, includeWord: true });\n * // '৫০.০০ টাকা'\n * ```\n *\n * @example\n * Large amounts:\n * ```typescript\n * formatCurrency(1000000);\n * // '৳ ১০০০০০০.০০'\n *\n * formatCurrency(50000000, { includeWord: true });\n * // '৳ ৫০০০০০০০.০০ টাকা'\n * ```\n *\n * @example\n * Small and zero amounts:\n * ```typescript\n * formatCurrency(0);\n * // '৳ ০.০০'\n *\n * formatCurrency(0.5);\n * // '৳ ০.৫০'\n *\n * formatCurrency(0.01);\n * // '৳ ০.০১'\n * ```\n *\n * @example\n * Negative amounts (debits):\n * ```typescript\n * formatCurrency(-100);\n * // '৳ -১০০.০০'\n *\n * formatCurrency(-1234.56, { includeWord: true });\n * // '৳ -১২৩৪.৫৬ টাকা'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * formatCurrency('invalid');\n * // throws Error: Invalid amount\n *\n * formatCurrency(NaN);\n * // throws Error: Invalid amount\n * ```\n */\nexport function formatCurrency(\n amount: number | string,\n options: {\n includeSymbol?: boolean;\n includeWord?: boolean;\n } = {}\n): string {\n const { includeSymbol = true, includeWord = false } = options;\n const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;\n\n if (Number.isNaN(numAmount)) {\n throw new Error('Invalid amount');\n }\n\n const banglaAmount = toBanglaNumber(numAmount.toFixed(2));\n const parts: string[] = [];\n\n if (includeSymbol) {\n parts.push('৳');\n }\n\n parts.push(banglaAmount);\n\n if (includeWord) {\n parts.push('টাকা');\n }\n\n return parts.join(' ');\n}\n\n","import { fromBanglaNumber } from '../number';\n\n/**\n * Parses a Bangla currency string to a number.\n *\n * This function extracts numeric values from Bengali currency strings,\n * automatically removing currency symbols (৳) and words (টাকা).\n * It supports various formatting styles commonly used in Bangladesh.\n *\n * **Recognized Elements:**\n * - Currency symbol: ৳\n * - Currency word: টাকা\n * - Bangla digits: ০-৯\n *\n * @param currencyString - The currency string to parse\n * @returns The numeric amount as a JavaScript number\n *\n * @example\n * With symbol:\n * ```typescript\n * parseCurrency('৳ ১২৩৪.৫৬');\n * // 1234.56\n *\n * parseCurrency('৳১০০');\n * // 100\n *\n * parseCurrency('৳ ১০০.৫০');\n * // 100.5\n * ```\n *\n * @example\n * With word \"টাকা\":\n * ```typescript\n * parseCurrency('১০০.০০ টাকা');\n * // 100\n *\n * parseCurrency('১০০ টাকা');\n * // 100\n *\n * parseCurrency('৫০০ টাকা');\n * // 500\n * ```\n *\n * @example\n * With both symbol and word:\n * ```typescript\n * parseCurrency('৳ ১০০.০০ টাকা');\n * // 100\n *\n * parseCurrency('৳ ৫০০ টাকা');\n * // 500\n * ```\n *\n * @example\n * Without symbol or word (plain Bangla numbers):\n * ```typescript\n * parseCurrency('১০০');\n * // 100\n *\n * parseCurrency('১২৩৪.৫৬');\n * // 1234.56\n *\n * parseCurrency('৫০০');\n * // 500\n * ```\n *\n * @example\n * With whitespace and formatting:\n * ```typescript\n * parseCurrency(' ৳ ১০০ ');\n * // 100\n *\n * parseCurrency('৳ ১০০.৫০ টাকা');\n * // 100.5\n * ```\n *\n * @example\n * Large amounts:\n * ```typescript\n * parseCurrency('৳ ১০০০০০০.০০');\n * // 1000000\n *\n * parseCurrency('৫০০০০০০০ টাকা');\n * // 50000000\n * ```\n *\n * @example\n * Negative amounts:\n * ```typescript\n * parseCurrency('৳ -১০০.০০');\n * // -100\n *\n * parseCurrency('-৫০০ টাকা');\n * // -500\n * ```\n */\nexport function parseCurrency(currencyString: string): number {\n // Remove currency symbols and words\n let cleaned = currencyString\n .replace(/৳/g, '')\n .replace(/টাকা/g, '')\n .trim();\n\n // Remove any extra whitespace\n cleaned = cleaned.replace(/\\s+/g, '');\n\n return fromBanglaNumber(cleaned);\n}\n\n","/**\n * Checks if a value is a valid currency amount.\n *\n * Valid currency amounts must be finite numbers (can be negative for debits).\n *\n * @param value - The value to check\n * @returns true if the value is a valid currency amount\n *\n * @example\n * ```typescript\n * isValidCurrency(100); // true\n * isValidCurrency(1234.56); // true\n * isValidCurrency(-50); // true (negative amounts allowed)\n * isValidCurrency(0); // true\n * isValidCurrency(NaN); // false\n * isValidCurrency(Infinity); // false\n * isValidCurrency('100' as any); // false\n * ```\n */\nexport function isValidCurrency(value: number): boolean {\n return typeof value === 'number' && !isNaN(value) && isFinite(value);\n}\n\n/**\n * Checks if a string appears to be a Bangla currency format.\n *\n * This function checks if the string contains the Taka symbol (৳)\n * or the word \"টাকা\", or contains Bangla digits.\n *\n * @param value - The string to check\n * @returns true if the string appears to be Bangla currency\n *\n * @example\n * ```typescript\n * isBanglaCurrency('৳ ১২৩৪.৫৬'); // true\n * isBanglaCurrency('১০০ টাকা'); // true\n * isBanglaCurrency('৳১২৩৪'); // true\n * isBanglaCurrency('১২৩৪.৫৬'); // true (has Bangla digits)\n * isBanglaCurrency('1234.56'); // false\n * isBanglaCurrency('hello'); // false\n * ```\n */\nexport function isBanglaCurrency(value: string): boolean {\n if (typeof value !== 'string' || !value.trim()) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Check for currency symbol or word\n if (trimmed.includes('৳') || trimmed.includes('টাকা')) {\n return true;\n }\n\n // Check for Bangla digits\n const banglaDigitPattern = /[০-৯]/;\n return banglaDigitPattern.test(trimmed);\n}\n\n/**\n * Checks if a currency amount is positive (greater than 0).\n *\n * @param value - The currency amount to check\n * @returns true if the amount is positive\n *\n * @example\n * ```typescript\n * isPositiveAmount(100); // true\n * isPositiveAmount(0.01); // true\n * isPositiveAmount(0); // false\n * isPositiveAmount(-50); // false\n * ```\n */\nexport function isPositiveAmount(value: number): boolean {\n return isValidCurrency(value) && value > 0;\n}\n\n/**\n * Checks if a currency amount is negative (less than 0).\n *\n * @param value - The currency amount to check\n * @returns true if the amount is negative\n *\n * @example\n * ```typescript\n * isNegativeAmount(-100); // true\n * isNegativeAmount(-0.01); // true\n * isNegativeAmount(0); // false\n * isNegativeAmount(50); // false\n * ```\n */\nexport function isNegativeAmount(value: number): boolean {\n return isValidCurrency(value) && value < 0;\n}\n\n/**\n * Checks if a currency amount is zero.\n *\n * @param value - The currency amount to check\n * @returns true if the amount is exactly zero\n *\n * @example\n * ```typescript\n * isZeroAmount(0); // true\n * isZeroAmount(-0); // true\n * isZeroAmount(0.00); // true\n * isZeroAmount(0.01); // false\n * isZeroAmount(100); // false\n * ```\n */\nexport function isZeroAmount(value: number): boolean {\n return isValidCurrency(value) && value === 0;\n}\n\n/**\n * Sanitizes currency input to ensure it's a valid number.\n *\n * This function:\n * - Converts string numbers to floats\n * - Removes common currency symbols and whitespace from strings\n * - Returns null for invalid inputs\n *\n * @param value - The input value to sanitize\n * @returns Sanitized number or null if invalid\n *\n * @example\n * ```typescript\n * sanitizeCurrencyInput('1234.56'); // 1234.56\n * sanitizeCurrencyInput('৳ 100'); // '৳ 100' (as string, needs parseCurrency)\n * sanitizeCurrencyInput(500); // 500\n * sanitizeCurrencyInput('invalid'); // null\n * sanitizeCurrencyInput(NaN); // null\n * ```\n */\nexport function sanitizeCurrencyInput(value: any): number | string | null {\n // Handle number input\n if (typeof value === 'number') {\n if (isNaN(value) || !isFinite(value)) {\n return null;\n }\n return value;\n }\n\n // Handle string input\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') {\n return null;\n }\n\n // If it contains Bangla currency symbols/digits, return as-is for parseCurrency\n if (isBanglaCurrency(trimmed)) {\n return trimmed;\n }\n\n // Try to parse as regular number\n const parsed = parseFloat(trimmed);\n if (isNaN(parsed)) {\n return null;\n }\n return parsed;\n }\n\n return null;\n}\n\n/**\n * Checks if a currency amount is within a valid range.\n *\n * @param value - The currency amount to check\n * @param min - Minimum value (inclusive)\n * @param max - Maximum value (inclusive)\n * @returns true if the amount is within the range\n *\n * @example\n * ```typescript\n * isCurrencyInRange(50, 0, 100); // true\n * isCurrencyInRange(100, 0, 100); // true\n * isCurrencyInRange(150, 0, 100); // false\n * isCurrencyInRange(-50, 0, 100); // false\n * ```\n */\nexport function isCurrencyInRange(value: number, min: number, max: number): boolean {\n if (!isValidCurrency(value) || !isValidCurrency(min) || !isValidCurrency(max)) {\n return false;\n }\n\n if (min > max) {\n return false;\n }\n\n return value >= min && value <= max;\n}\n\n/**\n * Checks if a currency string has the Taka symbol (৳).\n *\n * @param value - The currency string to check\n * @returns true if the string contains ৳\n *\n * @example\n * ```typescript\n * hasTakaSymbol('৳ ১০০'); // true\n * hasTakaSymbol('৳১০০'); // true\n * hasTakaSymbol('১০০ টাকা'); // false\n * hasTakaSymbol('100'); // false\n * ```\n */\nexport function hasTakaSymbol(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n return value.includes('৳');\n}\n\n/**\n * Checks if a currency string has the word \"টাকা\".\n *\n * @param value - The currency string to check\n * @returns true if the string contains টাকা\n *\n * @example\n * ```typescript\n * hasTakaWord('১০০ টাকা'); // true\n * hasTakaWord('৳ ১০০ টাকা'); // true\n * hasTakaWord('৳ ১০০'); // false\n * hasTakaWord('100'); // false\n * ```\n */\nexport function hasTakaWord(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n return value.includes('টাকা');\n}\n","import { formatCurrency } from './formatCurrency';\nimport { parseCurrency } from './parseCurrency';\nimport { isValidCurrency, sanitizeCurrencyInput } from './validate';\n\n/**\n * Safely formats a currency amount with a fallback value.\n *\n * Unlike formatCurrency, this function doesn't throw errors for invalid inputs.\n * Instead, it returns the fallback value.\n *\n * @param amount - The amount to format\n * @param options - Formatting options\n * @param fallback - Value to return if formatting fails (default: '')\n * @returns Formatted currency string or fallback value\n *\n * @example\n * ```typescript\n * safeFormatCurrency(1234.56); // '৳ ১২৩৪.৫৬'\n * safeFormatCurrency(NaN); // ''\n * safeFormatCurrency(Infinity, {}, 'N/A'); // 'N/A'\n * safeFormatCurrency(100, { includeWord: true }); // '৳ ১০০.০০ টাকা'\n * ```\n */\nexport function safeFormatCurrency(\n amount: number | string,\n options: {\n includeSymbol?: boolean;\n includeWord?: boolean;\n } = {},\n fallback: string = ''\n): string {\n try {\n const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;\n if (!isValidCurrency(numAmount)) {\n return fallback;\n }\n return formatCurrency(amount, options);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely parses a currency string with a fallback value.\n *\n * @param currencyString - The currency string to parse\n * @param fallback - Value to return if parsing fails (default: 0)\n * @returns Parsed amount or fallback value\n *\n * @example\n * ```typescript\n * safeParseCurrency('৳ ১২৩৪.৫৬'); // 1234.56\n * safeParseCurrency('invalid'); // 0\n * safeParseCurrency('invalid', -1); // -1\n * ```\n */\nexport function safeParseCurrency(currencyString: string, fallback: number = 0): number {\n try {\n const result = parseCurrency(currencyString);\n if (!isValidCurrency(result)) {\n return fallback;\n }\n return result;\n } catch {\n return fallback;\n }\n}\n\n/**\n * Formats an array of currency amounts.\n *\n * @param amounts - Array of amounts to format\n * @param options - Formatting options\n * @returns Array of formatted currency strings (invalid amounts are skipped)\n *\n * @example\n * ```typescript\n * batchFormatCurrency([100, 200, 300]);\n * // ['৳ ১০০.০০', '৳ ২০০.০০', '৳ ৩০০.০০']\n *\n * batchFormatCurrency([100, NaN, 200], { includeWord: true });\n * // ['৳ ১০০.০০ টাকা', '৳ ২০০.০০ টাকা']\n * ```\n */\nexport function batchFormatCurrency(\n amounts: number[],\n options: {\n includeSymbol?: boolean;\n includeWord?: boolean;\n } = {}\n): string[] {\n return amounts\n .filter(amount => isValidCurrency(amount))\n .map(amount => formatCurrency(amount, options));\n}\n\n/**\n * Rounds a currency amount to a specified number of decimal places.\n *\n * @param amount - The amount to round\n * @param decimals - Number of decimal places (default: 2)\n * @returns Rounded amount\n *\n * @example\n * ```typescript\n * roundCurrency(123.456); // 123.46\n * roundCurrency(123.454); // 123.45\n * roundCurrency(123.456, 1); // 123.5\n * roundCurrency(123, 2); // 123.00\n * ```\n */\nexport function roundCurrency(amount: number, decimals: number = 2): number {\n if (!isValidCurrency(amount)) {\n throw new Error('Invalid currency amount');\n }\n\n const multiplier = Math.pow(10, decimals);\n return Math.round(amount * multiplier) / multiplier;\n}\n\n/**\n * Calculates the sum of multiple currency amounts.\n *\n * @param amounts - Array of amounts to sum\n * @returns Total sum rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * sumCurrency([100, 200, 300]); // 600\n * sumCurrency([123.45, 67.89]); // 191.34\n * sumCurrency([10.1, 20.2, 30.3]); // 60.6\n * ```\n */\nexport function sumCurrency(amounts: number[]): number {\n const validAmounts = amounts.filter(amount => isValidCurrency(amount));\n const sum = validAmounts.reduce((acc, amount) => acc + amount, 0);\n return roundCurrency(sum, 2);\n}\n\n/**\n * Calculates the difference between two currency amounts.\n *\n * @param amount1 - First amount\n * @param amount2 - Second amount\n * @returns Difference (amount1 - amount2) rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * subtractCurrency(200, 100); // 100\n * subtractCurrency(150.75, 50.25); // 100.50\n * subtractCurrency(100, 200); // -100\n * ```\n */\nexport function subtractCurrency(amount1: number, amount2: number): number {\n if (!isValidCurrency(amount1) || !isValidCurrency(amount2)) {\n throw new Error('Invalid currency amounts');\n }\n\n return roundCurrency(amount1 - amount2, 2);\n}\n\n/**\n * Multiplies a currency amount by a factor.\n *\n * @param amount - The amount to multiply\n * @param factor - Multiplication factor\n * @returns Product rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * multiplyCurrency(100, 2); // 200\n * multiplyCurrency(123.45, 1.5); // 185.18\n * multiplyCurrency(99.99, 0.5); // 50.00\n * ```\n */\nexport function multiplyCurrency(amount: number, factor: number): number {\n if (!isValidCurrency(amount) || !isValidCurrency(factor)) {\n throw new Error('Invalid currency amount or factor');\n }\n\n return roundCurrency(amount * factor, 2);\n}\n\n/**\n * Divides a currency amount by a divisor.\n *\n * @param amount - The amount to divide\n * @param divisor - Division divisor (must not be zero)\n * @returns Quotient rounded to 2 decimal places\n * @throws {Error} If divisor is zero\n *\n * @example\n * ```typescript\n * divideCurrency(200, 2); // 100\n * divideCurrency(100, 3); // 33.33\n * divideCurrency(150, 4); // 37.50\n * divideCurrency(100, 0); // throws Error\n * ```\n */\nexport function divideCurrency(amount: number, divisor: number): number {\n if (!isValidCurrency(amount) || !isValidCurrency(divisor)) {\n throw new Error('Invalid currency amount or divisor');\n }\n\n if (divisor === 0) {\n throw new Error('Cannot divide by zero');\n }\n\n return roundCurrency(amount / divisor, 2);\n}\n\n/**\n * Calculates a percentage of a currency amount.\n *\n * @param amount - The base amount\n * @param percentage - Percentage (e.g., 15 for 15%)\n * @returns Calculated percentage amount rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * calculatePercentage(1000, 15); // 150 (15% of 1000)\n * calculatePercentage(200, 10); // 20 (10% of 200)\n * calculatePercentage(99.99, 5); // 5.00 (5% of 99.99)\n * ```\n */\nexport function calculatePercentage(amount: number, percentage: number): number {\n if (!isValidCurrency(amount) || !isValidCurrency(percentage)) {\n throw new Error('Invalid currency amount or percentage');\n }\n\n return roundCurrency((amount * percentage) / 100, 2);\n}\n\n/**\n * Applies a discount percentage to a currency amount.\n *\n * @param amount - The original amount\n * @param discountPercent - Discount percentage (e.g., 10 for 10% off)\n * @returns Amount after discount rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * applyDiscount(1000, 10); // 900 (10% off)\n * applyDiscount(500, 25); // 375 (25% off)\n * applyDiscount(199.99, 15); // 169.99 (15% off)\n * ```\n */\nexport function applyDiscount(amount: number, discountPercent: number): number {\n const discount = calculatePercentage(amount, discountPercent);\n return subtractCurrency(amount, discount);\n}\n\n/**\n * Adds tax percentage to a currency amount.\n *\n * @param amount - The base amount\n * @param taxPercent - Tax percentage (e.g., 15 for 15% tax)\n * @returns Amount after tax rounded to 2 decimal places\n *\n * @example\n * ```typescript\n * addTax(1000, 15); // 1150 (15% VAT)\n * addTax(500, 10); // 550 (10% tax)\n * addTax(99.99, 5); // 104.99 (5% tax)\n * ```\n */\nexport function addTax(amount: number, taxPercent: number): number {\n const tax = calculatePercentage(amount, taxPercent);\n return roundCurrency(amount + tax, 2);\n}\n\n/**\n * Splits a currency amount into equal parts.\n *\n * @param amount - The total amount to split\n * @param parts - Number of parts to split into\n * @returns Array of split amounts (last part may differ slightly due to rounding)\n *\n * @example\n * ```typescript\n * splitAmount(100, 3); // [33.33, 33.33, 33.34]\n * splitAmount(150, 2); // [75.00, 75.00]\n * splitAmount(10, 4); // [2.50, 2.50, 2.50, 2.50]\n * ```\n */\nexport function splitAmount(amount: number, parts: number): number[] {\n if (!isValidCurrency(amount)) {\n throw new Error('Invalid currency amount');\n }\n\n if (!Number.isInteger(parts) || parts < 1) {\n throw new Error('Parts must be a positive integer');\n }\n\n const perPart = divideCurrency(amount, parts);\n const result: number[] = Array(parts - 1).fill(perPart);\n\n // Calculate the last part to ensure sum equals original amount\n const sumSoFar = sumCurrency(result);\n const lastPart = subtractCurrency(amount, sumSoFar);\n\n result.push(lastPart);\n return result;\n}\n\n/**\n * Compares two currency amounts.\n *\n * @param amount1 - First amount\n * @param amount2 - Second amount\n * @returns -1 if amount1 < amount2, 0 if equal, 1 if amount1 > amount2\n *\n * @example\n * ```typescript\n * compareCurrency(100, 200); // -1\n * compareCurrency(200, 100); // 1\n * compareCurrency(100, 100); // 0\n * compareCurrency(100.001, 100.002); // -1\n * ```\n */\nexport function compareCurrency(amount1: number, amount2: number): number {\n if (!isValidCurrency(amount1) || !isValidCurrency(amount2)) {\n throw new Error('Invalid currency amounts');\n }\n\n const rounded1 = roundCurrency(amount1, 2);\n const rounded2 = roundCurrency(amount2, 2);\n\n if (rounded1 < rounded2) return -1;\n if (rounded1 > rounded2) return 1;\n return 0;\n}\n\n/**\n * Gets the absolute value of a currency amount.\n *\n * @param amount - The amount\n * @returns Absolute value\n *\n * @example\n * ```typescript\n * getAbsoluteAmount(-100); // 100\n * getAbsoluteAmount(100); // 100\n * getAbsoluteAmount(-50.75); // 50.75\n * ```\n */\nexport function getAbsoluteAmount(amount: number): number {\n if (!isValidCurrency(amount)) {\n throw new Error('Invalid currency amount');\n }\n\n return Math.abs(amount);\n}\n\n/**\n * Converts between positive and negative amounts.\n *\n * @param amount - The amount to negate\n * @returns Negated amount\n *\n * @example\n * ```typescript\n * negateAmount(100); // -100\n * negateAmount(-100); // 100\n * negateAmount(0); // 0\n * ```\n */\nexport function negateAmount(amount: number): number {\n if (!isValidCurrency(amount)) {\n throw new Error('Invalid currency amount');\n }\n\n return -amount;\n}\n\n/**\n * Parses and formats currency in one step.\n *\n * This combines sanitization, validation, and formatting.\n *\n * @param value - Input value (number, string, or currency string)\n * @param options - Formatting options\n * @returns Formatted currency string\n * @throws {Error} If value cannot be parsed as valid currency\n *\n * @example\n * ```typescript\n * parseAndFormatCurrency('1234.56'); // '৳ ১২৩৪.৫৬'\n * parseAndFormatCurrency(' 500 ', { includeWord: true }); // '৳ ৫০০.০০ টাকা'\n * parseAndFormatCurrency(100); // '৳ ১০০.০০'\n * parseAndFormatCurrency('invalid'); // throws Error\n * ```\n */\nexport function parseAndFormatCurrency(\n value: any,\n options: {\n includeSymbol?: boolean;\n includeWord?: boolean;\n } = {}\n): string {\n const sanitized = sanitizeCurrencyInput(value);\n\n if (sanitized === null) {\n throw new Error('Invalid currency input');\n }\n\n // If sanitized is a string (Bangla currency), parse it first\n if (typeof sanitized === 'string') {\n const parsed = parseCurrency(sanitized);\n return formatCurrency(parsed, options);\n }\n\n // Otherwise it's already a number\n return formatCurrency(sanitized, options);\n}\n","import { BANGLA_MONTHS } from '../constants';\n\n/**\n * Converts a month number (1-12) to Bangla month name.\n *\n * This function maps standard month numbers to Bengali calendar month names.\n * The Bengali calendar has 12 months, each with its traditional name.\n *\n * **Month Mapping:**\n * 1. বৈশাখ (Boishakh)\n * 2. জ্যৈষ্ঠ (Jyoishtho)\n * 3. আষাঢ় (Asharh)\n * 4. শ্রাবণ (Srabon)\n * 5. ভাদ্র (Bhadro)\n * 6. আশ্বিন (Ashwin)\n * 7. কার্তিক (Kartik)\n * 8. অগ্রহায়ণ (Ogrohayon)\n * 9. পৌষ (Poush)\n * 10. মাঘ (Magh)\n * 11. ফাল্গুন (Falgun)\n * 12. চৈত্র (Choitro)\n *\n * @param monthNumber - Month number (1-12)\n * @returns Bangla month name\n * @throws {Error} If month number is not between 1 and 12\n *\n * @example\n * First three months:\n * ```typescript\n * toBanglaMonth(1); // 'বৈশাখ'\n * toBanglaMonth(2); // 'জ্যৈষ্ঠ'\n * toBanglaMonth(3); // 'আষাঢ়'\n * ```\n *\n * @example\n * Mid-year months:\n * ```typescript\n * toBanglaMonth(6); // 'আশ্বিন'\n * toBanglaMonth(7); // 'কার্তিক'\n * toBanglaMonth(8); // 'অগ্রহায়ণ'\n * ```\n *\n * @example\n * Last month:\n * ```typescript\n * toBanglaMonth(12); // 'চৈত্র'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * toBanglaMonth(0); // throws Error: Month number must be between 1 and 12\n * toBanglaMonth(13); // throws Error: Month number must be between 1 and 12\n * toBanglaMonth(-1); // throws Error: Month number must be between 1 and 12\n * ```\n *\n * @example\n * Practical usage (dropdown options):\n * ```typescript\n * const months = Array.from({ length: 12 }, (_, i) => ({\n * value: i + 1,\n * label: toBanglaMonth(i + 1)\n * }));\n * // [{ value: 1, label: 'বৈশাখ' }, { value: 2, label: 'জ্যৈষ্ঠ' }, ...]\n * ```\n */\nexport function toBanglaMonth(monthNumber: number): string {\n if (monthNumber < 1 || monthNumber > 12) {\n throw new Error('Month number must be between 1 and 12');\n }\n\n return BANGLA_MONTHS[monthNumber - 1];\n}\n\n","import { BANGLA_MONTHS } from '../constants';\n\n/**\n * Converts a Bangla month name to month number (1-12).\n *\n * This function performs the reverse operation of toBanglaMonth,\n * converting Bengali month names to their numeric equivalents.\n *\n * **Valid Month Names:**\n * - বৈশাখ → 1\n * - জ্যৈষ্ঠ → 2\n * - আষাঢ় → 3\n * - শ্রাবণ → 4\n * - ভাদ্র → 5\n * - আশ্বিন → 6\n * - কার্তিক → 7\n * - অগ্রহায়ণ → 8\n * - পৌষ → 9\n * - মাঘ → 10\n * - ফাল্গুন → 11\n * - চৈত্র → 12\n *\n * @param monthName - Bangla month name\n * @returns Month number (1-12)\n * @throws {Error} If month name is not a valid Bangla month\n *\n * @example\n * First quarter months:\n * ```typescript\n * fromBanglaMonth('বৈশাখ'); // 1\n * fromBanglaMonth('জ্যৈষ্ঠ'); // 2\n * fromBanglaMonth('আষাঢ়'); // 3\n * ```\n *\n * @example\n * Mid-year months:\n * ```typescript\n * fromBanglaMonth('আশ্বিন'); // 6\n * fromBanglaMonth('কার্তিক'); // 7\n * fromBanglaMonth('অগ্রহায়ণ'); // 8\n * ```\n *\n * @example\n * Last month:\n * ```typescript\n * fromBanglaMonth('চৈত্র'); // 12\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * fromBanglaMonth('invalid');\n * // throws Error: Invalid Bangla month name: invalid\n *\n * fromBanglaMonth('January');\n * // throws Error: Invalid Bangla month name: January\n * ```\n *\n * @example\n * Practical usage (form parsing):\n * ```typescript\n * const userInput = 'পৌষ';\n * const monthNumber = fromBanglaMonth(userInput); // 9\n *\n * // Use with Date object\n * const date = new Date(2024, monthNumber - 1, 15);\n * ```\n */\nexport function fromBanglaMonth(monthName: string): number {\n const index = BANGLA_MONTHS.indexOf(monthName as any);\n\n if (index === -1) {\n throw new Error(`Invalid Bangla month name: ${monthName}`);\n }\n\n return index + 1;\n}\n\n","import { toBanglaMonth } from './toBanglaMonth';\n\n/**\n * Gets the Bangla month name from a Date object.\n *\n * This function extracts the month from a JavaScript Date object and\n * converts it to the corresponding Bangla month name. Note that this\n * uses a direct 1:1 mapping (JS month + 1 = Bangla month number).\n *\n * **Note:** This is a simplified mapping. For accurate Bengali calendar\n * conversions, use the calendar module which accounts for Bengali new year\n * and proper date calculations.\n *\n * @param date - Date object\n * @returns Bangla month name\n *\n * @example\n * Getting month name from current date:\n * ```typescript\n * const today = new Date();\n * const monthName = getMonthName(today);\n * console.log(`Current month: ${monthName}`);\n * ```\n *\n * @example\n * Getting month name from specific dates:\n * ```typescript\n * const jan = new Date(2024, 0, 15); // January\n * getMonthName(jan); // 'বৈশাখ'\n *\n * const june = new Date(2024, 5, 15); // June\n * getMonthName(june); // 'আশ্বিন'\n *\n * const dec = new Date(2024, 11, 31); // December\n * getMonthName(dec); // 'চৈত্র'\n * ```\n *\n * @example\n * Practical usage (display):\n * ```typescript\n * const appointment = new Date(2024, 3, 20);\n * const monthName = getMonthName(appointment);\n * console.log(`Appointment in ${monthName}`); // 'Appointment in শ্রাবণ'\n * ```\n */\nexport function getMonthName(date: Date): string {\n // JavaScript months are 0-indexed (0-11), Bangla months are 1-indexed (1-12)\n // We need to convert: JS month 0 (Jan) = Bangla month 10 (পৌষ), etc.\n // This is a simplified mapping - actual conversion would need Bengali calendar logic\n // For now, we'll use a direct 1:1 mapping where JS month + 1 = Bangla month\n // Note: This is a placeholder - proper implementation would require Bengali calendar conversion\n const jsMonth = date.getMonth() + 1;\n return toBanglaMonth(jsMonth);\n}\n\n","/**\n * Validation utilities for date formatting and parsing operations.\n *\n * This module provides validation functions for Date objects and date strings\n * used in Bangla date formatting and parsing.\n *\n * @module date/validate\n */\n\n/**\n * Checks if a value is a valid Date object.\n *\n * A valid Date object must be an instance of Date and not represent\n * an Invalid Date (i.e., created from invalid input like new Date('invalid')).\n *\n * @param date - Value to validate\n * @returns true if valid Date object, false otherwise\n *\n * @example\n * Valid dates:\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate(new Date(2024, 0, 15)); // true\n * isValidDate(new Date('2024-01-15')); // true\n * ```\n *\n * @example\n * Invalid dates:\n * ```typescript\n * isValidDate(new Date('invalid')); // false\n * isValidDate(new Date('not-a-date')); // false\n * isValidDate('2024-01-15' as any); // false (string, not Date)\n * isValidDate(1705276800000 as any); // false (timestamp, not Date)\n * isValidDate(null as any); // false\n * ```\n */\nexport function isValidDate(date: Date): boolean {\n return date instanceof Date && !isNaN(date.getTime());\n}\n\n/**\n * Checks if a string is a valid Bengali date format.\n *\n * Valid formats include:\n * - \"১৫ বৈশাখ ১৪৩১\" (with Bengali digits and month name)\n * - \"১৫ বৈশাখ\" (without year)\n * - \"15 বৈশাখ 1431\" (with English digits and month name)\n * - \"১৫/০৪/২০২৪\" or \"১৫-০৪-২০২৪\" (Bengali digits with separators)\n * - \"15/04/2024\" or \"15-04-2024\" (English digits with separators)\n *\n * @param dateString - String to validate\n * @returns true if string matches a valid Bengali date format, false otherwise\n *\n * @example\n * Valid formats:\n * ```typescript\n * isValidBengaliDateString('১৫ বৈশাখ ১৪৩১'); // true\n * isValidBengaliDateString('১৫ বৈশাখ'); // true\n * isValidBengaliDateString('15 বৈশাখ 1431'); // true\n * isValidBengaliDateString('১৫/০৪/২০২৪'); // true\n * isValidBengaliDateString('15-04-2024'); // true\n * ```\n *\n * @example\n * Invalid formats:\n * ```typescript\n * isValidBengaliDateString('invalid'); // false\n * isValidBengaliDateString('2024-01-15'); // false (ISO format not supported)\n * isValidBengaliDateString(''); // false\n * isValidBengaliDateString(' '); // false\n * ```\n */\nexport function isValidBengaliDateString(dateString: string): boolean {\n if (typeof dateString !== 'string' || dateString.trim() === '') {\n return false;\n }\n\n const cleaned = dateString.trim().replace(/\\s+/g, ' ');\n\n // Reject ISO format (YYYY-MM-DD or YYYY/MM/DD)\n if (/^\\d{4}[\\-\\/]\\d{1,2}[\\-\\/]\\d{1,2}$/.test(cleaned)) {\n return false;\n }\n\n // Format: \"১৫ বৈশাখ ১৪৩১\" or \"১৫ বৈশাখ\" or \"15 বৈশাখ 1431\"\n const monthNamePattern =\n /^(\\d+|[০-৯]+)\\s+(বৈশাখ|জ্যৈষ্ঠ|আষাঢ়|শ্রাবণ|ভাদ্র|আশ্বিন|কার্তিক|অগ্রহায়ণ|পৌষ|মাঘ|ফাল্গুন|চৈত্র)(?:\\s+(\\d+|[০-৯]+))?$/;\n\n // Format: \"১৫/০৪/২০২৪\" or \"১৫-০৪-২০২৪\" or \"15/04/2024\" or \"15-04-2024\" (DD/MM/YYYY)\n const separatorPattern = /^(\\d{1,2}|[০-৯]{1,2})[\\/\\-](\\d{1,2}|[০-৯]{1,2})[\\/\\-](\\d{2,4}|[০-৯]{2,4})$/;\n\n return monthNamePattern.test(cleaned) || separatorPattern.test(cleaned);\n}\n\n/**\n * Checks if a string contains Bengali digits.\n *\n * Bengali digits: ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯\n *\n * @param text - String to check\n * @returns true if string contains at least one Bengali digit, false otherwise\n *\n * @example\n * Strings with Bengali digits:\n * ```typescript\n * hasBengaliDigits('১৫'); // true\n * hasBengaliDigits('১৫ বৈশাখ'); // true\n * hasBengaliDigits('Today is ১৫ বৈশাখ'); // true\n * hasBengaliDigits('১'); // true\n * ```\n *\n * @example\n * Strings without Bengali digits:\n * ```typescript\n * hasBengaliDigits('15'); // false\n * hasBengaliDigits('বৈশাখ'); // false\n * hasBengaliDigits(''); // false\n * hasBengaliDigits('hello'); // false\n * ```\n */\nexport function hasBengaliDigits(text: string): boolean {\n if (typeof text !== 'string') {\n return false;\n }\n return /[০-৯]/.test(text);\n}\n\n/**\n * Checks if a string contains a Bengali month name.\n *\n * Valid month names:\n * বৈশাখ, জ্যৈষ্ঠ, আষাঢ়, শ্রাবণ, ভাদ্র, আশ্বিন,\n * কার্তিক, অগ্রহায়ণ, পৌষ, মাঘ, ফাল্গুন, চৈত্র\n *\n * @param text - String to check\n * @returns true if string contains a Bengali month name, false otherwise\n *\n * @example\n * Strings with month names:\n * ```typescript\n * hasBengaliMonth('১৫ বৈশাখ ১৪৩১'); // true\n * hasBengaliMonth('বৈশাখ'); // true\n * hasBengaliMonth('Today is বৈশাখ month'); // true\n * hasBengaliMonth('চৈত্র'); // true\n * ```\n *\n * @example\n * Strings without month names:\n * ```typescript\n * hasBengaliMonth('১৫/০৪/২০২৪'); // false\n * hasBengaliMonth('15'); // false\n * hasBengaliMonth('January'); // false\n * hasBengaliMonth(''); // false\n * ```\n */\nexport function hasBengaliMonth(text: string): boolean {\n if (typeof text !== 'string') {\n return false;\n }\n const monthPattern = /(বৈশাখ|জ্যৈষ্ঠ|আষাঢ়|শ্রাবণ|ভাদ্র|আশ্বিন|কার্তিক|অগ্রহায়ণ|পৌষ|মাঘ|ফাল্গুন|চৈত্র)/;\n return monthPattern.test(text);\n}\n\n/**\n * Sanitizes a Date object, returning null if invalid.\n *\n * This function validates a Date object and returns it if valid,\n * or null if it's not a valid Date.\n *\n * @param date - Date object to sanitize\n * @returns The Date object if valid, null otherwise\n *\n * @example\n * Valid dates:\n * ```typescript\n * sanitizeDate(new Date(2024, 0, 15));\n * // Date object for 2024-01-15\n *\n * sanitizeDate(new Date());\n * // Current date\n * ```\n *\n * @example\n * Invalid dates:\n * ```typescript\n * sanitizeDate(new Date('invalid')); // null\n * sanitizeDate('2024-01-15' as any); // null\n * sanitizeDate(null as any); // null\n * ```\n *\n * @example\n * Practical usage:\n * ```typescript\n * function formatUserDate(userInput: any): string {\n * const validDate = sanitizeDate(userInput);\n * if (validDate) {\n * return formatDate(validDate);\n * }\n * return 'Invalid date';\n * }\n * ```\n */\nexport function sanitizeDate(date: Date): Date | null {\n if (!isValidDate(date)) {\n return null;\n }\n return date;\n}\n","import { BANGLA_MONTHS } from '../constants';\n\n/**\n * Checks if a month number is valid (1-12).\n *\n * @param monthNumber - The month number to check\n * @returns true if the month number is between 1 and 12 (inclusive)\n *\n * @example\n * ```typescript\n * isValidMonthNumber(1); // true\n * isValidMonthNumber(12); // true\n * isValidMonthNumber(0); // false\n * isValidMonthNumber(13); // false\n * isValidMonthNumber(1.5); // false (not an integer)\n * ```\n */\nexport function isValidMonthNumber(monthNumber: number): boolean {\n return (\n typeof monthNumber === 'number' &&\n Number.isInteger(monthNumber) &&\n monthNumber >= 1 &&\n monthNumber <= 12\n );\n}\n\n/**\n * Checks if a string is a valid Bangla month name.\n *\n * Valid Bangla month names:\n * - বৈশাখ (Boishakh)\n * - জ্যৈষ্ঠ (Jyoishtho)\n * - আষাঢ় (Asharh)\n * - শ্রাবণ (Srabon)\n * - ভাদ্র (Bhadro)\n * - আশ্বিন (Ashwin)\n * - কার্তিক (Kartik)\n * - অগ্রহায়ণ (Ogrohayon)\n * - পৌষ (Poush)\n * - মাঘ (Magh)\n * - ফাল্গুন (Falgun)\n * - চৈত্র (Choitro)\n *\n * @param monthName - The month name to check\n * @returns true if the name is a valid Bangla month name\n *\n * @example\n * ```typescript\n * isValidBanglaMonth('বৈশাখ'); // true\n * isValidBanglaMonth('চৈত্র'); // true\n * isValidBanglaMonth(' বৈশাখ '); // true (handles whitespace)\n * isValidBanglaMonth('January'); // false\n * isValidBanglaMonth('invalid'); // false\n * ```\n */\nexport function isValidBanglaMonth(monthName: string): boolean {\n if (typeof monthName !== 'string') {\n return false;\n }\n\n const trimmed = monthName.trim();\n return BANGLA_MONTHS.includes(trimmed as any);\n}\n\n// Re-export isValidDate from date module to avoid duplication\nexport { isValidDate } from '../date/validate';\n\n/**\n * Sanitizes month number input.\n *\n * This function:\n * - Converts string numbers to integers\n * - Rounds decimal numbers to integers\n * - Returns null for invalid inputs\n *\n * @param value - The input value to sanitize\n * @returns Sanitized month number (1-12) or null if invalid\n *\n * @example\n * ```typescript\n * sanitizeMonthNumber('5'); // 5\n * sanitizeMonthNumber(3.7); // 4\n * sanitizeMonthNumber(3.2); // 3\n * sanitizeMonthNumber('invalid'); // null\n * sanitizeMonthNumber(0); // null\n * sanitizeMonthNumber(13); // null\n * ```\n */\nexport function sanitizeMonthNumber(value: any): number | null {\n // Try to convert string to number\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') {\n return null;\n }\n const parsed = Number(trimmed);\n if (isNaN(parsed)) {\n return null;\n }\n value = parsed;\n }\n\n // Must be a number at this point\n if (typeof value !== 'number' || isNaN(value) || !isFinite(value)) {\n return null;\n }\n\n // Round to integer\n const rounded = Math.round(value);\n\n // Must be valid month number\n if (rounded < 1 || rounded > 12) {\n return null;\n }\n\n return rounded;\n}\n\n/**\n * Sanitizes Bangla month name input.\n *\n * This function trims whitespace and validates the month name.\n *\n * @param value - The input value to sanitize\n * @returns Sanitized Bangla month name or null if invalid\n *\n * @example\n * ```typescript\n * sanitizeBanglaMonth(' বৈশাখ '); // 'বৈশাখ'\n * sanitizeBanglaMonth('চৈত্র'); // 'চৈত্র'\n * sanitizeBanglaMonth('invalid'); // null\n * sanitizeBanglaMonth(''); // null\n * ```\n */\nexport function sanitizeBanglaMonth(value: any): string | null {\n if (typeof value !== 'string') {\n return null;\n }\n\n const trimmed = value.trim();\n\n if (trimmed === '' || !isValidBanglaMonth(trimmed)) {\n return null;\n }\n\n return trimmed;\n}\n","import { BANGLA_MONTHS } from '../constants';\nimport { toBanglaMonth } from './toBanglaMonth';\nimport { fromBanglaMonth } from './fromBanglaMonth';\nimport { isValidMonthNumber, isValidBanglaMonth, sanitizeMonthNumber } from './validate';\n\n/**\n * Safely converts a month number to Bangla month name with a fallback.\n *\n * @param monthNumber - Month number (1-12)\n * @param fallback - Value to return if conversion fails (default: '')\n * @returns Bangla month name or fallback value\n *\n * @example\n * ```typescript\n * safeToBanglaMonth(1); // 'বৈশাখ'\n * safeToBanglaMonth(12); // 'চৈত্র'\n * safeToBanglaMonth(0); // ''\n * safeToBanglaMonth(13, 'N/A'); // 'N/A'\n * ```\n */\nexport function safeToBanglaMonth(monthNumber: number, fallback: string = ''): string {\n try {\n if (!isValidMonthNumber(monthNumber)) {\n return fallback;\n }\n return toBanglaMonth(monthNumber);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely converts a Bangla month name to month number with a fallback.\n *\n * @param monthName - Bangla month name\n * @param fallback - Value to return if conversion fails (default: 0)\n * @returns Month number (1-12) or fallback value\n *\n * @example\n * ```typescript\n * safeFromBanglaMonth('বৈশাখ'); // 1\n * safeFromBanglaMonth('চৈত্র'); // 12\n * safeFromBanglaMonth('invalid'); // 0\n * safeFromBanglaMonth('invalid', -1); // -1\n * ```\n */\nexport function safeFromBanglaMonth(monthName: string, fallback: number = 0): number {\n try {\n if (!isValidBanglaMonth(monthName)) {\n return fallback;\n }\n return fromBanglaMonth(monthName);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Gets all Bangla month names as an array.\n *\n * @returns Array of all 12 Bangla month names\n *\n * @example\n * ```typescript\n * const months = getAllMonths();\n * // ['বৈশাখ', 'জ্যৈষ্ঠ', 'আষাঢ়', 'শ্রাবণ', 'ভাদ্র', 'আশ্বিন',\n * // 'কার্তিক', 'অগ্রহায়ণ', 'পৌষ', 'মাঘ', 'ফাল্গুন', 'চৈত্র']\n *\n * // Use for dropdown options\n * months.forEach((month, index) => {\n * console.log(`${index + 1}: ${month}`);\n * });\n * ```\n */\nexport function getAllMonths(): string[] {\n return [...BANGLA_MONTHS];\n}\n\n/**\n * Gets the next month in the Bangla calendar.\n *\n * @param currentMonth - Current month number or Bangla month name\n * @returns Next month number or name (wraps from 12 to 1)\n * @throws {Error} If current month is invalid\n *\n * @example\n * ```typescript\n * getNextMonth(1); // 2\n * getNextMonth(12); // 1 (wraps around)\n * getNextMonth('বৈশাখ'); // 'জ্যৈষ্ঠ'\n * getNextMonth('চৈত্র'); // 'বৈশাখ' (wraps around)\n * ```\n */\nexport function getNextMonth(currentMonth: number | string): number | string {\n if (typeof currentMonth === 'number') {\n if (!isValidMonthNumber(currentMonth)) {\n throw new Error('Invalid month number');\n }\n return currentMonth === 12 ? 1 : currentMonth + 1;\n } else {\n if (!isValidBanglaMonth(currentMonth)) {\n throw new Error('Invalid Bangla month name');\n }\n const monthNum = fromBanglaMonth(currentMonth);\n const nextNum = monthNum === 12 ? 1 : monthNum + 1;\n return toBanglaMonth(nextNum);\n }\n}\n\n/**\n * Gets the previous month in the Bangla calendar.\n *\n * @param currentMonth - Current month number or Bangla month name\n * @returns Previous month number or name (wraps from 1 to 12)\n * @throws {Error} If current month is invalid\n *\n * @example\n * ```typescript\n * getPreviousMonth(2); // 1\n * getPreviousMonth(1); // 12 (wraps around)\n * getPreviousMonth('জ্যৈষ্ঠ'); // 'বৈশাখ'\n * getPreviousMonth('বৈশাখ'); // 'চৈত্র' (wraps around)\n * ```\n */\nexport function getPreviousMonth(currentMonth: number | string): number | string {\n if (typeof currentMonth === 'number') {\n if (!isValidMonthNumber(currentMonth)) {\n throw new Error('Invalid month number');\n }\n return currentMonth === 1 ? 12 : currentMonth - 1;\n } else {\n if (!isValidBanglaMonth(currentMonth)) {\n throw new Error('Invalid Bangla month name');\n }\n const monthNum = fromBanglaMonth(currentMonth);\n const prevNum = monthNum === 1 ? 12 : monthNum - 1;\n return toBanglaMonth(prevNum);\n }\n}\n\n/**\n * Gets a range of months between start and end (inclusive).\n *\n * @param start - Starting month (number or name)\n * @param end - Ending month (number or name)\n * @returns Array of month numbers or names\n * @throws {Error} If start or end are invalid\n *\n * @example\n * ```typescript\n * getMonthRange(1, 3);\n * // [1, 2, 3]\n *\n * getMonthRange('বৈশাখ', 'আষাঢ়');\n * // ['বৈশাখ', 'জ্যৈষ্ঠ', 'আষাঢ়']\n *\n * getMonthRange(11, 2); // Wraps around\n * // [11, 12, 1, 2]\n * ```\n */\nexport function getMonthRange(start: number | string, end: number | string): (number | string)[] {\n const isNumber = typeof start === 'number';\n\n let startNum: number;\n let endNum: number;\n\n if (isNumber) {\n if (!isValidMonthNumber(start as number) || !isValidMonthNumber(end as number)) {\n throw new Error('Invalid month numbers');\n }\n startNum = start as number;\n endNum = end as number;\n } else {\n if (!isValidBanglaMonth(start as string) || !isValidBanglaMonth(end as string)) {\n throw new Error('Invalid Bangla month names');\n }\n startNum = fromBanglaMonth(start as string);\n endNum = fromBanglaMonth(end as string);\n }\n\n const result: (number | string)[] = [];\n let current = startNum;\n\n while (true) {\n if (isNumber) {\n result.push(current);\n } else {\n result.push(toBanglaMonth(current));\n }\n\n if (current === endNum) {\n break;\n }\n\n current = current === 12 ? 1 : current + 1;\n\n // Safety check to prevent infinite loop\n if (result.length > 12) {\n break;\n }\n }\n\n return result;\n}\n\n/**\n * Checks if a given month is within a range.\n *\n * @param month - Month to check (number or name)\n * @param start - Range start (number or name)\n * @param end - Range end (number or name)\n * @returns true if month is within the range\n *\n * @example\n * ```typescript\n * isMonthInRange(2, 1, 3); // true\n * isMonthInRange('জ্যৈষ্ঠ', 'বৈশাখ', 'আষাঢ়'); // true\n * isMonthInRange(5, 1, 3); // false\n * isMonthInRange(1, 11, 2); // true (wraps around)\n * ```\n */\nexport function isMonthInRange(\n month: number | string,\n start: number | string,\n end: number | string\n): boolean {\n try {\n const range = getMonthRange(start, end);\n return range.includes(month);\n } catch {\n return false;\n }\n}\n\n/**\n * Compares two months.\n *\n * @param month1 - First month (number or name)\n * @param month2 - Second month (number or name)\n * @returns -1 if month1 comes before month2, 0 if equal, 1 if month1 comes after month2\n * @throws {Error} If months are invalid\n *\n * @example\n * ```typescript\n * compareMonths(1, 2); // -1\n * compareMonths(5, 3); // 1\n * compareMonths(3, 3); // 0\n * compareMonths('বৈশাখ', 'জ্যৈষ্ঠ'); // -1\n * ```\n */\nexport function compareMonths(month1: number | string, month2: number | string): number {\n let num1: number;\n let num2: number;\n\n if (typeof month1 === 'number') {\n if (!isValidMonthNumber(month1)) {\n throw new Error('Invalid month1');\n }\n num1 = month1;\n } else {\n if (!isValidBanglaMonth(month1)) {\n throw new Error('Invalid month1');\n }\n num1 = fromBanglaMonth(month1);\n }\n\n if (typeof month2 === 'number') {\n if (!isValidMonthNumber(month2)) {\n throw new Error('Invalid month2');\n }\n num2 = month2;\n } else {\n if (!isValidBanglaMonth(month2)) {\n throw new Error('Invalid month2');\n }\n num2 = fromBanglaMonth(month2);\n }\n\n if (num1 < num2) return -1;\n if (num1 > num2) return 1;\n return 0;\n}\n\n/**\n * Gets the month index (0-11) for a given month.\n *\n * This is useful for JavaScript Date operations where months are 0-indexed.\n *\n * @param month - Month number (1-12) or Bangla month name\n * @returns Month index (0-11)\n * @throws {Error} If month is invalid\n *\n * @example\n * ```typescript\n * getMonthIndex(1); // 0\n * getMonthIndex(12); // 11\n * getMonthIndex('বৈশাখ'); // 0\n * getMonthIndex('চৈত্র'); // 11\n * ```\n */\nexport function getMonthIndex(month: number | string): number {\n if (typeof month === 'number') {\n if (!isValidMonthNumber(month)) {\n throw new Error('Invalid month number');\n }\n return month - 1;\n } else {\n if (!isValidBanglaMonth(month)) {\n throw new Error('Invalid Bangla month name');\n }\n return fromBanglaMonth(month) - 1;\n }\n}\n\n/**\n * Gets the month number from a 0-based index.\n *\n * @param index - Month index (0-11)\n * @returns Month number (1-12)\n * @throws {Error} If index is out of range\n *\n * @example\n * ```typescript\n * getMonthFromIndex(0); // 1\n * getMonthFromIndex(11); // 12\n * getMonthFromIndex(5); // 6\n * ```\n */\nexport function getMonthFromIndex(index: number): number {\n if (!Number.isInteger(index) || index < 0 || index > 11) {\n throw new Error('Index must be between 0 and 11');\n }\n return index + 1;\n}\n\n/**\n * Parses and converts to Bangla month in one step.\n *\n * @param value - Input value (number, string number, or already Bangla month name)\n * @returns Bangla month name\n * @throws {Error} If value cannot be parsed as a valid month\n *\n * @example\n * ```typescript\n * parseAndConvertToMonth('1'); // 'বৈশাখ'\n * parseAndConvertToMonth(5); // 'ভাদ্র'\n * parseAndConvertToMonth(' 3 '); // 'আষাঢ়'\n * parseAndConvertToMonth('বৈশাখ'); // 'বৈশাখ' (already Bangla)\n * parseAndConvertToMonth('invalid'); // throws Error\n * ```\n */\nexport function parseAndConvertToMonth(value: any): string {\n // If it's already a valid Bangla month name, return it\n if (typeof value === 'string' && isValidBanglaMonth(value.trim())) {\n return value.trim();\n }\n\n // Try to sanitize as month number\n const sanitized = sanitizeMonthNumber(value);\n if (sanitized === null) {\n throw new Error('Invalid month input');\n }\n\n return toBanglaMonth(sanitized);\n}\n\n/**\n * Batch converts month numbers to Bangla month names.\n *\n * @param monthNumbers - Array of month numbers\n * @returns Array of Bangla month names (invalid months are skipped)\n *\n * @example\n * ```typescript\n * batchToBanglaMonth([1, 2, 3]);\n * // ['বৈশাখ', 'জ্যৈষ্ঠ', 'আষাঢ়']\n *\n * batchToBanglaMonth([1, 13, 3, 0, 5]);\n * // ['বৈশাখ', 'আষাঢ়', 'ভাদ্র'] (invalid months skipped)\n * ```\n */\nexport function batchToBanglaMonth(monthNumbers: number[]): string[] {\n return monthNumbers\n .filter(num => isValidMonthNumber(num))\n .map(num => toBanglaMonth(num));\n}\n\n/**\n * Creates a month mapping object.\n *\n * @returns Object mapping month numbers to Bangla month names\n *\n * @example\n * ```typescript\n * const mapping = getMonthMapping();\n * console.log(mapping[1]); // 'বৈশাখ'\n * console.log(mapping[12]); // 'চৈত্র'\n * ```\n */\nexport function getMonthMapping(): Record<number, string> {\n const mapping: Record<number, string> = {};\n for (let i = 1; i <= 12; i++) {\n mapping[i] = toBanglaMonth(i);\n }\n return mapping;\n}\n","import { BANGLA_WEEKDAYS } from '../constants';\n\n/**\n * Converts a weekday number to its Bangla weekday name.\n *\n * This function converts JavaScript weekday numbers (0-6, where 0 = Sunday) to their\n * corresponding Bangla weekday names. This matches the convention used by JavaScript's\n * `Date.getDay()` method.\n *\n * **Weekday Mapping:**\n * - 0 → রবিবার (Sunday)\n * - 1 → সোমবার (Monday)\n * - 2 → মঙ্গলবার (Tuesday)\n * - 3 → বুধবার (Wednesday)\n * - 4 → বৃহস্পতিবার (Thursday)\n * - 5 → শুক্রবার (Friday)\n * - 6 → শনিবার (Saturday)\n *\n * @param weekdayNumber - Weekday number (0-6, where 0 = Sunday)\n * @returns Bangla weekday name\n * @throws {Error} If weekdayNumber is not between 0 and 6\n *\n * @example\n * Basic conversion:\n * ```typescript\n * toBanglaWeekday(0); // 'রবিবার' (Sunday)\n * toBanglaWeekday(1); // 'সোমবার' (Monday)\n * toBanglaWeekday(6); // 'শনিবার' (Saturday)\n * ```\n *\n * @example\n * With Date object:\n * ```typescript\n * const today = new Date();\n * const weekdayNumber = today.getDay();\n * const banglaWeekday = toBanglaWeekday(weekdayNumber);\n * console.log(`Today is ${banglaWeekday}`);\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * toBanglaWeekday(7); // throws Error: Weekday number must be between 0 and 6\n * toBanglaWeekday(-1); // throws Error: Weekday number must be between 0 and 6\n * ```\n *\n * @example\n * Calendar generation:\n * ```typescript\n * const weekdays = [0, 1, 2, 3, 4, 5, 6].map(day => toBanglaWeekday(day));\n * console.log(weekdays);\n * // ['রবিবার', 'সোমবার', 'মঙ্গলবার', 'বুধবার', 'বৃহস্পতিবার', 'শুক্রবার', 'শনিবার']\n * ```\n */\nexport function toBanglaWeekday(weekdayNumber: number): string {\n if (weekdayNumber < 0 || weekdayNumber > 6) {\n throw new Error('Weekday number must be between 0 and 6');\n }\n\n return BANGLA_WEEKDAYS[weekdayNumber];\n}\n\n","import { BANGLA_WEEKDAYS } from '../constants';\n\n/**\n * Converts a Bangla weekday name to its corresponding weekday number.\n *\n * This function performs the reverse operation of `toBanglaWeekday()`, converting\n * Bangla weekday names to JavaScript weekday numbers (0-6). The conversion is\n * case-sensitive and requires exact matches.\n *\n * **Weekday Mapping:**\n * - রবিবার → 0 (Sunday)\n * - সোমবার → 1 (Monday)\n * - মঙ্গলবার → 2 (Tuesday)\n * - বুধবার → 3 (Wednesday)\n * - বৃহস্পতিবার → 4 (Thursday)\n * - শুক্রবার → 5 (Friday)\n * - শনিবার → 6 (Saturday)\n *\n * @param weekdayName - Bangla weekday name (case-sensitive)\n * @returns Weekday number (0-6, where 0 = Sunday)\n * @throws {Error} If weekdayName is not a valid Bangla weekday name\n *\n * @example\n * Basic conversion:\n * ```typescript\n * fromBanglaWeekday('রবিবার'); // 0 (Sunday)\n * fromBanglaWeekday('সোমবার'); // 1 (Monday)\n * fromBanglaWeekday('শনিবার'); // 6 (Saturday)\n * ```\n *\n * @example\n * Round-trip conversion:\n * ```typescript\n * const original = 3;\n * const bangla = toBanglaWeekday(original); // 'বুধবার'\n * const converted = fromBanglaWeekday(bangla); // 3\n * console.log(original === converted); // true\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * fromBanglaWeekday('invalid'); // throws Error: Invalid Bangla weekday name: invalid\n * fromBanglaWeekday(''); // throws Error: Invalid Bangla weekday name:\n * fromBanglaWeekday('রবিবার'); // throws Error (case-sensitive)\n * ```\n *\n * @example\n * Finding weekday index:\n * ```typescript\n * const userInput = 'শুক্রবার';\n * const dayIndex = fromBanglaWeekday(userInput);\n * if (dayIndex === 5 || dayIndex === 6) {\n * console.log('This is a weekend day!');\n * }\n * ```\n */\nexport function fromBanglaWeekday(weekdayName: string): number {\n const index = BANGLA_WEEKDAYS.indexOf(weekdayName as any);\n\n if (index === -1) {\n throw new Error(`Invalid Bangla weekday name: ${weekdayName}`);\n }\n\n return index;\n}\n\n","import { toBanglaWeekday } from './toBanglaWeekday';\n\n/**\n * Gets the Bangla weekday name from a Date object.\n *\n * This is a convenience function that combines `Date.getDay()` with `toBanglaWeekday()`\n * to directly get the Bangla weekday name from a Date object in a single call.\n *\n * @param date - JavaScript Date object\n * @returns Bangla weekday name for the given date\n * @throws {Error} If the date's weekday number is invalid (this should never happen with valid Date objects)\n *\n * @example\n * Basic usage:\n * ```typescript\n * const today = new Date();\n * const weekday = getWeekdayName(today);\n * console.log(`আজ ${weekday}`); // e.g., \"আজ শুক্রবার\"\n * ```\n *\n * @example\n * Specific date:\n * ```typescript\n * const date = new Date('2024-01-07'); // Sunday\n * getWeekdayName(date); // 'রবিবার'\n *\n * const date2 = new Date('2024-01-08'); // Monday\n * getWeekdayName(date2); // 'সোমবার'\n * ```\n *\n * @example\n * Formatting date displays:\n * ```typescript\n * const event = {\n * date: new Date('2024-12-25'),\n * name: 'Special Event'\n * };\n *\n * const weekday = getWeekdayName(event.date);\n * console.log(`${event.name} is on ${weekday}`);\n * // \"Special Event is on বুধবার\"\n * ```\n *\n * @example\n * Calendar rendering:\n * ```typescript\n * const dates = [\n * new Date('2024-01-01'),\n * new Date('2024-01-02'),\n * new Date('2024-01-03'),\n * ];\n *\n * dates.forEach(date => {\n * console.log(`${date.toLocaleDateString()}: ${getWeekdayName(date)}`);\n * });\n * ```\n */\nexport function getWeekdayName(date: Date): string {\n const weekdayNumber = date.getDay();\n return toBanglaWeekday(weekdayNumber);\n}\n\n","import { BANGLA_WEEKDAYS } from '../constants';\n\n/**\n * Validates if a value is a valid weekday number (0-6).\n *\n * This function checks if the input is a number between 0-6 (inclusive),\n * where 0 represents Sunday and 6 represents Saturday, matching JavaScript's\n * Date.getDay() convention.\n *\n * @param value - The value to validate\n * @returns true if the value is a valid weekday number, false otherwise\n *\n * @example\n * ```typescript\n * isValidWeekdayNumber(0); // true (Sunday)\n * isValidWeekdayNumber(6); // true (Saturday)\n * isValidWeekdayNumber(3); // true (Wednesday)\n * isValidWeekdayNumber(7); // false (out of range)\n * isValidWeekdayNumber(-1); // false (out of range)\n * isValidWeekdayNumber('0'); // false (not a number)\n * isValidWeekdayNumber(NaN); // false\n * ```\n */\nexport function isValidWeekdayNumber(value: any): boolean {\n if (typeof value !== 'number') {\n return false;\n }\n\n if (!Number.isFinite(value)) {\n return false;\n }\n\n if (!Number.isInteger(value)) {\n return false;\n }\n\n return value >= 0 && value <= 6;\n}\n\n/**\n * Validates if a value is a valid Bangla weekday name.\n *\n * This function checks if the input is one of the seven Bangla weekday names.\n * The check is case-sensitive and requires exact matches.\n *\n * **Valid names**:\n * - রবিবার (Sunday)\n * - সোমবার (Monday)\n * - মঙ্গলবার (Tuesday)\n * - বুধবার (Wednesday)\n * - বৃহস্পতিবার (Thursday)\n * - শুক্রবার (Friday)\n * - শনিবার (Saturday)\n *\n * @param value - The value to validate\n * @returns true if the value is a valid Bangla weekday name, false otherwise\n *\n * @example\n * ```typescript\n * isValidBanglaWeekday('রবিবার'); // true\n * isValidBanglaWeekday('সোমবার'); // true\n * isValidBanglaWeekday('শনিবার'); // true\n * isValidBanglaWeekday('invalid'); // false\n * isValidBanglaWeekday(''); // false\n * isValidBanglaWeekday(123); // false\n * ```\n */\nexport function isValidBanglaWeekday(value: any): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n\n const trimmed = value.trim();\n\n if (trimmed === '') {\n return false;\n }\n\n return BANGLA_WEEKDAYS.includes(trimmed as any);\n}\n\n/**\n * Validates if a value is a valid Date object for weekday extraction.\n *\n * This function checks if the input is a valid Date object that can be used\n * with `getWeekdayName()`.\n *\n * @param value - The value to validate\n * @returns true if the value is a valid Date object, false otherwise\n *\n * @example\n * ```typescript\n * isValidDateForWeekday(new Date()); // true\n * isValidDateForWeekday(new Date('2024-01-07')); // true\n * isValidDateForWeekday(new Date('invalid')); // false (Invalid Date)\n * isValidDateForWeekday('2024-01-07'); // false (string, not Date)\n * isValidDateForWeekday(123); // false\n * isValidDateForWeekday(null); // false\n * ```\n */\nexport function isValidDateForWeekday(value: any): boolean {\n if (!(value instanceof Date)) {\n return false;\n }\n\n // Check if the date is valid (not Invalid Date)\n return !isNaN(value.getTime());\n}\n\n/**\n * Sanitizes weekday name input by trimming whitespace.\n *\n * This function cleans user input for weekday name lookups by removing\n * leading and trailing whitespace.\n *\n * @param input - The weekday name string to sanitize\n * @returns Sanitized weekday name\n *\n * @example\n * ```typescript\n * sanitizeWeekdayInput(' রবিবার '); // 'রবিবার'\n * sanitizeWeekdayInput('সোমবার'); // 'সোমবার'\n * sanitizeWeekdayInput(' মঙ্গলবার\\n'); // 'মঙ্গলবার'\n * ```\n */\nexport function sanitizeWeekdayInput(input: string): string {\n if (typeof input !== 'string') {\n return '';\n }\n\n return input.trim();\n}\n","import { toBanglaWeekday } from './toBanglaWeekday';\nimport { fromBanglaWeekday } from './fromBanglaWeekday';\nimport { sanitizeWeekdayInput } from './validate';\n\n/**\n * Checks if a weekday number represents a weekend day.\n *\n * In Bangladesh, weekends are Friday (5) and Saturday (6).\n * This follows the common work week convention where Friday is the main holiday.\n *\n * @param weekdayNumber - Weekday number (0-6, where 0 = Sunday)\n * @returns true if the day is a weekend (Friday or Saturday), false otherwise\n *\n * @example\n * ```typescript\n * isWeekend(5); // true (Friday)\n * isWeekend(6); // true (Saturday)\n * isWeekend(0); // false (Sunday)\n * isWeekend(3); // false (Wednesday)\n * ```\n */\nexport function isWeekend(weekdayNumber: number): boolean {\n if (weekdayNumber < 0 || weekdayNumber > 6) {\n throw new Error('Weekday number must be between 0 and 6');\n }\n\n // Bangladesh weekend: Friday (5) and Saturday (6)\n return weekdayNumber === 5 || weekdayNumber === 6;\n}\n\n/**\n * Checks if a Bangla weekday name represents a weekend day.\n *\n * @param weekdayName - Bangla weekday name\n * @returns true if the day is a weekend (শুক্রবার or শনিবার), false otherwise\n *\n * @example\n * ```typescript\n * isBanglaWeekend('শুক্রবার'); // true\n * isBanglaWeekend('শনিবার'); // true\n * isBanglaWeekend('রবিবার'); // false\n * ```\n */\nexport function isBanglaWeekend(weekdayName: string): boolean {\n const weekdayNumber = fromBanglaWeekday(weekdayName);\n return isWeekend(weekdayNumber);\n}\n\n/**\n * Gets the next weekday number in sequence.\n *\n * This function returns the next day of the week, wrapping from Saturday (6)\n * back to Sunday (0).\n *\n * @param weekdayNumber - Current weekday number (0-6)\n * @returns Next weekday number (0-6)\n *\n * @example\n * ```typescript\n * getNextWeekday(0); // 1 (Sunday → Monday)\n * getNextWeekday(5); // 6 (Friday → Saturday)\n * getNextWeekday(6); // 0 (Saturday → Sunday, wraps around)\n * ```\n */\nexport function getNextWeekday(weekdayNumber: number): number {\n if (weekdayNumber < 0 || weekdayNumber > 6) {\n throw new Error('Weekday number must be between 0 and 6');\n }\n\n return (weekdayNumber + 1) % 7;\n}\n\n/**\n * Gets the previous weekday number in sequence.\n *\n * This function returns the previous day of the week, wrapping from Sunday (0)\n * back to Saturday (6).\n *\n * @param weekdayNumber - Current weekday number (0-6)\n * @returns Previous weekday number (0-6)\n *\n * @example\n * ```typescript\n * getPreviousWeekday(1); // 0 (Monday → Sunday)\n * getPreviousWeekday(0); // 6 (Sunday → Saturday, wraps around)\n * getPreviousWeekday(6); // 5 (Saturday → Friday)\n * ```\n */\nexport function getPreviousWeekday(weekdayNumber: number): number {\n if (weekdayNumber < 0 || weekdayNumber > 6) {\n throw new Error('Weekday number must be between 0 and 6');\n }\n\n return (weekdayNumber - 1 + 7) % 7;\n}\n\n/**\n * Gets the Bangla weekday name for the next day.\n *\n * Convenience function that combines `getNextWeekday()` with `toBanglaWeekday()`.\n *\n * @param weekdayNumber - Current weekday number (0-6)\n * @returns Bangla name of the next weekday\n *\n * @example\n * ```typescript\n * getNextBanglaWeekday(0); // 'সোমবার' (Sunday → Monday)\n * getNextBanglaWeekday(6); // 'রবিবার' (Saturday → Sunday)\n * ```\n */\nexport function getNextBanglaWeekday(weekdayNumber: number): string {\n const nextDay = getNextWeekday(weekdayNumber);\n return toBanglaWeekday(nextDay);\n}\n\n/**\n * Gets the Bangla weekday name for the previous day.\n *\n * Convenience function that combines `getPreviousWeekday()` with `toBanglaWeekday()`.\n *\n * @param weekdayNumber - Current weekday number (0-6)\n * @returns Bangla name of the previous weekday\n *\n * @example\n * ```typescript\n * getPreviousBanglaWeekday(1); // 'রবিবার' (Monday → Sunday)\n * getPreviousBanglaWeekday(0); // 'শনিবার' (Sunday → Saturday)\n * ```\n */\nexport function getPreviousBanglaWeekday(weekdayNumber: number): string {\n const prevDay = getPreviousWeekday(weekdayNumber);\n return toBanglaWeekday(prevDay);\n}\n\n/**\n * Parses user input with sanitization and converts to weekday number.\n *\n * This function combines sanitization (trimming) and conversion to weekday number,\n * making it ideal for processing form inputs or user-entered weekday names.\n *\n * @param input - The user input weekday name to parse\n * @returns Weekday number (0-6)\n * @throws Error if the sanitized input is not a valid weekday name\n *\n * @example\n * ```typescript\n * parseWeekdayInput(' রবিবার '); // 0\n * parseWeekdayInput('সোমবার'); // 1\n * parseWeekdayInput('শনিবার \\n'); // 6\n * parseWeekdayInput('invalid'); // throws Error\n * ```\n */\nexport function parseWeekdayInput(input: string): number {\n const sanitized = sanitizeWeekdayInput(input);\n return fromBanglaWeekday(sanitized);\n}\n\n/**\n * Safely converts a weekday number to Bangla with a fallback value.\n *\n * This is useful in UI contexts where you want to always display something,\n * even if the conversion fails.\n *\n * @param weekdayNumber - The weekday number to convert\n * @param fallback - Value to return if conversion fails (default: '')\n * @returns Bangla weekday name or fallback value\n *\n * @example\n * ```typescript\n * safeToBanglaWeekday(0); // 'রবিবার'\n * safeToBanglaWeekday(7, '---'); // '---' (out of range)\n * safeToBanglaWeekday(-1, 'N/A'); // 'N/A' (out of range)\n * ```\n */\nexport function safeToBanglaWeekday(weekdayNumber: number, fallback: string = ''): string {\n try {\n return toBanglaWeekday(weekdayNumber);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely converts a Bangla weekday name to number with a fallback.\n *\n * @param weekdayName - The Bangla weekday name to convert\n * @param fallback - Value to return if conversion fails (default: -1)\n * @returns Weekday number or fallback value\n *\n * @example\n * ```typescript\n * safeFromBanglaWeekday('রবিবার'); // 0\n * safeFromBanglaWeekday('invalid', -1); // -1\n * safeFromBanglaWeekday('', 99); // 99\n * ```\n */\nexport function safeFromBanglaWeekday(weekdayName: string, fallback: number = -1): number {\n try {\n return fromBanglaWeekday(weekdayName);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Gets all Bangla weekday names as an array.\n *\n * Returns a copy of the weekday names array for iteration or display purposes.\n * The array starts with Sunday (রবিবার) at index 0.\n *\n * @returns Array of all Bangla weekday names\n *\n * @example\n * ```typescript\n * const weekdays = getAllBanglaWeekdays();\n * console.log(weekdays[0]); // 'রবিবার'\n * console.log(weekdays.length); // 7\n *\n * // Use for dropdown/select options\n * weekdays.forEach((day, index) => {\n * console.log(`${index}: ${day}`);\n * });\n * ```\n */\nexport function getAllBanglaWeekdays(): string[] {\n return [\n 'রবিবার',\n 'সোমবার',\n 'মঙ্গলবার',\n 'বুধবার',\n 'বৃহস্পতিবার',\n 'শুক্রবার',\n 'শনিবার',\n ];\n}\n\n/**\n * Calculates the number of days between two weekday numbers.\n *\n * This function calculates the shortest distance between two weekdays,\n * considering the circular nature of the week.\n *\n * @param from - Starting weekday number (0-6)\n * @param to - Target weekday number (0-6)\n * @returns Number of days to go forward from 'from' to reach 'to' (0-6)\n *\n * @example\n * ```typescript\n * getDaysBetween(0, 3); // 3 (Sunday to Wednesday)\n * getDaysBetween(5, 1); // 3 (Friday to Monday, forward)\n * getDaysBetween(6, 0); // 1 (Saturday to Sunday)\n * getDaysBetween(3, 3); // 0 (same day)\n * ```\n */\nexport function getDaysBetween(from: number, to: number): number {\n if (from < 0 || from > 6 || to < 0 || to > 6) {\n throw new Error('Weekday numbers must be between 0 and 6');\n }\n\n return (to - from + 7) % 7;\n}\n","import { toBanglaNumber } from '../number';\nimport { getMonthName } from '../month';\nimport { getWeekdayName } from '../weekday';\n\n/**\n * Formats a Gregorian date with Bangla digits, month names, and weekdays.\n *\n * This function formats a standard JavaScript Date object using Bengali digits,\n * Bengali month names (based on Gregorian calendar), and Bengali weekday names.\n *\n * **Note:** This uses a simplified 1:1 mapping where Gregorian month corresponds\n * directly to a Bengali month name (January = বৈশাখ, etc.). For accurate Bengali\n * calendar conversion, use the `calendar` module's `getBengaliDate` function.\n *\n * **Output Formats:**\n * - Long (default): \"day month year\" or \"weekday day month year\"\n * - Short: Combines day and month in one part\n *\n * **Weekday Names:**\n * - রবিবার (Robibar) - Sunday\n * - সোমবার (Sombar) - Monday\n * - মঙ্গলবার (Mongolbar) - Tuesday\n * - বুধবার (Budhbar) - Wednesday\n * - বৃহস্পতিবার (Brihaspotibar) - Thursday\n * - শুক্রবার (Shukrobar) - Friday\n * - শনিবার (Shonibar) - Saturday\n *\n * @param date - Date object to format\n * @param options - Formatting options\n * @param options.includeWeekday - Include weekday name (default: false)\n * @param options.includeYear - Include year (default: true)\n * @param options.format - Format style: 'short' or 'long' (default: 'long')\n * @returns Formatted date string in Bangla\n *\n * @example\n * Basic formatting (with year):\n * ```typescript\n * formatDate(new Date(2024, 0, 15));\n * // \"১৫ বৈশাখ ২০২৪\"\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * formatDate(new Date(2024, 0, 15), { includeYear: false });\n * // \"১৫ বৈশাখ\"\n * ```\n *\n * @example\n * With weekday:\n * ```typescript\n * formatDate(new Date(2024, 0, 15), { includeWeekday: true });\n * // \"সোমবার ১৫ বৈশাখ ২০২৪\" (if Jan 15, 2024 is Monday)\n * ```\n *\n * @example\n * Short format:\n * ```typescript\n * formatDate(new Date(2024, 0, 15), { format: 'short' });\n * // \"১৫ বৈশাখ ২০২৪\"\n * ```\n *\n * @example\n * All options combined:\n * ```typescript\n * formatDate(\n * new Date(2024, 0, 15),\n * { includeWeekday: true, includeYear: false, format: 'short' }\n * );\n * // \"সোমবার ১৫ বৈশাখ\"\n * ```\n *\n * @example\n * Display current date:\n * ```typescript\n * const today = formatDate(new Date(), { includeWeekday: true });\n * console.log(`আজ: ${today}`);\n * // \"আজ: মঙ্গলবার ৭ পৌষ ২০২৫\" (example)\n * ```\n *\n * @example\n * Event list formatting:\n * ```typescript\n * const events = [\n * new Date(2024, 3, 14),\n * new Date(2024, 11, 16),\n * new Date(2025, 1, 21)\n * ];\n * events.forEach(event => {\n * console.log(formatDate(event, { includeWeekday: true, includeYear: false }));\n * });\n * // \"রবিবার ১৪ শ্রাবণ\"\n * // \"সোমবার ১৬ চৈত্র\"\n * // \"শুক্রবার ২১ জ্যৈষ্ঠ\"\n * ```\n */\nexport function formatDate(\n date: Date,\n options: {\n includeWeekday?: boolean;\n includeYear?: boolean;\n format?: 'short' | 'long';\n } = {}\n): string {\n const {\n includeWeekday = false,\n includeYear = true,\n format = 'long',\n } = options;\n\n const parts: string[] = [];\n\n if (includeWeekday) {\n const weekday = getWeekdayName(date);\n parts.push(weekday);\n }\n\n const day = toBanglaNumber(date.getDate());\n const month = getMonthName(date);\n const year = includeYear ? toBanglaNumber(date.getFullYear()) : null;\n\n if (format === 'short') {\n parts.push(`${day} ${month}`);\n } else {\n parts.push(day, month);\n }\n\n if (year) {\n parts.push(year);\n }\n\n return parts.join(' ');\n}\n\n","import { fromBanglaNumber } from '../number';\nimport { fromBanglaMonth } from '../month';\n\n/**\n * Parses a Bengali formatted date string into a JavaScript Date object.\n *\n * This function supports multiple Bengali date formats with both Bengali\n * and English digits. It handles month names and separator-based formats.\n *\n * **Supported Formats:**\n * 1. Month name format: \"day month [year]\"\n * - \"১৫ বৈশাখ ১৪৩১\" (Bengali digits)\n * - \"15 বৈশাখ 1431\" (English digits)\n * - \"১৫ বৈশাখ\" (without year, uses current year)\n *\n * 2. Separator format: \"day/month/year\" or \"day-month-year\"\n * - \"১৫/০৪/২০২৪\" (Bengali digits with slash)\n * - \"15-04-2024\" (English digits with dash)\n * - \"১৫/০৪/২০২৪\" (mixed Bengali/English)\n *\n * **Note:** This parses to Gregorian dates with Bengali formatting.\n * For Bengali calendar date parsing, use the `calendar` module's `fromBengali` function.\n *\n * @param dateString - Bengali formatted date string\n * @returns JavaScript Date object\n * @throws {Error} If the date string cannot be parsed\n *\n * @example\n * Month name format with Bengali digits:\n * ```typescript\n * parseDate('১৫ বৈশাখ ১৪৩১');\n * // Date object for the 15th day of month 1 (Boishakh) in year 1431\n * ```\n *\n * @example\n * Month name format with English digits:\n * ```typescript\n * parseDate('15 বৈশাখ 1431');\n * // Date object for the 15th day of month 1 in year 1431\n * ```\n *\n * @example\n * Without year (uses current year):\n * ```typescript\n * parseDate('১৫ বৈশাখ');\n * // Date object for 15 Boishakh of current year\n * ```\n *\n * @example\n * Separator format with Bengali digits:\n * ```typescript\n * parseDate('১৫/০৪/২০২৪');\n * // Date object for April 15, 2024\n * ```\n *\n * @example\n * Separator format with English digits:\n * ```typescript\n * parseDate('15-04-2024');\n * // Date object for April 15, 2024\n * ```\n *\n * @example\n * All month names:\n * ```typescript\n * parseDate('১ বৈশাখ ১৪৩১'); // Boishakh (month 1)\n * parseDate('১ জ্যৈষ্ঠ ১৪৩১'); // Joishtho (month 2)\n * parseDate('১ আষাঢ় ১৪৩১'); // Asharh (month 3)\n * parseDate('১ শ্রাবণ ১৪৩১'); // Srabon (month 4)\n * parseDate('১ ভাদ্র ১৪৩১'); // Bhadro (month 5)\n * parseDate('১ আশ্বিন ১৪৩১'); // Ashwin (month 6)\n * parseDate('১ কার্তিক ১৪৩১'); // Kartik (month 7)\n * parseDate('১ অগ্রহায়ণ ১৪৩১'); // Agrahayan (month 8)\n * parseDate('১ পৌষ ১৪৩১'); // Poush (month 9)\n * parseDate('১ মাঘ ১৪৩১'); // Magh (month 10)\n * parseDate('১ ফাল্গুন ১৪৩১'); // Falgun (month 11)\n * parseDate('১ চৈত্র ১৪৩১'); // Chaitra (month 12)\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * parseDate('invalid');\n * // throws Error: Unable to parse date string: invalid\n *\n * parseDate('2024-01-15');\n * // throws Error: Unable to parse date string: 2024-01-15\n * // (ISO format not supported)\n *\n * parseDate('');\n * // throws Error: Unable to parse date string:\n * ```\n *\n * @example\n * Practical usage (form handling):\n * ```typescript\n * try {\n * const userInput = '১৫ বৈশাখ ১৪৩১';\n * const date = parseDate(userInput);\n * console.log('Parsed date:', date);\n * } catch (error) {\n * console.error('Invalid date format');\n * }\n * ```\n *\n * @example\n * Parse and format back:\n * ```typescript\n * const original = '১৫ বৈশাখ ১৪৩১';\n * const parsed = parseDate(original);\n * const formatted = formatDate(parsed);\n * // formatted should match original format\n * ```\n */\nexport function parseDate(dateString: string): Date {\n // Remove extra whitespace\n const cleaned = dateString.trim().replace(/\\s+/g, ' ');\n\n // Try format: \"১৫ বৈশাখ ২০২৪\" or \"১৫ বৈশাখ\"\n const monthNameMatch = cleaned.match(\n /^(\\d+|[০-৯]+)\\s+(বৈশাখ|জ্যৈষ্ঠ|আষাঢ়|শ্রাবণ|ভাদ্র|আশ্বিন|কার্তিক|অগ্রহায়ণ|পৌষ|মাঘ|ফাল্গুন|চৈত্র)(?:\\s+(\\d+|[০-৯]+))?$/\n );\n\n if (monthNameMatch) {\n const dayStr = monthNameMatch[1];\n const monthName = monthNameMatch[2];\n const yearStr = monthNameMatch[3];\n\n const day = /[০-৯]/.test(dayStr) ? fromBanglaNumber(dayStr) : parseInt(dayStr, 10);\n const month = fromBanglaMonth(monthName);\n const year = yearStr\n ? /[০-৯]/.test(yearStr)\n ? fromBanglaNumber(yearStr)\n : parseInt(yearStr, 10)\n : new Date().getFullYear();\n\n // Note: This is a simplified conversion\n // For accurate Bengali calendar conversion, use the calendar module\n return new Date(year, month - 1, day);\n }\n\n // Try format: \"১৫/০৪/২০২৪\" or \"১৫-০৪-২০২৪\"\n const separatorMatch = cleaned.match(/^(\\d+|[০-৯]+)[\\/\\-](\\d+|[০-৯]+)[\\/\\-](\\d+|[০-৯]+)$/);\n\n if (separatorMatch) {\n const dayStr = separatorMatch[1];\n const monthStr = separatorMatch[2];\n const yearStr = separatorMatch[3];\n\n const day = /[০-৯]/.test(dayStr) ? fromBanglaNumber(dayStr) : parseInt(dayStr, 10);\n const month = /[০-৯]/.test(monthStr) ? fromBanglaNumber(monthStr) : parseInt(monthStr, 10);\n const year = /[০-৯]/.test(yearStr) ? fromBanglaNumber(yearStr) : parseInt(yearStr, 10);\n\n return new Date(year, month - 1, day);\n }\n\n throw new Error(`Unable to parse date string: ${dateString}`);\n}\n","/**\n * Utility functions for date formatting and parsing operations.\n *\n * This module provides helper functions for working with Bangla date formatting,\n * including safe conversions, date comparisons, and formatting utilities.\n *\n * @module date/utils\n */\n\nimport { formatDate } from './formatDate';\nimport { parseDate } from './parseDate';\nimport { isValidDate, isValidBengaliDateString } from './validate';\n\n/**\n * Safely formats a date with fallback value.\n *\n * Unlike formatDate, this function doesn't throw on invalid dates.\n * Returns a fallback string for invalid inputs.\n *\n * @param date - Date object to format\n * @param options - Formatting options\n * @param fallback - Fallback string if formatting fails (default: empty string)\n * @returns Formatted date string or fallback\n *\n * @example\n * Valid dates:\n * ```typescript\n * safeFormatDate(new Date(2024, 0, 15));\n * // \"১৫ বৈশাখ ২০২৪\" (example - depends on conversion)\n * ```\n *\n * @example\n * Invalid dates with fallback:\n * ```typescript\n * safeFormatDate(new Date('invalid'), {}, 'তারিখ নেই');\n * // \"তারিখ নেই\"\n *\n * safeFormatDate(null as any, {}, 'N/A');\n * // \"N/A\"\n * ```\n *\n * @example\n * Default fallback:\n * ```typescript\n * safeFormatDate(new Date('invalid'));\n * // \"\"\n * ```\n */\nexport function safeFormatDate(\n date: Date,\n options?: {\n includeWeekday?: boolean;\n includeYear?: boolean;\n format?: 'short' | 'long';\n },\n fallback: string = ''\n): string {\n try {\n if (!isValidDate(date)) {\n return fallback;\n }\n return formatDate(date, options);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely parses a Bengali date string with fallback.\n *\n * Unlike parseDate, this function doesn't throw on invalid strings.\n * Returns a fallback Date for invalid inputs.\n *\n * @param dateString - Bengali date string to parse\n * @param fallback - Fallback Date if parsing fails (default: current date)\n * @returns Parsed Date object or fallback\n *\n * @example\n * Valid date strings:\n * ```typescript\n * safeParseDate('১৫ বৈশাখ ১৪৩১');\n * // Date object for the parsed date\n * ```\n *\n * @example\n * Invalid strings with fallback:\n * ```typescript\n * const fallbackDate = new Date(2024, 0, 1);\n * safeParseDate('invalid', fallbackDate);\n * // Returns fallbackDate\n *\n * safeParseDate('not a date', fallbackDate);\n * // Returns fallbackDate\n * ```\n */\nexport function safeParseDate(dateString: string, fallback?: Date): Date {\n try {\n return parseDate(dateString);\n } catch {\n return fallback || new Date();\n }\n}\n\n/**\n * Formats today's date in Bangla.\n *\n * Convenience function that formats the current date.\n *\n * @param options - Formatting options\n * @returns Formatted current date string\n *\n * @example\n * ```typescript\n * formatToday();\n * // \"৭ বৈশাখ ২০২৫\" (example for current date)\n * ```\n *\n * @example\n * With weekday:\n * ```typescript\n * formatToday({ includeWeekday: true });\n * // \"মঙ্গলবার ৭ বৈশাখ ২০২৫\" (example)\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * formatToday({ includeYear: false });\n * // \"৭ বৈশাখ\"\n * ```\n */\nexport function formatToday(options?: {\n includeWeekday?: boolean;\n includeYear?: boolean;\n format?: 'short' | 'long';\n}): string {\n return formatDate(new Date(), options);\n}\n\n/**\n * Formats an array of dates in Bangla.\n *\n * @param dates - Array of Date objects\n * @param options - Formatting options\n * @returns Array of formatted date strings\n *\n * @example\n * ```typescript\n * const dates = [\n * new Date(2024, 0, 15),\n * new Date(2024, 1, 20),\n * new Date(2024, 2, 25)\n * ];\n * batchFormatDates(dates);\n * // [\"১৫ বৈশাখ ২০২৪\", \"২০ জ্যৈষ্ঠ ২০২৪\", \"২৫ আষাঢ় ২০২৪\"] (examples)\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * batchFormatDates(dates, { includeYear: false });\n * // [\"১৫ বৈশাখ\", \"২০ জ্যৈষ্ঠ\", \"২৫ আষাঢ়\"]\n * ```\n */\nexport function batchFormatDates(\n dates: Date[],\n options?: {\n includeWeekday?: boolean;\n includeYear?: boolean;\n format?: 'short' | 'long';\n }\n): string[] {\n return dates.map(date => safeFormatDate(date, options));\n}\n\n/**\n * Parses an array of Bengali date strings.\n *\n * @param dateStrings - Array of Bengali date strings\n * @returns Array of Date objects\n *\n * @example\n * ```typescript\n * const dateStrings = [\n * '১৫ বৈশাখ ১৪৩১',\n * '২০ জ্যৈষ্ঠ ১৪৩১',\n * '১৫/০৪/২০২৪'\n * ];\n * const dates = batchParseDates(dateStrings);\n * // Array of Date objects\n * ```\n *\n * @example\n * Handling invalid dates:\n * ```typescript\n * const mixed = ['১৫ বৈশাখ ১৪৩১', 'invalid'];\n * const dates = batchParseDates(mixed);\n * // First element: parsed Date, second element: current Date (fallback)\n * ```\n */\nexport function batchParseDates(dateStrings: string[]): Date[] {\n return dateStrings.map(str => safeParseDate(str));\n}\n\n/**\n * Checks if a date string can be parsed.\n *\n * @param dateString - String to check\n * @returns true if string can be parsed, false otherwise\n *\n * @example\n * Valid strings:\n * ```typescript\n * canParseBengaliDate('১৫ বৈশাখ ১৪৩১'); // true\n * canParseBengaliDate('১৫/০৪/২০২৪'); // true\n * canParseBengaliDate('15 বৈশাখ 1431'); // true\n * ```\n *\n * @example\n * Invalid strings:\n * ```typescript\n * canParseBengaliDate('invalid'); // false\n * canParseBengaliDate('2024-01-15'); // false\n * canParseBengaliDate(''); // false\n * ```\n */\nexport function canParseBengaliDate(dateString: string): boolean {\n return isValidBengaliDateString(dateString);\n}\n\n/**\n * Compares two dates.\n *\n * @param date1 - First date\n * @param date2 - Second date\n * @returns -1 if date1 < date2, 0 if equal, 1 if date1 > date2\n *\n * @example\n * First date is earlier:\n * ```typescript\n * compareDates(new Date(2024, 0, 10), new Date(2024, 0, 15));\n * // -1\n * ```\n *\n * @example\n * Dates are equal:\n * ```typescript\n * const date = new Date(2024, 0, 15);\n * compareDates(date, new Date(date));\n * // 0\n * ```\n *\n * @example\n * First date is later:\n * ```typescript\n * compareDates(new Date(2024, 0, 20), new Date(2024, 0, 15));\n * // 1\n * ```\n */\nexport function compareDates(date1: Date, date2: Date): -1 | 0 | 1 {\n if (!isValidDate(date1) || !isValidDate(date2)) {\n throw new Error('Invalid date');\n }\n\n const time1 = date1.getTime();\n const time2 = date2.getTime();\n\n if (time1 < time2) return -1;\n if (time1 > time2) return 1;\n return 0;\n}\n\n/**\n * Checks if a date is today.\n *\n * @param date - Date to check\n * @returns true if date is today, false otherwise\n *\n * @example\n * ```typescript\n * isToday(new Date());\n * // true\n *\n * isToday(new Date(2024, 0, 1));\n * // false (unless today is 2024-01-01)\n * ```\n */\nexport function isToday(date: Date): boolean {\n if (!isValidDate(date)) {\n return false;\n }\n\n const today = new Date();\n return (\n date.getDate() === today.getDate() &&\n date.getMonth() === today.getMonth() &&\n date.getFullYear() === today.getFullYear()\n );\n}\n\n/**\n * Checks if a date is in the past.\n *\n * @param date - Date to check\n * @returns true if date is before now, false otherwise\n *\n * @example\n * ```typescript\n * isPast(new Date(2020, 0, 1));\n * // true\n *\n * isPast(new Date(2030, 0, 1));\n * // false\n * ```\n */\nexport function isPast(date: Date): boolean {\n if (!isValidDate(date)) {\n return false;\n }\n\n return date.getTime() < Date.now();\n}\n\n/**\n * Checks if a date is in the future.\n *\n * @param date - Date to check\n * @returns true if date is after now, false otherwise\n *\n * @example\n * ```typescript\n * isFuture(new Date(2030, 0, 1));\n * // true\n *\n * isFuture(new Date(2020, 0, 1));\n * // false\n * ```\n */\nexport function isFuture(date: Date): boolean {\n if (!isValidDate(date)) {\n return false;\n }\n\n return date.getTime() > Date.now();\n}\n\n/**\n * Gets the difference in days between two dates.\n *\n * @param date1 - First date\n * @param date2 - Second date\n * @returns Number of days between dates (date2 - date1)\n *\n * @example\n * ```typescript\n * const date1 = new Date(2024, 0, 1);\n * const date2 = new Date(2024, 0, 11);\n * getDaysDifference(date1, date2);\n * // 10\n * ```\n *\n * @example\n * Negative difference:\n * ```typescript\n * const date1 = new Date(2024, 0, 11);\n * const date2 = new Date(2024, 0, 1);\n * getDaysDifference(date1, date2);\n * // -10\n * ```\n */\nexport function getDaysDifference(date1: Date, date2: Date): number {\n if (!isValidDate(date1) || !isValidDate(date2)) {\n throw new Error('Invalid date');\n }\n\n const diffTime = date2.getTime() - date1.getTime();\n return Math.floor(diffTime / (1000 * 60 * 60 * 24));\n}\n\n/**\n * Adds days to a date.\n *\n * @param date - Starting date\n * @param days - Number of days to add (can be negative)\n * @returns New Date object\n *\n * @example\n * Adding days:\n * ```typescript\n * const date = new Date(2024, 0, 1);\n * addDays(date, 10);\n * // Date for 2024-01-11\n * ```\n *\n * @example\n * Subtracting days:\n * ```typescript\n * const date = new Date(2024, 0, 11);\n * addDays(date, -10);\n * // Date for 2024-01-01\n * ```\n */\nexport function addDays(date: Date, days: number): Date {\n if (!isValidDate(date)) {\n throw new Error('Invalid date');\n }\n\n const result = new Date(date);\n result.setDate(result.getDate() + days);\n return result;\n}\n\n/**\n * Checks if a date is in a range (inclusive).\n *\n * @param date - Date to check\n * @param start - Start of range (inclusive)\n * @param end - End of range (inclusive)\n * @returns true if date is in range, false otherwise\n *\n * @example\n * Date within range:\n * ```typescript\n * isDateInRange(\n * new Date(2024, 0, 15),\n * new Date(2024, 0, 10),\n * new Date(2024, 0, 20)\n * );\n * // true\n * ```\n *\n * @example\n * Date on boundary:\n * ```typescript\n * isDateInRange(\n * new Date(2024, 0, 10),\n * new Date(2024, 0, 10),\n * new Date(2024, 0, 20)\n * );\n * // true\n * ```\n *\n * @example\n * Date outside range:\n * ```typescript\n * isDateInRange(\n * new Date(2024, 0, 25),\n * new Date(2024, 0, 10),\n * new Date(2024, 0, 20)\n * );\n * // false\n * ```\n */\nexport function isDateInRange(date: Date, start: Date, end: Date): boolean {\n if (!isValidDate(date) || !isValidDate(start) || !isValidDate(end)) {\n return false;\n }\n\n return compareDates(date, start) >= 0 && compareDates(date, end) <= 0;\n}\n","import { BANGLA_SEASONS } from '../constants';\n\n/**\n * Gets the Bangla season name from a Bengali month number.\n *\n * This function maps Bengali month numbers (1-12) to their corresponding seasons\n * according to the traditional Bengali calendar system.\n *\n * **Month to Season Mapping:**\n * - Months 1-2 (বৈশাখ-জ্যৈষ্ঠ) → গ্রীষ্ম (Summer)\n * - Months 3-5 (আষাঢ়-শ্রাবণ-ভাদ্র) → বর্ষা (Monsoon)\n * - Months 6-7 (আশ্বিন-কার্তিক) → শরৎ (Autumn)\n * - Month 8 (অগ্রহায়ণ) → হেমন্ত (Late Autumn)\n * - Months 9-10 (পৌষ-মাঘ) → শীত (Winter)\n * - Months 11-12 (ফাল্গুন-চৈত্র) → বসন্ত (Spring)\n *\n * @param monthNumber - Bengali month number (1-12)\n * @returns Bangla season name\n * @throws {Error} If monthNumber is not between 1 and 12\n *\n * @example\n * Basic usage:\n * ```typescript\n * getSeasonFromMonth(1); // 'গ্রীষ্ম' (বৈশাখ - Summer)\n * getSeasonFromMonth(4); // 'বর্ষা' (শ্রাবণ - Monsoon)\n * getSeasonFromMonth(8); // 'হেমন্ত' (অগ্রহায়ণ - Late Autumn)\n * getSeasonFromMonth(12); // 'বসন্ত' (চৈত্র - Spring)\n * ```\n *\n * @example\n * All months mapped to seasons:\n * ```typescript\n * // Summer months\n * getSeasonFromMonth(1); // 'গ্রীষ্ম' (Boishakh)\n * getSeasonFromMonth(2); // 'গ্রীষ্ম' (Joishtho)\n *\n * // Monsoon months\n * getSeasonFromMonth(3); // 'বর্ষা' (Asharh)\n * getSeasonFromMonth(4); // 'বর্ষা' (Shrabon)\n * getSeasonFromMonth(5); // 'বর্ষা' (Bhadro)\n *\n * // Autumn months\n * getSeasonFromMonth(6); // 'শরৎ' (Ashwin)\n * getSeasonFromMonth(7); // 'শরৎ' (Kartik)\n *\n * // Late Autumn\n * getSeasonFromMonth(8); // 'হেমন্ত' (Ogrohayon)\n *\n * // Winter months\n * getSeasonFromMonth(9); // 'শীত' (Poush)\n * getSeasonFromMonth(10); // 'শীত' (Magh)\n *\n * // Spring months\n * getSeasonFromMonth(11); // 'বসন্ত' (Falgun)\n * getSeasonFromMonth(12); // 'বসন্ত' (Choitro)\n * ```\n *\n * @example\n * Error handling:\n * ```typescript\n * getSeasonFromMonth(0); // throws Error: Month number must be between 1 and 12\n * getSeasonFromMonth(13); // throws Error: Month number must be between 1 and 12\n * ```\n *\n * @example\n * Use in calendar application:\n * ```typescript\n * const bengaliMonths = [\n * 'বৈশাখ', 'জ্যৈষ্ঠ', 'আষাঢ়', 'শ্রাবণ', 'ভাদ্র', 'আশ্বিন',\n * 'কার্তিক', 'অগ্রহায়ণ', 'পৌষ', 'মাঘ', 'ফাল্গুন', 'চৈত্র'\n * ];\n *\n * for (let month = 1; month <= 12; month++) {\n * const monthName = bengaliMonths[month - 1];\n * const season = getSeasonFromMonth(month);\n * console.log(`${monthName} - ${season}`);\n * }\n * ```\n */\nexport function getSeasonFromMonth(monthNumber: number): string {\n if (monthNumber < 1 || monthNumber > 12) {\n throw new Error('Month number must be between 1 and 12');\n }\n\n // Bangladesh standard Bangla seasons\n // গ্রীষ্ম: বৈশাখ–জ্যৈষ্ঠ (1–2)\n // বর্ষা: আষাঢ়–শ্রাবণ (3–4)\n // শরৎ: ভাদ্র–আশ্বিন (5–6)\n // হেমন্ত: কার্তিক–অগ্রহায়ণ (7–8)\n // শীত: পৌষ–মাঘ (9–10)\n // বসন্ত: ফাল্গুন–চৈত্র (11–12)\n\n if (monthNumber <= 2) {\n return BANGLA_SEASONS[0]; // গ্রীষ্ম\n } else if (monthNumber <= 4) {\n return BANGLA_SEASONS[1]; // বর্ষা\n } else if (monthNumber <= 6) {\n return BANGLA_SEASONS[2]; // শরৎ\n } else if (monthNumber <= 8) {\n return BANGLA_SEASONS[3]; // হেমন্ত\n } else if (monthNumber <= 10) {\n return BANGLA_SEASONS[4]; // শীত\n } else {\n return BANGLA_SEASONS[5]; // বসন্ত\n }\n}\n","import { getBengaliMonthLengths } from './utils';\n\n/**\n * Converts a Bengali calendar date to Gregorian date.\n *\n * This function performs the reverse operation of toBengali, converting\n * from the Bengali calendar to the Gregorian calendar. It accurately\n * handles month boundaries, year transitions, and leap years.\n *\n * **Input Format:**\n * - year: Bengali year (positive integer)\n * - month: Bengali month (1-12)\n * - day: Day of month (1-31, depending on month)\n *\n * **Bengali to Gregorian Mapping:**\n * - Bengali year + 593 or 594 = Gregorian year (depends on date)\n * - 1 Boishakh (Bengali New Year) = April 14 (Gregorian)\n *\n * @param bengaliDate - Bengali date object with year, month, and day properties\n * @returns Gregorian Date object\n * @throws {Error} If the Bengali date is invalid\n *\n * @example\n * Bengali New Year to Gregorian:\n * ```typescript\n * fromBengali({ year: 1431, month: 1, day: 1 });\n * // Date object for April 14, 2024 (Pohela Boishakh)\n * ```\n *\n * @example\n * Mid-year conversions:\n * ```typescript\n * fromBengali({ year: 1431, month: 6, day: 15 });\n * // Date object for October 1, 2024 (approx - Ashwin)\n *\n * fromBengali({ year: 1431, month: 9, day: 1 });\n * // Date object for December 16, 2024 (approx - Poush)\n * ```\n *\n * @example\n * End of year:\n * ```typescript\n * fromBengali({ year: 1431, month: 12, day: 30 });\n * // Date object for April 13, 2025 (last day before new year)\n * ```\n *\n * @example\n * Practical usage (event scheduling):\n * ```typescript\n * const bengaliEvent = { year: 1431, month: 1, day: 1 };\n * const gregorianDate = fromBengali(bengaliEvent);\n * console.log(`Event date: ${gregorianDate.toLocaleDateString()}`);\n * // \"Event date: 4/14/2024\"\n * ```\n *\n * @example\n * Leap year handling:\n * ```typescript\n * // Falgun 30 in a leap year\n * fromBengali({ year: 1427, month: 11, day: 30 });\n * // Valid conversion (2020 is a leap year)\n *\n * // Falgun 30 in a non-leap year would be invalid\n * // (month 11 only has 29 days in non-leap years)\n * ```\n *\n * @example\n * Round-trip conversion:\n * ```typescript\n * const original = new Date(2024, 6, 15);\n * const bengali = toBengali(original);\n * const converted = fromBengali(bengali);\n * // converted should equal original date\n * ```\n */\nexport function fromBengali(b: { year: number; month: number; day: number }): Date {\n const { year, month, day } = b;\n\n const monthLengths = getBengaliMonthLengths(year);\n\n // --- Validation ---\n if (month < 1 || month > 12) {\n throw new Error('Invalid Bengali month');\n }\n if (day < 1 || day > monthLengths[month - 1]) {\n throw new Error('Invalid Bengali day for given month');\n }\n\n /**\n * 1 Boishakh anchor (Bangladesh Revised Calendar)\n * Bengali year + 593 = Gregorian year of Boishakh\n */\n const gYear = year + 593;\n const boishakh1 = new Date(Date.UTC(gYear, 3, 14)); // April 14\n\n /**\n * Days since 1 Boishakh\n */\n let daysOffset = 0;\n\n // Full months before current month\n for (let m = 1; m < month; m++) {\n daysOffset += monthLengths[m - 1];\n }\n\n // Days inside current month\n daysOffset += day - 1;\n\n return new Date(boishakh1.getTime() + daysOffset * 86400000);\n}\n","import { toBengali } from './toBengali';\nimport { toBanglaNumber } from '../number';\nimport { toBanglaMonth } from '../month';\n\n/**\n * Formats a Gregorian date as a Bengali calendar date string with Bengali text.\n *\n * This function converts a Gregorian date to the Bengali calendar and formats it\n * with Bengali digits and month names. It's ideal for displaying dates in\n * Bengali cultural contexts.\n *\n * **Output Format:**\n * - Default: \"day month year\" (e.g., \"১৫ বৈশাখ ১৪৩১\")\n * - With weekday: \"weekday day month year\" (e.g., \"রবিবার ১৫ বৈশাখ ১৪৩১\")\n * - Without year: \"day month\" (e.g., \"১৫ বৈশাখ\")\n *\n * **Weekday Names:**\n * - রবিবার (Robibar) - Sunday\n * - সোমবার (Sombar) - Monday\n * - মঙ্গলবার (Mongolbar) - Tuesday\n * - বুধবার (Budhbar) - Wednesday\n * - বৃহস্পতিবার (Brihaspotibar) - Thursday\n * - শুক্রবার (Shukrobar) - Friday\n * - শনিবার (Shonibar) - Saturday\n *\n * @param date - Gregorian Date object to format\n * @param options - Formatting options\n * @param options.includeYear - Include Bengali year in output (default: true)\n * @param options.includeWeekday - Include weekday name in output (default: false)\n * @returns Formatted Bengali date string\n *\n * @example\n * Basic formatting (with year):\n * ```typescript\n * getBengaliDate(new Date(2024, 3, 14));\n * // \"১ বৈশাখ ১৪৩১\" (Pohela Boishakh 1431)\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * getBengaliDate(new Date(2024, 3, 14), { includeYear: false });\n * // \"১ বৈশাখ\"\n * ```\n *\n * @example\n * With weekday:\n * ```typescript\n * getBengaliDate(new Date(2024, 3, 14), { includeWeekday: true });\n * // \"রবিবার ১ বৈশাখ ১৪৩১\" (if April 14, 2024 is Sunday)\n * ```\n *\n * @example\n * With weekday, without year:\n * ```typescript\n * getBengaliDate(\n * new Date(2024, 3, 14),\n * { includeWeekday: true, includeYear: false }\n * );\n * // \"রবিবার ১ বৈশাখ\"\n * ```\n *\n * @example\n * Display current date in Bengali:\n * ```typescript\n * const today = new Date();\n * const bengaliToday = getBengaliDate(today, { includeWeekday: true });\n * console.log(`আজ: ${bengaliToday}`);\n * // \"আজ: মঙ্গলবার ২৪ পৌষ ১৪৩১\" (example)\n * ```\n *\n * @example\n * Birthday display:\n * ```typescript\n * const birthday = new Date(2024, 6, 15);\n * const bengaliBirthday = getBengaliDate(birthday);\n * console.log(`জন্মদিন: ${bengaliBirthday}`);\n * // \"জন্মদিন: ১ শ্রাবণ ১৪৩১\" (example)\n * ```\n *\n * @example\n * Event calendar:\n * ```typescript\n * const events = [\n * new Date(2024, 3, 14),\n * new Date(2024, 11, 16),\n * new Date(2025, 1, 21)\n * ];\n * events.forEach(event => {\n * console.log(getBengaliDate(event, { includeWeekday: true }));\n * });\n * // \"রবিবার ১ বৈশাখ ১৪৩১\"\n * // \"সোমবার ২ পৌষ ১৪৩১\"\n * // \"শুক্রবার ৯ ফাল্গুন ১৪৩১\"\n * ```\n */\nexport function getBengaliDate(\n date: Date,\n options: {\n includeYear?: boolean;\n includeWeekday?: boolean;\n } = {}\n): string {\n const { includeYear = true, includeWeekday = false } = options;\n const bengali = toBengali(date);\n\n const weekdays = ['রবিবার', 'সোমবার', 'মঙ্গলবার', 'বুধবার', 'বৃহস্পতিবার', 'শুক্রবার', 'শনিবার'];\n\n const parts: string[] = [\n ...(includeWeekday ? [weekdays[date.getDay()]] : []),\n toBanglaNumber(bengali.day),\n toBanglaMonth(bengali.month),\n ...(includeYear ? [toBanglaNumber(bengali.year)] : []),\n ];\n\n return parts.join(' ');\n}\n","/**\n * Validation utilities for Bengali calendar operations.\n *\n * This module provides non-throwing validation functions for Bengali calendar dates.\n * All validators return boolean values or null for sanitization functions.\n *\n * @module calendar/validate\n */\n\nimport { getBengaliMonthLengths } from './utils';\n\n/**\n * Checks if a year is a valid Bengali calendar year.\n *\n * Valid Bengali years are positive integers. The Bengali calendar\n * is typically 593-594 years behind the Gregorian calendar.\n *\n * @param year - Year to validate\n * @returns true if year is a valid Bengali year, false otherwise\n *\n * @example\n * Valid years:\n * ```typescript\n * isValidBengaliYear(1431); // true\n * isValidBengaliYear(1400); // true\n * isValidBengaliYear(1); // true\n * ```\n *\n * @example\n * Invalid years:\n * ```typescript\n * isValidBengaliYear(0); // false\n * isValidBengaliYear(-10); // false\n * isValidBengaliYear(1431.5); // false\n * isValidBengaliYear('1431' as any); // false\n * ```\n */\nexport function isValidBengaliYear(year: number): boolean {\n return typeof year === 'number' && Number.isInteger(year) && year > 0 && isFinite(year);\n}\n\n/**\n * Checks if a month is a valid Bengali calendar month (1-12).\n *\n * Bengali calendar has 12 months:\n * 1=বৈশাখ, 2=জ্যৈষ্ঠ, 3=আষাঢ়, 4=শ্রাবণ, 5=ভাদ্র, 6=আশ্বিন,\n * 7=কার্তিক, 8=অগ্রহায়ণ, 9=পৌষ, 10=মাঘ, 11=ফাল্গুন, 12=চৈত্র\n *\n * @param month - Month to validate (1-12)\n * @returns true if month is valid, false otherwise\n *\n * @example\n * Valid months:\n * ```typescript\n * isValidBengaliMonth(1); // true (Boishakh)\n * isValidBengaliMonth(6); // true (Ashwin)\n * isValidBengaliMonth(12); // true (Chaitra)\n * ```\n *\n * @example\n * Invalid months:\n * ```typescript\n * isValidBengaliMonth(0); // false\n * isValidBengaliMonth(13); // false\n * isValidBengaliMonth(6.5); // false\n * ```\n */\nexport function isValidBengaliMonth(month: number): boolean {\n return typeof month === 'number' && Number.isInteger(month) && month >= 1 && month <= 12;\n}\n\n/**\n * Checks if a day is valid for a given Bengali month and year.\n *\n * Bengali calendar month lengths:\n * - Months 1-5 (বৈশাখ-ভাদ্র): 31 days\n * - Months 6-10 (আশ্বিন-মাঘ): 30 days\n * - Month 11 (ফাল্গুন): 29 or 30 days (depends on Gregorian leap year)\n * - Month 12 (চৈত্র): 30 days\n *\n * @param day - Day to validate\n * @param month - Bengali month (1-12)\n * @param year - Bengali year\n * @returns true if day is valid for the given month/year, false otherwise\n *\n * @example\n * Valid days:\n * ```typescript\n * isValidBengaliDay(15, 1, 1431); // true (Boishakh has 31 days)\n * isValidBengaliDay(31, 1, 1431); // true (last day of Boishakh)\n * isValidBengaliDay(30, 6, 1431); // true (Ashwin has 30 days)\n * ```\n *\n * @example\n * Invalid days:\n * ```typescript\n * isValidBengaliDay(32, 1, 1431); // false (Boishakh has only 31 days)\n * isValidBengaliDay(31, 6, 1431); // false (Ashwin has only 30 days)\n * isValidBengaliDay(0, 1, 1431); // false (day must be >= 1)\n * isValidBengaliDay(15.5, 1, 1431); // false (must be integer)\n * ```\n *\n * @example\n * Leap year handling:\n * ```typescript\n * // 1427 Bengali corresponds to 2020 Gregorian (leap year)\n * isValidBengaliDay(30, 11, 1427); // true (Falgun has 30 days in leap year)\n *\n * // 1428 Bengali corresponds to 2021 Gregorian (not leap year)\n * isValidBengaliDay(30, 11, 1428); // false (Falgun has only 29 days)\n * isValidBengaliDay(29, 11, 1428); // true\n * ```\n */\nexport function isValidBengaliDay(day: number, month: number, year: number): boolean {\n if (\n typeof day !== 'number' ||\n !Number.isInteger(day) ||\n day < 1 ||\n !isValidBengaliMonth(month) ||\n !isValidBengaliYear(year)\n ) {\n return false;\n }\n\n const monthLengths = getBengaliMonthLengths(year);\n return day <= monthLengths[month - 1];\n}\n\n/**\n * Checks if a Bengali date object is valid.\n *\n * A valid Bengali date object must have valid year, month, and day properties\n * that form a valid date combination.\n *\n * @param date - Bengali date object with year, month, day properties\n * @returns true if the date object is valid, false otherwise\n *\n * @example\n * Valid dates:\n * ```typescript\n * isValidBengaliDate({ year: 1431, month: 1, day: 1 }); // true\n * isValidBengaliDate({ year: 1431, month: 6, day: 15 }); // true\n * isValidBengaliDate({ year: 1431, month: 12, day: 30 }); // true\n * ```\n *\n * @example\n * Invalid dates:\n * ```typescript\n * isValidBengaliDate({ year: 1431, month: 13, day: 1 }); // false (invalid month)\n * isValidBengaliDate({ year: 1431, month: 1, day: 32 }); // false (day > 31)\n * isValidBengaliDate({ year: 0, month: 1, day: 1 }); // false (invalid year)\n * isValidBengaliDate({ year: 1431, month: 6, day: 31 }); // false (Ashwin has only 30 days)\n * ```\n *\n * @example\n * Type validation:\n * ```typescript\n * isValidBengaliDate({ year: 1431, month: 1 } as any); // false (missing day)\n * isValidBengaliDate({ year: '1431', month: 1, day: 1 } as any); // false (year not number)\n * isValidBengaliDate(null as any); // false\n * ```\n */\nexport function isValidBengaliDate(date: { year: number; month: number; day: number }): boolean {\n if (!date || typeof date !== 'object') {\n return false;\n }\n\n const { year, month, day } = date;\n\n return (\n isValidBengaliYear(year) && isValidBengaliMonth(month) && isValidBengaliDay(day, month, year)\n );\n}\n\n/**\n * Sanitizes a Bengali date object, returning null if invalid.\n *\n * This function validates all components of a Bengali date and returns\n * the date object if valid, or null if any component is invalid.\n *\n * @param date - Bengali date object to sanitize\n * @returns The date object if valid, null otherwise\n *\n * @example\n * Valid dates:\n * ```typescript\n * sanitizeBengaliDate({ year: 1431, month: 1, day: 1 });\n * // { year: 1431, month: 1, day: 1 }\n *\n * sanitizeBengaliDate({ year: 1431, month: 6, day: 15 });\n * // { year: 1431, month: 6, day: 15 }\n * ```\n *\n * @example\n * Invalid dates:\n * ```typescript\n * sanitizeBengaliDate({ year: 1431, month: 13, day: 1 }); // null\n * sanitizeBengaliDate({ year: 1431, month: 1, day: 32 }); // null\n * sanitizeBengaliDate({ year: 0, month: 1, day: 1 }); // null\n * sanitizeBengaliDate(null as any); // null\n * ```\n *\n * @example\n * Practical usage (form validation):\n * ```typescript\n * const userInput = { year: 1431, month: 1, day: 15 };\n * const validDate = sanitizeBengaliDate(userInput);\n *\n * if (validDate) {\n * console.log('Valid date:', validDate);\n * } else {\n * console.log('Invalid date provided');\n * }\n * ```\n */\nexport function sanitizeBengaliDate(date: {\n year: number;\n month: number;\n day: number;\n}): { year: number; month: number; day: number } | null {\n if (!isValidBengaliDate(date)) {\n return null;\n }\n return date;\n}\n","/**\n * Utility functions for Bengali calendar operations.\n *\n * This module provides helper functions for working with Bengali calendar dates,\n * including safe conversions, date arithmetic, comparisons, and formatting utilities.\n *\n * @module calendar/utils\n */\n\nimport { toBengali } from './toBengali';\nimport { fromBengali } from './fromBengali';\nimport { getBengaliDate } from './getBengaliDate';\nimport { isValidBengaliDate, isValidBengaliYear, isValidBengaliMonth } from './validate';\n\n/**\n * Safely converts a Gregorian date to Bengali date with fallback.\n *\n * Unlike toBengali, this function doesn't throw on invalid dates.\n * Returns a fallback date object for invalid inputs.\n *\n * @param date - Gregorian Date object\n * @param fallback - Fallback value if conversion fails\n * @returns Bengali date object or fallback\n *\n * @example\n * Valid dates:\n * ```typescript\n * const bengaliDate = safeToBengali(new Date(2024, 0, 15));\n * // { year: 1430, month: 10, day: 2 }\n * ```\n *\n * @example\n * Invalid dates with fallback:\n * ```typescript\n * safeToBengali(new Date('invalid'), { year: 1431, month: 1, day: 1 });\n * // { year: 1431, month: 1, day: 1 }\n *\n * safeToBengali(null as any, { year: 1431, month: 1, day: 1 });\n * // { year: 1431, month: 1, day: 1 }\n * ```\n *\n * @example\n * Default fallback (current Bengali date):\n * ```typescript\n * safeToBengali(new Date('invalid'));\n * // Returns current Bengali date\n * ```\n */\nexport function safeToBengali(\n date: Date,\n fallback?: { year: number; month: number; day: number }\n): { year: number; month: number; day: number } {\n try {\n if (!(date instanceof Date) || isNaN(date.getTime())) {\n return fallback || toBengali(new Date());\n }\n return toBengali(date);\n } catch {\n return fallback || toBengali(new Date());\n }\n}\n\n/**\n * Safely converts a Bengali date to Gregorian date with fallback.\n *\n * Unlike fromBengali, this function doesn't throw on invalid dates.\n * Returns a fallback Date object for invalid inputs.\n *\n * @param bengaliDate - Bengali date object with year, month, day\n * @param fallback - Fallback Date if conversion fails (default: current date)\n * @returns Gregorian Date object or fallback\n *\n * @example\n * Valid conversions:\n * ```typescript\n * safeFromBengali({ year: 1431, month: 1, day: 1 });\n * // Date object for 2024-04-14\n * ```\n *\n * @example\n * Invalid dates with fallback:\n * ```typescript\n * const fallbackDate = new Date(2024, 0, 1);\n * safeFromBengali({ year: 1431, month: 13, day: 1 }, fallbackDate);\n * // Returns fallbackDate\n *\n * safeFromBengali({ year: 0, month: 1, day: 1 }, fallbackDate);\n * // Returns fallbackDate\n * ```\n */\nexport function safeFromBengali(\n bengaliDate: { year: number; month: number; day: number },\n fallback?: Date\n): Date {\n try {\n if (!isValidBengaliDate(bengaliDate)) {\n return fallback || new Date();\n }\n return fromBengali(bengaliDate);\n } catch {\n return fallback || new Date();\n }\n}\n\n/**\n * Gets the number of days in a Bengali month.\n *\n * Bengali calendar month lengths:\n * - Months 1-5: 31 days\n * - Months 6-10: 30 days\n * - Month 11: 29 or 30 days (depends on leap year)\n * - Month 12: 30 days\n *\n * @param month - Bengali month (1-12)\n * @param year - Bengali year (for leap year calculation)\n * @returns Number of days in the month, or 0 if invalid\n *\n * @example\n * First five months (31 days):\n * ```typescript\n * getBengaliMonthDays(1, 1431); // 31 (Boishakh)\n * getBengaliMonthDays(2, 1431); // 31 (Joishtho)\n * getBengaliMonthDays(5, 1431); // 31 (Bhadro)\n * ```\n *\n * @example\n * Months 6-10 and 12 (30 days):\n * ```typescript\n * getBengaliMonthDays(6, 1431); // 30 (Ashwin)\n * getBengaliMonthDays(10, 1431); // 30 (Magh)\n * getBengaliMonthDays(12, 1431); // 30 (Chaitra)\n * ```\n *\n * @example\n * Falgun (month 11) - leap year handling:\n * ```typescript\n * getBengaliMonthDays(11, 1427); // 30 (2020 is leap year)\n * getBengaliMonthDays(11, 1428); // 29 (2021 is not leap year)\n * ```\n *\n * @example\n * Invalid inputs:\n * ```typescript\n * getBengaliMonthDays(0, 1431); // 0\n * getBengaliMonthDays(13, 1431); // 0\n * ```\n */\nexport function getBengaliMonthDays(month: number, year: number): number {\n if (!isValidBengaliMonth(month) || !isValidBengaliYear(year)) {\n return 0;\n }\n\n const monthLengths = getBengaliMonthLengths(year);\n return monthLengths[month - 1];\n}\n\n/**\n * Adds days to a Bengali date.\n *\n * This function properly handles month and year boundaries, including\n * varying month lengths and leap years.\n *\n * @param bengaliDate - Starting Bengali date\n * @param days - Number of days to add (can be negative to subtract)\n * @returns New Bengali date object\n *\n * @example\n * Adding days within same month:\n * ```typescript\n * addDaysToBengaliDate({ year: 1431, month: 1, day: 10 }, 5);\n * // { year: 1431, month: 1, day: 15 }\n * ```\n *\n * @example\n * Adding days across months:\n * ```typescript\n * addDaysToBengaliDate({ year: 1431, month: 1, day: 30 }, 5);\n * // { year: 1431, month: 2, day: 4 } (crosses to Joishtho)\n * ```\n *\n * @example\n * Adding days across years:\n * ```typescript\n * addDaysToBengaliDate({ year: 1431, month: 12, day: 29 }, 5);\n * // { year: 1432, month: 1, day: 3 } (crosses to new year)\n * ```\n *\n * @example\n * Subtracting days:\n * ```typescript\n * addDaysToBengaliDate({ year: 1431, month: 2, day: 5 }, -10);\n * // { year: 1431, month: 1, day: 26 }\n * ```\n */\nexport function addDaysToBengaliDate(\n bengaliDate: { year: number; month: number; day: number },\n days: number\n): { year: number; month: number; day: number } {\n if (!isValidBengaliDate(bengaliDate)) {\n throw new Error('Invalid Bengali date');\n }\n\n // Convert to Gregorian, add days, convert back\n const gregorianDate = fromBengali(bengaliDate);\n const newDate = new Date(gregorianDate.getTime() + days * 86400000);\n return toBengali(newDate);\n}\n\n/**\n * Calculates the difference in days between two Bengali dates.\n *\n * The result is positive if the second date is later, negative if earlier.\n *\n * @param date1 - First Bengali date\n * @param date2 - Second Bengali date\n * @returns Number of days between dates (date2 - date1)\n *\n * @example\n * Difference within same month:\n * ```typescript\n * const diff = getBengaliDateDifference(\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 15 }\n * );\n * // 5\n * ```\n *\n * @example\n * Difference across months:\n * ```typescript\n * const diff = getBengaliDateDifference(\n * { year: 1431, month: 1, day: 1 },\n * { year: 1431, month: 2, day: 1 }\n * );\n * // 31 (Boishakh has 31 days)\n * ```\n *\n * @example\n * Negative difference (earlier date):\n * ```typescript\n * const diff = getBengaliDateDifference(\n * { year: 1431, month: 1, day: 15 },\n * { year: 1431, month: 1, day: 10 }\n * );\n * // -5\n * ```\n *\n * @example\n * Across years:\n * ```typescript\n * const diff = getBengaliDateDifference(\n * { year: 1431, month: 1, day: 1 },\n * { year: 1432, month: 1, day: 1 }\n * );\n * // 366 (days in Bengali year 1431)\n * ```\n */\nexport function getBengaliDateDifference(\n date1: { year: number; month: number; day: number },\n date2: { year: number; month: number; day: number }\n): number {\n if (!isValidBengaliDate(date1) || !isValidBengaliDate(date2)) {\n throw new Error('Invalid Bengali date');\n }\n\n const gregorian1 = fromBengali(date1);\n const gregorian2 = fromBengali(date2);\n\n return Math.floor((gregorian2.getTime() - gregorian1.getTime()) / 86400000);\n}\n\n/**\n * Compares two Bengali dates.\n *\n * @param date1 - First Bengali date\n * @param date2 - Second Bengali date\n * @returns -1 if date1 < date2, 0 if equal, 1 if date1 > date2\n *\n * @example\n * First date is earlier:\n * ```typescript\n * compareBengaliDates(\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 15 }\n * ); // -1\n * ```\n *\n * @example\n * Dates are equal:\n * ```typescript\n * compareBengaliDates(\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 10 }\n * ); // 0\n * ```\n *\n * @example\n * First date is later:\n * ```typescript\n * compareBengaliDates(\n * { year: 1431, month: 2, day: 1 },\n * { year: 1431, month: 1, day: 31 }\n * ); // 1\n * ```\n */\nexport function compareBengaliDates(\n date1: { year: number; month: number; day: number },\n date2: { year: number; month: number; day: number }\n): -1 | 0 | 1 {\n if (!isValidBengaliDate(date1) || !isValidBengaliDate(date2)) {\n throw new Error('Invalid Bengali date');\n }\n\n if (date1.year !== date2.year) {\n return date1.year < date2.year ? -1 : 1;\n }\n if (date1.month !== date2.month) {\n return date1.month < date2.month ? -1 : 1;\n }\n if (date1.day !== date2.day) {\n return date1.day < date2.day ? -1 : 1;\n }\n return 0;\n}\n\n/**\n * Checks if a Bengali date is in a range (inclusive).\n *\n * @param date - Bengali date to check\n * @param start - Start of range (inclusive)\n * @param end - End of range (inclusive)\n * @returns true if date is in range, false otherwise\n *\n * @example\n * Date within range:\n * ```typescript\n * isBengaliDateInRange(\n * { year: 1431, month: 1, day: 15 },\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 20 }\n * ); // true\n * ```\n *\n * @example\n * Date on boundaries:\n * ```typescript\n * isBengaliDateInRange(\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 20 }\n * ); // true (start boundary)\n * ```\n *\n * @example\n * Date outside range:\n * ```typescript\n * isBengaliDateInRange(\n * { year: 1431, month: 2, day: 1 },\n * { year: 1431, month: 1, day: 10 },\n * { year: 1431, month: 1, day: 20 }\n * ); // false\n * ```\n */\nexport function isBengaliDateInRange(\n date: { year: number; month: number; day: number },\n start: { year: number; month: number; day: number },\n end: { year: number; month: number; day: number }\n): boolean {\n if (!isValidBengaliDate(date) || !isValidBengaliDate(start) || !isValidBengaliDate(end)) {\n return false;\n }\n\n return compareBengaliDates(date, start) >= 0 && compareBengaliDates(date, end) <= 0;\n}\n\n/**\n * Gets the first day of a Bengali month.\n *\n * @param month - Bengali month (1-12)\n * @param year - Bengali year\n * @returns Bengali date object for the first day of the month\n *\n * @example\n * ```typescript\n * getFirstDayOfBengaliMonth(1, 1431);\n * // { year: 1431, month: 1, day: 1 }\n *\n * getFirstDayOfBengaliMonth(6, 1431);\n * // { year: 1431, month: 6, day: 1 }\n * ```\n */\nexport function getFirstDayOfBengaliMonth(\n month: number,\n year: number\n): { year: number; month: number; day: number } {\n if (!isValidBengaliMonth(month) || !isValidBengaliYear(year)) {\n throw new Error('Invalid month or year');\n }\n\n return { year, month, day: 1 };\n}\n\n/**\n * Gets the last day of a Bengali month.\n *\n * @param month - Bengali month (1-12)\n * @param year - Bengali year\n * @returns Bengali date object for the last day of the month\n *\n * @example\n * Months with 31 days:\n * ```typescript\n * getLastDayOfBengaliMonth(1, 1431);\n * // { year: 1431, month: 1, day: 31 } (Boishakh)\n * ```\n *\n * @example\n * Months with 30 days:\n * ```typescript\n * getLastDayOfBengaliMonth(6, 1431);\n * // { year: 1431, month: 6, day: 30 } (Ashwin)\n * ```\n *\n * @example\n * Falgun with leap year:\n * ```typescript\n * getLastDayOfBengaliMonth(11, 1427);\n * // { year: 1427, month: 11, day: 30 } (leap year)\n *\n * getLastDayOfBengaliMonth(11, 1428);\n * // { year: 1428, month: 11, day: 29 } (non-leap year)\n * ```\n */\nexport function getLastDayOfBengaliMonth(\n month: number,\n year: number\n): { year: number; month: number; day: number } {\n if (!isValidBengaliMonth(month) || !isValidBengaliYear(year)) {\n throw new Error('Invalid month or year');\n }\n\n const days = getBengaliMonthDays(month, year);\n return { year, month, day: days };\n}\n\n/**\n * Checks if a Bengali year is a leap year.\n *\n * Bengali leap years correspond to Gregorian leap years.\n * The Bengali calendar adjusts Falgun (month 11) from 29 to 30 days in leap years.\n *\n * @param year - Bengali year\n * @returns true if leap year, false otherwise\n *\n * @example\n * Leap years:\n * ```typescript\n * isBengaliLeapYear(1427); // true (corresponds to 2020, a leap year)\n * isBengaliLeapYear(1420); // true (corresponds to 2013... wait, let me recalculate)\n * ```\n *\n * @example\n * Non-leap years:\n * ```typescript\n * isBengaliLeapYear(1428); // false (corresponds to 2021)\n * isBengaliLeapYear(1429); // false (corresponds to 2022)\n * ```\n */\nexport function isBengaliLeapYear(year: number): boolean {\n if (!isValidBengaliYear(year)) {\n return false;\n }\n\n const gregorianYear = year + 593;\n return (gregorianYear % 4 === 0 && gregorianYear % 100 !== 0) || gregorianYear % 400 === 0;\n}\n\n/**\n * Formats a Bengali date as a string with Bengali digits.\n *\n * This is a convenience wrapper around getBengaliDate.\n *\n * @param bengaliDate - Bengali date object\n * @param options - Formatting options\n * @returns Formatted Bengali date string\n *\n * @example\n * Basic formatting:\n * ```typescript\n * formatBengaliDate({ year: 1431, month: 1, day: 15 });\n * // \"১৫ বৈশাখ ১৪৩১\"\n * ```\n *\n * @example\n * Without year:\n * ```typescript\n * formatBengaliDate(\n * { year: 1431, month: 1, day: 15 },\n * { includeYear: false }\n * );\n * // \"১৫ বৈশাখ\"\n * ```\n *\n * @example\n * With weekday:\n * ```typescript\n * formatBengaliDate(\n * { year: 1431, month: 1, day: 1 },\n * { includeWeekday: true }\n * );\n * // \"রবিবার ১ বৈশাখ ১৪৩১\" (if 1 Boishakh 1431 is a Sunday)\n * ```\n */\nexport function formatBengaliDate(\n bengaliDate: { year: number; month: number; day: number },\n options?: { includeYear?: boolean; includeWeekday?: boolean }\n): string {\n if (!isValidBengaliDate(bengaliDate)) {\n throw new Error('Invalid Bengali date');\n }\n\n const gregorianDate = fromBengali(bengaliDate);\n return getBengaliDate(gregorianDate, options);\n}\n\n/**\n * Gets the current date in Bengali calendar.\n *\n * @returns Current Bengali date object\n *\n * @example\n * ```typescript\n * const today = getCurrentBengaliDate();\n * // { year: 1431, month: 9, day: 24 } (example for 2025-01-07)\n * ```\n */\nexport function getCurrentBengaliDate(): { year: number; month: number; day: number } {\n return toBengali(new Date());\n}\n\n/**\n * Batch converts an array of Gregorian dates to Bengali dates.\n *\n * @param dates - Array of Gregorian Date objects\n * @returns Array of Bengali date objects\n *\n * @example\n * ```typescript\n * const dates = [\n * new Date(2024, 3, 14),\n * new Date(2024, 3, 15),\n * new Date(2024, 3, 16)\n * ];\n * const bengaliDates = batchToBengali(dates);\n * // [\n * // { year: 1431, month: 1, day: 1 },\n * // { year: 1431, month: 1, day: 2 },\n * // { year: 1431, month: 1, day: 3 }\n * // ]\n * ```\n */\nexport function batchToBengali(dates: Date[]): Array<{ year: number; month: number; day: number }> {\n return dates.map((date) => safeToBengali(date));\n}\n\n/**\n * Gets the month lengths for a given Bengali year.\n */\nexport function getBengaliMonthLengths(bengaliYear: number): number[] {\n // Gregorian year when Falgun falls\n const gregorianYear = bengaliYear + 594;\n const isLeapYear =\n gregorianYear % 4 === 0 && (gregorianYear % 100 !== 0 || gregorianYear % 400 === 0);\n\n return [\n 31, // Boishakh\n 31, // Joishtho\n 31, // Asharh\n 31, // Srabon\n 31, // Bhadro\n 30, // Ashwin\n 30, // Kartik\n 30, // Agrahayan\n 30, // Poush\n 30, // Magh\n isLeapYear ? 30 : 29, // Falgun ← 30 in leap years\n 30, // Chaitra\n ];\n}\n","import { getBengaliMonthLengths } from './utils';\n\n/**\n * Converts a Gregorian date to Bengali calendar date.\n *\n * This function performs accurate conversion from the Gregorian calendar\n * to the Bengali calendar (also known as Bangla calendar or Bengali calendar).\n * The Bengali calendar year is typically 593-594 years behind the Gregorian calendar.\n *\n * **Bengali Calendar System:**\n * - New Year (Pohela Boishakh): April 14 (Gregorian)\n * - 12 months with varying lengths (31, 30, or 29/30 days)\n * - Leap year adjustment in Falgun (month 11)\n *\n * **Month Names:**\n * 1. বৈশাখ (Boishakh) - 31 days\n * 2. জ্যৈষ্ঠ (Joishtho) - 31 days\n * 3. আষাঢ় (Asharh) - 31 days\n * 4. শ্রাবণ (Srabon) - 31 days\n * 5. ভাদ্র (Bhadro) - 31 days\n * 6. আশ্বিন (Ashwin) - 30 days\n * 7. কার্তিক (Kartik) - 30 days\n * 8. অগ্রহায়ণ (Agrahayan) - 30 days\n * 9. পৌষ (Poush) - 30 days\n * 10. মাঘ (Magh) - 30 days\n * 11. ফাল্গুন (Falgun) - 29 or 30 days (leap year dependent)\n * 12. চৈত্র (Chaitra) - 30 days\n *\n * @param date - Gregorian Date object to convert\n * @returns Bengali date object with year, month (1-12), and day properties\n *\n * @example\n * Bengali New Year (Pohela Boishakh):\n * ```typescript\n * toBengali(new Date(2024, 3, 14)); // April 14, 2024\n * // { year: 1431, month: 1, day: 1 }\n * ```\n *\n * @example\n * Mid-year dates:\n * ```typescript\n * toBengali(new Date(2024, 6, 15)); // July 15, 2024\n * // { year: 1431, month: 4, day: 1 } (approx - Srabon)\n *\n * toBengali(new Date(2024, 11, 31)); // December 31, 2024\n * // { year: 1431, month: 9, day: 17 } (approx - Poush)\n * ```\n *\n * @example\n * Before Bengali New Year (same Gregorian year):\n * ```typescript\n * toBengali(new Date(2024, 0, 15)); // January 15, 2024\n * // { year: 1430, month: 10, day: 2 } (approx - Magh)\n * ```\n *\n * @example\n * Practical usage:\n * ```typescript\n * const today = new Date();\n * const bengaliDate = toBengali(today);\n * console.log(`${bengaliDate.day}/${bengaliDate.month}/${bengaliDate.year}`);\n * // \"24/9/1431\" (example)\n * ```\n *\n * @example\n * Leap year handling:\n * ```typescript\n * // 2020 is a leap year, affecting Falgun (month 11)\n * toBengali(new Date(2021, 2, 14)); // March 14, 2021\n * // Month 11 (Falgun) will have 30 days in Bengali year 1427\n * ```\n */\nexport function toBengali(date: Date): { year: number; month: number; day: number } {\n const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));\n\n const gYear = d.getUTCFullYear();\n const gMonth = d.getUTCMonth() + 1;\n const gDay = d.getUTCDate();\n\n // Determine Bengali year\n const isBeforeBoishakh = gMonth < 4 || (gMonth === 4 && gDay < 14);\n const bengaliYear = gYear - (isBeforeBoishakh ? 594 : 593);\n\n // Always count from 1 Boishakh\n const boishakhYear = isBeforeBoishakh ? gYear - 1 : gYear;\n const boishakh1 = new Date(Date.UTC(boishakhYear, 3, 14)); // April 14\n\n const daysSinceBoishakh = Math.floor((d.getTime() - boishakh1.getTime()) / 86400000);\n\n const monthLengths = getBengaliMonthLengths(bengaliYear);\n\n let remaining = daysSinceBoishakh;\n let monthIndex = 0;\n\n while (remaining >= monthLengths[monthIndex]) {\n remaining -= monthLengths[monthIndex];\n monthIndex++;\n }\n\n return {\n year: bengaliYear,\n month: monthIndex + 1,\n day: remaining + 1,\n };\n}\n","import { getSeasonFromMonth } from './getSeasonFromMonth';\nimport { toBengali } from '../calendar/toBengali';\n\n/**\n * Gets the Bangla season name from a Date object.\n *\n * This function determines the current Bengali season based on the Bengali month of the given date.\n * It follows the traditional Bengali calendar system which divides the year into six seasons.\n *\n * **Bengali Seasons (ঋতু):**\n * - গ্রীষ্ম (Grisshô - Summer): months 1-2 (বৈশাখ-জ্যৈষ্ঠ)\n * - বর্ষা (Bôrsha - Monsoon): months 3-5 (আষাঢ়-শ্রাবণ-ভাদ্র)\n * - শরৎ (Shôrôt - Autumn): months 6-7 (আশ্বিন-কার্তিক)\n * - হেমন্ত (Hemonto - Late Autumn): month 8 (অগ্রহায়ণ)\n * - শীত (Sheet - Winter): months 9-10 (পৌষ-মাঘ)\n * - বসন্ত (Bôshonto - Spring): months 11-12 (ফাল্গুন-চৈত্র)\n *\n * @param date - JavaScript Date object\n * @returns Bangla season name\n *\n * @example\n * Basic usage:\n * ```typescript\n * const date1 = new Date('2024-04-15'); // Bengali month 1 (Boishakh)\n * getSeason(date1); // 'গ্রীষ্ম'\n *\n * const date2 = new Date('2024-07-15'); // Bengali month 4 (Monsoon period)\n * getSeason(date2); // 'বর্ষা'\n * ```\n *\n * @example\n * All seasons throughout the year:\n * ```typescript\n * getSeason(new Date('2024-04-15')); // 'গ্রীষ্ম' (Summer - Boishakh)\n * getSeason(new Date('2024-07-15')); // 'বর্ষা' (Monsoon - Srabon)\n * getSeason(new Date('2024-10-15')); // 'শরৎ' (Autumn - Kartik)\n * getSeason(new Date('2024-11-15')); // 'হেমন্ত' (Late Autumn - Agrahayan)\n * getSeason(new Date('2024-01-07')); // 'শীত' (Winter - Poush)\n * getSeason(new Date('2024-03-15')); // 'বসন্ত' (Spring - Falgun)\n * ```\n *\n * @example\n * Current season:\n * ```typescript\n * const today = new Date();\n * const currentSeason = getSeason(today);\n * console.log(`বর্তমান ঋতু: ${currentSeason}`);\n * // Output example: \"বর্তমান ঋতু: শীত\"\n * ```\n *\n * @example\n * Season-specific content:\n * ```typescript\n * const date = new Date();\n * const season = getSeason(date);\n *\n * const greetings: Record<string, string> = {\n * 'গ্রীষ্ম': 'গ্রীষ্মের শুভেচ্ছা!',\n * 'বর্ষা': 'বর্ষার শুভেচ্ছা!',\n * 'শরৎ': 'শরতের শুভেচ্ছা!',\n * 'হেমন্ত': 'হেমন্তের শুভেচ্ছা!',\n * 'শীত': 'শীতের শুভেচ্ছা!',\n * 'বসন্ত': 'বসন্তের শুভেচ্ছা!'\n * };\n *\n * console.log(greetings[season]);\n * ```\n */\nexport function getSeason(date: Date): string {\n const bengaliDate = toBengali(date);\n return getSeasonFromMonth(bengaliDate.month);\n}\n\n","import { BANGLA_SEASONS } from '../constants';\n\n/**\n * Validates if a value is a valid month number (1-12).\n *\n * This function checks if the input is an integer between 1 and 12 (inclusive),\n * representing January through December.\n *\n * @param value - The value to validate\n * @returns true if the value is a valid month number, false otherwise\n *\n * @example\n * ```typescript\n * isValidMonth(1); // true (January)\n * isValidMonth(12); // true (December)\n * isValidMonth(6); // true (June)\n * isValidMonth(0); // false (out of range)\n * isValidMonth(13); // false (out of range)\n * isValidMonth('6'); // false (not a number)\n * isValidMonth(6.5); // false (not an integer)\n * ```\n */\nexport function isValidMonth(value: any): boolean {\n if (typeof value !== 'number') {\n return false;\n }\n\n if (!Number.isFinite(value)) {\n return false;\n }\n\n if (!Number.isInteger(value)) {\n return false;\n }\n\n return value >= 1 && value <= 12;\n}\n\n/**\n * Validates if a value is a valid Bangla season name.\n *\n * This function checks if the input is one of the six Bangla season names.\n * The check is case-sensitive and requires exact matches.\n *\n * **Valid season names:**\n * - গ্রীষ্ম (Summer)\n * - বর্ষা (Monsoon)\n * - শরৎ (Autumn)\n * - হেমন্ত (Late Autumn)\n * - শীত (Winter)\n * - বসন্ত (Spring)\n *\n * @param value - The value to validate\n * @returns true if the value is a valid Bangla season name, false otherwise\n *\n * @example\n * ```typescript\n * isValidSeasonName('গ্রীষ্ম'); // true\n * isValidSeasonName('বর্ষা'); // true\n * isValidSeasonName('বসন্ত'); // true\n * isValidSeasonName('invalid'); // false\n * isValidSeasonName(''); // false\n * isValidSeasonName(123); // false\n * ```\n */\nexport function isValidSeasonName(value: any): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n\n const trimmed = value.trim();\n\n if (trimmed === '') {\n return false;\n }\n\n return BANGLA_SEASONS.includes(trimmed as any);\n}\n\n/**\n * Validates if a value is a valid Date object for season determination.\n *\n * @param value - The value to validate\n * @returns true if the value is a valid Date object, false otherwise\n *\n * @example\n * ```typescript\n * isValidDateForSeason(new Date()); // true\n * isValidDateForSeason(new Date('2024-01-07')); // true\n * isValidDateForSeason(new Date('invalid')); // false\n * isValidDateForSeason('2024-01-07'); // false (string, not Date)\n * ```\n */\nexport function isValidDateForSeason(value: any): boolean {\n if (!(value instanceof Date)) {\n return false;\n }\n\n return !isNaN(value.getTime());\n}\n","import { BANGLA_SEASONS } from '../constants';\nimport { getSeason } from './getSeason';\nimport { getSeasonFromMonth } from './getSeasonFromMonth';\n\n/**\n * Gets all Bangla season names as an array.\n *\n * Returns the six Bangla seasons in order:\n * গ্রীষ্ম, বর্ষা, শরৎ, হেমন্ত, শীত, বসন্ত\n *\n * @returns Array of all Bangla season names\n *\n * @example\n * ```typescript\n * const seasons = getAllSeasons();\n * console.log(seasons);\n * // ['গ্রীষ্ম', 'বর্ষা', 'শরৎ', 'হেমন্ত', 'শীত', 'বসন্ত']\n *\n * // Use for dropdown/select options\n * seasons.forEach((season, index) => {\n * console.log(`${index + 1}: ${season}`);\n * });\n * ```\n */\nexport function getAllSeasons(): string[] {\n return ['গ্রীষ্ম', 'বর্ষা', 'শরৎ', 'হেমন্ত', 'শীত', 'বসন্ত'];\n}\n\n/**\n * Gets the month numbers for a given season.\n *\n * This function returns an array of month numbers (1-12) that belong to\n * the specified season in the Bengali calendar system.\n *\n * **Season to Month Mapping:**\n * - গ্রীষ্ম (Summer): months 1-2 (বৈশাখ-জ্যৈষ্ঠ)\n * - বর্ষা (Monsoon): months 3-5 (আষাঢ়-শ্রাবণ-ভাদ্র)\n * - শরৎ (Autumn): months 6-7 (আশ্বিন-কার্তিক)\n * - হেমন্ত (Late Autumn): month 8 (অগ্রহায়ণ)\n * - শীত (Winter): months 9-10 (পৌষ-মাঘ)\n * - বসন্ত (Spring): months 11-12 (ফাল্গুন-চৈত্র)\n *\n * @param seasonName - Bangla season name\n * @returns Array of month numbers for the season\n * @throws {Error} If season name is invalid\n *\n * @example\n * ```typescript\n * getSeasonMonths('গ্রীষ্ম'); // [1, 2]\n * getSeasonMonths('বর্ষা'); // [3, 4, 5]\n * getSeasonMonths('শরৎ'); // [6, 7]\n * getSeasonMonths('হেমন্ত'); // [8]\n * getSeasonMonths('শীত'); // [9, 10]\n * getSeasonMonths('বসন্ত'); // [11, 12]\n * ```\n */\nexport function getSeasonMonths(seasonName: string): number[] {\n const seasonMap: Record<string, number[]> = {\n 'গ্রীষ্ম': [1, 2],\n 'বর্ষা': [3, 4, 5],\n 'শরৎ': [6, 7],\n 'হেমন্ত': [8],\n 'শীত': [9, 10],\n 'বসন্ত': [11, 12],\n };\n\n const months = seasonMap[seasonName];\n if (!months) {\n throw new Error(`Invalid season name: ${seasonName}`);\n }\n\n return months;\n}\n\n/**\n * Gets the season index (0-5) for a given season name.\n *\n * @param seasonName - Bangla season name\n * @returns Season index (0-5), or -1 if invalid\n *\n * @example\n * ```typescript\n * getSeasonIndex('গ্রীষ্ম'); // 0\n * getSeasonIndex('বর্ষা'); // 1\n * getSeasonIndex('বসন্ত'); // 5\n * getSeasonIndex('invalid'); // -1\n * ```\n */\nexport function getSeasonIndex(seasonName: string): number {\n return BANGLA_SEASONS.indexOf(seasonName as any);\n}\n\n/**\n * Gets the season name by index (0-5).\n *\n * @param index - Season index (0-5)\n * @returns Bangla season name\n * @throws {Error} If index is out of range\n *\n * @example\n * ```typescript\n * getSeasonByIndex(0); // 'গ্রীষ্ম'\n * getSeasonByIndex(1); // 'বর্ষা'\n * getSeasonByIndex(5); // 'বসন্ত'\n * getSeasonByIndex(6); // throws Error\n * ```\n */\nexport function getSeasonByIndex(index: number): string {\n if (index < 0 || index > 5) {\n throw new Error('Season index must be between 0 and 5');\n }\n\n return BANGLA_SEASONS[index];\n}\n\n/**\n * Checks if a given month belongs to a specific season.\n *\n * @param monthNumber - Month number (1-12)\n * @param seasonName - Bangla season name\n * @returns true if the month belongs to the season, false otherwise\n *\n * @example\n * ```typescript\n * isMonthInSeason(1, 'গ্রীষ্ম'); // true\n * isMonthInSeason(3, 'বর্ষা'); // true\n * isMonthInSeason(1, 'শীত'); // false\n * ```\n */\nexport function isMonthInSeason(monthNumber: number, seasonName: string): boolean {\n if (monthNumber < 1 || monthNumber > 12) {\n return false;\n }\n\n try {\n const months = getSeasonMonths(seasonName);\n return months.includes(monthNumber);\n } catch {\n return false;\n }\n}\n\n/**\n * Gets the next season in the cycle.\n *\n * @param currentSeason - Current Bangla season name\n * @returns Next season name\n * @throws {Error} If current season name is invalid\n *\n * @example\n * ```typescript\n * getNextSeason('গ্রীষ্ম'); // 'বর্ষা'\n * getNextSeason('শীত'); // 'বসন্ত'\n * getNextSeason('বসন্ত'); // 'গ্রীষ্ম' (wraps around)\n * ```\n */\nexport function getNextSeason(currentSeason: string): string {\n const index = getSeasonIndex(currentSeason);\n if (index === -1) {\n throw new Error(`Invalid season name: ${currentSeason}`);\n }\n\n const nextIndex = (index + 1) % 6;\n return BANGLA_SEASONS[nextIndex];\n}\n\n/**\n * Gets the previous season in the cycle.\n *\n * @param currentSeason - Current Bangla season name\n * @returns Previous season name\n * @throws {Error} If current season name is invalid\n *\n * @example\n * ```typescript\n * getPreviousSeason('বর্ষা'); // 'গ্রীষ্ম'\n * getPreviousSeason('বসন্ত'); // 'শীত'\n * getPreviousSeason('গ্রীষ্ম'); // 'বসন্ত' (wraps around)\n * ```\n */\nexport function getPreviousSeason(currentSeason: string): string {\n const index = getSeasonIndex(currentSeason);\n if (index === -1) {\n throw new Error(`Invalid season name: ${currentSeason}`);\n }\n\n const prevIndex = (index - 1 + 6) % 6;\n return BANGLA_SEASONS[prevIndex];\n}\n\n/**\n * Safely gets season from a Date object with a fallback value.\n *\n * @param date - Date object\n * @param fallback - Value to return if getting season fails\n * @returns Season name or fallback value\n *\n * @example\n * ```typescript\n * safeGetSeason(new Date('2024-01-15')); // 'গ্রীষ্ম'\n * safeGetSeason(new Date('invalid'), 'N/A'); // 'N/A'\n * ```\n */\nexport function safeGetSeason(date: Date, fallback: string = ''): string {\n // Check if date is valid first\n if (!(date instanceof Date) || isNaN(date.getTime())) {\n return fallback;\n }\n\n try {\n return getSeason(date);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely gets season from a month number with a fallback value.\n *\n * @param monthNumber - Month number (1-12)\n * @param fallback - Value to return if getting season fails\n * @returns Season name or fallback value\n *\n * @example\n * ```typescript\n * safeGetSeasonFromMonth(1); // 'গ্রীষ্ম'\n * safeGetSeasonFromMonth(13, 'N/A'); // 'N/A'\n * ```\n */\nexport function safeGetSeasonFromMonth(monthNumber: number, fallback: string = ''): string {\n try {\n return getSeasonFromMonth(monthNumber);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Gets the current season based on current date.\n *\n * @returns Current Bangla season name\n *\n * @example\n * ```typescript\n * const currentSeason = getCurrentSeason();\n * console.log(`বর্তমান ঋতু: ${currentSeason}`);\n * ```\n */\nexport function getCurrentSeason(): string {\n return getSeason(new Date());\n}\n\n/**\n * Checks if two dates are in the same season.\n *\n * @param date1 - First date\n * @param date2 - Second date\n * @returns true if both dates are in the same season\n *\n * @example\n * ```typescript\n * const date1 = new Date('2024-01-15'); // গ্রীষ্ম\n * const date2 = new Date('2024-02-20'); // গ্রীষ্ম\n * const date3 = new Date('2024-03-15'); // বর্ষা\n *\n * isSameSeason(date1, date2); // true\n * isSameSeason(date1, date3); // false\n * ```\n */\nexport function isSameSeason(date1: Date, date2: Date): boolean {\n const season1 = getSeason(date1);\n const season2 = getSeason(date2);\n return season1 === season2;\n}\n\n/**\n * Gets season information including name, months, and description.\n *\n * @param seasonName - Bangla season name\n * @returns Object with season details\n * @throws {Error} If season name is invalid\n *\n * @example\n * ```typescript\n * const info = getSeasonInfo('গ্রীষ্ম');\n * console.log(info);\n * // {\n * // name: 'গ্রীষ্ম',\n * // months: [1, 2],\n * // index: 0,\n * // monthNames: ['বৈশাখ', 'জ্যৈষ্ঠ']\n * // }\n * ```\n */\nexport function getSeasonInfo(seasonName: string): {\n name: string;\n months: number[];\n index: number;\n monthNames: string[];\n} {\n const index = getSeasonIndex(seasonName);\n if (index === -1) {\n throw new Error(`Invalid season name: ${seasonName}`);\n }\n\n const months = getSeasonMonths(seasonName);\n\n const monthNameMap: Record<number, string> = {\n 1: 'বৈশাখ',\n 2: 'জ্যৈষ্ঠ',\n 3: 'আষাঢ়',\n 4: 'শ্রাবণ',\n 5: 'ভাদ্র',\n 6: 'আশ্বিন',\n 7: 'কার্তিক',\n 8: 'অগ্রহায়ণ',\n 9: 'পৌষ',\n 10: 'মাঘ',\n 11: 'ফাল্গুন',\n 12: 'চৈত্র',\n };\n\n const monthNames = months.map(m => monthNameMap[m]);\n\n return {\n name: seasonName,\n months,\n index,\n monthNames,\n };\n}\n","import { toBanglaNumber } from '../number';\n\n/**\n * Converts a positive integer to its ordinal form in Bangla.\n *\n * This function converts numbers to ordinal representations following Bangla\n * linguistic conventions. It includes special ordinal forms for numbers 1-25\n * and multiples of 10 up to 100. For other numbers, it appends the \"তম\" suffix\n * to the Bangla number.\n *\n * **Note:** Only positive integers are supported. Zero and negative numbers will throw an error.\n *\n * **Special Ordinals:** Numbers 1-25, 30, 40, 50, 60, 70, 80, 90, 100 have\n * dedicated ordinal forms (e.g., প্রথম, দ্বিতীয়, তৃতীয়, etc.)\n *\n * **General Pattern:** Other numbers use the pattern: [Bangla number] + \"তম\"\n * (e.g., ২৬তম, ৩৫তম, ১০১তম)\n *\n * @param number - The positive integer to convert (must be > 0)\n * @returns The ordinal form in Bangla\n * @throws {Error} If the number is less than 1 (zero or negative)\n *\n * @example\n * First few ordinals (special forms):\n * ```typescript\n * toOrdinal(1); // 'প্রথম' (first)\n * toOrdinal(2); // 'দ্বিতীয়' (second)\n * toOrdinal(3); // 'তৃতীয়' (third)\n * toOrdinal(4); // 'চতুর্থ' (fourth)\n * toOrdinal(5); // 'পঞ্চম' (fifth)\n * toOrdinal(10); // 'দশম' (tenth)\n * ```\n *\n * @example\n * Teen ordinals (11-20):\n * ```typescript\n * toOrdinal(11); // 'একাদশ' (eleventh)\n * toOrdinal(15); // 'পঞ্চদশ' (fifteenth)\n * toOrdinal(20); // 'বিংশ' (twentieth)\n * ```\n *\n * @example\n * Extended special forms (21-25):\n * ```typescript\n * toOrdinal(21); // 'একবিংশ'\n * toOrdinal(22); // 'দ্বাবিংশ'\n * toOrdinal(25); // 'পঞ্চবিংশ'\n * ```\n *\n * @example\n * Multiples of 10:\n * ```typescript\n * toOrdinal(30); // 'ত্রিংশ'\n * toOrdinal(50); // 'পঞ্চাশত্তম'\n * toOrdinal(100); // 'শততম'\n * ```\n *\n * @example\n * General pattern with \"তম\" suffix:\n * ```typescript\n * toOrdinal(26); // '২৬তম'\n * toOrdinal(35); // '৩৫তম'\n * toOrdinal(101); // '১০১তম'\n * toOrdinal(1000); // '১০০০তম'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * toOrdinal(0); // throws Error: Number must be greater than 0\n * toOrdinal(-5); // throws Error: Number must be greater than 0\n * ```\n *\n * @example\n * Practical usage (lists, rankings):\n * ```typescript\n * const rank = 3;\n * const ordinal = toOrdinal(rank);\n * console.log(`${ordinal} স্থান`); // 'তৃতীয় স্থান' (third place)\n *\n * const chapter = 15;\n * console.log(`${toOrdinal(chapter)} অধ্যায়`); // 'পঞ্চদশ অধ্যায়' (fifteenth chapter)\n * ```\n */\nexport function toOrdinal(number: number): string {\n if (number < 1) {\n throw new Error('Number must be greater than 0');\n }\n\n // Special cases for first few ordinals\n const specialOrdinals: Record<number, string> = {\n 1: 'প্রথম',\n 2: 'দ্বিতীয়',\n 3: 'তৃতীয়',\n 4: 'চতুর্থ',\n 5: 'পঞ্চম',\n 6: 'ষষ্ঠ',\n 7: 'সপ্তম',\n 8: 'অষ্টম',\n 9: 'নবম',\n 10: 'দশম',\n 11: 'একাদশ',\n 12: 'দ্বাদশ',\n 13: 'ত্রয়োদশ',\n 14: 'চতুর্দশ',\n 15: 'পঞ্চদশ',\n 16: 'ষোড়শ',\n 17: 'সপ্তদশ',\n 18: 'অষ্টাদশ',\n 19: 'ঊনবিংশ',\n 20: 'বিংশ',\n 21: 'একবিংশ',\n 22: 'দ্বাবিংশ',\n 23: 'ত্রয়োবিংশ',\n 24: 'চতুর্বিংশ',\n 25: 'পঞ্চবিংশ',\n 30: 'ত্রিংশ',\n 40: 'চত্বারিংশ',\n 50: 'পঞ্চাশত্তম',\n 60: 'ষষ্টিতম',\n 70: 'সপ্ততিতম',\n 80: 'অশীতিতম',\n 90: 'নবতিতম',\n 100: 'শততম',\n };\n\n if (specialOrdinals[number]) {\n return specialOrdinals[number];\n }\n\n // For other numbers, append \"তম\" (tom) suffix\n const banglaNumber = toBanglaNumber(number);\n return `${banglaNumber}তম`;\n}\n\n","/**\n * Checks if a number is valid for ordinal conversion.\n *\n * Valid ordinal numbers must be positive integers (1 or greater).\n *\n * @param value - The value to check\n * @returns true if the value is a valid positive integer for ordinals\n *\n * @example\n * ```typescript\n * isValidOrdinal(1); // true\n * isValidOrdinal(100); // true\n * isValidOrdinal(0); // false\n * isValidOrdinal(-5); // false\n * isValidOrdinal(1.5); // false\n * isValidOrdinal('5' as any); // false\n * ```\n */\nexport function isValidOrdinal(value: number): boolean {\n return typeof value === 'number' &&\n !isNaN(value) &&\n isFinite(value) &&\n Number.isInteger(value) &&\n value >= 1;\n}\n\n/**\n * Checks if a string appears to be a Bangla ordinal.\n *\n * This function checks if the string contains Bangla ordinal keywords\n * or ends with the ordinal suffix \"তম\".\n *\n * @param value - The string to check\n * @returns true if the string appears to be a Bangla ordinal\n *\n * @example\n * ```typescript\n * isBanglaOrdinal('প্রথম'); // true\n * isBanglaOrdinal('দ্বিতীয়'); // true\n * isBanglaOrdinal('২৬তম'); // true\n * isBanglaOrdinal('১০০তম'); // true\n * isBanglaOrdinal('hello'); // false\n * isBanglaOrdinal('123'); // false\n * ```\n */\nexport function isBanglaOrdinal(value: string): boolean {\n if (typeof value !== 'string' || !value.trim()) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Check for common ordinal keywords\n const ordinalKeywords = [\n 'প্রথম', 'দ্বিতীয়', 'তৃতীয়', 'চতুর্থ', 'পঞ্চম',\n 'ষষ্ঠ', 'সপ্তম', 'অষ্টম', 'নবম', 'দশম',\n 'একাদশ', 'দ্বাদশ', 'ত্রয়োদশ', 'চতুর্দশ', 'পঞ্চদশ',\n 'ষোড়শ', 'সপ্তদশ', 'অষ্টাদশ', 'ঊনবিংশ', 'বিংশ',\n 'একবিংশ', 'দ্বাবিংশ', 'ত্রয়োবিংশ', 'চতুর্বিংশ', 'পঞ্চবিংশ',\n 'ত্রিংশ', 'চত্বারিংশ', 'পঞ্চাশত্তম', 'ষষ্টিতম', 'সপ্ততিতম',\n 'অশীতিতম', 'নবতিতম', 'শততম'\n ];\n\n // Check if it's a known ordinal keyword\n if (ordinalKeywords.includes(trimmed)) {\n return true;\n }\n\n // Check if it ends with \"তম\" suffix\n return trimmed.endsWith('তম');\n}\n\n/**\n * Checks if a number has a special ordinal form.\n *\n * Returns true if the number has a dedicated ordinal word\n * (1-25, 30, 40, 50, 60, 70, 80, 90, 100).\n *\n * @param value - The number to check\n * @returns true if the number has a special ordinal form\n *\n * @example\n * ```typescript\n * hasSpecialOrdinal(1); // true (প্রথম)\n * hasSpecialOrdinal(15); // true (পঞ্চদশ)\n * hasSpecialOrdinal(100); // true (শততম)\n * hasSpecialOrdinal(26); // false (uses ২৬তম pattern)\n * hasSpecialOrdinal(35); // false (uses ৩৫তম pattern)\n * ```\n */\nexport function hasSpecialOrdinal(value: number): boolean {\n if (!isValidOrdinal(value)) {\n return false;\n }\n\n const specialNumbers = [\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n 21, 22, 23, 24, 25,\n 30, 40, 50, 60, 70, 80, 90, 100\n ];\n\n return specialNumbers.includes(value);\n}\n\n/**\n * Sanitizes ordinal input to ensure it's a valid positive integer.\n *\n * This function:\n * - Converts string numbers to integers\n * - Rounds decimal numbers to integers\n * - Returns null for invalid inputs\n *\n * @param value - The input value to sanitize\n * @returns Sanitized positive integer or null if invalid\n *\n * @example\n * ```typescript\n * sanitizeOrdinalInput('5'); // 5\n * sanitizeOrdinalInput(3.7); // 4\n * sanitizeOrdinalInput(3.2); // 3\n * sanitizeOrdinalInput('invalid'); // null\n * sanitizeOrdinalInput(-5); // null\n * sanitizeOrdinalInput(0); // null\n * ```\n */\nexport function sanitizeOrdinalInput(value: any): number | null {\n // Try to convert string to number\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') {\n return null;\n }\n const parsed = Number(trimmed);\n if (isNaN(parsed)) {\n return null;\n }\n value = parsed;\n }\n\n // Must be a number at this point\n if (typeof value !== 'number' || isNaN(value) || !isFinite(value)) {\n return null;\n }\n\n // Round to integer\n const rounded = Math.round(value);\n\n // Must be positive\n if (rounded < 1) {\n return null;\n }\n\n return rounded;\n}\n\n/**\n * Checks if a number is in the range for special ordinals.\n *\n * Special ordinals range from 1 to 100 (with specific numbers having\n * dedicated ordinal forms).\n *\n * @param value - The number to check\n * @returns true if the number is in the special ordinals range\n *\n * @example\n * ```typescript\n * isInSpecialOrdinalRange(1); // true\n * isInSpecialOrdinalRange(50); // true\n * isInSpecialOrdinalRange(100); // true\n * isInSpecialOrdinalRange(101); // false\n * isInSpecialOrdinalRange(0); // false\n * ```\n */\nexport function isInSpecialOrdinalRange(value: number): boolean {\n return isValidOrdinal(value) && value >= 1 && value <= 100;\n}\n","import { toOrdinal } from './toOrdinal';\nimport { isValidOrdinal, sanitizeOrdinalInput } from './validate';\n\n/**\n * Safely converts a number to ordinal with a fallback value.\n *\n * Unlike toOrdinal, this function doesn't throw errors for invalid inputs.\n * Instead, it returns the fallback value.\n *\n * @param number - The number to convert\n * @param fallback - Value to return if conversion fails (default: '')\n * @returns Ordinal string or fallback value\n *\n * @example\n * ```typescript\n * safeToOrdinal(5); // 'পঞ্চম'\n * safeToOrdinal(0); // ''\n * safeToOrdinal(-5, 'N/A'); // 'N/A'\n * safeToOrdinal(1.5, '---'); // '---'\n * ```\n */\nexport function safeToOrdinal(number: number, fallback: string = ''): string {\n try {\n if (!isValidOrdinal(number)) {\n return fallback;\n }\n return toOrdinal(number);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Converts an array of numbers to ordinals.\n *\n * This function processes multiple numbers at once, converting each to\n * its ordinal form. Invalid numbers are skipped.\n *\n * @param numbers - Array of numbers to convert\n * @returns Array of ordinal strings (invalid numbers are skipped)\n *\n * @example\n * ```typescript\n * batchToOrdinal([1, 2, 3, 4, 5]);\n * // ['প্রথম', 'দ্বিতীয়', 'তৃতীয়', 'চতুর্থ', 'পঞ্চম']\n *\n * batchToOrdinal([1, -5, 3, 0, 5]);\n * // ['প্রথম', 'তৃতীয়', 'পঞ্চম'] (invalid numbers skipped)\n *\n * batchToOrdinal([10, 20, 30]);\n * // ['দশম', 'বিংশ', 'ত্রিংশ']\n * ```\n */\nexport function batchToOrdinal(numbers: number[]): string[] {\n return numbers\n .filter(num => isValidOrdinal(num))\n .map(num => toOrdinal(num));\n}\n\n/**\n * Parses and converts input to ordinal in one step.\n *\n * This function sanitizes the input (handling strings, decimals) and\n * then converts to ordinal.\n *\n * @param value - Input value (number or string)\n * @returns Ordinal string\n * @throws {Error} If input cannot be sanitized to a valid positive integer\n *\n * @example\n * ```typescript\n * parseAndConvertToOrdinal('5'); // 'পঞ্চম'\n * parseAndConvertToOrdinal(3.7); // 'চতুর্থ' (rounds to 4)\n * parseAndConvertToOrdinal(3.2); // 'তৃতীয়' (rounds to 3)\n * parseAndConvertToOrdinal('10'); // 'দশম'\n * parseAndConvertToOrdinal('invalid'); // throws Error\n * ```\n */\nexport function parseAndConvertToOrdinal(value: any): string {\n const sanitized = sanitizeOrdinalInput(value);\n if (sanitized === null) {\n throw new Error('Invalid input for ordinal conversion');\n }\n return toOrdinal(sanitized);\n}\n\n/**\n * Gets all special ordinal numbers and their forms.\n *\n * Returns an array of objects containing the number and its ordinal form\n * for all numbers that have special ordinal representations.\n *\n * @returns Array of {number, ordinal} pairs for special ordinals\n *\n * @example\n * ```typescript\n * const specials = getSpecialOrdinals();\n * // [\n * // { number: 1, ordinal: 'প্রথম' },\n * // { number: 2, ordinal: 'দ্বিতীয়' },\n * // { number: 3, ordinal: 'তৃতীয়' },\n * // ...\n * // { number: 100, ordinal: 'শততম' }\n * // ]\n *\n * specials.forEach(({ number, ordinal }) => {\n * console.log(`${number}: ${ordinal}`);\n * });\n * ```\n */\nexport function getSpecialOrdinals(): Array<{ number: number; ordinal: string }> {\n const specialNumbers = [\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n 21, 22, 23, 24, 25,\n 30, 40, 50, 60, 70, 80, 90, 100\n ];\n\n return specialNumbers.map(number => ({\n number,\n ordinal: toOrdinal(number)\n }));\n}\n\n/**\n * Creates a sequence of ordinals from start to end (inclusive).\n *\n * @param start - Starting number (must be >= 1)\n * @param end - Ending number (must be >= start)\n * @returns Array of ordinal strings\n * @throws {Error} If start or end are invalid\n *\n * @example\n * ```typescript\n * getOrdinalSequence(1, 5);\n * // ['প্রথম', 'দ্বিতীয়', 'তৃতীয়', 'চতুর্থ', 'পঞ্চম']\n *\n * getOrdinalSequence(10, 13);\n * // ['দশম', 'একাদশ', 'দ্বাদশ', 'ত্রয়োদশ']\n *\n * getOrdinalSequence(98, 102);\n * // ['৯৮তম', '৯৯তম', 'শততম', '১০১তম', '১০২তম']\n * ```\n */\nexport function getOrdinalSequence(start: number, end: number): string[] {\n if (!isValidOrdinal(start) || !isValidOrdinal(end)) {\n throw new Error('Start and end must be positive integers');\n }\n\n if (start > end) {\n throw new Error('Start must be less than or equal to end');\n }\n\n const sequence: string[] = [];\n for (let i = start; i <= end; i++) {\n sequence.push(toOrdinal(i));\n }\n\n return sequence;\n}\n\n/**\n * Formats a number with ordinal for display.\n *\n * This function combines the number (in digits) with its ordinal form,\n * useful for rankings, positions, or lists.\n *\n * @param number - The number to format\n * @param options - Formatting options\n * @param options.separator - Separator between number and ordinal (default: ' ')\n * @param options.showNumber - Whether to show the number (default: true)\n * @returns Formatted ordinal string\n * @throws {Error} If number is invalid\n *\n * @example\n * ```typescript\n * formatOrdinal(1);\n * // '1 প্রথম'\n *\n * formatOrdinal(5, { separator: ': ' });\n * // '5: পঞ্চম'\n *\n * formatOrdinal(10, { showNumber: false });\n * // 'দশম'\n *\n * formatOrdinal(26);\n * // '26 ২৬তম'\n * ```\n */\nexport function formatOrdinal(\n number: number,\n options: {\n separator?: string;\n showNumber?: boolean;\n } = {}\n): string {\n const { separator = ' ', showNumber = true } = options;\n\n const ordinal = toOrdinal(number);\n\n if (!showNumber) {\n return ordinal;\n }\n\n return `${number}${separator}${ordinal}`;\n}\n\n/**\n * Checks if a given ordinal is in special form or suffix form.\n *\n * @param number - The number to check\n * @returns 'special' for dedicated forms, 'suffix' for \"তম\" pattern\n * @throws {Error} If number is invalid\n *\n * @example\n * ```typescript\n * getOrdinalType(1); // 'special'\n * getOrdinalType(15); // 'special'\n * getOrdinalType(100); // 'special'\n * getOrdinalType(26); // 'suffix'\n * getOrdinalType(101); // 'suffix'\n * ```\n */\nexport function getOrdinalType(number: number): 'special' | 'suffix' {\n if (!isValidOrdinal(number)) {\n throw new Error('Number must be a valid positive integer');\n }\n\n const ordinal = toOrdinal(number);\n\n // If it ends with \"তম\" and contains Bangla digits, it's a suffix form\n if (ordinal.endsWith('তম') && /[০-৯]/.test(ordinal)) {\n return 'suffix';\n }\n\n return 'special';\n}\n\n/**\n * Gets the ordinal for a ranking or position.\n *\n * This is a convenience function specifically designed for rankings,\n * competitions, or lists.\n *\n * @param position - The position/rank (1-based)\n * @param suffix - Optional suffix to append (e.g., 'স্থান', 'পুরস্কার')\n * @returns Formatted ranking string\n * @throws {Error} If position is invalid\n *\n * @example\n * ```typescript\n * getRanking(1); // 'প্রথম'\n * getRanking(1, 'স্থান'); // 'প্রথম স্থান'\n * getRanking(3, 'পুরস্কার'); // 'তৃতীয় পুরস্কার'\n * getRanking(10, 'শ্রেণী'); // 'দশম শ্রেণী'\n * ```\n */\nexport function getRanking(position: number, suffix?: string): string {\n const ordinal = toOrdinal(position);\n\n if (suffix) {\n return `${ordinal} ${suffix}`;\n }\n\n return ordinal;\n}\n\n/**\n * Compares two numbers and returns which is earlier in ordinal sequence.\n *\n * @param num1 - First number\n * @param num2 - Second number\n * @returns -1 if num1 comes first, 1 if num2 comes first, 0 if equal\n *\n * @example\n * ```typescript\n * compareOrdinals(1, 2); // -1 (প্রথম comes before দ্বিতীয়)\n * compareOrdinals(5, 3); // 1 (পঞ্চম comes after তৃতীয়)\n * compareOrdinals(10, 10); // 0 (same position)\n * ```\n */\nexport function compareOrdinals(num1: number, num2: number): number {\n if (!isValidOrdinal(num1) || !isValidOrdinal(num2)) {\n throw new Error('Both numbers must be valid positive integers');\n }\n\n if (num1 < num2) return -1;\n if (num1 > num2) return 1;\n return 0;\n}\n\n/**\n * Gets the next ordinal in sequence.\n *\n * @param current - Current number\n * @returns Next ordinal string\n * @throws {Error} If current is invalid\n *\n * @example\n * ```typescript\n * getNextOrdinal(1); // 'দ্বিতীয়'\n * getNextOrdinal(9); // 'দশম'\n * getNextOrdinal(99); // 'শততম'\n * getNextOrdinal(100); // '১০১তম'\n * ```\n */\nexport function getNextOrdinal(current: number): string {\n if (!isValidOrdinal(current)) {\n throw new Error('Current must be a valid positive integer');\n }\n\n return toOrdinal(current + 1);\n}\n\n/**\n * Gets the previous ordinal in sequence.\n *\n * @param current - Current number\n * @returns Previous ordinal string\n * @throws {Error} If current is invalid or if current is 1\n *\n * @example\n * ```typescript\n * getPreviousOrdinal(2); // 'প্রথম'\n * getPreviousOrdinal(10); // 'নবম'\n * getPreviousOrdinal(100); // '৯৯তম'\n * getPreviousOrdinal(1); // throws Error (no previous ordinal)\n * ```\n */\nexport function getPreviousOrdinal(current: number): string {\n if (!isValidOrdinal(current)) {\n throw new Error('Current must be a valid positive integer');\n }\n\n if (current === 1) {\n throw new Error('No previous ordinal for 1 (প্রথম is the first)');\n }\n\n return toOrdinal(current - 1);\n}\n\n/**\n * Creates an ordinal map for a list of items.\n *\n * This function is useful for adding ordinal numbers to a list of items.\n *\n * @param items - Array of items\n * @param startFrom - Starting position (default: 1)\n * @returns Array of objects with position, ordinal, and item\n *\n * @example\n * ```typescript\n * const winners = ['আলী', 'বাবলু', 'চান্দু'];\n * const ranked = createOrdinalList(winners);\n * // [\n * // { position: 1, ordinal: 'প্রথম', item: 'আলী' },\n * // { position: 2, ordinal: 'দ্বিতীয়', item: 'বাবলু' },\n * // { position: 3, ordinal: 'তৃতীয়', item: 'চান্দু' }\n * // ]\n *\n * const chapters = ['ভূমিকা', 'মূল অংশ', 'উপসংহার'];\n * const numbered = createOrdinalList(chapters);\n * numbered.forEach(({ ordinal, item }) => {\n * console.log(`${ordinal} অধ্যায়: ${item}`);\n * });\n * ```\n */\nexport function createOrdinalList<T>(\n items: T[],\n startFrom: number = 1\n): Array<{ position: number; ordinal: string; item: T }> {\n if (!isValidOrdinal(startFrom)) {\n throw new Error('startFrom must be a valid positive integer');\n }\n\n return items.map((item, index) => {\n const position = startFrom + index;\n return {\n position,\n ordinal: toOrdinal(position),\n item\n };\n });\n}\n","import { toBanglaNumber } from '../number';\n\n/**\n * Formats a time in Bangla with customizable options.\n *\n * This function converts time to Bangla digits and supports both 12-hour and 24-hour formats.\n * It can accept either a Date object or a time string in HH:mm or HH:mm:ss format.\n *\n * **12-Hour Format Periods:**\n * - রাত (night): 12:00 AM - 11:59 PM when hour is 0\n * - সকাল (morning): 1:00 AM - 11:59 AM\n * - দুপুর (noon): 12:00 PM - 12:59 PM\n * - বিকাল (afternoon/evening): 1:00 PM - 11:59 PM\n *\n * @param date - Date object or time string (HH:mm or HH:mm:ss format)\n * @param options - Formatting options\n * @param options.includeSeconds - Whether to include seconds in output (default: false)\n * @param options.use12Hour - Whether to use 12-hour format with Bangla period (default: false)\n * @returns Formatted time string in Bangla\n * @throws {Error} If time string format is invalid\n *\n * @example\n * Basic 24-hour format:\n * ```typescript\n * formatTime(new Date('2024-01-07T14:30:00')); // '১৪:৩০'\n * formatTime('14:30'); // '১৪:৩০'\n * formatTime('09:15'); // '০৯:১৫'\n * ```\n *\n * @example\n * With seconds:\n * ```typescript\n * formatTime('14:30:45', { includeSeconds: true }); // '১৪:৩০:৪৫'\n * formatTime(new Date('2024-01-07T09:15:30'), { includeSeconds: true }); // '০৯:১৫:৩০'\n * ```\n *\n * @example\n * 12-hour format with Bangla periods:\n * ```typescript\n * formatTime('09:30', { use12Hour: true }); // '০৯:৩০ সকাল'\n * formatTime('14:30', { use12Hour: true }); // '০২:৩০ বিকাল'\n * formatTime('12:00', { use12Hour: true }); // '১২:০০ দুপুর'\n * formatTime('00:00', { use12Hour: true }); // '১২:০০ রাত'\n * ```\n *\n * @example\n * Combining options:\n * ```typescript\n * formatTime('14:30:45', { use12Hour: true, includeSeconds: true }); // '০২:৩০:৪৫ বিকাল'\n * formatTime('09:15:30', { use12Hour: true, includeSeconds: true }); // '০৯:১৫:৩০ সকাল'\n * ```\n *\n * @example\n * Error cases:\n * ```typescript\n * formatTime('invalid'); // throws Error: Invalid time string format\n * formatTime('25:00'); // throws Error: Invalid time string format\n * formatTime('12:70'); // throws Error: Invalid time string format\n * ```\n *\n * @example\n * Real-world usage:\n * ```typescript\n * const event = {\n * name: 'Team Meeting',\n * time: new Date('2024-01-07T10:30:00')\n * };\n *\n * const formattedTime = formatTime(event.time, { use12Hour: true });\n * console.log(`${event.name}: ${formattedTime}`);\n * // Output: \"Team Meeting: ১০:৩০ সকাল\"\n * ```\n */\nexport function formatTime(\n date: Date | string,\n options: {\n includeSeconds?: boolean;\n use12Hour?: boolean;\n } = {}\n): string {\n const { includeSeconds = false, use12Hour = false } = options;\n\n let hours: number;\n let minutes: number;\n let seconds: number;\n\n if (typeof date === 'string') {\n const timeParts = date.split(':');\n hours = parseInt(timeParts[0], 10);\n minutes = parseInt(timeParts[1], 10);\n seconds = timeParts[2] ? parseInt(timeParts[2], 10) : 0;\n\n if (Number.isNaN(hours) || Number.isNaN(minutes)) {\n throw new Error('Invalid time string format. Use HH:mm or HH:mm:ss');\n }\n } else {\n hours = date.getHours();\n minutes = date.getMinutes();\n seconds = date.getSeconds();\n }\n\n let displayHours = hours;\n let period = '';\n\n if (use12Hour) {\n if (hours === 0) {\n displayHours = 12;\n period = 'রাত';\n } else if (hours < 12) {\n period = 'সকাল';\n } else if (hours === 12) {\n period = 'দুপুর';\n } else {\n displayHours = hours - 12;\n period = 'বিকাল';\n }\n }\n\n // Pad with leading zeros for consistent formatting\n const banglaHours = toBanglaNumber(displayHours.toString().padStart(2, '0'));\n const banglaMinutes = toBanglaNumber(minutes.toString().padStart(2, '0'));\n const parts: string[] = [banglaHours, banglaMinutes];\n\n if (includeSeconds) {\n const banglaSeconds = toBanglaNumber(seconds.toString().padStart(2, '0'));\n parts.push(banglaSeconds);\n }\n\n const timeString = parts.join(':');\n\n if (period) {\n return `${timeString} ${period}`;\n }\n\n return timeString;\n}\n\n","import { toBanglaNumber } from '../number';\n\n/**\n * Formats a date as relative time in Bangla.\n *\n * This function converts a date to a human-readable relative time string in Bangla,\n * such as \"৫ মিনিট আগে\" (5 minutes ago) or \"আগামীকাল\" (tomorrow).\n *\n * **Time Units (from smallest to largest):**\n * - Seconds: < 60 seconds\n * - Minutes: < 60 minutes\n * - Hours: < 24 hours\n * - Days: Named days (আজ, গতকাল, আগামীকাল, etc.) and day counts\n * - Weeks: < 30 days\n * - Months: < 365 days\n * - Years: >= 365 days\n *\n * **Special Day Names:**\n * - আজ (today): Same calendar day\n * - গতকাল (yesterday): 1 day ago\n * - আগামীকাল (tomorrow): 1 day from now\n * - গত পরশু (day before yesterday): 2 days ago\n * - পরশু (day after tomorrow): 2 days from now\n *\n * @param date - The date to format\n * @param baseDate - Base date for comparison (defaults to current date/time)\n * @returns Relative time string in Bangla\n *\n * @example\n * Immediate time:\n * ```typescript\n * const now = new Date();\n * relativeTime(now, now); // 'এখন'\n * ```\n *\n * @example\n * Recent past (seconds and minutes):\n * ```typescript\n * const now = new Date();\n * const fiveSecondsAgo = new Date(now.getTime() - 5000);\n * relativeTime(fiveSecondsAgo, now); // '৫ সেকেন্ড আগে'\n *\n * const tenMinutesAgo = new Date(now.getTime() - 10 * 60 * 1000);\n * relativeTime(tenMinutesAgo, now); // '১০ মিনিট আগে'\n * ```\n *\n * @example\n * Hours:\n * ```typescript\n * const now = new Date();\n * const twoHoursAgo = new Date(now.getTime() - 2 * 60 * 60 * 1000);\n * relativeTime(twoHoursAgo, now); // '২ ঘণ্টা আগে'\n *\n * const threeHoursLater = new Date(now.getTime() + 3 * 60 * 60 * 1000);\n * relativeTime(threeHoursLater, now); // '৩ ঘণ্টা পরে'\n * ```\n *\n * @example\n * Named days:\n * ```typescript\n * const today = new Date('2024-01-07');\n * const yesterday = new Date('2024-01-06');\n * const tomorrow = new Date('2024-01-08');\n *\n * relativeTime(yesterday, today); // 'গতকাল'\n * relativeTime(tomorrow, today); // 'আগামীকাল'\n * relativeTime(new Date('2024-01-05'), today); // 'গত পরশু'\n * relativeTime(new Date('2024-01-09'), today); // 'পরশু'\n * ```\n *\n * @example\n * Days, weeks, months:\n * ```typescript\n * const now = new Date();\n * const threeDaysAgo = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000);\n * relativeTime(threeDaysAgo, now); // '৩ দিন আগে'\n *\n * const twoWeeksAgo = new Date(now.getTime() - 14 * 24 * 60 * 60 * 1000);\n * relativeTime(twoWeeksAgo, now); // '২ সপ্তাহ আগে'\n *\n * const threeMonthsAgo = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);\n * relativeTime(threeMonthsAgo, now); // '৩ মাস আগে'\n * ```\n *\n * @example\n * Years:\n * ```typescript\n * const now = new Date();\n * const oneYearAgo = new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000);\n * relativeTime(oneYearAgo, now); // '১ বছর আগে'\n * ```\n *\n * @example\n * Real-world usage (social media post):\n * ```typescript\n * const postDate = new Date('2024-01-07T10:30:00');\n * const currentDate = new Date('2024-01-07T11:15:00');\n *\n * const timeAgo = relativeTime(postDate, currentDate);\n * console.log(`Posted ${timeAgo}`); // \"Posted ৪৫ মিনিট আগে\"\n * ```\n */\nexport function relativeTime(\n date: Date,\n baseDate: Date = new Date()\n): string {\n const diffMs = date.getTime() - baseDate.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const absDiffHours = Math.abs(diffHours);\n\n // Check if dates are on the same calendar day\n const baseDay = new Date(baseDate);\n baseDay.setHours(0, 0, 0, 0);\n const targetDay = new Date(date);\n targetDay.setHours(0, 0, 0, 0);\n const diffDays = Math.floor(\n (targetDay.getTime() - baseDay.getTime()) / (1000 * 60 * 60 * 24)\n );\n\n // If time difference is less than 24 hours, prioritize hours/minutes/seconds\n // over day names (even if it crosses a day boundary)\n if (absDiffHours < 24) {\n if (diffSeconds === 0) {\n return 'এখন';\n }\n\n if (Math.abs(diffSeconds) < 60) {\n if (diffSeconds < 0) {\n return `${toBanglaNumber(Math.abs(diffSeconds))} সেকেন্ড আগে`;\n } else {\n return `${toBanglaNumber(diffSeconds)} সেকেন্ড পরে`;\n }\n }\n\n if (Math.abs(diffMinutes) < 60) {\n if (diffMinutes < 0) {\n return `${toBanglaNumber(Math.abs(diffMinutes))} মিনিট আগে`;\n } else {\n return `${toBanglaNumber(diffMinutes)} মিনিট পরে`;\n }\n }\n\n if (diffHours < 0) {\n return `${toBanglaNumber(Math.abs(diffHours))} ঘণ্টা আগে`;\n } else {\n return `${toBanglaNumber(diffHours)} ঘণ্টা পরে`;\n }\n }\n\n // Yesterday/Tomorrow\n if (diffDays === -1) {\n return 'গতকাল';\n }\n\n if (diffDays === 1) {\n return 'আগামীকাল';\n }\n\n // Day before yesterday / Day after tomorrow\n if (diffDays === -2) {\n return 'গত পরশু';\n }\n\n if (diffDays === 2) {\n return 'পরশু';\n }\n\n // Days ago/from now\n if (diffDays < 0) {\n if (Math.abs(diffDays) < 7) {\n return `${toBanglaNumber(Math.abs(diffDays))} দিন আগে`;\n } else if (Math.abs(diffDays) < 30) {\n const weeks = Math.floor(Math.abs(diffDays) / 7);\n return `${toBanglaNumber(weeks)} সপ্তাহ আগে`;\n } else if (Math.abs(diffDays) < 365) {\n const months = Math.floor(Math.abs(diffDays) / 30);\n return `${toBanglaNumber(months)} মাস আগে`;\n } else {\n const years = Math.floor(Math.abs(diffDays) / 365);\n return `${toBanglaNumber(years)} বছর আগে`;\n }\n } else {\n if (diffDays < 7) {\n return `${toBanglaNumber(diffDays)} দিন পরে`;\n } else if (diffDays < 30) {\n const weeks = Math.floor(diffDays / 7);\n return `${toBanglaNumber(weeks)} সপ্তাহ পরে`;\n } else if (diffDays < 365) {\n const months = Math.floor(diffDays / 30);\n return `${toBanglaNumber(months)} মাস পরে`;\n } else {\n const years = Math.floor(diffDays / 365);\n return `${toBanglaNumber(years)} বছর পরে`;\n }\n }\n}\n\n/**\n * Gets relative day names in Bangla.\n *\n * This function returns special Bangla day names for dates within a 2-day range\n * from the base date. Returns an empty string for dates outside this range.\n *\n * **Supported Day Names:**\n * - আজ (today): Same calendar day\n * - গতকাল (yesterday): 1 day before\n * - আগামীকাল (tomorrow): 1 day after\n * - গত পরশু (day before yesterday): 2 days before\n * - পরশু (day after tomorrow): 2 days after\n *\n * @param date - The date to check\n * @param baseDate - Base date for comparison (defaults to current date)\n * @returns Day name in Bangla, or empty string if outside range\n *\n * @example\n * Basic usage:\n * ```typescript\n * const today = new Date('2024-01-07');\n *\n * relativeDay(today, today); // 'আজ'\n * relativeDay(new Date('2024-01-06'), today); // 'গতকাল'\n * relativeDay(new Date('2024-01-08'), today); // 'আগামীকাল'\n * relativeDay(new Date('2024-01-05'), today); // 'গত পরশু'\n * relativeDay(new Date('2024-01-09'), today); // 'পরশু'\n * ```\n *\n * @example\n * Outside range:\n * ```typescript\n * const today = new Date('2024-01-07');\n * relativeDay(new Date('2024-01-04'), today); // '' (3 days ago, outside range)\n * relativeDay(new Date('2024-01-10'), today); // '' (3 days from now, outside range)\n * ```\n *\n * @example\n * Calendar widget usage:\n * ```typescript\n * const dates = [\n * new Date('2024-01-05'),\n * new Date('2024-01-06'),\n * new Date('2024-01-07'),\n * new Date('2024-01-08'),\n * new Date('2024-01-09'),\n * ];\n *\n * const today = new Date('2024-01-07');\n * dates.forEach(date => {\n * const dayName = relativeDay(date, today);\n * console.log(dayName || date.toLocaleDateString());\n * });\n * // Output:\n * // \"গত পরশু\"\n * // \"গতকাল\"\n * // \"আজ\"\n * // \"আগামীকাল\"\n * // \"পরশু\"\n * ```\n */\nexport function relativeDay(\n date: Date,\n baseDate: Date = new Date()\n): string {\n const today = new Date(baseDate);\n today.setHours(0, 0, 0, 0);\n\n const targetDate = new Date(date);\n targetDate.setHours(0, 0, 0, 0);\n\n const diffDays = Math.floor(\n (targetDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)\n );\n\n if (diffDays === 0) {\n return 'আজ';\n } else if (diffDays === -1) {\n return 'গতকাল';\n } else if (diffDays === 1) {\n return 'আগামীকাল';\n } else if (diffDays === -2) {\n return 'গত পরশু';\n } else if (diffDays === 2) {\n return 'পরশু';\n }\n\n return '';\n}\n\n\n","import { isValidDate } from '../date/validate';\n\n/**\n * Validates if a string represents a valid time format.\n *\n * This function checks if the input is a valid time string in HH:mm or HH:mm:ss format.\n * It validates both the format and the actual time values (hours 0-23, minutes/seconds 0-59).\n *\n * @param value - The value to validate\n * @returns true if the value is a valid time string, false otherwise\n *\n * @example\n * ```typescript\n * isValidTimeString('14:30'); // true\n * isValidTimeString('09:15:45'); // true\n * isValidTimeString('23:59'); // true\n * isValidTimeString('00:00'); // true\n * isValidTimeString('24:00'); // false (hour out of range)\n * isValidTimeString('12:60'); // false (minute out of range)\n * isValidTimeString('invalid'); // false\n * isValidTimeString('12'); // false (missing minutes)\n * ```\n */\nexport function isValidTimeString(value: any): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n\n const trimmed = value.trim();\n\n if (trimmed === '') {\n return false;\n }\n\n // Match HH:mm or HH:mm:ss format\n const timePattern = /^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/;\n const match = trimmed.match(timePattern);\n\n if (!match) {\n return false;\n }\n\n const hours = parseInt(match[1], 10);\n const minutes = parseInt(match[2], 10);\n const seconds = match[3] ? parseInt(match[3], 10) : 0;\n\n // Validate ranges\n if (hours < 0 || hours > 23) {\n return false;\n }\n\n if (minutes < 0 || minutes > 59) {\n return false;\n }\n\n if (seconds < 0 || seconds > 59) {\n return false;\n }\n\n return true;\n}\n\n// isValidDate is imported from date/validate for internal use\n// and re-exported to maintain API compatibility\nexport { isValidDate };\n\n/**\n * Validates if a value can be used for time formatting.\n *\n * This function checks if the input is either a valid Date object or a valid time string.\n *\n * @param value - The value to validate\n * @returns true if the value can be formatted as time, false otherwise\n *\n * @example\n * ```typescript\n * isValidTimeInput(new Date()); // true\n * isValidTimeInput('14:30'); // true\n * isValidTimeInput('09:15:45'); // true\n * isValidTimeInput('invalid'); // false\n * isValidTimeInput(123); // false\n * ```\n */\nexport function isValidTimeInput(value: any): boolean {\n return isValidDate(value) || isValidTimeString(value);\n}\n\n/**\n * Validates if a time string has seconds component.\n *\n * @param timeString - The time string to check\n * @returns true if the time string includes seconds, false otherwise\n *\n * @example\n * ```typescript\n * hasSeconds('14:30:45'); // true\n * hasSeconds('14:30'); // false\n * ```\n */\nexport function hasSeconds(timeString: string): boolean {\n if (!isValidTimeString(timeString)) {\n return false;\n }\n\n const parts = timeString.trim().split(':');\n return parts.length === 3;\n}\n\n/**\n * Sanitizes time string input by trimming whitespace.\n *\n * @param input - The time string to sanitize\n * @returns Sanitized time string\n *\n * @example\n * ```typescript\n * sanitizeTimeInput(' 14:30 '); // '14:30'\n * sanitizeTimeInput('09:15:45 '); // '09:15:45'\n * ```\n */\nexport function sanitizeTimeInput(input: string): string {\n if (typeof input !== 'string') {\n return '';\n }\n\n return input.trim();\n}\n","import { formatTime } from './formatTime';\nimport { relativeTime } from './relativeTime';\nimport { sanitizeTimeInput } from './validate';\n\n/**\n * Parses a time string and returns hours, minutes, and seconds.\n *\n * @param timeString - Time string in HH:mm or HH:mm:ss format\n * @returns Object with hours, minutes, and seconds\n * @throws Error if the time string is invalid\n *\n * @example\n * ```typescript\n * parseTime('14:30'); // { hours: 14, minutes: 30, seconds: 0 }\n * parseTime('09:15:45'); // { hours: 9, minutes: 15, seconds: 45 }\n * parseTime('23:59:59'); // { hours: 23, minutes: 59, seconds: 59 }\n * ```\n */\nexport function parseTime(timeString: string): {\n hours: number;\n minutes: number;\n seconds: number;\n} {\n const sanitized = sanitizeTimeInput(timeString);\n const timeParts = sanitized.split(':');\n\n const hours = parseInt(timeParts[0], 10);\n const minutes = parseInt(timeParts[1], 10);\n const seconds = timeParts[2] ? parseInt(timeParts[2], 10) : 0;\n\n if (Number.isNaN(hours) || Number.isNaN(minutes)) {\n throw new Error('Invalid time string format. Use HH:mm or HH:mm:ss');\n }\n\n if (hours < 0 || hours > 23) {\n throw new Error('Hours must be between 0 and 23');\n }\n\n if (minutes < 0 || minutes > 59) {\n throw new Error('Minutes must be between 0 and 59');\n }\n\n if (seconds < 0 || seconds > 59) {\n throw new Error('Seconds must be between 0 and 59');\n }\n\n return { hours, minutes, seconds };\n}\n\n/**\n * Converts a time string to total seconds since midnight.\n *\n * @param timeString - Time string in HH:mm or HH:mm:ss format\n * @returns Total seconds since midnight\n *\n * @example\n * ```typescript\n * timeToSeconds('01:00'); // 3600\n * timeToSeconds('01:30'); // 5400\n * timeToSeconds('12:00:00'); // 43200\n * ```\n */\nexport function timeToSeconds(timeString: string): number {\n const { hours, minutes, seconds } = parseTime(timeString);\n return hours * 3600 + minutes * 60 + seconds;\n}\n\n/**\n * Converts seconds since midnight to a time string.\n *\n * @param totalSeconds - Total seconds since midnight\n * @returns Time string in HH:mm:ss format\n *\n * @example\n * ```typescript\n * secondsToTime(3600); // '01:00:00'\n * secondsToTime(5400); // '01:30:00'\n * secondsToTime(43200); // '12:00:00'\n * ```\n */\nexport function secondsToTime(totalSeconds: number): string {\n if (totalSeconds < 0 || totalSeconds >= 86400) {\n throw new Error('Seconds must be between 0 and 86399');\n }\n\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds\n .toString()\n .padStart(2, '0')}`;\n}\n\n/**\n * Compares two time strings and returns -1, 0, or 1.\n *\n * @param time1 - First time string\n * @param time2 - Second time string\n * @returns -1 if time1 < time2, 0 if equal, 1 if time1 > time2\n *\n * @example\n * ```typescript\n * compareTimes('09:00', '10:00'); // -1\n * compareTimes('14:30', '14:30'); // 0\n * compareTimes('18:00', '12:00'); // 1\n * ```\n */\nexport function compareTimes(time1: string, time2: string): number {\n const seconds1 = timeToSeconds(time1);\n const seconds2 = timeToSeconds(time2);\n\n if (seconds1 < seconds2) return -1;\n if (seconds1 > seconds2) return 1;\n return 0;\n}\n\n/**\n * Checks if a time string falls within a given time range.\n *\n * @param time - Time to check\n * @param startTime - Start of range (inclusive)\n * @param endTime - End of range (inclusive)\n * @returns true if time is within range, false otherwise\n *\n * @example\n * ```typescript\n * isTimeInRange('10:00', '09:00', '11:00'); // true\n * isTimeInRange('08:00', '09:00', '11:00'); // false\n * isTimeInRange('09:00', '09:00', '11:00'); // true (inclusive)\n * ```\n */\nexport function isTimeInRange(time: string, startTime: string, endTime: string): boolean {\n const timeSeconds = timeToSeconds(time);\n const startSeconds = timeToSeconds(startTime);\n const endSeconds = timeToSeconds(endTime);\n\n return timeSeconds >= startSeconds && timeSeconds <= endSeconds;\n}\n\n/**\n * Adds a duration (in minutes) to a time string.\n *\n * @param timeString - Starting time\n * @param minutes - Minutes to add (can be negative to subtract)\n * @returns New time string\n *\n * @example\n * ```typescript\n * addMinutesToTime('10:00', 30); // '10:30:00'\n * addMinutesToTime('10:30', 45); // '11:15:00'\n * addMinutesToTime('10:00', -15); // '09:45:00'\n * ```\n */\nexport function addMinutesToTime(timeString: string, minutes: number): string {\n const totalSeconds = timeToSeconds(timeString);\n let newSeconds = totalSeconds + minutes * 60;\n\n // Handle wraparound for negative times or times beyond 24 hours\n newSeconds = ((newSeconds % 86400) + 86400) % 86400;\n\n return secondsToTime(newSeconds);\n}\n\n/**\n * Calculates the difference in minutes between two times.\n *\n * @param time1 - First time string\n * @param time2 - Second time string\n * @returns Difference in minutes (time2 - time1)\n *\n * @example\n * ```typescript\n * timeDifferenceMinutes('09:00', '10:30'); // 90\n * timeDifferenceMinutes('10:30', '09:00'); // -90\n * timeDifferenceMinutes('09:00', '09:00'); // 0\n * ```\n */\nexport function timeDifferenceMinutes(time1: string, time2: string): number {\n const seconds1 = timeToSeconds(time1);\n const seconds2 = timeToSeconds(time2);\n return Math.floor((seconds2 - seconds1) / 60);\n}\n\n/**\n * Safely formats time with a fallback value.\n *\n * @param date - Date or time string to format\n * @param options - Formatting options\n * @param fallback - Value to return if formatting fails\n * @returns Formatted time or fallback value\n *\n * @example\n * ```typescript\n * safeFormatTime(new Date(), { use12Hour: true }); // '১০:৩০ সকাল'\n * safeFormatTime('invalid', {}, '---'); // '---'\n * ```\n */\nexport function safeFormatTime(\n date: Date | string,\n options: { includeSeconds?: boolean; use12Hour?: boolean } = {},\n fallback: string = ''\n): string {\n try {\n return formatTime(date, options);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Safely gets relative time with a fallback value.\n *\n * @param date - Date to format\n * @param baseDate - Base date for comparison\n * @param fallback - Value to return if formatting fails\n * @returns Relative time string or fallback value\n *\n * @example\n * ```typescript\n * const now = new Date();\n * safeRelativeTime(now); // 'এখন'\n * safeRelativeTime(new Date('invalid'), now, 'N/A'); // 'N/A'\n * ```\n */\nexport function safeRelativeTime(\n date: Date,\n baseDate: Date = new Date(),\n fallback: string = ''\n): string {\n try {\n return relativeTime(date, baseDate);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Gets the time of day period in Bangla.\n *\n * This function returns the appropriate Bangla time period based on the hour:\n * - রাত (night): 00:00 - 05:59\n * - সকাল (morning): 06:00 - 11:59\n * - দুপুর (afternoon/noon): 12:00 - 14:59\n * - বিকাল (evening): 15:00 - 17:59\n * - সন্ধ্যা (dusk): 18:00 - 19:59\n * - রাত (night): 20:00 - 23:59\n *\n * @param date - Date object or time string\n * @returns Time period in Bangla\n *\n * @example\n * ```typescript\n * getTimePeriod('08:00'); // 'সকাল'\n * getTimePeriod('14:30'); // 'দুপুর'\n * getTimePeriod('18:00'); // 'সন্ধ্যা'\n * getTimePeriod('22:00'); // 'রাত'\n * ```\n */\nexport function getTimePeriod(date: Date | string): string {\n let hours: number;\n\n if (typeof date === 'string') {\n const { hours: h } = parseTime(date);\n hours = h;\n } else {\n hours = date.getHours();\n }\n\n if (hours >= 0 && hours < 6) {\n return 'রাত';\n } else if (hours >= 6 && hours < 12) {\n return 'সকাল';\n } else if (hours >= 12 && hours < 15) {\n return 'দুপুর';\n } else if (hours >= 15 && hours < 18) {\n return 'বিকাল';\n } else if (hours >= 18 && hours < 20) {\n return 'সন্ধ্যা';\n } else {\n return 'রাত';\n }\n}\n\n/**\n * Gets current time in Bangla format.\n *\n * @param options - Formatting options\n * @returns Current time in Bangla\n *\n * @example\n * ```typescript\n * getCurrentTimeBangla(); // '১৪:৩০'\n * getCurrentTimeBangla({ use12Hour: true }); // '০২:৩০ দুপুর'\n * getCurrentTimeBangla({ includeSeconds: true }); // '১৪:৩০:৪৫'\n * ```\n */\nexport function getCurrentTimeBangla(\n options: { includeSeconds?: boolean; use12Hour?: boolean } = {}\n): string {\n return formatTime(new Date(), options);\n}\n\n/**\n * Checks if two dates are on the same day.\n *\n * @param date1 - First date\n * @param date2 - Second date\n * @returns true if both dates are on the same calendar day\n *\n * @example\n * ```typescript\n * const date1 = new Date('2024-01-07T10:00:00');\n * const date2 = new Date('2024-01-07T15:00:00');\n * isSameDay(date1, date2); // true\n *\n * const date3 = new Date('2024-01-08T10:00:00');\n * isSameDay(date1, date3); // false\n * ```\n */\nexport function isSameDay(date1: Date, date2: Date): boolean {\n return (\n date1.getFullYear() === date2.getFullYear() &&\n date1.getMonth() === date2.getMonth() &&\n date1.getDate() === date2.getDate()\n );\n}\n","import { toBanglaNumber } from '../number';\n\n/**\n * Formats a Bangladeshi phone number with various formatting options.\n *\n * This function takes a Bangladeshi phone number in any valid format and\n * returns it formatted according to the specified options. It supports\n * different formatting styles, country code inclusion, and Bangla digit conversion.\n *\n * **Format Options:**\n * - `spaced` (default): 017 1234 5678\n * - `dashed`: 017-1234-5678\n * - `compact`: 01712345678\n *\n * @param phoneNumber - Phone number to format (with or without country code)\n * @param options - Formatting options\n * @param options.includeCountryCode - Add +880 country code (default: false)\n * @param options.useBanglaDigits - Convert digits to Bangla numerals (default: false)\n * @param options.format - Format style: 'spaced', 'dashed', or 'compact' (default: 'spaced')\n * @returns Formatted phone number\n * @throws {Error} If phone number has invalid length\n *\n * @example\n * Basic formatting (default spaced format):\n * ```typescript\n * formatPhone('01712345678');\n * // '017 1234 5678'\n *\n * formatPhone('+8801712345678');\n * // '017 1234 5678'\n *\n * formatPhone('017 1234 5678');\n * // '017 1234 5678'\n * ```\n *\n * @example\n * Different format styles:\n * ```typescript\n * formatPhone('01712345678', { format: 'dashed' });\n * // '017-1234-5678'\n *\n * formatPhone('01712345678', { format: 'compact' });\n * // '01712345678'\n *\n * formatPhone('01712345678', { format: 'spaced' });\n * // '017 1234 5678'\n * ```\n *\n * @example\n * With country code:\n * ```typescript\n * formatPhone('01712345678', { includeCountryCode: true });\n * // '+880 017 1234 5678'\n *\n * formatPhone('01712345678', {\n * includeCountryCode: true,\n * format: 'dashed'\n * });\n * // '+880 017-1234-5678'\n * ```\n *\n * @example\n * With Bangla digits:\n * ```typescript\n * formatPhone('01712345678', { useBanglaDigits: true });\n * // '০১৭ ১২৩৪ ৫৬৭৮'\n *\n * formatPhone('01712345678', {\n * useBanglaDigits: true,\n * format: 'dashed'\n * });\n * // '০১৭-১২৩৪-৫৬৭৮'\n *\n * formatPhone('01712345678', {\n * useBanglaDigits: true,\n * includeCountryCode: true\n * });\n * // '+৮৮০ ০১৭ ১২৩৪ ৫৬৭৮'\n * ```\n *\n * @example\n * All options combined:\n * ```typescript\n * formatPhone('8801712345678', {\n * includeCountryCode: true,\n * useBanglaDigits: true,\n * format: 'dashed'\n * });\n * // '+৮৮০ ০১৭-১২৩৪-৫৬৭৮'\n * ```\n */\nexport function formatPhone(\n phoneNumber: string,\n options: {\n includeCountryCode?: boolean;\n useBanglaDigits?: boolean;\n format?: 'spaced' | 'dashed' | 'compact';\n } = {}\n): string {\n const { includeCountryCode = false, useBanglaDigits = false, format = 'spaced' } = options;\n\n // Remove all non-digit characters\n const digits = phoneNumber.replace(/\\D/g, '');\n\n // Remove country code if present\n let number = digits;\n if (digits.startsWith('880')) {\n number = digits.slice(3);\n } else if (digits.startsWith('+880')) {\n number = digits.slice(4);\n }\n\n // Validate length (Bangladeshi mobile numbers are 11 digits with country code, 10 without)\n if (number.length !== 10 && number.length !== 11) {\n throw new Error('Invalid Bangladeshi phone number length');\n }\n\n // Format: 01X-XXXX-XXXX or 01X XXXX XXXX\n let formatted = '';\n if (number.length === 11) {\n // Includes leading 0\n formatted = `${number.slice(0, 3)} ${number.slice(3, 7)} ${number.slice(7)}`;\n } else {\n // 10 digits\n formatted = `0${number.slice(0, 2)} ${number.slice(2, 6)} ${number.slice(6)}`;\n }\n\n if (format === 'dashed') {\n formatted = formatted.replace(/\\s/g, '-');\n } else if (format === 'compact') {\n formatted = formatted.replace(/\\s/g, '');\n }\n\n if (includeCountryCode) {\n formatted = '+880 ' + formatted;\n }\n\n if (useBanglaDigits) {\n formatted = toBanglaNumber(formatted.replace(/\\s|-/g, ''));\n // Re-add formatting\n if (format === 'spaced') {\n formatted = `${formatted.slice(0, 3)} ${formatted.slice(3, 7)} ${formatted.slice(7)}`;\n } else if (format === 'dashed') {\n formatted = `${formatted.slice(0, 3)}-${formatted.slice(3, 7)}-${formatted.slice(7)}`;\n }\n if (includeCountryCode) {\n formatted = '+৮৮০ ' + formatted;\n }\n }\n\n return formatted;\n}\n","/**\n * Validates a Bangladeshi phone number.\n *\n * This function checks if the input is a valid Bangladeshi mobile phone number.\n * It supports numbers with or without country code (+880 or 880) and validates\n * against recognized operator codes.\n *\n * **Valid Operator Codes:**\n * - 013 (Grameenphone)\n * - 014 (Banglalink)\n * - 015 (Teletalk)\n * - 016 (Airtel)\n * - 017 (Grameenphone)\n * - 018 (Robi)\n * - 019 (Banglalink)\n *\n * @param phoneNumber - Phone number string to validate\n * @returns true if valid Bangladeshi phone number, false otherwise\n *\n * @example\n * Valid phone numbers:\n * ```typescript\n * validatePhone('01712345678'); // true\n * validatePhone('+8801712345678'); // true\n * validatePhone('8801712345678'); // true\n * validatePhone('017 1234 5678'); // true\n * validatePhone('017-1234-5678'); // true\n * ```\n *\n * @example\n * Invalid phone numbers:\n * ```typescript\n * validatePhone('0171234567'); // false (too short)\n * validatePhone('017123456789'); // false (too long)\n * validatePhone('01212345678'); // false (invalid operator code)\n * validatePhone('1712345678'); // false (missing leading 0)\n * ```\n */\nexport function validatePhone(phoneNumber: string): boolean {\n // Remove all non-digit characters\n const digits = phoneNumber.replace(/\\D/g, '');\n\n // Check if it starts with country code\n let number = digits;\n if (digits.startsWith('880')) {\n number = digits.slice(3);\n } else if (digits.startsWith('+880')) {\n number = digits.slice(4);\n }\n\n // Bangladeshi mobile numbers should be 10 digits (without country code)\n // or 11 digits (with leading 0)\n if (number.length !== 10 && number.length !== 11) {\n return false;\n }\n\n // Should start with 01 (for mobile)\n if (!number.startsWith('01') && number.length === 11) {\n return false;\n }\n\n if (number.length === 10 && !number.startsWith('1')) {\n return false;\n }\n\n // Valid operator codes: 013, 014, 015, 016, 017, 018, 019\n const operatorCode = number.length === 11 ? number.slice(0, 3) : '0' + number.slice(0, 2);\n const validCodes = ['013', '014', '015', '016', '017', '018', '019'];\n\n return validCodes.includes(operatorCode);\n}\n\n/**\n * Validates a Bangladeshi operator code.\n *\n * @param operatorCode - Three-digit operator code (013-019)\n * @returns true if valid operator code, false otherwise\n *\n * @example\n * ```typescript\n * isValidOperatorCode('017'); // true\n * isValidOperatorCode('018'); // true\n * isValidOperatorCode('012'); // false (not a valid operator)\n * isValidOperatorCode('020'); // false (out of range)\n * ```\n */\nexport function isValidOperatorCode(operatorCode: string): boolean {\n const validCodes = ['013', '014', '015', '016', '017', '018', '019'];\n return validCodes.includes(operatorCode);\n}\n\n/**\n * Checks if a phone number has a country code.\n *\n * @param phoneNumber - Phone number string\n * @returns true if phone number includes country code\n *\n * @example\n * ```typescript\n * hasCountryCode('+8801712345678'); // true\n * hasCountryCode('8801712345678'); // true\n * hasCountryCode('01712345678'); // false\n * ```\n */\nexport function hasCountryCode(phoneNumber: string): boolean {\n const trimmed = phoneNumber.trim();\n return trimmed.startsWith('+880') || trimmed.startsWith('880');\n}\n\n/**\n * Sanitizes a phone number by removing non-digit characters.\n *\n * This function cleans user input by removing spaces, dashes, parentheses,\n * and other non-digit characters (except the leading + for country code).\n *\n * @param phoneNumber - Phone number string to sanitize\n * @returns Sanitized phone number string\n *\n * @example\n * ```typescript\n * sanitizePhoneNumber('017 1234 5678'); // '01712345678'\n * sanitizePhoneNumber('017-1234-5678'); // '01712345678'\n * sanitizePhoneNumber('+880 171 234 5678'); // '+88001712345678'\n * sanitizePhoneNumber('(017) 1234-5678'); // '01712345678'\n * ```\n */\nexport function sanitizePhoneNumber(phoneNumber: string): string {\n if (typeof phoneNumber !== 'string') {\n return '';\n }\n\n let sanitized = phoneNumber.trim();\n\n // Preserve leading + if present\n const hasPlus = sanitized.startsWith('+');\n\n // Remove all non-digit characters\n sanitized = sanitized.replace(/\\D/g, '');\n\n // Re-add the + if it was there\n if (hasPlus) {\n sanitized = '+' + sanitized;\n }\n\n return sanitized;\n}\n\n/**\n * Checks if a phone number string contains only valid characters.\n *\n * Valid characters are: digits (0-9), spaces, dashes, parentheses, and + for country code.\n *\n * @param phoneNumber - Phone number string to check\n * @returns true if contains only valid characters\n *\n * @example\n * ```typescript\n * isValidPhoneFormat('017 1234 5678'); // true\n * isValidPhoneFormat('017-1234-5678'); // true\n * isValidPhoneFormat('+880 171 234 5678'); // true\n * isValidPhoneFormat('017abc5678'); // false\n * ```\n */\nexport function isValidPhoneFormat(phoneNumber: string): boolean {\n if (typeof phoneNumber !== 'string') {\n return false;\n }\n\n // Valid characters: digits, spaces, dashes, parentheses, plus sign\n const validPattern = /^[\\d\\s\\-()+ ]+$/;\n return validPattern.test(phoneNumber.trim());\n}\n","import { formatPhone } from './formatPhone';\nimport { validatePhone, sanitizePhoneNumber } from './validatePhone';\n\n/**\n * Operator information for Bangladeshi mobile networks.\n */\nexport interface OperatorInfo {\n code: string;\n name: string;\n nameBangla: string;\n}\n\n/**\n * Parsed phone number information.\n */\nexport interface ParsedPhoneNumber {\n original: string;\n countryCode: string;\n operatorCode: string;\n number: string;\n fullNumber: string;\n}\n\n/**\n * Gets the mobile operator name from a phone number.\n *\n * This function identifies the mobile network operator based on the\n * three-digit operator code (013-019).\n *\n * **Operator Mapping:**\n * - 013, 017 → Grameenphone (গ্রামীণফোন)\n * - 014, 019 → Banglalink (বাংলালিংক)\n * - 015 → Teletalk (টেলিটক)\n * - 016 → Airtel (এয়ারটেল)\n * - 018 → Robi (রবি)\n *\n * @param phoneNumber - Bangladeshi phone number\n * @returns Operator information or null if invalid\n *\n * @example\n * ```typescript\n * getOperator('01712345678');\n * // { code: '017', name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' }\n *\n * getOperator('01812345678');\n * // { code: '018', name: 'Robi', nameBangla: 'রবি' }\n *\n * getOperator('invalid'); // null\n * ```\n */\nexport function getOperator(phoneNumber: string): OperatorInfo | null {\n if (!validatePhone(phoneNumber)) {\n return null;\n }\n\n const digits = phoneNumber.replace(/\\D/g, '');\n let number = digits;\n\n // Remove country code if present\n if (digits.startsWith('880')) {\n number = digits.slice(3);\n }\n\n // Get operator code\n const operatorCode = number.length === 11 ? number.slice(0, 3) : '0' + number.slice(0, 2);\n\n const operatorMap: Record<string, { name: string; nameBangla: string }> = {\n '013': { name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' },\n '014': { name: 'Banglalink', nameBangla: 'বাংলালিংক' },\n '015': { name: 'Teletalk', nameBangla: 'টেলিটক' },\n '016': { name: 'Airtel', nameBangla: 'এয়ারটেল' },\n '017': { name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' },\n '018': { name: 'Robi', nameBangla: 'রবি' },\n '019': { name: 'Banglalink', nameBangla: 'বাংলালিংক' },\n };\n\n const operator = operatorMap[operatorCode];\n if (!operator) {\n return null;\n }\n\n return {\n code: operatorCode,\n ...operator,\n };\n}\n\n/**\n * Parses a phone number into its components.\n *\n * @param phoneNumber - Phone number to parse\n * @returns Parsed phone number components\n * @throws {Error} If phone number is invalid\n *\n * @example\n * ```typescript\n * parsePhoneNumber('01712345678');\n * // {\n * // original: '01712345678',\n * // countryCode: '880',\n * // operatorCode: '017',\n * // number: '12345678',\n * // fullNumber: '01712345678'\n * // }\n *\n * parsePhoneNumber('+8801812345678');\n * // {\n * // original: '+8801812345678',\n * // countryCode: '880',\n * // operatorCode: '018',\n * // number: '12345678',\n * // fullNumber: '01812345678'\n * // }\n * ```\n */\nexport function parsePhoneNumber(phoneNumber: string): ParsedPhoneNumber {\n if (!validatePhone(phoneNumber)) {\n throw new Error('Invalid phone number');\n }\n\n const original = phoneNumber;\n const digits = phoneNumber.replace(/\\D/g, '');\n\n let number = digits;\n const countryCode = '880';\n\n // Remove country code if present\n if (digits.startsWith('880')) {\n number = digits.slice(3);\n }\n\n // Ensure it has leading 0\n if (number.length === 10) {\n number = '0' + number;\n }\n\n const operatorCode = number.slice(0, 3);\n const subscriberNumber = number.slice(3);\n\n return {\n original,\n countryCode,\n operatorCode,\n number: subscriberNumber,\n fullNumber: number,\n };\n}\n\n/**\n * Normalizes a phone number to standard format (11 digits with leading 0).\n *\n * This function converts any valid Bangladeshi phone number format to\n * the standard 11-digit format with leading 0 (e.g., 01712345678).\n *\n * @param phoneNumber - Phone number to normalize\n * @returns Normalized phone number\n * @throws {Error} If phone number is invalid\n *\n * @example\n * ```typescript\n * normalizePhoneNumber('017 1234 5678'); // '01712345678'\n * normalizePhoneNumber('+8801712345678'); // '01712345678'\n * normalizePhoneNumber('8801712345678'); // '01712345678'\n * normalizePhoneNumber('1712345678'); // '01712345678'\n * ```\n */\nexport function normalizePhoneNumber(phoneNumber: string): string {\n const parsed = parsePhoneNumber(phoneNumber);\n return parsed.fullNumber;\n}\n\n/**\n * Adds country code to a phone number.\n *\n * @param phoneNumber - Phone number (with or without country code)\n * @param format - Format style ('plus' or 'plain')\n * @returns Phone number with country code\n * @throws {Error} If phone number is invalid\n *\n * @example\n * ```typescript\n * addCountryCode('01712345678'); // '+8801712345678'\n * addCountryCode('01712345678', 'plain'); // '8801712345678'\n * addCountryCode('+8801712345678'); // '+8801712345678' (already has it)\n * ```\n */\nexport function addCountryCode(\n phoneNumber: string,\n format: 'plus' | 'plain' = 'plus'\n): string {\n const normalized = normalizePhoneNumber(phoneNumber);\n\n // Remove leading 0 for international format\n const withoutLeadingZero = normalized.slice(1);\n\n if (format === 'plus') {\n return `+880${withoutLeadingZero}`;\n } else {\n return `880${withoutLeadingZero}`;\n }\n}\n\n/**\n * Removes country code from a phone number.\n *\n * @param phoneNumber - Phone number (with or without country code)\n * @returns Phone number without country code (11 digits with leading 0)\n * @throws {Error} If phone number is invalid\n *\n * @example\n * ```typescript\n * removeCountryCode('+8801712345678'); // '01712345678'\n * removeCountryCode('8801712345678'); // '01712345678'\n * removeCountryCode('01712345678'); // '01712345678' (already without it)\n * ```\n */\nexport function removeCountryCode(phoneNumber: string): string {\n return normalizePhoneNumber(phoneNumber);\n}\n\n/**\n * Safely formats a phone number with a fallback value.\n *\n * @param phoneNumber - Phone number to format\n * @param options - Formatting options\n * @param fallback - Value to return if formatting fails\n * @returns Formatted phone number or fallback value\n *\n * @example\n * ```typescript\n * safeFormatPhone('01712345678', { format: 'spaced' }); // '017 1234 5678'\n * safeFormatPhone('invalid', {}, '---'); // '---'\n * ```\n */\nexport function safeFormatPhone(\n phoneNumber: string,\n options: {\n includeCountryCode?: boolean;\n useBanglaDigits?: boolean;\n format?: 'spaced' | 'dashed' | 'compact';\n } = {},\n fallback: string = ''\n): string {\n try {\n return formatPhone(phoneNumber, options);\n } catch {\n return fallback;\n }\n}\n\n/**\n * Checks if two phone numbers are the same.\n *\n * This function normalizes both numbers and compares them, so it correctly\n * identifies the same number in different formats.\n *\n * @param phone1 - First phone number\n * @param phone2 - Second phone number\n * @returns true if both numbers are the same\n *\n * @example\n * ```typescript\n * isSameNumber('01712345678', '+8801712345678'); // true\n * isSameNumber('017 1234 5678', '017-1234-5678'); // true\n * isSameNumber('01712345678', '01812345678'); // false\n * ```\n */\nexport function isSameNumber(phone1: string, phone2: string): boolean {\n try {\n const normalized1 = normalizePhoneNumber(phone1);\n const normalized2 = normalizePhoneNumber(phone2);\n return normalized1 === normalized2;\n } catch {\n return false;\n }\n}\n\n/**\n * Gets all valid operator codes.\n *\n * @returns Array of valid operator codes\n *\n * @example\n * ```typescript\n * const codes = getAllOperatorCodes();\n * // ['013', '014', '015', '016', '017', '018', '019']\n * ```\n */\nexport function getAllOperatorCodes(): string[] {\n return ['013', '014', '015', '016', '017', '018', '019'];\n}\n\n/**\n * Gets all operators with their information.\n *\n * @returns Array of operator information\n *\n * @example\n * ```typescript\n * const operators = getAllOperators();\n * operators.forEach(op => {\n * console.log(`${op.code}: ${op.name} (${op.nameBangla})`);\n * });\n * ```\n */\nexport function getAllOperators(): OperatorInfo[] {\n return [\n { code: '013', name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' },\n { code: '014', name: 'Banglalink', nameBangla: 'বাংলালিংক' },\n { code: '015', name: 'Teletalk', nameBangla: 'টেলিটক' },\n { code: '016', name: 'Airtel', nameBangla: 'এয়ারটেল' },\n { code: '017', name: 'Grameenphone', nameBangla: 'গ্রামীণফোন' },\n { code: '018', name: 'Robi', nameBangla: 'রবি' },\n { code: '019', name: 'Banglalink', nameBangla: 'বাংলালিংক' },\n ];\n}\n\n/**\n * Parses and formats a phone number in one step.\n *\n * This combines sanitization, validation, and formatting into a single operation.\n *\n * @param phoneNumber - Raw phone number input\n * @param options - Formatting options\n * @returns Formatted phone number\n * @throws {Error} If phone number is invalid after sanitization\n *\n * @example\n * ```typescript\n * parseAndFormat(' 017 1234 5678 ', { format: 'dashed' });\n * // '017-1234-5678'\n *\n * parseAndFormat('+880 171 234 5678', { includeCountryCode: false });\n * // '017 1234 5678'\n * ```\n */\nexport function parseAndFormat(\n phoneNumber: string,\n options: {\n includeCountryCode?: boolean;\n useBanglaDigits?: boolean;\n format?: 'spaced' | 'dashed' | 'compact';\n } = {}\n): string {\n const sanitized = sanitizePhoneNumber(phoneNumber);\n return formatPhone(sanitized, options);\n}\n","/**\n * Validates if a string contains ONLY Bengali/Bangla characters and whitespace.\n *\n * This function checks if the entire string consists exclusively of characters\n * from the Bengali Unicode range (U+0980 to U+09FF) and whitespace.\n * It returns false if any non-Bengali, non-whitespace character is present.\n *\n * **Use Cases:**\n * - Form validation (ensuring pure Bengali input)\n * - Content filtering (verifying Bengali-only text)\n * - Data validation (checking text purity)\n *\n * **Allowed Characters:**\n * - Bengali consonants, vowels, diacritics\n * - Bengali digits (০-৯)\n * - Bengali punctuation\n * - Whitespace (spaces, tabs, newlines)\n *\n * **Not Allowed:**\n * - English letters (a-z, A-Z)\n * - English digits (0-9)\n * - Special characters not in Bengali range\n * - Emojis or other Unicode characters\n *\n * @param text - String to validate\n * @returns true if string contains only Bengali characters and whitespace, false otherwise\n *\n * @example\n * Valid pure Bengali text:\n * ```typescript\n * validateBangla('বাংলা'); // true\n * validateBangla('শুভ সকাল'); // true\n * validateBangla('১২৩ টাকা'); // true\n * validateBangla('হ্যালো ওয়ার্ল্ড'); // true\n * ```\n *\n * @example\n * Invalid mixed content:\n * ```typescript\n * validateBangla('Hello বাংলা'); // false (contains English)\n * validateBangla('বাংলা 123'); // false (contains English digits)\n * validateBangla('Test'); // false (English only)\n * validateBangla('বাংলা!'); // false (contains non-Bengali punctuation)\n * ```\n *\n * @example\n * Whitespace handling:\n * ```typescript\n * validateBangla('বাংলা ভাষা'); // true (space allowed)\n * validateBangla(' বাংলা '); // true (spaces allowed)\n * validateBangla(' '); // true (whitespace only)\n * ```\n *\n * @example\n * Empty string:\n * ```typescript\n * validateBangla(''); // false\n * ```\n *\n * @example\n * Form validation:\n * ```typescript\n * function validateBengaliName(name: string): boolean {\n * return validateBangla(name) && name.trim().length > 0;\n * }\n *\n * validateBengaliName('মাহমুদ'); // true\n * validateBengaliName('Mahmud'); // false\n * ```\n */\nexport function validateBangla(text: string): boolean {\n const banglaRegex = /^[\\u0980-\\u09FF\\s]+$/;\n return banglaRegex.test(text);\n}\n","/**\n * Checks if a character is a Bengali digit.\n *\n * Bengali digits range from ০ (0) to ৯ (9).\n * This function checks if the input string contains at least one Bengali digit.\n *\n * **Bengali Digits:**\n * - ০ (shunno) - 0\n * - ১ (ek) - 1\n * - ২ (dui) - 2\n * - ৩ (tin) - 3\n * - ৪ (char) - 4\n * - ৫ (pach) - 5\n * - ৬ (choy) - 6\n * - ৭ (saat) - 7\n * - ৮ (aat) - 8\n * - ৯ (noy) - 9\n *\n * @param char - Character or string to check\n * @returns true if contains at least one Bengali digit, false otherwise\n *\n * @example\n * Single Bengali digits:\n * ```typescript\n * isBanglaDigit('০'); // true\n * isBanglaDigit('৫'); // true\n * isBanglaDigit('৯'); // true\n * ```\n *\n * @example\n * Multiple Bengali digits:\n * ```typescript\n * isBanglaDigit('১২৩'); // true\n * isBanglaDigit('৪৫৬'); // true\n * ```\n *\n * @example\n * Mixed content:\n * ```typescript\n * isBanglaDigit('১৫ দিন'); // true\n * isBanglaDigit('বয়স: ২৫'); // true\n * ```\n *\n * @example\n * English digits:\n * ```typescript\n * isBanglaDigit('0'); // false\n * isBanglaDigit('5'); // false\n * isBanglaDigit('123'); // false\n * ```\n *\n * @example\n * Non-digit characters:\n * ```typescript\n * isBanglaDigit('abc'); // false\n * isBanglaDigit('বাংলা'); // false\n * isBanglaDigit(''); // false\n * ```\n */\nexport function isBanglaDigit(char: string): boolean {\n return /[০-৯]/.test(char);\n}\n","/**\n * Checks if a string contains Bengali/Bangla characters.\n *\n * This function tests if the input string contains at least one character\n * from the Bengali Unicode range (U+0980 to U+09FF), which includes:\n * - Bengali consonants (ক খ গ ঘ ঙ চ ছ জ ঝ ঞ etc.)\n * - Bengali vowels (অ আ ই ঈ উ ঊ etc.)\n * - Bengali vowel diacritics (া ি ী ু ূ etc.)\n * - Bengali digits (০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯)\n * - Bengali punctuation and symbols\n *\n * @param text - String to check\n * @returns true if contains at least one Bengali character, false otherwise\n *\n * @example\n * Pure Bengali text:\n * ```typescript\n * isBanglaText('বাংলা'); // true\n * isBanglaText('হ্যালো'); // true\n * isBanglaText('শুভ সকাল'); // true\n * ```\n *\n * @example\n * Bengali digits:\n * ```typescript\n * isBanglaText('১২৩'); // true\n * isBanglaText('৫০০'); // true\n * ```\n *\n * @example\n * Mixed Bengali and English:\n * ```typescript\n * isBanglaText('Hello বাংলা'); // true\n * isBanglaText('Price: ১০০ টাকা'); // true\n * isBanglaText('Test ১২৩'); // true\n * ```\n *\n * @example\n * English only:\n * ```typescript\n * isBanglaText('Hello'); // false\n * isBanglaText('123'); // false\n * isBanglaText('Test'); // false\n * ```\n *\n * @example\n * Empty or special characters:\n * ```typescript\n * isBanglaText(''); // false\n * isBanglaText(' '); // false\n * isBanglaText('123 abc'); // false\n * ```\n */\nexport function isBanglaText(text: string): boolean {\n // Bangla Unicode range: U+0980 to U+09FF\n const banglaRegex = /[\\u0980-\\u09FF]/;\n return banglaRegex.test(text);\n}\n","/**\n * General utility functions for Bengali/Bangla text operations.\n *\n * This module provides helper functions for working with Bengali text,\n * including counting, detecting, sanitizing, and analyzing Bengali content.\n *\n * @module utils/utils\n */\n\nimport { isBanglaDigit } from './isBanglaDigit';\n\n/**\n * Counts the number of Bengali characters in a string.\n *\n * This function counts characters from the Bengali Unicode range (U+0980 to U+09FF),\n * excluding whitespace and non-Bengali characters.\n *\n * @param text - String to analyze\n * @returns Number of Bengali characters\n *\n * @example\n * Pure Bengali text:\n * ```typescript\n * countBengaliCharacters('বাংলা'); // 5\n * countBengaliCharacters('হ্যালো'); // 6\n * ```\n *\n * @example\n * Mixed content:\n * ```typescript\n * countBengaliCharacters('Hello বাংলা'); // 5\n * countBengaliCharacters('১২৩ টাকা'); // 6\n * ```\n *\n * @example\n * With whitespace:\n * ```typescript\n * countBengaliCharacters('শুভ সকাল'); // 8 (spaces not counted)\n * ```\n */\nexport function countBengaliCharacters(text: string): number {\n const bengaliChars = text.match(/[\\u0980-\\u09FF]/g);\n return bengaliChars ? bengaliChars.length : 0;\n}\n\n/**\n * Counts the number of Bengali digits in a string.\n *\n * Bengali digits: ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯\n *\n * @param text - String to analyze\n * @returns Number of Bengali digits\n *\n * @example\n * ```typescript\n * countBengaliDigits('১২৩'); // 3\n * countBengaliDigits('মূল্য: ১০০ টাকা'); // 3\n * countBengaliDigits('Hello 123'); // 0 (English digits not counted)\n * ```\n */\nexport function countBengaliDigits(text: string): number {\n const bengaliDigits = text.match(/[০-৯]/g);\n return bengaliDigits ? bengaliDigits.length : 0;\n}\n\n/**\n * Checks if a string contains mixed Bengali and non-Bengali content.\n *\n * Returns true if the string has both Bengali characters and non-Bengali\n * alphanumeric characters.\n *\n * @param text - String to check\n * @returns true if content is mixed, false otherwise\n *\n * @example\n * Mixed content:\n * ```typescript\n * isMixedContent('Hello বাংলা'); // true\n * isMixedContent('বাংলা 123'); // true\n * isMixedContent('Price: ১০০ taka'); // true\n * ```\n *\n * @example\n * Pure content:\n * ```typescript\n * isMixedContent('বাংলা'); // false (pure Bengali)\n * isMixedContent('Hello'); // false (pure English)\n * isMixedContent('১২৩'); // false (Bengali digits only)\n * ```\n */\nexport function isMixedContent(text: string): boolean {\n const hasBengali = /[\\u0980-\\u09FF]/.test(text);\n const hasNonBengali = /[a-zA-Z0-9]/.test(text);\n return hasBengali && hasNonBengali;\n}\n\n/**\n * Extracts only Bengali characters from a string.\n *\n * Removes all non-Bengali characters, keeping only characters\n * from the Bengali Unicode range (U+0980 to U+09FF).\n *\n * @param text - String to extract from\n * @param preserveWhitespace - Whether to preserve whitespace (default: false)\n * @returns String containing only Bengali characters\n *\n * @example\n * Extract from mixed content:\n * ```typescript\n * extractBengaliChars('Hello বাংলা World'); // 'বাংলা'\n * extractBengaliChars('Price: ১০০ taka'); // '১০০'\n * extractBengaliChars('123 বাংলা 456'); // 'বাংলা'\n * ```\n *\n * @example\n * With whitespace preservation:\n * ```typescript\n * extractBengaliChars('Hello বাংলা ভাষা', true); // 'বাংলা ভাষা'\n * extractBengaliChars('Test ১২৩ টাকা', true); // '১২৩ টাকা'\n * ```\n *\n * @example\n * Pure Bengali text:\n * ```typescript\n * extractBengaliChars('বাংলা'); // 'বাংলা' (unchanged)\n * ```\n */\nexport function extractBengaliChars(text: string, preserveWhitespace: boolean = false): string {\n if (preserveWhitespace) {\n return text.replace(/[^\\u0980-\\u09FF\\s]/g, '').trim();\n }\n return text.replace(/[^\\u0980-\\u09FF]/g, '');\n}\n\n/**\n * Removes all Bengali characters from a string.\n *\n * Keeps only non-Bengali characters, removing everything from\n * the Bengali Unicode range.\n *\n * @param text - String to process\n * @returns String with Bengali characters removed\n *\n * @example\n * ```typescript\n * removeBengaliChars('Hello বাংলা World'); // 'Hello World'\n * removeBengaliChars('Price: ১০০ taka'); // 'Price: taka'\n * removeBengaliChars('১২৩ টাকা'); // ' '\n * ```\n */\nexport function removeBengaliChars(text: string): string {\n return text.replace(/[\\u0980-\\u09FF]/g, '');\n}\n\n/**\n * Gets the percentage of Bengali characters in a string.\n *\n * Calculates what percentage of the total non-whitespace characters\n * are Bengali characters.\n *\n * @param text - String to analyze\n * @returns Percentage (0-100) of Bengali characters\n *\n * @example\n * ```typescript\n * getBengaliPercentage('বাংলা'); // 100\n * getBengaliPercentage('Hello'); // 0\n * getBengaliPercentage('Hello বাংলা'); // 50 (5 of 10 chars)\n * getBengaliPercentage(''); // 0\n * ```\n */\nexport function getBengaliPercentage(text: string): number {\n const withoutWhitespace = text.replace(/\\s/g, '');\n if (withoutWhitespace.length === 0) {\n return 0;\n }\n\n const bengaliCount = countBengaliCharacters(text);\n return Math.round((bengaliCount / withoutWhitespace.length) * 100);\n}\n\n/**\n * Checks if text is primarily Bengali (more than 50% Bengali characters).\n *\n * @param text - String to check\n * @returns true if more than 50% is Bengali, false otherwise\n *\n * @example\n * ```typescript\n * isPrimarilyBengali('বাংলা'); // true (100%)\n * isPrimarilyBengali('বাংলা ভাষা hello'); // true (>50%)\n * isPrimarilyBengali('Hello বাংলা world test'); // false (<50%)\n * isPrimarilyBengali('Hello'); // false (0%)\n * ```\n */\nexport function isPrimarilyBengali(text: string): boolean {\n return getBengaliPercentage(text) > 50;\n}\n\n/**\n * Sanitizes Bengali text by removing non-Bengali characters.\n *\n * If fallback is provided, returns fallback when result would be empty.\n *\n * @param text - Text to sanitize\n * @param preserveWhitespace - Preserve whitespace (default: true)\n * @param fallback - Fallback value if result is empty (default: empty string)\n * @returns Sanitized Bengali text or fallback\n *\n * @example\n * ```typescript\n * sanitizeBengaliText('Hello বাংলা World'); // 'বাংলা'\n * sanitizeBengaliText('Test 123 টাকা'); // 'টাকা'\n * sanitizeBengaliText('বাংলা ভাষা'); // 'বাংলা ভাষা'\n * ```\n *\n * @example\n * With fallback:\n * ```typescript\n * sanitizeBengaliText('Hello World', true, 'N/A'); // 'N/A'\n * sanitizeBengaliText('123', false, 'নেই'); // 'নেই'\n * ```\n */\nexport function sanitizeBengaliText(\n text: string,\n preserveWhitespace: boolean = true,\n fallback: string = ''\n): string {\n const result = extractBengaliChars(text, preserveWhitespace);\n return result.length > 0 ? result : fallback;\n}\n\n/**\n * Checks if all digits in a string are Bengali digits.\n *\n * Returns true if string contains digits and all digits are Bengali.\n * Returns false if contains English digits or no digits at all.\n *\n * @param text - String to check\n * @returns true if all digits are Bengali, false otherwise\n *\n * @example\n * All Bengali digits:\n * ```typescript\n * hasOnlyBengaliDigits('১২৩'); // true\n * hasOnlyBengaliDigits('মূল্য: ১০০'); // true\n * hasOnlyBengaliDigits('বাংলা'); // false (no digits)\n * ```\n *\n * @example\n * Mixed or English digits:\n * ```typescript\n * hasOnlyBengaliDigits('123'); // false (English digits)\n * hasOnlyBengaliDigits('১২3'); // false (mixed)\n * hasOnlyBengaliDigits('Price: 100'); // false\n * ```\n */\nexport function hasOnlyBengaliDigits(text: string): boolean {\n const hasDigits = /\\d|[০-৯]/.test(text);\n if (!hasDigits) {\n return false;\n }\n\n const hasEnglishDigits = /\\d/.test(text);\n return !hasEnglishDigits && isBanglaDigit(text);\n}\n\n/**\n * Normalizes whitespace in Bengali text.\n *\n * Replaces multiple consecutive whitespaces with a single space\n * and trims leading/trailing whitespace.\n *\n * @param text - Text to normalize\n * @returns Text with normalized whitespace\n *\n * @example\n * ```typescript\n * normalizeWhitespace('বাংলা ভাষা'); // 'বাংলা ভাষা'\n * normalizeWhitespace(' শুভ সকাল '); // 'শুভ সকাল'\n * normalizeWhitespace('হ্যালো\\n\\nওয়ার্ল্ড'); // 'হ্যালো ওয়ার্ল্ড'\n * ```\n */\nexport function normalizeWhitespace(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\n}\n\n/**\n * Splits text into Bengali and non-Bengali parts.\n *\n * Returns an object with separate strings for Bengali and non-Bengali content.\n *\n * @param text - Text to split\n * @returns Object with bengali and nonBengali strings\n *\n * @example\n * ```typescript\n * splitBengaliContent('Hello বাংলা World');\n * // { bengali: 'বাংলা', nonBengali: 'Hello World' }\n *\n * splitBengaliContent('Price: ১০০ taka');\n * // { bengali: '১০০', nonBengali: 'Price: taka' }\n * ```\n */\nexport function splitBengaliContent(text: string): { bengali: string; nonBengali: string } {\n return {\n bengali: extractBengaliChars(text, true).trim(),\n nonBengali: removeBengaliChars(text).trim(),\n };\n}\n\n/**\n * Checks if a string contains any Bengali consonants.\n *\n * Bengali consonants: ক খ গ ঘ ঙ চ ছ জ ঝ ঞ ট ঠ ড ঢ ণ ত থ দ ধ ন প ফ ব ভ ম য র ল শ ষ স হ ড় ঢ় য় ৎ\n *\n * @param text - Text to check\n * @returns true if contains Bengali consonants, false otherwise\n *\n * @example\n * ```typescript\n * hasBengaliConsonants('বাংলা'); // true\n * hasBengaliConsonants('আই'); // false (vowels only)\n * hasBengaliConsonants('১২৩'); // false (digits only)\n * hasBengaliConsonants('Hello'); // false\n * ```\n */\nexport function hasBengaliConsonants(text: string): boolean {\n // Bengali consonants range: U+0995 to U+09B9, plus additional consonants\n const consonantRegex = /[ক-হড়ঢ়য়ৎ]/;\n return consonantRegex.test(text);\n}\n\n/**\n * Checks if a string contains any Bengali vowels (independent or diacritics).\n *\n * Bengali vowels: অ আ ই ঈ উ ঊ ঋ ৠ ঌ ৡ এ ঐ ও ঔ\n * Bengali vowel diacritics: া ি ী ু ূ ৃ ৄ ে ৈ ো ৌ\n *\n * @param text - Text to check\n * @returns true if contains Bengali vowels, false otherwise\n *\n * @example\n * ```typescript\n * hasBengaliVowels('আম'); // true\n * hasBengaliVowels('বাংলা'); // true (has vowel diacritics)\n * hasBengaliVowels('ক'); // false (consonant only)\n * hasBengaliVowels('123'); // false\n * ```\n */\nexport function hasBengaliVowels(text: string): boolean {\n // Independent vowels: U+0985 to U+0994\n // Vowel diacritics: U+09BE to U+09CC\n const vowelRegex = /[অ-ঔা-ৌ]/;\n return vowelRegex.test(text);\n}\n"],"mappings":"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","names":["index_exports","__export","BANGLA_DIGITS","BANGLA_MONTHS","BANGLA_SEASONS","BANGLA_WEEKDAYS","ENGLISH_DIGITS","addCountryCode","addDays","addDaysToBengaliDate","addMinutesToTime","addTax","applyDiscount","batchFormatCurrency","batchFormatDates","batchFromBanglaNumber","batchParseDates","batchToBanglaMonth","batchToBanglaNumber","batchToBengali","batchToOrdinal","calculatePercentage","canParseBengaliDate","compareBengaliDates","compareCurrency","compareDates","compareMonths","compareOrdinals","compareTimes","convertToWordsAndDigits","countBengaliCharacters","countBengaliDigits","createOrdinalList","divideCurrency","extractBengaliChars","formatAndConvert","formatBengaliDate","formatCurrency","formatDate","formatNumber","formatOrdinal","formatPhone","formatTime","formatToday","formatWithUnits","fromBanglaMonth","fromBanglaNumber","fromBanglaWeekday","fromBengali","getAbsoluteAmount","getAllBanglaWeekdays","getAllMonths","getAllOperatorCodes","getAllOperators","getAllSeasons","getBengaliDate","getBengaliDateDifference","getBengaliMonthDays","getBengaliMonthLengths","getBengaliPercentage","getCurrentBengaliDate","getCurrentSeason","getCurrentTimeBangla","getDaysBetween","getDaysDifference","getFirstDayOfBengaliMonth","getLastDayOfBengaliMonth","getMonthFromIndex","getMonthIndex","getMonthMapping","getMonthName","getMonthRange","getNextBanglaWeekday","getNextMonth","getNextOrdinal","getNextSeason","getNextWeekday","getOperator","getOrdinalSequence","getOrdinalType","getPreviousBanglaWeekday","getPreviousMonth","getPreviousOrdinal","getPreviousSeason","getPreviousWeekday","getRanking","getSeason","getSeasonByIndex","getSeasonFromMonth","getSeasonIndex","getSeasonInfo","getSeasonMonths","getSpecialOrdinals","getTimePeriod","getWeekdayName","hasBengaliConsonants","hasBengaliDigits","hasBengaliMonth","hasBengaliVowels","hasCountryCode","hasOnlyBengaliDigits","hasSeconds","hasSpecialOrdinal","hasTakaSymbol","hasTakaWord","isBanglaCurrency","isBanglaDigit","isBanglaOrdinal","isBanglaText","isBanglaWeekend","isBengaliDateInRange","isBengaliLeapYear","isCurrencyInRange","isDateInRange","isFuture","isInSpecialOrdinalRange","isMixedContent","isMonthInRange","isMonthInSeason","isNegativeAmount","isNumberInRange","isPast","isPositiveAmount","isPrimarilyBengali","isSameDay","isSameNumber","isSameSeason","isTimeInRange","isToday","isValidBanglaMonth","isValidBanglaNumber","isValidBanglaWeekday","isValidBengaliDate","isValidBengaliDateString","isValidBengaliDay","isValidBengaliMonth","isValidBengaliYear","isValidCurrency","isValidDate","isValidDateForSeason","isValidDateForWeekday","isValidMonth","isValidMonthNumber","isValidNumber","isValidNumberForOrdinal","isValidNumberForWords","isValidOperatorCode","isValidOrdinal","isValidPhoneFormat","isValidSeasonName","isValidTimeInput","isValidTimeString","isValidWeekdayNumber","isWeekend","isZeroAmount","multiplyCurrency","negateAmount","normalizePhoneNumber","normalizeWhitespace","parseAndConvertToBangla","parseAndConvertToMonth","parseAndConvertToOrdinal","parseAndFormat","parseAndFormatCurrency","parseCurrency","parseDate","parsePhoneNumber","parseTime","parseWeekdayInput","relativeDay","relativeTime","removeBengaliChars","removeCountryCode","roundCurrency","safeFormatCurrency","safeFormatDate","safeFormatPhone","safeFormatTime","safeFromBanglaMonth","safeFromBanglaNumber","safeFromBanglaWeekday","safeFromBengali","safeGetSeason","safeGetSeasonFromMonth","safeParseCurrency","safeParseDate","safeRelativeTime","safeToBanglaMonth","safeToBanglaNumber","safeToBanglaWeekday","safeToBengali","safeToOrdinal","sanitizeBanglaMonth","sanitizeBengaliDate","sanitizeBengaliText","sanitizeCurrencyInput","sanitizeDate","sanitizeMonthNumber","sanitizeNumberInput","sanitizeOrdinalInput","sanitizePhoneNumber","sanitizeTimeInput","sanitizeWeekdayInput","secondsToTime","splitAmount","splitBengaliContent","subtractCurrency","sumCurrency","timeDifferenceMinutes","timeToSeconds","toBanglaMonth","toBanglaNumber","toBanglaWeekday","toBengali","toOrdinal","toWords","truncateDecimals","validateBangla","validatePhone","__toCommonJS","BANGLA_DIGITS","ENGLISH_DIGITS","BANGLA_MONTHS","BANGLA_WEEKDAYS","BANGLA_SEASONS","toBanglaNumber","input","value","absInput","log10","hasDecimal","hasDigit","result","i","char","index","ENGLISH_DIGITS","BANGLA_DIGITS","__name","fromBanglaNumber","input","value","hasDecimal","hasDigit","result","i","char","index","BANGLA_DIGITS","ENGLISH_DIGITS","parsed","__name","toWords","number","convertBelowHundred","convertBelowThousand","convertBelowLakh","convertBelowCrore","convertBelowArab","convertBelowKharab","__name","n","ones","tens","ten","one","hundred","remainder","result","thousand","lakh","crore","arab","formatWithUnits","number","options","precision","useBanglaDigits","absNumber","sign","value","unit","formatted","toBanglaNumber","rounded","__name","formatNumber","number","options","useBanglaDigits","separator","numStr","integerPart","decimalPart","formattedInteger","toBanglaNumber","formatted","formatIntegerPart","formattedDecimal","__name","isNegative","absolutePart","rightmost3","remaining","groups","i","start","isValidBanglaNumber","input","value","hasDecimal","hasDigit","char","BANGLA_DIGITS","__name","isValidNumber","absInput","log10","ENGLISH_DIGITS","isValidNumberForWords","isValidNumberForOrdinal","sanitizeNumberInput","result","batchToBanglaNumber","inputs","success","errors","input","output","toBanglaNumber","error","__name","batchFromBanglaNumber","fromBanglaNumber","safeToBanglaNumber","fallback","safeFromBanglaNumber","parseAndConvertToBangla","sanitized","sanitizeNumberInput","formatAndConvert","useBanglaDigits","separator","formatNumber","convertToWordsAndDigits","toWords","isNumberInRange","value","min","max","truncateDecimals","decimals","multiplier","formatCurrency","amount","options","includeSymbol","includeWord","numAmount","banglaAmount","toBanglaNumber","parts","__name","parseCurrency","currencyString","cleaned","fromBanglaNumber","__name","isValidCurrency","value","__name","isBanglaCurrency","trimmed","isPositiveAmount","isNegativeAmount","isZeroAmount","sanitizeCurrencyInput","parsed","isCurrencyInRange","min","max","hasTakaSymbol","hasTakaWord","safeFormatCurrency","amount","options","fallback","numAmount","isValidCurrency","formatCurrency","__name","safeParseCurrency","currencyString","result","parseCurrency","batchFormatCurrency","amounts","roundCurrency","decimals","multiplier","sumCurrency","sum","acc","subtractCurrency","amount1","amount2","multiplyCurrency","factor","divideCurrency","divisor","calculatePercentage","percentage","applyDiscount","discountPercent","discount","addTax","taxPercent","tax","splitAmount","parts","perPart","sumSoFar","lastPart","compareCurrency","rounded1","rounded2","getAbsoluteAmount","negateAmount","parseAndFormatCurrency","value","sanitized","sanitizeCurrencyInput","parsed","toBanglaMonth","monthNumber","BANGLA_MONTHS","__name","fromBanglaMonth","monthName","index","BANGLA_MONTHS","__name","getMonthName","date","jsMonth","toBanglaMonth","__name","isValidDate","date","__name","isValidBengaliDateString","dateString","cleaned","monthNamePattern","separatorPattern","hasBengaliDigits","text","hasBengaliMonth","sanitizeDate","isValidMonthNumber","monthNumber","__name","isValidBanglaMonth","monthName","trimmed","BANGLA_MONTHS","sanitizeMonthNumber","value","parsed","rounded","sanitizeBanglaMonth","safeToBanglaMonth","monthNumber","fallback","isValidMonthNumber","toBanglaMonth","__name","safeFromBanglaMonth","monthName","isValidBanglaMonth","fromBanglaMonth","getAllMonths","BANGLA_MONTHS","getNextMonth","currentMonth","monthNum","nextNum","getPreviousMonth","prevNum","getMonthRange","start","end","isNumber","startNum","endNum","result","current","isMonthInRange","month","compareMonths","month1","month2","num1","num2","getMonthIndex","getMonthFromIndex","index","parseAndConvertToMonth","value","sanitized","sanitizeMonthNumber","batchToBanglaMonth","monthNumbers","num","getMonthMapping","mapping","i","toBanglaWeekday","weekdayNumber","BANGLA_WEEKDAYS","__name","fromBanglaWeekday","weekdayName","index","BANGLA_WEEKDAYS","__name","getWeekdayName","date","weekdayNumber","toBanglaWeekday","__name","isValidWeekdayNumber","value","__name","isValidBanglaWeekday","trimmed","BANGLA_WEEKDAYS","isValidDateForWeekday","sanitizeWeekdayInput","input","isWeekend","weekdayNumber","__name","isBanglaWeekend","weekdayName","fromBanglaWeekday","getNextWeekday","getPreviousWeekday","getNextBanglaWeekday","nextDay","toBanglaWeekday","getPreviousBanglaWeekday","prevDay","parseWeekdayInput","input","sanitized","sanitizeWeekdayInput","safeToBanglaWeekday","fallback","safeFromBanglaWeekday","getAllBanglaWeekdays","getDaysBetween","from","to","formatDate","date","options","includeWeekday","includeYear","format","parts","weekday","getWeekdayName","day","toBanglaNumber","month","getMonthName","year","__name","parseDate","dateString","cleaned","monthNameMatch","dayStr","monthName","yearStr","day","fromBanglaNumber","month","fromBanglaMonth","year","separatorMatch","monthStr","__name","safeFormatDate","date","options","fallback","isValidDate","formatDate","__name","safeParseDate","dateString","parseDate","formatToday","batchFormatDates","dates","batchParseDates","dateStrings","str","canParseBengaliDate","isValidBengaliDateString","compareDates","date1","date2","time1","time2","isToday","today","isPast","isFuture","getDaysDifference","diffTime","addDays","days","result","isDateInRange","start","end","getSeasonFromMonth","monthNumber","BANGLA_SEASONS","__name","fromBengali","b","year","month","day","monthLengths","getBengaliMonthLengths","gYear","boishakh1","daysOffset","m","__name","getBengaliDate","date","options","includeYear","includeWeekday","bengali","toBengali","toBanglaNumber","toBanglaMonth","__name","isValidBengaliYear","year","__name","isValidBengaliMonth","month","isValidBengaliDay","day","monthLengths","getBengaliMonthLengths","isValidBengaliDate","date","sanitizeBengaliDate","safeToBengali","date","fallback","toBengali","__name","safeFromBengali","bengaliDate","isValidBengaliDate","fromBengali","getBengaliMonthDays","month","year","isValidBengaliMonth","isValidBengaliYear","getBengaliMonthLengths","addDaysToBengaliDate","days","gregorianDate","newDate","getBengaliDateDifference","date1","date2","gregorian1","gregorian2","compareBengaliDates","isBengaliDateInRange","start","end","getFirstDayOfBengaliMonth","getLastDayOfBengaliMonth","isBengaliLeapYear","gregorianYear","formatBengaliDate","options","getBengaliDate","getCurrentBengaliDate","batchToBengali","dates","bengaliYear","toBengali","date","d","gYear","gMonth","gDay","isBeforeBoishakh","bengaliYear","boishakhYear","boishakh1","daysSinceBoishakh","monthLengths","getBengaliMonthLengths","remaining","monthIndex","__name","getSeason","date","bengaliDate","toBengali","getSeasonFromMonth","__name","isValidMonth","value","__name","isValidSeasonName","trimmed","BANGLA_SEASONS","isValidDateForSeason","getAllSeasons","__name","getSeasonMonths","seasonName","months","getSeasonIndex","BANGLA_SEASONS","getSeasonByIndex","index","isMonthInSeason","monthNumber","getNextSeason","currentSeason","nextIndex","getPreviousSeason","prevIndex","safeGetSeason","date","fallback","getSeason","safeGetSeasonFromMonth","getSeasonFromMonth","getCurrentSeason","isSameSeason","date1","date2","season1","season2","getSeasonInfo","monthNameMap","monthNames","m","toOrdinal","number","specialOrdinals","toBanglaNumber","__name","isValidOrdinal","value","__name","isBanglaOrdinal","trimmed","hasSpecialOrdinal","sanitizeOrdinalInput","parsed","rounded","isInSpecialOrdinalRange","safeToOrdinal","number","fallback","isValidOrdinal","toOrdinal","__name","batchToOrdinal","numbers","num","parseAndConvertToOrdinal","value","sanitized","sanitizeOrdinalInput","getSpecialOrdinals","getOrdinalSequence","start","end","sequence","i","formatOrdinal","options","separator","showNumber","ordinal","getOrdinalType","getRanking","position","suffix","compareOrdinals","num1","num2","getNextOrdinal","current","getPreviousOrdinal","createOrdinalList","items","startFrom","item","index","formatTime","date","options","includeSeconds","use12Hour","hours","minutes","seconds","timeParts","displayHours","period","banglaHours","toBanglaNumber","banglaMinutes","parts","banglaSeconds","timeString","__name","relativeTime","date","baseDate","diffMs","diffSeconds","diffMinutes","diffHours","absDiffHours","baseDay","targetDay","diffDays","toBanglaNumber","weeks","months","years","__name","relativeDay","today","targetDate","isValidTimeString","value","trimmed","timePattern","match","hours","minutes","seconds","__name","isValidTimeInput","value","isValidDate","isValidTimeString","__name","hasSeconds","timeString","sanitizeTimeInput","input","parseTime","timeString","timeParts","sanitizeTimeInput","hours","minutes","seconds","__name","timeToSeconds","secondsToTime","totalSeconds","compareTimes","time1","time2","seconds1","seconds2","isTimeInRange","time","startTime","endTime","timeSeconds","startSeconds","endSeconds","addMinutesToTime","newSeconds","timeDifferenceMinutes","safeFormatTime","date","options","fallback","formatTime","safeRelativeTime","baseDate","relativeTime","getTimePeriod","h","getCurrentTimeBangla","isSameDay","date1","date2","formatPhone","phoneNumber","options","includeCountryCode","useBanglaDigits","format","digits","number","formatted","toBanglaNumber","__name","validatePhone","phoneNumber","digits","number","operatorCode","__name","isValidOperatorCode","hasCountryCode","trimmed","sanitizePhoneNumber","sanitized","hasPlus","isValidPhoneFormat","getOperator","phoneNumber","validatePhone","digits","number","operatorCode","operator","__name","parsePhoneNumber","original","countryCode","subscriberNumber","normalizePhoneNumber","addCountryCode","format","withoutLeadingZero","removeCountryCode","safeFormatPhone","options","fallback","formatPhone","isSameNumber","phone1","phone2","normalized1","normalized2","getAllOperatorCodes","getAllOperators","parseAndFormat","sanitized","sanitizePhoneNumber","validateBangla","text","__name","isBanglaDigit","char","__name","isBanglaText","text","__name","countBengaliCharacters","text","bengaliChars","__name","countBengaliDigits","bengaliDigits","isMixedContent","hasBengali","hasNonBengali","extractBengaliChars","preserveWhitespace","removeBengaliChars","getBengaliPercentage","withoutWhitespace","bengaliCount","isPrimarilyBengali","sanitizeBengaliText","fallback","result","hasOnlyBengaliDigits","isBanglaDigit","normalizeWhitespace","splitBengaliContent","hasBengaliConsonants","hasBengaliVowels"]}