gst-validator 1.0.2 → 1.0.4
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/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/package.json +10 -4
- package/src/gstin.cjs +131 -0
- package/src/index.cjs +2 -0
- package/src/index.d.cts +21 -0
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Module format
|
|
4
4
|
|
|
5
|
-
This package
|
|
5
|
+
This package supports both ESM and CommonJS. Use `import` or `require()` depending on your project.
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
Validate and parse Indian GSTIN numbers - real checksum verification, state-code lookup, and the embedded PAN, all offline.
|
package/package.json
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gst-validator",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Validate and parse Indian GSTIN numbers, including checksum verification and the embedded PAN",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"types": "./src/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"
|
|
11
|
-
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./src/index.d.ts",
|
|
12
|
+
"default": "./src/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./src/index.d.cts",
|
|
16
|
+
"default": "./src/index.cjs"
|
|
17
|
+
}
|
|
12
18
|
}
|
|
13
19
|
},
|
|
14
20
|
"files": [
|
|
@@ -37,7 +43,7 @@
|
|
|
37
43
|
"author": "Vijay Misal <misalvijay153@gmail.com>",
|
|
38
44
|
"license": "MIT",
|
|
39
45
|
"dependencies": {
|
|
40
|
-
"pan-card-validator": "
|
|
46
|
+
"pan-card-validator": "1.0.4"
|
|
41
47
|
},
|
|
42
48
|
"engines": {
|
|
43
49
|
"node": ">=18"
|
package/src/gstin.cjs
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const { parsePan } = require('pan-card-validator');
|
|
2
|
+
|
|
3
|
+
// Public spec: 2 state code + 10-char PAN + 1 entity number + 'Z' + 1 checksum.
|
|
4
|
+
const GSTIN_PATTERN = /^([0-9]{2})([A-Z]{5}[0-9]{4}[A-Z])([1-9A-Z])(Z)([0-9A-Z])$/;
|
|
5
|
+
const CHECKSUM_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
6
|
+
|
|
7
|
+
// Published by the GST Network (as of 2026); code 97/99 reserved for
|
|
8
|
+
// centralized/other jurisdictions not tied to a single state.
|
|
9
|
+
const STATE_CODES = {
|
|
10
|
+
'01': 'Jammu and Kashmir',
|
|
11
|
+
'02': 'Himachal Pradesh',
|
|
12
|
+
'03': 'Punjab',
|
|
13
|
+
'04': 'Chandigarh',
|
|
14
|
+
'05': 'Uttarakhand',
|
|
15
|
+
'06': 'Haryana',
|
|
16
|
+
'07': 'Delhi',
|
|
17
|
+
'08': 'Rajasthan',
|
|
18
|
+
'09': 'Uttar Pradesh',
|
|
19
|
+
10: 'Bihar',
|
|
20
|
+
11: 'Sikkim',
|
|
21
|
+
12: 'Arunachal Pradesh',
|
|
22
|
+
13: 'Nagaland',
|
|
23
|
+
14: 'Manipur',
|
|
24
|
+
15: 'Mizoram',
|
|
25
|
+
16: 'Tripura',
|
|
26
|
+
17: 'Meghalaya',
|
|
27
|
+
18: 'Assam',
|
|
28
|
+
19: 'West Bengal',
|
|
29
|
+
20: 'Jharkhand',
|
|
30
|
+
21: 'Odisha',
|
|
31
|
+
22: 'Chattisgarh',
|
|
32
|
+
23: 'Madhya Pradesh',
|
|
33
|
+
24: 'Gujarat',
|
|
34
|
+
25: 'Daman and Diu',
|
|
35
|
+
26: 'Dadra and Nagar Haveli',
|
|
36
|
+
27: 'Maharashtra',
|
|
37
|
+
28: 'Andhra Pradesh',
|
|
38
|
+
29: 'Karnataka',
|
|
39
|
+
30: 'Goa',
|
|
40
|
+
31: 'Lakshadweep',
|
|
41
|
+
32: 'Kerala',
|
|
42
|
+
33: 'Tamil Nadu',
|
|
43
|
+
34: 'Puducherry',
|
|
44
|
+
35: 'Andaman and Nicobar Islands',
|
|
45
|
+
36: 'Telangana',
|
|
46
|
+
37: 'Andhra Pradesh (New)',
|
|
47
|
+
38: 'Ladakh',
|
|
48
|
+
97: 'Other Territory',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
function normalize(input) {
|
|
52
|
+
return typeof input === 'string' ? input.trim().toUpperCase() : '';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function computeChecksum(gstinBody) {
|
|
56
|
+
let factor = 2;
|
|
57
|
+
let sum = 0;
|
|
58
|
+
const mod = CHECKSUM_CHARS.length;
|
|
59
|
+
|
|
60
|
+
for (let i = gstinBody.length - 1; i >= 0; i--) {
|
|
61
|
+
const codePoint = CHECKSUM_CHARS.indexOf(gstinBody[i]);
|
|
62
|
+
let digit = factor * codePoint;
|
|
63
|
+
digit = Math.floor(digit / mod) + (digit % mod);
|
|
64
|
+
sum += digit;
|
|
65
|
+
factor = factor === 2 ? 1 : 2;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const checksumIndex = (mod - (sum % mod)) % mod;
|
|
69
|
+
return CHECKSUM_CHARS[checksumIndex];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Parses a GSTIN into its structural components, verifying its checksum
|
|
74
|
+
* digit and the embedded PAN's structure.
|
|
75
|
+
* @param {string} input
|
|
76
|
+
* @returns {{
|
|
77
|
+
* valid: boolean,
|
|
78
|
+
* gstin?: string,
|
|
79
|
+
* stateCode?: string,
|
|
80
|
+
* stateName?: string,
|
|
81
|
+
* pan?: string,
|
|
82
|
+
* panEntityType?: string,
|
|
83
|
+
* registrationNumber?: string,
|
|
84
|
+
* checkDigit?: string,
|
|
85
|
+
* }}
|
|
86
|
+
*/
|
|
87
|
+
function parseGstin(input) {
|
|
88
|
+
const gstin = normalize(input);
|
|
89
|
+
const match = GSTIN_PATTERN.exec(gstin);
|
|
90
|
+
|
|
91
|
+
if (!match) {
|
|
92
|
+
return { valid: false };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const [, stateCode, pan, registrationNumber, , checkDigit] = match;
|
|
96
|
+
|
|
97
|
+
if (!(stateCode in STATE_CODES)) {
|
|
98
|
+
return { valid: false };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (computeChecksum(gstin.slice(0, 14)) !== checkDigit) {
|
|
102
|
+
return { valid: false };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const panInfo = parsePan(pan);
|
|
106
|
+
if (!panInfo.valid) {
|
|
107
|
+
return { valid: false };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
valid: true,
|
|
112
|
+
gstin,
|
|
113
|
+
stateCode,
|
|
114
|
+
stateName: STATE_CODES[stateCode] ?? null,
|
|
115
|
+
pan,
|
|
116
|
+
panEntityType: panInfo.entityType,
|
|
117
|
+
registrationNumber,
|
|
118
|
+
checkDigit,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Validates a GSTIN's format, checksum, and embedded PAN structure.
|
|
124
|
+
* @param {string} input
|
|
125
|
+
* @returns {boolean}
|
|
126
|
+
*/
|
|
127
|
+
function isValidGstin(input) {
|
|
128
|
+
return parseGstin(input).valid;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = { isValidGstin, parseGstin };
|
package/src/index.cjs
ADDED
package/src/index.d.cts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ParsedGstin {
|
|
2
|
+
valid: boolean;
|
|
3
|
+
gstin?: string;
|
|
4
|
+
stateCode?: string;
|
|
5
|
+
stateName?: string | null;
|
|
6
|
+
pan?: string;
|
|
7
|
+
panEntityType?: string;
|
|
8
|
+
registrationNumber?: string;
|
|
9
|
+
checkDigit?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parses a GSTIN into its structural components, verifying its checksum
|
|
14
|
+
* digit and the embedded PAN's structure.
|
|
15
|
+
*/
|
|
16
|
+
export function parseGstin(input: string): ParsedGstin;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validates a GSTIN's format, checksum, and embedded PAN structure.
|
|
20
|
+
*/
|
|
21
|
+
export function isValidGstin(input: string): boolean;
|