@lacspace/nepali-utils 1.0.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/LICENSE +21 -0
- package/README.md +74 -0
- package/dist/index.cjs +112 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +49 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lacspace
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# @lacspace/nepali-utils
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@lacspace/nepali-utils) [](https://github.com/lacspace/npm-packages/blob/main/LICENSE)
|
|
4
|
+
|
|
5
|
+
Everyday helpers for building Nepal-facing apps: NPR currency formatting with the South-Asian (lakh/crore) grouping, Devanagari numerals, amount-in-words for invoices, common validators, and province data. Zero dependencies, isomorphic, fully typed.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @lacspace/nepali-utils
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Currency & numbers
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { formatNPR, groupNepali, toDevanagari, fromDevanagari } from "@lacspace/nepali-utils";
|
|
17
|
+
|
|
18
|
+
formatNPR(1234567.5); // "Rs. 12,34,567.50"
|
|
19
|
+
formatNPR(1234567.5, { symbol: "रू " , devanagari: true }); // "रू १२,३४,५६७.५०"
|
|
20
|
+
formatNPR(50000, { decimals: 0, symbol: "" }); // "50,000"
|
|
21
|
+
|
|
22
|
+
groupNepali(1234567); // "12,34,567" (South-Asian grouping)
|
|
23
|
+
toDevanagari("2081"); // "२०८१"
|
|
24
|
+
fromDevanagari("२०८१"); // "2081"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Amount in words (for invoices)
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { numberToWords, amountInWords } from "@lacspace/nepali-utils";
|
|
31
|
+
|
|
32
|
+
numberToWords(1234567);
|
|
33
|
+
// "Twelve Lakh Thirty Four Thousand Five Hundred Sixty Seven"
|
|
34
|
+
|
|
35
|
+
amountInWords(1234567.75);
|
|
36
|
+
// "Rupees Twelve Lakh Thirty Four Thousand Five Hundred Sixty Seven and Seventy Five Paisa Only"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Validators
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { isValidNepaliMobile, isValidPAN } from "@lacspace/nepali-utils";
|
|
43
|
+
|
|
44
|
+
isValidNepaliMobile("9812345678"); // true
|
|
45
|
+
isValidNepaliMobile("+9779812345678"); // true
|
|
46
|
+
isValidNepaliMobile("1234567890"); // false
|
|
47
|
+
|
|
48
|
+
isValidPAN("123456789"); // true (9 digits)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Provinces
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { PROVINCES } from "@lacspace/nepali-utils";
|
|
55
|
+
|
|
56
|
+
PROVINCES[2];
|
|
57
|
+
// { number: 3, name: "Bagmati", nameNp: "बागमती", capital: "Hetauda" }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
| Function | Description |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| `formatNPR(amount, opts?)` | NPR currency string; opts: `symbol`, `decimals`, `devanagari` |
|
|
65
|
+
| `groupNepali(value)` | South-Asian digit grouping |
|
|
66
|
+
| `toDevanagari(x)` / `fromDevanagari(x)` | numeral conversion |
|
|
67
|
+
| `numberToWords(n)` | South-Asian words (Lakh/Crore/Arab) |
|
|
68
|
+
| `amountInWords(n)` | "Rupees … only" wrapper |
|
|
69
|
+
| `isValidNepaliMobile(s)` / `isValidPAN(s)` | validators |
|
|
70
|
+
| `PROVINCES` | the 7 federal provinces |
|
|
71
|
+
|
|
72
|
+
## License
|
|
73
|
+
|
|
74
|
+
MIT © [Lacspace](https://lacspace.com)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
var DEVANAGARI = ["\u0966", "\u0967", "\u0968", "\u0969", "\u096A", "\u096B", "\u096C", "\u096D", "\u096E", "\u096F"];
|
|
5
|
+
function toDevanagari(input) {
|
|
6
|
+
return String(input).replace(/[0-9]/g, (d) => DEVANAGARI[Number(d)]);
|
|
7
|
+
}
|
|
8
|
+
function fromDevanagari(input) {
|
|
9
|
+
return input.replace(/[०-९]/g, (d) => String(DEVANAGARI.indexOf(d)));
|
|
10
|
+
}
|
|
11
|
+
function groupNepali(value) {
|
|
12
|
+
const s = String(value).replace(/[^\d]/g, "");
|
|
13
|
+
if (s.length <= 3) return s;
|
|
14
|
+
const last3 = s.slice(-3);
|
|
15
|
+
const rest = s.slice(0, -3);
|
|
16
|
+
return rest.replace(/\B(?=(\d{2})+(?!\d))/g, ",") + "," + last3;
|
|
17
|
+
}
|
|
18
|
+
function formatNPR(amount, options = {}) {
|
|
19
|
+
const { symbol = "Rs. ", decimals = 2, devanagari = false } = options;
|
|
20
|
+
const negative = amount < 0;
|
|
21
|
+
const fixed = Math.abs(amount).toFixed(decimals);
|
|
22
|
+
const [intPart, decPart] = fixed.split(".");
|
|
23
|
+
let out = groupNepali(intPart);
|
|
24
|
+
if (decPart) out += "." + decPart;
|
|
25
|
+
if (devanagari) out = toDevanagari(out);
|
|
26
|
+
return (negative ? "-" : "") + symbol + out;
|
|
27
|
+
}
|
|
28
|
+
var ONES = [
|
|
29
|
+
"",
|
|
30
|
+
"One",
|
|
31
|
+
"Two",
|
|
32
|
+
"Three",
|
|
33
|
+
"Four",
|
|
34
|
+
"Five",
|
|
35
|
+
"Six",
|
|
36
|
+
"Seven",
|
|
37
|
+
"Eight",
|
|
38
|
+
"Nine",
|
|
39
|
+
"Ten",
|
|
40
|
+
"Eleven",
|
|
41
|
+
"Twelve",
|
|
42
|
+
"Thirteen",
|
|
43
|
+
"Fourteen",
|
|
44
|
+
"Fifteen",
|
|
45
|
+
"Sixteen",
|
|
46
|
+
"Seventeen",
|
|
47
|
+
"Eighteen",
|
|
48
|
+
"Nineteen"
|
|
49
|
+
];
|
|
50
|
+
var TENS = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"];
|
|
51
|
+
function twoDigitWords(n) {
|
|
52
|
+
if (n < 20) return ONES[n];
|
|
53
|
+
const t = Math.floor(n / 10);
|
|
54
|
+
const o = n % 10;
|
|
55
|
+
return TENS[t] + (o ? " " + ONES[o] : "");
|
|
56
|
+
}
|
|
57
|
+
function numberToWords(value) {
|
|
58
|
+
let n = Math.floor(Math.abs(value));
|
|
59
|
+
if (n === 0) return "Zero";
|
|
60
|
+
const parts = [];
|
|
61
|
+
const units = [
|
|
62
|
+
[1e9, "Arab"],
|
|
63
|
+
[1e7, "Crore"],
|
|
64
|
+
[1e5, "Lakh"],
|
|
65
|
+
[1e3, "Thousand"],
|
|
66
|
+
[100, "Hundred"]
|
|
67
|
+
];
|
|
68
|
+
for (const [size, name] of units) {
|
|
69
|
+
if (n >= size) {
|
|
70
|
+
const count = Math.floor(n / size);
|
|
71
|
+
parts.push((size === 100 ? ONES[count] : twoDigitWords(count)) + " " + name);
|
|
72
|
+
n %= size;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (n > 0) parts.push(twoDigitWords(n));
|
|
76
|
+
return (value < 0 ? "Minus " : "") + parts.join(" ");
|
|
77
|
+
}
|
|
78
|
+
function amountInWords(amount) {
|
|
79
|
+
const rupees = Math.floor(Math.abs(amount));
|
|
80
|
+
const paisa = Math.round((Math.abs(amount) - rupees) * 100);
|
|
81
|
+
let out = "Rupees " + numberToWords(rupees);
|
|
82
|
+
if (paisa > 0) out += " and " + numberToWords(paisa) + " Paisa";
|
|
83
|
+
return (amount < 0 ? "Minus " : "") + out + " Only";
|
|
84
|
+
}
|
|
85
|
+
function isValidNepaliMobile(input) {
|
|
86
|
+
const s = input.replace(/[\s-]/g, "");
|
|
87
|
+
return /^(\+?977)?9[678]\d{8}$/.test(s);
|
|
88
|
+
}
|
|
89
|
+
function isValidPAN(input) {
|
|
90
|
+
return /^\d{9}$/.test(input.trim());
|
|
91
|
+
}
|
|
92
|
+
var PROVINCES = [
|
|
93
|
+
{ number: 1, name: "Koshi", nameNp: "\u0915\u094B\u0936\u0940", capital: "Biratnagar" },
|
|
94
|
+
{ number: 2, name: "Madhesh", nameNp: "\u092E\u0927\u0947\u0936", capital: "Janakpur" },
|
|
95
|
+
{ number: 3, name: "Bagmati", nameNp: "\u092C\u093E\u0917\u092E\u0924\u0940", capital: "Hetauda" },
|
|
96
|
+
{ number: 4, name: "Gandaki", nameNp: "\u0917\u0923\u094D\u0921\u0915\u0940", capital: "Pokhara" },
|
|
97
|
+
{ number: 5, name: "Lumbini", nameNp: "\u0932\u0941\u092E\u094D\u092C\u093F\u0928\u0940", capital: "Deukhuri" },
|
|
98
|
+
{ number: 6, name: "Karnali", nameNp: "\u0915\u0930\u094D\u0923\u093E\u0932\u0940", capital: "Birendranagar" },
|
|
99
|
+
{ number: 7, name: "Sudurpashchim", nameNp: "\u0938\u0941\u0926\u0942\u0930\u092A\u0936\u094D\u091A\u093F\u092E", capital: "Godawari" }
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
exports.PROVINCES = PROVINCES;
|
|
103
|
+
exports.amountInWords = amountInWords;
|
|
104
|
+
exports.formatNPR = formatNPR;
|
|
105
|
+
exports.fromDevanagari = fromDevanagari;
|
|
106
|
+
exports.groupNepali = groupNepali;
|
|
107
|
+
exports.isValidNepaliMobile = isValidNepaliMobile;
|
|
108
|
+
exports.isValidPAN = isValidPAN;
|
|
109
|
+
exports.numberToWords = numberToWords;
|
|
110
|
+
exports.toDevanagari = toDevanagari;
|
|
111
|
+
//# sourceMappingURL=index.cjs.map
|
|
112
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @lacspace/nepali-utils — everyday Nepal helpers: NPR currency formatting,\n * Nepali (South-Asian) digit grouping, Devanagari numerals, amount-in-words,\n * common validators, and province data. Zero-dependency, isomorphic.\n */\n\nconst DEVANAGARI = [\"०\", \"१\", \"२\", \"३\", \"४\", \"५\", \"६\", \"७\", \"८\", \"९\"] as const;\n\n/** Convert Arabic numerals to Devanagari: `\"2081\"` → `\"२०८१\"`. */\nexport function toDevanagari(input: string | number): string {\n return String(input).replace(/[0-9]/g, (d) => DEVANAGARI[Number(d)]!);\n}\n\n/** Convert Devanagari numerals to Arabic: `\"२०८१\"` → `\"2081\"`. */\nexport function fromDevanagari(input: string): string {\n return input.replace(/[०-९]/g, (d) => String(DEVANAGARI.indexOf(d as (typeof DEVANAGARI)[number])));\n}\n\n/**\n * Group an integer with the South-Asian (Nepali) system: the last three digits,\n * then groups of two. `1234567` → `\"12,34,567\"`.\n */\nexport function groupNepali(value: number | string): string {\n const s = String(value).replace(/[^\\d]/g, \"\");\n if (s.length <= 3) return s;\n const last3 = s.slice(-3);\n const rest = s.slice(0, -3);\n return rest.replace(/\\B(?=(\\d{2})+(?!\\d))/g, \",\") + \",\" + last3;\n}\n\nexport interface FormatNprOptions {\n /** Show a symbol/prefix. Default `\"Rs. \"`. Use `\"\"` for none. */\n symbol?: string;\n /** Number of decimal places. Default `2`. */\n decimals?: number;\n /** Render digits in Devanagari. Default `false`. */\n devanagari?: boolean;\n}\n\n/**\n * Format an amount as Nepalese Rupees with South-Asian grouping.\n * `formatNPR(1234567.5)` → `\"Rs. 12,34,567.50\"`.\n */\nexport function formatNPR(amount: number, options: FormatNprOptions = {}): string {\n const { symbol = \"Rs. \", decimals = 2, devanagari = false } = options;\n const negative = amount < 0;\n const fixed = Math.abs(amount).toFixed(decimals);\n const [intPart, decPart] = fixed.split(\".\");\n let out = groupNepali(intPart!);\n if (decPart) out += \".\" + decPart;\n if (devanagari) out = toDevanagari(out);\n return (negative ? \"-\" : \"\") + symbol + out;\n}\n\nconst ONES = [\n \"\", \"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\",\n \"Ten\", \"Eleven\", \"Twelve\", \"Thirteen\", \"Fourteen\", \"Fifteen\", \"Sixteen\",\n \"Seventeen\", \"Eighteen\", \"Nineteen\",\n];\nconst TENS = [\"\", \"\", \"Twenty\", \"Thirty\", \"Forty\", \"Fifty\", \"Sixty\", \"Seventy\", \"Eighty\", \"Ninety\"];\n\nfunction twoDigitWords(n: number): string {\n if (n < 20) return ONES[n]!;\n const t = Math.floor(n / 10);\n const o = n % 10;\n return TENS[t]! + (o ? \" \" + ONES[o] : \"\");\n}\n\n/**\n * Amount in words using the South-Asian system (Thousand, Lakh, Crore, Arab) —\n * perfect for invoices. `numberToWords(1234567)` →\n * `\"Twelve Lakh Thirty Four Thousand Five Hundred Sixty Seven\"`.\n */\nexport function numberToWords(value: number): string {\n let n = Math.floor(Math.abs(value));\n if (n === 0) return \"Zero\";\n const parts: string[] = [];\n const units: [number, string][] = [\n [1e9, \"Arab\"],\n [1e7, \"Crore\"],\n [1e5, \"Lakh\"],\n [1e3, \"Thousand\"],\n [1e2, \"Hundred\"],\n ];\n for (const [size, name] of units) {\n if (n >= size) {\n const count = Math.floor(n / size);\n // Hundreds are 1–9; the higher units take up to two digits.\n parts.push((size === 100 ? ONES[count] : twoDigitWords(count)) + \" \" + name);\n n %= size;\n }\n }\n if (n > 0) parts.push(twoDigitWords(n));\n return (value < 0 ? \"Minus \" : \"\") + parts.join(\" \");\n}\n\n/** `numberToWords` plus a \"Rupees … only\" wrapper for invoices. */\nexport function amountInWords(amount: number): string {\n const rupees = Math.floor(Math.abs(amount));\n const paisa = Math.round((Math.abs(amount) - rupees) * 100);\n let out = \"Rupees \" + numberToWords(rupees);\n if (paisa > 0) out += \" and \" + numberToWords(paisa) + \" Paisa\";\n return (amount < 0 ? \"Minus \" : \"\") + out + \" Only\";\n}\n\n/** True for a valid Nepali mobile number (10 digits starting 96–98, optional +977). */\nexport function isValidNepaliMobile(input: string): boolean {\n const s = input.replace(/[\\s-]/g, \"\");\n return /^(\\+?977)?9[678]\\d{8}$/.test(s);\n}\n\n/** True for a valid Nepal PAN / VAT number (9 digits). */\nexport function isValidPAN(input: string): boolean {\n return /^\\d{9}$/.test(input.trim());\n}\n\nexport interface Province {\n number: number;\n name: string;\n nameNp: string;\n capital: string;\n}\n\n/** Nepal's seven federal provinces. */\nexport const PROVINCES: readonly Province[] = [\n { number: 1, name: \"Koshi\", nameNp: \"कोशी\", capital: \"Biratnagar\" },\n { number: 2, name: \"Madhesh\", nameNp: \"मधेश\", capital: \"Janakpur\" },\n { number: 3, name: \"Bagmati\", nameNp: \"बागमती\", capital: \"Hetauda\" },\n { number: 4, name: \"Gandaki\", nameNp: \"गण्डकी\", capital: \"Pokhara\" },\n { number: 5, name: \"Lumbini\", nameNp: \"लुम्बिनी\", capital: \"Deukhuri\" },\n { number: 6, name: \"Karnali\", nameNp: \"कर्णाली\", capital: \"Birendranagar\" },\n { number: 7, name: \"Sudurpashchim\", nameNp: \"सुदूरपश्चिम\", capital: \"Godawari\" },\n];\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @lacspace/nepali-utils — everyday Nepal helpers: NPR currency formatting,
|
|
3
|
+
* Nepali (South-Asian) digit grouping, Devanagari numerals, amount-in-words,
|
|
4
|
+
* common validators, and province data. Zero-dependency, isomorphic.
|
|
5
|
+
*/
|
|
6
|
+
/** Convert Arabic numerals to Devanagari: `"2081"` → `"२०८१"`. */
|
|
7
|
+
declare function toDevanagari(input: string | number): string;
|
|
8
|
+
/** Convert Devanagari numerals to Arabic: `"२०८१"` → `"2081"`. */
|
|
9
|
+
declare function fromDevanagari(input: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Group an integer with the South-Asian (Nepali) system: the last three digits,
|
|
12
|
+
* then groups of two. `1234567` → `"12,34,567"`.
|
|
13
|
+
*/
|
|
14
|
+
declare function groupNepali(value: number | string): string;
|
|
15
|
+
interface FormatNprOptions {
|
|
16
|
+
/** Show a symbol/prefix. Default `"Rs. "`. Use `""` for none. */
|
|
17
|
+
symbol?: string;
|
|
18
|
+
/** Number of decimal places. Default `2`. */
|
|
19
|
+
decimals?: number;
|
|
20
|
+
/** Render digits in Devanagari. Default `false`. */
|
|
21
|
+
devanagari?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Format an amount as Nepalese Rupees with South-Asian grouping.
|
|
25
|
+
* `formatNPR(1234567.5)` → `"Rs. 12,34,567.50"`.
|
|
26
|
+
*/
|
|
27
|
+
declare function formatNPR(amount: number, options?: FormatNprOptions): string;
|
|
28
|
+
/**
|
|
29
|
+
* Amount in words using the South-Asian system (Thousand, Lakh, Crore, Arab) —
|
|
30
|
+
* perfect for invoices. `numberToWords(1234567)` →
|
|
31
|
+
* `"Twelve Lakh Thirty Four Thousand Five Hundred Sixty Seven"`.
|
|
32
|
+
*/
|
|
33
|
+
declare function numberToWords(value: number): string;
|
|
34
|
+
/** `numberToWords` plus a "Rupees … only" wrapper for invoices. */
|
|
35
|
+
declare function amountInWords(amount: number): string;
|
|
36
|
+
/** True for a valid Nepali mobile number (10 digits starting 96–98, optional +977). */
|
|
37
|
+
declare function isValidNepaliMobile(input: string): boolean;
|
|
38
|
+
/** True for a valid Nepal PAN / VAT number (9 digits). */
|
|
39
|
+
declare function isValidPAN(input: string): boolean;
|
|
40
|
+
interface Province {
|
|
41
|
+
number: number;
|
|
42
|
+
name: string;
|
|
43
|
+
nameNp: string;
|
|
44
|
+
capital: string;
|
|
45
|
+
}
|
|
46
|
+
/** Nepal's seven federal provinces. */
|
|
47
|
+
declare const PROVINCES: readonly Province[];
|
|
48
|
+
|
|
49
|
+
export { type FormatNprOptions, PROVINCES, type Province, amountInWords, formatNPR, fromDevanagari, groupNepali, isValidNepaliMobile, isValidPAN, numberToWords, toDevanagari };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @lacspace/nepali-utils — everyday Nepal helpers: NPR currency formatting,
|
|
3
|
+
* Nepali (South-Asian) digit grouping, Devanagari numerals, amount-in-words,
|
|
4
|
+
* common validators, and province data. Zero-dependency, isomorphic.
|
|
5
|
+
*/
|
|
6
|
+
/** Convert Arabic numerals to Devanagari: `"2081"` → `"२०८१"`. */
|
|
7
|
+
declare function toDevanagari(input: string | number): string;
|
|
8
|
+
/** Convert Devanagari numerals to Arabic: `"२०८१"` → `"2081"`. */
|
|
9
|
+
declare function fromDevanagari(input: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Group an integer with the South-Asian (Nepali) system: the last three digits,
|
|
12
|
+
* then groups of two. `1234567` → `"12,34,567"`.
|
|
13
|
+
*/
|
|
14
|
+
declare function groupNepali(value: number | string): string;
|
|
15
|
+
interface FormatNprOptions {
|
|
16
|
+
/** Show a symbol/prefix. Default `"Rs. "`. Use `""` for none. */
|
|
17
|
+
symbol?: string;
|
|
18
|
+
/** Number of decimal places. Default `2`. */
|
|
19
|
+
decimals?: number;
|
|
20
|
+
/** Render digits in Devanagari. Default `false`. */
|
|
21
|
+
devanagari?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Format an amount as Nepalese Rupees with South-Asian grouping.
|
|
25
|
+
* `formatNPR(1234567.5)` → `"Rs. 12,34,567.50"`.
|
|
26
|
+
*/
|
|
27
|
+
declare function formatNPR(amount: number, options?: FormatNprOptions): string;
|
|
28
|
+
/**
|
|
29
|
+
* Amount in words using the South-Asian system (Thousand, Lakh, Crore, Arab) —
|
|
30
|
+
* perfect for invoices. `numberToWords(1234567)` →
|
|
31
|
+
* `"Twelve Lakh Thirty Four Thousand Five Hundred Sixty Seven"`.
|
|
32
|
+
*/
|
|
33
|
+
declare function numberToWords(value: number): string;
|
|
34
|
+
/** `numberToWords` plus a "Rupees … only" wrapper for invoices. */
|
|
35
|
+
declare function amountInWords(amount: number): string;
|
|
36
|
+
/** True for a valid Nepali mobile number (10 digits starting 96–98, optional +977). */
|
|
37
|
+
declare function isValidNepaliMobile(input: string): boolean;
|
|
38
|
+
/** True for a valid Nepal PAN / VAT number (9 digits). */
|
|
39
|
+
declare function isValidPAN(input: string): boolean;
|
|
40
|
+
interface Province {
|
|
41
|
+
number: number;
|
|
42
|
+
name: string;
|
|
43
|
+
nameNp: string;
|
|
44
|
+
capital: string;
|
|
45
|
+
}
|
|
46
|
+
/** Nepal's seven federal provinces. */
|
|
47
|
+
declare const PROVINCES: readonly Province[];
|
|
48
|
+
|
|
49
|
+
export { type FormatNprOptions, PROVINCES, type Province, amountInWords, formatNPR, fromDevanagari, groupNepali, isValidNepaliMobile, isValidPAN, numberToWords, toDevanagari };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var DEVANAGARI = ["\u0966", "\u0967", "\u0968", "\u0969", "\u096A", "\u096B", "\u096C", "\u096D", "\u096E", "\u096F"];
|
|
3
|
+
function toDevanagari(input) {
|
|
4
|
+
return String(input).replace(/[0-9]/g, (d) => DEVANAGARI[Number(d)]);
|
|
5
|
+
}
|
|
6
|
+
function fromDevanagari(input) {
|
|
7
|
+
return input.replace(/[०-९]/g, (d) => String(DEVANAGARI.indexOf(d)));
|
|
8
|
+
}
|
|
9
|
+
function groupNepali(value) {
|
|
10
|
+
const s = String(value).replace(/[^\d]/g, "");
|
|
11
|
+
if (s.length <= 3) return s;
|
|
12
|
+
const last3 = s.slice(-3);
|
|
13
|
+
const rest = s.slice(0, -3);
|
|
14
|
+
return rest.replace(/\B(?=(\d{2})+(?!\d))/g, ",") + "," + last3;
|
|
15
|
+
}
|
|
16
|
+
function formatNPR(amount, options = {}) {
|
|
17
|
+
const { symbol = "Rs. ", decimals = 2, devanagari = false } = options;
|
|
18
|
+
const negative = amount < 0;
|
|
19
|
+
const fixed = Math.abs(amount).toFixed(decimals);
|
|
20
|
+
const [intPart, decPart] = fixed.split(".");
|
|
21
|
+
let out = groupNepali(intPart);
|
|
22
|
+
if (decPart) out += "." + decPart;
|
|
23
|
+
if (devanagari) out = toDevanagari(out);
|
|
24
|
+
return (negative ? "-" : "") + symbol + out;
|
|
25
|
+
}
|
|
26
|
+
var ONES = [
|
|
27
|
+
"",
|
|
28
|
+
"One",
|
|
29
|
+
"Two",
|
|
30
|
+
"Three",
|
|
31
|
+
"Four",
|
|
32
|
+
"Five",
|
|
33
|
+
"Six",
|
|
34
|
+
"Seven",
|
|
35
|
+
"Eight",
|
|
36
|
+
"Nine",
|
|
37
|
+
"Ten",
|
|
38
|
+
"Eleven",
|
|
39
|
+
"Twelve",
|
|
40
|
+
"Thirteen",
|
|
41
|
+
"Fourteen",
|
|
42
|
+
"Fifteen",
|
|
43
|
+
"Sixteen",
|
|
44
|
+
"Seventeen",
|
|
45
|
+
"Eighteen",
|
|
46
|
+
"Nineteen"
|
|
47
|
+
];
|
|
48
|
+
var TENS = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"];
|
|
49
|
+
function twoDigitWords(n) {
|
|
50
|
+
if (n < 20) return ONES[n];
|
|
51
|
+
const t = Math.floor(n / 10);
|
|
52
|
+
const o = n % 10;
|
|
53
|
+
return TENS[t] + (o ? " " + ONES[o] : "");
|
|
54
|
+
}
|
|
55
|
+
function numberToWords(value) {
|
|
56
|
+
let n = Math.floor(Math.abs(value));
|
|
57
|
+
if (n === 0) return "Zero";
|
|
58
|
+
const parts = [];
|
|
59
|
+
const units = [
|
|
60
|
+
[1e9, "Arab"],
|
|
61
|
+
[1e7, "Crore"],
|
|
62
|
+
[1e5, "Lakh"],
|
|
63
|
+
[1e3, "Thousand"],
|
|
64
|
+
[100, "Hundred"]
|
|
65
|
+
];
|
|
66
|
+
for (const [size, name] of units) {
|
|
67
|
+
if (n >= size) {
|
|
68
|
+
const count = Math.floor(n / size);
|
|
69
|
+
parts.push((size === 100 ? ONES[count] : twoDigitWords(count)) + " " + name);
|
|
70
|
+
n %= size;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (n > 0) parts.push(twoDigitWords(n));
|
|
74
|
+
return (value < 0 ? "Minus " : "") + parts.join(" ");
|
|
75
|
+
}
|
|
76
|
+
function amountInWords(amount) {
|
|
77
|
+
const rupees = Math.floor(Math.abs(amount));
|
|
78
|
+
const paisa = Math.round((Math.abs(amount) - rupees) * 100);
|
|
79
|
+
let out = "Rupees " + numberToWords(rupees);
|
|
80
|
+
if (paisa > 0) out += " and " + numberToWords(paisa) + " Paisa";
|
|
81
|
+
return (amount < 0 ? "Minus " : "") + out + " Only";
|
|
82
|
+
}
|
|
83
|
+
function isValidNepaliMobile(input) {
|
|
84
|
+
const s = input.replace(/[\s-]/g, "");
|
|
85
|
+
return /^(\+?977)?9[678]\d{8}$/.test(s);
|
|
86
|
+
}
|
|
87
|
+
function isValidPAN(input) {
|
|
88
|
+
return /^\d{9}$/.test(input.trim());
|
|
89
|
+
}
|
|
90
|
+
var PROVINCES = [
|
|
91
|
+
{ number: 1, name: "Koshi", nameNp: "\u0915\u094B\u0936\u0940", capital: "Biratnagar" },
|
|
92
|
+
{ number: 2, name: "Madhesh", nameNp: "\u092E\u0927\u0947\u0936", capital: "Janakpur" },
|
|
93
|
+
{ number: 3, name: "Bagmati", nameNp: "\u092C\u093E\u0917\u092E\u0924\u0940", capital: "Hetauda" },
|
|
94
|
+
{ number: 4, name: "Gandaki", nameNp: "\u0917\u0923\u094D\u0921\u0915\u0940", capital: "Pokhara" },
|
|
95
|
+
{ number: 5, name: "Lumbini", nameNp: "\u0932\u0941\u092E\u094D\u092C\u093F\u0928\u0940", capital: "Deukhuri" },
|
|
96
|
+
{ number: 6, name: "Karnali", nameNp: "\u0915\u0930\u094D\u0923\u093E\u0932\u0940", capital: "Birendranagar" },
|
|
97
|
+
{ number: 7, name: "Sudurpashchim", nameNp: "\u0938\u0941\u0926\u0942\u0930\u092A\u0936\u094D\u091A\u093F\u092E", capital: "Godawari" }
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
export { PROVINCES, amountInWords, formatNPR, fromDevanagari, groupNepali, isValidNepaliMobile, isValidPAN, numberToWords, toDevanagari };
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
102
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @lacspace/nepali-utils — everyday Nepal helpers: NPR currency formatting,\n * Nepali (South-Asian) digit grouping, Devanagari numerals, amount-in-words,\n * common validators, and province data. Zero-dependency, isomorphic.\n */\n\nconst DEVANAGARI = [\"०\", \"१\", \"२\", \"३\", \"४\", \"५\", \"६\", \"७\", \"८\", \"९\"] as const;\n\n/** Convert Arabic numerals to Devanagari: `\"2081\"` → `\"२०८१\"`. */\nexport function toDevanagari(input: string | number): string {\n return String(input).replace(/[0-9]/g, (d) => DEVANAGARI[Number(d)]!);\n}\n\n/** Convert Devanagari numerals to Arabic: `\"२०८१\"` → `\"2081\"`. */\nexport function fromDevanagari(input: string): string {\n return input.replace(/[०-९]/g, (d) => String(DEVANAGARI.indexOf(d as (typeof DEVANAGARI)[number])));\n}\n\n/**\n * Group an integer with the South-Asian (Nepali) system: the last three digits,\n * then groups of two. `1234567` → `\"12,34,567\"`.\n */\nexport function groupNepali(value: number | string): string {\n const s = String(value).replace(/[^\\d]/g, \"\");\n if (s.length <= 3) return s;\n const last3 = s.slice(-3);\n const rest = s.slice(0, -3);\n return rest.replace(/\\B(?=(\\d{2})+(?!\\d))/g, \",\") + \",\" + last3;\n}\n\nexport interface FormatNprOptions {\n /** Show a symbol/prefix. Default `\"Rs. \"`. Use `\"\"` for none. */\n symbol?: string;\n /** Number of decimal places. Default `2`. */\n decimals?: number;\n /** Render digits in Devanagari. Default `false`. */\n devanagari?: boolean;\n}\n\n/**\n * Format an amount as Nepalese Rupees with South-Asian grouping.\n * `formatNPR(1234567.5)` → `\"Rs. 12,34,567.50\"`.\n */\nexport function formatNPR(amount: number, options: FormatNprOptions = {}): string {\n const { symbol = \"Rs. \", decimals = 2, devanagari = false } = options;\n const negative = amount < 0;\n const fixed = Math.abs(amount).toFixed(decimals);\n const [intPart, decPart] = fixed.split(\".\");\n let out = groupNepali(intPart!);\n if (decPart) out += \".\" + decPart;\n if (devanagari) out = toDevanagari(out);\n return (negative ? \"-\" : \"\") + symbol + out;\n}\n\nconst ONES = [\n \"\", \"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\",\n \"Ten\", \"Eleven\", \"Twelve\", \"Thirteen\", \"Fourteen\", \"Fifteen\", \"Sixteen\",\n \"Seventeen\", \"Eighteen\", \"Nineteen\",\n];\nconst TENS = [\"\", \"\", \"Twenty\", \"Thirty\", \"Forty\", \"Fifty\", \"Sixty\", \"Seventy\", \"Eighty\", \"Ninety\"];\n\nfunction twoDigitWords(n: number): string {\n if (n < 20) return ONES[n]!;\n const t = Math.floor(n / 10);\n const o = n % 10;\n return TENS[t]! + (o ? \" \" + ONES[o] : \"\");\n}\n\n/**\n * Amount in words using the South-Asian system (Thousand, Lakh, Crore, Arab) —\n * perfect for invoices. `numberToWords(1234567)` →\n * `\"Twelve Lakh Thirty Four Thousand Five Hundred Sixty Seven\"`.\n */\nexport function numberToWords(value: number): string {\n let n = Math.floor(Math.abs(value));\n if (n === 0) return \"Zero\";\n const parts: string[] = [];\n const units: [number, string][] = [\n [1e9, \"Arab\"],\n [1e7, \"Crore\"],\n [1e5, \"Lakh\"],\n [1e3, \"Thousand\"],\n [1e2, \"Hundred\"],\n ];\n for (const [size, name] of units) {\n if (n >= size) {\n const count = Math.floor(n / size);\n // Hundreds are 1–9; the higher units take up to two digits.\n parts.push((size === 100 ? ONES[count] : twoDigitWords(count)) + \" \" + name);\n n %= size;\n }\n }\n if (n > 0) parts.push(twoDigitWords(n));\n return (value < 0 ? \"Minus \" : \"\") + parts.join(\" \");\n}\n\n/** `numberToWords` plus a \"Rupees … only\" wrapper for invoices. */\nexport function amountInWords(amount: number): string {\n const rupees = Math.floor(Math.abs(amount));\n const paisa = Math.round((Math.abs(amount) - rupees) * 100);\n let out = \"Rupees \" + numberToWords(rupees);\n if (paisa > 0) out += \" and \" + numberToWords(paisa) + \" Paisa\";\n return (amount < 0 ? \"Minus \" : \"\") + out + \" Only\";\n}\n\n/** True for a valid Nepali mobile number (10 digits starting 96–98, optional +977). */\nexport function isValidNepaliMobile(input: string): boolean {\n const s = input.replace(/[\\s-]/g, \"\");\n return /^(\\+?977)?9[678]\\d{8}$/.test(s);\n}\n\n/** True for a valid Nepal PAN / VAT number (9 digits). */\nexport function isValidPAN(input: string): boolean {\n return /^\\d{9}$/.test(input.trim());\n}\n\nexport interface Province {\n number: number;\n name: string;\n nameNp: string;\n capital: string;\n}\n\n/** Nepal's seven federal provinces. */\nexport const PROVINCES: readonly Province[] = [\n { number: 1, name: \"Koshi\", nameNp: \"कोशी\", capital: \"Biratnagar\" },\n { number: 2, name: \"Madhesh\", nameNp: \"मधेश\", capital: \"Janakpur\" },\n { number: 3, name: \"Bagmati\", nameNp: \"बागमती\", capital: \"Hetauda\" },\n { number: 4, name: \"Gandaki\", nameNp: \"गण्डकी\", capital: \"Pokhara\" },\n { number: 5, name: \"Lumbini\", nameNp: \"लुम्बिनी\", capital: \"Deukhuri\" },\n { number: 6, name: \"Karnali\", nameNp: \"कर्णाली\", capital: \"Birendranagar\" },\n { number: 7, name: \"Sudurpashchim\", nameNp: \"सुदूरपश्चिम\", capital: \"Godawari\" },\n];\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lacspace/nepali-utils",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Everyday Nepal helpers — NPR currency formatting, Devanagari numerals, amount-in-words, validators, provinces. Zero-dependency.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": ["dist"],
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": ["nepal", "nepali", "npr", "currency", "devanagari", "amount-in-words", "validator", "typescript"],
|
|
28
|
+
"author": "Lacspace <contact@lacspace.com>",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"homepage": "https://lacspace.com",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/lacspace/npm-packages.git",
|
|
34
|
+
"directory": "nepali-utils"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/lacspace/npm-packages/issues"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
}
|
|
42
|
+
}
|