indian-gst-validator 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 +135 -0
- package/index.js +14 -0
- package/package.json +29 -0
- package/src/checksum.js +43 -0
- package/src/gstValidator.js +68 -0
- package/src/pan.js +35 -0
- package/src/stateCodes.js +49 -0
- package/test/test.js +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ayush Kumar
|
|
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,135 @@
|
|
|
1
|
+
|
|
2
|
+
# 🇮🇳 Indian GST Validator
|
|
3
|
+
|
|
4
|
+
A lightweight JavaScript library to validate Indian GSTIN (Goods and Services Tax Identification Number) and extract useful information from it.
|
|
5
|
+
|
|
6
|
+
`indian-gst-validator` helps developers validate GSTIN format, verify checksum, extract PAN, and identify the state and GST holder type — all without making an API call.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- Validate GSTIN format
|
|
11
|
+
- Verify GSTIN checksum
|
|
12
|
+
- Extract PAN from GSTIN
|
|
13
|
+
- Get state name from GST state code
|
|
14
|
+
- Identify GST holder type
|
|
15
|
+
- Validate PAN format
|
|
16
|
+
- Lightweight and easy to use
|
|
17
|
+
- No external API or dependencies required
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
Install the package using npm:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install indian-gst-validator
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
const {
|
|
31
|
+
isValidGST,
|
|
32
|
+
getStateFromGST,
|
|
33
|
+
extractPAN,
|
|
34
|
+
getGSTHolderType
|
|
35
|
+
} = require("indian-gst-validator");
|
|
36
|
+
|
|
37
|
+
const gstin = "27AAPFU0939F1ZV";
|
|
38
|
+
|
|
39
|
+
// Validate GSTIN
|
|
40
|
+
console.log(isValidGST(gstin));
|
|
41
|
+
|
|
42
|
+
// Get state name
|
|
43
|
+
console.log(getStateFromGST(gstin));
|
|
44
|
+
|
|
45
|
+
// Extract PAN
|
|
46
|
+
console.log(extractPAN(gstin));
|
|
47
|
+
|
|
48
|
+
// Get GST holder type
|
|
49
|
+
console.log(getGSTHolderType(gstin));
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## API Reference
|
|
53
|
+
|
|
54
|
+
### `isValidGST(gstin)`
|
|
55
|
+
|
|
56
|
+
Checks whether the provided GSTIN has a valid format and checksum.
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
isValidGST("27AAPFU0939F1ZV");
|
|
60
|
+
// true or false
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### `getStateFromGST(gstin)`
|
|
64
|
+
|
|
65
|
+
Returns the state or UT name associated with the GSTIN state code.
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
getStateFromGST("27AAPFU0939F1ZV");
|
|
69
|
+
// "Maharashtra"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### `extractPAN(gstin)`
|
|
73
|
+
|
|
74
|
+
Extracts the PAN embedded in a GSTIN.
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
extractPAN("27AAPFU0939F1ZV");
|
|
78
|
+
// "AAPFU0939F"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### `getGSTHolderType(gstin)`
|
|
82
|
+
|
|
83
|
+
Returns the holder type based on the PAN's fourth character.
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
getGSTHolderType("27AAPFU0939F1ZV");
|
|
87
|
+
// "Firm"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> **Note:** Return values depend on the input and the package's implementation. Invalid inputs may return `false`, `null`, or another documented fallback.
|
|
91
|
+
|
|
92
|
+
## Running Tests
|
|
93
|
+
|
|
94
|
+
Clone the repository and install dependencies:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
git clone https://github.com/Ayushkr7380/indian-gst-validator.git
|
|
98
|
+
|
|
99
|
+
cd indian-gst-validator
|
|
100
|
+
|
|
101
|
+
npm install
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Run the test suite:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npm test
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Important Note
|
|
111
|
+
|
|
112
|
+
This package performs local GSTIN format and checksum validation. It does **not** verify GST registration status, taxpayer details, or active status from the official GST portal.
|
|
113
|
+
|
|
114
|
+
For official GST registration verification, use the appropriate GST portal or authorized API.
|
|
115
|
+
|
|
116
|
+
## Contributing
|
|
117
|
+
|
|
118
|
+
Contributions, bug reports, and feature suggestions are welcome!
|
|
119
|
+
|
|
120
|
+
1. Fork the repository
|
|
121
|
+
2. Create a new branch
|
|
122
|
+
3. Make your changes
|
|
123
|
+
4. Run the tests
|
|
124
|
+
5. Submit a pull request
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
129
|
+
|
|
130
|
+
## Author
|
|
131
|
+
|
|
132
|
+
**Ayush Kumar**
|
|
133
|
+
|
|
134
|
+
- GitHub: [@Ayushkr7380](https://github.com/Ayushkr7380)
|
|
135
|
+
- npm: [indian-gst-validator](https://www.npmjs.com/package/indian-gst-validator)
|
package/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { isValidGST, getStateFromGST, extractPAN, getGSTHolderType } = require("./src/gstValidator");
|
|
2
|
+
const { getStateName, STATE_CODES } = require("./src/stateCodes");
|
|
3
|
+
const { isValidPANFormat, getHolderType } = require("./src/pan");
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
isValidGST,
|
|
7
|
+
getStateFromGST,
|
|
8
|
+
extractPAN,
|
|
9
|
+
getGSTHolderType,
|
|
10
|
+
getStateName,
|
|
11
|
+
STATE_CODES,
|
|
12
|
+
isValidPANFormat,
|
|
13
|
+
getHolderType,
|
|
14
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "indian-gst-validator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Validate and extract details from Indian GST numbers",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node test/test.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"gst",
|
|
11
|
+
"gstin",
|
|
12
|
+
"india",
|
|
13
|
+
"validator",
|
|
14
|
+
"tax"
|
|
15
|
+
],
|
|
16
|
+
"author": "Ayush Kumar",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/Ayushkr7380/indian-gst-validator.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/Ayushkr7380/indian-gst-validator#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/Ayushkr7380/indian-gst-validator/issues"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=14"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/checksum.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Characters used for GST checksum calculation
|
|
2
|
+
const CHAR_SET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
3
|
+
|
|
4
|
+
// Calculate the check digit using the first 14 characters of the GST number
|
|
5
|
+
function calculateCheckDigit(gstFirst14) {
|
|
6
|
+
let sum = 0;
|
|
7
|
+
|
|
8
|
+
for (let i = 0; i < gstFirst14.length; i++) {
|
|
9
|
+
const char = gstFirst14[i];
|
|
10
|
+
const codePoint = CHAR_SET.indexOf(char);
|
|
11
|
+
|
|
12
|
+
// Alternate between multiplying by 1 and 2
|
|
13
|
+
const factor = i % 2 === 0 ? 1 : 2;
|
|
14
|
+
|
|
15
|
+
const product = codePoint * factor;
|
|
16
|
+
|
|
17
|
+
// Convert the product into a base-36 digit sum
|
|
18
|
+
const digit = Math.floor(product / 36) + (product % 36);
|
|
19
|
+
|
|
20
|
+
sum += digit;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Calculate the final checksum value
|
|
24
|
+
const checksumValue = (36 - (sum % 36)) % 36;
|
|
25
|
+
|
|
26
|
+
return CHAR_SET[checksumValue];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Check whether the GST number has a valid checksum
|
|
30
|
+
function isValidChecksum(gstNumber) {
|
|
31
|
+
if (typeof gstNumber !== "string" || gstNumber.length !== 15) return false;
|
|
32
|
+
|
|
33
|
+
const first14 = gstNumber.slice(0, 14).toUpperCase();
|
|
34
|
+
const providedCheckDigit = gstNumber[14].toUpperCase();
|
|
35
|
+
|
|
36
|
+
// Compare the calculated check digit with the provided one
|
|
37
|
+
const calculated = calculateCheckDigit(first14);
|
|
38
|
+
|
|
39
|
+
return calculated === providedCheckDigit;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Export the checksum functions
|
|
43
|
+
module.exports = { calculateCheckDigit, isValidChecksum };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const { getStateName } = require("./stateCodes");
|
|
2
|
+
const { isValidPANFormat, getHolderType } = require("./pan");
|
|
3
|
+
const { isValidChecksum } = require("./checksum");
|
|
4
|
+
|
|
5
|
+
// Regex to check the basic GST number format
|
|
6
|
+
const GST_REGEX = /^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/;
|
|
7
|
+
|
|
8
|
+
// Check whether the GST number follows the correct format
|
|
9
|
+
function isValidGSTFormat(gst) {
|
|
10
|
+
if (typeof gst !== "string") return false;
|
|
11
|
+
|
|
12
|
+
return GST_REGEX.test(gst.toUpperCase());
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Validate the GST number using its format, state code, PAN and checksum
|
|
16
|
+
function isValidGST(gstNumber) {
|
|
17
|
+
if (typeof gstNumber !== "string") return false;
|
|
18
|
+
|
|
19
|
+
const gst = gstNumber.toUpperCase().trim();
|
|
20
|
+
|
|
21
|
+
if (!isValidGSTFormat(gst)) return false;
|
|
22
|
+
|
|
23
|
+
// The first two characters represent the state code
|
|
24
|
+
const stateCode = gst.slice(0, 2);
|
|
25
|
+
if (!getStateName(stateCode)) return false;
|
|
26
|
+
|
|
27
|
+
// Extract and validate the PAN embedded in the GST number
|
|
28
|
+
const pan = gst.slice(2, 12);
|
|
29
|
+
if (!isValidPANFormat(pan)) return false;
|
|
30
|
+
|
|
31
|
+
// Check whether the last character matches the calculated checksum
|
|
32
|
+
if (!isValidChecksum(gst)) return false;
|
|
33
|
+
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Get the state name from the first two characters of the GST number
|
|
38
|
+
function getStateFromGST(gstNumber) {
|
|
39
|
+
if (typeof gstNumber !== "string" || gstNumber.length < 2) return null;
|
|
40
|
+
|
|
41
|
+
const stateCode = gstNumber.slice(0, 2);
|
|
42
|
+
|
|
43
|
+
return getStateName(stateCode);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Extract the PAN from a GST number
|
|
47
|
+
function extractPAN(gstNumber) {
|
|
48
|
+
if (typeof gstNumber !== "string" || gstNumber.length < 12) return null;
|
|
49
|
+
|
|
50
|
+
return gstNumber.slice(2, 12).toUpperCase();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Get the PAN holder type associated with the GST number
|
|
54
|
+
function getGSTHolderType(gstNumber) {
|
|
55
|
+
const pan = extractPAN(gstNumber);
|
|
56
|
+
|
|
57
|
+
if (!pan) return null;
|
|
58
|
+
|
|
59
|
+
return getHolderType(pan);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Export the GST validation and extraction functions
|
|
63
|
+
module.exports = {
|
|
64
|
+
isValidGST,
|
|
65
|
+
getStateFromGST,
|
|
66
|
+
extractPAN,
|
|
67
|
+
getGSTHolderType,
|
|
68
|
+
};
|
package/src/pan.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// PAN format validation pattern
|
|
2
|
+
const PAN_REGEX = /^[A-Z]{3}[ABCFGHLJPT][A-Z][0-9]{4}[A-Z]$/;
|
|
3
|
+
|
|
4
|
+
// PAN holder types based on the fourth character
|
|
5
|
+
const HOLDER_TYPES = {
|
|
6
|
+
A: "Association of Persons (AOP)",
|
|
7
|
+
B: "Body of Individuals (BOI)",
|
|
8
|
+
C: "Company",
|
|
9
|
+
F: "Firm / Partnership",
|
|
10
|
+
G: "Government",
|
|
11
|
+
H: "Hindu Undivided Family (HUF)",
|
|
12
|
+
L: "Local Authority",
|
|
13
|
+
J: "Artificial Juridical Person",
|
|
14
|
+
P: "Individual",
|
|
15
|
+
T: "Trust",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Check whether the given PAN follows the correct format
|
|
19
|
+
function isValidPANFormat(pan) {
|
|
20
|
+
if (typeof pan !== "string") return false;
|
|
21
|
+
|
|
22
|
+
return PAN_REGEX.test(pan.toUpperCase());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Get the PAN holder type from its fourth character
|
|
26
|
+
function getHolderType(pan) {
|
|
27
|
+
if (!isValidPANFormat(pan)) return null;
|
|
28
|
+
|
|
29
|
+
const fourthChar = pan.toUpperCase()[3];
|
|
30
|
+
|
|
31
|
+
return HOLDER_TYPES[fourthChar] || null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Export the functions and holder type mapping
|
|
35
|
+
module.exports = { isValidPANFormat, getHolderType, HOLDER_TYPES };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Indian state and union territory codes with their names
|
|
2
|
+
const STATE_CODES = {
|
|
3
|
+
"01": "Jammu and Kashmir",
|
|
4
|
+
"02": "Himachal Pradesh",
|
|
5
|
+
"03": "Punjab",
|
|
6
|
+
"04": "Chandigarh",
|
|
7
|
+
"05": "Uttarakhand",
|
|
8
|
+
"06": "Haryana",
|
|
9
|
+
"07": "Delhi",
|
|
10
|
+
"08": "Rajasthan",
|
|
11
|
+
"09": "Uttar Pradesh",
|
|
12
|
+
"10": "Bihar",
|
|
13
|
+
"11": "Sikkim",
|
|
14
|
+
"12": "Arunachal Pradesh",
|
|
15
|
+
"13": "Nagaland",
|
|
16
|
+
"14": "Manipur",
|
|
17
|
+
"15": "Mizoram",
|
|
18
|
+
"16": "Tripura",
|
|
19
|
+
"17": "Meghalaya",
|
|
20
|
+
"18": "Assam",
|
|
21
|
+
"19": "West Bengal",
|
|
22
|
+
"20": "Jharkhand",
|
|
23
|
+
"21": "Odisha",
|
|
24
|
+
"22": "Chhattisgarh",
|
|
25
|
+
"23": "Madhya Pradesh",
|
|
26
|
+
"24": "Gujarat",
|
|
27
|
+
"25": "Daman and Diu",
|
|
28
|
+
"26": "Dadra and Nagar Haveli",
|
|
29
|
+
"27": "Maharashtra",
|
|
30
|
+
"28": "Andhra Pradesh (Old)",
|
|
31
|
+
"29": "Karnataka",
|
|
32
|
+
"30": "Goa",
|
|
33
|
+
"31": "Lakshadweep",
|
|
34
|
+
"32": "Kerala",
|
|
35
|
+
"33": "Tamil Nadu",
|
|
36
|
+
"34": "Puducherry",
|
|
37
|
+
"35": "Andaman and Nicobar Islands",
|
|
38
|
+
"36": "Telangana",
|
|
39
|
+
"37": "Andhra Pradesh",
|
|
40
|
+
"38": "Ladakh",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Get the state name using its code
|
|
44
|
+
function getStateName(code) {
|
|
45
|
+
return STATE_CODES[code] || null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Export the codes and function
|
|
49
|
+
module.exports = { STATE_CODES, getStateName };
|
package/test/test.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const gst = require("../index");
|
|
2
|
+
|
|
3
|
+
// Test cases for GST number validation
|
|
4
|
+
const tests = [
|
|
5
|
+
["27AAPFU0939F1ZV", true, "Valid GST number"],
|
|
6
|
+
["27AAPFU0939F1ZX", false, "Wrong checksum"],
|
|
7
|
+
["99AAPFU0939F1ZV", false, "Invalid state code"],
|
|
8
|
+
["27AAPFU0939F1Z", false, "Too short (14 chars)"],
|
|
9
|
+
["", false, "Empty string"],
|
|
10
|
+
[null, false, "Null input"],
|
|
11
|
+
[12345, false, "Number instead of string"],
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
let passed = 0;
|
|
15
|
+
let failed = 0;
|
|
16
|
+
|
|
17
|
+
// Run each test case and compare the result with the expected value
|
|
18
|
+
tests.forEach(([input, expected, description]) => {
|
|
19
|
+
const result = gst.isValidGST(input);
|
|
20
|
+
const status = result === expected ? "PASS" : "FAIL";
|
|
21
|
+
|
|
22
|
+
// Keep track of passed and failed test cases
|
|
23
|
+
if (status === "PASS") passed++;
|
|
24
|
+
else failed++;
|
|
25
|
+
|
|
26
|
+
console.log(
|
|
27
|
+
`[${status}] ${description} — input: ${input}, expected: ${expected}, got: ${result}`
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Print the final test summary
|
|
32
|
+
console.log(`\n${passed} passed, ${failed} failed`);
|