@indodev/toolkit 0.2.0 → 0.3.1

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.
Files changed (58) hide show
  1. package/dist/{compare-B1MKSOWV.d.cts → compare-CZadJMGl.d.cts} +54 -1
  2. package/dist/{compare-B1MKSOWV.d.ts → compare-CZadJMGl.d.ts} +54 -1
  3. package/dist/currency/index.cjs +23 -0
  4. package/dist/currency/index.cjs.map +1 -1
  5. package/dist/currency/index.d.cts +367 -3
  6. package/dist/currency/index.d.ts +367 -3
  7. package/dist/currency/index.js +21 -1
  8. package/dist/currency/index.js.map +1 -1
  9. package/dist/index.cjs +1188 -0
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +7 -4
  12. package/dist/index.d.ts +7 -4
  13. package/dist/index.js +1165 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/nik/index.cjs +44 -0
  16. package/dist/nik/index.cjs.map +1 -1
  17. package/dist/nik/index.d.cts +44 -1
  18. package/dist/nik/index.d.ts +44 -1
  19. package/dist/nik/index.js +41 -1
  20. package/dist/nik/index.js.map +1 -1
  21. package/dist/npwp/index.cjs +95 -0
  22. package/dist/npwp/index.cjs.map +1 -0
  23. package/dist/npwp/index.d.cts +76 -0
  24. package/dist/npwp/index.d.ts +76 -0
  25. package/dist/npwp/index.js +90 -0
  26. package/dist/npwp/index.js.map +1 -0
  27. package/dist/phone/index.cjs +42 -0
  28. package/dist/phone/index.cjs.map +1 -1
  29. package/dist/phone/index.d.cts +57 -1
  30. package/dist/phone/index.d.ts +57 -1
  31. package/dist/phone/index.js +39 -1
  32. package/dist/phone/index.js.map +1 -1
  33. package/dist/plate/index.cjs +99 -0
  34. package/dist/plate/index.cjs.map +1 -0
  35. package/dist/plate/index.d.cts +8 -0
  36. package/dist/plate/index.d.ts +8 -0
  37. package/dist/plate/index.js +94 -0
  38. package/dist/plate/index.js.map +1 -0
  39. package/dist/text/index.cjs +811 -0
  40. package/dist/text/index.cjs.map +1 -1
  41. package/dist/text/index.d.cts +1 -1
  42. package/dist/text/index.d.ts +1 -1
  43. package/dist/text/index.js +808 -1
  44. package/dist/text/index.js.map +1 -1
  45. package/dist/types-i5e6R0AS.d.cts +39 -0
  46. package/dist/types-i5e6R0AS.d.ts +39 -0
  47. package/dist/utils-DDVlOusI.d.cts +30 -0
  48. package/dist/utils-DDVlOusI.d.ts +30 -0
  49. package/dist/vin/index.cjs +84 -0
  50. package/dist/vin/index.cjs.map +1 -0
  51. package/dist/vin/index.d.cts +39 -0
  52. package/dist/vin/index.d.ts +39 -0
  53. package/dist/vin/index.js +74 -0
  54. package/dist/vin/index.js.map +1 -0
  55. package/package.json +48 -18
  56. package/LICENCE +0 -21
  57. package/dist/words-Dy8iYkbv.d.cts +0 -333
  58. package/dist/words-Dy8iYkbv.d.ts +0 -333
@@ -697,6 +697,59 @@ declare function contractAbbreviation(text: string, options?: {
697
697
  mode?: 'all' | 'address' | 'title' | 'org';
698
698
  }): string;
699
699
 
700
+ /**
701
+ * Filters common Indonesian profanity words by masking them.
702
+ *
703
+ * @param text - The text to filter
704
+ * @param mask - The masking character (default: '*')
705
+ * @returns Filtered text
706
+ *
707
+ * @example
708
+ * ```typescript
709
+ * profanityFilter('kamu anjing banget'); // 'kamu ****** banget'
710
+ * ```
711
+ */
712
+ declare function profanityFilter(text: string, mask?: string): string;
713
+ /**
714
+ * Removes common Indonesian stopwords from text.
715
+ *
716
+ * @param text - The text to process
717
+ * @returns Text with stopwords removed
718
+ *
719
+ * @example
720
+ * ```typescript
721
+ * removeStopwords('saya sedang makan nasi'); // 'makan nasi'
722
+ * ```
723
+ */
724
+ declare function removeStopwords(text: string): string;
725
+
726
+ /**
727
+ * Normalizes informal Indonesian text to a more formal version.
728
+ * This is a basic rule-based implementation.
729
+ *
730
+ * @param text - The text to normalize
731
+ * @returns Formalized text
732
+ *
733
+ * @example
734
+ * ```typescript
735
+ * toFormal('gw lagi makan'); // 'saya sedang makan'
736
+ * ```
737
+ */
738
+ declare function toFormal(text: string): string;
739
+ /**
740
+ * Detects if a text follows "alay" style (unconventional capitalization or number substitution).
741
+ *
742
+ * @param text - The text to check
743
+ * @returns `true` if alay style detected, `false` otherwise
744
+ *
745
+ * @example
746
+ * ```typescript
747
+ * isAlay('AqU sAyAnG qMu'); // true
748
+ * isAlay('Makan 4y4m'); // true
749
+ * ```
750
+ */
751
+ declare function isAlay(text: string): boolean;
752
+
700
753
  /**
701
754
  * Truncate text to specified length, word-aware
702
755
  *
@@ -935,4 +988,4 @@ declare function compareStrings(str1: string, str2: string, options?: CompareOpt
935
988
  */
936
989
  declare function similarity(str1: string, str2: string): number;
937
990
 
938
- export { type CompareOptions as C, type ExtractOptions as E, type SlugifyOptions as S, type TitleCaseOptions as T, toSentenceCase as a, sanitize as b, capitalize as c, contractAbbreviation as d, expandAbbreviation as e, truncate as f, extractWords as g, compareStrings as h, similarity as i, type SanitizeOptions as j, type TruncateOptions as k, normalizeWhitespace as n, removeAccents as r, slugify as s, toTitleCase as t };
991
+ export { type CompareOptions as C, type ExtractOptions as E, type SlugifyOptions as S, type TitleCaseOptions as T, toSentenceCase as a, sanitize as b, capitalize as c, contractAbbreviation as d, expandAbbreviation as e, truncate as f, extractWords as g, removeStopwords as h, toFormal as i, isAlay as j, compareStrings as k, similarity as l, type SanitizeOptions as m, normalizeWhitespace as n, type TruncateOptions as o, profanityFilter as p, removeAccents as r, slugify as s, toTitleCase as t };
@@ -697,6 +697,59 @@ declare function contractAbbreviation(text: string, options?: {
697
697
  mode?: 'all' | 'address' | 'title' | 'org';
698
698
  }): string;
699
699
 
700
+ /**
701
+ * Filters common Indonesian profanity words by masking them.
702
+ *
703
+ * @param text - The text to filter
704
+ * @param mask - The masking character (default: '*')
705
+ * @returns Filtered text
706
+ *
707
+ * @example
708
+ * ```typescript
709
+ * profanityFilter('kamu anjing banget'); // 'kamu ****** banget'
710
+ * ```
711
+ */
712
+ declare function profanityFilter(text: string, mask?: string): string;
713
+ /**
714
+ * Removes common Indonesian stopwords from text.
715
+ *
716
+ * @param text - The text to process
717
+ * @returns Text with stopwords removed
718
+ *
719
+ * @example
720
+ * ```typescript
721
+ * removeStopwords('saya sedang makan nasi'); // 'makan nasi'
722
+ * ```
723
+ */
724
+ declare function removeStopwords(text: string): string;
725
+
726
+ /**
727
+ * Normalizes informal Indonesian text to a more formal version.
728
+ * This is a basic rule-based implementation.
729
+ *
730
+ * @param text - The text to normalize
731
+ * @returns Formalized text
732
+ *
733
+ * @example
734
+ * ```typescript
735
+ * toFormal('gw lagi makan'); // 'saya sedang makan'
736
+ * ```
737
+ */
738
+ declare function toFormal(text: string): string;
739
+ /**
740
+ * Detects if a text follows "alay" style (unconventional capitalization or number substitution).
741
+ *
742
+ * @param text - The text to check
743
+ * @returns `true` if alay style detected, `false` otherwise
744
+ *
745
+ * @example
746
+ * ```typescript
747
+ * isAlay('AqU sAyAnG qMu'); // true
748
+ * isAlay('Makan 4y4m'); // true
749
+ * ```
750
+ */
751
+ declare function isAlay(text: string): boolean;
752
+
700
753
  /**
701
754
  * Truncate text to specified length, word-aware
702
755
  *
@@ -935,4 +988,4 @@ declare function compareStrings(str1: string, str2: string, options?: CompareOpt
935
988
  */
936
989
  declare function similarity(str1: string, str2: string): number;
937
990
 
938
- export { type CompareOptions as C, type ExtractOptions as E, type SlugifyOptions as S, type TitleCaseOptions as T, toSentenceCase as a, sanitize as b, capitalize as c, contractAbbreviation as d, expandAbbreviation as e, truncate as f, extractWords as g, compareStrings as h, similarity as i, type SanitizeOptions as j, type TruncateOptions as k, normalizeWhitespace as n, removeAccents as r, slugify as s, toTitleCase as t };
991
+ export { type CompareOptions as C, type ExtractOptions as E, type SlugifyOptions as S, type TitleCaseOptions as T, toSentenceCase as a, sanitize as b, capitalize as c, contractAbbreviation as d, expandAbbreviation as e, truncate as f, extractWords as g, removeStopwords as h, toFormal as i, isAlay as j, compareStrings as k, similarity as l, type SanitizeOptions as m, normalizeWhitespace as n, type TruncateOptions as o, profanityFilter as p, removeAccents as r, slugify as s, toTitleCase as t };
@@ -235,7 +235,30 @@ function roundToClean(amount, unit = "ribu") {
235
235
  const divisor = divisors[unit];
236
236
  return Math.round(amount / divisor) * divisor;
237
237
  }
238
+ function formatAccounting(amount, options) {
239
+ const isNegative = amount < 0;
240
+ const formatted = formatRupiah(Math.abs(amount), options);
241
+ if (isNegative) {
242
+ return `(${formatted})`;
243
+ }
244
+ return formatted;
245
+ }
246
+ function calculateTax(amount, rate = 0.11) {
247
+ return amount * rate;
248
+ }
249
+ function addRupiahSymbol(amount) {
250
+ if (typeof amount === "number") {
251
+ return `Rp ${amount.toLocaleString("id-ID")}`;
252
+ }
253
+ if (amount.trim().startsWith("Rp")) {
254
+ return amount;
255
+ }
256
+ return `Rp ${amount.trim()}`;
257
+ }
238
258
 
259
+ exports.addRupiahSymbol = addRupiahSymbol;
260
+ exports.calculateTax = calculateTax;
261
+ exports.formatAccounting = formatAccounting;
239
262
  exports.formatCompact = formatCompact;
240
263
  exports.formatRupiah = formatRupiah;
241
264
  exports.parseRupiah = parseRupiah;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/currency/format.ts","../../src/currency/parse.ts","../../src/currency/words.ts","../../src/currency/utils.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Currency formatting utilities for Indonesian Rupiah.\n *\n * @module currency/format\n * @packageDocumentation\n */\n\nimport type { 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;\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 // Precision 0: no decimal separator needed\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 (isNegative) {\n result = `-${result}`;\n }\n\n if (symbol) {\n const space = spaceAfterSymbol ? ' ' : '';\n result = `Rp${space}${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 * @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 * @public\n */\nexport function formatCompact(amount: number): string {\n const isNegative = 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 // Below 100k: use standard formatting instead of \"ribu\"\n result = abs.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.');\n } else {\n result = abs.toString();\n }\n\n if (isNegative) {\n result = `-${result}`;\n }\n\n return `Rp ${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 { uppercase = false, withCurrency = true } = 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.floor(Math.abs(amount));\n\n let words = '';\n\n // Break into groups: triliun, miliar, juta, ribu, sisa\n const triliun = Math.floor(absAmount / 1_000_000_000_000);\n const miliar = Math.floor((absAmount % 1_000_000_000_000) / 1_000_000_000);\n const juta = Math.floor((absAmount % 1_000_000_000) / 1_000_000);\n const ribu = Math.floor((absAmount % 1_000_000) / 1_000);\n const sisa = absAmount % 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 // Special rule: 1000 = \"seribu\" not \"satu ribu\"\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 if (isNegative) {\n words = 'minus ' + words;\n }\n\n if (withCurrency) {\n words += ' rupiah';\n }\n\n return uppercase ? capitalize(words) : words;\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 type { RoundUnit } 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"]}
1
+ {"version":3,"sources":["../../src/currency/format.ts","../../src/currency/parse.ts","../../src/currency/words.ts","../../src/currency/utils.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Currency formatting utilities for Indonesian Rupiah.\n *\n * @module currency/format\n * @packageDocumentation\n */\n\nimport type { 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;\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 // Precision 0: no decimal separator needed\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 (isNegative) {\n result = `-${result}`;\n }\n\n if (symbol) {\n const space = spaceAfterSymbol ? ' ' : '';\n result = `Rp${space}${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 * @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 * @public\n */\nexport function formatCompact(amount: number): string {\n const isNegative = 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 // Below 100k: use standard formatting instead of \"ribu\"\n result = abs.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.');\n } else {\n result = abs.toString();\n }\n\n if (isNegative) {\n result = `-${result}`;\n }\n\n return `Rp ${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 { uppercase = false, withCurrency = true } = 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.floor(Math.abs(amount));\n\n let words = '';\n\n // Break into groups: triliun, miliar, juta, ribu, sisa\n const triliun = Math.floor(absAmount / 1_000_000_000_000);\n const miliar = Math.floor((absAmount % 1_000_000_000_000) / 1_000_000_000);\n const juta = Math.floor((absAmount % 1_000_000_000) / 1_000_000);\n const ribu = Math.floor((absAmount % 1_000_000) / 1_000);\n const sisa = absAmount % 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 // Special rule: 1000 = \"seribu\" not \"satu ribu\"\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 if (isNegative) {\n words = 'minus ' + words;\n }\n\n if (withCurrency) {\n words += ' rupiah';\n }\n\n return uppercase ? capitalize(words) : words;\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 (default: 0.11 for 11%)\n * @returns The calculated tax amount\n *\n * @example\n * ```typescript\n * calculateTax(1000000); // 110000\n * ```\n */\nexport function calculateTax(amount: number, rate: number = 0.11): 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 return `Rp ${amount.toLocaleString('id-ID')}`;\n }\n\n if (amount.trim().startsWith('Rp')) {\n return amount;\n }\n\n return `Rp ${amount.trim()}`;\n}\n"]}
@@ -1,5 +1,334 @@
1
- import { b as RoundUnit } from '../words-Dy8iYkbv.cjs';
2
- export { R as RupiahOptions, W as WordOptions, a as formatCompact, f as formatRupiah, p as parseRupiah, t as toWords } from '../words-Dy8iYkbv.cjs';
1
+ /**
2
+ * Currency module types for Indonesian Rupiah utilities.
3
+ *
4
+ * @module currency/types
5
+ * @packageDocumentation
6
+ */
7
+ /**
8
+ * Options for formatting Rupiah currency.
9
+ *
10
+ * @example
11
+ * Default formatting:
12
+ * ```typescript
13
+ * const options: RupiahOptions = {
14
+ * symbol: true,
15
+ * decimal: false,
16
+ * separator: '.',
17
+ * };
18
+ * formatRupiah(1500000, options); // 'Rp 1.500.000'
19
+ * ```
20
+ *
21
+ * @example
22
+ * With decimals:
23
+ * ```typescript
24
+ * const options: RupiahOptions = {
25
+ * symbol: true,
26
+ * decimal: true,
27
+ * precision: 2,
28
+ * };
29
+ * formatRupiah(1500000.50, options); // 'Rp 1.500.000,50'
30
+ * ```
31
+ *
32
+ * @public
33
+ */
34
+ interface RupiahOptions {
35
+ /**
36
+ * Whether to show 'Rp' symbol.
37
+ *
38
+ * @defaultValue true
39
+ */
40
+ symbol?: boolean;
41
+ /**
42
+ * Whether to show decimal places.
43
+ *
44
+ * @defaultValue false
45
+ */
46
+ decimal?: boolean;
47
+ /**
48
+ * Thousands separator character.
49
+ *
50
+ * @defaultValue '.'
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * '.' // Indonesian standard
55
+ * ',' // International standard
56
+ * ' ' // Space separator
57
+ * ```
58
+ */
59
+ separator?: string;
60
+ /**
61
+ * Decimal separator character.
62
+ *
63
+ * @defaultValue ','
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * ',' // Indonesian standard
68
+ * '.' // International standard
69
+ * ```
70
+ */
71
+ decimalSeparator?: string;
72
+ /**
73
+ * Number of decimal places to show.
74
+ *
75
+ * @defaultValue 0
76
+ */
77
+ precision?: number;
78
+ /**
79
+ * Whether to add space after 'Rp' symbol.
80
+ *
81
+ * @defaultValue true
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * true // 'Rp 1.500.000'
86
+ * false // 'Rp1.500.000'
87
+ * ```
88
+ */
89
+ spaceAfterSymbol?: boolean;
90
+ }
91
+ /**
92
+ * Options for converting numbers to Indonesian words (terbilang).
93
+ *
94
+ * @example
95
+ * Default:
96
+ * ```typescript
97
+ * toWords(1500000); // 'satu juta lima ratus ribu rupiah'
98
+ * ```
99
+ *
100
+ * @example
101
+ * Uppercase:
102
+ * ```typescript
103
+ * toWords(1500000, { uppercase: true });
104
+ * // 'Satu juta lima ratus ribu rupiah'
105
+ * ```
106
+ *
107
+ * @example
108
+ * Without currency suffix:
109
+ * ```typescript
110
+ * toWords(1500000, { withCurrency: false });
111
+ * // 'satu juta lima ratus ribu'
112
+ * ```
113
+ *
114
+ * @public
115
+ */
116
+ interface WordOptions {
117
+ /**
118
+ * Whether to capitalize the first letter.
119
+ *
120
+ * @defaultValue false
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * false // 'satu juta'
125
+ * true // 'Satu juta'
126
+ * ```
127
+ */
128
+ uppercase?: boolean;
129
+ /**
130
+ * Whether to add 'rupiah' at the end.
131
+ *
132
+ * @defaultValue true
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * true // 'satu juta rupiah'
137
+ * false // 'satu juta'
138
+ * ```
139
+ */
140
+ withCurrency?: boolean;
141
+ }
142
+ /**
143
+ * Unit for rounding currency amounts.
144
+ *
145
+ * Common Indonesian currency rounding units:
146
+ * - `'ribu'`: Round to thousands (1.000)
147
+ * - `'ratus-ribu'`: Round to hundred thousands (100.000)
148
+ * - `'juta'`: Round to millions (1.000.000)
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * roundToClean(1234567, 'ribu'); // 1235000
153
+ * roundToClean(1234567, 'ratus-ribu'); // 1200000
154
+ * roundToClean(1234567, 'juta'); // 1000000
155
+ * ```
156
+ *
157
+ * @public
158
+ */
159
+ type RoundUnit = 'ribu' | 'ratus-ribu' | 'juta';
160
+
161
+ /**
162
+ * Currency formatting utilities for Indonesian Rupiah.
163
+ *
164
+ * @module currency/format
165
+ * @packageDocumentation
166
+ */
167
+
168
+ /**
169
+ * Formats a number as Indonesian Rupiah currency.
170
+ *
171
+ * Provides flexible formatting options including symbol display,
172
+ * decimal places, and custom separators.
173
+ *
174
+ * @param amount - The amount to format
175
+ * @param options - Formatting options
176
+ * @returns Formatted Rupiah string
177
+ *
178
+ * @example
179
+ * Basic formatting:
180
+ * ```typescript
181
+ * formatRupiah(1500000); // 'Rp 1.500.000'
182
+ * ```
183
+ *
184
+ * @example
185
+ * With decimals:
186
+ * ```typescript
187
+ * formatRupiah(1500000.50, { decimal: true }); // 'Rp 1.500.000,50'
188
+ * ```
189
+ *
190
+ * @example
191
+ * Without symbol:
192
+ * ```typescript
193
+ * formatRupiah(1500000, { symbol: false }); // '1.500.000'
194
+ * ```
195
+ *
196
+ * @example
197
+ * Custom separators:
198
+ * ```typescript
199
+ * formatRupiah(1500000, { separator: ',' }); // 'Rp 1,500,000'
200
+ * ```
201
+ *
202
+ * @public
203
+ */
204
+ declare function formatRupiah(amount: number, options?: RupiahOptions): string;
205
+ /**
206
+ * Formats a number in compact Indonesian format.
207
+ *
208
+ * Uses Indonesian units: ribu, juta, miliar, triliun.
209
+ * Follows Indonesian grammar rules (e.g., "1 juta" not "1,0 juta").
210
+ *
211
+ * @param amount - The amount to format
212
+ * @returns Compact formatted string
213
+ *
214
+ * @example
215
+ * Millions:
216
+ * ```typescript
217
+ * formatCompact(1500000); // 'Rp 1,5 juta'
218
+ * formatCompact(1000000); // 'Rp 1 juta'
219
+ * ```
220
+ *
221
+ * @example
222
+ * Thousands:
223
+ * ```typescript
224
+ * formatCompact(500000); // 'Rp 500 ribu'
225
+ * ```
226
+ *
227
+ * @example
228
+ * Small numbers:
229
+ * ```typescript
230
+ * formatCompact(1500); // 'Rp 1.500'
231
+ * ```
232
+ *
233
+ * @public
234
+ */
235
+ declare function formatCompact(amount: number): string;
236
+
237
+ /**
238
+ * Currency parsing utilities for Indonesian Rupiah.
239
+ *
240
+ * @module currency/parse
241
+ * @packageDocumentation
242
+ */
243
+ /**
244
+ * Parses a formatted Rupiah string back to a number.
245
+ *
246
+ * Handles multiple formats:
247
+ * - Standard: "Rp 1.500.000"
248
+ * - No symbol: "1.500.000"
249
+ * - With decimals: "Rp 1.500.000,50"
250
+ * - Compact: "Rp 1,5 juta", "Rp 500 ribu"
251
+ *
252
+ * @param formatted - The formatted Rupiah string to parse
253
+ * @returns Parsed number, or null if invalid
254
+ *
255
+ * @example
256
+ * Standard format:
257
+ * ```typescript
258
+ * parseRupiah('Rp 1.500.000'); // 1500000
259
+ * ```
260
+ *
261
+ * @example
262
+ * With decimals:
263
+ * ```typescript
264
+ * parseRupiah('Rp 1.500.000,50'); // 1500000.50
265
+ * ```
266
+ *
267
+ * @example
268
+ * Compact format:
269
+ * ```typescript
270
+ * parseRupiah('Rp 1,5 juta'); // 1500000
271
+ * parseRupiah('Rp 500 ribu'); // 500000
272
+ * ```
273
+ *
274
+ * @example
275
+ * Invalid input:
276
+ * ```typescript
277
+ * parseRupiah('invalid'); // null
278
+ * ```
279
+ *
280
+ * @public
281
+ */
282
+ declare function parseRupiah(formatted: string): number | null;
283
+
284
+ /**
285
+ * Convert numbers to Indonesian words (terbilang).
286
+ *
287
+ * @module currency/words
288
+ * @packageDocumentation
289
+ */
290
+
291
+ /**
292
+ * Converts a number to Indonesian words (terbilang).
293
+ *
294
+ * Supports numbers up to trillions (triliun).
295
+ * Follows Indonesian language rules for number pronunciation.
296
+ *
297
+ * Special rules:
298
+ * - 1 = "satu" in most cases, but "se-" for 100, 1000
299
+ * - 11 = "sebelas" (not "satu belas")
300
+ * - 100 = "seratus" (not "satu ratus")
301
+ * - 1000 = "seribu" (not "satu ribu")
302
+ *
303
+ * @param amount - The number to convert
304
+ * @param options - Conversion options
305
+ * @returns Indonesian words representation
306
+ *
307
+ * @example
308
+ * Basic numbers:
309
+ * ```typescript
310
+ * toWords(123); // 'seratus dua puluh tiga rupiah'
311
+ * ```
312
+ *
313
+ * @example
314
+ * Large numbers:
315
+ * ```typescript
316
+ * toWords(1500000); // 'satu juta lima ratus ribu rupiah'
317
+ * ```
318
+ *
319
+ * @example
320
+ * With options:
321
+ * ```typescript
322
+ * toWords(1500000, { uppercase: true });
323
+ * // 'Satu juta lima ratus ribu rupiah'
324
+ *
325
+ * toWords(1500000, { withCurrency: false });
326
+ * // 'satu juta lima ratus ribu'
327
+ * ```
328
+ *
329
+ * @public
330
+ */
331
+ declare function toWords(amount: number, options?: WordOptions): string;
3
332
 
4
333
  /**
5
334
  * Currency utility functions.
@@ -39,5 +368,40 @@ export { R as RupiahOptions, W as WordOptions, a as formatCompact, f as formatRu
39
368
  * @public
40
369
  */
41
370
  declare function roundToClean(amount: number, unit?: RoundUnit): number;
371
+ /**
372
+ * Formats a number as Indonesian Rupiah in accounting style.
373
+ * Negative numbers are wrapped in parentheses.
374
+ *
375
+ * @param amount - The amount to format
376
+ * @param options - Formatting options
377
+ * @returns Formatted accounting string
378
+ *
379
+ * @example
380
+ * ```typescript
381
+ * formatAccounting(-1500000); // '(Rp 1.500.000)'
382
+ * ```
383
+ */
384
+ declare function formatAccounting(amount: number, options?: RupiahOptions): string;
385
+ /**
386
+ * Calculates tax (PPN) for a given amount.
387
+ *
388
+ * @param amount - The base amount
389
+ * @param rate - The tax rate (default: 0.11 for 11%)
390
+ * @returns The calculated tax amount
391
+ *
392
+ * @example
393
+ * ```typescript
394
+ * calculateTax(1000000); // 110000
395
+ * ```
396
+ */
397
+ declare function calculateTax(amount: number, rate?: number): number;
398
+ /**
399
+ * Helper to ensure a string or number has the 'Rp ' prefix.
400
+ * If already prefixed, it returns the input as is.
401
+ *
402
+ * @param amount - The amount or formatted string
403
+ * @returns String with Rupiah prefix
404
+ */
405
+ declare function addRupiahSymbol(amount: string | number): string;
42
406
 
43
- export { RoundUnit, roundToClean };
407
+ export { type RoundUnit, type RupiahOptions, type WordOptions, addRupiahSymbol, calculateTax, formatAccounting, formatCompact, formatRupiah, parseRupiah, roundToClean, toWords };