@indodev/toolkit 0.4.2 → 0.5.0
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.
- package/dist/index.cjs +3 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -15
- package/dist/index.js.map +1 -1
- package/dist/{parse-BDfy3aQw.d.cts → parse-BmmsNlJt.d.cts} +20 -4
- package/dist/{parse-BDfy3aQw.d.ts → parse-BmmsNlJt.d.ts} +20 -4
- package/dist/phone/index.cjs +8 -18
- package/dist/phone/index.cjs.map +1 -1
- package/dist/phone/index.d.cts +6 -4
- package/dist/phone/index.d.ts +6 -4
- package/dist/phone/index.js +8 -18
- package/dist/phone/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/nik/constants.ts","../src/nik/utils/date.ts","../src/nik/validate.ts","../src/nik/parse.ts","../src/nik/format.ts","../src/nik/utils.ts","../src/phone/constants.ts","../src/phone/validate.ts","../src/phone/utils.ts","../src/phone/format.ts","../src/phone/links.ts","../src/phone/parse.ts","../src/npwp/validate.ts","../src/npwp/format.ts","../src/plate/regions.ts","../src/plate/utils.ts","../src/vin/constants.ts","../src/vin/validate.ts","../src/email-validator/constants.ts","../src/email-validator/email-validator.ts","../src/currency/format.ts","../src/currency/parse.ts","../src/currency/words.ts","../src/currency/utils.ts","../src/text/constants.ts","../src/text/capitalization.ts","../src/text/slug.ts","../src/text/sanitize.ts","../src/text/abbreviation.ts","../src/text/filter.ts","../src/text/normalization.ts","../src/text/extract.ts","../src/text/compare.ts","../src/datetime/types.ts","../src/datetime/constants.ts","../src/datetime/calc.ts","../src/datetime/parse.ts","../src/datetime/format.ts","../src/datetime/relative.ts","../src/datetime/timezone.ts"],"names":["NIK_PATTERN","capitalize","escapeRegex","getAge","normalizeDate"],"mappings":"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;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA;AAAA,EAGA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA;AAAA,EAGA,IAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA;AAAA,EAGA,IAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,QAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA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","file":"index.js","sourcesContent":["/**\n * Indonesian province codes and names\n * Based on Dukcapil Kemendagri data\n */\nexport const PROVINCES: Record<string, string> = {\n '11': 'Aceh',\n '12': 'Sumatera Utara',\n '13': 'Sumatera Barat',\n '14': 'Riau',\n '15': 'Jambi',\n '16': 'Sumatera Selatan',\n '17': 'Bengkulu',\n '18': 'Lampung',\n '19': 'Kepulauan Bangka Belitung',\n '21': 'Kepulauan Riau',\n '31': 'DKI Jakarta',\n '32': 'Jawa Barat',\n '33': 'Jawa Tengah',\n '34': 'DI Yogyakarta',\n '35': 'Jawa Timur',\n '36': 'Banten',\n '51': 'Bali',\n '52': 'Nusa Tenggara Barat',\n '53': 'Nusa Tenggara Timur',\n '61': 'Kalimantan Barat',\n '62': 'Kalimantan Tengah',\n '63': 'Kalimantan Selatan',\n '64': 'Kalimantan Timur',\n '65': 'Kalimantan Utara',\n '71': 'Sulawesi Utara',\n '72': 'Sulawesi Tengah',\n '73': 'Sulawesi Selatan',\n '74': 'Sulawesi Tenggara',\n '75': 'Gorontalo',\n '76': 'Sulawesi Barat',\n '81': 'Maluku',\n '82': 'Maluku Utara',\n '91': 'Papua',\n '92': 'Papua Barat',\n '93': 'Papua Selatan',\n '94': 'Papua Tengah',\n '95': 'Papua Pegunungan',\n '96': 'Papua Barat Daya',\n};\n\n/**\n * Regency codes for each province (simplified - only major ones)\n * In a real implementation, you'd have complete data\n */\nexport const REGENCIES: Record<string, Record<string, string>> = {\n '32': {\n '01': 'Kab. Bogor',\n '02': 'Kab. Sukabumi',\n '03': 'Kab. Cianjur',\n '71': 'Kota Bandung',\n '72': 'Kota Bekasi',\n '73': 'Kota Depok',\n },\n '31': { \n '01': 'Kota Jakarta Selatan',\n '02': 'Kota Jakarta Timur',\n '03': 'Kota Jakarta Pusat',\n '04': 'Kota Jakarta Barat',\n '05': 'Kota Jakarta Utara',\n },\n};","/**\n * Shared date parsing and validation utilities for NIK module.\n *\n * @module nik/utils/date\n * @packageDocumentation\n */\n\n/**\n * Result of parsing date components from a NIK string.\n *\n * @public\n */\nexport interface ParsedNIKDate {\n /** 2-digit year code (00-99) from NIK positions 7-8 */\n year: number;\n /** Full 4-digit year (1900-1999 or 2000-2099) */\n fullYear: number;\n /** Month (1-12) from NIK positions 9-10 */\n month: number;\n /** Actual day (1-31), decoded from encoded day */\n day: number;\n /** Gender derived from day encoding */\n gender: 'male' | 'female';\n /** Original encoded day (1-31 for male, 41-71 for female) */\n dayEncoded: number;\n}\n\n/**\n * Parses date components from a NIK string.\n *\n * Extracts year, month, and encoded day from positions 7-12 of the NIK.\n * For females, the day is encoded as (actual day + 40).\n *\n * @param nik - 16-digit NIK string\n * @returns ParsedNIKDate or null if NIK format is invalid\n *\n * @example\n * ```typescript\n * const result = parseNIKDate('3201018901310123');\n * // { year: 89, fullYear: 1989, month: 1, day: 31, gender: 'male', dayEncoded: 31 }\n * ```\n *\n * @public\n */\nexport function parseNIKDate(nik: string): ParsedNIKDate | null {\n if (nik.length !== 16) {\n return null;\n }\n\n const yearStr = nik.substring(6, 8);\n const monthStr = nik.substring(8, 10);\n const dayEncodedStr = nik.substring(10, 12);\n\n const year = parseInt(yearStr, 10);\n if (isNaN(year)) return null;\n\n const fullYear = year > 30 ? 1900 + year : 2000 + year;\n\n const month = parseInt(monthStr, 10);\n if (isNaN(month)) return null;\n\n const dayEncoded = parseInt(dayEncodedStr, 10);\n if (isNaN(dayEncoded)) return null;\n\n const gender: 'male' | 'female' = dayEncoded > 40 ? 'female' : 'male';\n const day = dayEncoded > 40 ? dayEncoded - 40 : dayEncoded;\n\n return { year, fullYear, month, day, gender, dayEncoded };\n}\n\n/**\n * Validates if year/month/day form a valid calendar date.\n *\n * Uses JavaScript's Date object to check if the date actually exists\n * (handles leap years, invalid month/day combinations).\n *\n * @param year - Full 4-digit year\n * @param month - Month (1-12)\n * @param day - Day (1-31)\n * @returns true if valid calendar date\n *\n * @example\n * ```typescript\n * validateNIKDateComponents(2024, 2, 29); // true (leap year)\n * validateNIKDateComponents(2023, 2, 29); // false\n * validateNIKDateComponents(2024, 13, 1); // false\n * ```\n *\n * @public\n */\nexport function validateNIKDateComponents(\n year: number,\n month: number,\n day: number\n): boolean {\n if (month < 1 || month > 12) return false;\n if (day < 1 || day > 31) return false;\n\n const testDate = new Date(year, month - 1, day);\n return (\n testDate.getFullYear() === year &&\n testDate.getMonth() === month - 1 &&\n testDate.getDate() === day\n );\n}\n","import { PROVINCES } from './constants';\nimport { parseNIKDate, validateNIKDateComponents } from './utils/date';\n\nconst NIK_PATTERN = /^\\d{16}$/;\n\n/**\n * Validates a NIK (Nomor Induk Kependudukan) format.\n *\n * A valid NIK must:\n * - Be exactly 16 digits\n * - Have a valid province code (positions 1-2)\n * - Have a valid date (positions 7-12)\n * - Not be in the future\n * - Not be before 1900\n *\n * For female NIKs, the day is encoded as (actual day + 40).\n * For example, a female born on the 15th would have day = 55.\n *\n * @param nik - The 16-digit NIK string to validate\n * @returns `true` if the NIK is valid, `false` otherwise\n *\n * @example\n * ```typescript\n * validateNIK('3201234567890123'); // true - valid NIK\n * validateNIK('1234'); // false - wrong length\n * validateNIK('9912345678901234'); // false - invalid province\n * ```\n *\n * @public\n */\nexport function validateNIK(nik: string): boolean {\n if (!NIK_PATTERN.test(nik)) {\n return false;\n }\n\n const provinceCode = nik.substring(0, 2);\n if (!PROVINCES[provinceCode]) {\n return false;\n }\n\n const parsed = parseNIKDate(nik);\n if (!parsed) {\n return false;\n }\n\n const { fullYear, month, day } = parsed;\n\n if (!validateNIKDateComponents(fullYear, month, day)) {\n return false;\n }\n\n const now = new Date();\n if (new Date(fullYear, month - 1, day) > now || fullYear < 1900) {\n return false;\n }\n\n return true;\n}\n","import { PROVINCES, REGENCIES } from './constants';\nimport { NIKInfo } from './types';\nimport { parseNIKDate, validateNIKDateComponents } from './utils/date';\n\nconst NIK_PATTERN = /^\\d{16}$/;\n\n/**\n * Parses a NIK and extracts all embedded information.\n *\n * Extracts province, regency, district codes, birth date, gender,\n * and serial number from a 16-digit NIK string.\n *\n * @param nik - The 16-digit NIK string to parse\n * @returns Parsed NIK information, or `null` if the NIK format is invalid\n *\n * @example\n * Parse a valid male NIK:\n * ```typescript\n * const info = parseNIK('3201018901310123');\n * console.log(info);\n * // {\n * // province: { code: '32', name: 'Jawa Barat' },\n * // regency: { code: '01', name: 'Kab. Bogor' },\n * // district: { code: '01', name: null },\n * // birthDate: Date(1989, 0, 31), // Jan 31, 1989\n * // gender: 'male',\n * // serialNumber: '0123',\n * // isValid: true\n * // }\n * ```\n *\n * @example\n * Parse a female NIK (day + 40):\n * ```typescript\n * const info = parseNIK('3201019508550123');\n * console.log(info.gender); // 'female'\n * console.log(info.birthDate); // Date(1995, 7, 15) - Aug 15, 1995\n * ```\n *\n * @example\n * Invalid NIK returns null:\n * ```typescript\n * const info = parseNIK('invalid');\n * console.log(info); // null\n * ```\n *\n * @public\n */\nexport function parseNIK(nik: string): NIKInfo | null {\n if (!NIK_PATTERN.test(nik)) {\n return null;\n }\n\n const provinceCode = nik.substring(0, 2);\n const regencyCode = nik.substring(2, 4);\n const districtCode = nik.substring(4, 6);\n const serialNumber = nik.substring(12, 16);\n\n const province = PROVINCES[provinceCode];\n if (!province) {\n return null;\n }\n\n const regencies = REGENCIES[provinceCode] || {};\n const regency = regencies[regencyCode] || 'Unknown';\n\n const parsed = parseNIKDate(nik);\n if (!parsed) {\n return null;\n }\n\n const { fullYear, month, day, gender } = parsed;\n\n if (!validateNIKDateComponents(fullYear, month, day)) {\n return null;\n }\n\n const birthDate = new Date(fullYear, month - 1, day);\n\n return {\n province: {\n code: provinceCode,\n name: province,\n },\n regency: {\n code: regencyCode,\n name: regency,\n },\n district: {\n code: districtCode,\n name: null,\n },\n birthDate,\n gender,\n serialNumber,\n isValid: true,\n };\n}\n","import { MaskOptions } from './types';\n\n/**\n * Formats a NIK with separators for better readability.\n *\n * Groups the NIK into logical segments: province, regency, district,\n * year, month, day, and serial number.\n *\n * @param nik - The 16-digit NIK string to format\n * @param separator - Character to use as separator\n * @returns Formatted NIK string, or original string if invalid format\n *\n * @example\n * Default separator (dash):\n * ```typescript\n * formatNIK('3201234567890123');\n * // '32-01-23-45-67-89-0123'\n * ```\n *\n * @example\n * Custom separator:\n * ```typescript\n * formatNIK('3201234567890123', ' ');\n * // '32 01 23 45 67 89 0123'\n * ```\n *\n * @example\n * Invalid NIK returns as-is:\n * ```typescript\n * formatNIK('1234');\n * // '1234'\n * ```\n *\n * @public\n */\nexport function formatNIK(nik: string, separator: string = '-'): string {\n if (!/^\\d{16}$/.test(nik)) {\n return nik;\n }\n\n // Format: PP-KK-DD-YY-MM-DD-XXXX\n // PP = Province (2 digits)\n // KK = Regency (2 digits)\n // DD = District (2 digits)\n // YY = Year (2 digits)\n // MM = Month (2 digits)\n // DD = Day (2 digits, +40 for female)\n // XXXX = Serial number (4 digits)\n return [\n nik.substring(0, 2), // Province\n nik.substring(2, 4), // Regency\n nik.substring(4, 6), // District\n nik.substring(6, 8), // Year\n nik.substring(8, 10), // Month\n nik.substring(10, 12), // Day\n nik.substring(12, 16), // Serial\n ].join(separator);\n}\n\n/**\n * Masks a NIK to protect privacy while keeping partial visibility.\n *\n * By default, shows the first 4 and last 4 digits, masking the middle 8.\n * Optionally formats the masked NIK with separators.\n *\n * @param nik - The 16-digit NIK string to mask\n * @param options - Masking configuration options\n * @returns Masked NIK string, or original string if invalid format\n *\n * @example\n * Default masking (first 4, last 4):\n * ```typescript\n * maskNIK('3201234567890123');\n * // '3201********0123'\n * ```\n *\n * @example\n * Custom mask character:\n * ```typescript\n * maskNIK('3201234567890123', { char: 'X' });\n * // '3201XXXXXXXX0123'\n * ```\n *\n * @example\n * With separator:\n * ```typescript\n * maskNIK('3201234567890123', { separator: '-' });\n * // '32-01-**-**-**-**-0123'\n * ```\n *\n * @example\n * Custom start and end:\n * ```typescript\n * maskNIK('3201234567890123', { start: 6, end: 4 });\n * // '320123******0123'\n * ```\n *\n * @public\n */\nexport function maskNIK(nik: string, options: MaskOptions = {}): string {\n if (!/^\\d{16}$/.test(nik)) {\n return nik;\n }\n\n const { start = 4, end = 4, char = '*', separator } = options;\n\n if (start + end >= 16) {\n return nik;\n }\n\n if (separator) {\n // Format with separator first, then apply masking\n const formatted = formatNIK(nik, separator);\n const parts = formatted.split(separator);\n\n // Calculate which parts to mask\n // Format: PP-KK-DD-YY-MM-DD-XXXX (7 parts)\n // Mask parts based on character positions\n let charCount = 0;\n const maskedParts = parts.map((part) => {\n const partStart = charCount;\n const partEnd = charCount + part.length;\n charCount += part.length;\n\n // Check if this part should be fully/partially masked\n if (partEnd <= start) {\n // Fully visible (before start)\n return part;\n } else if (partStart >= 16 - end) {\n // Fully visible (after end)\n return part;\n } else if (partStart >= start && partEnd <= 16 - end) {\n // Fully masked\n return char.repeat(part.length);\n } else {\n // Partially masked\n return part\n .split('')\n .map((ch, idx) => {\n const pos = partStart + idx;\n if (pos < start || pos >= 16 - end) {\n return ch;\n }\n return char;\n })\n .join('');\n }\n });\n\n return maskedParts.join(separator);\n }\n\n // Without separator: simple masking\n const startPart = nik.substring(0, start);\n const endPart = nik.substring(16 - end);\n const maskLength = 16 - start - end;\n return startPart + char.repeat(maskLength) + endPart;\n}","import { parseNIK } from './parse';\n\n/**\n * Calculates the age of a person based on their NIK.\n *\n * @param nik - The 16-digit NIK string\n * @param referenceDate - The date to calculate age from (default: current date)\n * @returns The age in years, or null if the NIK is invalid or birth date cannot be parsed\n *\n * @example\n * ```typescript\n * getAge('3201018901310123'); // 35 (as of 2024)\n * ```\n */\nexport function getAge(\n nik: string,\n referenceDate: Date = new Date()\n): number | null {\n const info = parseNIK(nik);\n if (!info || !info.birthDate) {\n return null;\n }\n\n const birthDate = info.birthDate;\n let age = referenceDate.getFullYear() - birthDate.getFullYear();\n const m = referenceDate.getMonth() - birthDate.getMonth();\n\n if (m < 0 || (m === 0 && referenceDate.getDate() < birthDate.getDate())) {\n age--;\n }\n\n return age;\n}\n\n/**\n * Formats the birth date from a NIK into a human-readable string.\n *\n * @param nik - The 16-digit NIK string\n * @param locale - The locale to use for formatting (default: 'id-ID')\n * @returns Formatted birth date string, or null if invalid\n *\n * @example\n * ```typescript\n * formatBirthDate('3201018901310123'); // '31 Januari 1989'\n * ```\n */\nexport function formatBirthDate(\n nik: string,\n options: Intl.DateTimeFormatOptions = {\n day: 'numeric',\n month: 'long',\n year: 'numeric',\n },\n locale: string = 'id-ID'\n): string | null {\n const info = parseNIK(nik);\n if (!info || !info.birthDate) {\n return null;\n }\n\n return new Intl.DateTimeFormat(locale, options).format(info.birthDate);\n}\n\n/**\n * Checks if a NIK matches a specific gender.\n *\n * @param nik - The 16-digit NIK string\n * @param gender - The gender to check ('male' | 'female')\n * @returns True if the NIK matches the gender, false otherwise\n */\nexport function isValidForGender(\n nik: string,\n gender: 'male' | 'female'\n): boolean {\n const info = parseNIK(nik);\n if (!info) {\n return false;\n }\n return info.gender === gender;\n}\n\n/**\n * Checks if a NIK matches a specific birth date.\n *\n * @param nik - The 16-digit NIK string\n * @param birthDate - The birth date to check\n * @returns True if the NIK matches the birth date, false otherwise\n */\nexport function isValidForBirthDate(nik: string, birthDate: Date): boolean {\n const info = parseNIK(nik);\n if (!info || !info.birthDate) {\n return false;\n }\n\n return (\n info.birthDate.getFullYear() === birthDate.getFullYear() &&\n info.birthDate.getMonth() === birthDate.getMonth() &&\n info.birthDate.getDate() === birthDate.getDate()\n );\n}\n","import { OperatorName } from './types';\n\n/**\n * Phone number constants for Indonesian operators and area codes.\n *\n * Data sources:\n * - Operator prefixes: Official operator documentation and Wikipedia\n * - Area codes: Ministry of Communication and Information Technology (Kemendagri)\n *\n * Last updated: December 2025\n *\n * @see {@link https://en.wikipedia.org/wiki/Telephone_numbers_in_Indonesia Wikipedia - Telephone numbers in Indonesia}\n * @internal\n */\n\n/**\n * Mobile operator prefix mapping.\n *\n * Maps 4-digit prefixes (e.g., '0812') to operator names.\n * Used for operator detection in mobile numbers.\n *\n * **Important Notes:**\n * - Tri (3 Indonesia) has merged with Indosat as of 2024\n * - Axis has been acquired by XL but maintains separate branding\n * - Some operators have both prepaid and postpaid services\n *\n * @example\n * ```typescript\n * OPERATOR_PREFIXES['0812']; // 'Telkomsel'\n * OPERATOR_PREFIXES['0817']; // 'XL'\n * OPERATOR_PREFIXES['0895']; // 'Indosat'\n * ```\n *\n * @internal\n */\nexport const OPERATOR_PREFIXES: Record<string, OperatorName> = {\n // Telkomsel (Halo, Simpati, by.U)\n '0811': 'Telkomsel',\n '0812': 'Telkomsel',\n '0813': 'Telkomsel',\n '0821': 'Telkomsel',\n '0822': 'Telkomsel',\n '0823': 'Telkomsel',\n '0851': 'Telkomsel',\n '0852': 'Telkomsel',\n '0853': 'Telkomsel',\n\n // XL Axiata (XL Prepaid, XL Prioritas, LIVE.ON)\n '0817': 'XL',\n '0818': 'XL',\n '0819': 'XL',\n '0859': 'XL',\n '0877': 'XL',\n '0878': 'XL',\n '0879': 'XL',\n\n // Indosat Ooredoo (IM3, Mentari)\n // Note: Tri (3 Indonesia) merged with Indosat\n '0814': 'Indosat',\n '0815': 'Indosat',\n '0816': 'Indosat',\n '0855': 'Indosat',\n '0856': 'Indosat',\n '0857': 'Indosat',\n '0858': 'Indosat',\n '0895': 'Indosat',\n '0896': 'Indosat',\n '0897': 'Indosat',\n '0898': 'Indosat',\n '0899': 'Indosat',\n\n // Smartfren (Smartfren Power Up)\n '0881': 'Smartfren',\n '0882': 'Smartfren',\n '0883': 'Smartfren',\n '0884': 'Smartfren',\n '0885': 'Smartfren',\n '0886': 'Smartfren',\n '0887': 'Smartfren',\n '0888': 'Smartfren',\n '0889': 'Smartfren',\n\n // Axis (Acquired by XL but maintains separate branding)\n '0831': 'Axis',\n '0832': 'Axis',\n '0833': 'Axis',\n '0838': 'Axis',\n} as const;\n\n/**\n * Landline area code mapping.\n *\n * Maps area codes to city/region names for landline numbers.\n * Includes both 3-digit (e.g., '021') and 4-digit (e.g., '0274') codes.\n *\n * This mapping covers all provinces in Indonesia including:\n * - Jakarta, Banten, West Java, Central Java, Yogyakarta\n * - East Java, Bali, Nusa Tenggara\n * - Sulawesi, Kalimantan\n * - Sumatra, Maluku, Papua\n *\n * @example\n * ```typescript\n * AREA_CODES['021']; // 'Jakarta'\n * AREA_CODES['0274']; // 'Yogyakarta'\n * AREA_CODES['0361']; // 'Denpasar'\n * ```\n *\n * @internal\n */\nexport const AREA_CODES: Record<string, string> = {\n // ========================================\n // JAKARTA, BANTEN & WEST JAVA\n // ========================================\n\n // Jakarta & Greater Jakarta\n '021': 'Jakarta',\n\n // Banten\n '0252': 'Lebak',\n '0253': 'Pandeglang',\n '0254': 'Cilegon & Serang',\n\n // West Java\n '022': 'Bandung',\n '0231': 'Cirebon',\n '0232': 'Kuningan',\n '0233': 'Majalengka',\n '0234': 'Indramayu',\n '0251': 'Bogor',\n '0260': 'Subang',\n '0261': 'Sumedang',\n '0262': 'Garut',\n '0263': 'Cianjur',\n '0264': 'Purwakarta',\n '0265': 'Tasikmalaya',\n '0266': 'Sukabumi',\n '0267': 'Karawang',\n\n // ========================================\n // CENTRAL JAVA & YOGYAKARTA\n // ========================================\n\n // Central Java\n '024': 'Semarang',\n '0271': 'Solo',\n '0272': 'Klaten',\n '0273': 'Wonogiri',\n '0275': 'Purworejo',\n '0276': 'Boyolali',\n '0280': 'Cilacap',\n '0281': 'Banyumas & Purbalingga',\n '0282': 'Cilacap',\n '0283': 'Tegal & Brebes',\n '0284': 'Pemalang',\n '0285': 'Pekalongan',\n '0286': 'Banjarnegara & Wonosobo',\n '0287': 'Kebumen',\n '0289': 'Bumiayu',\n '0291': 'Kudus & Jepara',\n '0292': 'Grobogan',\n '0293': 'Magelang',\n '0294': 'Kendal',\n '0295': 'Pati & Rembang',\n '0296': 'Blora',\n '0297': 'Karimun Jawa',\n '0298': 'Salatiga',\n\n // Yogyakarta\n '0274': 'Yogyakarta',\n\n // ========================================\n // EAST JAVA, BALI & NUSA TENGGARA\n // ========================================\n\n // East Java\n '031': 'Surabaya',\n '0321': 'Mojokerto & Jombang',\n '0322': 'Lamongan',\n '0323': 'Sampang',\n '0324': 'Pamekasan',\n '0325': 'Bawean',\n '0326': 'Masalembu',\n '0327': 'Kangean',\n '0328': 'Sumenep',\n '0331': 'Jember',\n '0332': 'Bondowoso',\n '0333': 'Banyuwangi',\n '0334': 'Lumajang',\n '0335': 'Probolinggo',\n '0336': 'Jember',\n '0338': 'Situbondo',\n '0341': 'Malang',\n '0342': 'Blitar',\n '0343': 'Pasuruan',\n '0351': 'Madiun',\n '0352': 'Ponorogo',\n '0353': 'Bojonegoro',\n '0354': 'Kediri',\n '0355': 'Tulungagung',\n '0356': 'Tuban',\n '0357': 'Pacitan',\n '0358': 'Nganjuk',\n\n // Bali\n '0361': 'Denpasar',\n '0362': 'Singaraja',\n '0363': 'Amlapura',\n '0365': 'Negara',\n '0366': 'Tabanan',\n '0368': 'Gianyar',\n\n // Nusa Tenggara Barat (NTB)\n '0370': 'Mataram',\n '0371': 'Sumbawa',\n '0372': 'West Sumbawa',\n '0373': 'Dompu',\n '0374': 'Bima',\n '0376': 'East Lombok',\n\n // Nusa Tenggara Timur (NTT)\n '0379': 'Alor',\n '0380': 'Kupang',\n '0381': 'Ende',\n '0382': 'Sikka',\n '0383': 'East Flores',\n '0384': 'Ngada',\n '0385': 'Manggarai',\n '0386': 'West Manggarai',\n '0387': 'Sumba',\n '0388': 'North & South Central Timor',\n '0389': 'Belu',\n\n // ========================================\n // SULAWESI\n // ========================================\n\n // South Sulawesi\n '0410': 'Pangkajene',\n '0411': 'Makassar',\n '0413': 'Bantaeng & Bulukumba',\n '0414': 'Selayar',\n '0417': 'Malino',\n '0418': 'Takalar',\n '0419': 'Jeneponto',\n '0420': 'Enrekang',\n '0421': 'Pare Pare',\n '0423': 'Tana Toraja',\n '0427': 'Barru',\n '0471': 'Luwu',\n '0472': 'Wajo (Pitumpanua)',\n '0473': 'North Luwu',\n '0474': 'East Luwu',\n '0475': 'Sorowako',\n '0481': 'Bone',\n '0482': 'Sinjai',\n '0484': 'Soppeng',\n '0485': 'Wajo',\n\n // West Sulawesi\n '0422': 'Majene',\n '0426': 'Mamuju',\n '0428': 'Polewali',\n '0429': 'Central Mamuju',\n\n // Central Sulawesi\n '0409': 'Morowali',\n '0445': 'Buol',\n '0450': 'Parigi Moutong',\n '0451': 'Palu',\n '0452': 'Poso',\n '0453': 'Toli-Toli',\n '0454': 'Tinombo',\n '0455': 'Moutong',\n '0457': 'Donggala',\n '0458': 'Tentena',\n '0461': 'Banggai',\n '0462': 'Banggai Island',\n '0463': 'Bunta',\n '0464': 'Tojo Una-Una',\n '0465': 'North Morowali',\n\n // Southeast Sulawesi\n '0401': 'Kendari',\n '0402': 'Buton',\n '0403': 'Muna',\n '0404': 'Wakatobi',\n '0405': 'Kolaka',\n '0408': 'Konawe',\n\n // North Sulawesi\n '0430': 'South Minahasa',\n '0431': 'Manado',\n '0432': 'Sangihe',\n '0433': 'Talaud',\n '0434': 'Bolaang Mongondow',\n '0438': 'Bitung',\n\n // Gorontalo\n '0435': 'Gorontalo',\n '0442': 'North Gorontalo',\n '0443': 'Pohuwato',\n\n // ========================================\n // KALIMANTAN\n // ========================================\n\n // West Kalimantan\n '0534': 'Ketapang',\n '0535': 'Kayong Utara',\n '0561': 'Pontianak',\n '0562': 'Sambas & Singkawang',\n '0563': 'Landak',\n '0564': 'Sanggau',\n '0565': 'Sintang',\n '0567': 'Kapuas Hulu',\n '0568': 'Melawi',\n\n // Central Kalimantan\n '0513': 'Kapuas',\n '0519': 'North Barito',\n '0526': 'South & East Barito',\n '0528': 'Murung Raya',\n '0531': 'East Kotawaringin',\n '0532': 'West Kotawaringin',\n '0536': 'Palangka Raya',\n '0537': 'Gunung Mas',\n '0538': 'Seruyan',\n '0539': 'Seruyan & East Kotawaringin',\n\n // South Kalimantan\n '0511': 'Banjarmasin',\n '0512': 'Tanah Laut',\n '0517': 'Hulu Sungai Selatan',\n '0518': 'Tanah Bumbu',\n '0527': 'Hulu Sungai Utara',\n\n // East Kalimantan\n '0541': 'Samarinda',\n '0542': 'Balikpapan',\n '0543': 'Paser',\n '0545': 'West Kutai',\n '0548': 'Bontang',\n '0549': 'East Kutai',\n '0554': 'Berau',\n\n // North Kalimantan\n '0551': 'Tarakan',\n '0552': 'Bulungan',\n '0553': 'Malinau',\n '0556': 'Nunukan',\n\n // ========================================\n // SUMATRA\n // ========================================\n\n // Aceh\n '0627': 'Subulussalam & Dairi (North Sumatra)',\n '0629': 'Southeast Aceh',\n '0641': 'Langsa',\n '0642': 'Gayo Lues',\n '0643': 'Central Aceh',\n '0644': 'Bireuen',\n '0645': 'Lhokseumawe',\n '0646': 'East Aceh',\n '0650': 'Simeulue',\n '0651': 'Banda Aceh',\n '0652': 'Sabang',\n '0653': 'Pidie',\n '0654': 'Aceh Jaya',\n '0655': 'West Aceh',\n '0656': 'South Aceh',\n '0657': 'South Aceh',\n '0658': 'Singkil',\n '0659': 'Southwest Aceh',\n\n // North Sumatra\n '061': 'Medan',\n '0620': 'Pangkalan Brandan',\n '0621': 'Tebing Tinggi',\n '0622': 'Pematang Siantar',\n '0623': 'Asahan',\n '0624': 'Labuhan Batu',\n '0625': 'Parapat',\n '0626': 'Samosir',\n // '0627': 'Dairi', // for this prefix, it same with Subulussalam (Aceh)\n '0628': 'Karo',\n '0630': 'South Nias',\n '0631': 'Sibolga',\n '0632': 'Toba Samosir',\n '0633': 'North Tapanuli',\n '0634': 'Padang Sidempuan',\n '0635': 'South Tapanuli',\n '0636': 'Mandailing Natal',\n '0638': 'Barus',\n '0639': 'Nias',\n\n // West Sumatra\n '0751': 'Padang',\n '0752': 'Bukittinggi',\n '0753': 'Pasaman',\n '0754': 'Sawahlunto',\n '0755': 'Solok',\n '0756': 'South Pesisir',\n '0757': 'South Pesisir',\n '0759': 'Mentawai',\n\n // Riau\n '0760': 'Kuantan Singingi',\n '0761': 'Pekanbaru',\n '0762': 'Kampar',\n '0763': 'Bengkalis',\n '0764': 'Siak',\n '0765': 'Dumai',\n '0766': 'Bengkalis',\n '0767': 'Rokan Hulu',\n '0768': 'Indragiri Hilir',\n '0769': 'Indragiri Hulu',\n\n // Riau Islands\n '0770': 'Muka Kuning Batamindo',\n '0771': 'Tanjungpinang',\n '0772': 'Anambas',\n '0773': 'Natuna',\n '0776': 'Lingga',\n '0777': 'Great Karimun',\n '0778': 'Batam',\n '0779': 'Kundur',\n\n // Jambi\n '0741': 'Jambi',\n '0742': 'West Tanjung Jabung',\n '0743': 'Batanghari',\n '0744': 'Tebo',\n '0745': 'Sarolangun',\n '0746': 'Merangin',\n '0747': 'Bungo',\n '0748': 'Kerinci',\n\n // South Sumatra\n '0702': 'Empat Lawang',\n '0711': 'Palembang',\n '0712': 'Ogan Komering Ilir',\n '0713': 'Prabumulih',\n '0714': 'Musi Banyuasin',\n '0730': 'Pagar Alam',\n '0731': 'Lahat',\n '0733': 'Lubuklinggau',\n '0734': 'Muara Enim',\n '0735': 'Ogan Komering Ulu',\n\n // Bangka Belitung\n '0715': 'Belinyu',\n '0716': 'West Bangka',\n '0717': 'Pangkal Pinang',\n '0718': 'Central & South Bangka',\n '0719': 'Belitung',\n\n // Bengkulu\n '0732': 'Rejang Lebong',\n '0736': 'Bengkulu',\n '0737': 'North Bengkulu',\n '0739': 'South Bengkulu',\n\n // Lampung\n '0721': 'Bandar Lampung',\n '0722': 'Tanggamus',\n '0723': 'Way Kanan',\n '0724': 'North Lampung',\n '0725': 'Metro',\n '0726': 'Tulang Bawang',\n '0727': 'South Lampung',\n '0728': 'West Lampung',\n '0729': 'Pringsewu',\n\n // ========================================\n // MALUKU & PAPUA\n // ========================================\n\n // Maluku\n '0910': 'Ambon',\n '0911': 'Southeast Maluku',\n '0913': 'Tual',\n '0914': 'Saumlaki',\n '0916': 'Namlea',\n '0918': 'Ternate',\n '0921': 'Sanana',\n '0924': 'Tobelo',\n\n // Papua & West Papua\n '0901': 'Timika',\n '0902': 'Agats',\n '0951': 'Sorong',\n '0952': 'South Sorong',\n '0967': 'Manokwari',\n '0969': 'Sorong',\n '0971': 'Merauke',\n '0975': 'Boven Digoel',\n '0979': 'Tembagapura',\n '0981': 'Jayapura',\n '0986': 'Wamena',\n} as const;\n\n/**\n * Valid mobile number prefixes (first 4 digits after country code).\n *\n * Used for quick validation without operator detection.\n *\n * @internal\n */\nexport const VALID_MOBILE_PREFIXES = Object.keys(OPERATOR_PREFIXES);\n\n/**\n * Valid area codes for landline numbers.\n *\n * Used for landline validation.\n *\n * @internal\n */\nexport const VALID_AREA_CODES = Object.keys(AREA_CODES);\n","import { OPERATOR_PREFIXES, AREA_CODES } from './constants';\n\n/**\n * Validates an Indonesian phone number format.\n *\n * Accepts multiple input formats:\n * - National format: 08xx-xxxx-xxxx or 08xxxxxxxxxx\n * - International with +: +62 8xx-xxxx-xxxx or +628xxxxxxxxxx\n * - International without +: 62 8xx-xxxx-xxxx or 628xxxxxxxxxx\n *\n * For mobile numbers, validates:\n * - Starts with 08 (national) or 628 (international)\n * - Has valid operator prefix (0811, 0812, 0817, etc.)\n * - Total length is 10-13 digits (after removing non-digits)\n *\n * For landline numbers, validates:\n * - Starts with 0 followed by area code (021, 022, etc.)\n * - Total length is appropriate for landline\n *\n * @param phone - The phone number string to validate\n * @returns `true` if the phone number is valid, `false` otherwise\n *\n * @example\n * Valid mobile number (national):\n * ```typescript\n * validatePhoneNumber('081234567890'); // true\n * ```\n *\n * @example\n * Valid mobile number (international):\n * ```typescript\n * validatePhoneNumber('+6281234567890'); // true\n * validatePhoneNumber('6281234567890'); // true\n * ```\n *\n * @example\n * With separators:\n * ```typescript\n * validatePhoneNumber('0812-3456-7890'); // true\n * validatePhoneNumber('+62 812-3456-7890'); // true\n * ```\n *\n * @example\n * Invalid numbers:\n * ```typescript\n * validatePhoneNumber('1234'); // false - too short\n * validatePhoneNumber('08001234567'); // false - invalid prefix\n * validatePhoneNumber('+1234567890'); // false - wrong country code\n * ```\n *\n * @public\n */\nexport function validatePhoneNumber(phone: string): boolean {\n if (!phone || typeof phone !== 'string') {\n return false;\n }\n\n // Only allow digits, +, -, space, parentheses, dot\n if (!/^[\\d\\s\\-+().]+$/.test(phone)) {\n return false;\n }\n\n const cleaned = phone.replace(/[\\s\\-().]/g, '');\n\n let normalized: string;\n\n if (cleaned.startsWith('+62')) {\n normalized = '0' + cleaned.substring(3);\n } else if (cleaned.startsWith('62') && !cleaned.startsWith('620')) {\n normalized = '0' + cleaned.substring(2);\n } else if (cleaned.startsWith('0')) {\n normalized = cleaned;\n } else {\n return false;\n }\n\n if (normalized.startsWith('08')) {\n return validateMobileNumber(normalized);\n }\n\n if (normalized.startsWith('0')) {\n return validateLandlineNumber(normalized);\n }\n\n return false;\n}\n\n/**\n * Validates a mobile phone number (08xx format).\n *\n * @param phone - Phone number in 08xx format\n * @returns true if valid mobile number\n * @internal\n */\nfunction validateMobileNumber(phone: string): boolean {\n // Mobile numbers should be 10-13 digits\n if (phone.length < 10 || phone.length > 13) {\n return false;\n }\n\n // Check if prefix is valid (first 4 digits)\n const prefix = phone.substring(0, 4);\n if (!OPERATOR_PREFIXES[prefix]) {\n return false;\n }\n\n // All digits should be numeric\n if (!/^\\d+$/.test(phone)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Validates a landline phone number.\n *\n * @param phone - Phone number in landline format\n * @returns true if valid landline number\n * @internal\n */\nfunction validateLandlineNumber(phone: string): boolean {\n // Landline numbers typically 9-11 digits\n if (phone.length < 9 || phone.length > 11) {\n return false;\n }\n\n // Check common area codes (3 or 4 digits)\n const areaCode3 = phone.substring(0, 3);\n const areaCode4 = phone.substring(0, 4);\n\n if (AREA_CODES[areaCode3] || AREA_CODES[areaCode4]) {\n return true;\n }\n\n // If not in our area code list, check if it follows general pattern\n // Landlines start with 0 followed by 2-4 digit area code\n if (/^0[2-9]\\d{7,9}$/.test(phone)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Checks if a phone number is a mobile number.\n *\n * @param phone - The phone number to check\n * @returns `true` if it's a mobile number (08xx), `false` otherwise\n *\n * @example\n * ```typescript\n * isMobileNumber('081234567890'); // true\n * isMobileNumber('+6281234567890'); // true\n * isMobileNumber('0212345678'); // false (landline)\n * ```\n *\n * @public\n */\nexport function isMobileNumber(phone: string): boolean {\n if (!validatePhoneNumber(phone)) {\n return false;\n }\n\n const cleaned = phone.replace(/[^\\d+]/g, '');\n let normalized: string;\n\n if (cleaned.startsWith('+62')) {\n normalized = '0' + cleaned.substring(3);\n } else if (cleaned.startsWith('62') && !cleaned.startsWith('620')) {\n normalized = '0' + cleaned.substring(2);\n } else {\n normalized = cleaned;\n }\n\n return normalized.startsWith('08');\n}\n\n/**\n * Checks if a phone number is a landline number.\n *\n * @param phone - The phone number to check\n * @returns `true` if it's a landline number, `false` otherwise\n *\n * @example\n * ```typescript\n * isLandlineNumber('0212345678'); // true\n * isLandlineNumber('081234567890'); // false (mobile)\n * ```\n *\n * @public\n */\nexport function isLandlineNumber(phone: string): boolean {\n if (!validatePhoneNumber(phone)) {\n return false;\n }\n\n return !isMobileNumber(phone);\n}\n","import { AREA_CODES } from './constants';\n\n/**\n * Normalizes a cleaned phone number to national format (0xxx).\n *\n * Accepts pre-cleaned phone string (digits only, optional leading +).\n * Use `cleanPhoneNumber()` first if input may contain separators.\n *\n * @param phone - Cleaned phone number string\n * @returns Phone number in 08xx format, or empty string if invalid\n *\n * @example\n * ```typescript\n * normalizePhoneNumber('+6281234567890'); // '081234567890'\n * normalizePhoneNumber('6281234567890'); // '081234567890'\n * normalizePhoneNumber('081234567890'); // '081234567890'\n * ```\n *\n * @example\n * Invalid inputs return empty string:\n * ```typescript\n * normalizePhoneNumber(''); // ''\n * normalizePhoneNumber('620812345678'); // '' (620 is not valid country code pattern)\n * normalizePhoneNumber('invalid'); // ''\n * ```\n *\n * @public\n */\nexport function normalizePhoneNumber(phone: string): string {\n if (!phone || typeof phone !== 'string') {\n return '';\n }\n\n if (phone.startsWith('+62')) {\n return '0' + phone.substring(3);\n }\n\n if (phone.startsWith('62') && !phone.startsWith('620')) {\n return '0' + phone.substring(2);\n }\n\n if (phone.startsWith('0')) {\n return phone;\n }\n\n return '';\n}\n\n/**\n * Compares two phone numbers regardless of format.\n *\n * Both inputs are normalized to national format for comparison.\n * Returns false if either input is invalid.\n *\n * @param phoneA - First phone number in any format\n * @param phoneB - Second phone number in any format\n * @returns true if both represent the same number, false otherwise\n *\n * @example\n * Same number in different formats:\n * ```typescript\n * comparePhones('081234567890', '+6281234567890'); // true\n * comparePhones('0812-3456-7890', '6281234567890'); // true\n * ```\n *\n * @example\n * Different numbers:\n * ```typescript\n * comparePhones('081234567890', '081234567891'); // false\n * comparePhones('0212345678', '0221234567'); // false\n * ```\n *\n * @example\n * Invalid inputs return false:\n * ```typescript\n * comparePhones('invalid', '081234567890'); // false\n * comparePhones('', ''); // false\n * ```\n *\n * @public\n */\nexport function comparePhones(phoneA: string, phoneB: string): boolean {\n if (typeof phoneA !== 'string' || typeof phoneB !== 'string') {\n return false;\n }\n\n const cleanedA = phoneA.replace(/[^\\d+]/g, '');\n const cleanedB = phoneB.replace(/[^\\d+]/g, '');\n\n const normalizedA = normalizeToNational(cleanedA);\n const normalizedB = normalizeToNational(cleanedB);\n\n if (!normalizedA || !normalizedB) {\n return false;\n }\n\n return normalizedA === normalizedB;\n}\n\n/**\n * Internal helper to normalize to national format.\n * Duplicates logic from normalizePhoneNumber to avoid circular deps.\n */\nfunction normalizeToNational(phone: string): string {\n if (phone.startsWith('+62')) {\n return '0' + phone.substring(3);\n }\n if (phone.startsWith('62') && !phone.startsWith('620')) {\n return '0' + phone.substring(2);\n }\n if (phone.startsWith('0')) {\n return phone;\n }\n return '';\n}\n\n/**\n * Gets the region name for a landline number.\n *\n * @param phone - Landline phone number in national format\n * @returns Region name, or null if not found\n *\n * @example\n * ```typescript\n * getLandlineRegion('0212345678'); // 'Jakarta'\n * getLandlineRegion('+62212345678'); // 'Jakarta'\n * getLandlineRegion('081234567890'); // null (mobile)\n * ```\n *\n * @public\n */\nexport function getLandlineRegion(phone: string): string | null {\n if (!phone || typeof phone !== 'string') {\n return null;\n }\n\n const cleaned = phone.replace(/[^\\d+]/g, '');\n const normalized = normalizeToNational(cleaned);\n\n if (!normalized || !normalized.startsWith('0')) {\n return null;\n }\n\n if (normalized.startsWith('08')) {\n return null;\n }\n\n const areaCode4 = normalized.substring(0, 4);\n if (AREA_CODES[areaCode4]) {\n return AREA_CODES[areaCode4];\n }\n\n const areaCode3 = normalized.substring(0, 3);\n if (AREA_CODES[areaCode3]) {\n return AREA_CODES[areaCode3];\n }\n\n const areaCode2 = normalized.substring(0, 2);\n if (AREA_CODES[areaCode2]) {\n return AREA_CODES[areaCode2];\n }\n\n return null;\n}\n","import { AREA_CODES } from './constants';\nimport { PhoneFormat, MaskOptions } from './types';\nimport { validatePhoneNumber } from './validate';\nimport { normalizePhoneNumber } from './utils';\n\n/**\n * Formats an Indonesian phone number to the specified format.\n *\n * Accepts various input formats and converts to the desired output format.\n * Automatically adds appropriate separators for readability.\n *\n * @param phone - The phone number to format\n * @param format - Target format ('international', 'national', 'e164', 'display')\n * @returns Formatted phone number, or original string if invalid\n *\n * @example\n * International format:\n * ```typescript\n * formatPhoneNumber('081234567890', 'international');\n * // '+62 812-3456-7890'\n * ```\n *\n * @example\n * National format:\n * ```typescript\n * formatPhoneNumber('+6281234567890', 'national');\n * // '0812-3456-7890'\n * ```\n *\n * @example\n * E.164 format (no spaces/dashes):\n * ```typescript\n * formatPhoneNumber('0812-3456-7890', 'e164');\n * // '6281234567890'\n * ```\n *\n * @public\n */\nexport function formatPhoneNumber(\n phone: string,\n format: PhoneFormat = 'national'\n): string {\n if (!validatePhoneNumber(phone)) {\n return phone;\n }\n\n const cleaned = cleanPhoneNumber(phone);\n\n const normalized = normalizePhoneNumber(cleaned);\n if (!normalized) {\n return phone;\n }\n\n switch (format) {\n case 'international':\n return toInternational(normalized);\n case 'national':\n case 'display':\n return toNational(normalized);\n case 'e164':\n return toE164(normalized);\n default:\n return phone;\n }\n}\n\n/**\n * Converts a phone number to international format (+62 xxx-xxxx-xxxx).\n *\n * @param phone - The phone number to convert\n * @returns Phone number in international format with separators\n *\n * @example\n * ```typescript\n * toInternational('081234567890');\n * // '+62 812-3456-7890'\n * ```\n *\n * @example\n * Already international:\n * ```typescript\n * toInternational('+6281234567890');\n * // '+62 812-3456-7890'\n * ```\n *\n * @public\n */\nexport function toInternational(phone: string): string {\n const cleaned = cleanPhoneNumber(phone);\n if (!cleaned) {\n return phone;\n }\n\n const normalized = normalizePhoneNumber(cleaned);\n if (!normalized) {\n return phone;\n }\n\n const withoutZero = normalized.substring(1);\n\n if (normalized.startsWith('08')) {\n if (withoutZero.length === 11) {\n return `+62 ${withoutZero.substring(0, 3)}-${withoutZero.substring(3, 7)}-${withoutZero.substring(7)}`;\n } else if (withoutZero.length === 10) {\n return `+62 ${withoutZero.substring(0, 3)}-${withoutZero.substring(3, 6)}-${withoutZero.substring(6)}`;\n } else if (withoutZero.length === 9) {\n return `+62 ${withoutZero.substring(0, 3)}-${withoutZero.substring(3)}`;\n } else if (withoutZero.length === 12) {\n return `+62 ${withoutZero.substring(0, 3)}-${withoutZero.substring(3, 7)}-${withoutZero.substring(7)}`;\n }\n }\n\n const areaCodeLength = getAreaCodeLength(normalized);\n const areaCode = normalized.substring(1, areaCodeLength + 1);\n const localNumber = normalized.substring(areaCodeLength + 1);\n\n return `+62 ${areaCode}-${localNumber}`;\n}\n\n/**\n * Converts a phone number to national format (08xx-xxxx-xxxx).\n *\n * @param phone - The phone number to convert\n * @returns Phone number in national format with dashes\n *\n * @example\n * ```typescript\n * toNational('+6281234567890');\n * // '0812-3456-7890'\n * ```\n *\n * @example\n * Already national:\n * ```typescript\n * toNational('081234567890');\n * // '0812-3456-7890'\n * ```\n *\n * @public\n */\nexport function toNational(phone: string): string {\n const cleaned = cleanPhoneNumber(phone);\n if (!cleaned) {\n return phone;\n }\n\n const normalized = normalizePhoneNumber(cleaned);\n if (!normalized) {\n return phone;\n }\n\n if (normalized.startsWith('08')) {\n if (normalized.length === 12) {\n return `${normalized.substring(0, 4)}-${normalized.substring(4, 8)}-${normalized.substring(8)}`;\n } else if (normalized.length === 11) {\n return `${normalized.substring(0, 4)}-${normalized.substring(4, 7)}-${normalized.substring(7)}`;\n } else if (normalized.length === 10) {\n return `${normalized.substring(0, 4)}-${normalized.substring(4)}`;\n } else if (normalized.length === 13) {\n return `${normalized.substring(0, 4)}-${normalized.substring(4, 8)}-${normalized.substring(8)}`;\n }\n }\n\n const areaCodeLength = getAreaCodeLength(normalized);\n const areaCodeWithZero = normalized.substring(0, areaCodeLength + 1);\n const localNumber = normalized.substring(areaCodeLength + 1);\n\n return `${areaCodeWithZero}-${localNumber}`;\n}\n\n/**\n * Converts a phone number to E.164 format (6281234567890).\n *\n * E.164 is the international standard format without spaces or dashes.\n * Suitable for API calls and database storage.\n *\n * @param phone - The phone number to convert\n * @returns Phone number in E.164 format\n *\n * @example\n * ```typescript\n * toE164('0812-3456-7890');\n * // '6281234567890'\n * ```\n *\n * @example\n * From international format:\n * ```typescript\n * toE164('+62 812-3456-7890');\n * // '6281234567890'\n * ```\n *\n * @public\n */\nexport function toE164(phone: string): string {\n const cleaned = cleanPhoneNumber(phone);\n if (!cleaned) {\n return phone;\n }\n\n const normalized = normalizePhoneNumber(cleaned);\n if (!normalized) {\n return phone;\n }\n\n return '62' + normalized.substring(1);\n}\n\n/**\n * Removes all non-digit characters from a phone number, preserving leading +.\n *\n * @param phone - The phone number to clean\n * @returns Cleaned phone number with only digits (and optional leading +)\n *\n * @example\n * ```typescript\n * cleanPhoneNumber('0812-3456-7890');\n * // '081234567890'\n * ```\n *\n * @example\n * ```typescript\n * cleanPhoneNumber('+62 812 3456 7890');\n * // '+6281234567890'\n * ```\n *\n * @public\n */\nexport function cleanPhoneNumber(phone: string): string {\n if (!phone || typeof phone !== 'string') {\n return '';\n }\n\n return phone.replace(/[^\\d+]/g, '');\n}\n\n/**\n * Determines area code length for landline numbers.\n *\n * @param normalized - Phone number in national format (0xxx)\n * @returns Area code length (digits after leading 0)\n * @internal\n */\nfunction getAreaCodeLength(normalized: string): number {\n // Check 4-digit area codes ('0xxxx')\n const fourDigitCode = normalized.substring(0, 5);\n if (AREA_CODES[fourDigitCode]) {\n return 4;\n }\n\n // Check 3-digit area codes ('0xxx')\n const threeDigitCode = normalized.substring(0, 4);\n if (AREA_CODES[threeDigitCode]) {\n return 3;\n }\n\n // Check 2-digit area codes ('0xx')\n const twoDigitCode = normalized.substring(0, 3);\n if (AREA_CODES[twoDigitCode]) {\n return 2;\n }\n\n return 2;\n}\n\n/**\n * Masks a phone number for privacy protection.\n *\n * By default, shows the first 4 and last 4 digits, masking the middle digits.\n * Optionally formats with separators.\n *\n * @param phone - The phone number to mask\n * @param options - Masking configuration options\n * @returns Masked phone number, or original string if invalid\n *\n * @example\n * Default masking:\n * ```typescript\n * maskPhoneNumber('081234567890');\n * // '0812****7890'\n * ```\n *\n * @example\n * Custom mask character:\n * ```typescript\n * maskPhoneNumber('081234567890', { char: 'X' });\n * // '0812XXXX7890'\n * ```\n *\n * @example\n * With separator:\n * ```typescript\n * maskPhoneNumber('081234567890', { separator: '-' });\n * // '0812-****-7890'\n * ```\n *\n * @public\n */\nexport function maskPhoneNumber(\n phone: string,\n options: MaskOptions = {}\n): string {\n const cleaned = cleanPhoneNumber(phone);\n if (!cleaned) {\n return phone;\n }\n\n const isInternational = cleaned.startsWith('+');\n let toMask: string;\n\n if (isInternational) {\n toMask = cleaned;\n } else {\n const normalized = normalizePhoneNumber(cleaned);\n toMask = normalized || cleaned;\n }\n\n if (toMask.length < 4) {\n return phone;\n }\n\n const { char = '*', separator } = options;\n let { start = 4, end = 4 } = options;\n\n if (start + end >= toMask.length) {\n // Auto-adjust for short numbers to ensure masking happens\n if (toMask.length < 10) {\n const minMaskLength = 1;\n const availableForVisible = toMask.length - minMaskLength;\n\n if (availableForVisible >= 2) {\n start = Math.floor(availableForVisible / 2);\n end = availableForVisible - start;\n } else {\n return toMask;\n }\n } else {\n return toMask;\n }\n }\n\n const startPart = toMask.substring(0, start);\n const endPart = toMask.substring(toMask.length - end);\n const maskLength = toMask.length - start - end;\n const masked = startPart + char.repeat(maskLength) + endPart;\n\n if (separator) {\n return `${masked.substring(0, start)}${separator}${masked.substring(start, masked.length - end)}${separator}${masked.substring(masked.length - end)}`;\n }\n\n return masked;\n}\n","import { toE164 } from './format';\nimport { validatePhoneNumber } from './validate';\n\n/**\n * Generates a WhatsApp click-to-chat link.\n *\n * @param phone - The Indonesian phone number\n * @param message - Optional pre-filled message\n * @returns WhatsApp link, or empty string if phone is invalid\n *\n * @example\n * ```typescript\n * generateWALink('081234567890', 'Halo!');\n * // 'https://wa.me/6281234567890?text=Halo%21'\n * ```\n *\n * @public\n */\nexport function generateWALink(phone: string, message?: string): string {\n if (!validatePhoneNumber(phone)) {\n return '';\n }\n\n const e164 = toE164(phone);\n let link = `https://wa.me/${e164}`;\n\n if (message) {\n link += `?text=${encodeURIComponent(message)}`;\n }\n\n return link;\n}\n\n/**\n * Generates an SMS link (sms:).\n *\n * @param phone - The Indonesian phone number\n * @param body - Optional SMS body\n * @returns SMS link, or empty string if phone is invalid\n *\n * @example\n * ```typescript\n * generateSmsLink('081234567890', 'Pesan ini');\n * // 'sms:+6281234567890?body=Pesan%20ini'\n * ```\n *\n * @public\n */\nexport function generateSmsLink(phone: string, body?: string): string {\n if (!validatePhoneNumber(phone)) {\n return '';\n }\n\n const e164 = toE164(phone);\n let link = `sms:+${e164}`;\n\n if (body) {\n link += `?body=${encodeURIComponent(body)}`;\n }\n\n return link;\n}\n\n/**\n * Generates a telephone link (tel:).\n *\n * @param phone - The Indonesian phone number\n * @returns Tel link, or empty string if phone is invalid\n *\n * @example\n * ```typescript\n * generateTelLink('081234567890');\n * // 'tel:+6281234567890'\n * ```\n *\n * @public\n */\nexport function generateTelLink(phone: string): string {\n if (!validatePhoneNumber(phone)) {\n return '';\n }\n\n const e164 = toE164(phone);\n return `tel:+${e164}`;\n}\n","import { OPERATOR_PREFIXES } from './constants';\nimport { PhoneInfo, OperatorName } from './types';\nimport {\n cleanPhoneNumber,\n toInternational,\n toNational,\n toE164,\n} from './format';\nimport { validatePhoneNumber, isMobileNumber } from './validate';\nimport { normalizePhoneNumber, getLandlineRegion } from './utils';\n\n/**\n * Parses an Indonesian phone number and extracts all information.\n *\n * Extracts country code, operator, formatted variants, and determines\n * if it's a mobile or landline number.\n *\n * @param phone - The phone number to parse\n * @returns Parsed phone information, or `null` if invalid\n *\n * @example\n * Parse a mobile number:\n * ```typescript\n * const info = parsePhoneNumber('081234567890');\n * console.log(info);\n * // {\n * // countryCode: '62',\n * // operator: 'Telkomsel',\n * // number: '81234567890',\n * // formatted: {\n * // international: '+62 812-3456-7890',\n * // national: '0812-3456-7890',\n * // e164: '6281234567890'\n * // },\n * // isValid: true,\n * // isMobile: true,\n * // isLandline: false\n * // }\n * ```\n *\n * @example\n * Parse with different input format:\n * ```typescript\n * const info = parsePhoneNumber('+62 812-3456-7890');\n * console.log(info.operator); // 'Telkomsel'\n * console.log(info.formatted.national); // '0812-3456-7890'\n * ```\n *\n * @example\n * Parse a landline:\n * ```typescript\n * const info = parsePhoneNumber('0212345678');\n * console.log(info.region); // 'Jakarta'\n * console.log(info.isLandline); // true\n * ```\n *\n * @public\n */\nexport function parsePhoneNumber(phone: string): PhoneInfo | null {\n if (!validatePhoneNumber(phone)) {\n return null;\n }\n\n const cleaned = cleanPhoneNumber(phone);\n const normalized = normalizePhoneNumber(cleaned);\n\n if (!normalized) {\n return null;\n }\n\n const countryCode = '62';\n const number = normalized.substring(1); // Remove leading 0\n const isMobile = normalized.startsWith('08');\n const isLandline = !isMobile;\n\n let operator: OperatorName | null = null;\n let region: string | null = null;\n\n if (isMobile) {\n operator = getOperator(normalized);\n } else {\n region = getLandlineRegion(normalized);\n }\n\n return {\n countryCode,\n operator,\n number,\n formatted: {\n international: toInternational(normalized),\n national: toNational(normalized),\n e164: toE164(normalized),\n },\n isValid: true,\n isMobile,\n isLandline,\n region,\n };\n}\n\n/**\n * Detects the mobile operator from a phone number.\n *\n * Identifies the operator based on the phone number prefix.\n * Returns `null` if the operator cannot be determined or if it's not a mobile number.\n *\n * @param phone - The phone number to check\n * @returns Operator name, or `null` if not detected\n *\n * @example\n * Telkomsel numbers:\n * ```typescript\n * getOperator('081234567890'); // 'Telkomsel'\n * getOperator('0812-3456-7890'); // 'Telkomsel'\n * getOperator('+6281234567890'); // 'Telkomsel'\n * ```\n *\n * @example\n * XL numbers:\n * ```typescript\n * getOperator('081734567890'); // 'XL'\n * ```\n *\n * @example\n * Non-mobile or invalid:\n * ```typescript\n * getOperator('0212345678'); // null (landline)\n * getOperator('1234'); // null (invalid)\n * ```\n *\n * @public\n */\nexport function getOperator(phone: string): OperatorName | null {\n if (!isMobileNumber(phone)) {\n return null;\n }\n\n const cleaned = cleanPhoneNumber(phone);\n const normalized = normalizePhoneNumber(cleaned);\n\n if (!normalized || normalized.length < 4) {\n return null;\n }\n\n const prefix = normalized.substring(0, 4);\n return OPERATOR_PREFIXES[prefix] || null;\n}\n\n/**\n * Checks if a phone number belongs to a specific provider.\n *\n * @param phone - The phone number to check\n * @param providerName - The provider name to match (case-insensitive)\n * @returns `true` if it matches, `false` otherwise\n *\n * @example\n * ```typescript\n * isProvider('081234567890', 'Telkomsel'); // true\n * isProvider('081734567890', 'xl'); // true\n * ```\n *\n * @public\n */\nexport function isProvider(phone: string, providerName: string): boolean {\n const operator = getOperator(phone);\n if (!operator) {\n return false;\n }\n return operator.toLowerCase() === providerName.toLowerCase();\n}\n","/**\n * Validates an Indonesian NPWP (Nomor Pokok Wajib Pajak).\n *\n * Supports both 15-digit (standard) and 16-digit (new NIK-based) formats.\n *\n * @param npwp - The NPWP string to validate\n * @returns `true` if valid, `false` otherwise\n *\n * @example\n * ```typescript\n * validateNPWP('01.234.567.8-012.000'); // true\n * validateNPWP('012345678012000'); // true\n * ```\n */\nexport function validateNPWP(npwp: string): boolean {\n if (!npwp || typeof npwp !== 'string') {\n return false;\n }\n\n const cleaned = npwp.replace(/[^\\d]/g, '');\n\n // Must be 15 or 16 digits\n if (cleaned.length !== 15 && cleaned.length !== 16) {\n return false;\n }\n\n // Basic check: all numeric\n if (!/^\\d+$/.test(cleaned)) {\n return false;\n }\n\n return true;\n}\n","import { validateNPWP } from './validate';\nimport { NPWPInfo, MaskOptions } from './types';\n\n/**\n * Formats an NPWP string into standard Indonesian format (99.999.999.9-999.999).\n *\n * @param npwp - The NPWP string to format\n * @returns Formatted NPWP string, or original if invalid\n *\n * @example\n * ```typescript\n * formatNPWP('012345678012000'); // '01.234.567.8-012.000'\n * ```\n */\nexport function formatNPWP(npwp: string): string {\n if (!validateNPWP(npwp)) {\n return npwp;\n }\n\n const cleaned = npwp.replace(/[^\\d]/g, '');\n\n if (cleaned.length === 15) {\n return `${cleaned.substring(0, 2)}.${cleaned.substring(\n 2,\n 5\n )}.${cleaned.substring(5, 8)}.${cleaned.substring(8, 9)}-${cleaned.substring(\n 9,\n 12\n )}.${cleaned.substring(12, 15)}`;\n }\n\n // 16-digit NPWP (NIK) usually doesn't have a standard \"dots\" format like 15-digit\n // but if it's NIK, it might be formatted as NIK elsewhere.\n // For now, return as is or implement a simple format.\n return cleaned;\n}\n\n/**\n * Parses an NPWP string into its components.\n *\n * @param npwp - The NPWP string to parse\n * @returns NPWPInfo object, or null if invalid\n */\nexport function parseNPWP(npwp: string): NPWPInfo | null {\n if (!validateNPWP(npwp)) {\n return null;\n }\n\n const cleaned = npwp.replace(/[^\\d]/g, '');\n const isNikBased = cleaned.length === 16;\n\n if (isNikBased) {\n return {\n npwp: cleaned,\n type: cleaned.substring(0, 2),\n serial: cleaned.substring(2, 8),\n checksum: cleaned.substring(8, 9),\n taxOfficeCode: cleaned.substring(9, 12),\n branchCode: cleaned.substring(12, 16),\n isNikBased: true,\n };\n }\n\n return {\n npwp: cleaned,\n type: cleaned.substring(0, 2),\n serial: cleaned.substring(2, 8),\n checksum: cleaned.substring(8, 9),\n taxOfficeCode: cleaned.substring(9, 12),\n branchCode: cleaned.substring(12, 15),\n isNikBased: false,\n };\n}\n\n/**\n * Masks an NPWP string for privacy.\n *\n * @param npwp - The NPWP string to mask\n * @param options - Masking options\n * @returns Masked NPWP string\n */\nexport function maskNPWP(npwp: string, options?: MaskOptions): string {\n if (!npwp) return '';\n\n const { visibleStart = 2, visibleEnd = 3, maskChar = '*' } = options || {};\n\n // If input is formatted, we mask the digits but keep the symbols in place\n if (npwp.includes('.') || npwp.includes('-')) {\n let digitCount = 0;\n const digitsOnly = npwp.replace(/[^\\d]/g, '');\n const totalDigits = digitsOnly.length;\n\n return npwp\n .split('')\n .map((char) => {\n if (/\\d/.test(char)) {\n digitCount++;\n if (\n digitCount <= visibleStart ||\n digitCount > totalDigits - visibleEnd\n ) {\n return char;\n }\n return maskChar;\n }\n return char;\n })\n .join('');\n }\n\n const cleaned = npwp.replace(/[^\\d]/g, '');\n\n if (cleaned.length < visibleStart + visibleEnd) {\n return cleaned.replace(/./g, maskChar);\n }\n\n const start = cleaned.substring(0, visibleStart);\n const end = cleaned.substring(cleaned.length - visibleEnd);\n const middle = maskChar.repeat(cleaned.length - visibleStart - visibleEnd);\n\n return `${start}${middle}${end}`;\n}\n","/**\n * Mapping of Indonesian license plate prefixes to their regions.\n */\nexport const PLATE_REGIONS: Record<string, string> = {\n A: 'Banten',\n B: 'Jakarta, Depok, Tangerang, Bekasi',\n D: 'Bandung, Cimahi',\n E: 'Cirebon, Indramayu, Majalengka, Kuningan',\n F: 'Bogor, Cianjur, Sukabumi',\n G: 'Pekalongan, Pemalang, Batang, Tegal, Brebes',\n H: 'Semarang, Salatiga, Kendal, Demak',\n K: 'Pati, Kudus, Jepara, Rembang, Blora, Grobogan',\n L: 'Surabaya',\n M: 'Madura',\n N: 'Malang, Probolinggo, Pasuruan, Lumajang, Batu',\n P: 'Besuki, Bondowoso, Situbondo, Jember, Banyuwangi',\n R: 'Banyumas, Cilacap, Purbalinggo, Banjarnegara',\n S: 'Bojonegoro, Tuban, Lamongan, Jombang, Mojokerto',\n T: 'Purwakarta, Subang, Karawang',\n AA: 'Kedu, Magelang, Purworejo, Kebumen, Temanggung, Wonosobo',\n AB: 'Yogyakarta',\n AD: 'Surakarta, Boyolali, Sukoharjo, Karanganyar, Wonogiri, Sragen, Klaten',\n AE: 'Madiun, Ngawi, Magetan, Ponorogo, Pacitan',\n AG: 'Kediri, Blitar, Tulungagung, Nganjuk, Trenggalek',\n BA: 'Sumatera Barat',\n BB: 'Sumatera Utara (Pantai Barat)',\n BD: 'Bengkulu',\n BE: 'Lampung',\n BG: 'Sumatera Selatan',\n BH: 'Jambi',\n BK: 'Sumatera Utara (Pantai Timur)',\n BL: 'Aceh',\n BM: 'Riau',\n BN: 'Kepulauan Bangka Belitung',\n BP: 'Kepulauan Riau',\n DA: 'Kalimantan Selatan',\n DB: 'Sulawesi Utara (Daratan)',\n DC: 'Sulawesi Barat',\n DD: 'Sulawesi Selatan (Selatan)',\n DE: 'Maluku',\n DF: 'Timor Timur (Historical)',\n DG: 'Maluku Utara',\n DH: 'NTT (Timor)',\n DK: 'Bali',\n DL: 'Sulawesi Utara (Kepulauan)',\n DM: 'Gorontalo',\n DN: 'Sulawesi Tengah',\n DP: 'Sulawesi Selatan (Utara)',\n DR: 'NTB (Lombok)',\n DS: 'Papua',\n DT: 'Sulawesi Tenggara',\n EA: 'NTB (Sumbawa)',\n EB: 'NTT (Flores)',\n ED: 'NTT (Sumba)',\n KB: 'Kalimantan Barat',\n KH: 'Kalimantan Tengah',\n KT: 'Kalimantan Timur',\n KU: 'Kalimantan Utara',\n PA: 'Papua',\n PB: 'Papua Barat',\n};\n","import { PLATE_REGIONS } from './regions';\n\n/**\n * Validates an Indonesian license plate number format.\n * Format: [1-2 letters] [1-4 digits] [1-3 letters]\n *\n * @param plate - The plate number string to validate\n * @returns `true` if valid, `false` otherwise\n *\n * @example\n * ```typescript\n * validatePlate('B 1234 ABC'); // true\n * validatePlate('AB 1 CD'); // true\n * ```\n */\nexport function validatePlate(plate: string): boolean {\n if (!plate || typeof plate !== 'string') {\n return false;\n }\n\n const cleaned = plate.replace(/\\s+/g, '').toUpperCase();\n const regex = /^[A-Z]{1,2}\\d{1,4}[A-Z]{1,3}$/;\n\n return regex.test(cleaned);\n}\n\n/**\n * Gets the region name from a license plate number.\n *\n * @param plate - The plate number\n * @returns Region name or null if not found\n */\nexport function getRegionFromPlate(plate: string): string | null {\n if (!plate || typeof plate !== 'string') {\n return null;\n }\n\n const cleaned = plate.replace(/\\s+/g, '').toUpperCase();\n const match = cleaned.match(/^([A-Z]{1,2})/);\n\n if (!match) {\n return null;\n }\n\n const prefix = match[1];\n return PLATE_REGIONS[prefix] || null;\n}\n\n/**\n * Formats a license plate number with spaces (e.g., B 1234 ABC).\n *\n * @param plate - The plate number\n * @returns Formatted plate string\n */\nexport function formatPlate(plate: string): string {\n if (!plate) return '';\n\n const cleaned = plate.replace(/\\s+/g, '').toUpperCase();\n const match = cleaned.match(/^([A-Z]{1,2})(\\d{1,4})([A-Z]{1,3})$/);\n\n if (!match) {\n return cleaned;\n }\n\n return `${match[1]} ${match[2]} ${match[3]}`;\n}\n","/**\n * The standard length of a VIN (ISO 3779).\n */\nexport const VIN_LENGTH = 17;\n\n/**\n * The 0-based index of the check digit in the VIN (Position 9).\n */\nexport const VIN_CHECK_DIGIT_INDEX = 8;\n\n/**\n * The modulus used in the VIN checksum calculation.\n */\nexport const VIN_MODULUS = 11;\n\n/**\n * The character representing a checksum value of 10.\n */\nexport const VIN_CHECK_DIGIT_X = 'X';\n\n/**\n * Weights used in the VIN checksum calculation.\n * Each position (1-17) is multiplied by its corresponding weight.\n * Position 9 is the check digit itself (weight 0).\n */\nexport const VIN_WEIGHTS = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2];\n\n/**\n * Values assigned to each valid character for VIN calculation.\n * Invalid characters: I, O, Q are not allowed in VIN.\n */\nexport const VIN_CHAR_VALUES: Record<string, number> = {\n '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,\n 'A': 1, 'B': 2, 'C': 3, 'D': 4, 'E': 5, 'F': 6, 'G': 7, 'H': 8,\n 'J': 1, 'K': 2, 'L': 3, 'M': 4, 'N': 5, 'P': 7, 'R': 9,\n 'S': 2, 'T': 3, 'U': 4, 'V': 5, 'W': 6, 'X': 7, 'Y': 8, 'Z': 9,\n};\n\n/**\n * Characters excluded from VIN (I, O, Q).\n */\nexport const EXCLUDED_VIN_CHARS = ['I', 'O', 'Q'];\n\n/**\n * Version of the VIN utility module.\n */\nexport const VIN_VERSION = '1.0.0';\n\n","import {\n VIN_WEIGHTS,\n VIN_CHAR_VALUES,\n EXCLUDED_VIN_CHARS,\n VIN_LENGTH,\n VIN_CHECK_DIGIT_INDEX,\n VIN_MODULUS,\n VIN_CHECK_DIGIT_X,\n} from './constants';\n\n/**\n * Validates a Vehicle Identification Number (VIN) based on ISO 3779.\n *\n * Checks for:\n * - Exactly 17 characters length.\n * - Exclusion of characters I, O, and Q.\n * - Checksum validation using the check digit at position 9.\n *\n * @param vin - The VIN string to validate\n * @returns boolean indicating if the VIN is valid\n *\n * @example\n * ```typescript\n * import { validateVIN } from '@indodev/toolkit/vin';\n *\n * validateVIN('1HBHA82L7ZB000001'); // true\n * validateVIN('1HBHA82I7ZB000001'); // false (contains 'I')\n * ```\n */\nexport function validateVIN(vin: string): boolean {\n if (!vin || vin.length !== VIN_LENGTH) {\n return false;\n }\n\n const normalizedVIN = vin.toUpperCase();\n\n // 1. Check for excluded characters (I, O, Q)\n for (const char of EXCLUDED_VIN_CHARS) {\n if (normalizedVIN.includes(char)) {\n return false;\n }\n }\n\n // 2. Checksum validation (Position 9)\n let sum = 0;\n for (let i = 0; i < VIN_LENGTH; i++) {\n const char = normalizedVIN[i];\n const weight = VIN_WEIGHTS[i];\n const val = VIN_CHAR_VALUES[char];\n\n if (val === undefined) {\n return false; // Invalid character found\n }\n\n sum += val * weight;\n }\n\n const checkDigitValue = sum % VIN_MODULUS;\n const expectedCheckDigit =\n checkDigitValue === 10 ? VIN_CHECK_DIGIT_X : checkDigitValue.toString();\n const actualCheckDigit = normalizedVIN[VIN_CHECK_DIGIT_INDEX];\n\n return actualCheckDigit === expectedCheckDigit;\n}\n","/**\n * Regular expression for standard email validation.\n * Optimized for RFC 5322 compliance.\n */\nexport const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$/;\n\n/**\n * Common disposable email domains to block if needed.\n */\nexport const DISPOSABLE_DOMAINS = [\n 'mailinator.com',\n '10minutemail.com',\n 'temp-mail.org',\n 'guerrillamail.com',\n];\n","import { EMAIL_REGEX, DISPOSABLE_DOMAINS } from './constants';\nimport type { EmailValidationOptions, EmailMaskOptions, EmailInfo } from './types';\n\n/**\n * List of common global email providers.\n */\nconst COMMON_PROVIDERS = ['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'icloud.com'];\n\n/**\n * The maximum length of an email address according to RFC 5321.\n */\nconst MAX_EMAIL_LENGTH = 254;\n\n/**\n * Validates if a string is a properly formatted email address based on RFC 5322.\n * \n * Performs checks for:\n * - Proper email format (regex).\n * - RFC specific rules (no double dots, username length < 64).\n * - Maximum total length (254 characters).\n * - Optional: disposable email detection.\n * \n * @param email - The email string to validate.\n * @param options - Optional validation configuration.\n * @returns `true` if valid, `false` otherwise.\n * \n * @example\n * ```typescript\n * import { validateEmail } from '@indodev/toolkit/email-validator';\n * \n * validateEmail('user@example.com'); // true\n * validateEmail('invalid-email'); // false\n * validateEmail('spam@mailinator.com', { blockDisposable: true }); // false\n * ```\n */\nexport function validateEmail(email: string, options?: EmailValidationOptions): boolean {\n if (!email || typeof email !== 'string') {\n return false;\n }\n\n const trimmedEmail = email.trim().toLowerCase();\n\n if (trimmedEmail.length > MAX_EMAIL_LENGTH) {\n return false;\n }\n\n const parts = trimmedEmail.split('@');\n if (parts.length !== 2) {\n return false;\n }\n\n const [username, domain] = parts;\n\n if (!username || !domain) {\n return false;\n }\n\n if (username.length > 64) {\n return false;\n }\n\n if (\n username.includes('..') ||\n username.startsWith('.') ||\n username.endsWith('.') ||\n domain.startsWith('.') ||\n domain.endsWith('.') ||\n domain.includes('..')\n ) {\n return false;\n }\n\n if (!EMAIL_REGEX.test(trimmedEmail)) {\n return false;\n }\n\n if (options?.blockDisposable) {\n if (DISPOSABLE_DOMAINS.includes(domain)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Parses an email address to extract useful metadata.\n * \n * @param email - The email address to parse.\n * @returns `EmailInfo` object containing details or `null` if the email is invalid.\n * \n * @example\n * ```typescript\n * import { getEmailInfo } from '@indodev/toolkit/email-validator';\n * \n * const info = getEmailInfo('adam@gmail.com');\n * // { username: 'adam', domain: 'gmail.com', isCommonProvider: true, isDisposable: false }\n * ```\n */\nexport function getEmailInfo(email: string): EmailInfo | null {\n if (!validateEmail(email)) return null;\n\n const [username, domain] = email.trim().toLowerCase().split('@');\n\n return {\n username,\n domain,\n isCommonProvider: COMMON_PROVIDERS.includes(domain),\n isDisposable: DISPOSABLE_DOMAINS.includes(domain),\n };\n}\n\n/**\n * Masks the username portion of an email for privacy protection.\n * \n * Falls back to a standard mask if the username is too short to respect visibleStart/visibleEnd.\n * \n * @param email - The email address to mask.\n * @param options - Optional masking configuration.\n * @returns Masked email string or original if invalid.\n * \n * @example\n * ```typescript\n * import { maskEmail } from '@indodev/toolkit/email-validator';\n * \n * maskEmail('user@example.com'); // 'u**r@example.com'\n * maskEmail('user@example.com', { maskChar: '#' }); // 'u##r@example.com'\n * ```\n */\nexport function maskEmail(email: string, options?: EmailMaskOptions): string {\n if (!validateEmail(email)) return email;\n\n const { visibleStart = 1, visibleEnd = 1, maskChar = '*' } = options || {};\n const [username, domain] = email.split('@');\n\n // Fallback for very short usernames\n if (username.length <= 3) {\n return `${username[0]}${maskChar.repeat(3)}@${domain}`;\n }\n\n // Calculate masked length\n const maskedLength = username.length - (visibleStart + visibleEnd);\n\n // If the result of masking would be empty or negative, use fallback\n if (maskedLength <= 0) {\n return `${username[0]}${maskChar.repeat(3)}@${domain}`;\n }\n\n const start = username.slice(0, visibleStart);\n const end = username.slice(username.length - visibleEnd);\n\n return `${start}${maskChar.repeat(maskedLength)}${end}@${domain}`;\n}\n\n/**\n * Normalizes an email address by trimming whitespace and converting to lowercase.\n * \n * @param email - The email to normalize.\n * @returns Normalized email string.\n * \n * @example\n * ```typescript\n * import { normalizeEmail } from '@indodev/toolkit/email-validator';\n * \n * normalizeEmail(' USER@Example.COM '); // 'user@example.com'\n * ```\n */\nexport function normalizeEmail(email: string): string {\n return email.trim().toLowerCase();\n}\n","/**\n * Currency formatting utilities for Indonesian Rupiah.\n *\n * @module currency/format\n * @packageDocumentation\n */\n\nimport type { CompactOptions, RupiahOptions } from './types';\n\n/**\n * Formats a number as Indonesian Rupiah currency.\n *\n * Provides flexible formatting options including symbol display,\n * decimal places, and custom separators.\n *\n * @param amount - The amount to format\n * @param options - Formatting options\n * @returns Formatted Rupiah string\n *\n * @example\n * Basic formatting:\n * ```typescript\n * formatRupiah(1500000); // 'Rp 1.500.000'\n * ```\n *\n * @example\n * With decimals:\n * ```typescript\n * formatRupiah(1500000.50, { decimal: true }); // 'Rp 1.500.000,50'\n * ```\n *\n * @example\n * Without symbol:\n * ```typescript\n * formatRupiah(1500000, { symbol: false }); // '1.500.000'\n * ```\n *\n * @example\n * Custom separators:\n * ```typescript\n * formatRupiah(1500000, { separator: ',' }); // 'Rp 1,500,000'\n * ```\n *\n * @public\n */\nexport function formatRupiah(amount: number, options?: RupiahOptions): string {\n const {\n symbol = true,\n decimal = false,\n separator = '.',\n decimalSeparator = ',',\n spaceAfterSymbol = true,\n } = options || {};\n\n // Default precision: 2 for decimals, 0 otherwise\n const precision =\n options?.precision !== undefined ? options.precision : decimal ? 2 : 0;\n\n const isNegative = amount < 0 && amount !== 0;\n const absAmount = Math.abs(amount);\n\n let result: string;\n\n if (decimal) {\n const factor = Math.pow(10, precision);\n const rounded = Math.round(absAmount * factor) / factor;\n\n if (precision > 0) {\n const [intPart, decPart] = rounded.toFixed(precision).split('.');\n const formattedInt = intPart.replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n result = `${formattedInt}${decimalSeparator}${decPart}`;\n } else {\n const intPart = rounded.toString();\n result = intPart.replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n }\n } else {\n const intAmount = Math.floor(absAmount);\n result = intAmount.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n }\n\n if (symbol) {\n const space = spaceAfterSymbol ? ' ' : '';\n if (isNegative) {\n result = `-Rp${space}${result}`;\n } else {\n result = `Rp${space}${result}`;\n }\n } else if (isNegative) {\n result = `-${result}`;\n }\n\n return result;\n}\n\n/**\n * Formats a number in compact Indonesian format.\n *\n * Uses Indonesian units: ribu, juta, miliar, triliun.\n * Follows Indonesian grammar rules (e.g., \"1 juta\" not \"1,0 juta\").\n *\n * @param amount - The amount to format\n * @param options - Compact formatting options\n * @returns Compact formatted string\n *\n * @example\n * Millions:\n * ```typescript\n * formatCompact(1500000); // 'Rp 1,5 juta'\n * formatCompact(1000000); // 'Rp 1 juta'\n * ```\n *\n * @example\n * Thousands:\n * ```typescript\n * formatCompact(500000); // 'Rp 500 ribu'\n * ```\n *\n * @example\n * Small numbers:\n * ```typescript\n * formatCompact(1500); // 'Rp 1.500'\n * ```\n *\n * @example\n * Without symbol:\n * ```typescript\n * formatCompact(1500000, { symbol: false }); // '1,5 juta'\n * ```\n *\n * @public\n */\nexport function formatCompact(\n amount: number,\n options?: CompactOptions\n): string {\n const { symbol = true, spaceAfterSymbol = true } = options || {};\n\n const isNegative = amount < 0 && amount !== 0;\n const abs = Math.abs(amount);\n\n let result: string;\n\n if (abs >= 1_000_000_000_000) {\n result = formatCompactValue(abs / 1_000_000_000_000, 'triliun');\n } else if (abs >= 1_000_000_000) {\n result = formatCompactValue(abs / 1_000_000_000, 'miliar');\n } else if (abs >= 1_000_000) {\n result = formatCompactValue(abs / 1_000_000, 'juta');\n } else if (abs >= 100_000) {\n result = formatCompactValue(abs / 1000, 'ribu');\n } else if (abs >= 1_000) {\n result = abs.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.');\n } else {\n result = abs.toString();\n }\n\n if (symbol) {\n const space = spaceAfterSymbol ? ' ' : '';\n if (isNegative) {\n result = `-Rp${space}${result}`;\n } else {\n result = `Rp${space}${result}`;\n }\n } else if (isNegative) {\n result = `-${result}`;\n }\n\n return result;\n}\n\n/**\n * Formats a value with Indonesian unit, applying grammar rules.\n *\n * Automatically removes trailing \".0\" to follow proper Indonesian grammar.\n * For example: \"1 juta\" instead of \"1,0 juta\".\n *\n * @param value - The numeric value to format\n * @param unit - The Indonesian unit (ribu, juta, miliar, triliun)\n * @returns Formatted string with unit\n * @internal\n */\nfunction formatCompactValue(value: number, unit: string): string {\n const rounded = Math.round(value * 10) / 10;\n\n if (rounded % 1 === 0) {\n return `${rounded.toFixed(0)} ${unit}`;\n }\n\n return `${rounded.toString().replace('.', ',')} ${unit}`;\n}\n","/**\n * Currency parsing utilities for Indonesian Rupiah.\n *\n * @module currency/parse\n * @packageDocumentation\n */\n\n/**\n * Parses a formatted Rupiah string back to a number.\n *\n * Handles multiple formats:\n * - Standard: \"Rp 1.500.000\"\n * - No symbol: \"1.500.000\"\n * - With decimals: \"Rp 1.500.000,50\"\n * - Compact: \"Rp 1,5 juta\", \"Rp 500 ribu\"\n *\n * @param formatted - The formatted Rupiah string to parse\n * @returns Parsed number, or null if invalid\n *\n * @example\n * Standard format:\n * ```typescript\n * parseRupiah('Rp 1.500.000'); // 1500000\n * ```\n *\n * @example\n * With decimals:\n * ```typescript\n * parseRupiah('Rp 1.500.000,50'); // 1500000.50\n * ```\n *\n * @example\n * Compact format:\n * ```typescript\n * parseRupiah('Rp 1,5 juta'); // 1500000\n * parseRupiah('Rp 500 ribu'); // 500000\n * ```\n *\n * @example\n * Invalid input:\n * ```typescript\n * parseRupiah('invalid'); // null\n * ```\n *\n * @public\n */\nexport function parseRupiah(formatted: string): number | null {\n if (!formatted || typeof formatted !== 'string') {\n return null;\n }\n\n const cleaned = formatted.trim().toLowerCase();\n\n // Check for compact units (juta, ribu, miliar, triliun)\n const compactUnits = {\n triliun: 1_000_000_000_000,\n miliar: 1_000_000_000,\n juta: 1_000_000,\n ribu: 1_000,\n };\n\n for (const [unit, multiplier] of Object.entries(compactUnits)) {\n if (cleaned.includes(unit)) {\n const match = cleaned.match(/(-?\\d+[,.]?\\d*)/);\n if (match) {\n const num = parseFloat(match[1].replace(',', '.'));\n return num * multiplier;\n }\n }\n }\n\n // Standard format: remove 'Rp' and spaces\n let numStr = cleaned.replace(/rp/gi, '').trim();\n\n const hasDot = numStr.includes('.');\n const hasComma = numStr.includes(',');\n\n if (hasDot && hasComma) {\n // Determine format based on last separator position\n // Indonesian: 1.500.000,50 vs International: 1,500,000.50\n const lastDot = numStr.lastIndexOf('.');\n const lastComma = numStr.lastIndexOf(',');\n\n if (lastComma > lastDot) {\n numStr = numStr.replace(/\\./g, '').replace(',', '.');\n } else {\n numStr = numStr.replace(/,/g, '');\n }\n } else if (hasComma) {\n const parts = numStr.split(',');\n // Decimal if only 1-2 digits after comma\n if (parts.length === 2 && parts[1].length <= 2) {\n numStr = numStr.replace(',', '.');\n } else {\n numStr = numStr.replace(/,/g, '');\n }\n } else if (hasDot) {\n const parts = numStr.split('.');\n // If not decimal format, remove dots (thousands separator)\n if (parts.length > 2 || (parts.length === 2 && parts[1].length > 2)) {\n numStr = numStr.replace(/\\./g, '');\n }\n }\n\n const parsed = parseFloat(numStr);\n return isNaN(parsed) ? null : parsed;\n}\n","/**\n * Convert numbers to Indonesian words (terbilang).\n *\n * @module currency/words\n * @packageDocumentation\n */\n\nimport type { WordOptions } from './types';\n\n/**\n * Basic Indonesian number words (0-9).\n * @internal\n */\nconst BASIC_NUMBERS = [\n '',\n 'satu',\n 'dua',\n 'tiga',\n 'empat',\n 'lima',\n 'enam',\n 'tujuh',\n 'delapan',\n 'sembilan',\n];\n\n/**\n * Indonesian words for 10-19.\n * @internal\n */\nconst TEENS = [\n 'sepuluh',\n 'sebelas',\n 'dua belas',\n 'tiga belas',\n 'empat belas',\n 'lima belas',\n 'enam belas',\n 'tujuh belas',\n 'delapan belas',\n 'sembilan belas',\n];\n\n/**\n * Indonesian words for tens (20, 30, 40, etc).\n * @internal\n */\nconst TENS = [\n '',\n '',\n 'dua puluh',\n 'tiga puluh',\n 'empat puluh',\n 'lima puluh',\n 'enam puluh',\n 'tujuh puluh',\n 'delapan puluh',\n 'sembilan puluh',\n];\n\n/**\n * Converts a number to Indonesian words (terbilang).\n *\n * Supports numbers up to trillions (triliun).\n * Follows Indonesian language rules for number pronunciation.\n *\n * Special rules:\n * - 1 = \"satu\" in most cases, but \"se-\" for 100, 1000\n * - 11 = \"sebelas\" (not \"satu belas\")\n * - 100 = \"seratus\" (not \"satu ratus\")\n * - 1000 = \"seribu\" (not \"satu ribu\")\n *\n * @param amount - The number to convert\n * @param options - Conversion options\n * @returns Indonesian words representation\n *\n * @example\n * Basic numbers:\n * ```typescript\n * toWords(123); // 'seratus dua puluh tiga rupiah'\n * ```\n *\n * @example\n * Large numbers:\n * ```typescript\n * toWords(1500000); // 'satu juta lima ratus ribu rupiah'\n * ```\n *\n * @example\n * With options:\n * ```typescript\n * toWords(1500000, { uppercase: true });\n * // 'Satu juta lima ratus ribu rupiah'\n *\n * toWords(1500000, { withCurrency: false });\n * // 'satu juta lima ratus ribu'\n * ```\n *\n * @public\n */\nexport function toWords(amount: number, options?: WordOptions): string {\n const {\n uppercase = false,\n withCurrency = true,\n withDecimals = false,\n } = options || {};\n\n if (amount === 0) {\n let result = 'nol';\n if (withCurrency) result += ' rupiah';\n return uppercase ? capitalize(result) : result;\n }\n\n const isNegative = amount < 0;\n const absAmount = Math.abs(amount);\n const intPart = Math.floor(absAmount);\n\n let words = convertInteger(intPart);\n\n if (isNegative) {\n words = 'minus ' + words;\n }\n\n if (withCurrency) {\n words += ' rupiah';\n }\n\n if (withDecimals) {\n const decimalPart = Math.round((absAmount - intPart) * 100);\n if (decimalPart > 0) {\n words += ' koma ' + convertDecimal(decimalPart);\n }\n }\n\n return uppercase ? capitalize(words) : words;\n}\n\n/**\n * Converts the integer part to Indonesian words.\n */\nfunction convertInteger(num: number): string {\n if (num === 0) return 'nol';\n\n let words = '';\n\n const triliun = Math.floor(num / 1_000_000_000_000);\n const miliar = Math.floor((num % 1_000_000_000_000) / 1_000_000_000);\n const juta = Math.floor((num % 1_000_000_000) / 1_000_000);\n const ribu = Math.floor((num % 1_000_000) / 1_000);\n const sisa = num % 1_000;\n\n if (triliun > 0) {\n words += convertGroup(triliun) + ' triliun';\n }\n\n if (miliar > 0) {\n if (words) words += ' ';\n words += convertGroup(miliar) + ' miliar';\n }\n\n if (juta > 0) {\n if (words) words += ' ';\n words += convertGroup(juta) + ' juta';\n }\n\n if (ribu > 0) {\n if (words) words += ' ';\n words += ribu === 1 ? 'seribu' : convertGroup(ribu) + ' ribu';\n }\n\n if (sisa > 0) {\n if (words) words += ' ';\n words += convertGroup(sisa);\n }\n\n return words;\n}\n\n/**\n * Converts decimal part (0-99) to Indonesian words.\n */\nfunction convertDecimal(num: number): string {\n if (num === 0) return '';\n if (num < 10) return BASIC_NUMBERS[num];\n if (num < 20) return TEENS[num - 10];\n\n const tens = Math.floor(num / 10);\n const ones = num % 10;\n\n let result = TENS[tens];\n if (ones > 0) {\n result += ' ' + BASIC_NUMBERS[ones];\n }\n\n return result;\n}\n\n/**\n * Converts a group of 1-3 digits (0-999) to Indonesian words.\n *\n * @param num - Number to convert (0-999)\n * @returns Indonesian words for the number\n * @internal\n */\nfunction convertGroup(num: number): string {\n if (num === 0) return '';\n\n let result = '';\n\n const hundreds = Math.floor(num / 100);\n if (hundreds > 0) {\n // Special rule: 100 = \"seratus\" not \"satu ratus\"\n result = hundreds === 1 ? 'seratus' : BASIC_NUMBERS[hundreds] + ' ratus';\n }\n\n const remainder = num % 100;\n if (remainder > 0) {\n if (result) result += ' ';\n result += convertTwoDigits(remainder);\n }\n\n return result;\n}\n\n/**\n * Converts numbers 1-99 to Indonesian words.\n *\n * @param num - Number to convert (1-99)\n * @returns Indonesian words for the number\n * @internal\n */\nfunction convertTwoDigits(num: number): string {\n if (num === 0) return '';\n if (num < 10) return BASIC_NUMBERS[num];\n if (num >= 10 && num < 20) return TEENS[num - 10];\n\n const tens = Math.floor(num / 10);\n const ones = num % 10;\n\n let result = TENS[tens];\n if (ones > 0) {\n result += ' ' + BASIC_NUMBERS[ones];\n }\n\n return result;\n}\n\n/**\n * Capitalizes the first letter of a string.\n *\n * @param str - String to capitalize\n * @returns String with first letter capitalized\n * @internal\n */\nfunction capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n","/**\n * Currency utility functions.\n *\n * @module currency/utils\n * @packageDocumentation\n */\n\nimport { formatRupiah } from './format';\nimport type { RoundUnit, RupiahOptions } from './types';\n\n/**\n * Rounds a number to a clean currency amount.\n *\n * Common use case: displaying approximate prices or budgets\n * in clean, rounded numbers.\n *\n * @param amount - The amount to round\n * @param unit - The unit to round to (default: 'ribu')\n * @returns Rounded amount\n *\n * @example\n * Round to thousands:\n * ```typescript\n * roundToClean(1234567, 'ribu'); // 1235000\n * ```\n *\n * @example\n * Round to hundred thousands:\n * ```typescript\n * roundToClean(1234567, 'ratus-ribu'); // 1200000\n * ```\n *\n * @example\n * Round to millions:\n * ```typescript\n * roundToClean(1234567, 'juta'); // 1000000\n * ```\n *\n * @public\n */\nexport function roundToClean(amount: number, unit: RoundUnit = 'ribu'): number {\n const divisors: Record<RoundUnit, number> = {\n ribu: 1000,\n 'ratus-ribu': 100000,\n juta: 1000000,\n };\n\n const divisor = divisors[unit];\n\n // Math.round handles both positive and negative numbers\n return Math.round(amount / divisor) * divisor;\n}\n\n/**\n * Formats a number as Indonesian Rupiah in accounting style.\n * Negative numbers are wrapped in parentheses.\n *\n * @param amount - The amount to format\n * @param options - Formatting options\n * @returns Formatted accounting string\n *\n * @example\n * ```typescript\n * formatAccounting(-1500000); // '(Rp 1.500.000)'\n * ```\n */\nexport function formatAccounting(\n amount: number,\n options?: RupiahOptions\n): string {\n const isNegative = amount < 0;\n const formatted = formatRupiah(Math.abs(amount), options);\n\n if (isNegative) {\n return `(${formatted})`;\n }\n\n return formatted;\n}\n\n/**\n * Calculates tax (PPN) for a given amount.\n *\n * @param amount - The base amount\n * @param rate - The tax rate (e.g., 0.11 for 11% PPN)\n * @returns The calculated tax amount\n *\n * @example\n * ```typescript\n * calculateTax(1000000, 0.11); // 110000\n * ```\n */\nexport function calculateTax(amount: number, rate: number): number {\n return amount * rate;\n}\n\n/**\n * Helper to ensure a string or number has the 'Rp ' prefix.\n * If already prefixed, it returns the input as is.\n *\n * @param amount - The amount or formatted string\n * @returns String with Rupiah prefix\n */\nexport function addRupiahSymbol(amount: string | number): string {\n if (typeof amount === 'number') {\n const formatted = amount.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.');\n return `Rp ${formatted}`;\n }\n\n if (amount.trim().startsWith('Rp')) {\n return amount.trim();\n }\n\n return `Rp ${amount.trim()}`;\n}\n","/**\n * ============================================================================\n * INDONESIAN TEXT UTILITIES - CONSTANTS\n * ============================================================================\n *\n * This file contains constants for Indonesian and English text processing:\n * - LOWERCASE_WORDS: Particles that stay lowercase in title case\n * - ACRONYMS: Abbreviations that stay UPPERCASE in title case\n * - ABBREVIATIONS: Full expansions of common Indonesian abbreviations\n *\n * ============================================================================\n * MAINTENANCE GUIDE\n * ============================================================================\n *\n * ## How to Add New Entries\n *\n * ### 1. LOWERCASE_WORDS (Particles)\n *\n * Add words that should remain lowercase in title case (except when first word).\n *\n * **Indonesian Grammar Rules (PUEBI):**\n * - Prepositions: di, ke, dari, untuk, dengan, pada, dalam, etc.\n * - Conjunctions: dan, atau, tetapi, serta, maupun, etc.\n * - Articles/particles: yang, sebagai, adalah, akan, telah, etc.\n *\n * **English Grammar Rules (Chicago Manual of Style):**\n * - Articles: a, an, the\n * - Conjunctions: and, or, but, nor, for, yet, so\n * - Short prepositions (<5 letters): at, by, in, of, on, to, up, etc.\n *\n * **Example Addition:**\n * ```typescript\n * export const LOWERCASE_WORDS = [\n * // ... existing entries\n * 'bagi', // Indonesian: for/to (preposition)\n * 'antara', // Indonesian: between (preposition)\n * 'into', // English: preposition\n * ] as const;\n * ```\n *\n * **Testing:** Add test case in `toTitleCase.test.ts`:\n * ```typescript\n * it('keeps \"bagi\" lowercase in middle', () => {\n * expect(toTitleCase('buku bagi pemula')).toBe('Buku bagi Pemula');\n * });\n * ```\n *\n * ### 2. ACRONYMS (Always Uppercase)\n *\n * Add abbreviations that should always appear in UPPERCASE.\n *\n * **Categories:**\n * - Government & Military: TNI, POLRI, KPK, DPR, etc.\n * - Business Entities: PT, CV, BUMN, etc.\n * - Banks: BCA, BRI, BNI, etc.\n * - Services: BPJS, PLN, KTP, SIM, etc.\n * - Technology: IT, AI, API, SEO, etc.\n * - Education: UI, ITB, UGM, etc.\n * - International: UN, WHO, NATO, ASEAN, etc.\n *\n * **Validation Checklist:**\n * ✅ Is it commonly written in ALL CAPS?\n * ✅ Is it an official acronym (not just shortened word)?\n * ✅ Will it look wrong if title-cased (e.g., \"Pt\" instead of \"PT\")?\n *\n * **Example Addition:**\n * ```typescript\n * export const ACRONYMS = [\n * // ... existing entries\n * 'OJK', // Otoritas Jasa Keuangan\n * 'BI', // Bank Indonesia\n * 'NASA', // National Aeronautics and Space Administration\n * ] as const;\n * ```\n *\n * **Testing:** Add test case in `toTitleCase.test.ts`:\n * ```typescript\n * it('preserves OJK uppercase', () => {\n * expect(toTitleCase('ojk indonesia')).toBe('OJK Indonesia');\n * });\n * ```\n *\n * ### 3. ABBREVIATIONS (Expansion Mapping)\n *\n * Add abbreviation → full form mappings for `expandAbbreviation()` function.\n *\n * **Categories (use comment headers):**\n * - Address: Jl., Gg., Kec., Kab., etc.\n * - Academic Titles: Dr., Ir., Prof., S.H., M.M., etc.\n * - Honorifics: Bpk., Yth., H., Hj., etc.\n * - Organizations: PT., CV., UD., etc.\n * - Common: dst., dll., a.n., etc.\n * - Contact Info: Tlp., HP., Fax, etc.\n * - Days/Months: Sen., Jan., Feb., etc.\n * - Units: kg., km., lt., etc.\n *\n * **Key Format Rules:**\n * - Include period if commonly written: `'Jl.'` not `'Jl'`\n * - Use proper capitalization: `'Jalan'` not `'jalan'`\n * - Keep it concise: Full form only, no explanations\n *\n * **Example Addition:**\n * ```typescript\n * export const ABBREVIATIONS: Record<string, string> = {\n * // ... existing entries\n *\n * // ========== New Category Example ==========\n * 'Apt.': 'Apartemen',\n * 'Ruko': 'Rumah Toko',\n * 'Rukan': 'Rumah Kantor',\n * };\n * ```\n *\n * **Testing:** Add test case in `abbreviation.test.ts`:\n * ```typescript\n * it('expands Apt. to Apartemen', () => {\n * expect(expandAbbreviation('Apt. Sudirman'))\n * .toBe('Apartemen Sudirman');\n * });\n * ```\n *\n * ============================================================================\n * DATA SOURCES & REFERENCES\n * ============================================================================\n *\n * When adding new entries, refer to these authoritative sources:\n *\n * **Indonesian Language:**\n * - PUEBI (Pedoman Umum Ejaan Bahasa Indonesia)\n * https://puebi.js.org/\n *\n * - KBBI (Kamus Besar Bahasa Indonesia)\n * https://kbbi.kemdikbud.go.id/\n *\n * - Wikipedia Indonesia - Daftar Singkatan\n * https://id.wikipedia.org/wiki/Daftar_singkatan_di_Indonesia\n *\n * **English Language:**\n * - Chicago Manual of Style (Title Case Rules)\n * https://www.chicagomanualofstyle.org/\n *\n * - AP Stylebook\n * https://www.apstylebook.com/\n *\n * **Government & Official:**\n * - Kemendagri (addresses, administrative divisions)\n * https://www.kemendagri.go.id/\n *\n * - Kemenkumham (business entities)\n * https://www.kemenkumham.go.id/\n *\n * - Kemendikbud (education, degrees)\n * https://www.kemdikbud.go.id/\n *\n * ============================================================================\n * CONTRIBUTION GUIDELINES\n * ============================================================================\n *\n * **Before Adding:**\n * 1. ✅ Check if entry already exists (Ctrl+F)\n * 2. ✅ Verify spelling from official sources\n * 3. ✅ Ensure it's commonly used (not obscure)\n * 4. ✅ Choose correct category/section\n *\n * **After Adding:**\n * 1. ✅ Add corresponding test case\n * 2. ✅ Run tests: `npm test constants`\n * 3. ✅ Update this file's documentation if needed\n * 4. ✅ Add source reference in PR description\n *\n * **PR Template:**\n * ```\n * ### Added Constants\n *\n * **Type:** [LOWERCASE_WORDS | ACRONYMS | ABBREVIATIONS]\n *\n * **Entries:**\n * - `OJK` - Otoritas Jasa Keuangan\n * - `BI` - Bank Indonesia\n *\n * **Source:** https://www.ojk.go.id/\n *\n * **Test Coverage:** ✅ Added in toTitleCase.test.ts line 245\n *\n * **Rationale:**\n * Commonly used financial regulatory bodies in Indonesian context.\n * ```\n *\n * ============================================================================\n * COMMON PITFALLS TO AVOID\n * ============================================================================\n *\n * ❌ **Don't add brand-specific styling** (e.g., \"iPhone\" → keep user control)\n * ❌ **Don't add regional dialects** (stick to standard Indonesian/English)\n * ❌ **Don't add context-dependent acronyms** (e.g., \"UI\" = both User Interface & Universitas Indonesia)\n * ❌ **Don't add very rare/obscure terms** (focus on common usage)\n * ❌ **Don't forget the period** in ABBREVIATIONS (e.g., use `'Dr.'` not `'Dr'`)\n * ❌ **Don't mix singular/plural** in ABBREVIATIONS (choose one consistently)\n *\n * ✅ **Do keep entries alphabetically sorted** within categories\n * ✅ **Do use proper capitalization** in expanded forms\n * ✅ **Do add comments** for non-obvious entries\n * ✅ **Do verify against official sources** before adding\n * ✅ **Do write test cases** for new additions\n *\n * ============================================================================\n * FUTURE EXTENSIBILITY\n * ============================================================================\n *\n * **Planned Enhancements:**\n *\n * 1. **External Data Source Support:**\n * ```typescript\n * import customAcronyms from './data/custom-acronyms.json';\n * export const ACRONYMS = [...DEFAULT_ACRONYMS, ...customAcronyms];\n * ```\n *\n * 2. **Context-Aware Acronyms:**\n * ```typescript\n * export const CONTEXT_ACRONYMS = {\n * 'UI': {\n * tech: 'UI', // User Interface\n * education: 'UI', // Universitas Indonesia\n * }\n * };\n * ```\n *\n * 3. **Locale-Specific Sets:**\n * ```typescript\n * export const LOWERCASE_WORDS = {\n * id: [...], // Indonesian\n * en: [...], // English\n * mixed: [...], // Combined (default)\n * };\n * ```\n *\n * 4. **Dynamic Loading:**\n * ```typescript\n * // Load additional acronyms from user config\n * export async function loadCustomConstants(url: string) {\n * const data = await fetch(url).then(r => r.json());\n * return [...ACRONYMS, ...data.acronyms];\n * }\n * ```\n *\n * ============================================================================\n * VERSIONING & CHANGELOG\n * ============================================================================\n *\n * Track major additions here:\n *\n * - v0.2.0 (2024-12-18): Initial comprehensive dataset\n * - 50+ Indonesian particles\n * - 150+ acronyms (Indonesian + International)\n * - 80+ abbreviation mappings\n *\n * - v0.2.1 (TBD): Add financial sector acronyms (OJK, BI, etc.)\n * - v0.2.2 (TBD): Add technology company acronyms\n *\n * ============================================================================\n */\n\n/**\n * Indonesian and English lowercase particles\n * These words remain lowercase in title case (except when first word)\n *\n * Based on:\n * - Indonesian grammar (PUEBI)\n * - English title case rules (Chicago Manual of Style)\n */\nexport const LOWERCASE_WORDS = [\n // Indonesian prepositions (kata depan)\n 'di',\n 'ke',\n 'dari',\n 'pada',\n 'dalam',\n 'untuk',\n 'dengan',\n 'oleh',\n 'kepada',\n 'terhadap',\n 'tentang',\n 'tanpa',\n 'hingga',\n 'sampai',\n 'sejak',\n 'menuju',\n 'melalui',\n\n // Indonesian conjunctions (kata hubung)\n 'dan',\n 'atau',\n 'tetapi',\n 'namun',\n 'serta',\n 'maupun',\n 'melainkan',\n 'sedangkan',\n\n // Indonesian articles/particles\n 'yang',\n 'sebagai',\n 'adalah',\n 'ialah',\n 'yaitu',\n 'bahwa',\n 'akan',\n 'telah',\n 'sudah',\n 'belum',\n\n // English articles\n 'a',\n 'an',\n 'the',\n\n // English conjunctions\n 'and',\n 'or',\n 'but',\n 'nor',\n 'for',\n 'yet',\n 'so',\n 'as',\n\n // English prepositions (short ones, < 5 letters)\n 'at',\n 'by',\n 'in',\n 'of',\n 'on',\n 'to',\n 'up',\n 'via',\n 'per',\n 'off',\n 'out',\n\n // English prepositions (5+ letters - optional, some style guides capitalize these)\n // 'about',\n // 'above',\n // 'across',\n // 'after',\n // 'among',\n // 'below',\n // 'under',\n // 'until',\n // 'with',\n] as const;\n\n/**\n * Indonesian and international acronyms\n * These always remain UPPERCASE in title case\n */\nexport const ACRONYMS = [\n // Indonesian government & military\n 'DKI', // Daerah Khusus Ibukota\n 'DIY', // Daerah Istimewa Yogyakarta\n 'TNI', // Tentara Nasional Indonesia\n 'POLRI', // Kepolisian Republik Indonesia\n 'ABRI', // Angkatan Bersenjata Republik Indonesia\n 'MPR', // Majelis Permusyawaratan Rakyat\n 'DPR', // Dewan Perwakilan Rakyat\n 'KPK', // Komisi Pemberantasan Korupsi\n 'BIN', // Badan Intelijen Negara\n\n // Indonesian business entities\n 'PT', // Perseroan Terbatas\n 'CV', // Commanditaire Vennootschap\n 'UD', // Usaha Dagang\n 'PD', // Perusahaan Daerah\n 'Tbk', // Terbuka (publicly traded)\n 'BUMN', // Badan Usaha Milik Negara\n 'BUMD', // Badan Usaha Milik Daerah\n\n // Indonesian banks\n 'BCA', // Bank Central Asia\n 'BRI', // Bank Rakyat Indonesia\n 'BNI', // Bank Negara Indonesia\n 'BTN', // Bank Tabungan Negara\n 'BSI', // Bank Syariah Indonesia\n 'BPD', // Bank Pembangunan Daerah\n\n // Indonesian government services\n 'KTP', // Kartu Tanda Penduduk\n 'NIK', // Nomor Induk Kependudukan\n 'NPWP', // Nomor Pokok Wajib Pajak\n 'SIM', // Surat Izin Mengemudi\n 'STNK', // Surat Tanda Nomor Kendaraan\n 'BPJS', // Badan Penyelenggara Jaminan Sosial\n 'KIS', // Kartu Indonesia Sehat\n 'KIP', // Kartu Indonesia Pintar\n 'PKH', // Program Keluarga Harapan\n\n // Indonesian utilities & infrastructure\n 'PLN', // Perusahaan Listrik Negara\n 'PDAM', // Perusahaan Daerah Air Minum\n 'PGN', // Perusahaan Gas Negara\n 'KAI', // Kereta Api Indonesia\n 'MRT', // Mass Rapid Transit\n 'LRT', // Light Rail Transit\n\n // Indonesian taxes & fees\n 'PBB', // Pajak Bumi dan Bangunan\n 'PPh', // Pajak Penghasilan\n 'PPN', // Pajak Pertambahan Nilai\n 'BPHTB', // Bea Perolehan Hak atas Tanah dan Bangunan\n\n // Indonesian education\n 'UI', // Universitas Indonesia\n 'ITB', // Institut Teknologi Bandung\n 'UGM', // Universitas Gadjah Mada\n 'IPB', // Institut Pertanian Bogor\n 'ITS', // Institut Teknologi Sepuluh Nopember\n 'UNPAD', // Universitas Padjadjaran\n 'UNDIP', // Universitas Diponegoro\n 'UNAIR', // Universitas Airlangga\n 'UNS', // Universitas Sebelas Maret\n\n // Indonesian degrees (gelar)\n 'S.Pd', // Sarjana Pendidikan\n 'S.H', // Sarjana Hukum\n 'S.E', // Sarjana Ekonomi\n 'S.T', // Sarjana Teknik\n 'S.Kom', // Sarjana Komputer\n 'S.Si', // Sarjana Sains\n 'S.Sos', // Sarjana Sosial\n 'M.Pd', // Magister Pendidikan\n 'M.M', // Magister Manajemen\n 'M.T', // Magister Teknik\n 'M.Kom', // Magister Komputer\n\n // Common services\n 'ATM', // Automated Teller Machine\n 'POS', // Point of Sale\n 'SMS', // Short Message Service\n 'GPS', // Global Positioning System\n 'WiFi', // Wireless Fidelity (technically Wi-Fi)\n 'USB', // Universal Serial Bus\n 'PIN', // Personal Identification Number\n 'OTP', // One Time Password\n 'QR', // Quick Response\n\n // Technology & IT\n 'IT', // Information Technology\n 'AI', // Artificial Intelligence\n 'ML', // Machine Learning\n 'API', // Application Programming Interface\n 'UI', // User Interface (duplicate with Universitas Indonesia, context matters)\n 'UX', // User Experience\n 'SEO', // Search Engine Optimization\n 'SaaS', // Software as a Service\n 'CRM', // Customer Relationship Management\n 'ERP', // Enterprise Resource Planning\n\n // Business titles\n 'CEO', // Chief Executive Officer\n 'CFO', // Chief Financial Officer\n 'CTO', // Chief Technology Officer\n 'COO', // Chief Operating Officer\n 'CMO', // Chief Marketing Officer\n 'HR', // Human Resources\n 'PR', // Public Relations\n 'VP', // Vice President\n 'GM', // General Manager\n\n // International organizations\n 'UN', // United Nations\n 'WHO', // World Health Organization\n 'UNESCO', // United Nations Educational, Scientific and Cultural Organization\n 'NATO', // North Atlantic Treaty Organization\n 'ASEAN', // Association of Southeast Asian Nations\n 'APEC', // Asia-Pacific Economic Cooperation\n 'WTO', // World Trade Organization\n 'IMF', // International Monetary Fund\n\n // Medical\n 'ICU', // Intensive Care Unit\n 'ER', // Emergency Room\n 'MRI', // Magnetic Resonance Imaging\n 'CT', // Computed Tomography\n 'DNA', // Deoxyribonucleic Acid\n 'RNA', // Ribonucleic Acid\n 'HIV', // Human Immunodeficiency Virus\n 'AIDS', // Acquired Immunodeficiency Syndrome\n 'COVID', // Coronavirus Disease\n\n // Measurements & units\n 'KM', // Kilometer\n 'CM', // Centimeter\n 'MM', // Millimeter\n 'KG', // Kilogram\n 'RPM', // Revolutions Per Minute\n 'MPH', // Miles Per Hour\n 'KPH', // Kilometers Per Hour\n\n // Finance\n 'IPO', // Initial Public Offering\n 'ATM', // Automated Teller Machine (duplicate)\n 'ROI', // Return on Investment\n 'GDP', // Gross Domestic Product\n 'VAT', // Value Added Tax\n] as const;\n\n/**\n * Indonesian abbreviations mapping\n * Organized by category for maintainability\n */\nexport const ABBREVIATIONS: Record<string, string> = {\n // ========== Address Abbreviations ==========\n 'Jl.': 'Jalan',\n 'Gg.': 'Gang',\n 'No.': 'Nomor',\n 'Kp.': 'Kampung',\n 'Ds.': 'Desa',\n 'Kel.': 'Kelurahan',\n 'Kec.': 'Kecamatan',\n 'Kab.': 'Kabupaten',\n Kota: 'Kota',\n 'Prov.': 'Provinsi',\n 'Prop.': 'Provinsi',\n 'Rt.': 'Rukun Tetangga',\n 'Rw.': 'Rukun Warga',\n Blok: 'Blok',\n 'Komp.': 'Kompleks',\n Perumahan: 'Perumahan',\n 'Perum.': 'Perumahan',\n\n // ========== Academic Titles ==========\n 'Dr.': 'Doktor',\n 'Ir.': 'Insinyur',\n 'Prof.': 'Profesor',\n 'Drs.': 'Doktorandus',\n 'Dra.': 'Doktoranda',\n\n // Bachelor degrees\n 'S.Pd.': 'Sarjana Pendidikan',\n 'S.H.': 'Sarjana Hukum',\n 'S.E.': 'Sarjana Ekonomi',\n 'S.T.': 'Sarjana Teknik',\n 'S.Kom.': 'Sarjana Komputer',\n 'S.Si.': 'Sarjana Sains',\n 'S.Sos.': 'Sarjana Sosial',\n 'S.I.Kom.': 'Sarjana Ilmu Komunikasi',\n 'S.S.': 'Sarjana Sastra',\n 'S.Psi.': 'Sarjana Psikologi',\n 'S.Farm.': 'Sarjana Farmasi',\n 'S.Ked.': 'Sarjana Kedokteran',\n\n // Master degrees\n 'M.Sc.': 'Master of Science',\n 'M.M.': 'Magister Manajemen',\n 'M.Pd.': 'Magister Pendidikan',\n 'M.T.': 'Magister Teknik',\n 'M.Kom.': 'Magister Komputer',\n 'M.Si.': 'Magister Sains',\n 'M.H.': 'Magister Hukum',\n 'M.A.': 'Master of Arts',\n MBA: 'Master of Business Administration',\n\n // ========== Honorifics ==========\n 'Bpk.': 'Bapak',\n Ibu: 'Ibu',\n 'Sdr.': 'Saudara',\n 'Sdri.': 'Saudari',\n 'Yth.': 'Yang Terhormat',\n 'H.': 'Haji',\n 'Hj.': 'Hajjah',\n 'Tn.': 'Tuan',\n 'Ny.': 'Nyonya',\n 'Nn.': 'Nona',\n\n // ========== Organizations ==========\n 'PT.': 'Perseroan Terbatas',\n 'CV.': 'Commanditaire Vennootschap',\n 'UD.': 'Usaha Dagang',\n 'PD.': 'Perusahaan Daerah',\n 'Tbk.': 'Terbuka',\n Koperasi: 'Koperasi',\n Yayasan: 'Yayasan',\n\n // ========== Common Abbreviations ==========\n 'dst.': 'dan seterusnya',\n 'dsb.': 'dan sebagainya',\n 'dll.': 'dan lain-lain',\n 'dkk.': 'dan kawan-kawan',\n 'a.n.': 'atas nama',\n 'u.p.': 'untuk perhatian',\n 'u.b.': 'untuk beliau',\n 'c.q.': 'casu quo',\n 'hlm.': 'halaman',\n 'tgl.': 'tanggal',\n 'bln.': 'bulan',\n 'thn.': 'tahun',\n 'ttd.': 'tertanda',\n\n // ========== Contact Information ==========\n 'Tlp.': 'Telepon',\n 'Telp.': 'Telepon',\n 'HP.': 'Handphone',\n Fax: 'Faksimile',\n Email: 'Email',\n Website: 'Website',\n\n // ========== Days (Indonesian) ==========\n 'Sen.': 'Senin',\n 'Sel.': 'Selasa',\n 'Rab.': 'Rabu',\n 'Kam.': 'Kamis',\n 'Jum.': 'Jumat',\n 'Sab.': 'Sabtu',\n 'Min.': 'Minggu',\n\n // ========== Months (Indonesian) ==========\n 'Jan.': 'Januari',\n 'Feb.': 'Februari',\n 'Mar.': 'Maret',\n 'Apr.': 'April',\n Mei: 'Mei',\n 'Jun.': 'Juni',\n 'Jul.': 'Juli',\n 'Agt.': 'Agustus',\n 'Sep.': 'September',\n 'Okt.': 'Oktober',\n 'Nov.': 'November',\n 'Des.': 'Desember',\n\n // ========== Units & Measurements ==========\n 'kg.': 'kilogram',\n 'gr.': 'gram',\n 'lt.': 'liter',\n 'ml.': 'mililiter',\n 'km.': 'kilometer',\n 'cm.': 'sentimeter',\n 'mm.': 'milimeter',\n 'm2.': 'meter persegi',\n 'm3.': 'meter kubik',\n 'ha.': 'hektar',\n};\n\n/**\n * Common Indonesian profanity/swear words for filtering.\n * This is a basic set for simple masking.\n */\nexport const PROFANITY = [\n 'anjing',\n 'babi',\n 'bangsat',\n 'bajingan',\n 'brengsek',\n 'goblok',\n 'tolol',\n 'idiot',\n 'perek',\n 'jablay',\n 'kontol',\n 'memek',\n 'ngewe',\n 'puki',\n 'jembut',\n 'asu',\n 'itil',\n 'lanjiao',\n 'pantek',\n 'anying',\n 'anjrit',\n] as const;\n\n/**\n * Common Indonesian stopwords for removal.\n */\nexport const STOPWORDS = [\n 'ada',\n 'adalah',\n 'adanya',\n 'adapun',\n 'agak',\n 'agaknya',\n 'agar',\n 'akan',\n 'akankah',\n 'akhir',\n 'akhiri',\n 'akhirnya',\n 'aku',\n 'akulah',\n 'amat',\n 'amatlah',\n 'anda',\n 'andalah',\n 'antar',\n 'antara',\n 'antaranya',\n 'apa',\n 'apaan',\n 'apabila',\n 'apakah',\n 'apalagi',\n 'apatah',\n 'artinya',\n 'asal',\n 'asalkan',\n 'atas',\n 'atau',\n 'ataukah',\n 'ataupun',\n 'awal',\n 'awalnya',\n 'bagai',\n 'bagaikan',\n 'bagaimana',\n 'bagaimanakah',\n 'bagaimanapun',\n 'bagi',\n 'bagian',\n 'bahkan',\n 'bahwa',\n 'bahwasanya',\n 'baik',\n 'bakal',\n 'bakalan',\n 'balik',\n 'banyak',\n 'bapak',\n 'baru',\n 'bawah',\n 'beberapa',\n 'begini',\n 'beginian',\n 'beginikah',\n 'beginilah',\n 'begitu',\n 'begitukah',\n 'begitulah',\n 'begitupun',\n 'bekerja',\n 'belakang',\n 'belakangan',\n 'belum',\n 'belumlah',\n 'benar',\n 'benarkah',\n 'benarlah',\n 'berada',\n 'berakhir',\n 'berakhirlah',\n 'berakhirnya',\n 'berapa',\n 'berapakah',\n 'berapalah',\n 'berapapun',\n 'berarti',\n 'berawal',\n 'berbagai',\n 'berikut',\n 'berikutnya',\n 'berjumlah',\n 'berkali-kali',\n 'berkata',\n 'berkeinginan',\n 'berkenaan',\n 'berlainan',\n 'berlalu',\n 'berlangsung',\n 'berlebihan',\n 'bermacam',\n 'bermacam-macam',\n 'bermaksud',\n 'bermula',\n 'bersama',\n 'bersama-sama',\n 'bersiap',\n 'bersiap-siap',\n 'bertanya',\n 'bertanya-tanya',\n 'berturut',\n 'berturut-turut',\n 'bertutur',\n 'berujar',\n 'berupa',\n 'besar',\n 'betul',\n 'betulkah',\n 'biasa',\n 'biasanya',\n 'bila',\n 'bilakah',\n 'bisa',\n 'bisakah',\n 'boleh',\n 'bolehkah',\n 'bolehlah',\n 'buat',\n 'bukan',\n 'bukankah',\n 'bukanlah',\n 'bukannya',\n 'bulan',\n 'bung',\n 'cara',\n 'caranya',\n 'cukup',\n 'cukupkah',\n 'cukuplah',\n 'cuma',\n 'dahulu',\n 'dalam',\n 'dan',\n 'dapat',\n 'dari',\n 'daripada',\n 'datang',\n 'dekat',\n 'demi',\n 'demikian',\n 'demikianlah',\n 'dengan',\n 'depan',\n 'di',\n 'dia',\n 'diakhiri',\n 'diakhirinya',\n 'dialah',\n 'diantara',\n 'diantaranya',\n 'diberi',\n 'diberikan',\n 'diberikannya',\n 'dibuat',\n 'dibuatnya',\n 'didapat',\n 'didatangkan',\n 'digunakan',\n 'diibaratkan',\n 'diingat',\n 'diingatkan',\n 'diinginkan',\n 'dijawab',\n 'dijelaskan',\n 'dijelaskannya',\n 'dikarenakan',\n 'dikatakan',\n 'dikatakannya',\n 'dikerjakan',\n 'diketahui',\n 'diketahuinya',\n 'dikira',\n 'dilakukan',\n 'dilalui',\n 'dilihat',\n 'dimaksud',\n 'dimaksudkan',\n 'dimaksudkannya',\n 'dimana',\n 'dimanalah',\n 'dimulai',\n 'dimulailah',\n 'dimulainya',\n 'diminta',\n 'dimintai',\n 'dimisalkan',\n 'dimungkinkan',\n 'dini',\n 'dipastikan',\n 'diperbuat',\n 'diperbuatnya',\n 'dipergunakan',\n 'diperkirakan',\n 'diperlihatkan',\n 'diperlukan',\n 'diperlukannya',\n 'dipersoalkan',\n 'dipertanyakan',\n 'dipunyai',\n 'diri',\n 'dirinya',\n 'disampaikan',\n 'disebut',\n 'disebutkan',\n 'disebutkannya',\n 'disini',\n 'disinilah',\n 'disitulah',\n 'diterangkan',\n 'diterangkannya',\n 'diteruskan',\n 'ditujukan',\n 'ditunjuk',\n 'ditunjuki',\n 'ditunjukkan',\n 'ditunjukkannya',\n 'ditunjuknya',\n 'dituturkan',\n 'dituturkannya',\n 'diucapkan',\n 'diucapkannya',\n 'diungkapkan',\n 'dua',\n 'dulu',\n 'empat',\n 'enggak',\n 'enggaknya',\n 'entah',\n 'entahlah',\n 'guna',\n 'gunakan',\n 'hal',\n 'hampir',\n 'hanya',\n 'hanyalah',\n 'hari',\n 'harus',\n 'haruslah',\n 'harusnya',\n 'hendak',\n 'hendaklah',\n 'hendaknya',\n 'hingga',\n 'ia',\n 'ialah',\n 'ibarat',\n 'ibaratkan',\n 'ibaratnya',\n 'ibu',\n 'ikut',\n 'ingat',\n 'ingat-ingat',\n 'ingin',\n 'inginkah',\n 'inginkan',\n 'ini',\n 'inikah',\n 'inilah',\n 'itu',\n 'itukah',\n 'itulah',\n 'jadi',\n 'jadilah',\n 'jadinya',\n 'jangan',\n 'jangankan',\n 'janganlah',\n 'jauh',\n 'jawab',\n 'jawaban',\n 'jawabnya',\n 'jelas',\n 'jelaskan',\n 'jelaslah',\n 'jelasnya',\n 'jika',\n 'jikalau',\n 'juga',\n 'jumlah',\n 'jumlahnya',\n 'justru',\n 'kala',\n 'kalau',\n 'kalaulah',\n 'kalaupun',\n 'kali',\n 'kalian',\n 'kami',\n 'kamilah',\n 'kamu',\n 'kamulah',\n 'kan',\n 'kapan',\n 'kapankah',\n 'kapanpun',\n 'karena',\n 'karenanya',\n 'ke',\n 'keadaan',\n 'kebetulan',\n 'kecil',\n 'kedua',\n 'keduanya',\n 'keinginan',\n 'kelak',\n 'kelihatan',\n 'kelihatannya',\n 'kelima',\n 'keluar',\n 'kembali',\n 'kemudian',\n 'kemungkinan',\n 'kemungkinannya',\n 'kenapa',\n 'kepada',\n 'kepadanya',\n 'kesampaian',\n 'keseluruhan',\n 'keseluruhannya',\n 'keterlaluan',\n 'ketika',\n 'khususnya',\n 'kini',\n 'kinilah',\n 'kira',\n 'kira-kira',\n 'kiranya',\n 'kita',\n 'kitalah',\n 'kok',\n 'kurang',\n 'lagi',\n 'lagian',\n 'lah',\n 'lain',\n 'lainnya',\n 'lalu',\n 'lama',\n 'lamanya',\n 'lanjut',\n 'lanjutnya',\n 'lebih',\n 'lewat',\n 'luar',\n 'macam',\n 'maka',\n 'makanya',\n 'makin',\n 'malah',\n 'malahan',\n 'mampu',\n 'mampukah',\n 'mana',\n 'manakala',\n 'manalagi',\n 'masih',\n 'masihkah',\n 'masing',\n 'masing-masing',\n 'mau',\n 'maupun',\n 'melainkan',\n 'melakukan',\n 'melalui',\n 'melihat',\n 'melihatnya',\n 'memang',\n 'memastikan',\n 'memberi',\n 'memberikan',\n 'membuat',\n 'memerlukan',\n 'memihak',\n 'meminta',\n 'memisalkan',\n 'memperbuat',\n 'mempergunakan',\n 'memperkirakan',\n 'memperlihatkan',\n 'mempersiapkan',\n 'mempersoalkan',\n 'mempertanyakan',\n 'mempunyai',\n 'memulai',\n 'memungkinkan',\n 'memutuskan',\n 'menanti',\n 'menanti-nanti',\n 'menantikan',\n 'menunjuk',\n 'menunjuknya',\n 'menuju',\n 'menurut',\n 'menurutnya',\n 'menurutmu',\n 'menurutku',\n 'menurutnya',\n 'menurut mereka',\n 'menyampaikan',\n 'menyebut',\n 'menyebutkan',\n 'menjelaskan',\n 'menjadi',\n 'menjadikan',\n 'menjalani',\n 'menjelang',\n 'menjawab',\n 'menunjukkan',\n 'menuangkan',\n 'menulis',\n 'menyatakan',\n 'merupakan',\n 'mereka',\n 'merekalah',\n 'meski',\n 'meskipun',\n 'mula',\n 'mulai',\n 'mulailah',\n 'mulanya',\n 'mungkin',\n 'mungkinkah',\n 'nah',\n 'naik',\n 'namun',\n 'nanti',\n 'nantinya',\n 'nyaris',\n 'oleh',\n 'olehnya',\n 'orang',\n 'pada',\n 'padahal',\n 'padanya',\n 'pakai',\n 'paling',\n 'panjang',\n 'pantas',\n 'para',\n 'pasti',\n 'pastilah',\n 'pagi',\n 'per',\n 'pernah',\n 'persoalan',\n 'pertama',\n 'pertama-tama',\n 'perlu',\n 'perlukah',\n 'perlulah',\n 'pernah',\n 'pihak',\n 'pihaknya',\n 'pukul',\n 'pula',\n 'pun',\n 'punya',\n 'rasa',\n 'rasanya',\n 'rata',\n 'rupanya',\n 'saat',\n 'saatnya',\n 'saja',\n 'sajalah',\n 'salam',\n 'saling',\n 'sama',\n 'sama-sama',\n 'sambil',\n 'sampai',\n 'sampai-sampai',\n 'sampaikan',\n 'sana',\n 'sangat',\n 'sangatlah',\n 'satu',\n 'saya',\n 'sayalah',\n 'sayang',\n 'seperti',\n 'seperti-itu',\n 'sepura',\n 'sebab',\n 'sebabnya',\n 'sebagai',\n 'sebagaimana',\n 'sebagainya',\n 'sebagian',\n 'sebaik',\n 'sebaik-baiknya',\n 'sebaiknya',\n 'sebaliknya',\n 'sebanyak',\n 'sebegini',\n 'sebegitu',\n 'sebelum',\n 'sebelumnya',\n 'sebenarnya',\n 'seberapa',\n 'sebesar',\n 'sebetulnya',\n 'sebisanya',\n 'sebuah',\n 'sebut',\n 'sebutkan',\n 'sebutnya',\n 'secara',\n 'secukupnya',\n 'sedang',\n 'sedangkan',\n 'sedikit',\n 'sedikitnya',\n 'sedemikian',\n 'sediakala',\n 'sedikit',\n 'sedikitnya',\n 'segala',\n 'segalanya',\n 'segera',\n 'seharusnya',\n 'sehingga',\n 'seingat',\n 'sejak',\n 'sejauh',\n 'sejenak',\n 'sejumlah',\n 'sekali',\n 'sekali-kali',\n 'sekalian',\n 'sekaligus',\n 'sekalipun',\n 'sekarang',\n 'sekaranglah',\n 'sekecil',\n 'seketika',\n 'sekiranya',\n 'sekitar',\n 'sekitarnya',\n 'sekurang',\n 'sekurangnya',\n 'sela',\n 'selalu',\n 'selama',\n 'selama-lamanya',\n 'selamanya',\n 'selanjutnya',\n 'seluruh',\n 'seluruhnya',\n 'semacam',\n 'semakin',\n 'semampu',\n 'semampunya',\n 'semasa',\n 'semata',\n 'semata-mata',\n 'semaunya',\n 'sementara',\n 'semisal',\n 'semisalnya',\n 'sempat',\n 'semua',\n 'semuanya',\n 'semula',\n 'sendiri',\n 'sendirinya',\n 'seolah',\n 'seolah-olah',\n 'seorang',\n 'sepanjang',\n 'sepantasnya',\n 'sepantasnyalah',\n 'seperempat',\n 'seperti',\n 'sepertinya',\n 'sepihak',\n 'sepuluh',\n 'seratus',\n 'seribu',\n 'sering',\n 'seringnya',\n 'serta',\n 'serupa',\n 'sesaat',\n 'sesama',\n 'sesampai',\n 'sesampainya',\n 'sesegera',\n 'sesekali',\n 'seseorang',\n 'sesuatu',\n 'sesuatunya',\n 'sesudah',\n 'sesudahnya',\n 'setelah',\n 'setempat',\n 'setengah',\n 'seterusnya',\n 'setiap',\n 'setidaknya',\n 'setinggi',\n 'seusai',\n 'sewaktu',\n 'siap',\n 'siapa',\n 'siapakah',\n 'siapapun',\n 'sini',\n 'sinilah',\n 'situ',\n 'situlah',\n 'suatu',\n 'sudah',\n 'sudahkah',\n 'sudahlah',\n 'supaya',\n 'tadi',\n 'tadinya',\n 'tahu',\n 'tak',\n 'tambah',\n 'tambahnya',\n 'tampak',\n 'tampaknya',\n 'tandas',\n 'tandasnya',\n 'tanpa',\n 'tanya',\n 'tanyakan',\n 'tanyanya',\n 'tapi',\n 'tegas',\n 'tegasnya',\n 'telah',\n 'tempat',\n 'tengah',\n 'tentang',\n 'tentu',\n 'tentulah',\n 'tentunya',\n 'tepat',\n 'terakhir',\n 'terasa',\n 'terbanyak',\n 'terdahulu',\n 'terdapat',\n 'terdiri',\n 'terdiri-dari',\n 'terhadap',\n 'terhadapnya',\n 'teringat',\n 'teringat-ingat',\n 'terjadi',\n 'terjadilah',\n 'terjadinya',\n 'terkira',\n 'terlalu',\n 'terlebih',\n 'terlihat',\n 'termasuk',\n 'ternyata',\n 'tersampaikan',\n 'tersebut',\n 'tersebutlah',\n 'tertentu',\n 'tertuju',\n 'terus',\n 'terutama',\n 'tetap',\n 'tetapi',\n 'tiap',\n 'tiba',\n 'tiba-tiba',\n 'tidak',\n 'tidakkah',\n 'tidaklah',\n 'tiga',\n 'tadi',\n 'tadinya',\n 'tinggi',\n 'toh',\n 'tuju',\n 'tunjuk',\n 'turut',\n 'tutur',\n 'tuturnya',\n 'ucap',\n 'ucapnya',\n 'ujar',\n 'ujarnya',\n 'umumnya',\n 'ungkap',\n 'ungkapnya',\n 'untuk',\n 'untaian',\n 'usai',\n 'usah',\n 'waduh',\n 'wah',\n 'wahai',\n 'walau',\n 'walaupun',\n 'wong',\n 'yaitu',\n 'yakin',\n 'yakni',\n 'yang',\n] as const;\n","import { ACRONYMS, LOWERCASE_WORDS } from './constants';\nimport { TitleCaseOptions } from './types';\n\n/**\n * Capitalize the first letter of a string and lowercase the rest\n *\n * This function converts the first character to uppercase and all remaining\n * characters to lowercase. It handles empty strings, Unicode characters,\n * and multi-word strings (only first word is affected).\n *\n * @param text - The text to capitalize\n * @returns The capitalized text\n *\n * @example\n * Basic usage:\n * ```typescript\n * capitalize('joko') // → 'Joko'\n * capitalize('JOKO') // → 'Joko'\n * capitalize('jOKO') // → 'Joko'\n * ```\n *\n * @example\n * Multi-word strings (only first word capitalized):\n * ```typescript\n * capitalize('joko widodo') // → 'Joko widodo'\n * capitalize('JOKO WIDODO') // → 'Joko widodo'\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * capitalize('') // → ''\n * capitalize('a') // → 'A'\n * capitalize('123abc') // → '123abc'\n * ```\n *\n * @public\n */\nexport function capitalize(text: string): string {\n if (!text) return text;\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();\n}\n\n/**\n * Convert text to title case following Indonesian grammar rules\n *\n * This function capitalizes the first letter of each word while respecting\n * Indonesian language conventions:\n * - Keeps particles lowercase (di, ke, dari, untuk, dan, etc.)\n * - Preserves known acronyms in uppercase (PT, CV, TNI, DKI, etc.)\n * - Handles hyphenated words correctly (anak-anak → Anak-Anak)\n * - Normalizes whitespace automatically\n *\n * @param text - The text to convert to title case\n * @param options - Optional configuration\n * @returns The title-cased text with proper Indonesian grammar\n *\n * @example\n * Basic usage:\n * ```typescript\n * toTitleCase('joko widodo')\n * // → 'Joko Widodo'\n *\n * toTitleCase('JOKO WIDODO')\n * // → 'Joko Widodo'\n * ```\n *\n * @example\n * Indonesian particles (kept lowercase):\n * ```typescript\n * toTitleCase('buku untuk anak dan orang tua')\n * // → 'Buku untuk Anak dan Orang Tua'\n *\n * toTitleCase('dari jakarta ke bandung')\n * // → 'Dari Jakarta ke Bandung'\n * // (first word always capitalized)\n * ```\n *\n * @example\n * Acronyms (preserved in uppercase):\n * ```typescript\n * toTitleCase('pt bank bca tbk')\n * // → 'PT Bank BCA Tbk'\n *\n * toTitleCase('dki jakarta')\n * // → 'DKI Jakarta'\n *\n * toTitleCase('tni angkatan darat')\n * // → 'TNI Angkatan Darat'\n * ```\n *\n * @example\n * Hyphenated words:\n * ```typescript\n * toTitleCase('anak-anak bermain')\n * // → 'Anak-Anak Bermain'\n *\n * toTitleCase('makan-makan di rumah')\n * // → 'Makan-Makan di Rumah'\n * ```\n *\n * @example\n * With options:\n * ```typescript\n * toTitleCase('PT BCA', { preserveAcronyms: false })\n * // → 'Pt Bca'\n *\n * toTitleCase('mobil dari jepang', { exceptions: ['jepang'] })\n * // → 'Mobil dari jepang'\n *\n * toTitleCase('HELLO WORLD', { strict: true })\n * // → 'Hello World'\n * ```\n *\n * @public\n */\nexport function toTitleCase(text: string, options?: TitleCaseOptions): string {\n if (!text) return text;\n\n const {\n preserveAcronyms = true,\n strict = false,\n exceptions = [],\n } = options || {};\n\n const lowercaseSet = new Set([...LOWERCASE_WORDS, ...exceptions]);\n const acronymSet = new Set(ACRONYMS);\n\n const normalized = normalizeSpaces(text);\n const words = normalized.split(' ');\n\n return words\n .map((word, index) => {\n if (!word) return word;\n\n if (word.includes('-')) {\n return processHyphenatedWord(word, index === 0, {\n lowercaseSet,\n acronymSet,\n preserveAcronyms,\n strict,\n });\n }\n\n return processWord(word, index === 0, {\n lowercaseSet,\n acronymSet,\n preserveAcronyms,\n strict,\n });\n })\n .join(' ');\n}\n\n/**\n * Normalize whitespace in text (trim and collapse multiple spaces)\n */\nfunction normalizeSpaces(text: string): string {\n return text.trim().replace(/\\s+/g, ' ');\n}\n\n/**\n * Process a single word according to title case rules\n */\nfunction processWord(\n word: string,\n isFirstWord: boolean,\n context: {\n lowercaseSet: Set<string>;\n acronymSet: Set<string>;\n preserveAcronyms: boolean;\n strict: boolean;\n }\n): string {\n const { lowercaseSet, acronymSet, preserveAcronyms, strict } = context;\n const lowerWord = word.toLowerCase();\n const upperWord = word.toUpperCase();\n\n // Check if it's a known acronym\n if (preserveAcronyms && acronymSet.has(upperWord)) {\n return upperWord;\n }\n\n // Check if it should be lowercase (but not at the start)\n if (!isFirstWord && lowercaseSet.has(lowerWord)) {\n return lowerWord;\n }\n\n // Capitalize first letter\n if (strict) {\n return capitalizeFirstLetter(lowerWord);\n }\n\n return capitalizeFirstLetter(word.toLowerCase());\n}\n\n/**\n * Process hyphenated word (e.g., \"anak-anak\")\n */\nfunction processHyphenatedWord(\n word: string,\n isFirstWord: boolean,\n context: {\n lowercaseSet: Set<string>;\n acronymSet: Set<string>;\n preserveAcronyms: boolean;\n strict: boolean;\n }\n): string {\n return word\n .split('-')\n .map((part, index) =>\n processWord(part, isFirstWord && index === 0, context)\n )\n .join('-');\n}\n\n/**\n * Capitalize first letter of a word\n */\nfunction capitalizeFirstLetter(word: string): string {\n if (!word) return word;\n return word.charAt(0).toUpperCase() + word.slice(1);\n}\n\n/**\n * Convert text to sentence case (capitalize first letter of sentences only)\n *\n * This function capitalizes the first character of the text and the first\n * character after sentence-ending punctuation (. ! ?), while keeping\n * everything else in lowercase.\n *\n * **Sentence Detection Rules:**\n * - Period (.), exclamation (!), question mark (?) mark sentence endings\n * - Next letter after punctuation + space is capitalized\n * - Handles multiple spaces and newlines\n * - Does NOT treat abbreviations as sentence endings (e.g., \"Dr. Smith\")\n *\n * @param text - The text to convert to sentence case\n * @returns The sentence-cased text\n *\n * @example\n * Basic usage:\n * ```typescript\n * toSentenceCase('JOKO WIDODO ADALAH PRESIDEN')\n * // → 'Joko widodo adalah presiden'\n *\n * toSentenceCase('joko widodo adalah presiden')\n * // → 'Joko widodo adalah presiden'\n * ```\n *\n * @example\n * Multiple sentences:\n * ```typescript\n * toSentenceCase('halo, apa kabar? baik-baik saja.')\n * // → 'Halo, apa kabar? Baik-baik saja.'\n *\n * toSentenceCase('jakarta. surabaya. bandung.')\n * // → 'Jakarta. Surabaya. Bandung.'\n * ```\n *\n * @example\n * Different punctuation:\n * ```typescript\n * toSentenceCase('wow! amazing! fantastic!')\n * // → 'Wow! Amazing! Fantastic!'\n *\n * toSentenceCase('siapa nama anda? saya joko.')\n * // → 'Siapa nama anda? Saya joko.'\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * toSentenceCase('')\n * // → ''\n *\n * toSentenceCase('hello')\n * // → 'Hello'\n *\n * toSentenceCase(' hello. world. ')\n * // → 'Hello. World.'\n * ```\n *\n * @public\n */\nexport function toSentenceCase(text: string): string {\n if (!text) return text;\n\n const normalized = text.trim().replace(/\\s+/g, ' ');\n\n let result = '';\n let shouldCapitalize = true;\n\n for (let i = 0; i < normalized.length; i++) {\n const char = normalized[i];\n\n // Capitalize if we should and this is a letter\n if (shouldCapitalize && /[a-zA-ZÀ-ÿ]/.test(char)) {\n result += char.toUpperCase();\n shouldCapitalize = false;\n } else {\n result += char.toLowerCase();\n }\n\n // Mark next letter for capitalization after sentence-ending punctuation\n if (isSentenceEnd(char)) {\n shouldCapitalize = true;\n }\n\n // Handle abbreviations: don't capitalize after period in abbreviations\n if (char === '.' && i + 1 < normalized.length) {\n const nextChar = normalized[i + 1];\n\n // If next char is not a space, likely an abbreviation\n if (nextChar !== ' ' && !/[.!?]/.test(nextChar)) {\n shouldCapitalize = false;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Check if a character marks the end of a sentence\n */\nfunction isSentenceEnd(char: string): boolean {\n return char === '.' || char === '!' || char === '?';\n}\n","import type { SlugifyOptions } from './types';\n\n/**\n * Generate URL-safe slugs with Indonesian language support\n *\n * This function converts text into URL-friendly slugs by:\n * - Converting to lowercase (configurable)\n * - Replacing spaces with separators (default: hyphen)\n * - Replacing Indonesian conjunctions (& → dan, / → atau)\n * - Removing special characters\n * - Collapsing multiple separators\n * - Trimming leading/trailing separators\n *\n * **Character Handling:**\n * - Alphanumeric (a-z, A-Z, 0-9): Preserved\n * - Spaces: Replaced with separator\n * - Ampersand (&): Replaced with \"dan\"\n * - Slash (/): Replaced with \"atau\"\n * - Hyphens (-): Preserved as separators\n * - Other special chars: Removed\n *\n * @param text - The text to convert to slug\n * @param options - Optional configuration\n * @returns The URL-safe slug\n *\n * @example\n * Basic usage:\n * ```typescript\n * slugify('Cara Mudah Belajar TypeScript')\n * // → 'cara-mudah-belajar-typescript'\n *\n * slugify('HELLO WORLD')\n * // → 'hello-world'\n * ```\n *\n * @example\n * Indonesian conjunctions:\n * ```typescript\n * slugify('Ibu & Anak: Tips Kesehatan')\n * // → 'ibu-dan-anak-tips-kesehatan'\n *\n * slugify('Baju Pria/Wanita')\n * // → 'baju-pria-atau-wanita'\n *\n * slugify('A & B / C')\n * // → 'a-dan-b-atau-c'\n * ```\n *\n * @example\n * Special characters removed:\n * ```typescript\n * slugify('Harga Rp 100.000 (Diskon 20%)')\n * // → 'harga-rp-100000-diskon-20'\n *\n * slugify('Email: test@example.com')\n * // → 'email-testexamplecom'\n * ```\n *\n * @example\n * Multiple spaces/separators collapsed:\n * ```typescript\n * slugify('Produk Terbaru - - - 2024')\n * // → 'produk-terbaru-2024'\n *\n * slugify(' Hello World ')\n * // → 'hello-world'\n * ```\n *\n * @example\n * With options:\n * ```typescript\n * slugify('Hello World', { separator: '_' })\n * // → 'hello_world'\n *\n * slugify('Hello World', { lowercase: false })\n * // → 'Hello-World'\n *\n * slugify('C++ Programming', {\n * replacements: { 'C++': 'cpp' }\n * })\n * // → 'cpp-programming'\n *\n * slugify('Hello-World', { trim: false })\n * // → 'hello-world' (same, but won't trim if leading/trailing)\n * ```\n *\n * @public\n */\n\nexport function slugify(text: string, options?: SlugifyOptions): string {\n if (!text) return '';\n\n const {\n separator = '-',\n lowercase = true,\n replacements = {},\n trim = true,\n } = options || {};\n\n let result = text;\n\n // Apply custom replacements first\n for (const [search, replace] of Object.entries(replacements)) {\n result = result.replace(new RegExp(escapeRegex(search), 'g'), replace);\n }\n\n // Replace Indonesian conjunctions\n result = result.replace(/&/g, ' dan ');\n result = result.replace(/\\//g, ' atau ');\n\n // Convert to lowercase if needed\n if (lowercase) {\n result = result.toLowerCase();\n }\n\n // Remove chars that should NOT become separators (dots, apostrophes, @, accents, etc)\n result = result.replace(/[.'@éèêëàâäôöûüùïîçñ™®©]/g, '');\n\n // Replace remaining special chars with separator (everything except alphanumeric, spaces, hyphens)\n result = result.replace(/[^\\w\\s-]+/g, separator);\n\n // Replace spaces with separator\n result = result.replace(/\\s+/g, separator);\n\n // Replace existing hyphens with separator (if separator is not hyphen)\n if (separator !== '-') {\n result = result.replace(/-/g, separator);\n }\n\n // Only when trim: true, collapse multiple separators AND trim edges\n if (trim) {\n const separatorRegex = new RegExp(`\\\\${separator}+`, 'g');\n result = result.replace(separatorRegex, separator);\n\n const trimRegex = new RegExp(`^\\\\${separator}+|\\\\${separator}+$`, 'g');\n result = result.replace(trimRegex, '');\n }\n\n return result;\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","import type { SanitizeOptions } from './types';\n\n/**\n * Normalize all whitespace characters to single spaces\n *\n * This function:\n * - Collapses multiple spaces into one\n * - Converts tabs, newlines, and other whitespace to single space\n * - Trims leading and trailing whitespace\n * - Handles Unicode whitespace characters\n *\n * **Whitespace Characters Normalized:**\n * - Space (` `)\n * - Tab (`\\t`)\n * - Newline (`\\n`)\n * - Carriage return (`\\r`)\n * - Form feed (`\\f`)\n * - Vertical tab (`\\v`)\n * - Non-breaking space (`\\u00A0`)\n * - Other Unicode spaces\n *\n * @param text - The text to normalize\n * @returns Text with normalized whitespace\n *\n * @example\n * Basic usage:\n * ```typescript\n * normalizeWhitespace('hello world')\n * // → 'hello world'\n *\n * normalizeWhitespace('hello\\tworld')\n * // → 'hello world'\n * ```\n *\n * @example\n * Multiple types of whitespace:\n * ```typescript\n * normalizeWhitespace('hello\\n\\nworld')\n * // → 'hello world'\n *\n * normalizeWhitespace('hello\\r\\nworld')\n * // → 'hello world'\n *\n * normalizeWhitespace('line1\\n\\nline2\\tword')\n * // → 'line1 line2 word'\n * ```\n *\n * @example\n * Leading and trailing whitespace:\n * ```typescript\n * normalizeWhitespace(' hello world ')\n * // → 'hello world'\n *\n * normalizeWhitespace('\\n\\thello\\t\\n')\n * // → 'hello'\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * normalizeWhitespace('')\n * // → ''\n *\n * normalizeWhitespace(' ')\n * // → ''\n *\n * normalizeWhitespace('hello')\n * // → 'hello'\n * ```\n *\n * @public\n */\nexport function normalizeWhitespace(text: string): string {\n if (!text) return text;\n\n // Replace all whitespace characters with single space\n // \\s matches: space, tab, newline, carriage return, form feed, vertical tab\n return text.trim().replace(/\\s+/g, ' ');\n}\n\n/**\n * Remove or replace unwanted characters from text\n *\n * This function provides flexible text sanitization with options to:\n * - Remove newlines\n * - Remove extra spaces\n * - Remove punctuation\n * - Keep only allowed characters\n * - Trim leading/trailing whitespace\n *\n * @param text - The text to sanitize\n * @param options - Sanitization options\n * @returns The sanitized text\n *\n * @example\n * Remove extra spaces (default):\n * ```typescript\n * sanitize('hello world')\n * // → 'hello world'\n * ```\n *\n * @example\n * Remove newlines:\n * ```typescript\n * sanitize('line1\\nline2\\nline3', { removeNewlines: true })\n * // → 'line1 line2 line3'\n * ```\n *\n * @example\n * Remove punctuation:\n * ```typescript\n * sanitize('Hello, World!', { removePunctuation: true })\n * // → 'Hello World'\n * ```\n *\n * @example\n * Allow only specific characters:\n * ```typescript\n * sanitize('ABC123!@#', { allowedChars: 'A-Za-z0-9' })\n * // → 'ABC123'\n *\n * sanitize('Hello123!@#', { allowedChars: 'a-z' })\n * // → 'ello'\n * ```\n *\n * @example\n * Combined options:\n * ```typescript\n * sanitize(' Hello,\\n World! ', {\n * removeNewlines: true,\n * removePunctuation: true,\n * removeExtraSpaces: true,\n * trim: true\n * })\n * // → 'Hello World'\n * ```\n *\n * @public\n */\nexport function sanitize(text: string, options?: SanitizeOptions): string {\n if (!text) return text;\n\n const {\n removeNewlines = false,\n removeExtraSpaces = true,\n removePunctuation = false,\n allowedChars,\n trim = true,\n } = options || {};\n\n let result = text;\n\n // Remove newlines first (replace with space)\n if (removeNewlines) {\n result = result.replace(/[\\n\\r]/g, ' ');\n }\n\n // Remove punctuation\n if (removePunctuation) {\n result = result.replace(/[!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~]/g, '');\n }\n\n // Keep only allowed characters\n if (allowedChars) {\n const allowedRegex = new RegExp(`[^${allowedChars}]`, 'g');\n result = result.replace(allowedRegex, '');\n }\n\n // Remove extra spaces\n if (removeExtraSpaces) {\n if (trim) {\n // When trimming, we can safely collapse all spaces\n if (removeNewlines) {\n result = result.replace(/\\s+/g, ' ');\n } else {\n result = result.replace(/[ \\t]+/g, ' ');\n }\n } else {\n // When not trimming, preserve leading/trailing spaces\n // Only collapse spaces in the middle\n const leadingMatch = result.match(/^([ \\t]*)/);\n const trailingMatch = result.match(/([ \\t]*)$/);\n const leading = leadingMatch ? leadingMatch[1] : '';\n const trailing = trailingMatch ? trailingMatch[1] : '';\n\n const middle = result.slice(\n leading.length,\n result.length - trailing.length\n );\n const normalizedMiddle = removeNewlines\n ? middle.replace(/\\s+/g, ' ')\n : middle.replace(/[ \\t]+/g, ' ');\n\n result = leading + normalizedMiddle + trailing;\n }\n }\n\n // Trim\n if (trim) {\n result = result.trim();\n }\n\n return result;\n}\n\n/**\n * Remove diacritical marks (accents) from characters\n *\n * Converts accented characters to their base form:\n * - é → e\n * - ñ → n\n * - ü → u\n * - etc.\n *\n * Useful for:\n * - Search normalization\n * - Sorting/comparison\n * - URL generation\n * - Database queries\n *\n * @param text - The text to remove accents from\n * @returns Text with accents removed\n *\n * @example\n * Basic usage:\n * ```typescript\n * removeAccents('café')\n * // → 'cafe'\n *\n * removeAccents('résumé')\n * // → 'resume'\n * ```\n *\n * @example\n * Various accents:\n * ```typescript\n * removeAccents('naïve')\n * // → 'naive'\n *\n * removeAccents('Zürich')\n * // → 'Zurich'\n *\n * removeAccents('São Paulo')\n * // → 'Sao Paulo'\n * ```\n *\n * @example\n * Mixed text:\n * ```typescript\n * removeAccents('École française à Montréal')\n * // → 'Ecole francaise a Montreal'\n * ```\n *\n * @public\n */\nexport function removeAccents(text: string): string {\n if (!text) return text;\n\n // Manual mapping for Nordic and other special characters that don't decompose\n const specialChars: Record<string, string> = {\n Ø: 'O',\n ø: 'o',\n Æ: 'AE',\n æ: 'ae',\n Å: 'A',\n å: 'a',\n Đ: 'D',\n đ: 'd',\n Ł: 'L',\n ł: 'l',\n Þ: 'TH',\n þ: 'th',\n ß: 'ss',\n };\n\n // First apply manual mappings\n let result = text;\n for (const [accented, plain] of Object.entries(specialChars)) {\n result = result.replace(new RegExp(accented, 'g'), plain);\n }\n\n // Then normalize to NFD and remove combining diacritical marks\n return result.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');\n}\n","import { ABBREVIATIONS } from './constants';\nimport type { ExpandOptions } from './types';\n\n/**\n * Expand Indonesian abbreviations to their full form\n *\n * This function expands common Indonesian abbreviations like:\n * - Address: Jl. → Jalan, Kec. → Kecamatan\n * - Titles: Dr. → Doktor, S.H. → Sarjana Hukum\n * - Honorifics: Bpk. → Bapak, Yth. → Yang Terhormat\n * - Organizations: PT. → Perseroan Terbatas\n * - Common: dll. → dan lain-lain\n *\n * **Features:**\n * - Case-insensitive matching (Jl. = jl. = JL.)\n * - Mode filtering (all, address, title, org)\n * - Custom mapping support\n * - Preserves surrounding text\n * - Multiple abbreviations in one string\n *\n * @param text - The text containing abbreviations to expand\n * @param options - Optional configuration\n * @returns Text with abbreviations expanded\n *\n * @example\n * Basic usage:\n * ```typescript\n * expandAbbreviation('Jl. Sudirman No. 123')\n * // → 'Jalan Sudirman Nomor 123'\n *\n * expandAbbreviation('Dr. Joko Widodo, S.H.')\n * // → 'Doktor Joko Widodo, Sarjana Hukum'\n * ```\n *\n * @example\n * Address abbreviations:\n * ```typescript\n * expandAbbreviation('Kab. Bogor, Kec. Ciawi')\n * // → 'Kabupaten Bogor, Kecamatan Ciawi'\n *\n * expandAbbreviation('Jl. Merdeka Gg. 5 No. 10')\n * // → 'Jalan Merdeka Gang 5 Nomor 10'\n * ```\n *\n * @example\n * Academic titles:\n * ```typescript\n * expandAbbreviation('Prof. Dr. Ir. Ahmad')\n * // → 'Profesor Doktor Insinyur Ahmad'\n *\n * expandAbbreviation('Saya lulusan S.T. dari ITB')\n * // → 'Saya lulusan Sarjana Teknik dari ITB'\n * ```\n *\n * @example\n * Honorifics:\n * ```typescript\n * expandAbbreviation('Yth. Bpk. H. Ahmad')\n * // → 'Yang Terhormat Bapak Haji Ahmad'\n * ```\n *\n * @example\n * Organizations:\n * ```typescript\n * expandAbbreviation('PT. Maju Jaya Tbk.')\n * // → 'Perseroan Terbatas Maju Jaya Terbuka'\n * ```\n *\n * @example\n * Mode filtering:\n * ```typescript\n * expandAbbreviation('Dr. Joko di Jl. Sudirman', { mode: 'address' })\n * // → 'Dr. Joko di Jalan Sudirman'\n * // Only expands address abbreviations\n *\n * expandAbbreviation('Prof. Dr. di Jl. Sudirman', { mode: 'title' })\n * // → 'Profesor Doktor di Jl. Sudirman'\n * // Only expands title abbreviations\n * ```\n *\n * @example\n * Custom mappings:\n * ```typescript\n * expandAbbreviation('BUMN adalah perusahaan negara', {\n * customMap: { 'BUMN': 'Badan Usaha Milik Negara' }\n * })\n * // → 'Badan Usaha Milik Negara adalah perusahaan negara'\n * ```\n *\n * @example\n * Case sensitivity:\n * ```typescript\n * expandAbbreviation('jl. sudirman')\n * // → 'Jalan sudirman' (default: preserves surrounding case)\n *\n * expandAbbreviation('JL. SUDIRMAN')\n * // → 'Jalan SUDIRMAN'\n * ```\n *\n * @public\n */\nexport function expandAbbreviation(\n text: string,\n options?: ExpandOptions\n): string {\n if (!text) return text;\n\n const { mode = 'all', customMap = {}, preserveCase = false } = options || {};\n\n // Combine built-in and custom abbreviations\n const abbreviationsMap = {\n ...getAbbreviationsByMode(mode),\n ...customMap,\n };\n\n let result = text;\n\n // Sort by length (longest first) to avoid partial replacements\n // Example: Replace \"S.H.\" before \"S.\" to avoid \"Sarjana.H.\"\n const sortedAbbrevs = Object.keys(abbreviationsMap).sort(\n (a, b) => b.length - a.length\n );\n\n for (const abbrev of sortedAbbrevs) {\n const expansion = abbreviationsMap[abbrev];\n\n // Create case-insensitive regex with word boundaries\n // Handle word boundaries intelligently:\n // - If starts with word char, add \\b prefix\n // - If ends with word char, add \\b suffix\n // - If ends with dot, don't add \\b suffix (dots are non-word chars)\n const startBoundary = /^\\w/.test(abbrev) ? '\\\\b' : '';\n const endBoundary = /\\w$/.test(abbrev) ? '\\\\b' : '';\n\n const regex = new RegExp(\n `${startBoundary}${escapeRegex(abbrev)}${endBoundary}`,\n 'gi'\n );\n\n result = result.replace(regex, (match) => {\n // If preserveCase is false, use the expansion as-is\n if (!preserveCase) {\n return expansion;\n }\n\n // If preserveCase is true, try to match case of original\n return matchCase(match, expansion);\n });\n }\n\n return result;\n}\n\n/**\n * Get abbreviations filtered by mode\n */\nfunction getAbbreviationsByMode(\n mode: 'all' | 'address' | 'title' | 'org'\n): Record<string, string> {\n if (mode === 'all') {\n return ABBREVIATIONS;\n }\n\n const filtered: Record<string, string> = {};\n\n // Define which abbreviations belong to which category\n const addressAbbrevs = [\n 'Jl.',\n 'Gg.',\n 'No.',\n 'Kp.',\n 'Ds.',\n 'Kel.',\n 'Kec.',\n 'Kab.',\n 'Kota',\n 'Prov.',\n 'Prop.',\n 'Rt.',\n 'Rw.',\n 'Blok',\n 'Komp.',\n 'Perumahan',\n 'Perum.',\n ];\n\n const titleAbbrevs = [\n 'Dr.',\n 'Ir.',\n 'Prof.',\n 'Drs.',\n 'Dra.',\n 'S.Pd.',\n 'S.H.',\n 'S.E.',\n 'S.T.',\n 'S.Kom.',\n 'S.Si.',\n 'S.Sos.',\n 'S.I.Kom.',\n 'S.S.',\n 'S.Psi.',\n 'S.Farm.',\n 'S.Ked.',\n 'M.Sc.',\n 'M.M.',\n 'M.Pd.',\n 'M.T.',\n 'M.Kom.',\n 'M.Si.',\n 'M.H.',\n 'M.A.',\n 'MBA',\n ];\n\n const orgAbbrevs = [\n 'PT.',\n 'CV.',\n 'UD.',\n 'PD.',\n 'Tbk.',\n 'Koperasi',\n 'Yayasan',\n ];\n\n // Filter based on mode\n for (const [abbrev, expansion] of Object.entries(ABBREVIATIONS)) {\n if (mode === 'address' && addressAbbrevs.includes(abbrev)) {\n filtered[abbrev] = expansion;\n } else if (mode === 'title' && titleAbbrevs.includes(abbrev)) {\n filtered[abbrev] = expansion;\n } else if (mode === 'org' && orgAbbrevs.includes(abbrev)) {\n filtered[abbrev] = expansion;\n }\n }\n\n return filtered;\n}\n\n/**\n * Escape special regex characters in a string\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Match the case pattern of original string to replacement\n * - ALL CAPS → ALL CAPS\n * - Title Case → Title Case\n * - lowercase → lowercase\n */\nfunction matchCase(original: string, replacement: string): string {\n // Check if original is all uppercase\n if (original === original.toUpperCase()) {\n return replacement.toUpperCase();\n }\n\n // Check if original is all lowercase\n if (original === original.toLowerCase()) {\n return replacement.toLowerCase();\n }\n\n // Check if original is title case (first letter uppercase)\n if (original.charAt(0) === original.charAt(0).toUpperCase()) {\n return (\n replacement.charAt(0).toUpperCase() + replacement.slice(1).toLowerCase()\n );\n }\n\n // Default: return as-is\n return replacement;\n}\n\n/**\n * Contract full forms to abbreviations (reverse of expand)\n *\n * @param text - The text containing full forms to contract\n * @param options - Optional configuration\n * @returns Text with full forms contracted\n *\n * @example\n * ```typescript\n * contractAbbreviation('Jalan Sudirman Nomor 123')\n * // → 'Jl. Sudirman No. 123'\n *\n * contractAbbreviation('Doktor Ahmad, Sarjana Hukum')\n * // → 'Dr. Ahmad, S.H.'\n * ```\n *\n * @public\n */\nexport function contractAbbreviation(\n text: string,\n options?: { mode?: 'all' | 'address' | 'title' | 'org' }\n): string {\n if (!text) return text;\n\n const { mode = 'all' } = options || {};\n\n // Get abbreviations and create reverse mapping\n const abbreviationsMap = getAbbreviationsByMode(mode);\n const reverseMap: Record<string, string> = {};\n\n for (const [abbrev, expansion] of Object.entries(abbreviationsMap)) {\n reverseMap[expansion] = abbrev;\n }\n\n let result = text;\n\n // Sort by length (longest first) to avoid partial replacements\n const sortedExpansions = Object.keys(reverseMap).sort(\n (a, b) => b.length - a.length\n );\n\n for (const expansion of sortedExpansions) {\n const abbrev = reverseMap[expansion];\n\n // Case-insensitive replace\n const regex = new RegExp(`\\\\b${escapeRegex(expansion)}\\\\b`, 'gi');\n\n result = result.replace(regex, abbrev);\n }\n\n return result;\n}\n","import { PROFANITY, STOPWORDS } from './constants';\n\n/**\n * Filters common Indonesian profanity words by masking them.\n *\n * @param text - The text to filter\n * @param mask - The masking character (default: '*')\n * @returns Filtered text\n *\n * @example\n * ```typescript\n * profanityFilter('kamu anjing banget'); // 'kamu ****** banget'\n * ```\n */\nexport function profanityFilter(text: string, mask: string = '*'): string {\n let filtered = text;\n\n PROFANITY.forEach((word) => {\n const regex = new RegExp(`\\\\b${word}\\\\b`, 'gi');\n filtered = filtered.replace(regex, mask.repeat(word.length));\n });\n\n return filtered;\n}\n\n/**\n * Removes common Indonesian stopwords from text.\n *\n * @param text - The text to process\n * @returns Text with stopwords removed\n *\n * @example\n * ```typescript\n * removeStopwords('saya sedang makan nasi'); // 'makan nasi'\n * ```\n */\nexport function removeStopwords(text: string): string {\n const words = text.split(/\\s+/);\n const filtered = words.filter(\n (word) => !(STOPWORDS as readonly string[]).includes(word.toLowerCase())\n );\n\n return filtered.join(' ');\n}\n","/**\n * Basic mapping of common informal Indonesian words to formal ones.\n */\nconst INFORMAL_MAP: Record<string, string> = {\n gw: 'saya',\n gua: 'saya',\n lu: 'kamu',\n lo: 'kamu',\n elo: 'kamu',\n lagi: 'sedang',\n gue: 'saya',\n gwe: 'saya',\n gak: 'tidak',\n ga: 'tidak',\n nggak: 'tidak',\n kalo: 'kalau',\n karna: 'karena',\n tapi: 'tetapi',\n udah: 'sudah',\n dah: 'sudah',\n aja: 'saja',\n banget: 'sekali',\n emang: 'memang',\n pake: 'pakai',\n bikin: 'membuat',\n kasih: 'memberi',\n dapet: 'dapat',\n liat: 'lihat',\n ngasih: 'memberi',\n nyari: 'mencari',\n nanya: 'bertanya',\n bilang: 'berkata',\n};\n\n/**\n * Normalizes informal Indonesian text to a more formal version.\n * This is a basic rule-based implementation.\n *\n * @param text - The text to normalize\n * @returns Formalized text\n *\n * @example\n * ```typescript\n * toFormal('gw lagi makan'); // 'saya sedang makan'\n * ```\n */\nexport function toFormal(text: string): string {\n const words = text.split(/\\s+/);\n const formalized = words.map((word) => {\n const lower = word.toLowerCase().replace(/[^\\w]/g, '');\n const formal = INFORMAL_MAP[lower];\n if (formal) {\n // Keep capitalization if possible\n if (word[0] === word[0].toUpperCase()) {\n return formal.charAt(0).toUpperCase() + formal.slice(1);\n }\n return formal;\n }\n return word;\n });\n\n return formalized.join(' ');\n}\n\n/**\n * Detects if a text follows \"alay\" style (unconventional capitalization or number substitution).\n *\n * @param text - The text to check\n * @returns `true` if alay style detected, `false` otherwise\n *\n * @example\n * ```typescript\n * isAlay('AqU sAyAnG qMu'); // true\n * isAlay('Makan 4y4m'); // true\n * ```\n */\nexport function isAlay(text: string): boolean {\n if (!text) return false;\n\n // Rule 1: Alternating caps (mOxEd cAsE)\n // More specific: lower-UPPER-lower or UPPER-lower-UPPER, multiple times\n const alternatingCaps = /([a-z][A-Z][a-z]|[A-Z][a-z][A-Z])/.test(text);\n\n // Rule 2: Number substitution in words\n const numberSub = /\\b\\w*[0431572]\\w*\\b/.test(text);\n\n // Rule 3: Excessive 'q' instead of 'k'\n const qSub = /q/i.test(text) && !/u/i.test(text);\n\n // Rule 4: Excessive characters (e.g., 'siiaappp')\n const excessiveChars = /(.)\\1{2,}/.test(text);\n\n return alternatingCaps || numberSub || qSub || excessiveChars;\n}\n","import type { TruncateOptions, ExtractOptions } from './types';\n\n/**\n * Truncate text to specified length, word-aware\n *\n * This function shortens text to a maximum length while:\n * - Respecting word boundaries (don't cut words in half)\n * - Adding ellipsis to indicate truncation\n * - Preserving original text if already short enough\n * - Accounting for ellipsis length in total character count\n *\n * **Features:**\n * - Smart word boundary detection\n * - Customizable ellipsis\n * - No truncation for short text\n * - Handles edge cases gracefully\n *\n * @param text - The text to truncate\n * @param maxLength - Maximum length of output (including ellipsis)\n * @param options - Optional configuration\n * @returns The truncated text with ellipsis if needed\n *\n * @example\n * Basic usage:\n * ```typescript\n * truncate('Ini adalah contoh text yang panjang', 20)\n * // → 'Ini adalah contoh...'\n *\n * truncate('Short text', 20)\n * // → 'Short text' (no truncation needed)\n * ```\n *\n * @example\n * Word boundary handling:\n * ```typescript\n * truncate('Ini adalah contoh text yang panjang', 20, { wordBoundary: true })\n * // → 'Ini adalah contoh...' (stops at word)\n *\n * truncate('Ini adalah contoh text yang panjang', 20, { wordBoundary: false })\n * // → 'Ini adalah contoh t...' (cuts mid-word)\n * ```\n *\n * @example\n * Custom ellipsis:\n * ```typescript\n * truncate('Ini adalah contoh text yang panjang', 20, { ellipsis: '…' })\n * // → 'Ini adalah contoh…'\n *\n * truncate('Ini adalah contoh text yang panjang', 20, { ellipsis: ' [...]' })\n * // → 'Ini adalah [...]'\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * truncate('', 10)\n * // → ''\n *\n * truncate('Hello', 10)\n * // → 'Hello'\n *\n * truncate('Hello World', 11)\n * // → 'Hello World' (exact length, no ellipsis)\n * ```\n *\n * @public\n */\nexport function truncate(\n text: string,\n maxLength: number,\n options?: TruncateOptions\n): string {\n // Early return for empty or invalid input\n if (!text || maxLength <= 0) {\n return '';\n }\n\n const { ellipsis = '...', wordBoundary = true } = options || {};\n\n // Early return if text is already short enough\n if (text.length <= maxLength) {\n return text;\n }\n\n // Calculate available space for actual text (excluding ellipsis)\n const availableLength = maxLength - ellipsis.length;\n\n // If ellipsis is longer than maxLength, just return ellipsis truncated\n if (availableLength <= 0) {\n return ellipsis.slice(0, maxLength);\n }\n\n // Get preliminary truncated text\n let truncated = text.slice(0, availableLength);\n\n // If word boundary is enabled, find last complete word\n if (wordBoundary) {\n // Find the last space within the truncated text\n const lastSpaceIndex = truncated.lastIndexOf(' ');\n\n // Only cut at word boundary if we found a space\n // Why: Prevents returning empty string for single long word\n if (lastSpaceIndex > 0) {\n truncated = truncated.slice(0, lastSpaceIndex);\n }\n // If no space found, keep the full availableLength\n }\n\n // Trim any trailing whitespace before adding ellipsis\n truncated = truncated.trimEnd();\n\n return truncated + ellipsis;\n}\n\n/**\n * Extract words from text, respecting Indonesian language rules\n *\n * This function splits text into individual words while:\n * - Respecting hyphenated words (anak-anak as single word)\n * - Filtering by minimum length\n * - Optional lowercase conversion\n * - Removing punctuation and special characters\n *\n * **Features:**\n * - Indonesian hyphenation support (anak-anak, buku-buku)\n * - Minimum word length filtering\n * - Case normalization\n * - Handles punctuation gracefully\n *\n * @param text - The text to extract words from\n * @param options - Optional configuration\n * @returns Array of extracted words\n *\n * @example\n * Basic usage:\n * ```typescript\n * extractWords('Anak-anak bermain di taman')\n * // → ['Anak-anak', 'bermain', 'di', 'taman']\n *\n * extractWords('Hello, World! How are you?')\n * // → ['Hello', 'World', 'How', 'are', 'you']\n * ```\n *\n * @example\n * Hyphenated word handling:\n * ```typescript\n * extractWords('Anak-anak bermain di taman', { includeHyphenated: true })\n * // → ['Anak-anak', 'bermain', 'di', 'taman']\n *\n * extractWords('Anak-anak bermain di taman', { includeHyphenated: false })\n * // → ['Anak', 'anak', 'bermain', 'di', 'taman']\n * ```\n *\n * @example\n * Minimum length filtering:\n * ```typescript\n * extractWords('Di rumah ada 3 kucing', { minLength: 3 })\n * // → ['rumah', 'ada', 'kucing']\n * // 'Di' (2 chars) and '3' (1 char) filtered out\n *\n * extractWords('a b cd def ghij', { minLength: 3 })\n * // → ['def', 'ghij']\n * ```\n *\n * @example\n * Lowercase conversion:\n * ```typescript\n * extractWords('Hello WORLD', { lowercase: true })\n * // → ['hello', 'world']\n *\n * extractWords('Hello WORLD', { lowercase: false })\n * // → ['Hello', 'WORLD']\n * ```\n *\n * @example\n * Combined options:\n * ```typescript\n * extractWords('Anak-Anak BERMAIN di Taman', {\n * includeHyphenated: true,\n * minLength: 3,\n * lowercase: true\n * })\n * // → ['anak-anak', 'bermain', 'taman']\n * // 'di' filtered out (< 3 chars)\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * extractWords('')\n * // → []\n *\n * extractWords(' ')\n * // → []\n *\n * extractWords('!!!@@##')\n * // → []\n * ```\n *\n * @public\n */\nexport function extractWords(text: string, options?: ExtractOptions): string[] {\n // Early return for empty input\n if (!text || !text.trim()) {\n return [];\n }\n\n const {\n minLength = 0,\n includeHyphenated = true,\n lowercase = false,\n } = options || {};\n\n // Remove punctuation but preserve hyphens and spaces\n // Why: We want to keep hyphenated words like 'anak-anak' intact\n let cleaned = text;\n\n if (includeHyphenated) {\n // Keep hyphens, remove other punctuation\n // Replace punctuation except hyphens with spaces\n cleaned = text.replace(/[^\\w\\s-]/g, ' ');\n } else {\n // Replace all punctuation including hyphens with spaces\n cleaned = text.replace(/[^\\w\\s]/g, ' ');\n }\n\n // Split by whitespace to get individual words\n const words = cleaned\n .split(/\\s+/)\n .map((word) => word.trim())\n .filter((word) => word.length > 0)\n // Filter out words that are just hyphens (common artifact of punctuation removal)\n .filter((word) => !/^-+$/.test(word));\n\n // Apply filters\n let result = words;\n\n // Filter by minimum length\n if (minLength > 0) {\n result = result.filter((word) => word.length >= minLength);\n }\n\n // Convert to lowercase if requested\n if (lowercase) {\n result = result.map((word) => word.toLowerCase());\n }\n\n return result;\n}\n","import type { CompareOptions } from './types';\nimport { normalizeWhitespace, removeAccents } from './sanitize';\n\n/**\n * Compare strings with Indonesian-aware normalization\n *\n * This function allows flexible string comparison with options to ignore\n * case, whitespace, and accents. Useful for search, filtering, and\n * validation.\n *\n * **Features:**\n * - Case-insensitive comparison (default: false)\n * - Whitespace normalization (ignore extra spaces)\n * - Accent removal (café == cafe)\n * - Null-safe (handles empty strings)\n *\n * @param str1 - First string to compare\n * @param str2 - Second string to compare\n * @param options - Comparison options\n * @returns True if strings match according to options\n *\n * @example\n * Basic matching:\n * ```typescript\n * compareStrings('Hello', 'Hello') // → true\n * compareStrings('Hello', 'hello') // → false\n * ```\n *\n * @example\n * Case insensitive:\n * ```typescript\n * compareStrings('Hello', 'hello', { caseSensitive: false }) // → true\n * // Note: default is caseSensitive: false for convenience in many utils,\n * // but strict comparison usually defaults to true.\n * // Let's check the implementation default.\n * ```\n *\n * @example\n * Ignore whitespace:\n * ```typescript\n * compareStrings(' Hello World ', 'Hello World', { ignoreWhitespace: true })\n * // → true\n * ```\n *\n * @example\n * Ignore accents:\n * ```typescript\n * compareStrings('café', 'cafe', { ignoreAccents: true })\n * // → true\n * ```\n *\n * @public\n */\nexport function compareStrings(\n str1: string,\n str2: string,\n options?: CompareOptions\n): boolean {\n // Early return for exact match (optimization)\n if (str1 === str2) {\n return true;\n }\n\n // Handle null/undefined as empty strings for robust comparison\n // usage of (str || '') pattern\n const s1 = str1 || '';\n const s2 = str2 || '';\n\n const {\n caseSensitive = false,\n ignoreWhitespace = false,\n ignoreAccents = false,\n } = options || {};\n\n let normalized1 = s1;\n let normalized2 = s2;\n\n // Apply whitespace normalization\n if (ignoreWhitespace) {\n normalized1 = normalizeWhitespace(normalized1);\n normalized2 = normalizeWhitespace(normalized2);\n }\n\n // Apply accent removal\n if (ignoreAccents) {\n normalized1 = removeAccents(normalized1);\n normalized2 = removeAccents(normalized2);\n }\n\n // Apply case sensitivity\n if (!caseSensitive) {\n normalized1 = normalized1.toLowerCase();\n normalized2 = normalized2.toLowerCase();\n }\n\n return normalized1 === normalized2;\n}\n\n/**\n * Calculate similarity score between two strings (0-1) using Levenshtein distance\n *\n * This function measures the difference between two strings and returns a score\n * where 1.0 means identical and 0.0 means completely different.\n *\n * **Algorithm:**\n * Uses Levenshtein distance to calculate the minimum number of single-character\n * edits (insertions, deletions, substitutions) required to change one string\n * into the other.\n *\n * @param str1 - First string\n * @param str2 - Second string\n * @returns Similarity score between 0.0 and 1.0\n *\n * @example\n * Basic Usage:\n * ```typescript\n * similarity('hello', 'hello') // → 1.0 (identical)\n * similarity('hello', 'hallo') // → 0.8 (1 edit / 5 length)\n * similarity('hello', 'world') // → 0.2 (4 edits / 5 length)\n * ```\n *\n * @example\n * Case sensitivity:\n * Note: This function is case-sensitive. Use compareStrings options or\n * manual lowercasing if you need case-insensitive similarity.\n *\n * @public\n */\nexport function similarity(str1: string, str2: string): number {\n if (str1 === str2) return 1.0;\n if (str1.length === 0) return str2.length === 0 ? 1.0 : 0.0;\n if (str2.length === 0) return 0.0;\n\n const len1 = str1.length;\n const len2 = str2.length;\n\n // Track previous and current rows of the matrix\n // Optimization: We only need two rows, not the full matrix O(min(m,n)) space\n let prevRow = Array(len2 + 1).fill(0);\n let currentRow = Array(len2 + 1).fill(0);\n\n // Initialize first row\n for (let j = 0; j <= len2; j++) {\n prevRow[j] = j;\n }\n\n // Calculate distance\n for (let i = 1; i <= len1; i++) {\n currentRow[0] = i;\n\n for (let j = 1; j <= len2; j++) {\n const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;\n\n currentRow[j] = Math.min(\n currentRow[j - 1] + 1, // Insertion\n prevRow[j] + 1, // Deletion\n prevRow[j - 1] + cost // Substitution\n );\n }\n\n // Move current row to previous for next iteration\n [prevRow, currentRow] = [currentRow, prevRow];\n }\n\n // Calculate similarity: 1 - (distance / max_length)\n const distance = prevRow[len2];\n const maxLength = Math.max(len1, len2);\n\n return 1.0 - distance / maxLength;\n}\n","/**\n * Custom error classes for datetime module\n *\n * @module datetime/types\n * @packageDocumentation\n */\n\n/**\n * Error thrown when an invalid date is provided to a function.\n * Extends native Error with a `code` property for programmatic error handling.\n *\n * @example\n * ```typescript\n * try {\n * formatDate('invalid');\n * } catch (error) {\n * if (error instanceof InvalidDateError) {\n * console.log(error.code); // 'INVALID_DATE'\n * }\n * }\n * ```\n */\nexport class InvalidDateError extends Error {\n /** Error code for programmatic identification */\n readonly code = 'INVALID_DATE' as const;\n\n constructor(message: string = 'Invalid date provided') {\n super(message);\n this.name = 'InvalidDateError';\n }\n}\n\n/**\n * Error thrown when an invalid date range is provided.\n * Extends native Error with a `code` property for programmatic error handling.\n *\n * @example\n * ```typescript\n * try {\n * formatDateRange(new Date('2026-01-05'), new Date('2026-01-01'));\n * } catch (error) {\n * if (error instanceof InvalidDateRangeError) {\n * console.log(error.code); // 'INVALID_DATE_RANGE'\n * }\n * }\n * ```\n */\nexport class InvalidDateRangeError extends Error {\n /** Error code for programmatic identification */\n readonly code = 'INVALID_DATE_RANGE' as const;\n\n constructor(message: string = 'End date must be after start date') {\n super(message);\n this.name = 'InvalidDateRangeError';\n }\n}\n\n/**\n * Date formatting style options\n */\nexport type DateStyle =\n | 'full'\n | 'long'\n | 'medium'\n | 'short'\n | 'weekday'\n | 'month';\n\n/**\n * Options for getAge function\n */\nexport interface AgeOptions {\n /**\n * Reference date to calculate age from.\n * Defaults to current date at function call time.\n * @defaultValue new Date()\n */\n fromDate?: Date | string | number;\n\n /**\n * Return age as formatted string instead of object.\n * @defaultValue false\n */\n asString?: boolean;\n}\n\n/**\n * Age calculation result object\n */\nexport interface AgeResult {\n /** Full years */\n years: number;\n /** Remaining months (0-11) */\n months: number;\n /** Remaining days (0-30) */\n days: number;\n}\n","/**\n * Constants for Indonesian datetime formatting\n *\n * @module datetime/constants\n * @packageDocumentation\n */\n\n/** Full Indonesian month names (1-indexed: index 0 = empty, 1 = Januari) */\nexport const MONTH_NAMES: readonly string[] = [\n '', // Placeholder for 0-index\n 'Januari',\n 'Februari',\n 'Maret',\n 'April',\n 'Mei',\n 'Juni',\n 'Juli',\n 'Agustus',\n 'September',\n 'Oktober',\n 'November',\n 'Desember',\n];\n\n/** Short Indonesian month names (3-letter abbreviation) */\nexport const MONTH_NAMES_SHORT: readonly string[] = [\n '', // Placeholder for 0-index\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'Mei',\n 'Jun',\n 'Jul',\n 'Agu',\n 'Sep',\n 'Okt',\n 'Nov',\n 'Des',\n];\n\n/** Full Indonesian day names */\nexport const DAY_NAMES: readonly string[] = [\n 'Minggu',\n 'Senin',\n 'Selasa',\n 'Rabu',\n 'Kamis',\n 'Jumat',\n 'Sabtu',\n];\n\n/** Short Indonesian day names (3-letter abbreviation) */\nexport const DAY_NAMES_SHORT: readonly string[] = [\n 'Min',\n 'Sen',\n 'Sel',\n 'Rab',\n 'Kam',\n 'Jum',\n 'Sab',\n];\n\n/** Mapping of IANA timezone names to Indonesian abbreviations */\nexport const TIMEZONE_MAP: Readonly<Record<string, 'WIB' | 'WITA' | 'WIT'>> = {\n // UTC+7 - WIB\n 'Asia/Jakarta': 'WIB',\n 'Asia/Pontianak': 'WIB',\n\n // UTC+8 - WITA\n 'Asia/Makassar': 'WITA',\n 'Asia/Denpasar': 'WITA',\n 'Asia/Manado': 'WITA',\n 'Asia/Palu': 'WITA',\n\n // UTC+9 - WIT\n 'Asia/Jayapura': 'WIT',\n};\n\n/** Valid UTC offset hours that map to Indonesian timezones */\nexport const VALID_UTC_OFFSETS: readonly number[] = [7, 8, 9];\n","/**\n * Date calculation utilities\n *\n * @module datetime/calc\n * @packageDocumentation\n */\n\nimport { InvalidDateError } from './types';\n\n/**\n * Check if a year is a leap year.\n *\n * A year is a leap year if:\n * - Divisible by 4, but not by 100, OR\n * - Divisible by 400\n *\n * @param year - The year to check\n * @returns `true` if leap year, `false` otherwise (including invalid inputs)\n *\n * @example\n * ```typescript\n * isLeapYear(2024); // true\n * isLeapYear(2023); // false\n * isLeapYear(1900); // false (divisible by 100 but not 400)\n * isLeapYear(2000); // true (divisible by 400)\n * isLeapYear(NaN); // false\n * isLeapYear(3.5); // false (non-integer)\n * ```\n */\nexport function isLeapYear(year: number): boolean {\n // Return false for non-finite, non-integer, or NaN values\n if (!Number.isFinite(year) || !Number.isInteger(year)) {\n return false;\n }\n\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\n/**\n * Get the number of days in a month.\n *\n * Accounts for leap years in February.\n *\n * @param month - Month number (1-12, 1-indexed)\n * @param year - Full year (e.g., 2026)\n * @returns Number of days in the month, or 0 for invalid inputs\n *\n * @example\n * ```typescript\n * daysInMonth(1, 2026); // 31 (January)\n * daysInMonth(2, 2024); // 29 (February, leap year)\n * daysInMonth(2, 2023); // 28 (February, non-leap year)\n * daysInMonth(4, 2026); // 30 (April)\n * daysInMonth(13, 2026); // 0 (invalid month)\n * daysInMonth(2, NaN); // 0 (invalid year)\n * ```\n */\nexport function daysInMonth(month: number, year: number): number {\n // Validate inputs\n if (\n !Number.isFinite(month) ||\n !Number.isInteger(month) ||\n !Number.isFinite(year) ||\n !Number.isInteger(year) ||\n month < 1 ||\n month > 12\n ) {\n return 0;\n }\n\n // Months with 31 days: Jan(1), Mar(3), May(5), Jul(7), Aug(8), Oct(10), Dec(12)\n if ([1, 3, 5, 7, 8, 10, 12].includes(month)) {\n return 31;\n }\n\n // Months with 30 days: Apr(4), Jun(6), Sep(9), Nov(11)\n if ([4, 6, 9, 11].includes(month)) {\n return 30;\n }\n\n // February - check for leap year\n return isLeapYear(year) ? 29 : 28;\n}\n\n/**\n * Type guard to check if a value is a valid Date object.\n *\n * Returns `true` only for Date instances that represent a valid date\n * (i.e., not `Invalid Date`). Returns `false` for null, undefined,\n * invalid dates, and non-Date values.\n *\n * @param date - Value to check\n * @returns `true` if valid Date object, `false` otherwise\n *\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate(new Date('invalid')); // false\n * isValidDate(null); // false\n * isValidDate(undefined); // false\n * isValidDate('2024-01-01'); // false (string, not Date)\n * isValidDate(1704067200000); // false (number, not Date)\n * ```\n */\nexport function isValidDate(date: unknown): date is Date {\n return date instanceof Date && !Number.isNaN(date.getTime());\n}\n\n/**\n * Check if a date falls on a weekend (Saturday or Sunday).\n *\n * Note: This only checks Saturday/Sunday and does not account for\n * industry-specific Saturday work schedules.\n *\n * @param date - Date object to check\n * @returns `true` if Saturday or Sunday, `false` otherwise\n *\n * @example\n * ```typescript\n * isWeekend(new Date('2026-01-03')); // true (Saturday)\n * isWeekend(new Date('2026-01-04')); // true (Sunday)\n * isWeekend(new Date('2026-01-05')); // false (Monday)\n * ```\n */\nexport function isWeekend(date: Date): boolean {\n const day = date.getDay();\n return day === 0 || day === 6; // Sunday = 0, Saturday = 6\n}\n\n/**\n * Check if a date falls on a working day (Monday-Friday).\n *\n * Note: This only checks Monday-Friday and does not account for\n * national holidays (holiday lists require periodic updates and\n * are not included per project mandates).\n *\n * @param date - Date object to check\n * @returns `true` if Monday-Friday, `false` otherwise\n *\n * @example\n * ```typescript\n * isWorkingDay(new Date('2026-01-05')); // true (Monday)\n * isWorkingDay(new Date('2026-01-03')); // false (Saturday)\n * isWorkingDay(new Date('2026-01-04')); // false (Sunday)\n * ```\n */\nexport function isWorkingDay(date: Date): boolean {\n const day = date.getDay();\n return day >= 1 && day <= 5; // Monday = 1 to Friday = 5\n}\n\n/**\n * Normalize various date input types to a Date object.\n *\n * @param date - Date input (Date, string, or number timestamp)\n * @returns Date object\n * @throws {InvalidDateError} If the input cannot be parsed to a valid date\n */\nfunction normalizeDate(date: Date | string | number): Date {\n let result: Date;\n\n if (date instanceof Date) {\n result = date;\n } else if (typeof date === 'number') {\n result = new Date(date);\n } else if (typeof date === 'string') {\n result = new Date(date);\n } else {\n throw new InvalidDateError('Date must be a Date, string, or number');\n }\n\n if (Number.isNaN(result.getTime())) {\n throw new InvalidDateError(`Unable to parse date: ${String(date)}`);\n }\n\n return result;\n}\n\n/**\n * Calculate age from a birth date.\n *\n * Accounts for leap years and month length variations.\n * Can return as an object { years, months, days } or as a formatted string.\n *\n * @param birthDate - Birth date (Date, string, or number timestamp)\n * @param options - Options for age calculation\n * @returns Age as object or formatted string (based on asString option)\n * @throws {InvalidDateError} If birthDate or fromDate is invalid\n *\n * @example\n * ```typescript\n * // Get age as object\n * getAge('1990-06-15'); // { years: 36, months: 9, days: 21 }\n * getAge(new Date('1990-06-15'), { fromDate: new Date('2024-06-15') });\n * // { years: 34, months: 0, days: 0 }\n *\n * // Get age as string\n * getAge('1990-06-15', { asString: true });\n * // '36 Tahun 9 Bulan 21 Hari'\n *\n * getAge(new Date('2020-01-01'), { fromDate: new Date('2020-01-15'), asString: true });\n * // '15 Hari'\n * ```\n */\nexport function getAge(\n birthDate: Date | string | number,\n options: { fromDate?: Date | string | number; asString?: boolean } = {}\n): { years: number; months: number; days: number } | string {\n const birth = normalizeDate(birthDate);\n const from = options.fromDate ? normalizeDate(options.fromDate) : new Date();\n\n // Validate: birth date cannot be in the future\n if (birth.getTime() > from.getTime()) {\n throw new InvalidDateError(\n 'Birth date cannot be in the future relative to fromDate'\n );\n }\n\n let years = from.getFullYear() - birth.getFullYear();\n let months = from.getMonth() - birth.getMonth();\n let days = from.getDate() - birth.getDate();\n\n // Adjust for negative days\n if (days < 0) {\n months--;\n // Get days in previous month\n const prevMonth = from.getMonth() === 0 ? 11 : from.getMonth() - 1;\n const prevMonthYear =\n from.getMonth() === 0 ? from.getFullYear() - 1 : from.getFullYear();\n days += daysInMonth(prevMonth + 1, prevMonthYear);\n }\n\n // Adjust for negative months\n if (months < 0) {\n years--;\n months += 12;\n }\n\n const result = { years, months, days };\n\n if (options.asString) {\n return formatAgeString(result);\n }\n\n return result;\n}\n\n/**\n * Format age object as Indonesian string.\n * Omits zero components.\n *\n * @param age - Age object with years, months, days\n * @returns Formatted age string\n */\nfunction formatAgeString(age: {\n years: number;\n months: number;\n days: number;\n}): string {\n const parts: string[] = [];\n\n if (age.years > 0) {\n parts.push(`${age.years} Tahun`);\n }\n\n if (age.months > 0) {\n parts.push(`${age.months} Bulan`);\n }\n\n if (age.days > 0) {\n parts.push(`${age.days} Hari`);\n }\n\n // Handle edge case: all zeros (same day)\n if (parts.length === 0) {\n return '0 Hari';\n }\n\n return parts.join(' ');\n}\n","/**\n * Date parsing utilities for Indonesian formats\n *\n * @module datetime/parse\n * @packageDocumentation\n */\n\nimport { daysInMonth } from './calc';\n\n/**\n * Parse a date string in Indonesian format (DD-MM-YYYY) or ISO format (YYYY-MM-DD).\n *\n * Strict parsing rules:\n * - Accepts delimiters: `/`, `-`, `.`\n * - DD-MM-YYYY format: Day first (1-31), 4-digit year required\n * - ISO auto-detection: If first segment is 4 digits AND > 31, treated as YYYY-MM-DD\n * - Leap year validation: Feb 29 is only valid in leap years\n * - 2-digit years NOT supported\n * - Time components NOT supported\n *\n * @param dateStr - Date string to parse\n * @returns Date object if valid, `null` if invalid\n *\n * @example\n * ```typescript\n * // Indonesian format (DD-MM-YYYY)\n * parseDate('02-01-2026'); // Date(2026, 0, 2) - Jan 2, 2026\n * parseDate('02/01/2026'); // Date(2026, 0, 2)\n * parseDate('02.01.2026'); // Date(2026, 0, 2)\n *\n * // ISO format auto-detected (YYYY-MM-DD)\n * parseDate('2026-01-02'); // Date(2026, 0, 2)\n *\n * // Invalid inputs return null\n * parseDate('29-02-2023'); // null (not a leap year)\n * parseDate('02-01-26'); // null (2-digit year)\n * parseDate('02-01-2026 14:30'); // null (time component)\n * parseDate('invalid'); // null\n * ```\n */\nexport function parseDate(dateStr: string): Date | null {\n // Trim whitespace\n const trimmed = dateStr.trim();\n\n // Reject if empty\n if (!trimmed) {\n return null;\n }\n\n // Reject if contains time component (has space or colon)\n if (trimmed.includes(' ') || trimmed.includes(':')) {\n return null;\n }\n\n // Split by supported delimiters: / - .\n const parts = trimmed.split(/[-/.]/);\n\n // Must have exactly 3 parts\n if (parts.length !== 3) {\n return null;\n }\n\n // Parse all segments as integers\n const nums = parts.map((p) => parseInt(p, 10));\n\n // Check for NaN or negative values\n if (nums.some((n) => Number.isNaN(n) || n < 0)) {\n return null;\n }\n\n // Check for 2-digit years (any segment < 100 after the first position)\n // First segment can be < 100 (day) or > 31 (year in ISO format)\n const [first, second, third] = nums;\n\n // Determine format: ISO (YYYY-MM-DD) or Indonesian (DD-MM-YYYY)\n let day: number;\n let month: number;\n let year: number;\n\n // ISO format detection: first segment is 4 digits AND > 31 (must be a year)\n if (first > 999 && first > 31) {\n // ISO format: YYYY-MM-DD\n year = first;\n month = second;\n day = third;\n } else {\n // Indonesian format: DD-MM-YYYY\n // Validate that third segment is 4 digits (year)\n if (third < 1000) {\n return null; // 2-digit year not supported\n }\n\n day = first;\n month = second;\n year = third;\n }\n\n // Validate month range (1-12)\n if (month < 1 || month > 12) {\n return null;\n }\n\n // Validate year is reasonable (positive and 4 digits)\n if (year < 1000 || year > 9999) {\n return null;\n }\n\n // Validate day against month length\n const maxDays = daysInMonth(month, year);\n if (maxDays === 0 || day < 1 || day > maxDays) {\n return null;\n }\n\n // Create date (month is 0-indexed in JS Date)\n const date = new Date(year, month - 1, day);\n\n // Final validation: ensure the date was created correctly\n // (catches edge cases like Feb 30 being converted to Mar 2)\n if (\n date.getFullYear() !== year ||\n date.getMonth() !== month - 1 ||\n date.getDate() !== day\n ) {\n return null;\n }\n\n return date;\n}\n","/**\n * Date formatting utilities for Indonesian locale\n *\n * @module datetime/format\n * @packageDocumentation\n */\n\nimport {\n InvalidDateError,\n InvalidDateRangeError,\n type DateStyle,\n} from './types';\nimport { MONTH_NAMES, MONTH_NAMES_SHORT, DAY_NAMES } from './constants';\n\n/**\n * Normalize various date input types to a Date object.\n *\n * @param date - Date input (Date, string, or number timestamp)\n * @returns Date object\n * @throws {InvalidDateError} If the input cannot be parsed to a valid date\n */\nfunction normalizeDate(date: Date | string | number): Date {\n let result: Date;\n\n if (date instanceof Date) {\n result = date;\n } else if (typeof date === 'number') {\n // Assume milliseconds timestamp\n result = new Date(date);\n } else if (typeof date === 'string') {\n result = new Date(date);\n } else {\n throw new InvalidDateError('Date must be a Date, string, or number');\n }\n\n // Validate the result\n if (Number.isNaN(result.getTime())) {\n throw new InvalidDateError(`Unable to parse date: ${String(date)}`);\n }\n\n return result;\n}\n\n/**\n * Format a date with Indonesian locale.\n *\n * @param date - Date to format (Date, string, or number timestamp in milliseconds)\n * @param style - Formatting style (default: 'long')\n * @returns Formatted date string\n * @throws {InvalidDateError} If the date is invalid\n *\n * @example\n * ```typescript\n * formatDate(new Date('2026-01-02'), 'full'); // 'Jumat, 2 Januari 2026'\n * formatDate(new Date('2026-01-02'), 'long'); // '2 Januari 2026'\n * formatDate(new Date('2026-01-02'), 'medium'); // '2 Jan 2026'\n * formatDate(new Date('2026-01-02'), 'short'); // '02/01/2026'\n * formatDate(new Date('2026-01-02'), 'weekday'); // 'Jumat'\n * formatDate(new Date('2026-01-02'), 'month'); // 'Januari'\n * ```\n */\nexport function formatDate(\n date: Date | string | number,\n style: DateStyle = 'long'\n): string {\n const d = normalizeDate(date);\n\n const day = d.getDate();\n const month = d.getMonth() + 1; // 1-indexed\n const year = d.getFullYear();\n const dayOfWeek = d.getDay(); // 0 = Sunday\n\n switch (style) {\n case 'full':\n return `${DAY_NAMES[dayOfWeek]}, ${day} ${MONTH_NAMES[month]} ${year}`;\n\n case 'long':\n return `${day} ${MONTH_NAMES[month]} ${year}`;\n\n case 'medium':\n return `${day} ${MONTH_NAMES_SHORT[month]} ${year}`;\n\n case 'short': {\n const dd = String(day).padStart(2, '0');\n const mm = String(month).padStart(2, '0');\n return `${dd}/${mm}/${year}`;\n }\n\n case 'weekday':\n return DAY_NAMES[dayOfWeek];\n\n case 'month':\n return MONTH_NAMES[month];\n\n default:\n throw new InvalidDateError(`Unknown format style: ${style}`);\n }\n}\n\n/**\n * Format a date range with Indonesian locale and smart redundancy removal.\n *\n * Removes redundant month/year information when dates share them.\n *\n * @param start - Start date\n * @param end - End date\n * @param style - Formatting style (default: 'long')\n * @returns Formatted date range string\n * @throws {InvalidDateError} If either date is invalid\n * @throws {InvalidDateRangeError} If end date is before start date\n *\n * @example\n * ```typescript\n * // Same day\n * formatDateRange(\n * new Date('2026-01-02'),\n * new Date('2026-01-02')\n * ); // '2 Januari 2026'\n *\n * // Same month & year\n * formatDateRange(\n * new Date('2026-01-02'),\n * new Date('2026-01-05')\n * ); // '2 - 5 Januari 2026'\n *\n * // Same year\n * formatDateRange(\n * new Date('2026-01-30'),\n * new Date('2026-02-02')\n * ); // '30 Januari - 2 Februari 2026'\n *\n * // Different year\n * formatDateRange(\n * new Date('2025-12-30'),\n * new Date('2026-01-02')\n * ); // '30 Desember 2025 - 2 Januari 2026'\n * ```\n */\nexport function formatDateRange(\n start: Date,\n end: Date,\n style: Exclude<DateStyle, 'weekday' | 'month'> = 'long'\n): string {\n const s = normalizeDate(start);\n const e = normalizeDate(end);\n\n // Validate range\n if (e.getTime() < s.getTime()) {\n throw new InvalidDateRangeError();\n }\n\n // Short style: no redundancy removal, always full format\n if (style === 'short') {\n return `${formatDate(s, 'short')} - ${formatDate(e, 'short')}`;\n }\n\n // Full style: full weekday + date for both\n if (style === 'full') {\n return `${formatDate(s, 'full')} - ${formatDate(e, 'full')}`;\n }\n\n // Extract components\n const sDay = s.getDate();\n const eDay = e.getDate();\n const sMonth = s.getMonth() + 1;\n const eMonth = e.getMonth() + 1;\n const sYear = s.getFullYear();\n const eYear = e.getFullYear();\n\n // Same day: show single date\n if (sDay === eDay && sMonth === eMonth && sYear === eYear) {\n return formatDate(s, style);\n }\n\n // Different year: full format for both\n if (sYear !== eYear) {\n return `${formatDate(s, style)} - ${formatDate(e, style)}`;\n }\n\n // Same year, different month: omit year from start date\n if (sMonth !== eMonth) {\n if (style === 'long') {\n return `${sDay} ${MONTH_NAMES[sMonth]} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;\n }\n // medium style\n return `${sDay} ${MONTH_NAMES_SHORT[sMonth]} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;\n }\n\n // Same month & year: show range with single month/year\n if (style === 'long') {\n return `${sDay} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;\n }\n // medium style\n return `${sDay} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;\n}\n","/**\n * Relative time formatting for Indonesian locale\n *\n * @module datetime/relative\n * @packageDocumentation\n */\n\nimport { InvalidDateError } from './types';\nimport { formatDate } from './format';\n\n/**\n * Normalize various date input types to a Date object.\n *\n * @param date - Date input (Date, string, or number timestamp)\n * @returns Date object\n * @throws {InvalidDateError} If the input cannot be parsed to a valid date\n */\nfunction normalizeDate(date: Date | string | number): Date {\n let result: Date;\n\n if (date instanceof Date) {\n result = date;\n } else if (typeof date === 'number') {\n result = new Date(date);\n } else if (typeof date === 'string') {\n result = new Date(date);\n } else {\n throw new InvalidDateError('Date must be a Date, string, or number');\n }\n\n if (Number.isNaN(result.getTime())) {\n throw new InvalidDateError(`Unable to parse date: ${String(date)}`);\n }\n\n return result;\n}\n\n/**\n * Format a date as relative time in Indonesian.\n *\n * Returns human-readable relative time like \"Baru saja\", \"X menit yang lalu\",\n * \"Kemarin\", or falls back to formatted date for older dates.\n *\n * @param date - Date to format (Date, string, or number timestamp in milliseconds)\n * @param baseDate - Reference date for comparison (default: current date)\n * @returns Relative time string in Indonesian\n * @throws {InvalidDateError} If either date is invalid\n *\n * @example\n * ```typescript\n * // Assuming today is 2026-01-02 12:00:00\n * toRelativeTime(new Date('2026-01-02 11:59:00')); // 'Baru saja'\n * toRelativeTime(new Date('2026-01-02 11:00:00')); // '1 jam yang lalu'\n * toRelativeTime(new Date('2026-01-01 12:00:00')); // 'Kemarin'\n * toRelativeTime(new Date('2025-12-30 12:00:00')); // '3 hari yang lalu'\n * toRelativeTime(new Date('2025-12-01 12:00:00')); // '1 Desember 2025'\n * ```\n */\nexport function toRelativeTime(\n date: Date | string | number,\n baseDate: Date = new Date()\n): string {\n const d = normalizeDate(date);\n const base = normalizeDate(baseDate);\n\n const diffMs = d.getTime() - base.getTime();\n const diffSec = Math.floor(diffMs / 1000);\n const diffMin = Math.floor(diffMs / (1000 * 60));\n const diffHour = Math.floor(diffMs / (1000 * 60 * 60));\n const diffDay = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n // Exact match\n if (diffMs === 0) {\n return 'Sekarang';\n }\n\n // Future dates\n if (diffMs > 0) {\n // < 1 minute\n if (diffSec < 60) {\n return 'Baru saja';\n }\n\n // < 60 minutes\n if (diffMin < 60) {\n return `${diffMin} menit lagi`;\n }\n\n // < 24 hours\n if (diffHour < 24) {\n return `${diffHour} jam lagi`;\n }\n\n // 1 day (24-48 hours)\n if (diffHour < 48) {\n return 'Besok';\n }\n\n // 2-30 days\n if (diffDay <= 30) {\n return `${diffDay} hari lagi`;\n }\n\n // > 30 days: fallback to formatted date\n return formatDate(d, 'long');\n }\n\n // Past dates\n const absDiffSec = Math.abs(diffSec);\n const absDiffMin = Math.abs(diffMin);\n const absDiffHour = Math.abs(diffHour);\n const absDiffDay = Math.abs(diffDay);\n\n // < 1 minute\n if (absDiffSec < 60) {\n return 'Baru saja';\n }\n\n // < 60 minutes\n if (absDiffMin < 60) {\n return `${absDiffMin} menit yang lalu`;\n }\n\n // < 24 hours\n if (absDiffHour < 24) {\n return `${absDiffHour} jam yang lalu`;\n }\n\n // 1 day (24-48 hours)\n if (absDiffHour < 48) {\n return 'Kemarin';\n }\n\n // 2-30 days\n if (absDiffDay <= 30) {\n return `${absDiffDay} hari yang lalu`;\n }\n\n // > 30 days: fallback to formatted date\n return formatDate(d, 'long');\n}\n","/**\n * Timezone utilities for Indonesian locale\n *\n * @module datetime/timezone\n * @packageDocumentation\n */\n\nimport { TIMEZONE_MAP } from './constants';\n\n/**\n * Map IANA timezone names or UTC offsets to Indonesian abbreviations (WIB/WITA/WIT).\n *\n * Supported mappings:\n * - UTC+7 / Asia/Jakarta / Asia/Pontianak → \"WIB\"\n * - UTC+8 / Asia/Makassar / Asia/Denpasar → \"WITA\"\n * - UTC+9 / Asia/Jayapura → \"WIT\"\n *\n * @param input - IANA timezone name (case-sensitive), offset in hours, or offset string\n * @returns Indonesian timezone abbreviation or null if not Indonesian\n *\n * @example\n * ```typescript\n * // IANA timezone names\n * getIndonesianTimezone('Asia/Jakarta'); // 'WIB'\n * getIndonesianTimezone('Asia/Makassar'); // 'WITA'\n * getIndonesianTimezone('Asia/Jayapura'); // 'WIT'\n *\n * // Offset as number (hours)\n * getIndonesianTimezone(7); // 'WIB'\n * getIndonesianTimezone(8); // 'WITA'\n * getIndonesianTimezone(9); // 'WIT'\n *\n * // Offset as string\n * getIndonesianTimezone('+07:00'); // 'WIB'\n * getIndonesianTimezone('+0700'); // 'WIB'\n * getIndonesianTimezone('+08:00'); // 'WITA'\n *\n * // Non-Indonesian returns null\n * getIndonesianTimezone('America/New_York'); // null\n * getIndonesianTimezone(-5); // null\n * ```\n */\nexport function getIndonesianTimezone(\n input: string | number\n): 'WIB' | 'WITA' | 'WIT' | null {\n // Handle number input (offset in hours)\n if (typeof input === 'number') {\n if (!Number.isFinite(input) || !Number.isInteger(input)) {\n return null;\n }\n\n switch (input) {\n case 7:\n return 'WIB';\n case 8:\n return 'WITA';\n case 9:\n return 'WIT';\n default:\n return null;\n }\n }\n\n // Handle string input\n if (typeof input !== 'string') {\n return null;\n }\n\n const trimmed = input.trim();\n\n // Check if it's an offset string (+07:00, +0700, -05:00, etc.)\n const offsetMatch = trimmed.match(/^([+-])(\\d{2}):?(\\d{2})$/);\n if (offsetMatch) {\n const sign = offsetMatch[1];\n const hours = parseInt(offsetMatch[2], 10);\n const minutes = parseInt(offsetMatch[3], 10);\n\n // Indonesian timezones are all positive (UTC+)\n if (sign === '-') {\n return null;\n }\n\n // Validate format (must be exactly on the hour, no minutes)\n if (minutes !== 0) {\n return null;\n }\n\n // Map to Indonesian timezone\n switch (hours) {\n case 7:\n return 'WIB';\n case 8:\n return 'WITA';\n case 9:\n return 'WIT';\n default:\n return null;\n }\n }\n\n // Check if it's an IANA timezone name\n if (TIMEZONE_MAP[trimmed]) {\n return TIMEZONE_MAP[trimmed];\n }\n\n // Unknown timezone\n return null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/nik/constants.ts","../src/nik/utils/date.ts","../src/nik/validate.ts","../src/nik/parse.ts","../src/nik/format.ts","../src/nik/utils.ts","../src/phone/constants.ts","../src/phone/validate.ts","../src/phone/utils.ts","../src/phone/format.ts","../src/phone/links.ts","../src/phone/parse.ts","../src/npwp/validate.ts","../src/npwp/format.ts","../src/plate/regions.ts","../src/plate/utils.ts","../src/vin/constants.ts","../src/vin/validate.ts","../src/email-validator/constants.ts","../src/email-validator/email-validator.ts","../src/currency/format.ts","../src/currency/parse.ts","../src/currency/words.ts","../src/currency/utils.ts","../src/text/constants.ts","../src/text/capitalization.ts","../src/text/slug.ts","../src/text/sanitize.ts","../src/text/abbreviation.ts","../src/text/filter.ts","../src/text/normalization.ts","../src/text/extract.ts","../src/text/compare.ts","../src/datetime/types.ts","../src/datetime/constants.ts","../src/datetime/calc.ts","../src/datetime/parse.ts","../src/datetime/format.ts","../src/datetime/relative.ts","../src/datetime/timezone.ts"],"names":["NIK_PATTERN","capitalize","escapeRegex","getAge","normalizeDate"],"mappings":"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;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA;AAAA,EAGA,IAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,IAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA;AAAA,EAGA,IAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA;AAAA,EAGA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA;AAAA,EACA,OAAA;AAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EACA,KAAA;AAAA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","file":"index.js","sourcesContent":["/**\n * Indonesian province codes and names\n * Based on Dukcapil Kemendagri data\n */\nexport const PROVINCES: Record<string, string> = {\n '11': 'Aceh',\n '12': 'Sumatera Utara',\n '13': 'Sumatera Barat',\n '14': 'Riau',\n '15': 'Jambi',\n '16': 'Sumatera Selatan',\n '17': 'Bengkulu',\n '18': 'Lampung',\n '19': 'Kepulauan Bangka Belitung',\n '21': 'Kepulauan Riau',\n '31': 'DKI Jakarta',\n '32': 'Jawa Barat',\n '33': 'Jawa Tengah',\n '34': 'DI Yogyakarta',\n '35': 'Jawa Timur',\n '36': 'Banten',\n '51': 'Bali',\n '52': 'Nusa Tenggara Barat',\n '53': 'Nusa Tenggara Timur',\n '61': 'Kalimantan Barat',\n '62': 'Kalimantan Tengah',\n '63': 'Kalimantan Selatan',\n '64': 'Kalimantan Timur',\n '65': 'Kalimantan Utara',\n '71': 'Sulawesi Utara',\n '72': 'Sulawesi Tengah',\n '73': 'Sulawesi Selatan',\n '74': 'Sulawesi Tenggara',\n '75': 'Gorontalo',\n '76': 'Sulawesi Barat',\n '81': 'Maluku',\n '82': 'Maluku Utara',\n '91': 'Papua',\n '92': 'Papua Barat',\n '93': 'Papua Selatan',\n '94': 'Papua Tengah',\n '95': 'Papua Pegunungan',\n '96': 'Papua Barat Daya',\n};\n\n/**\n * Regency codes for each province (simplified - only major ones)\n * In a real implementation, you'd have complete data\n */\nexport const REGENCIES: Record<string, Record<string, string>> = {\n '32': {\n '01': 'Kab. Bogor',\n '02': 'Kab. Sukabumi',\n '03': 'Kab. Cianjur',\n '71': 'Kota Bandung',\n '72': 'Kota Bekasi',\n '73': 'Kota Depok',\n },\n '31': { \n '01': 'Kota Jakarta Selatan',\n '02': 'Kota Jakarta Timur',\n '03': 'Kota Jakarta Pusat',\n '04': 'Kota Jakarta Barat',\n '05': 'Kota Jakarta Utara',\n },\n};","/**\n * Shared date parsing and validation utilities for NIK module.\n *\n * @module nik/utils/date\n * @packageDocumentation\n */\n\n/**\n * Result of parsing date components from a NIK string.\n *\n * @public\n */\nexport interface ParsedNIKDate {\n /** 2-digit year code (00-99) from NIK positions 7-8 */\n year: number;\n /** Full 4-digit year (1900-1999 or 2000-2099) */\n fullYear: number;\n /** Month (1-12) from NIK positions 9-10 */\n month: number;\n /** Actual day (1-31), decoded from encoded day */\n day: number;\n /** Gender derived from day encoding */\n gender: 'male' | 'female';\n /** Original encoded day (1-31 for male, 41-71 for female) */\n dayEncoded: number;\n}\n\n/**\n * Parses date components from a NIK string.\n *\n * Extracts year, month, and encoded day from positions 7-12 of the NIK.\n * For females, the day is encoded as (actual day + 40).\n *\n * @param nik - 16-digit NIK string\n * @returns ParsedNIKDate or null if NIK format is invalid\n *\n * @example\n * ```typescript\n * const result = parseNIKDate('3201018901310123');\n * // { year: 89, fullYear: 1989, month: 1, day: 31, gender: 'male', dayEncoded: 31 }\n * ```\n *\n * @public\n */\nexport function parseNIKDate(nik: string): ParsedNIKDate | null {\n if (nik.length !== 16) {\n return null;\n }\n\n const yearStr = nik.substring(6, 8);\n const monthStr = nik.substring(8, 10);\n const dayEncodedStr = nik.substring(10, 12);\n\n const year = parseInt(yearStr, 10);\n if (isNaN(year)) return null;\n\n const fullYear = year > 30 ? 1900 + year : 2000 + year;\n\n const month = parseInt(monthStr, 10);\n if (isNaN(month)) return null;\n\n const dayEncoded = parseInt(dayEncodedStr, 10);\n if (isNaN(dayEncoded)) return null;\n\n const gender: 'male' | 'female' = dayEncoded > 40 ? 'female' : 'male';\n const day = dayEncoded > 40 ? dayEncoded - 40 : dayEncoded;\n\n return { year, fullYear, month, day, gender, dayEncoded };\n}\n\n/**\n * Validates if year/month/day form a valid calendar date.\n *\n * Uses JavaScript's Date object to check if the date actually exists\n * (handles leap years, invalid month/day combinations).\n *\n * @param year - Full 4-digit year\n * @param month - Month (1-12)\n * @param day - Day (1-31)\n * @returns true if valid calendar date\n *\n * @example\n * ```typescript\n * validateNIKDateComponents(2024, 2, 29); // true (leap year)\n * validateNIKDateComponents(2023, 2, 29); // false\n * validateNIKDateComponents(2024, 13, 1); // false\n * ```\n *\n * @public\n */\nexport function validateNIKDateComponents(\n year: number,\n month: number,\n day: number\n): boolean {\n if (month < 1 || month > 12) return false;\n if (day < 1 || day > 31) return false;\n\n const testDate = new Date(year, month - 1, day);\n return (\n testDate.getFullYear() === year &&\n testDate.getMonth() === month - 1 &&\n testDate.getDate() === day\n );\n}\n","import { PROVINCES } from './constants';\nimport { parseNIKDate, validateNIKDateComponents } from './utils/date';\n\nconst NIK_PATTERN = /^\\d{16}$/;\n\n/**\n * Validates a NIK (Nomor Induk Kependudukan) format.\n *\n * A valid NIK must:\n * - Be exactly 16 digits\n * - Have a valid province code (positions 1-2)\n * - Have a valid date (positions 7-12)\n * - Not be in the future\n * - Not be before 1900\n *\n * For female NIKs, the day is encoded as (actual day + 40).\n * For example, a female born on the 15th would have day = 55.\n *\n * @param nik - The 16-digit NIK string to validate\n * @returns `true` if the NIK is valid, `false` otherwise\n *\n * @example\n * ```typescript\n * validateNIK('3201234567890123'); // true - valid NIK\n * validateNIK('1234'); // false - wrong length\n * validateNIK('9912345678901234'); // false - invalid province\n * ```\n *\n * @public\n */\nexport function validateNIK(nik: string): boolean {\n if (!NIK_PATTERN.test(nik)) {\n return false;\n }\n\n const provinceCode = nik.substring(0, 2);\n if (!PROVINCES[provinceCode]) {\n return false;\n }\n\n const parsed = parseNIKDate(nik);\n if (!parsed) {\n return false;\n }\n\n const { fullYear, month, day } = parsed;\n\n if (!validateNIKDateComponents(fullYear, month, day)) {\n return false;\n }\n\n const now = new Date();\n if (new Date(fullYear, month - 1, day) > now || fullYear < 1900) {\n return false;\n }\n\n return true;\n}\n","import { PROVINCES, REGENCIES } from './constants';\nimport { NIKInfo } from './types';\nimport { parseNIKDate, validateNIKDateComponents } from './utils/date';\n\nconst NIK_PATTERN = /^\\d{16}$/;\n\n/**\n * Parses a NIK and extracts all embedded information.\n *\n * Extracts province, regency, district codes, birth date, gender,\n * and serial number from a 16-digit NIK string.\n *\n * @param nik - The 16-digit NIK string to parse\n * @returns Parsed NIK information, or `null` if the NIK format is invalid\n *\n * @example\n * Parse a valid male NIK:\n * ```typescript\n * const info = parseNIK('3201018901310123');\n * console.log(info);\n * // {\n * // province: { code: '32', name: 'Jawa Barat' },\n * // regency: { code: '01', name: 'Kab. Bogor' },\n * // district: { code: '01', name: null },\n * // birthDate: Date(1989, 0, 31), // Jan 31, 1989\n * // gender: 'male',\n * // serialNumber: '0123',\n * // isValid: true\n * // }\n * ```\n *\n * @example\n * Parse a female NIK (day + 40):\n * ```typescript\n * const info = parseNIK('3201019508550123');\n * console.log(info.gender); // 'female'\n * console.log(info.birthDate); // Date(1995, 7, 15) - Aug 15, 1995\n * ```\n *\n * @example\n * Invalid NIK returns null:\n * ```typescript\n * const info = parseNIK('invalid');\n * console.log(info); // null\n * ```\n *\n * @public\n */\nexport function parseNIK(nik: string): NIKInfo | null {\n if (!NIK_PATTERN.test(nik)) {\n return null;\n }\n\n const provinceCode = nik.substring(0, 2);\n const regencyCode = nik.substring(2, 4);\n const districtCode = nik.substring(4, 6);\n const serialNumber = nik.substring(12, 16);\n\n const province = PROVINCES[provinceCode];\n if (!province) {\n return null;\n }\n\n const regencies = REGENCIES[provinceCode] || {};\n const regency = regencies[regencyCode] || 'Unknown';\n\n const parsed = parseNIKDate(nik);\n if (!parsed) {\n return null;\n }\n\n const { fullYear, month, day, gender } = parsed;\n\n if (!validateNIKDateComponents(fullYear, month, day)) {\n return null;\n }\n\n const birthDate = new Date(fullYear, month - 1, day);\n\n return {\n province: {\n code: provinceCode,\n name: province,\n },\n regency: {\n code: regencyCode,\n name: regency,\n },\n district: {\n code: districtCode,\n name: null,\n },\n birthDate,\n gender,\n serialNumber,\n isValid: true,\n };\n}\n","import { MaskOptions } from './types';\n\n/**\n * Formats a NIK with separators for better readability.\n *\n * Groups the NIK into logical segments: province, regency, district,\n * year, month, day, and serial number.\n *\n * @param nik - The 16-digit NIK string to format\n * @param separator - Character to use as separator\n * @returns Formatted NIK string, or original string if invalid format\n *\n * @example\n * Default separator (dash):\n * ```typescript\n * formatNIK('3201234567890123');\n * // '32-01-23-45-67-89-0123'\n * ```\n *\n * @example\n * Custom separator:\n * ```typescript\n * formatNIK('3201234567890123', ' ');\n * // '32 01 23 45 67 89 0123'\n * ```\n *\n * @example\n * Invalid NIK returns as-is:\n * ```typescript\n * formatNIK('1234');\n * // '1234'\n * ```\n *\n * @public\n */\nexport function formatNIK(nik: string, separator: string = '-'): string {\n if (!/^\\d{16}$/.test(nik)) {\n return nik;\n }\n\n // Format: PP-KK-DD-YY-MM-DD-XXXX\n // PP = Province (2 digits)\n // KK = Regency (2 digits)\n // DD = District (2 digits)\n // YY = Year (2 digits)\n // MM = Month (2 digits)\n // DD = Day (2 digits, +40 for female)\n // XXXX = Serial number (4 digits)\n return [\n nik.substring(0, 2), // Province\n nik.substring(2, 4), // Regency\n nik.substring(4, 6), // District\n nik.substring(6, 8), // Year\n nik.substring(8, 10), // Month\n nik.substring(10, 12), // Day\n nik.substring(12, 16), // Serial\n ].join(separator);\n}\n\n/**\n * Masks a NIK to protect privacy while keeping partial visibility.\n *\n * By default, shows the first 4 and last 4 digits, masking the middle 8.\n * Optionally formats the masked NIK with separators.\n *\n * @param nik - The 16-digit NIK string to mask\n * @param options - Masking configuration options\n * @returns Masked NIK string, or original string if invalid format\n *\n * @example\n * Default masking (first 4, last 4):\n * ```typescript\n * maskNIK('3201234567890123');\n * // '3201********0123'\n * ```\n *\n * @example\n * Custom mask character:\n * ```typescript\n * maskNIK('3201234567890123', { char: 'X' });\n * // '3201XXXXXXXX0123'\n * ```\n *\n * @example\n * With separator:\n * ```typescript\n * maskNIK('3201234567890123', { separator: '-' });\n * // '32-01-**-**-**-**-0123'\n * ```\n *\n * @example\n * Custom start and end:\n * ```typescript\n * maskNIK('3201234567890123', { start: 6, end: 4 });\n * // '320123******0123'\n * ```\n *\n * @public\n */\nexport function maskNIK(nik: string, options: MaskOptions = {}): string {\n if (!/^\\d{16}$/.test(nik)) {\n return nik;\n }\n\n const { start = 4, end = 4, char = '*', separator } = options;\n\n if (start + end >= 16) {\n return nik;\n }\n\n if (separator) {\n // Format with separator first, then apply masking\n const formatted = formatNIK(nik, separator);\n const parts = formatted.split(separator);\n\n // Calculate which parts to mask\n // Format: PP-KK-DD-YY-MM-DD-XXXX (7 parts)\n // Mask parts based on character positions\n let charCount = 0;\n const maskedParts = parts.map((part) => {\n const partStart = charCount;\n const partEnd = charCount + part.length;\n charCount += part.length;\n\n // Check if this part should be fully/partially masked\n if (partEnd <= start) {\n // Fully visible (before start)\n return part;\n } else if (partStart >= 16 - end) {\n // Fully visible (after end)\n return part;\n } else if (partStart >= start && partEnd <= 16 - end) {\n // Fully masked\n return char.repeat(part.length);\n } else {\n // Partially masked\n return part\n .split('')\n .map((ch, idx) => {\n const pos = partStart + idx;\n if (pos < start || pos >= 16 - end) {\n return ch;\n }\n return char;\n })\n .join('');\n }\n });\n\n return maskedParts.join(separator);\n }\n\n // Without separator: simple masking\n const startPart = nik.substring(0, start);\n const endPart = nik.substring(16 - end);\n const maskLength = 16 - start - end;\n return startPart + char.repeat(maskLength) + endPart;\n}","import { parseNIK } from './parse';\n\n/**\n * Calculates the age of a person based on their NIK.\n *\n * @param nik - The 16-digit NIK string\n * @param referenceDate - The date to calculate age from (default: current date)\n * @returns The age in years, or null if the NIK is invalid or birth date cannot be parsed\n *\n * @example\n * ```typescript\n * getAge('3201018901310123'); // 35 (as of 2024)\n * ```\n */\nexport function getAge(\n nik: string,\n referenceDate: Date = new Date()\n): number | null {\n const info = parseNIK(nik);\n if (!info || !info.birthDate) {\n return null;\n }\n\n const birthDate = info.birthDate;\n let age = referenceDate.getFullYear() - birthDate.getFullYear();\n const m = referenceDate.getMonth() - birthDate.getMonth();\n\n if (m < 0 || (m === 0 && referenceDate.getDate() < birthDate.getDate())) {\n age--;\n }\n\n return age;\n}\n\n/**\n * Formats the birth date from a NIK into a human-readable string.\n *\n * @param nik - The 16-digit NIK string\n * @param locale - The locale to use for formatting (default: 'id-ID')\n * @returns Formatted birth date string, or null if invalid\n *\n * @example\n * ```typescript\n * formatBirthDate('3201018901310123'); // '31 Januari 1989'\n * ```\n */\nexport function formatBirthDate(\n nik: string,\n options: Intl.DateTimeFormatOptions = {\n day: 'numeric',\n month: 'long',\n year: 'numeric',\n },\n locale: string = 'id-ID'\n): string | null {\n const info = parseNIK(nik);\n if (!info || !info.birthDate) {\n return null;\n }\n\n return new Intl.DateTimeFormat(locale, options).format(info.birthDate);\n}\n\n/**\n * Checks if a NIK matches a specific gender.\n *\n * @param nik - The 16-digit NIK string\n * @param gender - The gender to check ('male' | 'female')\n * @returns True if the NIK matches the gender, false otherwise\n */\nexport function isValidForGender(\n nik: string,\n gender: 'male' | 'female'\n): boolean {\n const info = parseNIK(nik);\n if (!info) {\n return false;\n }\n return info.gender === gender;\n}\n\n/**\n * Checks if a NIK matches a specific birth date.\n *\n * @param nik - The 16-digit NIK string\n * @param birthDate - The birth date to check\n * @returns True if the NIK matches the birth date, false otherwise\n */\nexport function isValidForBirthDate(nik: string, birthDate: Date): boolean {\n const info = parseNIK(nik);\n if (!info || !info.birthDate) {\n return false;\n }\n\n return (\n info.birthDate.getFullYear() === birthDate.getFullYear() &&\n info.birthDate.getMonth() === birthDate.getMonth() &&\n info.birthDate.getDate() === birthDate.getDate()\n );\n}\n","import { OperatorName } from './types';\n\n/**\n * Phone number constants for Indonesian operators and area codes.\n *\n * Data sources:\n * - Operator prefixes: Official operator documentation and Wikipedia\n * - Area codes: Ministry of Communication and Information Technology (Kemendagri)\n *\n * Last updated: December 2025\n *\n * @see {@link https://en.wikipedia.org/wiki/Telephone_numbers_in_Indonesia Wikipedia - Telephone numbers in Indonesia}\n * @internal\n */\n\n/**\n * Mobile operator prefix mapping.\n *\n * Maps 4-digit prefixes (e.g., '0812') to operator names.\n * Used for operator detection in mobile numbers.\n *\n * **Important Notes:**\n * - Tri (3 Indonesia) has merged with Indosat as of 2024\n * - Axis has been acquired by XL but maintains separate branding\n * - Some operators have both prepaid and postpaid services\n *\n * @example\n * ```typescript\n * OPERATOR_PREFIXES['0812']; // 'Telkomsel'\n * OPERATOR_PREFIXES['0817']; // 'XL'\n * OPERATOR_PREFIXES['0895']; // 'Indosat'\n * ```\n *\n * @internal\n */\nexport const OPERATOR_PREFIXES: Record<string, OperatorName> = {\n // Telkomsel (Halo, Simpati, by.U)\n '0811': 'Telkomsel',\n '0812': 'Telkomsel',\n '0813': 'Telkomsel',\n '0821': 'Telkomsel',\n '0822': 'Telkomsel',\n '0823': 'Telkomsel',\n '0851': 'Telkomsel',\n '0852': 'Telkomsel',\n '0853': 'Telkomsel',\n\n // XL Axiata (XL Prepaid, XL Prioritas, LIVE.ON)\n '0817': 'XL',\n '0818': 'XL',\n '0819': 'XL',\n '0859': 'XL',\n '0877': 'XL',\n '0878': 'XL',\n '0879': 'XL',\n\n // Indosat Ooredoo (IM3, Mentari)\n // Note: Tri (3 Indonesia) merged with Indosat\n '0814': 'Indosat',\n '0815': 'Indosat',\n '0816': 'Indosat',\n '0855': 'Indosat',\n '0856': 'Indosat',\n '0857': 'Indosat',\n '0858': 'Indosat',\n '0895': 'Indosat',\n '0896': 'Indosat',\n '0897': 'Indosat',\n '0898': 'Indosat',\n '0899': 'Indosat',\n\n // Smartfren (Smartfren Power Up)\n '0881': 'Smartfren',\n '0882': 'Smartfren',\n '0883': 'Smartfren',\n '0884': 'Smartfren',\n '0885': 'Smartfren',\n '0886': 'Smartfren',\n '0887': 'Smartfren',\n '0888': 'Smartfren',\n '0889': 'Smartfren',\n\n // Axis (Acquired by XL but maintains separate branding)\n '0831': 'Axis',\n '0832': 'Axis',\n '0833': 'Axis',\n '0838': 'Axis',\n} as const;\n\n/**\n * Landline area code mapping.\n *\n * Maps area codes to city/region names for landline numbers.\n * Includes both 3-digit (e.g., '021') and 4-digit (e.g., '0274') codes.\n *\n * This mapping covers all provinces in Indonesia including:\n * - Jakarta, Banten, West Java, Central Java, Yogyakarta\n * - East Java, Bali, Nusa Tenggara\n * - Sulawesi, Kalimantan\n * - Sumatra, Maluku, Papua\n *\n * @example\n * ```typescript\n * AREA_CODES['021']; // 'Jakarta'\n * AREA_CODES['0274']; // 'Yogyakarta'\n * AREA_CODES['0361']; // 'Denpasar'\n * ```\n *\n * @internal\n */\nexport const AREA_CODES: Record<string, string> = {\n // ========================================\n // JAKARTA, BANTEN & WEST JAVA\n // ========================================\n\n // Jakarta & Greater Jakarta\n '021': 'Jakarta',\n\n // Banten\n '0252': 'Lebak',\n '0253': 'Pandeglang',\n '0254': 'Cilegon & Serang',\n\n // West Java\n '022': 'Bandung',\n '0231': 'Cirebon',\n '0232': 'Kuningan',\n '0233': 'Majalengka',\n '0234': 'Indramayu',\n '0251': 'Bogor',\n '0260': 'Subang',\n '0261': 'Sumedang',\n '0262': 'Garut',\n '0263': 'Cianjur',\n '0264': 'Purwakarta',\n '0265': 'Tasikmalaya',\n '0266': 'Sukabumi',\n '0267': 'Karawang',\n\n // ========================================\n // CENTRAL JAVA & YOGYAKARTA\n // ========================================\n\n // Central Java\n '024': 'Semarang',\n '0271': 'Solo',\n '0272': 'Klaten',\n '0273': 'Wonogiri',\n '0275': 'Purworejo',\n '0276': 'Boyolali',\n '0280': 'Cilacap',\n '0281': 'Banyumas & Purbalingga',\n '0282': 'Cilacap',\n '0283': 'Tegal & Brebes',\n '0284': 'Pemalang',\n '0285': 'Pekalongan',\n '0286': 'Banjarnegara & Wonosobo',\n '0287': 'Kebumen',\n '0289': 'Bumiayu',\n '0291': 'Kudus & Jepara',\n '0292': 'Grobogan',\n '0293': 'Magelang',\n '0294': 'Kendal',\n '0295': 'Pati & Rembang',\n '0296': 'Blora',\n '0297': 'Karimun Jawa',\n '0298': 'Salatiga',\n\n // Yogyakarta\n '0274': 'Yogyakarta',\n\n // ========================================\n // EAST JAVA, BALI & NUSA TENGGARA\n // ========================================\n\n // East Java\n '031': 'Surabaya',\n '0321': 'Mojokerto & Jombang',\n '0322': 'Lamongan',\n '0323': 'Sampang',\n '0324': 'Pamekasan',\n '0325': 'Bawean',\n '0326': 'Masalembu',\n '0327': 'Kangean',\n '0328': 'Sumenep',\n '0331': 'Jember',\n '0332': 'Bondowoso',\n '0333': 'Banyuwangi',\n '0334': 'Lumajang',\n '0335': 'Probolinggo',\n '0336': 'Jember',\n '0338': 'Situbondo',\n '0341': 'Malang',\n '0342': 'Blitar',\n '0343': 'Pasuruan',\n '0351': 'Madiun',\n '0352': 'Ponorogo',\n '0353': 'Bojonegoro',\n '0354': 'Kediri',\n '0355': 'Tulungagung',\n '0356': 'Tuban',\n '0357': 'Pacitan',\n '0358': 'Nganjuk',\n\n // Bali\n '0361': 'Denpasar',\n '0362': 'Singaraja',\n '0363': 'Amlapura',\n '0365': 'Negara',\n '0366': 'Tabanan',\n '0368': 'Gianyar',\n\n // Nusa Tenggara Barat (NTB)\n '0370': 'Mataram',\n '0371': 'Sumbawa',\n '0372': 'West Sumbawa',\n '0373': 'Dompu',\n '0374': 'Bima',\n '0376': 'East Lombok',\n\n // Nusa Tenggara Timur (NTT)\n '0379': 'Alor',\n '0380': 'Kupang',\n '0381': 'Ende',\n '0382': 'Sikka',\n '0383': 'East Flores',\n '0384': 'Ngada',\n '0385': 'Manggarai',\n '0386': 'West Manggarai',\n '0387': 'Sumba',\n '0388': 'North & South Central Timor',\n '0389': 'Belu',\n\n // ========================================\n // SULAWESI\n // ========================================\n\n // South Sulawesi\n '0410': 'Pangkajene',\n '0411': 'Makassar',\n '0413': 'Bantaeng & Bulukumba',\n '0414': 'Selayar',\n '0417': 'Malino',\n '0418': 'Takalar',\n '0419': 'Jeneponto',\n '0420': 'Enrekang',\n '0421': 'Pare Pare',\n '0423': 'Tana Toraja',\n '0427': 'Barru',\n '0471': 'Luwu',\n '0472': 'Wajo (Pitumpanua)',\n '0473': 'North Luwu',\n '0474': 'East Luwu',\n '0475': 'Sorowako',\n '0481': 'Bone',\n '0482': 'Sinjai',\n '0484': 'Soppeng',\n '0485': 'Wajo',\n\n // West Sulawesi\n '0422': 'Majene',\n '0426': 'Mamuju',\n '0428': 'Polewali',\n '0429': 'Central Mamuju',\n\n // Central Sulawesi\n '0409': 'Morowali',\n '0445': 'Buol',\n '0450': 'Parigi Moutong',\n '0451': 'Palu',\n '0452': 'Poso',\n '0453': 'Toli-Toli',\n '0454': 'Tinombo',\n '0455': 'Moutong',\n '0457': 'Donggala',\n '0458': 'Tentena',\n '0461': 'Banggai',\n '0462': 'Banggai Island',\n '0463': 'Bunta',\n '0464': 'Tojo Una-Una',\n '0465': 'North Morowali',\n\n // Southeast Sulawesi\n '0401': 'Kendari',\n '0402': 'Buton',\n '0403': 'Muna',\n '0404': 'Wakatobi',\n '0405': 'Kolaka',\n '0408': 'Konawe',\n\n // North Sulawesi\n '0430': 'South Minahasa',\n '0431': 'Manado',\n '0432': 'Sangihe',\n '0433': 'Talaud',\n '0434': 'Bolaang Mongondow',\n '0438': 'Bitung',\n\n // Gorontalo\n '0435': 'Gorontalo',\n '0442': 'North Gorontalo',\n '0443': 'Pohuwato',\n\n // ========================================\n // KALIMANTAN\n // ========================================\n\n // West Kalimantan\n '0534': 'Ketapang',\n '0535': 'Kayong Utara',\n '0561': 'Pontianak',\n '0562': 'Sambas & Singkawang',\n '0563': 'Landak',\n '0564': 'Sanggau',\n '0565': 'Sintang',\n '0567': 'Kapuas Hulu',\n '0568': 'Melawi',\n\n // Central Kalimantan\n '0513': 'Kapuas',\n '0519': 'North Barito',\n '0526': 'South & East Barito',\n '0528': 'Murung Raya',\n '0531': 'East Kotawaringin',\n '0532': 'West Kotawaringin',\n '0536': 'Palangka Raya',\n '0537': 'Gunung Mas',\n '0538': 'Seruyan',\n '0539': 'Seruyan & East Kotawaringin',\n\n // South Kalimantan\n '0511': 'Banjarmasin',\n '0512': 'Tanah Laut',\n '0517': 'Hulu Sungai Selatan',\n '0518': 'Tanah Bumbu',\n '0527': 'Hulu Sungai Utara',\n\n // East Kalimantan\n '0541': 'Samarinda',\n '0542': 'Balikpapan',\n '0543': 'Paser',\n '0545': 'West Kutai',\n '0548': 'Bontang',\n '0549': 'East Kutai',\n '0554': 'Berau',\n\n // North Kalimantan\n '0551': 'Tarakan',\n '0552': 'Bulungan',\n '0553': 'Malinau',\n '0556': 'Nunukan',\n\n // ========================================\n // SUMATRA\n // ========================================\n\n // Aceh\n '0627': 'Subulussalam & Dairi (North Sumatra)',\n '0629': 'Southeast Aceh',\n '0641': 'Langsa',\n '0642': 'Gayo Lues',\n '0643': 'Central Aceh',\n '0644': 'Bireuen',\n '0645': 'Lhokseumawe',\n '0646': 'East Aceh',\n '0650': 'Simeulue',\n '0651': 'Banda Aceh',\n '0652': 'Sabang',\n '0653': 'Pidie',\n '0654': 'Aceh Jaya',\n '0655': 'West Aceh',\n '0656': 'South Aceh',\n '0657': 'South Aceh',\n '0658': 'Singkil',\n '0659': 'Southwest Aceh',\n\n // North Sumatra\n '061': 'Medan',\n '0620': 'Pangkalan Brandan',\n '0621': 'Tebing Tinggi',\n '0622': 'Pematang Siantar',\n '0623': 'Asahan',\n '0624': 'Labuhan Batu',\n '0625': 'Parapat',\n '0626': 'Samosir',\n // '0627': 'Dairi', // for this prefix, it same with Subulussalam (Aceh)\n '0628': 'Karo',\n '0630': 'South Nias',\n '0631': 'Sibolga',\n '0632': 'Toba Samosir',\n '0633': 'North Tapanuli',\n '0634': 'Padang Sidempuan',\n '0635': 'South Tapanuli',\n '0636': 'Mandailing Natal',\n '0638': 'Barus',\n '0639': 'Nias',\n\n // West Sumatra\n '0751': 'Padang',\n '0752': 'Bukittinggi',\n '0753': 'Pasaman',\n '0754': 'Sawahlunto',\n '0755': 'Solok',\n '0756': 'South Pesisir',\n '0757': 'South Pesisir',\n '0759': 'Mentawai',\n\n // Riau\n '0760': 'Kuantan Singingi',\n '0761': 'Pekanbaru',\n '0762': 'Kampar',\n '0763': 'Bengkalis',\n '0764': 'Siak',\n '0765': 'Dumai',\n '0766': 'Bengkalis',\n '0767': 'Rokan Hulu',\n '0768': 'Indragiri Hilir',\n '0769': 'Indragiri Hulu',\n\n // Riau Islands\n '0770': 'Muka Kuning Batamindo',\n '0771': 'Tanjungpinang',\n '0772': 'Anambas',\n '0773': 'Natuna',\n '0776': 'Lingga',\n '0777': 'Great Karimun',\n '0778': 'Batam',\n '0779': 'Kundur',\n\n // Jambi\n '0741': 'Jambi',\n '0742': 'West Tanjung Jabung',\n '0743': 'Batanghari',\n '0744': 'Tebo',\n '0745': 'Sarolangun',\n '0746': 'Merangin',\n '0747': 'Bungo',\n '0748': 'Kerinci',\n\n // South Sumatra\n '0702': 'Empat Lawang',\n '0711': 'Palembang',\n '0712': 'Ogan Komering Ilir',\n '0713': 'Prabumulih',\n '0714': 'Musi Banyuasin',\n '0730': 'Pagar Alam',\n '0731': 'Lahat',\n '0733': 'Lubuklinggau',\n '0734': 'Muara Enim',\n '0735': 'Ogan Komering Ulu',\n\n // Bangka Belitung\n '0715': 'Belinyu',\n '0716': 'West Bangka',\n '0717': 'Pangkal Pinang',\n '0718': 'Central & South Bangka',\n '0719': 'Belitung',\n\n // Bengkulu\n '0732': 'Rejang Lebong',\n '0736': 'Bengkulu',\n '0737': 'North Bengkulu',\n '0739': 'South Bengkulu',\n\n // Lampung\n '0721': 'Bandar Lampung',\n '0722': 'Tanggamus',\n '0723': 'Way Kanan',\n '0724': 'North Lampung',\n '0725': 'Metro',\n '0726': 'Tulang Bawang',\n '0727': 'South Lampung',\n '0728': 'West Lampung',\n '0729': 'Pringsewu',\n\n // ========================================\n // MALUKU & PAPUA\n // ========================================\n\n // Maluku\n '0910': 'Ambon',\n '0911': 'Southeast Maluku',\n '0913': 'Tual',\n '0914': 'Saumlaki',\n '0916': 'Namlea',\n '0918': 'Ternate',\n '0921': 'Sanana',\n '0924': 'Tobelo',\n\n // Papua & West Papua\n '0901': 'Timika',\n '0902': 'Agats',\n '0951': 'Sorong',\n '0952': 'South Sorong',\n '0967': 'Manokwari',\n '0969': 'Sorong',\n '0971': 'Merauke',\n '0975': 'Boven Digoel',\n '0979': 'Tembagapura',\n '0981': 'Jayapura',\n '0986': 'Wamena',\n} as const;\n\n/**\n * Valid mobile number prefixes (first 4 digits after country code).\n *\n * Used for quick validation without operator detection.\n *\n * @internal\n */\nexport const VALID_MOBILE_PREFIXES = Object.keys(OPERATOR_PREFIXES);\n\n/**\n * Valid area codes for landline numbers.\n *\n * Used for landline validation.\n *\n * @internal\n */\nexport const VALID_AREA_CODES = Object.keys(AREA_CODES);\n","import { OPERATOR_PREFIXES, AREA_CODES } from './constants';\n\n/**\n * Validates an Indonesian phone number format.\n *\n * Accepts multiple input formats:\n * - National format: 08xx-xxxx-xxxx or 08xxxxxxxxxx\n * - International with +: +62 8xx-xxxx-xxxx or +628xxxxxxxxxx\n * - International without +: 62 8xx-xxxx-xxxx or 628xxxxxxxxxx\n *\n * For mobile numbers, validates:\n * - Starts with 08 (national) or 628 (international)\n * - Has valid operator prefix (0811, 0812, 0817, etc.)\n * - Total length is 10-13 digits (after removing non-digits)\n *\n * For landline numbers, validates:\n * - Starts with 0 followed by area code (021, 022, etc.)\n * - Total length is appropriate for landline\n *\n * @param phone - The phone number string to validate\n * @returns `true` if the phone number is valid, `false` otherwise\n *\n * @example\n * Valid mobile number (national):\n * ```typescript\n * validatePhoneNumber('081234567890'); // true\n * ```\n *\n * @example\n * Valid mobile number (international):\n * ```typescript\n * validatePhoneNumber('+6281234567890'); // true\n * validatePhoneNumber('6281234567890'); // true\n * ```\n *\n * @example\n * With separators:\n * ```typescript\n * validatePhoneNumber('0812-3456-7890'); // true\n * validatePhoneNumber('+62 812-3456-7890'); // true\n * ```\n *\n * @example\n * Invalid numbers:\n * ```typescript\n * validatePhoneNumber('1234'); // false - too short\n * validatePhoneNumber('08001234567'); // false - invalid prefix\n * validatePhoneNumber('+1234567890'); // false - wrong country code\n * ```\n *\n * @public\n */\nexport function validatePhoneNumber(phone: string): boolean {\n if (!phone || typeof phone !== 'string') {\n return false;\n }\n\n // Only allow digits, +, -, space, parentheses, dot\n if (!/^[\\d\\s\\-+().]+$/.test(phone)) {\n return false;\n }\n\n const cleaned = phone.replace(/[\\s\\-().]/g, '');\n\n let normalized: string;\n\n if (cleaned.startsWith('+62')) {\n normalized = '0' + cleaned.substring(3);\n } else if (cleaned.startsWith('62') && !cleaned.startsWith('620')) {\n normalized = '0' + cleaned.substring(2);\n } else if (cleaned.startsWith('0')) {\n normalized = cleaned;\n } else {\n return false;\n }\n\n if (normalized.startsWith('08')) {\n return validateMobileNumber(normalized);\n }\n\n if (normalized.startsWith('0')) {\n return validateLandlineNumber(normalized);\n }\n\n return false;\n}\n\n/**\n * Validates a mobile phone number (08xx format).\n *\n * @param phone - Phone number in 08xx format\n * @returns true if valid mobile number\n * @internal\n */\nfunction validateMobileNumber(phone: string): boolean {\n // Mobile numbers should be 10-13 digits\n if (phone.length < 10 || phone.length > 13) {\n return false;\n }\n\n // Check if prefix is valid (first 4 digits)\n const prefix = phone.substring(0, 4);\n if (!OPERATOR_PREFIXES[prefix]) {\n return false;\n }\n\n // All digits should be numeric\n if (!/^\\d+$/.test(phone)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Validates a landline phone number.\n *\n * @param phone - Phone number in landline format\n * @returns true if valid landline number\n * @internal\n */\nfunction validateLandlineNumber(phone: string): boolean {\n // Landline numbers typically 9-11 digits\n if (phone.length < 9 || phone.length > 11) {\n return false;\n }\n\n // Check common area codes (3 or 4 digits)\n const areaCode3 = phone.substring(0, 3);\n const areaCode4 = phone.substring(0, 4);\n\n if (AREA_CODES[areaCode3] || AREA_CODES[areaCode4]) {\n return true;\n }\n\n // If not in our area code list, check if it follows general pattern\n // Landlines start with 0 followed by 2-4 digit area code\n if (/^0[2-9]\\d{7,9}$/.test(phone)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Checks if a phone number is a mobile number.\n *\n * @param phone - The phone number to check\n * @returns `true` if it's a mobile number (08xx), `false` otherwise\n *\n * @example\n * ```typescript\n * isMobileNumber('081234567890'); // true\n * isMobileNumber('+6281234567890'); // true\n * isMobileNumber('0212345678'); // false (landline)\n * ```\n *\n * @public\n */\nexport function isMobileNumber(phone: string): boolean {\n if (!validatePhoneNumber(phone)) {\n return false;\n }\n\n const cleaned = phone.replace(/[^\\d+]/g, '');\n let normalized: string;\n\n if (cleaned.startsWith('+62')) {\n normalized = '0' + cleaned.substring(3);\n } else if (cleaned.startsWith('62') && !cleaned.startsWith('620')) {\n normalized = '0' + cleaned.substring(2);\n } else {\n normalized = cleaned;\n }\n\n return normalized.startsWith('08');\n}\n\n/**\n * Checks if a phone number is a landline number.\n *\n * @param phone - The phone number to check\n * @returns `true` if it's a landline number, `false` otherwise\n *\n * @example\n * ```typescript\n * isLandlineNumber('0212345678'); // true\n * isLandlineNumber('081234567890'); // false (mobile)\n * ```\n *\n * @public\n */\nexport function isLandlineNumber(phone: string): boolean {\n if (!validatePhoneNumber(phone)) {\n return false;\n }\n\n return !isMobileNumber(phone);\n}\n","import { AREA_CODES } from './constants';\n\n/**\n * Normalizes a cleaned phone number to national format (0xxx).\n *\n * Accepts pre-cleaned phone string (digits only, optional leading +).\n * Use `cleanPhoneNumber()` first if input may contain separators.\n *\n * @param phone - Cleaned phone number string\n * @returns Phone number in 08xx format, or empty string if invalid\n *\n * @example\n * ```typescript\n * normalizePhoneNumber('+6281234567890'); // '081234567890'\n * normalizePhoneNumber('6281234567890'); // '081234567890'\n * normalizePhoneNumber('081234567890'); // '081234567890'\n * ```\n *\n * @example\n * Invalid inputs return empty string:\n * ```typescript\n * normalizePhoneNumber(''); // ''\n * normalizePhoneNumber('620812345678'); // '' (620 is not valid country code pattern)\n * normalizePhoneNumber('invalid'); // ''\n * ```\n *\n * @public\n */\nexport function normalizePhoneNumber(phone: string): string {\n if (!phone || typeof phone !== 'string') {\n return '';\n }\n\n if (phone.startsWith('+62')) {\n return '0' + phone.substring(3);\n }\n\n if (phone.startsWith('62') && !phone.startsWith('620')) {\n return '0' + phone.substring(2);\n }\n\n if (phone.startsWith('0')) {\n return phone;\n }\n\n return '';\n}\n\n/**\n * Compares two phone numbers regardless of format.\n *\n * Both inputs are normalized to E.164 format for comparison.\n * Returns false if either input is invalid.\n *\n * @param phoneA - First phone number in any format\n * @param phoneB - Second phone number in any format\n * @returns true if both represent the same number, false otherwise\n *\n * @example\n * Same number in different formats:\n * ```typescript\n * comparePhones('081234567890', '+6281234567890'); // true\n * comparePhones('0812-3456-7890', '6281234567890'); // true\n * ```\n *\n * @example\n * Different numbers:\n * ```typescript\n * comparePhones('081234567890', '081234567891'); // false\n * comparePhones('0212345678', '0221234567'); // false\n * ```\n *\n * @example\n * Invalid inputs return false:\n * ```typescript\n * comparePhones('invalid', '081234567890'); // false\n * comparePhones('', ''); // false\n * ```\n *\n * @public\n */\nexport function comparePhones(phoneA: string, phoneB: string): boolean {\n if (typeof phoneA !== 'string' || typeof phoneB !== 'string') {\n return false;\n }\n\n const cleanedA = phoneA.replace(/[^\\d+]/g, '');\n const cleanedB = phoneB.replace(/[^\\d+]/g, '');\n\n const normalizedA = normalizePhoneNumber(cleanedA);\n const normalizedB = normalizePhoneNumber(cleanedB);\n\n if (!normalizedA || !normalizedB) {\n return false;\n }\n\n const e164A = '62' + normalizedA.substring(1);\n const e164B = '62' + normalizedB.substring(1);\n\n return e164A === e164B;\n}\n\n/**\n * Gets the region name for a landline number.\n *\n * Accepts phone number in any format (national, international, e164).\n *\n * @param phone - Landline phone number in any format\n * @returns Region name, or null if not found or if mobile number\n *\n * @example\n * ```typescript\n * getLandlineRegion('0212345678'); // 'Jakarta'\n * getLandlineRegion('+62212345678'); // 'Jakarta'\n * getLandlineRegion('081234567890'); // null (mobile)\n * ```\n *\n * @public\n */\nexport function getLandlineRegion(phone: string): string | null {\n if (!phone || typeof phone !== 'string') {\n return null;\n }\n\n const cleaned = phone.replace(/[^\\d+]/g, '');\n const normalized = normalizePhoneNumber(cleaned);\n\n if (!normalized || !normalized.startsWith('0')) {\n return null;\n }\n\n if (normalized.startsWith('08')) {\n return null;\n }\n\n const areaCode4 = normalized.substring(0, 4);\n if (AREA_CODES[areaCode4]) {\n return AREA_CODES[areaCode4];\n }\n\n const areaCode3 = normalized.substring(0, 3);\n if (AREA_CODES[areaCode3]) {\n return AREA_CODES[areaCode3];\n }\n\n const areaCode2 = normalized.substring(0, 2);\n if (AREA_CODES[areaCode2]) {\n return AREA_CODES[areaCode2];\n }\n\n return null;\n}\n","import { AREA_CODES } from './constants';\nimport { PhoneFormat, MaskOptions } from './types';\nimport { validatePhoneNumber } from './validate';\nimport { normalizePhoneNumber } from './utils';\n\n/**\n * Formats an Indonesian phone number to the specified format.\n *\n * Accepts various input formats and converts to the desired output format.\n * Automatically adds appropriate separators for readability.\n *\n * @param phone - The phone number to format\n * @param format - Target format ('international', 'national', 'e164', 'display')\n * @returns Formatted phone number, or original string if invalid\n *\n * @example\n * International format:\n * ```typescript\n * formatPhoneNumber('081234567890', 'international');\n * // '+62 812-3456-7890'\n * ```\n *\n * @example\n * National format:\n * ```typescript\n * formatPhoneNumber('+6281234567890', 'national');\n * // '0812-3456-7890'\n * ```\n *\n * @example\n * E.164 format (no spaces/dashes):\n * ```typescript\n * formatPhoneNumber('0812-3456-7890', 'e164');\n * // '6281234567890'\n * ```\n *\n * @public\n */\nexport function formatPhoneNumber(\n phone: string,\n format: PhoneFormat = 'national'\n): string {\n if (!validatePhoneNumber(phone)) {\n return phone;\n }\n\n const cleaned = cleanPhoneNumber(phone);\n\n const normalized = normalizePhoneNumber(cleaned);\n if (!normalized) {\n return phone;\n }\n\n switch (format) {\n case 'international':\n return toInternational(normalized);\n case 'national':\n case 'display':\n return toNational(normalized);\n case 'e164':\n return toE164(normalized);\n default:\n return phone;\n }\n}\n\n/**\n * Converts a phone number to international format (+62 xxx-xxxx-xxxx).\n *\n * @param phone - The phone number to convert\n * @returns Phone number in international format with separators\n *\n * @example\n * ```typescript\n * toInternational('081234567890');\n * // '+62 812-3456-7890'\n * ```\n *\n * @example\n * Already international:\n * ```typescript\n * toInternational('+6281234567890');\n * // '+62 812-3456-7890'\n * ```\n *\n * @public\n */\nexport function toInternational(phone: string): string {\n const cleaned = cleanPhoneNumber(phone);\n if (!cleaned) {\n return phone;\n }\n\n const normalized = normalizePhoneNumber(cleaned);\n if (!normalized) {\n return phone;\n }\n\n const withoutZero = normalized.substring(1);\n\n if (normalized.startsWith('08')) {\n if (withoutZero.length === 11) {\n return `+62 ${withoutZero.substring(0, 3)}-${withoutZero.substring(3, 7)}-${withoutZero.substring(7)}`;\n } else if (withoutZero.length === 10) {\n return `+62 ${withoutZero.substring(0, 3)}-${withoutZero.substring(3, 6)}-${withoutZero.substring(6)}`;\n } else if (withoutZero.length === 9) {\n return `+62 ${withoutZero.substring(0, 3)}-${withoutZero.substring(3)}`;\n } else if (withoutZero.length === 12) {\n return `+62 ${withoutZero.substring(0, 3)}-${withoutZero.substring(3, 7)}-${withoutZero.substring(7)}`;\n }\n }\n\n const areaCodeLength = getAreaCodeLength(normalized);\n const areaCode = normalized.substring(1, areaCodeLength + 1);\n const localNumber = normalized.substring(areaCodeLength + 1);\n\n return `+62 ${areaCode}-${localNumber}`;\n}\n\n/**\n * Converts a phone number to national format (08xx-xxxx-xxxx).\n *\n * @param phone - The phone number to convert\n * @returns Phone number in national format with dashes\n *\n * @example\n * ```typescript\n * toNational('+6281234567890');\n * // '0812-3456-7890'\n * ```\n *\n * @example\n * Already national:\n * ```typescript\n * toNational('081234567890');\n * // '0812-3456-7890'\n * ```\n *\n * @public\n */\nexport function toNational(phone: string): string {\n const cleaned = cleanPhoneNumber(phone);\n if (!cleaned) {\n return phone;\n }\n\n const normalized = normalizePhoneNumber(cleaned);\n if (!normalized) {\n return phone;\n }\n\n if (normalized.startsWith('08')) {\n if (normalized.length === 12) {\n return `${normalized.substring(0, 4)}-${normalized.substring(4, 8)}-${normalized.substring(8)}`;\n } else if (normalized.length === 11) {\n return `${normalized.substring(0, 4)}-${normalized.substring(4, 7)}-${normalized.substring(7)}`;\n } else if (normalized.length === 10) {\n return `${normalized.substring(0, 4)}-${normalized.substring(4)}`;\n } else if (normalized.length === 13) {\n return `${normalized.substring(0, 4)}-${normalized.substring(4, 8)}-${normalized.substring(8)}`;\n }\n }\n\n const areaCodeLength = getAreaCodeLength(normalized);\n const areaCodeWithZero = normalized.substring(0, areaCodeLength + 1);\n const localNumber = normalized.substring(areaCodeLength + 1);\n\n return `${areaCodeWithZero}-${localNumber}`;\n}\n\n/**\n * Converts a phone number to E.164 format (6281234567890).\n *\n * E.164 is the international standard format without spaces or dashes.\n * Suitable for API calls and database storage.\n *\n * @param phone - The phone number to convert\n * @returns Phone number in E.164 format\n *\n * @example\n * ```typescript\n * toE164('0812-3456-7890');\n * // '6281234567890'\n * ```\n *\n * @example\n * From international format:\n * ```typescript\n * toE164('+62 812-3456-7890');\n * // '6281234567890'\n * ```\n *\n * @public\n */\nexport function toE164(phone: string): string {\n const cleaned = cleanPhoneNumber(phone);\n if (!cleaned) {\n return phone;\n }\n\n const normalized = normalizePhoneNumber(cleaned);\n if (!normalized) {\n return phone;\n }\n\n return '62' + normalized.substring(1);\n}\n\n/**\n * Removes all non-digit characters from a phone number, preserving leading +.\n *\n * @param phone - The phone number to clean\n * @returns Cleaned phone number with only digits (and optional leading +)\n *\n * @example\n * ```typescript\n * cleanPhoneNumber('0812-3456-7890');\n * // '081234567890'\n * ```\n *\n * @example\n * ```typescript\n * cleanPhoneNumber('+62 812 3456 7890');\n * // '+6281234567890'\n * ```\n *\n * @public\n */\nexport function cleanPhoneNumber(phone: string): string {\n if (!phone || typeof phone !== 'string') {\n return '';\n }\n\n return phone.replace(/[^\\d+]/g, '');\n}\n\n/**\n * Determines area code length for landline numbers.\n *\n * @param normalized - Phone number in national format (0xxx)\n * @returns Area code length (digits after leading 0)\n * @internal\n */\nfunction getAreaCodeLength(normalized: string): number {\n // Check 4-digit area codes ('0xxxx')\n const fourDigitCode = normalized.substring(0, 5);\n if (AREA_CODES[fourDigitCode]) {\n return 4;\n }\n\n // Check 3-digit area codes ('0xxx')\n const threeDigitCode = normalized.substring(0, 4);\n if (AREA_CODES[threeDigitCode]) {\n return 3;\n }\n\n // Check 2-digit area codes ('0xx')\n const twoDigitCode = normalized.substring(0, 3);\n if (AREA_CODES[twoDigitCode]) {\n return 2;\n }\n\n return 2;\n}\n\n/**\n * Masks a phone number for privacy protection.\n *\n * By default, shows the first 4 and last 4 digits, masking the middle digits.\n * Optionally formats with separators.\n *\n * @param phone - The phone number to mask\n * @param options - Masking configuration options\n * @returns Masked phone number, or original string if invalid\n *\n * @example\n * Default masking:\n * ```typescript\n * maskPhoneNumber('081234567890');\n * // '0812****7890'\n * ```\n *\n * @example\n * Custom mask character:\n * ```typescript\n * maskPhoneNumber('081234567890', { char: 'X' });\n * // '0812XXXX7890'\n * ```\n *\n * @example\n * With separator:\n * ```typescript\n * maskPhoneNumber('081234567890', { separator: '-' });\n * // '0812-****-7890'\n * ```\n *\n * @public\n */\nexport function maskPhoneNumber(\n phone: string,\n options: MaskOptions = {}\n): string {\n const cleaned = cleanPhoneNumber(phone);\n if (!cleaned) {\n return phone;\n }\n\n const isInternational = cleaned.startsWith('+');\n let toMask: string;\n\n if (isInternational) {\n toMask = cleaned;\n } else {\n const normalized = normalizePhoneNumber(cleaned);\n toMask = normalized || cleaned;\n }\n\n if (toMask.length < 4) {\n return phone;\n }\n\n const { char = '*', separator } = options;\n let { start = 4, end = 4 } = options;\n\n if (start + end >= toMask.length) {\n // Auto-adjust for short numbers to ensure masking happens\n if (toMask.length < 10) {\n const minMaskLength = 1;\n const availableForVisible = toMask.length - minMaskLength;\n\n if (availableForVisible >= 2) {\n start = Math.floor(availableForVisible / 2);\n end = availableForVisible - start;\n } else {\n return toMask;\n }\n } else {\n return toMask;\n }\n }\n\n const startPart = toMask.substring(0, start);\n const endPart = toMask.substring(toMask.length - end);\n const maskLength = toMask.length - start - end;\n const masked = startPart + char.repeat(maskLength) + endPart;\n\n if (separator) {\n return `${masked.substring(0, start)}${separator}${masked.substring(start, masked.length - end)}${separator}${masked.substring(masked.length - end)}`;\n }\n\n return masked;\n}\n","import { toE164 } from './format';\nimport { validatePhoneNumber, isMobileNumber } from './validate';\n\n/**\n * Generates a WhatsApp click-to-chat link.\n *\n * WhatsApp only works on mobile numbers, so landlines will return empty string.\n *\n * @param phone - The Indonesian mobile phone number\n * @param message - Optional pre-filled message\n * @returns WhatsApp link, or empty string if phone is invalid or landline\n *\n * @example\n * ```typescript\n * generateWALink('081234567890', 'Halo!');\n * // 'https://wa.me/6281234567890?text=Halo%21'\n * ```\n *\n * @example\n * Landlines return empty string (WhatsApp doesn't work on landlines):\n * ```typescript\n * generateWALink('0212345678'); // ''\n * ```\n *\n * @public\n */\nexport function generateWALink(phone: string, message?: string): string {\n if (!validatePhoneNumber(phone) || !isMobileNumber(phone)) {\n return '';\n }\n\n const e164 = toE164(phone);\n let link = `https://wa.me/${e164}`;\n\n if (message) {\n link += `?text=${encodeURIComponent(message)}`;\n }\n\n return link;\n}\n\n/**\n * Generates an SMS link (sms:).\n *\n * SMS only works on mobile numbers, so landlines will return empty string.\n *\n * @param phone - The Indonesian mobile phone number\n * @param body - Optional SMS body\n * @returns SMS link, or empty string if phone is invalid or landline\n *\n * @example\n * ```typescript\n * generateSmsLink('081234567890', 'Pesan ini');\n * // 'sms:+6281234567890?body=Pesan%20ini'\n * ```\n *\n * @example\n * Landlines return empty string (SMS doesn't work on landlines):\n * ```typescript\n * generateSmsLink('0212345678'); // ''\n * ```\n *\n * @public\n */\nexport function generateSmsLink(phone: string, body?: string): string {\n if (!validatePhoneNumber(phone) || !isMobileNumber(phone)) {\n return '';\n }\n\n const e164 = toE164(phone);\n let link = `sms:+${e164}`;\n\n if (body) {\n link += `?body=${encodeURIComponent(body)}`;\n }\n\n return link;\n}\n\n/**\n * Generates a telephone link (tel:).\n *\n * @param phone - The Indonesian phone number\n * @returns Tel link, or empty string if phone is invalid\n *\n * @example\n * ```typescript\n * generateTelLink('081234567890');\n * // 'tel:+6281234567890'\n * ```\n *\n * @public\n */\nexport function generateTelLink(phone: string): string {\n if (!validatePhoneNumber(phone)) {\n return '';\n }\n\n const e164 = toE164(phone);\n return `tel:+${e164}`;\n}\n","import { OPERATOR_PREFIXES } from './constants';\nimport { PhoneInfo, OperatorName } from './types';\nimport {\n cleanPhoneNumber,\n toInternational,\n toNational,\n toE164,\n} from './format';\nimport { validatePhoneNumber, isMobileNumber } from './validate';\nimport { normalizePhoneNumber, getLandlineRegion } from './utils';\n\n/**\n * Parses an Indonesian phone number and extracts all information.\n *\n * Extracts country code, operator, formatted variants, and determines\n * if it's a mobile or landline number.\n *\n * @param phone - The phone number to parse\n * @returns Parsed phone information, or `null` if invalid\n *\n * @example\n * Parse a mobile number:\n * ```typescript\n * const info = parsePhoneNumber('081234567890');\n * console.log(info);\n * // {\n * // countryCode: '62',\n * // operator: 'Telkomsel',\n * // number: '81234567890',\n * // formatted: {\n * // international: '+62 812-3456-7890',\n * // national: '0812-3456-7890',\n * // e164: '6281234567890'\n * // },\n * // isValid: true,\n * // isMobile: true,\n * // isLandline: false\n * // }\n * ```\n *\n * @example\n * Parse with different input format:\n * ```typescript\n * const info = parsePhoneNumber('+62 812-3456-7890');\n * console.log(info.operator); // 'Telkomsel'\n * console.log(info.formatted.national); // '0812-3456-7890'\n * ```\n *\n * @example\n * Parse a landline:\n * ```typescript\n * const info = parsePhoneNumber('0212345678');\n * console.log(info.region); // 'Jakarta'\n * console.log(info.isLandline); // true\n * ```\n *\n * @public\n */\nexport function parsePhoneNumber(phone: string): PhoneInfo | null {\n if (!validatePhoneNumber(phone)) {\n return null;\n }\n\n const cleaned = cleanPhoneNumber(phone);\n const normalized = normalizePhoneNumber(cleaned);\n\n if (!normalized) {\n return null;\n }\n\n const countryCode = '62';\n const number = normalized.substring(1); // Remove leading 0\n const isMobile = normalized.startsWith('08');\n const isLandline = !isMobile;\n\n let operator: OperatorName | null = null;\n let region: string | null = null;\n\n if (isMobile) {\n operator = getOperator(normalized);\n } else {\n region = getLandlineRegion(normalized);\n }\n\n return {\n countryCode,\n operator,\n number,\n formatted: {\n international: toInternational(normalized),\n national: toNational(normalized),\n e164: toE164(normalized),\n },\n isValid: true,\n isMobile,\n isLandline,\n region,\n };\n}\n\n/**\n * Detects the mobile operator from a phone number.\n *\n * Identifies the operator based on the phone number prefix.\n * Returns `null` if the operator cannot be determined or if it's not a mobile number.\n *\n * @param phone - The phone number to check\n * @returns Operator name, or `null` if not detected\n *\n * @example\n * Telkomsel numbers:\n * ```typescript\n * getOperator('081234567890'); // 'Telkomsel'\n * getOperator('0812-3456-7890'); // 'Telkomsel'\n * getOperator('+6281234567890'); // 'Telkomsel'\n * ```\n *\n * @example\n * XL numbers:\n * ```typescript\n * getOperator('081734567890'); // 'XL'\n * ```\n *\n * @example\n * Non-mobile or invalid:\n * ```typescript\n * getOperator('0212345678'); // null (landline)\n * getOperator('1234'); // null (invalid)\n * ```\n *\n * @public\n */\nexport function getOperator(phone: string): OperatorName | null {\n if (!isMobileNumber(phone)) {\n return null;\n }\n\n const cleaned = cleanPhoneNumber(phone);\n const normalized = normalizePhoneNumber(cleaned);\n\n if (!normalized || normalized.length < 4) {\n return null;\n }\n\n const prefix = normalized.substring(0, 4);\n return OPERATOR_PREFIXES[prefix] || null;\n}\n\n/**\n * Checks if a phone number belongs to a specific provider.\n *\n * @param phone - The phone number to check\n * @param providerName - The provider name to match (case-insensitive)\n * @returns `true` if it matches, `false` otherwise\n *\n * @example\n * ```typescript\n * isProvider('081234567890', 'Telkomsel'); // true\n * isProvider('081734567890', 'xl'); // true\n * ```\n *\n * @public\n */\nexport function isProvider(phone: string, providerName: string): boolean {\n const operator = getOperator(phone);\n if (!operator) {\n return false;\n }\n return operator.toLowerCase() === providerName.toLowerCase();\n}\n","/**\n * Validates an Indonesian NPWP (Nomor Pokok Wajib Pajak).\n *\n * Supports both 15-digit (standard) and 16-digit (new NIK-based) formats.\n *\n * @param npwp - The NPWP string to validate\n * @returns `true` if valid, `false` otherwise\n *\n * @example\n * ```typescript\n * validateNPWP('01.234.567.8-012.000'); // true\n * validateNPWP('012345678012000'); // true\n * ```\n */\nexport function validateNPWP(npwp: string): boolean {\n if (!npwp || typeof npwp !== 'string') {\n return false;\n }\n\n const cleaned = npwp.replace(/[^\\d]/g, '');\n\n // Must be 15 or 16 digits\n if (cleaned.length !== 15 && cleaned.length !== 16) {\n return false;\n }\n\n // Basic check: all numeric\n if (!/^\\d+$/.test(cleaned)) {\n return false;\n }\n\n return true;\n}\n","import { validateNPWP } from './validate';\nimport { NPWPInfo, MaskOptions } from './types';\n\n/**\n * Formats an NPWP string into standard Indonesian format (99.999.999.9-999.999).\n *\n * @param npwp - The NPWP string to format\n * @returns Formatted NPWP string, or original if invalid\n *\n * @example\n * ```typescript\n * formatNPWP('012345678012000'); // '01.234.567.8-012.000'\n * ```\n */\nexport function formatNPWP(npwp: string): string {\n if (!validateNPWP(npwp)) {\n return npwp;\n }\n\n const cleaned = npwp.replace(/[^\\d]/g, '');\n\n if (cleaned.length === 15) {\n return `${cleaned.substring(0, 2)}.${cleaned.substring(\n 2,\n 5\n )}.${cleaned.substring(5, 8)}.${cleaned.substring(8, 9)}-${cleaned.substring(\n 9,\n 12\n )}.${cleaned.substring(12, 15)}`;\n }\n\n // 16-digit NPWP (NIK) usually doesn't have a standard \"dots\" format like 15-digit\n // but if it's NIK, it might be formatted as NIK elsewhere.\n // For now, return as is or implement a simple format.\n return cleaned;\n}\n\n/**\n * Parses an NPWP string into its components.\n *\n * @param npwp - The NPWP string to parse\n * @returns NPWPInfo object, or null if invalid\n */\nexport function parseNPWP(npwp: string): NPWPInfo | null {\n if (!validateNPWP(npwp)) {\n return null;\n }\n\n const cleaned = npwp.replace(/[^\\d]/g, '');\n const isNikBased = cleaned.length === 16;\n\n if (isNikBased) {\n return {\n npwp: cleaned,\n type: cleaned.substring(0, 2),\n serial: cleaned.substring(2, 8),\n checksum: cleaned.substring(8, 9),\n taxOfficeCode: cleaned.substring(9, 12),\n branchCode: cleaned.substring(12, 16),\n isNikBased: true,\n };\n }\n\n return {\n npwp: cleaned,\n type: cleaned.substring(0, 2),\n serial: cleaned.substring(2, 8),\n checksum: cleaned.substring(8, 9),\n taxOfficeCode: cleaned.substring(9, 12),\n branchCode: cleaned.substring(12, 15),\n isNikBased: false,\n };\n}\n\n/**\n * Masks an NPWP string for privacy.\n *\n * @param npwp - The NPWP string to mask\n * @param options - Masking options\n * @returns Masked NPWP string\n */\nexport function maskNPWP(npwp: string, options?: MaskOptions): string {\n if (!npwp) return '';\n\n const { visibleStart = 2, visibleEnd = 3, maskChar = '*' } = options || {};\n\n // If input is formatted, we mask the digits but keep the symbols in place\n if (npwp.includes('.') || npwp.includes('-')) {\n let digitCount = 0;\n const digitsOnly = npwp.replace(/[^\\d]/g, '');\n const totalDigits = digitsOnly.length;\n\n return npwp\n .split('')\n .map((char) => {\n if (/\\d/.test(char)) {\n digitCount++;\n if (\n digitCount <= visibleStart ||\n digitCount > totalDigits - visibleEnd\n ) {\n return char;\n }\n return maskChar;\n }\n return char;\n })\n .join('');\n }\n\n const cleaned = npwp.replace(/[^\\d]/g, '');\n\n if (cleaned.length < visibleStart + visibleEnd) {\n return cleaned.replace(/./g, maskChar);\n }\n\n const start = cleaned.substring(0, visibleStart);\n const end = cleaned.substring(cleaned.length - visibleEnd);\n const middle = maskChar.repeat(cleaned.length - visibleStart - visibleEnd);\n\n return `${start}${middle}${end}`;\n}\n","/**\n * Mapping of Indonesian license plate prefixes to their regions.\n */\nexport const PLATE_REGIONS: Record<string, string> = {\n A: 'Banten',\n B: 'Jakarta, Depok, Tangerang, Bekasi',\n D: 'Bandung, Cimahi',\n E: 'Cirebon, Indramayu, Majalengka, Kuningan',\n F: 'Bogor, Cianjur, Sukabumi',\n G: 'Pekalongan, Pemalang, Batang, Tegal, Brebes',\n H: 'Semarang, Salatiga, Kendal, Demak',\n K: 'Pati, Kudus, Jepara, Rembang, Blora, Grobogan',\n L: 'Surabaya',\n M: 'Madura',\n N: 'Malang, Probolinggo, Pasuruan, Lumajang, Batu',\n P: 'Besuki, Bondowoso, Situbondo, Jember, Banyuwangi',\n R: 'Banyumas, Cilacap, Purbalinggo, Banjarnegara',\n S: 'Bojonegoro, Tuban, Lamongan, Jombang, Mojokerto',\n T: 'Purwakarta, Subang, Karawang',\n AA: 'Kedu, Magelang, Purworejo, Kebumen, Temanggung, Wonosobo',\n AB: 'Yogyakarta',\n AD: 'Surakarta, Boyolali, Sukoharjo, Karanganyar, Wonogiri, Sragen, Klaten',\n AE: 'Madiun, Ngawi, Magetan, Ponorogo, Pacitan',\n AG: 'Kediri, Blitar, Tulungagung, Nganjuk, Trenggalek',\n BA: 'Sumatera Barat',\n BB: 'Sumatera Utara (Pantai Barat)',\n BD: 'Bengkulu',\n BE: 'Lampung',\n BG: 'Sumatera Selatan',\n BH: 'Jambi',\n BK: 'Sumatera Utara (Pantai Timur)',\n BL: 'Aceh',\n BM: 'Riau',\n BN: 'Kepulauan Bangka Belitung',\n BP: 'Kepulauan Riau',\n DA: 'Kalimantan Selatan',\n DB: 'Sulawesi Utara (Daratan)',\n DC: 'Sulawesi Barat',\n DD: 'Sulawesi Selatan (Selatan)',\n DE: 'Maluku',\n DF: 'Timor Timur (Historical)',\n DG: 'Maluku Utara',\n DH: 'NTT (Timor)',\n DK: 'Bali',\n DL: 'Sulawesi Utara (Kepulauan)',\n DM: 'Gorontalo',\n DN: 'Sulawesi Tengah',\n DP: 'Sulawesi Selatan (Utara)',\n DR: 'NTB (Lombok)',\n DS: 'Papua',\n DT: 'Sulawesi Tenggara',\n EA: 'NTB (Sumbawa)',\n EB: 'NTT (Flores)',\n ED: 'NTT (Sumba)',\n KB: 'Kalimantan Barat',\n KH: 'Kalimantan Tengah',\n KT: 'Kalimantan Timur',\n KU: 'Kalimantan Utara',\n PA: 'Papua',\n PB: 'Papua Barat',\n};\n","import { PLATE_REGIONS } from './regions';\n\n/**\n * Validates an Indonesian license plate number format.\n * Format: [1-2 letters] [1-4 digits] [1-3 letters]\n *\n * @param plate - The plate number string to validate\n * @returns `true` if valid, `false` otherwise\n *\n * @example\n * ```typescript\n * validatePlate('B 1234 ABC'); // true\n * validatePlate('AB 1 CD'); // true\n * ```\n */\nexport function validatePlate(plate: string): boolean {\n if (!plate || typeof plate !== 'string') {\n return false;\n }\n\n const cleaned = plate.replace(/\\s+/g, '').toUpperCase();\n const regex = /^[A-Z]{1,2}\\d{1,4}[A-Z]{1,3}$/;\n\n return regex.test(cleaned);\n}\n\n/**\n * Gets the region name from a license plate number.\n *\n * @param plate - The plate number\n * @returns Region name or null if not found\n */\nexport function getRegionFromPlate(plate: string): string | null {\n if (!plate || typeof plate !== 'string') {\n return null;\n }\n\n const cleaned = plate.replace(/\\s+/g, '').toUpperCase();\n const match = cleaned.match(/^([A-Z]{1,2})/);\n\n if (!match) {\n return null;\n }\n\n const prefix = match[1];\n return PLATE_REGIONS[prefix] || null;\n}\n\n/**\n * Formats a license plate number with spaces (e.g., B 1234 ABC).\n *\n * @param plate - The plate number\n * @returns Formatted plate string\n */\nexport function formatPlate(plate: string): string {\n if (!plate) return '';\n\n const cleaned = plate.replace(/\\s+/g, '').toUpperCase();\n const match = cleaned.match(/^([A-Z]{1,2})(\\d{1,4})([A-Z]{1,3})$/);\n\n if (!match) {\n return cleaned;\n }\n\n return `${match[1]} ${match[2]} ${match[3]}`;\n}\n","/**\n * The standard length of a VIN (ISO 3779).\n */\nexport const VIN_LENGTH = 17;\n\n/**\n * The 0-based index of the check digit in the VIN (Position 9).\n */\nexport const VIN_CHECK_DIGIT_INDEX = 8;\n\n/**\n * The modulus used in the VIN checksum calculation.\n */\nexport const VIN_MODULUS = 11;\n\n/**\n * The character representing a checksum value of 10.\n */\nexport const VIN_CHECK_DIGIT_X = 'X';\n\n/**\n * Weights used in the VIN checksum calculation.\n * Each position (1-17) is multiplied by its corresponding weight.\n * Position 9 is the check digit itself (weight 0).\n */\nexport const VIN_WEIGHTS = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2];\n\n/**\n * Values assigned to each valid character for VIN calculation.\n * Invalid characters: I, O, Q are not allowed in VIN.\n */\nexport const VIN_CHAR_VALUES: Record<string, number> = {\n '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,\n 'A': 1, 'B': 2, 'C': 3, 'D': 4, 'E': 5, 'F': 6, 'G': 7, 'H': 8,\n 'J': 1, 'K': 2, 'L': 3, 'M': 4, 'N': 5, 'P': 7, 'R': 9,\n 'S': 2, 'T': 3, 'U': 4, 'V': 5, 'W': 6, 'X': 7, 'Y': 8, 'Z': 9,\n};\n\n/**\n * Characters excluded from VIN (I, O, Q).\n */\nexport const EXCLUDED_VIN_CHARS = ['I', 'O', 'Q'];\n\n/**\n * Version of the VIN utility module.\n */\nexport const VIN_VERSION = '1.0.0';\n\n","import {\n VIN_WEIGHTS,\n VIN_CHAR_VALUES,\n EXCLUDED_VIN_CHARS,\n VIN_LENGTH,\n VIN_CHECK_DIGIT_INDEX,\n VIN_MODULUS,\n VIN_CHECK_DIGIT_X,\n} from './constants';\n\n/**\n * Validates a Vehicle Identification Number (VIN) based on ISO 3779.\n *\n * Checks for:\n * - Exactly 17 characters length.\n * - Exclusion of characters I, O, and Q.\n * - Checksum validation using the check digit at position 9.\n *\n * @param vin - The VIN string to validate\n * @returns boolean indicating if the VIN is valid\n *\n * @example\n * ```typescript\n * import { validateVIN } from '@indodev/toolkit/vin';\n *\n * validateVIN('1HBHA82L7ZB000001'); // true\n * validateVIN('1HBHA82I7ZB000001'); // false (contains 'I')\n * ```\n */\nexport function validateVIN(vin: string): boolean {\n if (!vin || vin.length !== VIN_LENGTH) {\n return false;\n }\n\n const normalizedVIN = vin.toUpperCase();\n\n // 1. Check for excluded characters (I, O, Q)\n for (const char of EXCLUDED_VIN_CHARS) {\n if (normalizedVIN.includes(char)) {\n return false;\n }\n }\n\n // 2. Checksum validation (Position 9)\n let sum = 0;\n for (let i = 0; i < VIN_LENGTH; i++) {\n const char = normalizedVIN[i];\n const weight = VIN_WEIGHTS[i];\n const val = VIN_CHAR_VALUES[char];\n\n if (val === undefined) {\n return false; // Invalid character found\n }\n\n sum += val * weight;\n }\n\n const checkDigitValue = sum % VIN_MODULUS;\n const expectedCheckDigit =\n checkDigitValue === 10 ? VIN_CHECK_DIGIT_X : checkDigitValue.toString();\n const actualCheckDigit = normalizedVIN[VIN_CHECK_DIGIT_INDEX];\n\n return actualCheckDigit === expectedCheckDigit;\n}\n","/**\n * Regular expression for standard email validation.\n * Optimized for RFC 5322 compliance.\n */\nexport const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$/;\n\n/**\n * Common disposable email domains to block if needed.\n */\nexport const DISPOSABLE_DOMAINS = [\n 'mailinator.com',\n '10minutemail.com',\n 'temp-mail.org',\n 'guerrillamail.com',\n];\n","import { EMAIL_REGEX, DISPOSABLE_DOMAINS } from './constants';\nimport type { EmailValidationOptions, EmailMaskOptions, EmailInfo } from './types';\n\n/**\n * List of common global email providers.\n */\nconst COMMON_PROVIDERS = ['gmail.com', 'yahoo.com', 'outlook.com', 'hotmail.com', 'icloud.com'];\n\n/**\n * The maximum length of an email address according to RFC 5321.\n */\nconst MAX_EMAIL_LENGTH = 254;\n\n/**\n * Validates if a string is a properly formatted email address based on RFC 5322.\n * \n * Performs checks for:\n * - Proper email format (regex).\n * - RFC specific rules (no double dots, username length < 64).\n * - Maximum total length (254 characters).\n * - Optional: disposable email detection.\n * \n * @param email - The email string to validate.\n * @param options - Optional validation configuration.\n * @returns `true` if valid, `false` otherwise.\n * \n * @example\n * ```typescript\n * import { validateEmail } from '@indodev/toolkit/email-validator';\n * \n * validateEmail('user@example.com'); // true\n * validateEmail('invalid-email'); // false\n * validateEmail('spam@mailinator.com', { blockDisposable: true }); // false\n * ```\n */\nexport function validateEmail(email: string, options?: EmailValidationOptions): boolean {\n if (!email || typeof email !== 'string') {\n return false;\n }\n\n const trimmedEmail = email.trim().toLowerCase();\n\n if (trimmedEmail.length > MAX_EMAIL_LENGTH) {\n return false;\n }\n\n const parts = trimmedEmail.split('@');\n if (parts.length !== 2) {\n return false;\n }\n\n const [username, domain] = parts;\n\n if (!username || !domain) {\n return false;\n }\n\n if (username.length > 64) {\n return false;\n }\n\n if (\n username.includes('..') ||\n username.startsWith('.') ||\n username.endsWith('.') ||\n domain.startsWith('.') ||\n domain.endsWith('.') ||\n domain.includes('..')\n ) {\n return false;\n }\n\n if (!EMAIL_REGEX.test(trimmedEmail)) {\n return false;\n }\n\n if (options?.blockDisposable) {\n if (DISPOSABLE_DOMAINS.includes(domain)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Parses an email address to extract useful metadata.\n * \n * @param email - The email address to parse.\n * @returns `EmailInfo` object containing details or `null` if the email is invalid.\n * \n * @example\n * ```typescript\n * import { getEmailInfo } from '@indodev/toolkit/email-validator';\n * \n * const info = getEmailInfo('adam@gmail.com');\n * // { username: 'adam', domain: 'gmail.com', isCommonProvider: true, isDisposable: false }\n * ```\n */\nexport function getEmailInfo(email: string): EmailInfo | null {\n if (!validateEmail(email)) return null;\n\n const [username, domain] = email.trim().toLowerCase().split('@');\n\n return {\n username,\n domain,\n isCommonProvider: COMMON_PROVIDERS.includes(domain),\n isDisposable: DISPOSABLE_DOMAINS.includes(domain),\n };\n}\n\n/**\n * Masks the username portion of an email for privacy protection.\n * \n * Falls back to a standard mask if the username is too short to respect visibleStart/visibleEnd.\n * \n * @param email - The email address to mask.\n * @param options - Optional masking configuration.\n * @returns Masked email string or original if invalid.\n * \n * @example\n * ```typescript\n * import { maskEmail } from '@indodev/toolkit/email-validator';\n * \n * maskEmail('user@example.com'); // 'u**r@example.com'\n * maskEmail('user@example.com', { maskChar: '#' }); // 'u##r@example.com'\n * ```\n */\nexport function maskEmail(email: string, options?: EmailMaskOptions): string {\n if (!validateEmail(email)) return email;\n\n const { visibleStart = 1, visibleEnd = 1, maskChar = '*' } = options || {};\n const [username, domain] = email.split('@');\n\n // Fallback for very short usernames\n if (username.length <= 3) {\n return `${username[0]}${maskChar.repeat(3)}@${domain}`;\n }\n\n // Calculate masked length\n const maskedLength = username.length - (visibleStart + visibleEnd);\n\n // If the result of masking would be empty or negative, use fallback\n if (maskedLength <= 0) {\n return `${username[0]}${maskChar.repeat(3)}@${domain}`;\n }\n\n const start = username.slice(0, visibleStart);\n const end = username.slice(username.length - visibleEnd);\n\n return `${start}${maskChar.repeat(maskedLength)}${end}@${domain}`;\n}\n\n/**\n * Normalizes an email address by trimming whitespace and converting to lowercase.\n * \n * @param email - The email to normalize.\n * @returns Normalized email string.\n * \n * @example\n * ```typescript\n * import { normalizeEmail } from '@indodev/toolkit/email-validator';\n * \n * normalizeEmail(' USER@Example.COM '); // 'user@example.com'\n * ```\n */\nexport function normalizeEmail(email: string): string {\n return email.trim().toLowerCase();\n}\n","/**\n * Currency formatting utilities for Indonesian Rupiah.\n *\n * @module currency/format\n * @packageDocumentation\n */\n\nimport type { CompactOptions, RupiahOptions } from './types';\n\n/**\n * Formats a number as Indonesian Rupiah currency.\n *\n * Provides flexible formatting options including symbol display,\n * decimal places, and custom separators.\n *\n * @param amount - The amount to format\n * @param options - Formatting options\n * @returns Formatted Rupiah string\n *\n * @example\n * Basic formatting:\n * ```typescript\n * formatRupiah(1500000); // 'Rp 1.500.000'\n * ```\n *\n * @example\n * With decimals:\n * ```typescript\n * formatRupiah(1500000.50, { decimal: true }); // 'Rp 1.500.000,50'\n * ```\n *\n * @example\n * Without symbol:\n * ```typescript\n * formatRupiah(1500000, { symbol: false }); // '1.500.000'\n * ```\n *\n * @example\n * Custom separators:\n * ```typescript\n * formatRupiah(1500000, { separator: ',' }); // 'Rp 1,500,000'\n * ```\n *\n * @public\n */\nexport function formatRupiah(amount: number, options?: RupiahOptions): string {\n const {\n symbol = true,\n decimal = false,\n separator = '.',\n decimalSeparator = ',',\n spaceAfterSymbol = true,\n } = options || {};\n\n // Default precision: 2 for decimals, 0 otherwise\n const precision =\n options?.precision !== undefined ? options.precision : decimal ? 2 : 0;\n\n const isNegative = amount < 0 && amount !== 0;\n const absAmount = Math.abs(amount);\n\n let result: string;\n\n if (decimal) {\n const factor = Math.pow(10, precision);\n const rounded = Math.round(absAmount * factor) / factor;\n\n if (precision > 0) {\n const [intPart, decPart] = rounded.toFixed(precision).split('.');\n const formattedInt = intPart.replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n result = `${formattedInt}${decimalSeparator}${decPart}`;\n } else {\n const intPart = rounded.toString();\n result = intPart.replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n }\n } else {\n const intAmount = Math.floor(absAmount);\n result = intAmount.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n }\n\n if (symbol) {\n const space = spaceAfterSymbol ? ' ' : '';\n if (isNegative) {\n result = `-Rp${space}${result}`;\n } else {\n result = `Rp${space}${result}`;\n }\n } else if (isNegative) {\n result = `-${result}`;\n }\n\n return result;\n}\n\n/**\n * Formats a number in compact Indonesian format.\n *\n * Uses Indonesian units: ribu, juta, miliar, triliun.\n * Follows Indonesian grammar rules (e.g., \"1 juta\" not \"1,0 juta\").\n *\n * @param amount - The amount to format\n * @param options - Compact formatting options\n * @returns Compact formatted string\n *\n * @example\n * Millions:\n * ```typescript\n * formatCompact(1500000); // 'Rp 1,5 juta'\n * formatCompact(1000000); // 'Rp 1 juta'\n * ```\n *\n * @example\n * Thousands:\n * ```typescript\n * formatCompact(500000); // 'Rp 500 ribu'\n * ```\n *\n * @example\n * Small numbers:\n * ```typescript\n * formatCompact(1500); // 'Rp 1.500'\n * ```\n *\n * @example\n * Without symbol:\n * ```typescript\n * formatCompact(1500000, { symbol: false }); // '1,5 juta'\n * ```\n *\n * @public\n */\nexport function formatCompact(\n amount: number,\n options?: CompactOptions\n): string {\n const { symbol = true, spaceAfterSymbol = true } = options || {};\n\n const isNegative = amount < 0 && amount !== 0;\n const abs = Math.abs(amount);\n\n let result: string;\n\n if (abs >= 1_000_000_000_000) {\n result = formatCompactValue(abs / 1_000_000_000_000, 'triliun');\n } else if (abs >= 1_000_000_000) {\n result = formatCompactValue(abs / 1_000_000_000, 'miliar');\n } else if (abs >= 1_000_000) {\n result = formatCompactValue(abs / 1_000_000, 'juta');\n } else if (abs >= 100_000) {\n result = formatCompactValue(abs / 1000, 'ribu');\n } else if (abs >= 1_000) {\n result = abs.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.');\n } else {\n result = abs.toString();\n }\n\n if (symbol) {\n const space = spaceAfterSymbol ? ' ' : '';\n if (isNegative) {\n result = `-Rp${space}${result}`;\n } else {\n result = `Rp${space}${result}`;\n }\n } else if (isNegative) {\n result = `-${result}`;\n }\n\n return result;\n}\n\n/**\n * Formats a value with Indonesian unit, applying grammar rules.\n *\n * Automatically removes trailing \".0\" to follow proper Indonesian grammar.\n * For example: \"1 juta\" instead of \"1,0 juta\".\n *\n * @param value - The numeric value to format\n * @param unit - The Indonesian unit (ribu, juta, miliar, triliun)\n * @returns Formatted string with unit\n * @internal\n */\nfunction formatCompactValue(value: number, unit: string): string {\n const rounded = Math.round(value * 10) / 10;\n\n if (rounded % 1 === 0) {\n return `${rounded.toFixed(0)} ${unit}`;\n }\n\n return `${rounded.toString().replace('.', ',')} ${unit}`;\n}\n","/**\n * Currency parsing utilities for Indonesian Rupiah.\n *\n * @module currency/parse\n * @packageDocumentation\n */\n\n/**\n * Parses a formatted Rupiah string back to a number.\n *\n * Handles multiple formats:\n * - Standard: \"Rp 1.500.000\"\n * - No symbol: \"1.500.000\"\n * - With decimals: \"Rp 1.500.000,50\"\n * - Compact: \"Rp 1,5 juta\", \"Rp 500 ribu\"\n *\n * @param formatted - The formatted Rupiah string to parse\n * @returns Parsed number, or null if invalid\n *\n * @example\n * Standard format:\n * ```typescript\n * parseRupiah('Rp 1.500.000'); // 1500000\n * ```\n *\n * @example\n * With decimals:\n * ```typescript\n * parseRupiah('Rp 1.500.000,50'); // 1500000.50\n * ```\n *\n * @example\n * Compact format:\n * ```typescript\n * parseRupiah('Rp 1,5 juta'); // 1500000\n * parseRupiah('Rp 500 ribu'); // 500000\n * ```\n *\n * @example\n * Invalid input:\n * ```typescript\n * parseRupiah('invalid'); // null\n * ```\n *\n * @public\n */\nexport function parseRupiah(formatted: string): number | null {\n if (!formatted || typeof formatted !== 'string') {\n return null;\n }\n\n const cleaned = formatted.trim().toLowerCase();\n\n // Check for compact units (juta, ribu, miliar, triliun)\n const compactUnits = {\n triliun: 1_000_000_000_000,\n miliar: 1_000_000_000,\n juta: 1_000_000,\n ribu: 1_000,\n };\n\n for (const [unit, multiplier] of Object.entries(compactUnits)) {\n if (cleaned.includes(unit)) {\n const match = cleaned.match(/(-?\\d+[,.]?\\d*)/);\n if (match) {\n const num = parseFloat(match[1].replace(',', '.'));\n return num * multiplier;\n }\n }\n }\n\n // Standard format: remove 'Rp' and spaces\n let numStr = cleaned.replace(/rp/gi, '').trim();\n\n const hasDot = numStr.includes('.');\n const hasComma = numStr.includes(',');\n\n if (hasDot && hasComma) {\n // Determine format based on last separator position\n // Indonesian: 1.500.000,50 vs International: 1,500,000.50\n const lastDot = numStr.lastIndexOf('.');\n const lastComma = numStr.lastIndexOf(',');\n\n if (lastComma > lastDot) {\n numStr = numStr.replace(/\\./g, '').replace(',', '.');\n } else {\n numStr = numStr.replace(/,/g, '');\n }\n } else if (hasComma) {\n const parts = numStr.split(',');\n // Decimal if only 1-2 digits after comma\n if (parts.length === 2 && parts[1].length <= 2) {\n numStr = numStr.replace(',', '.');\n } else {\n numStr = numStr.replace(/,/g, '');\n }\n } else if (hasDot) {\n const parts = numStr.split('.');\n // If not decimal format, remove dots (thousands separator)\n if (parts.length > 2 || (parts.length === 2 && parts[1].length > 2)) {\n numStr = numStr.replace(/\\./g, '');\n }\n }\n\n const parsed = parseFloat(numStr);\n return isNaN(parsed) ? null : parsed;\n}\n","/**\n * Convert numbers to Indonesian words (terbilang).\n *\n * @module currency/words\n * @packageDocumentation\n */\n\nimport type { WordOptions } from './types';\n\n/**\n * Basic Indonesian number words (0-9).\n * @internal\n */\nconst BASIC_NUMBERS = [\n '',\n 'satu',\n 'dua',\n 'tiga',\n 'empat',\n 'lima',\n 'enam',\n 'tujuh',\n 'delapan',\n 'sembilan',\n];\n\n/**\n * Indonesian words for 10-19.\n * @internal\n */\nconst TEENS = [\n 'sepuluh',\n 'sebelas',\n 'dua belas',\n 'tiga belas',\n 'empat belas',\n 'lima belas',\n 'enam belas',\n 'tujuh belas',\n 'delapan belas',\n 'sembilan belas',\n];\n\n/**\n * Indonesian words for tens (20, 30, 40, etc).\n * @internal\n */\nconst TENS = [\n '',\n '',\n 'dua puluh',\n 'tiga puluh',\n 'empat puluh',\n 'lima puluh',\n 'enam puluh',\n 'tujuh puluh',\n 'delapan puluh',\n 'sembilan puluh',\n];\n\n/**\n * Converts a number to Indonesian words (terbilang).\n *\n * Supports numbers up to trillions (triliun).\n * Follows Indonesian language rules for number pronunciation.\n *\n * Special rules:\n * - 1 = \"satu\" in most cases, but \"se-\" for 100, 1000\n * - 11 = \"sebelas\" (not \"satu belas\")\n * - 100 = \"seratus\" (not \"satu ratus\")\n * - 1000 = \"seribu\" (not \"satu ribu\")\n *\n * @param amount - The number to convert\n * @param options - Conversion options\n * @returns Indonesian words representation\n *\n * @example\n * Basic numbers:\n * ```typescript\n * toWords(123); // 'seratus dua puluh tiga rupiah'\n * ```\n *\n * @example\n * Large numbers:\n * ```typescript\n * toWords(1500000); // 'satu juta lima ratus ribu rupiah'\n * ```\n *\n * @example\n * With options:\n * ```typescript\n * toWords(1500000, { uppercase: true });\n * // 'Satu juta lima ratus ribu rupiah'\n *\n * toWords(1500000, { withCurrency: false });\n * // 'satu juta lima ratus ribu'\n * ```\n *\n * @public\n */\nexport function toWords(amount: number, options?: WordOptions): string {\n const {\n uppercase = false,\n withCurrency = true,\n withDecimals = false,\n } = options || {};\n\n if (amount === 0) {\n let result = 'nol';\n if (withCurrency) result += ' rupiah';\n return uppercase ? capitalize(result) : result;\n }\n\n const isNegative = amount < 0;\n const absAmount = Math.abs(amount);\n const intPart = Math.floor(absAmount);\n\n let words = convertInteger(intPart);\n\n if (isNegative) {\n words = 'minus ' + words;\n }\n\n if (withCurrency) {\n words += ' rupiah';\n }\n\n if (withDecimals) {\n const decimalPart = Math.round((absAmount - intPart) * 100);\n if (decimalPart > 0) {\n words += ' koma ' + convertDecimal(decimalPart);\n }\n }\n\n return uppercase ? capitalize(words) : words;\n}\n\n/**\n * Converts the integer part to Indonesian words.\n */\nfunction convertInteger(num: number): string {\n if (num === 0) return 'nol';\n\n let words = '';\n\n const triliun = Math.floor(num / 1_000_000_000_000);\n const miliar = Math.floor((num % 1_000_000_000_000) / 1_000_000_000);\n const juta = Math.floor((num % 1_000_000_000) / 1_000_000);\n const ribu = Math.floor((num % 1_000_000) / 1_000);\n const sisa = num % 1_000;\n\n if (triliun > 0) {\n words += convertGroup(triliun) + ' triliun';\n }\n\n if (miliar > 0) {\n if (words) words += ' ';\n words += convertGroup(miliar) + ' miliar';\n }\n\n if (juta > 0) {\n if (words) words += ' ';\n words += convertGroup(juta) + ' juta';\n }\n\n if (ribu > 0) {\n if (words) words += ' ';\n words += ribu === 1 ? 'seribu' : convertGroup(ribu) + ' ribu';\n }\n\n if (sisa > 0) {\n if (words) words += ' ';\n words += convertGroup(sisa);\n }\n\n return words;\n}\n\n/**\n * Converts decimal part (0-99) to Indonesian words.\n */\nfunction convertDecimal(num: number): string {\n if (num === 0) return '';\n if (num < 10) return BASIC_NUMBERS[num];\n if (num < 20) return TEENS[num - 10];\n\n const tens = Math.floor(num / 10);\n const ones = num % 10;\n\n let result = TENS[tens];\n if (ones > 0) {\n result += ' ' + BASIC_NUMBERS[ones];\n }\n\n return result;\n}\n\n/**\n * Converts a group of 1-3 digits (0-999) to Indonesian words.\n *\n * @param num - Number to convert (0-999)\n * @returns Indonesian words for the number\n * @internal\n */\nfunction convertGroup(num: number): string {\n if (num === 0) return '';\n\n let result = '';\n\n const hundreds = Math.floor(num / 100);\n if (hundreds > 0) {\n // Special rule: 100 = \"seratus\" not \"satu ratus\"\n result = hundreds === 1 ? 'seratus' : BASIC_NUMBERS[hundreds] + ' ratus';\n }\n\n const remainder = num % 100;\n if (remainder > 0) {\n if (result) result += ' ';\n result += convertTwoDigits(remainder);\n }\n\n return result;\n}\n\n/**\n * Converts numbers 1-99 to Indonesian words.\n *\n * @param num - Number to convert (1-99)\n * @returns Indonesian words for the number\n * @internal\n */\nfunction convertTwoDigits(num: number): string {\n if (num === 0) return '';\n if (num < 10) return BASIC_NUMBERS[num];\n if (num >= 10 && num < 20) return TEENS[num - 10];\n\n const tens = Math.floor(num / 10);\n const ones = num % 10;\n\n let result = TENS[tens];\n if (ones > 0) {\n result += ' ' + BASIC_NUMBERS[ones];\n }\n\n return result;\n}\n\n/**\n * Capitalizes the first letter of a string.\n *\n * @param str - String to capitalize\n * @returns String with first letter capitalized\n * @internal\n */\nfunction capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n","/**\n * Currency utility functions.\n *\n * @module currency/utils\n * @packageDocumentation\n */\n\nimport { formatRupiah } from './format';\nimport type { RoundUnit, RupiahOptions } from './types';\n\n/**\n * Rounds a number to a clean currency amount.\n *\n * Common use case: displaying approximate prices or budgets\n * in clean, rounded numbers.\n *\n * @param amount - The amount to round\n * @param unit - The unit to round to (default: 'ribu')\n * @returns Rounded amount\n *\n * @example\n * Round to thousands:\n * ```typescript\n * roundToClean(1234567, 'ribu'); // 1235000\n * ```\n *\n * @example\n * Round to hundred thousands:\n * ```typescript\n * roundToClean(1234567, 'ratus-ribu'); // 1200000\n * ```\n *\n * @example\n * Round to millions:\n * ```typescript\n * roundToClean(1234567, 'juta'); // 1000000\n * ```\n *\n * @public\n */\nexport function roundToClean(amount: number, unit: RoundUnit = 'ribu'): number {\n const divisors: Record<RoundUnit, number> = {\n ribu: 1000,\n 'ratus-ribu': 100000,\n juta: 1000000,\n };\n\n const divisor = divisors[unit];\n\n // Math.round handles both positive and negative numbers\n return Math.round(amount / divisor) * divisor;\n}\n\n/**\n * Formats a number as Indonesian Rupiah in accounting style.\n * Negative numbers are wrapped in parentheses.\n *\n * @param amount - The amount to format\n * @param options - Formatting options\n * @returns Formatted accounting string\n *\n * @example\n * ```typescript\n * formatAccounting(-1500000); // '(Rp 1.500.000)'\n * ```\n */\nexport function formatAccounting(\n amount: number,\n options?: RupiahOptions\n): string {\n const isNegative = amount < 0;\n const formatted = formatRupiah(Math.abs(amount), options);\n\n if (isNegative) {\n return `(${formatted})`;\n }\n\n return formatted;\n}\n\n/**\n * Calculates tax (PPN) for a given amount.\n *\n * @param amount - The base amount\n * @param rate - The tax rate (e.g., 0.11 for 11% PPN)\n * @returns The calculated tax amount\n *\n * @example\n * ```typescript\n * calculateTax(1000000, 0.11); // 110000\n * ```\n */\nexport function calculateTax(amount: number, rate: number): number {\n return amount * rate;\n}\n\n/**\n * Helper to ensure a string or number has the 'Rp ' prefix.\n * If already prefixed, it returns the input as is.\n *\n * @param amount - The amount or formatted string\n * @returns String with Rupiah prefix\n */\nexport function addRupiahSymbol(amount: string | number): string {\n if (typeof amount === 'number') {\n const formatted = amount.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.');\n return `Rp ${formatted}`;\n }\n\n if (amount.trim().startsWith('Rp')) {\n return amount.trim();\n }\n\n return `Rp ${amount.trim()}`;\n}\n","/**\n * ============================================================================\n * INDONESIAN TEXT UTILITIES - CONSTANTS\n * ============================================================================\n *\n * This file contains constants for Indonesian and English text processing:\n * - LOWERCASE_WORDS: Particles that stay lowercase in title case\n * - ACRONYMS: Abbreviations that stay UPPERCASE in title case\n * - ABBREVIATIONS: Full expansions of common Indonesian abbreviations\n *\n * ============================================================================\n * MAINTENANCE GUIDE\n * ============================================================================\n *\n * ## How to Add New Entries\n *\n * ### 1. LOWERCASE_WORDS (Particles)\n *\n * Add words that should remain lowercase in title case (except when first word).\n *\n * **Indonesian Grammar Rules (PUEBI):**\n * - Prepositions: di, ke, dari, untuk, dengan, pada, dalam, etc.\n * - Conjunctions: dan, atau, tetapi, serta, maupun, etc.\n * - Articles/particles: yang, sebagai, adalah, akan, telah, etc.\n *\n * **English Grammar Rules (Chicago Manual of Style):**\n * - Articles: a, an, the\n * - Conjunctions: and, or, but, nor, for, yet, so\n * - Short prepositions (<5 letters): at, by, in, of, on, to, up, etc.\n *\n * **Example Addition:**\n * ```typescript\n * export const LOWERCASE_WORDS = [\n * // ... existing entries\n * 'bagi', // Indonesian: for/to (preposition)\n * 'antara', // Indonesian: between (preposition)\n * 'into', // English: preposition\n * ] as const;\n * ```\n *\n * **Testing:** Add test case in `toTitleCase.test.ts`:\n * ```typescript\n * it('keeps \"bagi\" lowercase in middle', () => {\n * expect(toTitleCase('buku bagi pemula')).toBe('Buku bagi Pemula');\n * });\n * ```\n *\n * ### 2. ACRONYMS (Always Uppercase)\n *\n * Add abbreviations that should always appear in UPPERCASE.\n *\n * **Categories:**\n * - Government & Military: TNI, POLRI, KPK, DPR, etc.\n * - Business Entities: PT, CV, BUMN, etc.\n * - Banks: BCA, BRI, BNI, etc.\n * - Services: BPJS, PLN, KTP, SIM, etc.\n * - Technology: IT, AI, API, SEO, etc.\n * - Education: UI, ITB, UGM, etc.\n * - International: UN, WHO, NATO, ASEAN, etc.\n *\n * **Validation Checklist:**\n * ✅ Is it commonly written in ALL CAPS?\n * ✅ Is it an official acronym (not just shortened word)?\n * ✅ Will it look wrong if title-cased (e.g., \"Pt\" instead of \"PT\")?\n *\n * **Example Addition:**\n * ```typescript\n * export const ACRONYMS = [\n * // ... existing entries\n * 'OJK', // Otoritas Jasa Keuangan\n * 'BI', // Bank Indonesia\n * 'NASA', // National Aeronautics and Space Administration\n * ] as const;\n * ```\n *\n * **Testing:** Add test case in `toTitleCase.test.ts`:\n * ```typescript\n * it('preserves OJK uppercase', () => {\n * expect(toTitleCase('ojk indonesia')).toBe('OJK Indonesia');\n * });\n * ```\n *\n * ### 3. ABBREVIATIONS (Expansion Mapping)\n *\n * Add abbreviation → full form mappings for `expandAbbreviation()` function.\n *\n * **Categories (use comment headers):**\n * - Address: Jl., Gg., Kec., Kab., etc.\n * - Academic Titles: Dr., Ir., Prof., S.H., M.M., etc.\n * - Honorifics: Bpk., Yth., H., Hj., etc.\n * - Organizations: PT., CV., UD., etc.\n * - Common: dst., dll., a.n., etc.\n * - Contact Info: Tlp., HP., Fax, etc.\n * - Days/Months: Sen., Jan., Feb., etc.\n * - Units: kg., km., lt., etc.\n *\n * **Key Format Rules:**\n * - Include period if commonly written: `'Jl.'` not `'Jl'`\n * - Use proper capitalization: `'Jalan'` not `'jalan'`\n * - Keep it concise: Full form only, no explanations\n *\n * **Example Addition:**\n * ```typescript\n * export const ABBREVIATIONS: Record<string, string> = {\n * // ... existing entries\n *\n * // ========== New Category Example ==========\n * 'Apt.': 'Apartemen',\n * 'Ruko': 'Rumah Toko',\n * 'Rukan': 'Rumah Kantor',\n * };\n * ```\n *\n * **Testing:** Add test case in `abbreviation.test.ts`:\n * ```typescript\n * it('expands Apt. to Apartemen', () => {\n * expect(expandAbbreviation('Apt. Sudirman'))\n * .toBe('Apartemen Sudirman');\n * });\n * ```\n *\n * ============================================================================\n * DATA SOURCES & REFERENCES\n * ============================================================================\n *\n * When adding new entries, refer to these authoritative sources:\n *\n * **Indonesian Language:**\n * - PUEBI (Pedoman Umum Ejaan Bahasa Indonesia)\n * https://puebi.js.org/\n *\n * - KBBI (Kamus Besar Bahasa Indonesia)\n * https://kbbi.kemdikbud.go.id/\n *\n * - Wikipedia Indonesia - Daftar Singkatan\n * https://id.wikipedia.org/wiki/Daftar_singkatan_di_Indonesia\n *\n * **English Language:**\n * - Chicago Manual of Style (Title Case Rules)\n * https://www.chicagomanualofstyle.org/\n *\n * - AP Stylebook\n * https://www.apstylebook.com/\n *\n * **Government & Official:**\n * - Kemendagri (addresses, administrative divisions)\n * https://www.kemendagri.go.id/\n *\n * - Kemenkumham (business entities)\n * https://www.kemenkumham.go.id/\n *\n * - Kemendikbud (education, degrees)\n * https://www.kemdikbud.go.id/\n *\n * ============================================================================\n * CONTRIBUTION GUIDELINES\n * ============================================================================\n *\n * **Before Adding:**\n * 1. ✅ Check if entry already exists (Ctrl+F)\n * 2. ✅ Verify spelling from official sources\n * 3. ✅ Ensure it's commonly used (not obscure)\n * 4. ✅ Choose correct category/section\n *\n * **After Adding:**\n * 1. ✅ Add corresponding test case\n * 2. ✅ Run tests: `npm test constants`\n * 3. ✅ Update this file's documentation if needed\n * 4. ✅ Add source reference in PR description\n *\n * **PR Template:**\n * ```\n * ### Added Constants\n *\n * **Type:** [LOWERCASE_WORDS | ACRONYMS | ABBREVIATIONS]\n *\n * **Entries:**\n * - `OJK` - Otoritas Jasa Keuangan\n * - `BI` - Bank Indonesia\n *\n * **Source:** https://www.ojk.go.id/\n *\n * **Test Coverage:** ✅ Added in toTitleCase.test.ts line 245\n *\n * **Rationale:**\n * Commonly used financial regulatory bodies in Indonesian context.\n * ```\n *\n * ============================================================================\n * COMMON PITFALLS TO AVOID\n * ============================================================================\n *\n * ❌ **Don't add brand-specific styling** (e.g., \"iPhone\" → keep user control)\n * ❌ **Don't add regional dialects** (stick to standard Indonesian/English)\n * ❌ **Don't add context-dependent acronyms** (e.g., \"UI\" = both User Interface & Universitas Indonesia)\n * ❌ **Don't add very rare/obscure terms** (focus on common usage)\n * ❌ **Don't forget the period** in ABBREVIATIONS (e.g., use `'Dr.'` not `'Dr'`)\n * ❌ **Don't mix singular/plural** in ABBREVIATIONS (choose one consistently)\n *\n * ✅ **Do keep entries alphabetically sorted** within categories\n * ✅ **Do use proper capitalization** in expanded forms\n * ✅ **Do add comments** for non-obvious entries\n * ✅ **Do verify against official sources** before adding\n * ✅ **Do write test cases** for new additions\n *\n * ============================================================================\n * FUTURE EXTENSIBILITY\n * ============================================================================\n *\n * **Planned Enhancements:**\n *\n * 1. **External Data Source Support:**\n * ```typescript\n * import customAcronyms from './data/custom-acronyms.json';\n * export const ACRONYMS = [...DEFAULT_ACRONYMS, ...customAcronyms];\n * ```\n *\n * 2. **Context-Aware Acronyms:**\n * ```typescript\n * export const CONTEXT_ACRONYMS = {\n * 'UI': {\n * tech: 'UI', // User Interface\n * education: 'UI', // Universitas Indonesia\n * }\n * };\n * ```\n *\n * 3. **Locale-Specific Sets:**\n * ```typescript\n * export const LOWERCASE_WORDS = {\n * id: [...], // Indonesian\n * en: [...], // English\n * mixed: [...], // Combined (default)\n * };\n * ```\n *\n * 4. **Dynamic Loading:**\n * ```typescript\n * // Load additional acronyms from user config\n * export async function loadCustomConstants(url: string) {\n * const data = await fetch(url).then(r => r.json());\n * return [...ACRONYMS, ...data.acronyms];\n * }\n * ```\n *\n * ============================================================================\n * VERSIONING & CHANGELOG\n * ============================================================================\n *\n * Track major additions here:\n *\n * - v0.2.0 (2024-12-18): Initial comprehensive dataset\n * - 50+ Indonesian particles\n * - 150+ acronyms (Indonesian + International)\n * - 80+ abbreviation mappings\n *\n * - v0.2.1 (TBD): Add financial sector acronyms (OJK, BI, etc.)\n * - v0.2.2 (TBD): Add technology company acronyms\n *\n * ============================================================================\n */\n\n/**\n * Indonesian and English lowercase particles\n * These words remain lowercase in title case (except when first word)\n *\n * Based on:\n * - Indonesian grammar (PUEBI)\n * - English title case rules (Chicago Manual of Style)\n */\nexport const LOWERCASE_WORDS = [\n // Indonesian prepositions (kata depan)\n 'di',\n 'ke',\n 'dari',\n 'pada',\n 'dalam',\n 'untuk',\n 'dengan',\n 'oleh',\n 'kepada',\n 'terhadap',\n 'tentang',\n 'tanpa',\n 'hingga',\n 'sampai',\n 'sejak',\n 'menuju',\n 'melalui',\n\n // Indonesian conjunctions (kata hubung)\n 'dan',\n 'atau',\n 'tetapi',\n 'namun',\n 'serta',\n 'maupun',\n 'melainkan',\n 'sedangkan',\n\n // Indonesian articles/particles\n 'yang',\n 'sebagai',\n 'adalah',\n 'ialah',\n 'yaitu',\n 'bahwa',\n 'akan',\n 'telah',\n 'sudah',\n 'belum',\n\n // English articles\n 'a',\n 'an',\n 'the',\n\n // English conjunctions\n 'and',\n 'or',\n 'but',\n 'nor',\n 'for',\n 'yet',\n 'so',\n 'as',\n\n // English prepositions (short ones, < 5 letters)\n 'at',\n 'by',\n 'in',\n 'of',\n 'on',\n 'to',\n 'up',\n 'via',\n 'per',\n 'off',\n 'out',\n\n // English prepositions (5+ letters - optional, some style guides capitalize these)\n // 'about',\n // 'above',\n // 'across',\n // 'after',\n // 'among',\n // 'below',\n // 'under',\n // 'until',\n // 'with',\n] as const;\n\n/**\n * Indonesian and international acronyms\n * These always remain UPPERCASE in title case\n */\nexport const ACRONYMS = [\n // Indonesian government & military\n 'DKI', // Daerah Khusus Ibukota\n 'DIY', // Daerah Istimewa Yogyakarta\n 'TNI', // Tentara Nasional Indonesia\n 'POLRI', // Kepolisian Republik Indonesia\n 'ABRI', // Angkatan Bersenjata Republik Indonesia\n 'MPR', // Majelis Permusyawaratan Rakyat\n 'DPR', // Dewan Perwakilan Rakyat\n 'KPK', // Komisi Pemberantasan Korupsi\n 'BIN', // Badan Intelijen Negara\n\n // Indonesian business entities\n 'PT', // Perseroan Terbatas\n 'CV', // Commanditaire Vennootschap\n 'UD', // Usaha Dagang\n 'PD', // Perusahaan Daerah\n 'Tbk', // Terbuka (publicly traded)\n 'BUMN', // Badan Usaha Milik Negara\n 'BUMD', // Badan Usaha Milik Daerah\n\n // Indonesian banks\n 'BCA', // Bank Central Asia\n 'BRI', // Bank Rakyat Indonesia\n 'BNI', // Bank Negara Indonesia\n 'BTN', // Bank Tabungan Negara\n 'BSI', // Bank Syariah Indonesia\n 'BPD', // Bank Pembangunan Daerah\n\n // Indonesian government services\n 'KTP', // Kartu Tanda Penduduk\n 'NIK', // Nomor Induk Kependudukan\n 'NPWP', // Nomor Pokok Wajib Pajak\n 'SIM', // Surat Izin Mengemudi\n 'STNK', // Surat Tanda Nomor Kendaraan\n 'BPJS', // Badan Penyelenggara Jaminan Sosial\n 'KIS', // Kartu Indonesia Sehat\n 'KIP', // Kartu Indonesia Pintar\n 'PKH', // Program Keluarga Harapan\n\n // Indonesian utilities & infrastructure\n 'PLN', // Perusahaan Listrik Negara\n 'PDAM', // Perusahaan Daerah Air Minum\n 'PGN', // Perusahaan Gas Negara\n 'KAI', // Kereta Api Indonesia\n 'MRT', // Mass Rapid Transit\n 'LRT', // Light Rail Transit\n\n // Indonesian taxes & fees\n 'PBB', // Pajak Bumi dan Bangunan\n 'PPh', // Pajak Penghasilan\n 'PPN', // Pajak Pertambahan Nilai\n 'BPHTB', // Bea Perolehan Hak atas Tanah dan Bangunan\n\n // Indonesian education\n 'UI', // Universitas Indonesia\n 'ITB', // Institut Teknologi Bandung\n 'UGM', // Universitas Gadjah Mada\n 'IPB', // Institut Pertanian Bogor\n 'ITS', // Institut Teknologi Sepuluh Nopember\n 'UNPAD', // Universitas Padjadjaran\n 'UNDIP', // Universitas Diponegoro\n 'UNAIR', // Universitas Airlangga\n 'UNS', // Universitas Sebelas Maret\n\n // Indonesian degrees (gelar)\n 'S.Pd', // Sarjana Pendidikan\n 'S.H', // Sarjana Hukum\n 'S.E', // Sarjana Ekonomi\n 'S.T', // Sarjana Teknik\n 'S.Kom', // Sarjana Komputer\n 'S.Si', // Sarjana Sains\n 'S.Sos', // Sarjana Sosial\n 'M.Pd', // Magister Pendidikan\n 'M.M', // Magister Manajemen\n 'M.T', // Magister Teknik\n 'M.Kom', // Magister Komputer\n\n // Common services\n 'ATM', // Automated Teller Machine\n 'POS', // Point of Sale\n 'SMS', // Short Message Service\n 'GPS', // Global Positioning System\n 'WiFi', // Wireless Fidelity (technically Wi-Fi)\n 'USB', // Universal Serial Bus\n 'PIN', // Personal Identification Number\n 'OTP', // One Time Password\n 'QR', // Quick Response\n\n // Technology & IT\n 'IT', // Information Technology\n 'AI', // Artificial Intelligence\n 'ML', // Machine Learning\n 'API', // Application Programming Interface\n 'UI', // User Interface (duplicate with Universitas Indonesia, context matters)\n 'UX', // User Experience\n 'SEO', // Search Engine Optimization\n 'SaaS', // Software as a Service\n 'CRM', // Customer Relationship Management\n 'ERP', // Enterprise Resource Planning\n\n // Business titles\n 'CEO', // Chief Executive Officer\n 'CFO', // Chief Financial Officer\n 'CTO', // Chief Technology Officer\n 'COO', // Chief Operating Officer\n 'CMO', // Chief Marketing Officer\n 'HR', // Human Resources\n 'PR', // Public Relations\n 'VP', // Vice President\n 'GM', // General Manager\n\n // International organizations\n 'UN', // United Nations\n 'WHO', // World Health Organization\n 'UNESCO', // United Nations Educational, Scientific and Cultural Organization\n 'NATO', // North Atlantic Treaty Organization\n 'ASEAN', // Association of Southeast Asian Nations\n 'APEC', // Asia-Pacific Economic Cooperation\n 'WTO', // World Trade Organization\n 'IMF', // International Monetary Fund\n\n // Medical\n 'ICU', // Intensive Care Unit\n 'ER', // Emergency Room\n 'MRI', // Magnetic Resonance Imaging\n 'CT', // Computed Tomography\n 'DNA', // Deoxyribonucleic Acid\n 'RNA', // Ribonucleic Acid\n 'HIV', // Human Immunodeficiency Virus\n 'AIDS', // Acquired Immunodeficiency Syndrome\n 'COVID', // Coronavirus Disease\n\n // Measurements & units\n 'KM', // Kilometer\n 'CM', // Centimeter\n 'MM', // Millimeter\n 'KG', // Kilogram\n 'RPM', // Revolutions Per Minute\n 'MPH', // Miles Per Hour\n 'KPH', // Kilometers Per Hour\n\n // Finance\n 'IPO', // Initial Public Offering\n 'ATM', // Automated Teller Machine (duplicate)\n 'ROI', // Return on Investment\n 'GDP', // Gross Domestic Product\n 'VAT', // Value Added Tax\n] as const;\n\n/**\n * Indonesian abbreviations mapping\n * Organized by category for maintainability\n */\nexport const ABBREVIATIONS: Record<string, string> = {\n // ========== Address Abbreviations ==========\n 'Jl.': 'Jalan',\n 'Gg.': 'Gang',\n 'No.': 'Nomor',\n 'Kp.': 'Kampung',\n 'Ds.': 'Desa',\n 'Kel.': 'Kelurahan',\n 'Kec.': 'Kecamatan',\n 'Kab.': 'Kabupaten',\n Kota: 'Kota',\n 'Prov.': 'Provinsi',\n 'Prop.': 'Provinsi',\n 'Rt.': 'Rukun Tetangga',\n 'Rw.': 'Rukun Warga',\n Blok: 'Blok',\n 'Komp.': 'Kompleks',\n Perumahan: 'Perumahan',\n 'Perum.': 'Perumahan',\n\n // ========== Academic Titles ==========\n 'Dr.': 'Doktor',\n 'Ir.': 'Insinyur',\n 'Prof.': 'Profesor',\n 'Drs.': 'Doktorandus',\n 'Dra.': 'Doktoranda',\n\n // Bachelor degrees\n 'S.Pd.': 'Sarjana Pendidikan',\n 'S.H.': 'Sarjana Hukum',\n 'S.E.': 'Sarjana Ekonomi',\n 'S.T.': 'Sarjana Teknik',\n 'S.Kom.': 'Sarjana Komputer',\n 'S.Si.': 'Sarjana Sains',\n 'S.Sos.': 'Sarjana Sosial',\n 'S.I.Kom.': 'Sarjana Ilmu Komunikasi',\n 'S.S.': 'Sarjana Sastra',\n 'S.Psi.': 'Sarjana Psikologi',\n 'S.Farm.': 'Sarjana Farmasi',\n 'S.Ked.': 'Sarjana Kedokteran',\n\n // Master degrees\n 'M.Sc.': 'Master of Science',\n 'M.M.': 'Magister Manajemen',\n 'M.Pd.': 'Magister Pendidikan',\n 'M.T.': 'Magister Teknik',\n 'M.Kom.': 'Magister Komputer',\n 'M.Si.': 'Magister Sains',\n 'M.H.': 'Magister Hukum',\n 'M.A.': 'Master of Arts',\n MBA: 'Master of Business Administration',\n\n // ========== Honorifics ==========\n 'Bpk.': 'Bapak',\n Ibu: 'Ibu',\n 'Sdr.': 'Saudara',\n 'Sdri.': 'Saudari',\n 'Yth.': 'Yang Terhormat',\n 'H.': 'Haji',\n 'Hj.': 'Hajjah',\n 'Tn.': 'Tuan',\n 'Ny.': 'Nyonya',\n 'Nn.': 'Nona',\n\n // ========== Organizations ==========\n 'PT.': 'Perseroan Terbatas',\n 'CV.': 'Commanditaire Vennootschap',\n 'UD.': 'Usaha Dagang',\n 'PD.': 'Perusahaan Daerah',\n 'Tbk.': 'Terbuka',\n Koperasi: 'Koperasi',\n Yayasan: 'Yayasan',\n\n // ========== Common Abbreviations ==========\n 'dst.': 'dan seterusnya',\n 'dsb.': 'dan sebagainya',\n 'dll.': 'dan lain-lain',\n 'dkk.': 'dan kawan-kawan',\n 'a.n.': 'atas nama',\n 'u.p.': 'untuk perhatian',\n 'u.b.': 'untuk beliau',\n 'c.q.': 'casu quo',\n 'hlm.': 'halaman',\n 'tgl.': 'tanggal',\n 'bln.': 'bulan',\n 'thn.': 'tahun',\n 'ttd.': 'tertanda',\n\n // ========== Contact Information ==========\n 'Tlp.': 'Telepon',\n 'Telp.': 'Telepon',\n 'HP.': 'Handphone',\n Fax: 'Faksimile',\n Email: 'Email',\n Website: 'Website',\n\n // ========== Days (Indonesian) ==========\n 'Sen.': 'Senin',\n 'Sel.': 'Selasa',\n 'Rab.': 'Rabu',\n 'Kam.': 'Kamis',\n 'Jum.': 'Jumat',\n 'Sab.': 'Sabtu',\n 'Min.': 'Minggu',\n\n // ========== Months (Indonesian) ==========\n 'Jan.': 'Januari',\n 'Feb.': 'Februari',\n 'Mar.': 'Maret',\n 'Apr.': 'April',\n Mei: 'Mei',\n 'Jun.': 'Juni',\n 'Jul.': 'Juli',\n 'Agt.': 'Agustus',\n 'Sep.': 'September',\n 'Okt.': 'Oktober',\n 'Nov.': 'November',\n 'Des.': 'Desember',\n\n // ========== Units & Measurements ==========\n 'kg.': 'kilogram',\n 'gr.': 'gram',\n 'lt.': 'liter',\n 'ml.': 'mililiter',\n 'km.': 'kilometer',\n 'cm.': 'sentimeter',\n 'mm.': 'milimeter',\n 'm2.': 'meter persegi',\n 'm3.': 'meter kubik',\n 'ha.': 'hektar',\n};\n\n/**\n * Common Indonesian profanity/swear words for filtering.\n * This is a basic set for simple masking.\n */\nexport const PROFANITY = [\n 'anjing',\n 'babi',\n 'bangsat',\n 'bajingan',\n 'brengsek',\n 'goblok',\n 'tolol',\n 'idiot',\n 'perek',\n 'jablay',\n 'kontol',\n 'memek',\n 'ngewe',\n 'puki',\n 'jembut',\n 'asu',\n 'itil',\n 'lanjiao',\n 'pantek',\n 'anying',\n 'anjrit',\n] as const;\n\n/**\n * Common Indonesian stopwords for removal.\n */\nexport const STOPWORDS = [\n 'ada',\n 'adalah',\n 'adanya',\n 'adapun',\n 'agak',\n 'agaknya',\n 'agar',\n 'akan',\n 'akankah',\n 'akhir',\n 'akhiri',\n 'akhirnya',\n 'aku',\n 'akulah',\n 'amat',\n 'amatlah',\n 'anda',\n 'andalah',\n 'antar',\n 'antara',\n 'antaranya',\n 'apa',\n 'apaan',\n 'apabila',\n 'apakah',\n 'apalagi',\n 'apatah',\n 'artinya',\n 'asal',\n 'asalkan',\n 'atas',\n 'atau',\n 'ataukah',\n 'ataupun',\n 'awal',\n 'awalnya',\n 'bagai',\n 'bagaikan',\n 'bagaimana',\n 'bagaimanakah',\n 'bagaimanapun',\n 'bagi',\n 'bagian',\n 'bahkan',\n 'bahwa',\n 'bahwasanya',\n 'baik',\n 'bakal',\n 'bakalan',\n 'balik',\n 'banyak',\n 'bapak',\n 'baru',\n 'bawah',\n 'beberapa',\n 'begini',\n 'beginian',\n 'beginikah',\n 'beginilah',\n 'begitu',\n 'begitukah',\n 'begitulah',\n 'begitupun',\n 'bekerja',\n 'belakang',\n 'belakangan',\n 'belum',\n 'belumlah',\n 'benar',\n 'benarkah',\n 'benarlah',\n 'berada',\n 'berakhir',\n 'berakhirlah',\n 'berakhirnya',\n 'berapa',\n 'berapakah',\n 'berapalah',\n 'berapapun',\n 'berarti',\n 'berawal',\n 'berbagai',\n 'berikut',\n 'berikutnya',\n 'berjumlah',\n 'berkali-kali',\n 'berkata',\n 'berkeinginan',\n 'berkenaan',\n 'berlainan',\n 'berlalu',\n 'berlangsung',\n 'berlebihan',\n 'bermacam',\n 'bermacam-macam',\n 'bermaksud',\n 'bermula',\n 'bersama',\n 'bersama-sama',\n 'bersiap',\n 'bersiap-siap',\n 'bertanya',\n 'bertanya-tanya',\n 'berturut',\n 'berturut-turut',\n 'bertutur',\n 'berujar',\n 'berupa',\n 'besar',\n 'betul',\n 'betulkah',\n 'biasa',\n 'biasanya',\n 'bila',\n 'bilakah',\n 'bisa',\n 'bisakah',\n 'boleh',\n 'bolehkah',\n 'bolehlah',\n 'buat',\n 'bukan',\n 'bukankah',\n 'bukanlah',\n 'bukannya',\n 'bulan',\n 'bung',\n 'cara',\n 'caranya',\n 'cukup',\n 'cukupkah',\n 'cukuplah',\n 'cuma',\n 'dahulu',\n 'dalam',\n 'dan',\n 'dapat',\n 'dari',\n 'daripada',\n 'datang',\n 'dekat',\n 'demi',\n 'demikian',\n 'demikianlah',\n 'dengan',\n 'depan',\n 'di',\n 'dia',\n 'diakhiri',\n 'diakhirinya',\n 'dialah',\n 'diantara',\n 'diantaranya',\n 'diberi',\n 'diberikan',\n 'diberikannya',\n 'dibuat',\n 'dibuatnya',\n 'didapat',\n 'didatangkan',\n 'digunakan',\n 'diibaratkan',\n 'diingat',\n 'diingatkan',\n 'diinginkan',\n 'dijawab',\n 'dijelaskan',\n 'dijelaskannya',\n 'dikarenakan',\n 'dikatakan',\n 'dikatakannya',\n 'dikerjakan',\n 'diketahui',\n 'diketahuinya',\n 'dikira',\n 'dilakukan',\n 'dilalui',\n 'dilihat',\n 'dimaksud',\n 'dimaksudkan',\n 'dimaksudkannya',\n 'dimana',\n 'dimanalah',\n 'dimulai',\n 'dimulailah',\n 'dimulainya',\n 'diminta',\n 'dimintai',\n 'dimisalkan',\n 'dimungkinkan',\n 'dini',\n 'dipastikan',\n 'diperbuat',\n 'diperbuatnya',\n 'dipergunakan',\n 'diperkirakan',\n 'diperlihatkan',\n 'diperlukan',\n 'diperlukannya',\n 'dipersoalkan',\n 'dipertanyakan',\n 'dipunyai',\n 'diri',\n 'dirinya',\n 'disampaikan',\n 'disebut',\n 'disebutkan',\n 'disebutkannya',\n 'disini',\n 'disinilah',\n 'disitulah',\n 'diterangkan',\n 'diterangkannya',\n 'diteruskan',\n 'ditujukan',\n 'ditunjuk',\n 'ditunjuki',\n 'ditunjukkan',\n 'ditunjukkannya',\n 'ditunjuknya',\n 'dituturkan',\n 'dituturkannya',\n 'diucapkan',\n 'diucapkannya',\n 'diungkapkan',\n 'dua',\n 'dulu',\n 'empat',\n 'enggak',\n 'enggaknya',\n 'entah',\n 'entahlah',\n 'guna',\n 'gunakan',\n 'hal',\n 'hampir',\n 'hanya',\n 'hanyalah',\n 'hari',\n 'harus',\n 'haruslah',\n 'harusnya',\n 'hendak',\n 'hendaklah',\n 'hendaknya',\n 'hingga',\n 'ia',\n 'ialah',\n 'ibarat',\n 'ibaratkan',\n 'ibaratnya',\n 'ibu',\n 'ikut',\n 'ingat',\n 'ingat-ingat',\n 'ingin',\n 'inginkah',\n 'inginkan',\n 'ini',\n 'inikah',\n 'inilah',\n 'itu',\n 'itukah',\n 'itulah',\n 'jadi',\n 'jadilah',\n 'jadinya',\n 'jangan',\n 'jangankan',\n 'janganlah',\n 'jauh',\n 'jawab',\n 'jawaban',\n 'jawabnya',\n 'jelas',\n 'jelaskan',\n 'jelaslah',\n 'jelasnya',\n 'jika',\n 'jikalau',\n 'juga',\n 'jumlah',\n 'jumlahnya',\n 'justru',\n 'kala',\n 'kalau',\n 'kalaulah',\n 'kalaupun',\n 'kali',\n 'kalian',\n 'kami',\n 'kamilah',\n 'kamu',\n 'kamulah',\n 'kan',\n 'kapan',\n 'kapankah',\n 'kapanpun',\n 'karena',\n 'karenanya',\n 'ke',\n 'keadaan',\n 'kebetulan',\n 'kecil',\n 'kedua',\n 'keduanya',\n 'keinginan',\n 'kelak',\n 'kelihatan',\n 'kelihatannya',\n 'kelima',\n 'keluar',\n 'kembali',\n 'kemudian',\n 'kemungkinan',\n 'kemungkinannya',\n 'kenapa',\n 'kepada',\n 'kepadanya',\n 'kesampaian',\n 'keseluruhan',\n 'keseluruhannya',\n 'keterlaluan',\n 'ketika',\n 'khususnya',\n 'kini',\n 'kinilah',\n 'kira',\n 'kira-kira',\n 'kiranya',\n 'kita',\n 'kitalah',\n 'kok',\n 'kurang',\n 'lagi',\n 'lagian',\n 'lah',\n 'lain',\n 'lainnya',\n 'lalu',\n 'lama',\n 'lamanya',\n 'lanjut',\n 'lanjutnya',\n 'lebih',\n 'lewat',\n 'luar',\n 'macam',\n 'maka',\n 'makanya',\n 'makin',\n 'malah',\n 'malahan',\n 'mampu',\n 'mampukah',\n 'mana',\n 'manakala',\n 'manalagi',\n 'masih',\n 'masihkah',\n 'masing',\n 'masing-masing',\n 'mau',\n 'maupun',\n 'melainkan',\n 'melakukan',\n 'melalui',\n 'melihat',\n 'melihatnya',\n 'memang',\n 'memastikan',\n 'memberi',\n 'memberikan',\n 'membuat',\n 'memerlukan',\n 'memihak',\n 'meminta',\n 'memisalkan',\n 'memperbuat',\n 'mempergunakan',\n 'memperkirakan',\n 'memperlihatkan',\n 'mempersiapkan',\n 'mempersoalkan',\n 'mempertanyakan',\n 'mempunyai',\n 'memulai',\n 'memungkinkan',\n 'memutuskan',\n 'menanti',\n 'menanti-nanti',\n 'menantikan',\n 'menunjuk',\n 'menunjuknya',\n 'menuju',\n 'menurut',\n 'menurutnya',\n 'menurutmu',\n 'menurutku',\n 'menurutnya',\n 'menurut mereka',\n 'menyampaikan',\n 'menyebut',\n 'menyebutkan',\n 'menjelaskan',\n 'menjadi',\n 'menjadikan',\n 'menjalani',\n 'menjelang',\n 'menjawab',\n 'menunjukkan',\n 'menuangkan',\n 'menulis',\n 'menyatakan',\n 'merupakan',\n 'mereka',\n 'merekalah',\n 'meski',\n 'meskipun',\n 'mula',\n 'mulai',\n 'mulailah',\n 'mulanya',\n 'mungkin',\n 'mungkinkah',\n 'nah',\n 'naik',\n 'namun',\n 'nanti',\n 'nantinya',\n 'nyaris',\n 'oleh',\n 'olehnya',\n 'orang',\n 'pada',\n 'padahal',\n 'padanya',\n 'pakai',\n 'paling',\n 'panjang',\n 'pantas',\n 'para',\n 'pasti',\n 'pastilah',\n 'pagi',\n 'per',\n 'pernah',\n 'persoalan',\n 'pertama',\n 'pertama-tama',\n 'perlu',\n 'perlukah',\n 'perlulah',\n 'pernah',\n 'pihak',\n 'pihaknya',\n 'pukul',\n 'pula',\n 'pun',\n 'punya',\n 'rasa',\n 'rasanya',\n 'rata',\n 'rupanya',\n 'saat',\n 'saatnya',\n 'saja',\n 'sajalah',\n 'salam',\n 'saling',\n 'sama',\n 'sama-sama',\n 'sambil',\n 'sampai',\n 'sampai-sampai',\n 'sampaikan',\n 'sana',\n 'sangat',\n 'sangatlah',\n 'satu',\n 'saya',\n 'sayalah',\n 'sayang',\n 'seperti',\n 'seperti-itu',\n 'sepura',\n 'sebab',\n 'sebabnya',\n 'sebagai',\n 'sebagaimana',\n 'sebagainya',\n 'sebagian',\n 'sebaik',\n 'sebaik-baiknya',\n 'sebaiknya',\n 'sebaliknya',\n 'sebanyak',\n 'sebegini',\n 'sebegitu',\n 'sebelum',\n 'sebelumnya',\n 'sebenarnya',\n 'seberapa',\n 'sebesar',\n 'sebetulnya',\n 'sebisanya',\n 'sebuah',\n 'sebut',\n 'sebutkan',\n 'sebutnya',\n 'secara',\n 'secukupnya',\n 'sedang',\n 'sedangkan',\n 'sedikit',\n 'sedikitnya',\n 'sedemikian',\n 'sediakala',\n 'sedikit',\n 'sedikitnya',\n 'segala',\n 'segalanya',\n 'segera',\n 'seharusnya',\n 'sehingga',\n 'seingat',\n 'sejak',\n 'sejauh',\n 'sejenak',\n 'sejumlah',\n 'sekali',\n 'sekali-kali',\n 'sekalian',\n 'sekaligus',\n 'sekalipun',\n 'sekarang',\n 'sekaranglah',\n 'sekecil',\n 'seketika',\n 'sekiranya',\n 'sekitar',\n 'sekitarnya',\n 'sekurang',\n 'sekurangnya',\n 'sela',\n 'selalu',\n 'selama',\n 'selama-lamanya',\n 'selamanya',\n 'selanjutnya',\n 'seluruh',\n 'seluruhnya',\n 'semacam',\n 'semakin',\n 'semampu',\n 'semampunya',\n 'semasa',\n 'semata',\n 'semata-mata',\n 'semaunya',\n 'sementara',\n 'semisal',\n 'semisalnya',\n 'sempat',\n 'semua',\n 'semuanya',\n 'semula',\n 'sendiri',\n 'sendirinya',\n 'seolah',\n 'seolah-olah',\n 'seorang',\n 'sepanjang',\n 'sepantasnya',\n 'sepantasnyalah',\n 'seperempat',\n 'seperti',\n 'sepertinya',\n 'sepihak',\n 'sepuluh',\n 'seratus',\n 'seribu',\n 'sering',\n 'seringnya',\n 'serta',\n 'serupa',\n 'sesaat',\n 'sesama',\n 'sesampai',\n 'sesampainya',\n 'sesegera',\n 'sesekali',\n 'seseorang',\n 'sesuatu',\n 'sesuatunya',\n 'sesudah',\n 'sesudahnya',\n 'setelah',\n 'setempat',\n 'setengah',\n 'seterusnya',\n 'setiap',\n 'setidaknya',\n 'setinggi',\n 'seusai',\n 'sewaktu',\n 'siap',\n 'siapa',\n 'siapakah',\n 'siapapun',\n 'sini',\n 'sinilah',\n 'situ',\n 'situlah',\n 'suatu',\n 'sudah',\n 'sudahkah',\n 'sudahlah',\n 'supaya',\n 'tadi',\n 'tadinya',\n 'tahu',\n 'tak',\n 'tambah',\n 'tambahnya',\n 'tampak',\n 'tampaknya',\n 'tandas',\n 'tandasnya',\n 'tanpa',\n 'tanya',\n 'tanyakan',\n 'tanyanya',\n 'tapi',\n 'tegas',\n 'tegasnya',\n 'telah',\n 'tempat',\n 'tengah',\n 'tentang',\n 'tentu',\n 'tentulah',\n 'tentunya',\n 'tepat',\n 'terakhir',\n 'terasa',\n 'terbanyak',\n 'terdahulu',\n 'terdapat',\n 'terdiri',\n 'terdiri-dari',\n 'terhadap',\n 'terhadapnya',\n 'teringat',\n 'teringat-ingat',\n 'terjadi',\n 'terjadilah',\n 'terjadinya',\n 'terkira',\n 'terlalu',\n 'terlebih',\n 'terlihat',\n 'termasuk',\n 'ternyata',\n 'tersampaikan',\n 'tersebut',\n 'tersebutlah',\n 'tertentu',\n 'tertuju',\n 'terus',\n 'terutama',\n 'tetap',\n 'tetapi',\n 'tiap',\n 'tiba',\n 'tiba-tiba',\n 'tidak',\n 'tidakkah',\n 'tidaklah',\n 'tiga',\n 'tadi',\n 'tadinya',\n 'tinggi',\n 'toh',\n 'tuju',\n 'tunjuk',\n 'turut',\n 'tutur',\n 'tuturnya',\n 'ucap',\n 'ucapnya',\n 'ujar',\n 'ujarnya',\n 'umumnya',\n 'ungkap',\n 'ungkapnya',\n 'untuk',\n 'untaian',\n 'usai',\n 'usah',\n 'waduh',\n 'wah',\n 'wahai',\n 'walau',\n 'walaupun',\n 'wong',\n 'yaitu',\n 'yakin',\n 'yakni',\n 'yang',\n] as const;\n","import { ACRONYMS, LOWERCASE_WORDS } from './constants';\nimport { TitleCaseOptions } from './types';\n\n/**\n * Capitalize the first letter of a string and lowercase the rest\n *\n * This function converts the first character to uppercase and all remaining\n * characters to lowercase. It handles empty strings, Unicode characters,\n * and multi-word strings (only first word is affected).\n *\n * @param text - The text to capitalize\n * @returns The capitalized text\n *\n * @example\n * Basic usage:\n * ```typescript\n * capitalize('joko') // → 'Joko'\n * capitalize('JOKO') // → 'Joko'\n * capitalize('jOKO') // → 'Joko'\n * ```\n *\n * @example\n * Multi-word strings (only first word capitalized):\n * ```typescript\n * capitalize('joko widodo') // → 'Joko widodo'\n * capitalize('JOKO WIDODO') // → 'Joko widodo'\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * capitalize('') // → ''\n * capitalize('a') // → 'A'\n * capitalize('123abc') // → '123abc'\n * ```\n *\n * @public\n */\nexport function capitalize(text: string): string {\n if (!text) return text;\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();\n}\n\n/**\n * Convert text to title case following Indonesian grammar rules\n *\n * This function capitalizes the first letter of each word while respecting\n * Indonesian language conventions:\n * - Keeps particles lowercase (di, ke, dari, untuk, dan, etc.)\n * - Preserves known acronyms in uppercase (PT, CV, TNI, DKI, etc.)\n * - Handles hyphenated words correctly (anak-anak → Anak-Anak)\n * - Normalizes whitespace automatically\n *\n * @param text - The text to convert to title case\n * @param options - Optional configuration\n * @returns The title-cased text with proper Indonesian grammar\n *\n * @example\n * Basic usage:\n * ```typescript\n * toTitleCase('joko widodo')\n * // → 'Joko Widodo'\n *\n * toTitleCase('JOKO WIDODO')\n * // → 'Joko Widodo'\n * ```\n *\n * @example\n * Indonesian particles (kept lowercase):\n * ```typescript\n * toTitleCase('buku untuk anak dan orang tua')\n * // → 'Buku untuk Anak dan Orang Tua'\n *\n * toTitleCase('dari jakarta ke bandung')\n * // → 'Dari Jakarta ke Bandung'\n * // (first word always capitalized)\n * ```\n *\n * @example\n * Acronyms (preserved in uppercase):\n * ```typescript\n * toTitleCase('pt bank bca tbk')\n * // → 'PT Bank BCA Tbk'\n *\n * toTitleCase('dki jakarta')\n * // → 'DKI Jakarta'\n *\n * toTitleCase('tni angkatan darat')\n * // → 'TNI Angkatan Darat'\n * ```\n *\n * @example\n * Hyphenated words:\n * ```typescript\n * toTitleCase('anak-anak bermain')\n * // → 'Anak-Anak Bermain'\n *\n * toTitleCase('makan-makan di rumah')\n * // → 'Makan-Makan di Rumah'\n * ```\n *\n * @example\n * With options:\n * ```typescript\n * toTitleCase('PT BCA', { preserveAcronyms: false })\n * // → 'Pt Bca'\n *\n * toTitleCase('mobil dari jepang', { exceptions: ['jepang'] })\n * // → 'Mobil dari jepang'\n *\n * toTitleCase('HELLO WORLD', { strict: true })\n * // → 'Hello World'\n * ```\n *\n * @public\n */\nexport function toTitleCase(text: string, options?: TitleCaseOptions): string {\n if (!text) return text;\n\n const {\n preserveAcronyms = true,\n strict = false,\n exceptions = [],\n } = options || {};\n\n const lowercaseSet = new Set([...LOWERCASE_WORDS, ...exceptions]);\n const acronymSet = new Set(ACRONYMS);\n\n const normalized = normalizeSpaces(text);\n const words = normalized.split(' ');\n\n return words\n .map((word, index) => {\n if (!word) return word;\n\n if (word.includes('-')) {\n return processHyphenatedWord(word, index === 0, {\n lowercaseSet,\n acronymSet,\n preserveAcronyms,\n strict,\n });\n }\n\n return processWord(word, index === 0, {\n lowercaseSet,\n acronymSet,\n preserveAcronyms,\n strict,\n });\n })\n .join(' ');\n}\n\n/**\n * Normalize whitespace in text (trim and collapse multiple spaces)\n */\nfunction normalizeSpaces(text: string): string {\n return text.trim().replace(/\\s+/g, ' ');\n}\n\n/**\n * Process a single word according to title case rules\n */\nfunction processWord(\n word: string,\n isFirstWord: boolean,\n context: {\n lowercaseSet: Set<string>;\n acronymSet: Set<string>;\n preserveAcronyms: boolean;\n strict: boolean;\n }\n): string {\n const { lowercaseSet, acronymSet, preserveAcronyms, strict } = context;\n const lowerWord = word.toLowerCase();\n const upperWord = word.toUpperCase();\n\n // Check if it's a known acronym\n if (preserveAcronyms && acronymSet.has(upperWord)) {\n return upperWord;\n }\n\n // Check if it should be lowercase (but not at the start)\n if (!isFirstWord && lowercaseSet.has(lowerWord)) {\n return lowerWord;\n }\n\n // Capitalize first letter\n if (strict) {\n return capitalizeFirstLetter(lowerWord);\n }\n\n return capitalizeFirstLetter(word.toLowerCase());\n}\n\n/**\n * Process hyphenated word (e.g., \"anak-anak\")\n */\nfunction processHyphenatedWord(\n word: string,\n isFirstWord: boolean,\n context: {\n lowercaseSet: Set<string>;\n acronymSet: Set<string>;\n preserveAcronyms: boolean;\n strict: boolean;\n }\n): string {\n return word\n .split('-')\n .map((part, index) =>\n processWord(part, isFirstWord && index === 0, context)\n )\n .join('-');\n}\n\n/**\n * Capitalize first letter of a word\n */\nfunction capitalizeFirstLetter(word: string): string {\n if (!word) return word;\n return word.charAt(0).toUpperCase() + word.slice(1);\n}\n\n/**\n * Convert text to sentence case (capitalize first letter of sentences only)\n *\n * This function capitalizes the first character of the text and the first\n * character after sentence-ending punctuation (. ! ?), while keeping\n * everything else in lowercase.\n *\n * **Sentence Detection Rules:**\n * - Period (.), exclamation (!), question mark (?) mark sentence endings\n * - Next letter after punctuation + space is capitalized\n * - Handles multiple spaces and newlines\n * - Does NOT treat abbreviations as sentence endings (e.g., \"Dr. Smith\")\n *\n * @param text - The text to convert to sentence case\n * @returns The sentence-cased text\n *\n * @example\n * Basic usage:\n * ```typescript\n * toSentenceCase('JOKO WIDODO ADALAH PRESIDEN')\n * // → 'Joko widodo adalah presiden'\n *\n * toSentenceCase('joko widodo adalah presiden')\n * // → 'Joko widodo adalah presiden'\n * ```\n *\n * @example\n * Multiple sentences:\n * ```typescript\n * toSentenceCase('halo, apa kabar? baik-baik saja.')\n * // → 'Halo, apa kabar? Baik-baik saja.'\n *\n * toSentenceCase('jakarta. surabaya. bandung.')\n * // → 'Jakarta. Surabaya. Bandung.'\n * ```\n *\n * @example\n * Different punctuation:\n * ```typescript\n * toSentenceCase('wow! amazing! fantastic!')\n * // → 'Wow! Amazing! Fantastic!'\n *\n * toSentenceCase('siapa nama anda? saya joko.')\n * // → 'Siapa nama anda? Saya joko.'\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * toSentenceCase('')\n * // → ''\n *\n * toSentenceCase('hello')\n * // → 'Hello'\n *\n * toSentenceCase(' hello. world. ')\n * // → 'Hello. World.'\n * ```\n *\n * @public\n */\nexport function toSentenceCase(text: string): string {\n if (!text) return text;\n\n const normalized = text.trim().replace(/\\s+/g, ' ');\n\n let result = '';\n let shouldCapitalize = true;\n\n for (let i = 0; i < normalized.length; i++) {\n const char = normalized[i];\n\n // Capitalize if we should and this is a letter\n if (shouldCapitalize && /[a-zA-ZÀ-ÿ]/.test(char)) {\n result += char.toUpperCase();\n shouldCapitalize = false;\n } else {\n result += char.toLowerCase();\n }\n\n // Mark next letter for capitalization after sentence-ending punctuation\n if (isSentenceEnd(char)) {\n shouldCapitalize = true;\n }\n\n // Handle abbreviations: don't capitalize after period in abbreviations\n if (char === '.' && i + 1 < normalized.length) {\n const nextChar = normalized[i + 1];\n\n // If next char is not a space, likely an abbreviation\n if (nextChar !== ' ' && !/[.!?]/.test(nextChar)) {\n shouldCapitalize = false;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Check if a character marks the end of a sentence\n */\nfunction isSentenceEnd(char: string): boolean {\n return char === '.' || char === '!' || char === '?';\n}\n","import type { SlugifyOptions } from './types';\n\n/**\n * Generate URL-safe slugs with Indonesian language support\n *\n * This function converts text into URL-friendly slugs by:\n * - Converting to lowercase (configurable)\n * - Replacing spaces with separators (default: hyphen)\n * - Replacing Indonesian conjunctions (& → dan, / → atau)\n * - Removing special characters\n * - Collapsing multiple separators\n * - Trimming leading/trailing separators\n *\n * **Character Handling:**\n * - Alphanumeric (a-z, A-Z, 0-9): Preserved\n * - Spaces: Replaced with separator\n * - Ampersand (&): Replaced with \"dan\"\n * - Slash (/): Replaced with \"atau\"\n * - Hyphens (-): Preserved as separators\n * - Other special chars: Removed\n *\n * @param text - The text to convert to slug\n * @param options - Optional configuration\n * @returns The URL-safe slug\n *\n * @example\n * Basic usage:\n * ```typescript\n * slugify('Cara Mudah Belajar TypeScript')\n * // → 'cara-mudah-belajar-typescript'\n *\n * slugify('HELLO WORLD')\n * // → 'hello-world'\n * ```\n *\n * @example\n * Indonesian conjunctions:\n * ```typescript\n * slugify('Ibu & Anak: Tips Kesehatan')\n * // → 'ibu-dan-anak-tips-kesehatan'\n *\n * slugify('Baju Pria/Wanita')\n * // → 'baju-pria-atau-wanita'\n *\n * slugify('A & B / C')\n * // → 'a-dan-b-atau-c'\n * ```\n *\n * @example\n * Special characters removed:\n * ```typescript\n * slugify('Harga Rp 100.000 (Diskon 20%)')\n * // → 'harga-rp-100000-diskon-20'\n *\n * slugify('Email: test@example.com')\n * // → 'email-testexamplecom'\n * ```\n *\n * @example\n * Multiple spaces/separators collapsed:\n * ```typescript\n * slugify('Produk Terbaru - - - 2024')\n * // → 'produk-terbaru-2024'\n *\n * slugify(' Hello World ')\n * // → 'hello-world'\n * ```\n *\n * @example\n * With options:\n * ```typescript\n * slugify('Hello World', { separator: '_' })\n * // → 'hello_world'\n *\n * slugify('Hello World', { lowercase: false })\n * // → 'Hello-World'\n *\n * slugify('C++ Programming', {\n * replacements: { 'C++': 'cpp' }\n * })\n * // → 'cpp-programming'\n *\n * slugify('Hello-World', { trim: false })\n * // → 'hello-world' (same, but won't trim if leading/trailing)\n * ```\n *\n * @public\n */\n\nexport function slugify(text: string, options?: SlugifyOptions): string {\n if (!text) return '';\n\n const {\n separator = '-',\n lowercase = true,\n replacements = {},\n trim = true,\n } = options || {};\n\n let result = text;\n\n // Apply custom replacements first\n for (const [search, replace] of Object.entries(replacements)) {\n result = result.replace(new RegExp(escapeRegex(search), 'g'), replace);\n }\n\n // Replace Indonesian conjunctions\n result = result.replace(/&/g, ' dan ');\n result = result.replace(/\\//g, ' atau ');\n\n // Convert to lowercase if needed\n if (lowercase) {\n result = result.toLowerCase();\n }\n\n // Remove chars that should NOT become separators (dots, apostrophes, @, accents, etc)\n result = result.replace(/[.'@éèêëàâäôöûüùïîçñ™®©]/g, '');\n\n // Replace remaining special chars with separator (everything except alphanumeric, spaces, hyphens)\n result = result.replace(/[^\\w\\s-]+/g, separator);\n\n // Replace spaces with separator\n result = result.replace(/\\s+/g, separator);\n\n // Replace existing hyphens with separator (if separator is not hyphen)\n if (separator !== '-') {\n result = result.replace(/-/g, separator);\n }\n\n // Only when trim: true, collapse multiple separators AND trim edges\n if (trim) {\n const separatorRegex = new RegExp(`\\\\${separator}+`, 'g');\n result = result.replace(separatorRegex, separator);\n\n const trimRegex = new RegExp(`^\\\\${separator}+|\\\\${separator}+$`, 'g');\n result = result.replace(trimRegex, '');\n }\n\n return result;\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","import type { SanitizeOptions } from './types';\n\n/**\n * Normalize all whitespace characters to single spaces\n *\n * This function:\n * - Collapses multiple spaces into one\n * - Converts tabs, newlines, and other whitespace to single space\n * - Trims leading and trailing whitespace\n * - Handles Unicode whitespace characters\n *\n * **Whitespace Characters Normalized:**\n * - Space (` `)\n * - Tab (`\\t`)\n * - Newline (`\\n`)\n * - Carriage return (`\\r`)\n * - Form feed (`\\f`)\n * - Vertical tab (`\\v`)\n * - Non-breaking space (`\\u00A0`)\n * - Other Unicode spaces\n *\n * @param text - The text to normalize\n * @returns Text with normalized whitespace\n *\n * @example\n * Basic usage:\n * ```typescript\n * normalizeWhitespace('hello world')\n * // → 'hello world'\n *\n * normalizeWhitespace('hello\\tworld')\n * // → 'hello world'\n * ```\n *\n * @example\n * Multiple types of whitespace:\n * ```typescript\n * normalizeWhitespace('hello\\n\\nworld')\n * // → 'hello world'\n *\n * normalizeWhitespace('hello\\r\\nworld')\n * // → 'hello world'\n *\n * normalizeWhitespace('line1\\n\\nline2\\tword')\n * // → 'line1 line2 word'\n * ```\n *\n * @example\n * Leading and trailing whitespace:\n * ```typescript\n * normalizeWhitespace(' hello world ')\n * // → 'hello world'\n *\n * normalizeWhitespace('\\n\\thello\\t\\n')\n * // → 'hello'\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * normalizeWhitespace('')\n * // → ''\n *\n * normalizeWhitespace(' ')\n * // → ''\n *\n * normalizeWhitespace('hello')\n * // → 'hello'\n * ```\n *\n * @public\n */\nexport function normalizeWhitespace(text: string): string {\n if (!text) return text;\n\n // Replace all whitespace characters with single space\n // \\s matches: space, tab, newline, carriage return, form feed, vertical tab\n return text.trim().replace(/\\s+/g, ' ');\n}\n\n/**\n * Remove or replace unwanted characters from text\n *\n * This function provides flexible text sanitization with options to:\n * - Remove newlines\n * - Remove extra spaces\n * - Remove punctuation\n * - Keep only allowed characters\n * - Trim leading/trailing whitespace\n *\n * @param text - The text to sanitize\n * @param options - Sanitization options\n * @returns The sanitized text\n *\n * @example\n * Remove extra spaces (default):\n * ```typescript\n * sanitize('hello world')\n * // → 'hello world'\n * ```\n *\n * @example\n * Remove newlines:\n * ```typescript\n * sanitize('line1\\nline2\\nline3', { removeNewlines: true })\n * // → 'line1 line2 line3'\n * ```\n *\n * @example\n * Remove punctuation:\n * ```typescript\n * sanitize('Hello, World!', { removePunctuation: true })\n * // → 'Hello World'\n * ```\n *\n * @example\n * Allow only specific characters:\n * ```typescript\n * sanitize('ABC123!@#', { allowedChars: 'A-Za-z0-9' })\n * // → 'ABC123'\n *\n * sanitize('Hello123!@#', { allowedChars: 'a-z' })\n * // → 'ello'\n * ```\n *\n * @example\n * Combined options:\n * ```typescript\n * sanitize(' Hello,\\n World! ', {\n * removeNewlines: true,\n * removePunctuation: true,\n * removeExtraSpaces: true,\n * trim: true\n * })\n * // → 'Hello World'\n * ```\n *\n * @public\n */\nexport function sanitize(text: string, options?: SanitizeOptions): string {\n if (!text) return text;\n\n const {\n removeNewlines = false,\n removeExtraSpaces = true,\n removePunctuation = false,\n allowedChars,\n trim = true,\n } = options || {};\n\n let result = text;\n\n // Remove newlines first (replace with space)\n if (removeNewlines) {\n result = result.replace(/[\\n\\r]/g, ' ');\n }\n\n // Remove punctuation\n if (removePunctuation) {\n result = result.replace(/[!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~]/g, '');\n }\n\n // Keep only allowed characters\n if (allowedChars) {\n const allowedRegex = new RegExp(`[^${allowedChars}]`, 'g');\n result = result.replace(allowedRegex, '');\n }\n\n // Remove extra spaces\n if (removeExtraSpaces) {\n if (trim) {\n // When trimming, we can safely collapse all spaces\n if (removeNewlines) {\n result = result.replace(/\\s+/g, ' ');\n } else {\n result = result.replace(/[ \\t]+/g, ' ');\n }\n } else {\n // When not trimming, preserve leading/trailing spaces\n // Only collapse spaces in the middle\n const leadingMatch = result.match(/^([ \\t]*)/);\n const trailingMatch = result.match(/([ \\t]*)$/);\n const leading = leadingMatch ? leadingMatch[1] : '';\n const trailing = trailingMatch ? trailingMatch[1] : '';\n\n const middle = result.slice(\n leading.length,\n result.length - trailing.length\n );\n const normalizedMiddle = removeNewlines\n ? middle.replace(/\\s+/g, ' ')\n : middle.replace(/[ \\t]+/g, ' ');\n\n result = leading + normalizedMiddle + trailing;\n }\n }\n\n // Trim\n if (trim) {\n result = result.trim();\n }\n\n return result;\n}\n\n/**\n * Remove diacritical marks (accents) from characters\n *\n * Converts accented characters to their base form:\n * - é → e\n * - ñ → n\n * - ü → u\n * - etc.\n *\n * Useful for:\n * - Search normalization\n * - Sorting/comparison\n * - URL generation\n * - Database queries\n *\n * @param text - The text to remove accents from\n * @returns Text with accents removed\n *\n * @example\n * Basic usage:\n * ```typescript\n * removeAccents('café')\n * // → 'cafe'\n *\n * removeAccents('résumé')\n * // → 'resume'\n * ```\n *\n * @example\n * Various accents:\n * ```typescript\n * removeAccents('naïve')\n * // → 'naive'\n *\n * removeAccents('Zürich')\n * // → 'Zurich'\n *\n * removeAccents('São Paulo')\n * // → 'Sao Paulo'\n * ```\n *\n * @example\n * Mixed text:\n * ```typescript\n * removeAccents('École française à Montréal')\n * // → 'Ecole francaise a Montreal'\n * ```\n *\n * @public\n */\nexport function removeAccents(text: string): string {\n if (!text) return text;\n\n // Manual mapping for Nordic and other special characters that don't decompose\n const specialChars: Record<string, string> = {\n Ø: 'O',\n ø: 'o',\n Æ: 'AE',\n æ: 'ae',\n Å: 'A',\n å: 'a',\n Đ: 'D',\n đ: 'd',\n Ł: 'L',\n ł: 'l',\n Þ: 'TH',\n þ: 'th',\n ß: 'ss',\n };\n\n // First apply manual mappings\n let result = text;\n for (const [accented, plain] of Object.entries(specialChars)) {\n result = result.replace(new RegExp(accented, 'g'), plain);\n }\n\n // Then normalize to NFD and remove combining diacritical marks\n return result.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');\n}\n","import { ABBREVIATIONS } from './constants';\nimport type { ExpandOptions } from './types';\n\n/**\n * Expand Indonesian abbreviations to their full form\n *\n * This function expands common Indonesian abbreviations like:\n * - Address: Jl. → Jalan, Kec. → Kecamatan\n * - Titles: Dr. → Doktor, S.H. → Sarjana Hukum\n * - Honorifics: Bpk. → Bapak, Yth. → Yang Terhormat\n * - Organizations: PT. → Perseroan Terbatas\n * - Common: dll. → dan lain-lain\n *\n * **Features:**\n * - Case-insensitive matching (Jl. = jl. = JL.)\n * - Mode filtering (all, address, title, org)\n * - Custom mapping support\n * - Preserves surrounding text\n * - Multiple abbreviations in one string\n *\n * @param text - The text containing abbreviations to expand\n * @param options - Optional configuration\n * @returns Text with abbreviations expanded\n *\n * @example\n * Basic usage:\n * ```typescript\n * expandAbbreviation('Jl. Sudirman No. 123')\n * // → 'Jalan Sudirman Nomor 123'\n *\n * expandAbbreviation('Dr. Joko Widodo, S.H.')\n * // → 'Doktor Joko Widodo, Sarjana Hukum'\n * ```\n *\n * @example\n * Address abbreviations:\n * ```typescript\n * expandAbbreviation('Kab. Bogor, Kec. Ciawi')\n * // → 'Kabupaten Bogor, Kecamatan Ciawi'\n *\n * expandAbbreviation('Jl. Merdeka Gg. 5 No. 10')\n * // → 'Jalan Merdeka Gang 5 Nomor 10'\n * ```\n *\n * @example\n * Academic titles:\n * ```typescript\n * expandAbbreviation('Prof. Dr. Ir. Ahmad')\n * // → 'Profesor Doktor Insinyur Ahmad'\n *\n * expandAbbreviation('Saya lulusan S.T. dari ITB')\n * // → 'Saya lulusan Sarjana Teknik dari ITB'\n * ```\n *\n * @example\n * Honorifics:\n * ```typescript\n * expandAbbreviation('Yth. Bpk. H. Ahmad')\n * // → 'Yang Terhormat Bapak Haji Ahmad'\n * ```\n *\n * @example\n * Organizations:\n * ```typescript\n * expandAbbreviation('PT. Maju Jaya Tbk.')\n * // → 'Perseroan Terbatas Maju Jaya Terbuka'\n * ```\n *\n * @example\n * Mode filtering:\n * ```typescript\n * expandAbbreviation('Dr. Joko di Jl. Sudirman', { mode: 'address' })\n * // → 'Dr. Joko di Jalan Sudirman'\n * // Only expands address abbreviations\n *\n * expandAbbreviation('Prof. Dr. di Jl. Sudirman', { mode: 'title' })\n * // → 'Profesor Doktor di Jl. Sudirman'\n * // Only expands title abbreviations\n * ```\n *\n * @example\n * Custom mappings:\n * ```typescript\n * expandAbbreviation('BUMN adalah perusahaan negara', {\n * customMap: { 'BUMN': 'Badan Usaha Milik Negara' }\n * })\n * // → 'Badan Usaha Milik Negara adalah perusahaan negara'\n * ```\n *\n * @example\n * Case sensitivity:\n * ```typescript\n * expandAbbreviation('jl. sudirman')\n * // → 'Jalan sudirman' (default: preserves surrounding case)\n *\n * expandAbbreviation('JL. SUDIRMAN')\n * // → 'Jalan SUDIRMAN'\n * ```\n *\n * @public\n */\nexport function expandAbbreviation(\n text: string,\n options?: ExpandOptions\n): string {\n if (!text) return text;\n\n const { mode = 'all', customMap = {}, preserveCase = false } = options || {};\n\n // Combine built-in and custom abbreviations\n const abbreviationsMap = {\n ...getAbbreviationsByMode(mode),\n ...customMap,\n };\n\n let result = text;\n\n // Sort by length (longest first) to avoid partial replacements\n // Example: Replace \"S.H.\" before \"S.\" to avoid \"Sarjana.H.\"\n const sortedAbbrevs = Object.keys(abbreviationsMap).sort(\n (a, b) => b.length - a.length\n );\n\n for (const abbrev of sortedAbbrevs) {\n const expansion = abbreviationsMap[abbrev];\n\n // Create case-insensitive regex with word boundaries\n // Handle word boundaries intelligently:\n // - If starts with word char, add \\b prefix\n // - If ends with word char, add \\b suffix\n // - If ends with dot, don't add \\b suffix (dots are non-word chars)\n const startBoundary = /^\\w/.test(abbrev) ? '\\\\b' : '';\n const endBoundary = /\\w$/.test(abbrev) ? '\\\\b' : '';\n\n const regex = new RegExp(\n `${startBoundary}${escapeRegex(abbrev)}${endBoundary}`,\n 'gi'\n );\n\n result = result.replace(regex, (match) => {\n // If preserveCase is false, use the expansion as-is\n if (!preserveCase) {\n return expansion;\n }\n\n // If preserveCase is true, try to match case of original\n return matchCase(match, expansion);\n });\n }\n\n return result;\n}\n\n/**\n * Get abbreviations filtered by mode\n */\nfunction getAbbreviationsByMode(\n mode: 'all' | 'address' | 'title' | 'org'\n): Record<string, string> {\n if (mode === 'all') {\n return ABBREVIATIONS;\n }\n\n const filtered: Record<string, string> = {};\n\n // Define which abbreviations belong to which category\n const addressAbbrevs = [\n 'Jl.',\n 'Gg.',\n 'No.',\n 'Kp.',\n 'Ds.',\n 'Kel.',\n 'Kec.',\n 'Kab.',\n 'Kota',\n 'Prov.',\n 'Prop.',\n 'Rt.',\n 'Rw.',\n 'Blok',\n 'Komp.',\n 'Perumahan',\n 'Perum.',\n ];\n\n const titleAbbrevs = [\n 'Dr.',\n 'Ir.',\n 'Prof.',\n 'Drs.',\n 'Dra.',\n 'S.Pd.',\n 'S.H.',\n 'S.E.',\n 'S.T.',\n 'S.Kom.',\n 'S.Si.',\n 'S.Sos.',\n 'S.I.Kom.',\n 'S.S.',\n 'S.Psi.',\n 'S.Farm.',\n 'S.Ked.',\n 'M.Sc.',\n 'M.M.',\n 'M.Pd.',\n 'M.T.',\n 'M.Kom.',\n 'M.Si.',\n 'M.H.',\n 'M.A.',\n 'MBA',\n ];\n\n const orgAbbrevs = [\n 'PT.',\n 'CV.',\n 'UD.',\n 'PD.',\n 'Tbk.',\n 'Koperasi',\n 'Yayasan',\n ];\n\n // Filter based on mode\n for (const [abbrev, expansion] of Object.entries(ABBREVIATIONS)) {\n if (mode === 'address' && addressAbbrevs.includes(abbrev)) {\n filtered[abbrev] = expansion;\n } else if (mode === 'title' && titleAbbrevs.includes(abbrev)) {\n filtered[abbrev] = expansion;\n } else if (mode === 'org' && orgAbbrevs.includes(abbrev)) {\n filtered[abbrev] = expansion;\n }\n }\n\n return filtered;\n}\n\n/**\n * Escape special regex characters in a string\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Match the case pattern of original string to replacement\n * - ALL CAPS → ALL CAPS\n * - Title Case → Title Case\n * - lowercase → lowercase\n */\nfunction matchCase(original: string, replacement: string): string {\n // Check if original is all uppercase\n if (original === original.toUpperCase()) {\n return replacement.toUpperCase();\n }\n\n // Check if original is all lowercase\n if (original === original.toLowerCase()) {\n return replacement.toLowerCase();\n }\n\n // Check if original is title case (first letter uppercase)\n if (original.charAt(0) === original.charAt(0).toUpperCase()) {\n return (\n replacement.charAt(0).toUpperCase() + replacement.slice(1).toLowerCase()\n );\n }\n\n // Default: return as-is\n return replacement;\n}\n\n/**\n * Contract full forms to abbreviations (reverse of expand)\n *\n * @param text - The text containing full forms to contract\n * @param options - Optional configuration\n * @returns Text with full forms contracted\n *\n * @example\n * ```typescript\n * contractAbbreviation('Jalan Sudirman Nomor 123')\n * // → 'Jl. Sudirman No. 123'\n *\n * contractAbbreviation('Doktor Ahmad, Sarjana Hukum')\n * // → 'Dr. Ahmad, S.H.'\n * ```\n *\n * @public\n */\nexport function contractAbbreviation(\n text: string,\n options?: { mode?: 'all' | 'address' | 'title' | 'org' }\n): string {\n if (!text) return text;\n\n const { mode = 'all' } = options || {};\n\n // Get abbreviations and create reverse mapping\n const abbreviationsMap = getAbbreviationsByMode(mode);\n const reverseMap: Record<string, string> = {};\n\n for (const [abbrev, expansion] of Object.entries(abbreviationsMap)) {\n reverseMap[expansion] = abbrev;\n }\n\n let result = text;\n\n // Sort by length (longest first) to avoid partial replacements\n const sortedExpansions = Object.keys(reverseMap).sort(\n (a, b) => b.length - a.length\n );\n\n for (const expansion of sortedExpansions) {\n const abbrev = reverseMap[expansion];\n\n // Case-insensitive replace\n const regex = new RegExp(`\\\\b${escapeRegex(expansion)}\\\\b`, 'gi');\n\n result = result.replace(regex, abbrev);\n }\n\n return result;\n}\n","import { PROFANITY, STOPWORDS } from './constants';\n\n/**\n * Filters common Indonesian profanity words by masking them.\n *\n * @param text - The text to filter\n * @param mask - The masking character (default: '*')\n * @returns Filtered text\n *\n * @example\n * ```typescript\n * profanityFilter('kamu anjing banget'); // 'kamu ****** banget'\n * ```\n */\nexport function profanityFilter(text: string, mask: string = '*'): string {\n let filtered = text;\n\n PROFANITY.forEach((word) => {\n const regex = new RegExp(`\\\\b${word}\\\\b`, 'gi');\n filtered = filtered.replace(regex, mask.repeat(word.length));\n });\n\n return filtered;\n}\n\n/**\n * Removes common Indonesian stopwords from text.\n *\n * @param text - The text to process\n * @returns Text with stopwords removed\n *\n * @example\n * ```typescript\n * removeStopwords('saya sedang makan nasi'); // 'makan nasi'\n * ```\n */\nexport function removeStopwords(text: string): string {\n const words = text.split(/\\s+/);\n const filtered = words.filter(\n (word) => !(STOPWORDS as readonly string[]).includes(word.toLowerCase())\n );\n\n return filtered.join(' ');\n}\n","/**\n * Basic mapping of common informal Indonesian words to formal ones.\n */\nconst INFORMAL_MAP: Record<string, string> = {\n gw: 'saya',\n gua: 'saya',\n lu: 'kamu',\n lo: 'kamu',\n elo: 'kamu',\n lagi: 'sedang',\n gue: 'saya',\n gwe: 'saya',\n gak: 'tidak',\n ga: 'tidak',\n nggak: 'tidak',\n kalo: 'kalau',\n karna: 'karena',\n tapi: 'tetapi',\n udah: 'sudah',\n dah: 'sudah',\n aja: 'saja',\n banget: 'sekali',\n emang: 'memang',\n pake: 'pakai',\n bikin: 'membuat',\n kasih: 'memberi',\n dapet: 'dapat',\n liat: 'lihat',\n ngasih: 'memberi',\n nyari: 'mencari',\n nanya: 'bertanya',\n bilang: 'berkata',\n};\n\n/**\n * Normalizes informal Indonesian text to a more formal version.\n * This is a basic rule-based implementation.\n *\n * @param text - The text to normalize\n * @returns Formalized text\n *\n * @example\n * ```typescript\n * toFormal('gw lagi makan'); // 'saya sedang makan'\n * ```\n */\nexport function toFormal(text: string): string {\n const words = text.split(/\\s+/);\n const formalized = words.map((word) => {\n const lower = word.toLowerCase().replace(/[^\\w]/g, '');\n const formal = INFORMAL_MAP[lower];\n if (formal) {\n // Keep capitalization if possible\n if (word[0] === word[0].toUpperCase()) {\n return formal.charAt(0).toUpperCase() + formal.slice(1);\n }\n return formal;\n }\n return word;\n });\n\n return formalized.join(' ');\n}\n\n/**\n * Detects if a text follows \"alay\" style (unconventional capitalization or number substitution).\n *\n * @param text - The text to check\n * @returns `true` if alay style detected, `false` otherwise\n *\n * @example\n * ```typescript\n * isAlay('AqU sAyAnG qMu'); // true\n * isAlay('Makan 4y4m'); // true\n * ```\n */\nexport function isAlay(text: string): boolean {\n if (!text) return false;\n\n // Rule 1: Alternating caps (mOxEd cAsE)\n // More specific: lower-UPPER-lower or UPPER-lower-UPPER, multiple times\n const alternatingCaps = /([a-z][A-Z][a-z]|[A-Z][a-z][A-Z])/.test(text);\n\n // Rule 2: Number substitution in words\n const numberSub = /\\b\\w*[0431572]\\w*\\b/.test(text);\n\n // Rule 3: Excessive 'q' instead of 'k'\n const qSub = /q/i.test(text) && !/u/i.test(text);\n\n // Rule 4: Excessive characters (e.g., 'siiaappp')\n const excessiveChars = /(.)\\1{2,}/.test(text);\n\n return alternatingCaps || numberSub || qSub || excessiveChars;\n}\n","import type { TruncateOptions, ExtractOptions } from './types';\n\n/**\n * Truncate text to specified length, word-aware\n *\n * This function shortens text to a maximum length while:\n * - Respecting word boundaries (don't cut words in half)\n * - Adding ellipsis to indicate truncation\n * - Preserving original text if already short enough\n * - Accounting for ellipsis length in total character count\n *\n * **Features:**\n * - Smart word boundary detection\n * - Customizable ellipsis\n * - No truncation for short text\n * - Handles edge cases gracefully\n *\n * @param text - The text to truncate\n * @param maxLength - Maximum length of output (including ellipsis)\n * @param options - Optional configuration\n * @returns The truncated text with ellipsis if needed\n *\n * @example\n * Basic usage:\n * ```typescript\n * truncate('Ini adalah contoh text yang panjang', 20)\n * // → 'Ini adalah contoh...'\n *\n * truncate('Short text', 20)\n * // → 'Short text' (no truncation needed)\n * ```\n *\n * @example\n * Word boundary handling:\n * ```typescript\n * truncate('Ini adalah contoh text yang panjang', 20, { wordBoundary: true })\n * // → 'Ini adalah contoh...' (stops at word)\n *\n * truncate('Ini adalah contoh text yang panjang', 20, { wordBoundary: false })\n * // → 'Ini adalah contoh t...' (cuts mid-word)\n * ```\n *\n * @example\n * Custom ellipsis:\n * ```typescript\n * truncate('Ini adalah contoh text yang panjang', 20, { ellipsis: '…' })\n * // → 'Ini adalah contoh…'\n *\n * truncate('Ini adalah contoh text yang panjang', 20, { ellipsis: ' [...]' })\n * // → 'Ini adalah [...]'\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * truncate('', 10)\n * // → ''\n *\n * truncate('Hello', 10)\n * // → 'Hello'\n *\n * truncate('Hello World', 11)\n * // → 'Hello World' (exact length, no ellipsis)\n * ```\n *\n * @public\n */\nexport function truncate(\n text: string,\n maxLength: number,\n options?: TruncateOptions\n): string {\n // Early return for empty or invalid input\n if (!text || maxLength <= 0) {\n return '';\n }\n\n const { ellipsis = '...', wordBoundary = true } = options || {};\n\n // Early return if text is already short enough\n if (text.length <= maxLength) {\n return text;\n }\n\n // Calculate available space for actual text (excluding ellipsis)\n const availableLength = maxLength - ellipsis.length;\n\n // If ellipsis is longer than maxLength, just return ellipsis truncated\n if (availableLength <= 0) {\n return ellipsis.slice(0, maxLength);\n }\n\n // Get preliminary truncated text\n let truncated = text.slice(0, availableLength);\n\n // If word boundary is enabled, find last complete word\n if (wordBoundary) {\n // Find the last space within the truncated text\n const lastSpaceIndex = truncated.lastIndexOf(' ');\n\n // Only cut at word boundary if we found a space\n // Why: Prevents returning empty string for single long word\n if (lastSpaceIndex > 0) {\n truncated = truncated.slice(0, lastSpaceIndex);\n }\n // If no space found, keep the full availableLength\n }\n\n // Trim any trailing whitespace before adding ellipsis\n truncated = truncated.trimEnd();\n\n return truncated + ellipsis;\n}\n\n/**\n * Extract words from text, respecting Indonesian language rules\n *\n * This function splits text into individual words while:\n * - Respecting hyphenated words (anak-anak as single word)\n * - Filtering by minimum length\n * - Optional lowercase conversion\n * - Removing punctuation and special characters\n *\n * **Features:**\n * - Indonesian hyphenation support (anak-anak, buku-buku)\n * - Minimum word length filtering\n * - Case normalization\n * - Handles punctuation gracefully\n *\n * @param text - The text to extract words from\n * @param options - Optional configuration\n * @returns Array of extracted words\n *\n * @example\n * Basic usage:\n * ```typescript\n * extractWords('Anak-anak bermain di taman')\n * // → ['Anak-anak', 'bermain', 'di', 'taman']\n *\n * extractWords('Hello, World! How are you?')\n * // → ['Hello', 'World', 'How', 'are', 'you']\n * ```\n *\n * @example\n * Hyphenated word handling:\n * ```typescript\n * extractWords('Anak-anak bermain di taman', { includeHyphenated: true })\n * // → ['Anak-anak', 'bermain', 'di', 'taman']\n *\n * extractWords('Anak-anak bermain di taman', { includeHyphenated: false })\n * // → ['Anak', 'anak', 'bermain', 'di', 'taman']\n * ```\n *\n * @example\n * Minimum length filtering:\n * ```typescript\n * extractWords('Di rumah ada 3 kucing', { minLength: 3 })\n * // → ['rumah', 'ada', 'kucing']\n * // 'Di' (2 chars) and '3' (1 char) filtered out\n *\n * extractWords('a b cd def ghij', { minLength: 3 })\n * // → ['def', 'ghij']\n * ```\n *\n * @example\n * Lowercase conversion:\n * ```typescript\n * extractWords('Hello WORLD', { lowercase: true })\n * // → ['hello', 'world']\n *\n * extractWords('Hello WORLD', { lowercase: false })\n * // → ['Hello', 'WORLD']\n * ```\n *\n * @example\n * Combined options:\n * ```typescript\n * extractWords('Anak-Anak BERMAIN di Taman', {\n * includeHyphenated: true,\n * minLength: 3,\n * lowercase: true\n * })\n * // → ['anak-anak', 'bermain', 'taman']\n * // 'di' filtered out (< 3 chars)\n * ```\n *\n * @example\n * Edge cases:\n * ```typescript\n * extractWords('')\n * // → []\n *\n * extractWords(' ')\n * // → []\n *\n * extractWords('!!!@@##')\n * // → []\n * ```\n *\n * @public\n */\nexport function extractWords(text: string, options?: ExtractOptions): string[] {\n // Early return for empty input\n if (!text || !text.trim()) {\n return [];\n }\n\n const {\n minLength = 0,\n includeHyphenated = true,\n lowercase = false,\n } = options || {};\n\n // Remove punctuation but preserve hyphens and spaces\n // Why: We want to keep hyphenated words like 'anak-anak' intact\n let cleaned = text;\n\n if (includeHyphenated) {\n // Keep hyphens, remove other punctuation\n // Replace punctuation except hyphens with spaces\n cleaned = text.replace(/[^\\w\\s-]/g, ' ');\n } else {\n // Replace all punctuation including hyphens with spaces\n cleaned = text.replace(/[^\\w\\s]/g, ' ');\n }\n\n // Split by whitespace to get individual words\n const words = cleaned\n .split(/\\s+/)\n .map((word) => word.trim())\n .filter((word) => word.length > 0)\n // Filter out words that are just hyphens (common artifact of punctuation removal)\n .filter((word) => !/^-+$/.test(word));\n\n // Apply filters\n let result = words;\n\n // Filter by minimum length\n if (minLength > 0) {\n result = result.filter((word) => word.length >= minLength);\n }\n\n // Convert to lowercase if requested\n if (lowercase) {\n result = result.map((word) => word.toLowerCase());\n }\n\n return result;\n}\n","import type { CompareOptions } from './types';\nimport { normalizeWhitespace, removeAccents } from './sanitize';\n\n/**\n * Compare strings with Indonesian-aware normalization\n *\n * This function allows flexible string comparison with options to ignore\n * case, whitespace, and accents. Useful for search, filtering, and\n * validation.\n *\n * **Features:**\n * - Case-insensitive comparison (default: false)\n * - Whitespace normalization (ignore extra spaces)\n * - Accent removal (café == cafe)\n * - Null-safe (handles empty strings)\n *\n * @param str1 - First string to compare\n * @param str2 - Second string to compare\n * @param options - Comparison options\n * @returns True if strings match according to options\n *\n * @example\n * Basic matching:\n * ```typescript\n * compareStrings('Hello', 'Hello') // → true\n * compareStrings('Hello', 'hello') // → false\n * ```\n *\n * @example\n * Case insensitive:\n * ```typescript\n * compareStrings('Hello', 'hello', { caseSensitive: false }) // → true\n * // Note: default is caseSensitive: false for convenience in many utils,\n * // but strict comparison usually defaults to true.\n * // Let's check the implementation default.\n * ```\n *\n * @example\n * Ignore whitespace:\n * ```typescript\n * compareStrings(' Hello World ', 'Hello World', { ignoreWhitespace: true })\n * // → true\n * ```\n *\n * @example\n * Ignore accents:\n * ```typescript\n * compareStrings('café', 'cafe', { ignoreAccents: true })\n * // → true\n * ```\n *\n * @public\n */\nexport function compareStrings(\n str1: string,\n str2: string,\n options?: CompareOptions\n): boolean {\n // Early return for exact match (optimization)\n if (str1 === str2) {\n return true;\n }\n\n // Handle null/undefined as empty strings for robust comparison\n // usage of (str || '') pattern\n const s1 = str1 || '';\n const s2 = str2 || '';\n\n const {\n caseSensitive = false,\n ignoreWhitespace = false,\n ignoreAccents = false,\n } = options || {};\n\n let normalized1 = s1;\n let normalized2 = s2;\n\n // Apply whitespace normalization\n if (ignoreWhitespace) {\n normalized1 = normalizeWhitespace(normalized1);\n normalized2 = normalizeWhitespace(normalized2);\n }\n\n // Apply accent removal\n if (ignoreAccents) {\n normalized1 = removeAccents(normalized1);\n normalized2 = removeAccents(normalized2);\n }\n\n // Apply case sensitivity\n if (!caseSensitive) {\n normalized1 = normalized1.toLowerCase();\n normalized2 = normalized2.toLowerCase();\n }\n\n return normalized1 === normalized2;\n}\n\n/**\n * Calculate similarity score between two strings (0-1) using Levenshtein distance\n *\n * This function measures the difference between two strings and returns a score\n * where 1.0 means identical and 0.0 means completely different.\n *\n * **Algorithm:**\n * Uses Levenshtein distance to calculate the minimum number of single-character\n * edits (insertions, deletions, substitutions) required to change one string\n * into the other.\n *\n * @param str1 - First string\n * @param str2 - Second string\n * @returns Similarity score between 0.0 and 1.0\n *\n * @example\n * Basic Usage:\n * ```typescript\n * similarity('hello', 'hello') // → 1.0 (identical)\n * similarity('hello', 'hallo') // → 0.8 (1 edit / 5 length)\n * similarity('hello', 'world') // → 0.2 (4 edits / 5 length)\n * ```\n *\n * @example\n * Case sensitivity:\n * Note: This function is case-sensitive. Use compareStrings options or\n * manual lowercasing if you need case-insensitive similarity.\n *\n * @public\n */\nexport function similarity(str1: string, str2: string): number {\n if (str1 === str2) return 1.0;\n if (str1.length === 0) return str2.length === 0 ? 1.0 : 0.0;\n if (str2.length === 0) return 0.0;\n\n const len1 = str1.length;\n const len2 = str2.length;\n\n // Track previous and current rows of the matrix\n // Optimization: We only need two rows, not the full matrix O(min(m,n)) space\n let prevRow = Array(len2 + 1).fill(0);\n let currentRow = Array(len2 + 1).fill(0);\n\n // Initialize first row\n for (let j = 0; j <= len2; j++) {\n prevRow[j] = j;\n }\n\n // Calculate distance\n for (let i = 1; i <= len1; i++) {\n currentRow[0] = i;\n\n for (let j = 1; j <= len2; j++) {\n const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;\n\n currentRow[j] = Math.min(\n currentRow[j - 1] + 1, // Insertion\n prevRow[j] + 1, // Deletion\n prevRow[j - 1] + cost // Substitution\n );\n }\n\n // Move current row to previous for next iteration\n [prevRow, currentRow] = [currentRow, prevRow];\n }\n\n // Calculate similarity: 1 - (distance / max_length)\n const distance = prevRow[len2];\n const maxLength = Math.max(len1, len2);\n\n return 1.0 - distance / maxLength;\n}\n","/**\n * Custom error classes for datetime module\n *\n * @module datetime/types\n * @packageDocumentation\n */\n\n/**\n * Error thrown when an invalid date is provided to a function.\n * Extends native Error with a `code` property for programmatic error handling.\n *\n * @example\n * ```typescript\n * try {\n * formatDate('invalid');\n * } catch (error) {\n * if (error instanceof InvalidDateError) {\n * console.log(error.code); // 'INVALID_DATE'\n * }\n * }\n * ```\n */\nexport class InvalidDateError extends Error {\n /** Error code for programmatic identification */\n readonly code = 'INVALID_DATE' as const;\n\n constructor(message: string = 'Invalid date provided') {\n super(message);\n this.name = 'InvalidDateError';\n }\n}\n\n/**\n * Error thrown when an invalid date range is provided.\n * Extends native Error with a `code` property for programmatic error handling.\n *\n * @example\n * ```typescript\n * try {\n * formatDateRange(new Date('2026-01-05'), new Date('2026-01-01'));\n * } catch (error) {\n * if (error instanceof InvalidDateRangeError) {\n * console.log(error.code); // 'INVALID_DATE_RANGE'\n * }\n * }\n * ```\n */\nexport class InvalidDateRangeError extends Error {\n /** Error code for programmatic identification */\n readonly code = 'INVALID_DATE_RANGE' as const;\n\n constructor(message: string = 'End date must be after start date') {\n super(message);\n this.name = 'InvalidDateRangeError';\n }\n}\n\n/**\n * Date formatting style options\n */\nexport type DateStyle =\n | 'full'\n | 'long'\n | 'medium'\n | 'short'\n | 'weekday'\n | 'month';\n\n/**\n * Options for getAge function\n */\nexport interface AgeOptions {\n /**\n * Reference date to calculate age from.\n * Defaults to current date at function call time.\n * @defaultValue new Date()\n */\n fromDate?: Date | string | number;\n\n /**\n * Return age as formatted string instead of object.\n * @defaultValue false\n */\n asString?: boolean;\n}\n\n/**\n * Age calculation result object\n */\nexport interface AgeResult {\n /** Full years */\n years: number;\n /** Remaining months (0-11) */\n months: number;\n /** Remaining days (0-30) */\n days: number;\n}\n","/**\n * Constants for Indonesian datetime formatting\n *\n * @module datetime/constants\n * @packageDocumentation\n */\n\n/** Full Indonesian month names (1-indexed: index 0 = empty, 1 = Januari) */\nexport const MONTH_NAMES: readonly string[] = [\n '', // Placeholder for 0-index\n 'Januari',\n 'Februari',\n 'Maret',\n 'April',\n 'Mei',\n 'Juni',\n 'Juli',\n 'Agustus',\n 'September',\n 'Oktober',\n 'November',\n 'Desember',\n];\n\n/** Short Indonesian month names (3-letter abbreviation) */\nexport const MONTH_NAMES_SHORT: readonly string[] = [\n '', // Placeholder for 0-index\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'Mei',\n 'Jun',\n 'Jul',\n 'Agu',\n 'Sep',\n 'Okt',\n 'Nov',\n 'Des',\n];\n\n/** Full Indonesian day names */\nexport const DAY_NAMES: readonly string[] = [\n 'Minggu',\n 'Senin',\n 'Selasa',\n 'Rabu',\n 'Kamis',\n 'Jumat',\n 'Sabtu',\n];\n\n/** Short Indonesian day names (3-letter abbreviation) */\nexport const DAY_NAMES_SHORT: readonly string[] = [\n 'Min',\n 'Sen',\n 'Sel',\n 'Rab',\n 'Kam',\n 'Jum',\n 'Sab',\n];\n\n/** Mapping of IANA timezone names to Indonesian abbreviations */\nexport const TIMEZONE_MAP: Readonly<Record<string, 'WIB' | 'WITA' | 'WIT'>> = {\n // UTC+7 - WIB\n 'Asia/Jakarta': 'WIB',\n 'Asia/Pontianak': 'WIB',\n\n // UTC+8 - WITA\n 'Asia/Makassar': 'WITA',\n 'Asia/Denpasar': 'WITA',\n 'Asia/Manado': 'WITA',\n 'Asia/Palu': 'WITA',\n\n // UTC+9 - WIT\n 'Asia/Jayapura': 'WIT',\n};\n\n/** Valid UTC offset hours that map to Indonesian timezones */\nexport const VALID_UTC_OFFSETS: readonly number[] = [7, 8, 9];\n","/**\n * Date calculation utilities\n *\n * @module datetime/calc\n * @packageDocumentation\n */\n\nimport { InvalidDateError } from './types';\n\n/**\n * Check if a year is a leap year.\n *\n * A year is a leap year if:\n * - Divisible by 4, but not by 100, OR\n * - Divisible by 400\n *\n * @param year - The year to check\n * @returns `true` if leap year, `false` otherwise (including invalid inputs)\n *\n * @example\n * ```typescript\n * isLeapYear(2024); // true\n * isLeapYear(2023); // false\n * isLeapYear(1900); // false (divisible by 100 but not 400)\n * isLeapYear(2000); // true (divisible by 400)\n * isLeapYear(NaN); // false\n * isLeapYear(3.5); // false (non-integer)\n * ```\n */\nexport function isLeapYear(year: number): boolean {\n // Return false for non-finite, non-integer, or NaN values\n if (!Number.isFinite(year) || !Number.isInteger(year)) {\n return false;\n }\n\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\n/**\n * Get the number of days in a month.\n *\n * Accounts for leap years in February.\n *\n * @param month - Month number (1-12, 1-indexed)\n * @param year - Full year (e.g., 2026)\n * @returns Number of days in the month, or 0 for invalid inputs\n *\n * @example\n * ```typescript\n * daysInMonth(1, 2026); // 31 (January)\n * daysInMonth(2, 2024); // 29 (February, leap year)\n * daysInMonth(2, 2023); // 28 (February, non-leap year)\n * daysInMonth(4, 2026); // 30 (April)\n * daysInMonth(13, 2026); // 0 (invalid month)\n * daysInMonth(2, NaN); // 0 (invalid year)\n * ```\n */\nexport function daysInMonth(month: number, year: number): number {\n // Validate inputs\n if (\n !Number.isFinite(month) ||\n !Number.isInteger(month) ||\n !Number.isFinite(year) ||\n !Number.isInteger(year) ||\n month < 1 ||\n month > 12\n ) {\n return 0;\n }\n\n // Months with 31 days: Jan(1), Mar(3), May(5), Jul(7), Aug(8), Oct(10), Dec(12)\n if ([1, 3, 5, 7, 8, 10, 12].includes(month)) {\n return 31;\n }\n\n // Months with 30 days: Apr(4), Jun(6), Sep(9), Nov(11)\n if ([4, 6, 9, 11].includes(month)) {\n return 30;\n }\n\n // February - check for leap year\n return isLeapYear(year) ? 29 : 28;\n}\n\n/**\n * Type guard to check if a value is a valid Date object.\n *\n * Returns `true` only for Date instances that represent a valid date\n * (i.e., not `Invalid Date`). Returns `false` for null, undefined,\n * invalid dates, and non-Date values.\n *\n * @param date - Value to check\n * @returns `true` if valid Date object, `false` otherwise\n *\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate(new Date('invalid')); // false\n * isValidDate(null); // false\n * isValidDate(undefined); // false\n * isValidDate('2024-01-01'); // false (string, not Date)\n * isValidDate(1704067200000); // false (number, not Date)\n * ```\n */\nexport function isValidDate(date: unknown): date is Date {\n return date instanceof Date && !Number.isNaN(date.getTime());\n}\n\n/**\n * Check if a date falls on a weekend (Saturday or Sunday).\n *\n * Note: This only checks Saturday/Sunday and does not account for\n * industry-specific Saturday work schedules.\n *\n * @param date - Date object to check\n * @returns `true` if Saturday or Sunday, `false` otherwise\n *\n * @example\n * ```typescript\n * isWeekend(new Date('2026-01-03')); // true (Saturday)\n * isWeekend(new Date('2026-01-04')); // true (Sunday)\n * isWeekend(new Date('2026-01-05')); // false (Monday)\n * ```\n */\nexport function isWeekend(date: Date): boolean {\n const day = date.getDay();\n return day === 0 || day === 6; // Sunday = 0, Saturday = 6\n}\n\n/**\n * Check if a date falls on a working day (Monday-Friday).\n *\n * Note: This only checks Monday-Friday and does not account for\n * national holidays (holiday lists require periodic updates and\n * are not included per project mandates).\n *\n * @param date - Date object to check\n * @returns `true` if Monday-Friday, `false` otherwise\n *\n * @example\n * ```typescript\n * isWorkingDay(new Date('2026-01-05')); // true (Monday)\n * isWorkingDay(new Date('2026-01-03')); // false (Saturday)\n * isWorkingDay(new Date('2026-01-04')); // false (Sunday)\n * ```\n */\nexport function isWorkingDay(date: Date): boolean {\n const day = date.getDay();\n return day >= 1 && day <= 5; // Monday = 1 to Friday = 5\n}\n\n/**\n * Normalize various date input types to a Date object.\n *\n * @param date - Date input (Date, string, or number timestamp)\n * @returns Date object\n * @throws {InvalidDateError} If the input cannot be parsed to a valid date\n */\nfunction normalizeDate(date: Date | string | number): Date {\n let result: Date;\n\n if (date instanceof Date) {\n result = date;\n } else if (typeof date === 'number') {\n result = new Date(date);\n } else if (typeof date === 'string') {\n result = new Date(date);\n } else {\n throw new InvalidDateError('Date must be a Date, string, or number');\n }\n\n if (Number.isNaN(result.getTime())) {\n throw new InvalidDateError(`Unable to parse date: ${String(date)}`);\n }\n\n return result;\n}\n\n/**\n * Calculate age from a birth date.\n *\n * Accounts for leap years and month length variations.\n * Can return as an object { years, months, days } or as a formatted string.\n *\n * @param birthDate - Birth date (Date, string, or number timestamp)\n * @param options - Options for age calculation\n * @returns Age as object or formatted string (based on asString option)\n * @throws {InvalidDateError} If birthDate or fromDate is invalid\n *\n * @example\n * ```typescript\n * // Get age as object\n * getAge('1990-06-15'); // { years: 36, months: 9, days: 21 }\n * getAge(new Date('1990-06-15'), { fromDate: new Date('2024-06-15') });\n * // { years: 34, months: 0, days: 0 }\n *\n * // Get age as string\n * getAge('1990-06-15', { asString: true });\n * // '36 Tahun 9 Bulan 21 Hari'\n *\n * getAge(new Date('2020-01-01'), { fromDate: new Date('2020-01-15'), asString: true });\n * // '15 Hari'\n * ```\n */\nexport function getAge(\n birthDate: Date | string | number,\n options: { fromDate?: Date | string | number; asString?: boolean } = {}\n): { years: number; months: number; days: number } | string {\n const birth = normalizeDate(birthDate);\n const from = options.fromDate ? normalizeDate(options.fromDate) : new Date();\n\n // Validate: birth date cannot be in the future\n if (birth.getTime() > from.getTime()) {\n throw new InvalidDateError(\n 'Birth date cannot be in the future relative to fromDate'\n );\n }\n\n let years = from.getFullYear() - birth.getFullYear();\n let months = from.getMonth() - birth.getMonth();\n let days = from.getDate() - birth.getDate();\n\n // Adjust for negative days\n if (days < 0) {\n months--;\n // Get days in previous month\n const prevMonth = from.getMonth() === 0 ? 11 : from.getMonth() - 1;\n const prevMonthYear =\n from.getMonth() === 0 ? from.getFullYear() - 1 : from.getFullYear();\n days += daysInMonth(prevMonth + 1, prevMonthYear);\n }\n\n // Adjust for negative months\n if (months < 0) {\n years--;\n months += 12;\n }\n\n const result = { years, months, days };\n\n if (options.asString) {\n return formatAgeString(result);\n }\n\n return result;\n}\n\n/**\n * Format age object as Indonesian string.\n * Omits zero components.\n *\n * @param age - Age object with years, months, days\n * @returns Formatted age string\n */\nfunction formatAgeString(age: {\n years: number;\n months: number;\n days: number;\n}): string {\n const parts: string[] = [];\n\n if (age.years > 0) {\n parts.push(`${age.years} Tahun`);\n }\n\n if (age.months > 0) {\n parts.push(`${age.months} Bulan`);\n }\n\n if (age.days > 0) {\n parts.push(`${age.days} Hari`);\n }\n\n // Handle edge case: all zeros (same day)\n if (parts.length === 0) {\n return '0 Hari';\n }\n\n return parts.join(' ');\n}\n","/**\n * Date parsing utilities for Indonesian formats\n *\n * @module datetime/parse\n * @packageDocumentation\n */\n\nimport { daysInMonth } from './calc';\n\n/**\n * Parse a date string in Indonesian format (DD-MM-YYYY) or ISO format (YYYY-MM-DD).\n *\n * Strict parsing rules:\n * - Accepts delimiters: `/`, `-`, `.`\n * - DD-MM-YYYY format: Day first (1-31), 4-digit year required\n * - ISO auto-detection: If first segment is 4 digits AND > 31, treated as YYYY-MM-DD\n * - Leap year validation: Feb 29 is only valid in leap years\n * - 2-digit years NOT supported\n * - Time components NOT supported\n *\n * @param dateStr - Date string to parse\n * @returns Date object if valid, `null` if invalid\n *\n * @example\n * ```typescript\n * // Indonesian format (DD-MM-YYYY)\n * parseDate('02-01-2026'); // Date(2026, 0, 2) - Jan 2, 2026\n * parseDate('02/01/2026'); // Date(2026, 0, 2)\n * parseDate('02.01.2026'); // Date(2026, 0, 2)\n *\n * // ISO format auto-detected (YYYY-MM-DD)\n * parseDate('2026-01-02'); // Date(2026, 0, 2)\n *\n * // Invalid inputs return null\n * parseDate('29-02-2023'); // null (not a leap year)\n * parseDate('02-01-26'); // null (2-digit year)\n * parseDate('02-01-2026 14:30'); // null (time component)\n * parseDate('invalid'); // null\n * ```\n */\nexport function parseDate(dateStr: string): Date | null {\n // Trim whitespace\n const trimmed = dateStr.trim();\n\n // Reject if empty\n if (!trimmed) {\n return null;\n }\n\n // Reject if contains time component (has space or colon)\n if (trimmed.includes(' ') || trimmed.includes(':')) {\n return null;\n }\n\n // Split by supported delimiters: / - .\n const parts = trimmed.split(/[-/.]/);\n\n // Must have exactly 3 parts\n if (parts.length !== 3) {\n return null;\n }\n\n // Parse all segments as integers\n const nums = parts.map((p) => parseInt(p, 10));\n\n // Check for NaN or negative values\n if (nums.some((n) => Number.isNaN(n) || n < 0)) {\n return null;\n }\n\n // Check for 2-digit years (any segment < 100 after the first position)\n // First segment can be < 100 (day) or > 31 (year in ISO format)\n const [first, second, third] = nums;\n\n // Determine format: ISO (YYYY-MM-DD) or Indonesian (DD-MM-YYYY)\n let day: number;\n let month: number;\n let year: number;\n\n // ISO format detection: first segment is 4 digits AND > 31 (must be a year)\n if (first > 999 && first > 31) {\n // ISO format: YYYY-MM-DD\n year = first;\n month = second;\n day = third;\n } else {\n // Indonesian format: DD-MM-YYYY\n // Validate that third segment is 4 digits (year)\n if (third < 1000) {\n return null; // 2-digit year not supported\n }\n\n day = first;\n month = second;\n year = third;\n }\n\n // Validate month range (1-12)\n if (month < 1 || month > 12) {\n return null;\n }\n\n // Validate year is reasonable (positive and 4 digits)\n if (year < 1000 || year > 9999) {\n return null;\n }\n\n // Validate day against month length\n const maxDays = daysInMonth(month, year);\n if (maxDays === 0 || day < 1 || day > maxDays) {\n return null;\n }\n\n // Create date (month is 0-indexed in JS Date)\n const date = new Date(year, month - 1, day);\n\n // Final validation: ensure the date was created correctly\n // (catches edge cases like Feb 30 being converted to Mar 2)\n if (\n date.getFullYear() !== year ||\n date.getMonth() !== month - 1 ||\n date.getDate() !== day\n ) {\n return null;\n }\n\n return date;\n}\n","/**\n * Date formatting utilities for Indonesian locale\n *\n * @module datetime/format\n * @packageDocumentation\n */\n\nimport {\n InvalidDateError,\n InvalidDateRangeError,\n type DateStyle,\n} from './types';\nimport { MONTH_NAMES, MONTH_NAMES_SHORT, DAY_NAMES } from './constants';\n\n/**\n * Normalize various date input types to a Date object.\n *\n * @param date - Date input (Date, string, or number timestamp)\n * @returns Date object\n * @throws {InvalidDateError} If the input cannot be parsed to a valid date\n */\nfunction normalizeDate(date: Date | string | number): Date {\n let result: Date;\n\n if (date instanceof Date) {\n result = date;\n } else if (typeof date === 'number') {\n // Assume milliseconds timestamp\n result = new Date(date);\n } else if (typeof date === 'string') {\n result = new Date(date);\n } else {\n throw new InvalidDateError('Date must be a Date, string, or number');\n }\n\n // Validate the result\n if (Number.isNaN(result.getTime())) {\n throw new InvalidDateError(`Unable to parse date: ${String(date)}`);\n }\n\n return result;\n}\n\n/**\n * Format a date with Indonesian locale.\n *\n * @param date - Date to format (Date, string, or number timestamp in milliseconds)\n * @param style - Formatting style (default: 'long')\n * @returns Formatted date string\n * @throws {InvalidDateError} If the date is invalid\n *\n * @example\n * ```typescript\n * formatDate(new Date('2026-01-02'), 'full'); // 'Jumat, 2 Januari 2026'\n * formatDate(new Date('2026-01-02'), 'long'); // '2 Januari 2026'\n * formatDate(new Date('2026-01-02'), 'medium'); // '2 Jan 2026'\n * formatDate(new Date('2026-01-02'), 'short'); // '02/01/2026'\n * formatDate(new Date('2026-01-02'), 'weekday'); // 'Jumat'\n * formatDate(new Date('2026-01-02'), 'month'); // 'Januari'\n * ```\n */\nexport function formatDate(\n date: Date | string | number,\n style: DateStyle = 'long'\n): string {\n const d = normalizeDate(date);\n\n const day = d.getDate();\n const month = d.getMonth() + 1; // 1-indexed\n const year = d.getFullYear();\n const dayOfWeek = d.getDay(); // 0 = Sunday\n\n switch (style) {\n case 'full':\n return `${DAY_NAMES[dayOfWeek]}, ${day} ${MONTH_NAMES[month]} ${year}`;\n\n case 'long':\n return `${day} ${MONTH_NAMES[month]} ${year}`;\n\n case 'medium':\n return `${day} ${MONTH_NAMES_SHORT[month]} ${year}`;\n\n case 'short': {\n const dd = String(day).padStart(2, '0');\n const mm = String(month).padStart(2, '0');\n return `${dd}/${mm}/${year}`;\n }\n\n case 'weekday':\n return DAY_NAMES[dayOfWeek];\n\n case 'month':\n return MONTH_NAMES[month];\n\n default:\n throw new InvalidDateError(`Unknown format style: ${style}`);\n }\n}\n\n/**\n * Format a date range with Indonesian locale and smart redundancy removal.\n *\n * Removes redundant month/year information when dates share them.\n *\n * @param start - Start date\n * @param end - End date\n * @param style - Formatting style (default: 'long')\n * @returns Formatted date range string\n * @throws {InvalidDateError} If either date is invalid\n * @throws {InvalidDateRangeError} If end date is before start date\n *\n * @example\n * ```typescript\n * // Same day\n * formatDateRange(\n * new Date('2026-01-02'),\n * new Date('2026-01-02')\n * ); // '2 Januari 2026'\n *\n * // Same month & year\n * formatDateRange(\n * new Date('2026-01-02'),\n * new Date('2026-01-05')\n * ); // '2 - 5 Januari 2026'\n *\n * // Same year\n * formatDateRange(\n * new Date('2026-01-30'),\n * new Date('2026-02-02')\n * ); // '30 Januari - 2 Februari 2026'\n *\n * // Different year\n * formatDateRange(\n * new Date('2025-12-30'),\n * new Date('2026-01-02')\n * ); // '30 Desember 2025 - 2 Januari 2026'\n * ```\n */\nexport function formatDateRange(\n start: Date,\n end: Date,\n style: Exclude<DateStyle, 'weekday' | 'month'> = 'long'\n): string {\n const s = normalizeDate(start);\n const e = normalizeDate(end);\n\n // Validate range\n if (e.getTime() < s.getTime()) {\n throw new InvalidDateRangeError();\n }\n\n // Short style: no redundancy removal, always full format\n if (style === 'short') {\n return `${formatDate(s, 'short')} - ${formatDate(e, 'short')}`;\n }\n\n // Full style: full weekday + date for both\n if (style === 'full') {\n return `${formatDate(s, 'full')} - ${formatDate(e, 'full')}`;\n }\n\n // Extract components\n const sDay = s.getDate();\n const eDay = e.getDate();\n const sMonth = s.getMonth() + 1;\n const eMonth = e.getMonth() + 1;\n const sYear = s.getFullYear();\n const eYear = e.getFullYear();\n\n // Same day: show single date\n if (sDay === eDay && sMonth === eMonth && sYear === eYear) {\n return formatDate(s, style);\n }\n\n // Different year: full format for both\n if (sYear !== eYear) {\n return `${formatDate(s, style)} - ${formatDate(e, style)}`;\n }\n\n // Same year, different month: omit year from start date\n if (sMonth !== eMonth) {\n if (style === 'long') {\n return `${sDay} ${MONTH_NAMES[sMonth]} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;\n }\n // medium style\n return `${sDay} ${MONTH_NAMES_SHORT[sMonth]} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;\n }\n\n // Same month & year: show range with single month/year\n if (style === 'long') {\n return `${sDay} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;\n }\n // medium style\n return `${sDay} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;\n}\n","/**\n * Relative time formatting for Indonesian locale\n *\n * @module datetime/relative\n * @packageDocumentation\n */\n\nimport { InvalidDateError } from './types';\nimport { formatDate } from './format';\n\n/**\n * Normalize various date input types to a Date object.\n *\n * @param date - Date input (Date, string, or number timestamp)\n * @returns Date object\n * @throws {InvalidDateError} If the input cannot be parsed to a valid date\n */\nfunction normalizeDate(date: Date | string | number): Date {\n let result: Date;\n\n if (date instanceof Date) {\n result = date;\n } else if (typeof date === 'number') {\n result = new Date(date);\n } else if (typeof date === 'string') {\n result = new Date(date);\n } else {\n throw new InvalidDateError('Date must be a Date, string, or number');\n }\n\n if (Number.isNaN(result.getTime())) {\n throw new InvalidDateError(`Unable to parse date: ${String(date)}`);\n }\n\n return result;\n}\n\n/**\n * Format a date as relative time in Indonesian.\n *\n * Returns human-readable relative time like \"Baru saja\", \"X menit yang lalu\",\n * \"Kemarin\", or falls back to formatted date for older dates.\n *\n * @param date - Date to format (Date, string, or number timestamp in milliseconds)\n * @param baseDate - Reference date for comparison (default: current date)\n * @returns Relative time string in Indonesian\n * @throws {InvalidDateError} If either date is invalid\n *\n * @example\n * ```typescript\n * // Assuming today is 2026-01-02 12:00:00\n * toRelativeTime(new Date('2026-01-02 11:59:00')); // 'Baru saja'\n * toRelativeTime(new Date('2026-01-02 11:00:00')); // '1 jam yang lalu'\n * toRelativeTime(new Date('2026-01-01 12:00:00')); // 'Kemarin'\n * toRelativeTime(new Date('2025-12-30 12:00:00')); // '3 hari yang lalu'\n * toRelativeTime(new Date('2025-12-01 12:00:00')); // '1 Desember 2025'\n * ```\n */\nexport function toRelativeTime(\n date: Date | string | number,\n baseDate: Date = new Date()\n): string {\n const d = normalizeDate(date);\n const base = normalizeDate(baseDate);\n\n const diffMs = d.getTime() - base.getTime();\n const diffSec = Math.floor(diffMs / 1000);\n const diffMin = Math.floor(diffMs / (1000 * 60));\n const diffHour = Math.floor(diffMs / (1000 * 60 * 60));\n const diffDay = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n // Exact match\n if (diffMs === 0) {\n return 'Sekarang';\n }\n\n // Future dates\n if (diffMs > 0) {\n // < 1 minute\n if (diffSec < 60) {\n return 'Baru saja';\n }\n\n // < 60 minutes\n if (diffMin < 60) {\n return `${diffMin} menit lagi`;\n }\n\n // < 24 hours\n if (diffHour < 24) {\n return `${diffHour} jam lagi`;\n }\n\n // 1 day (24-48 hours)\n if (diffHour < 48) {\n return 'Besok';\n }\n\n // 2-30 days\n if (diffDay <= 30) {\n return `${diffDay} hari lagi`;\n }\n\n // > 30 days: fallback to formatted date\n return formatDate(d, 'long');\n }\n\n // Past dates\n const absDiffSec = Math.abs(diffSec);\n const absDiffMin = Math.abs(diffMin);\n const absDiffHour = Math.abs(diffHour);\n const absDiffDay = Math.abs(diffDay);\n\n // < 1 minute\n if (absDiffSec < 60) {\n return 'Baru saja';\n }\n\n // < 60 minutes\n if (absDiffMin < 60) {\n return `${absDiffMin} menit yang lalu`;\n }\n\n // < 24 hours\n if (absDiffHour < 24) {\n return `${absDiffHour} jam yang lalu`;\n }\n\n // 1 day (24-48 hours)\n if (absDiffHour < 48) {\n return 'Kemarin';\n }\n\n // 2-30 days\n if (absDiffDay <= 30) {\n return `${absDiffDay} hari yang lalu`;\n }\n\n // > 30 days: fallback to formatted date\n return formatDate(d, 'long');\n}\n","/**\n * Timezone utilities for Indonesian locale\n *\n * @module datetime/timezone\n * @packageDocumentation\n */\n\nimport { TIMEZONE_MAP } from './constants';\n\n/**\n * Map IANA timezone names or UTC offsets to Indonesian abbreviations (WIB/WITA/WIT).\n *\n * Supported mappings:\n * - UTC+7 / Asia/Jakarta / Asia/Pontianak → \"WIB\"\n * - UTC+8 / Asia/Makassar / Asia/Denpasar → \"WITA\"\n * - UTC+9 / Asia/Jayapura → \"WIT\"\n *\n * @param input - IANA timezone name (case-sensitive), offset in hours, or offset string\n * @returns Indonesian timezone abbreviation or null if not Indonesian\n *\n * @example\n * ```typescript\n * // IANA timezone names\n * getIndonesianTimezone('Asia/Jakarta'); // 'WIB'\n * getIndonesianTimezone('Asia/Makassar'); // 'WITA'\n * getIndonesianTimezone('Asia/Jayapura'); // 'WIT'\n *\n * // Offset as number (hours)\n * getIndonesianTimezone(7); // 'WIB'\n * getIndonesianTimezone(8); // 'WITA'\n * getIndonesianTimezone(9); // 'WIT'\n *\n * // Offset as string\n * getIndonesianTimezone('+07:00'); // 'WIB'\n * getIndonesianTimezone('+0700'); // 'WIB'\n * getIndonesianTimezone('+08:00'); // 'WITA'\n *\n * // Non-Indonesian returns null\n * getIndonesianTimezone('America/New_York'); // null\n * getIndonesianTimezone(-5); // null\n * ```\n */\nexport function getIndonesianTimezone(\n input: string | number\n): 'WIB' | 'WITA' | 'WIT' | null {\n // Handle number input (offset in hours)\n if (typeof input === 'number') {\n if (!Number.isFinite(input) || !Number.isInteger(input)) {\n return null;\n }\n\n switch (input) {\n case 7:\n return 'WIB';\n case 8:\n return 'WITA';\n case 9:\n return 'WIT';\n default:\n return null;\n }\n }\n\n // Handle string input\n if (typeof input !== 'string') {\n return null;\n }\n\n const trimmed = input.trim();\n\n // Check if it's an offset string (+07:00, +0700, -05:00, etc.)\n const offsetMatch = trimmed.match(/^([+-])(\\d{2}):?(\\d{2})$/);\n if (offsetMatch) {\n const sign = offsetMatch[1];\n const hours = parseInt(offsetMatch[2], 10);\n const minutes = parseInt(offsetMatch[3], 10);\n\n // Indonesian timezones are all positive (UTC+)\n if (sign === '-') {\n return null;\n }\n\n // Validate format (must be exactly on the hour, no minutes)\n if (minutes !== 0) {\n return null;\n }\n\n // Map to Indonesian timezone\n switch (hours) {\n case 7:\n return 'WIB';\n case 8:\n return 'WITA';\n case 9:\n return 'WIT';\n default:\n return null;\n }\n }\n\n // Check if it's an IANA timezone name\n if (TIMEZONE_MAP[trimmed]) {\n return TIMEZONE_MAP[trimmed];\n }\n\n // Unknown timezone\n return null;\n}\n"]}
|