nik-id 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 +492 -0
- package/dist/generate.cjs +95 -0
- package/dist/generate.d.cts +83 -0
- package/dist/generate.d.ts +83 -0
- package/dist/generate.js +70 -0
- package/dist/index.cjs +183 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +154 -0
- package/dist/parse.cjs +111 -0
- package/dist/parse.d.cts +81 -0
- package/dist/parse.d.ts +81 -0
- package/dist/parse.js +84 -0
- package/dist/types.cjs +18 -0
- package/dist/types.d.cts +183 -0
- package/dist/types.d.ts +183 -0
- package/dist/types.js +0 -0
- package/dist/validate.cjs +81 -0
- package/dist/validate.d.cts +81 -0
- package/dist/validate.d.ts +81 -0
- package/dist/validate.js +54 -0
- package/package.json +106 -0
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { NIKResult } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Modul parsing NIK (Nomor Induk Kependudukan).
|
|
5
|
+
*
|
|
6
|
+
* Menyediakan fungsi {@link parseNIK} yang memvalidasi dan mengekstrak
|
|
7
|
+
* semua komponen dari NIK: kode wilayah (provinsi, kabupaten/kota, kecamatan),
|
|
8
|
+
* tanggal lahir, jenis kelamin, dan nomor urut registrasi.
|
|
9
|
+
*
|
|
10
|
+
* Kode wilayah yang dikembalikan menggunakan format **Kemendagri** (bukan BPS).
|
|
11
|
+
* Untuk resolve ke nama wilayah, gunakan package `kode-wilayah-id` dengan
|
|
12
|
+
* fungsi `getProvinceByKemendagriCode()`, `getRegencyByKemendagriCode()`, dll.
|
|
13
|
+
*
|
|
14
|
+
* @module parse
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { parseNIK } from 'nik-id/parse';
|
|
19
|
+
*
|
|
20
|
+
* const result = parseNIK("3204076508850001");
|
|
21
|
+
* if (result.valid) {
|
|
22
|
+
* console.log(result.provinceCode); // "32"
|
|
23
|
+
* console.log(result.regencyCode); // "3204"
|
|
24
|
+
* console.log(result.districtCode); // "320407"
|
|
25
|
+
* console.log(result.gender); // "F"
|
|
26
|
+
* console.log(result.birthDate); // Date: 1985-08-25
|
|
27
|
+
* console.log(result.sequenceNumber); // "0001"
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Parse NIK menjadi komponen-komponennya.
|
|
34
|
+
*
|
|
35
|
+
* Fungsi ini pertama memvalidasi NIK menggunakan {@link validateNIK},
|
|
36
|
+
* kemudian mengekstrak setiap komponen ke dalam object {@link NIKResult}.
|
|
37
|
+
*
|
|
38
|
+
* Komponen yang diekstrak:
|
|
39
|
+
* - **provinceCode** — kode provinsi Kemendagri (2 digit)
|
|
40
|
+
* - **regencyCode** — kode kabupaten/kota Kemendagri (4 digit)
|
|
41
|
+
* - **districtCode** — kode kecamatan Kemendagri (6 digit)
|
|
42
|
+
* - **birthDate** — tanggal lahir sebagai `Date` object
|
|
43
|
+
* - **gender** — jenis kelamin (`"M"` atau `"F"`)
|
|
44
|
+
* - **sequenceNumber** — nomor urut registrasi (4 digit)
|
|
45
|
+
*
|
|
46
|
+
* @param nik - String NIK 16 digit yang akan di-parse
|
|
47
|
+
* @returns {@link NIKResult} — discriminated union yang bisa di-narrow
|
|
48
|
+
* menggunakan `result.valid`
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const result = parseNIK("3204076508850001");
|
|
53
|
+
* if (result.valid) {
|
|
54
|
+
* // result bertipe NIKValid — semua field tersedia
|
|
55
|
+
* console.log(result.provinceCode); // "32"
|
|
56
|
+
* console.log(result.regencyCode); // "3204"
|
|
57
|
+
* console.log(result.districtCode); // "320407"
|
|
58
|
+
* console.log(result.birthDate); // Date: 1985-08-25
|
|
59
|
+
* console.log(result.gender); // "F"
|
|
60
|
+
* console.log(result.sequenceNumber); // "0001"
|
|
61
|
+
* } else {
|
|
62
|
+
* // result bertipe NIKInvalid — ada error
|
|
63
|
+
* console.log(result.error); // "NIK harus 16 digit"
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* // Integrasi dengan kode-wilayah-id
|
|
70
|
+
* import { getProvinceByKemendagriCode } from 'kode-wilayah-id';
|
|
71
|
+
*
|
|
72
|
+
* const result = parseNIK("3204076508850001");
|
|
73
|
+
* if (result.valid) {
|
|
74
|
+
* const prov = getProvinceByKemendagriCode(result.provinceCode);
|
|
75
|
+
* console.log(prov?.name); // "JAWA BARAT"
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
declare function parseNIK(nik: string): NIKResult;
|
|
80
|
+
|
|
81
|
+
export { parseNIK };
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
function disambiguateYear(yy) {
|
|
3
|
+
const currentYY = (/* @__PURE__ */ new Date()).getFullYear() % 100;
|
|
4
|
+
return yy > currentYY ? 1900 + yy : 2e3 + yy;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// src/validate.ts
|
|
8
|
+
var MIN_PROVINCE_CODE = 11;
|
|
9
|
+
var MAX_PROVINCE_CODE = 97;
|
|
10
|
+
var NIK_LENGTH = 16;
|
|
11
|
+
var DIGITS_ONLY_PATTERN = /^\d{16}$/;
|
|
12
|
+
function isValidCalendarDate(year, month, day) {
|
|
13
|
+
const date = new Date(year, month - 1, day);
|
|
14
|
+
return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
|
|
15
|
+
}
|
|
16
|
+
function validateNIK(nik) {
|
|
17
|
+
if (typeof nik !== "string") {
|
|
18
|
+
return { valid: false, error: "NIK harus berupa string" };
|
|
19
|
+
}
|
|
20
|
+
if (nik.length !== NIK_LENGTH) {
|
|
21
|
+
return { valid: false, error: "NIK harus 16 digit" };
|
|
22
|
+
}
|
|
23
|
+
if (!DIGITS_ONLY_PATTERN.test(nik)) {
|
|
24
|
+
return { valid: false, error: "NIK hanya boleh berisi angka" };
|
|
25
|
+
}
|
|
26
|
+
const provinceCode = Number.parseInt(nik.substring(0, 2), 10);
|
|
27
|
+
if (provinceCode < MIN_PROVINCE_CODE || provinceCode > MAX_PROVINCE_CODE) {
|
|
28
|
+
return { valid: false, error: "Kode provinsi tidak valid" };
|
|
29
|
+
}
|
|
30
|
+
const dd = Number.parseInt(nik.substring(6, 8), 10);
|
|
31
|
+
const mm = Number.parseInt(nik.substring(8, 10), 10);
|
|
32
|
+
const yy = Number.parseInt(nik.substring(10, 12), 10);
|
|
33
|
+
const isValidMaleDD = dd >= 1 && dd <= 31;
|
|
34
|
+
const isValidFemaleDD = dd >= 41 && dd <= 71;
|
|
35
|
+
if (!isValidMaleDD && !isValidFemaleDD) {
|
|
36
|
+
return { valid: false, error: "Tanggal lahir tidak valid" };
|
|
37
|
+
}
|
|
38
|
+
if (mm < 1 || mm > 12) {
|
|
39
|
+
return { valid: false, error: "Tanggal lahir tidak valid" };
|
|
40
|
+
}
|
|
41
|
+
const actualDay = isValidFemaleDD ? dd - 40 : dd;
|
|
42
|
+
const fullYear = disambiguateYear(yy);
|
|
43
|
+
if (!isValidCalendarDate(fullYear, mm, actualDay)) {
|
|
44
|
+
return { valid: false, error: "Tanggal lahir tidak valid" };
|
|
45
|
+
}
|
|
46
|
+
const seq = nik.substring(12, 16);
|
|
47
|
+
if (seq === "0000") {
|
|
48
|
+
return { valid: false, error: "Nomor urut tidak valid" };
|
|
49
|
+
}
|
|
50
|
+
return { valid: true };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/parse.ts
|
|
54
|
+
function parseNIK(nik) {
|
|
55
|
+
const validation = validateNIK(nik);
|
|
56
|
+
if (!validation.valid) {
|
|
57
|
+
return { valid: false, error: validation.error };
|
|
58
|
+
}
|
|
59
|
+
const provinceCode = nik.substring(0, 2);
|
|
60
|
+
const regencyCode = nik.substring(0, 4);
|
|
61
|
+
const districtCode = nik.substring(0, 6);
|
|
62
|
+
const dd = Number.parseInt(nik.substring(6, 8), 10);
|
|
63
|
+
const mm = Number.parseInt(nik.substring(8, 10), 10);
|
|
64
|
+
const yy = Number.parseInt(nik.substring(10, 12), 10);
|
|
65
|
+
const isFemale = dd > 40;
|
|
66
|
+
const actualDay = isFemale ? dd - 40 : dd;
|
|
67
|
+
const gender = isFemale ? "F" : "M";
|
|
68
|
+
const fullYear = disambiguateYear(yy);
|
|
69
|
+
const birthDate = new Date(fullYear, mm - 1, actualDay);
|
|
70
|
+
const sequenceNumber = nik.substring(12, 16);
|
|
71
|
+
return {
|
|
72
|
+
valid: true,
|
|
73
|
+
nik,
|
|
74
|
+
provinceCode,
|
|
75
|
+
regencyCode,
|
|
76
|
+
districtCode,
|
|
77
|
+
birthDate,
|
|
78
|
+
gender,
|
|
79
|
+
sequenceNumber
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
parseNIK
|
|
84
|
+
};
|
package/dist/types.cjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
|
|
16
|
+
// src/types.ts
|
|
17
|
+
var types_exports = {};
|
|
18
|
+
module.exports = __toCommonJS(types_exports);
|
package/dist/types.d.cts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Definisi tipe data untuk parsing dan validasi NIK (Nomor Induk Kependudukan).
|
|
3
|
+
*
|
|
4
|
+
* NIK adalah nomor identitas penduduk Indonesia yang terdiri dari 16 digit:
|
|
5
|
+
* - Digit 1-2: kode provinsi (format Kemendagri)
|
|
6
|
+
* - Digit 3-4: kode kabupaten/kota (format Kemendagri)
|
|
7
|
+
* - Digit 5-6: kode kecamatan (format Kemendagri)
|
|
8
|
+
* - Digit 7-12: tanggal lahir (DDMMYY, perempuan DD+40)
|
|
9
|
+
* - Digit 13-16: nomor urut registrasi
|
|
10
|
+
*
|
|
11
|
+
* Semua kode wilayah menggunakan format **Kemendagri** (bukan BPS).
|
|
12
|
+
* Kalau butuh resolve ke nama wilayah, bisa pakai package `kode-wilayah-id`
|
|
13
|
+
* dengan fungsi `getProvinceByKemendagriCode()`, `getRegencyByKemendagriCode()`, dll.
|
|
14
|
+
*
|
|
15
|
+
* @module types
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Hasil parsing NIK yang valid — berisi semua komponen NIK yang sudah diekstrak.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const result = parseNIK("3204076508850001");
|
|
23
|
+
* if (result.valid) {
|
|
24
|
+
* console.log(result.provinceCode); // "32"
|
|
25
|
+
* console.log(result.regencyCode); // "3204"
|
|
26
|
+
* console.log(result.districtCode); // "320407"
|
|
27
|
+
* console.log(result.gender); // "F"
|
|
28
|
+
* console.log(result.birthDate); // Date: 1985-08-25
|
|
29
|
+
* console.log(result.sequenceNumber); // "0001"
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
interface NIKValid {
|
|
34
|
+
/** Selalu `true` — gunakan untuk narrowing discriminated union */
|
|
35
|
+
valid: true;
|
|
36
|
+
/** NIK asli yang di-parse (16 digit) */
|
|
37
|
+
nik: string;
|
|
38
|
+
/**
|
|
39
|
+
* Kode provinsi Kemendagri (2 digit).
|
|
40
|
+
* Contoh: `"32"` untuk Jawa Barat, `"11"` untuk Aceh.
|
|
41
|
+
*
|
|
42
|
+
* Bisa dipakai dengan `kode-wilayah-id`:
|
|
43
|
+
* ```typescript
|
|
44
|
+
* import { getProvinceByKemendagriCode } from 'kode-wilayah-id';
|
|
45
|
+
* const prov = getProvinceByKemendagriCode(result.provinceCode);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
provinceCode: string;
|
|
49
|
+
/**
|
|
50
|
+
* Kode kabupaten/kota Kemendagri (4 digit).
|
|
51
|
+
* Contoh: `"3204"` untuk Kab. Bandung.
|
|
52
|
+
*/
|
|
53
|
+
regencyCode: string;
|
|
54
|
+
/**
|
|
55
|
+
* Kode kecamatan Kemendagri (6 digit).
|
|
56
|
+
* Contoh: `"320407"` untuk Kec. Nagreg.
|
|
57
|
+
*/
|
|
58
|
+
districtCode: string;
|
|
59
|
+
/**
|
|
60
|
+
* Tanggal lahir yang sudah di-parse menjadi object `Date`.
|
|
61
|
+
* Tahun 2 digit disambiguasi: `YY > tahunSekarang` → 1900+YY, else 2000+YY.
|
|
62
|
+
*/
|
|
63
|
+
birthDate: Date;
|
|
64
|
+
/** Jenis kelamin: `"M"` (laki-laki) atau `"F"` (perempuan) */
|
|
65
|
+
gender: "M" | "F";
|
|
66
|
+
/** Nomor urut registrasi di kecamatan (4 digit, `"0001"`–`"9999"`) */
|
|
67
|
+
sequenceNumber: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Hasil parsing NIK yang tidak valid — berisi pesan error.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const result = parseNIK("123");
|
|
75
|
+
* if (!result.valid) {
|
|
76
|
+
* console.log(result.error); // "NIK harus 16 digit"
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
interface NIKInvalid {
|
|
81
|
+
/** Selalu `false` — gunakan untuk narrowing discriminated union */
|
|
82
|
+
valid: false;
|
|
83
|
+
/** Pesan error dalam bahasa Indonesia yang menjelaskan kenapa NIK tidak valid */
|
|
84
|
+
error: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Discriminated union hasil parsing NIK.
|
|
88
|
+
*
|
|
89
|
+
* Gunakan `result.valid` untuk narrowing:
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const result = parseNIK(input);
|
|
94
|
+
* if (result.valid) {
|
|
95
|
+
* // result bertipe NIKValid — semua field tersedia
|
|
96
|
+
* console.log(result.gender);
|
|
97
|
+
* } else {
|
|
98
|
+
* // result bertipe NIKInvalid — ada error
|
|
99
|
+
* console.log(result.error);
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
type NIKResult = NIKValid | NIKInvalid;
|
|
104
|
+
/**
|
|
105
|
+
* Hasil validasi NIK yang valid.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const result = validateNIK("3204076508850001");
|
|
110
|
+
* if (result.valid) {
|
|
111
|
+
* console.log("NIK valid!");
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
interface ValidationValid {
|
|
116
|
+
/** Selalu `true` */
|
|
117
|
+
valid: true;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Hasil validasi NIK yang tidak valid.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const result = validateNIK("123");
|
|
125
|
+
* if (!result.valid) {
|
|
126
|
+
* console.log(result.error); // "NIK harus 16 digit"
|
|
127
|
+
* }
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
interface ValidationInvalid {
|
|
131
|
+
/** Selalu `false` */
|
|
132
|
+
valid: false;
|
|
133
|
+
/** Pesan error dalam bahasa Indonesia */
|
|
134
|
+
error: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Discriminated union hasil validasi NIK.
|
|
138
|
+
*
|
|
139
|
+
* Lebih ringan dari {@link NIKResult} — cuma cek valid/tidak tanpa parsing.
|
|
140
|
+
*/
|
|
141
|
+
type ValidationResult = ValidationValid | ValidationInvalid;
|
|
142
|
+
/**
|
|
143
|
+
* Opsi untuk men-generate NIK.
|
|
144
|
+
*
|
|
145
|
+
* Semua field opsional — yang tidak diisi akan di-random.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* // Full random
|
|
150
|
+
* generateNIK();
|
|
151
|
+
*
|
|
152
|
+
* // Perempuan lahir 25 Agustus 1985
|
|
153
|
+
* generateNIK({ gender: "F", birthDate: new Date("1985-08-25") });
|
|
154
|
+
*
|
|
155
|
+
* // Wilayah spesifik (Kec. Nagreg, Kab. Bandung, Jawa Barat)
|
|
156
|
+
* generateNIK({ provinceCode: "32", regencyCode: "3204", districtCode: "320407" });
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
interface GenerateOptions {
|
|
160
|
+
/**
|
|
161
|
+
* Kode provinsi Kemendagri (2 digit).
|
|
162
|
+
* Kalau diisi, `regencyCode` juga harus diisi.
|
|
163
|
+
*/
|
|
164
|
+
provinceCode?: string;
|
|
165
|
+
/**
|
|
166
|
+
* Kode kabupaten/kota Kemendagri (4 digit).
|
|
167
|
+
* Kalau diisi, `provinceCode` harus match (2 digit pertama sama).
|
|
168
|
+
*/
|
|
169
|
+
regencyCode?: string;
|
|
170
|
+
/**
|
|
171
|
+
* Kode kecamatan Kemendagri (6 digit).
|
|
172
|
+
* Kalau diisi, `regencyCode` harus match (4 digit pertama sama).
|
|
173
|
+
*/
|
|
174
|
+
districtCode?: string;
|
|
175
|
+
/** Jenis kelamin: `"M"` (laki-laki) atau `"F"` (perempuan) */
|
|
176
|
+
gender?: "M" | "F";
|
|
177
|
+
/**
|
|
178
|
+
* Tanggal lahir. Kalau tidak diisi, di-random antara 1950-2005.
|
|
179
|
+
*/
|
|
180
|
+
birthDate?: Date;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export type { GenerateOptions, NIKInvalid, NIKResult, NIKValid, ValidationInvalid, ValidationResult, ValidationValid };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Definisi tipe data untuk parsing dan validasi NIK (Nomor Induk Kependudukan).
|
|
3
|
+
*
|
|
4
|
+
* NIK adalah nomor identitas penduduk Indonesia yang terdiri dari 16 digit:
|
|
5
|
+
* - Digit 1-2: kode provinsi (format Kemendagri)
|
|
6
|
+
* - Digit 3-4: kode kabupaten/kota (format Kemendagri)
|
|
7
|
+
* - Digit 5-6: kode kecamatan (format Kemendagri)
|
|
8
|
+
* - Digit 7-12: tanggal lahir (DDMMYY, perempuan DD+40)
|
|
9
|
+
* - Digit 13-16: nomor urut registrasi
|
|
10
|
+
*
|
|
11
|
+
* Semua kode wilayah menggunakan format **Kemendagri** (bukan BPS).
|
|
12
|
+
* Kalau butuh resolve ke nama wilayah, bisa pakai package `kode-wilayah-id`
|
|
13
|
+
* dengan fungsi `getProvinceByKemendagriCode()`, `getRegencyByKemendagriCode()`, dll.
|
|
14
|
+
*
|
|
15
|
+
* @module types
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Hasil parsing NIK yang valid — berisi semua komponen NIK yang sudah diekstrak.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const result = parseNIK("3204076508850001");
|
|
23
|
+
* if (result.valid) {
|
|
24
|
+
* console.log(result.provinceCode); // "32"
|
|
25
|
+
* console.log(result.regencyCode); // "3204"
|
|
26
|
+
* console.log(result.districtCode); // "320407"
|
|
27
|
+
* console.log(result.gender); // "F"
|
|
28
|
+
* console.log(result.birthDate); // Date: 1985-08-25
|
|
29
|
+
* console.log(result.sequenceNumber); // "0001"
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
interface NIKValid {
|
|
34
|
+
/** Selalu `true` — gunakan untuk narrowing discriminated union */
|
|
35
|
+
valid: true;
|
|
36
|
+
/** NIK asli yang di-parse (16 digit) */
|
|
37
|
+
nik: string;
|
|
38
|
+
/**
|
|
39
|
+
* Kode provinsi Kemendagri (2 digit).
|
|
40
|
+
* Contoh: `"32"` untuk Jawa Barat, `"11"` untuk Aceh.
|
|
41
|
+
*
|
|
42
|
+
* Bisa dipakai dengan `kode-wilayah-id`:
|
|
43
|
+
* ```typescript
|
|
44
|
+
* import { getProvinceByKemendagriCode } from 'kode-wilayah-id';
|
|
45
|
+
* const prov = getProvinceByKemendagriCode(result.provinceCode);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
provinceCode: string;
|
|
49
|
+
/**
|
|
50
|
+
* Kode kabupaten/kota Kemendagri (4 digit).
|
|
51
|
+
* Contoh: `"3204"` untuk Kab. Bandung.
|
|
52
|
+
*/
|
|
53
|
+
regencyCode: string;
|
|
54
|
+
/**
|
|
55
|
+
* Kode kecamatan Kemendagri (6 digit).
|
|
56
|
+
* Contoh: `"320407"` untuk Kec. Nagreg.
|
|
57
|
+
*/
|
|
58
|
+
districtCode: string;
|
|
59
|
+
/**
|
|
60
|
+
* Tanggal lahir yang sudah di-parse menjadi object `Date`.
|
|
61
|
+
* Tahun 2 digit disambiguasi: `YY > tahunSekarang` → 1900+YY, else 2000+YY.
|
|
62
|
+
*/
|
|
63
|
+
birthDate: Date;
|
|
64
|
+
/** Jenis kelamin: `"M"` (laki-laki) atau `"F"` (perempuan) */
|
|
65
|
+
gender: "M" | "F";
|
|
66
|
+
/** Nomor urut registrasi di kecamatan (4 digit, `"0001"`–`"9999"`) */
|
|
67
|
+
sequenceNumber: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Hasil parsing NIK yang tidak valid — berisi pesan error.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const result = parseNIK("123");
|
|
75
|
+
* if (!result.valid) {
|
|
76
|
+
* console.log(result.error); // "NIK harus 16 digit"
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
interface NIKInvalid {
|
|
81
|
+
/** Selalu `false` — gunakan untuk narrowing discriminated union */
|
|
82
|
+
valid: false;
|
|
83
|
+
/** Pesan error dalam bahasa Indonesia yang menjelaskan kenapa NIK tidak valid */
|
|
84
|
+
error: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Discriminated union hasil parsing NIK.
|
|
88
|
+
*
|
|
89
|
+
* Gunakan `result.valid` untuk narrowing:
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const result = parseNIK(input);
|
|
94
|
+
* if (result.valid) {
|
|
95
|
+
* // result bertipe NIKValid — semua field tersedia
|
|
96
|
+
* console.log(result.gender);
|
|
97
|
+
* } else {
|
|
98
|
+
* // result bertipe NIKInvalid — ada error
|
|
99
|
+
* console.log(result.error);
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
type NIKResult = NIKValid | NIKInvalid;
|
|
104
|
+
/**
|
|
105
|
+
* Hasil validasi NIK yang valid.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const result = validateNIK("3204076508850001");
|
|
110
|
+
* if (result.valid) {
|
|
111
|
+
* console.log("NIK valid!");
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
interface ValidationValid {
|
|
116
|
+
/** Selalu `true` */
|
|
117
|
+
valid: true;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Hasil validasi NIK yang tidak valid.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const result = validateNIK("123");
|
|
125
|
+
* if (!result.valid) {
|
|
126
|
+
* console.log(result.error); // "NIK harus 16 digit"
|
|
127
|
+
* }
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
interface ValidationInvalid {
|
|
131
|
+
/** Selalu `false` */
|
|
132
|
+
valid: false;
|
|
133
|
+
/** Pesan error dalam bahasa Indonesia */
|
|
134
|
+
error: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Discriminated union hasil validasi NIK.
|
|
138
|
+
*
|
|
139
|
+
* Lebih ringan dari {@link NIKResult} — cuma cek valid/tidak tanpa parsing.
|
|
140
|
+
*/
|
|
141
|
+
type ValidationResult = ValidationValid | ValidationInvalid;
|
|
142
|
+
/**
|
|
143
|
+
* Opsi untuk men-generate NIK.
|
|
144
|
+
*
|
|
145
|
+
* Semua field opsional — yang tidak diisi akan di-random.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* // Full random
|
|
150
|
+
* generateNIK();
|
|
151
|
+
*
|
|
152
|
+
* // Perempuan lahir 25 Agustus 1985
|
|
153
|
+
* generateNIK({ gender: "F", birthDate: new Date("1985-08-25") });
|
|
154
|
+
*
|
|
155
|
+
* // Wilayah spesifik (Kec. Nagreg, Kab. Bandung, Jawa Barat)
|
|
156
|
+
* generateNIK({ provinceCode: "32", regencyCode: "3204", districtCode: "320407" });
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
interface GenerateOptions {
|
|
160
|
+
/**
|
|
161
|
+
* Kode provinsi Kemendagri (2 digit).
|
|
162
|
+
* Kalau diisi, `regencyCode` juga harus diisi.
|
|
163
|
+
*/
|
|
164
|
+
provinceCode?: string;
|
|
165
|
+
/**
|
|
166
|
+
* Kode kabupaten/kota Kemendagri (4 digit).
|
|
167
|
+
* Kalau diisi, `provinceCode` harus match (2 digit pertama sama).
|
|
168
|
+
*/
|
|
169
|
+
regencyCode?: string;
|
|
170
|
+
/**
|
|
171
|
+
* Kode kecamatan Kemendagri (6 digit).
|
|
172
|
+
* Kalau diisi, `regencyCode` harus match (4 digit pertama sama).
|
|
173
|
+
*/
|
|
174
|
+
districtCode?: string;
|
|
175
|
+
/** Jenis kelamin: `"M"` (laki-laki) atau `"F"` (perempuan) */
|
|
176
|
+
gender?: "M" | "F";
|
|
177
|
+
/**
|
|
178
|
+
* Tanggal lahir. Kalau tidak diisi, di-random antara 1950-2005.
|
|
179
|
+
*/
|
|
180
|
+
birthDate?: Date;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export type { GenerateOptions, NIKInvalid, NIKResult, NIKValid, ValidationInvalid, ValidationResult, ValidationValid };
|
package/dist/types.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/validate.ts
|
|
21
|
+
var validate_exports = {};
|
|
22
|
+
__export(validate_exports, {
|
|
23
|
+
validateNIK: () => validateNIK
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(validate_exports);
|
|
26
|
+
|
|
27
|
+
// src/utils.ts
|
|
28
|
+
function disambiguateYear(yy) {
|
|
29
|
+
const currentYY = (/* @__PURE__ */ new Date()).getFullYear() % 100;
|
|
30
|
+
return yy > currentYY ? 1900 + yy : 2e3 + yy;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/validate.ts
|
|
34
|
+
var MIN_PROVINCE_CODE = 11;
|
|
35
|
+
var MAX_PROVINCE_CODE = 97;
|
|
36
|
+
var NIK_LENGTH = 16;
|
|
37
|
+
var DIGITS_ONLY_PATTERN = /^\d{16}$/;
|
|
38
|
+
function isValidCalendarDate(year, month, day) {
|
|
39
|
+
const date = new Date(year, month - 1, day);
|
|
40
|
+
return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
|
|
41
|
+
}
|
|
42
|
+
function validateNIK(nik) {
|
|
43
|
+
if (typeof nik !== "string") {
|
|
44
|
+
return { valid: false, error: "NIK harus berupa string" };
|
|
45
|
+
}
|
|
46
|
+
if (nik.length !== NIK_LENGTH) {
|
|
47
|
+
return { valid: false, error: "NIK harus 16 digit" };
|
|
48
|
+
}
|
|
49
|
+
if (!DIGITS_ONLY_PATTERN.test(nik)) {
|
|
50
|
+
return { valid: false, error: "NIK hanya boleh berisi angka" };
|
|
51
|
+
}
|
|
52
|
+
const provinceCode = Number.parseInt(nik.substring(0, 2), 10);
|
|
53
|
+
if (provinceCode < MIN_PROVINCE_CODE || provinceCode > MAX_PROVINCE_CODE) {
|
|
54
|
+
return { valid: false, error: "Kode provinsi tidak valid" };
|
|
55
|
+
}
|
|
56
|
+
const dd = Number.parseInt(nik.substring(6, 8), 10);
|
|
57
|
+
const mm = Number.parseInt(nik.substring(8, 10), 10);
|
|
58
|
+
const yy = Number.parseInt(nik.substring(10, 12), 10);
|
|
59
|
+
const isValidMaleDD = dd >= 1 && dd <= 31;
|
|
60
|
+
const isValidFemaleDD = dd >= 41 && dd <= 71;
|
|
61
|
+
if (!isValidMaleDD && !isValidFemaleDD) {
|
|
62
|
+
return { valid: false, error: "Tanggal lahir tidak valid" };
|
|
63
|
+
}
|
|
64
|
+
if (mm < 1 || mm > 12) {
|
|
65
|
+
return { valid: false, error: "Tanggal lahir tidak valid" };
|
|
66
|
+
}
|
|
67
|
+
const actualDay = isValidFemaleDD ? dd - 40 : dd;
|
|
68
|
+
const fullYear = disambiguateYear(yy);
|
|
69
|
+
if (!isValidCalendarDate(fullYear, mm, actualDay)) {
|
|
70
|
+
return { valid: false, error: "Tanggal lahir tidak valid" };
|
|
71
|
+
}
|
|
72
|
+
const seq = nik.substring(12, 16);
|
|
73
|
+
if (seq === "0000") {
|
|
74
|
+
return { valid: false, error: "Nomor urut tidak valid" };
|
|
75
|
+
}
|
|
76
|
+
return { valid: true };
|
|
77
|
+
}
|
|
78
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
79
|
+
0 && (module.exports = {
|
|
80
|
+
validateNIK
|
|
81
|
+
});
|