@indodev/toolkit 0.6.0 → 0.7.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.
Files changed (65) hide show
  1. package/dist/email-validator/index.cjs +10 -0
  2. package/dist/email-validator/index.cjs.map +1 -1
  3. package/dist/email-validator/index.d.cts +1 -1
  4. package/dist/email-validator/index.d.ts +1 -1
  5. package/dist/email-validator/index.js +10 -1
  6. package/dist/email-validator/index.js.map +1 -1
  7. package/dist/{parse-BmmsNlJt.d.cts → errors--47zprcf.d.cts} +41 -7
  8. package/dist/{parse-BmmsNlJt.d.ts → errors--47zprcf.d.ts} +41 -7
  9. package/dist/{email-validator-R9L5unIw.d.cts → errors-DdutHLae.d.cts} +23 -1
  10. package/dist/{email-validator-R9L5unIw.d.ts → errors-DdutHLae.d.ts} +23 -1
  11. package/dist/index.cjs +271 -24
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +7 -7
  14. package/dist/index.d.ts +7 -7
  15. package/dist/index.js +264 -25
  16. package/dist/index.js.map +1 -1
  17. package/dist/{compare-Ku_8OhuU.d.cts → mask-CToJqmrd.d.cts} +79 -1
  18. package/dist/{compare-Ku_8OhuU.d.ts → mask-CToJqmrd.d.ts} +79 -1
  19. package/dist/nik/index.cjs +21 -12
  20. package/dist/nik/index.cjs.map +1 -1
  21. package/dist/nik/index.d.cts +2 -2
  22. package/dist/nik/index.d.ts +2 -2
  23. package/dist/nik/index.js +21 -12
  24. package/dist/nik/index.js.map +1 -1
  25. package/dist/npwp/index.cjs +10 -0
  26. package/dist/npwp/index.cjs.map +1 -1
  27. package/dist/npwp/index.d.cts +23 -1
  28. package/dist/npwp/index.d.ts +23 -1
  29. package/dist/npwp/index.js +10 -1
  30. package/dist/npwp/index.js.map +1 -1
  31. package/dist/parse-B3UzEHq3.d.cts +155 -0
  32. package/dist/parse-B3UzEHq3.d.ts +155 -0
  33. package/dist/parse-DlrgrRfY.d.cts +155 -0
  34. package/dist/parse-DlrgrRfY.d.ts +155 -0
  35. package/dist/phone/index.cjs +36 -12
  36. package/dist/phone/index.cjs.map +1 -1
  37. package/dist/phone/index.d.cts +1 -1
  38. package/dist/phone/index.d.ts +1 -1
  39. package/dist/phone/index.js +36 -13
  40. package/dist/phone/index.js.map +1 -1
  41. package/dist/plate/index.cjs +57 -0
  42. package/dist/plate/index.cjs.map +1 -1
  43. package/dist/plate/index.d.cts +1 -1
  44. package/dist/plate/index.d.ts +1 -1
  45. package/dist/plate/index.js +56 -1
  46. package/dist/plate/index.js.map +1 -1
  47. package/dist/text/index.cjs +31 -8
  48. package/dist/text/index.cjs.map +1 -1
  49. package/dist/text/index.d.cts +2 -63
  50. package/dist/text/index.d.ts +2 -63
  51. package/dist/text/index.js +31 -8
  52. package/dist/text/index.js.map +1 -1
  53. package/dist/{utils-DT8-jt63.d.cts → utils-D4A4ro8M.d.cts} +21 -9
  54. package/dist/{utils-DT8-jt63.d.ts → utils-D4A4ro8M.d.ts} +21 -9
  55. package/dist/vin/index.cjs +64 -0
  56. package/dist/vin/index.cjs.map +1 -1
  57. package/dist/vin/index.d.cts +1 -1
  58. package/dist/vin/index.d.ts +1 -1
  59. package/dist/vin/index.js +63 -1
  60. package/dist/vin/index.js.map +1 -1
  61. package/package.json +1 -1
  62. package/dist/types-i5e6R0AS.d.cts +0 -39
  63. package/dist/types-i5e6R0AS.d.ts +0 -39
  64. package/dist/utils-DDVlOusI.d.cts +0 -30
  65. package/dist/utils-DDVlOusI.d.ts +0 -30
package/dist/index.cjs CHANGED
@@ -181,8 +181,17 @@ function maskNIK(nik, options = {}) {
181
181
  if (!/^\d{16}$/.test(nik)) {
182
182
  return nik;
183
183
  }
184
- const { start = 4, end = 4, char = "*", separator } = options;
185
- if (start + end >= 16) {
184
+ const { visibleStart, visibleEnd, maskChar, separator, start, end, char } = options;
185
+ const hasLegacyOptions = start !== void 0 || end !== void 0 || char !== void 0;
186
+ if (hasLegacyOptions) {
187
+ console.warn(
188
+ "[DEPRECATED] Mask options start/end/char are deprecated. Use visibleStart/visibleEnd/maskChar instead. These old names will be removed in v1.0.0."
189
+ );
190
+ }
191
+ const effectiveStart = visibleStart !== void 0 ? visibleStart : start !== void 0 ? start : 4;
192
+ const effectiveEnd = visibleEnd !== void 0 ? visibleEnd : end !== void 0 ? end : 4;
193
+ const effectiveChar = maskChar !== void 0 ? maskChar : char !== void 0 ? char : "*";
194
+ if (effectiveStart + effectiveEnd >= 16) {
186
195
  return nik;
187
196
  }
188
197
  if (separator) {
@@ -193,28 +202,28 @@ function maskNIK(nik, options = {}) {
193
202
  const partStart = charCount;
194
203
  const partEnd = charCount + part.length;
195
204
  charCount += part.length;
196
- if (partEnd <= start) {
205
+ if (partEnd <= effectiveStart) {
197
206
  return part;
198
- } else if (partStart >= 16 - end) {
207
+ } else if (partStart >= 16 - effectiveEnd) {
199
208
  return part;
200
- } else if (partStart >= start && partEnd <= 16 - end) {
201
- return char.repeat(part.length);
209
+ } else if (partStart >= effectiveStart && partEnd <= 16 - effectiveEnd) {
210
+ return effectiveChar.repeat(part.length);
202
211
  } else {
203
212
  return part.split("").map((ch, idx) => {
204
213
  const pos = partStart + idx;
205
- if (pos < start || pos >= 16 - end) {
214
+ if (pos < effectiveStart || pos >= 16 - effectiveEnd) {
206
215
  return ch;
207
216
  }
208
- return char;
217
+ return effectiveChar;
209
218
  }).join("");
210
219
  }
211
220
  });
212
221
  return maskedParts.join(separator);
213
222
  }
214
- const startPart = nik.substring(0, start);
215
- const endPart = nik.substring(16 - end);
216
- const maskLength = 16 - start - end;
217
- return startPart + char.repeat(maskLength) + endPart;
223
+ const startPart = nik.substring(0, effectiveStart);
224
+ const endPart = nik.substring(16 - effectiveEnd);
225
+ const maskLength = 16 - effectiveStart - effectiveEnd;
226
+ return startPart + effectiveChar.repeat(maskLength) + endPart;
218
227
  }
219
228
 
220
229
  // src/nik/utils.ts
@@ -934,28 +943,42 @@ function maskPhoneNumber(phone, options = {}) {
934
943
  if (toMask.length < 4) {
935
944
  return phone;
936
945
  }
937
- const { char = "*", separator } = options;
938
- let { start = 4, end = 4 } = options;
939
- if (start + end >= toMask.length) {
946
+ const { maskChar, separator, visibleStart, visibleEnd, start, end, char } = options;
947
+ const hasLegacyOptions = start !== void 0 || end !== void 0 || char !== void 0;
948
+ if (hasLegacyOptions) {
949
+ console.warn(
950
+ "[DEPRECATED] Mask options start/end/char are deprecated. Use visibleStart/visibleEnd/maskChar instead. These old names will be removed in v1.0.0."
951
+ );
952
+ }
953
+ const effectiveStart = visibleStart !== void 0 ? visibleStart : start !== void 0 ? start : 4;
954
+ const effectiveEnd = visibleEnd !== void 0 ? visibleEnd : end !== void 0 ? end : 4;
955
+ const effectiveChar = maskChar !== void 0 ? maskChar : char !== void 0 ? char : "*";
956
+ if (effectiveStart + effectiveEnd >= toMask.length) {
940
957
  if (toMask.length < 10) {
941
958
  const minMaskLength = 1;
942
959
  const availableForVisible = toMask.length - minMaskLength;
943
960
  if (availableForVisible >= 2) {
944
- start = Math.floor(availableForVisible / 2);
945
- end = availableForVisible - start;
961
+ const newStart = Math.floor(availableForVisible / 2);
962
+ const newEnd = availableForVisible - newStart;
963
+ const startPart2 = toMask.substring(0, newStart);
964
+ const endPart2 = toMask.substring(toMask.length - newEnd);
965
+ const masked2 = startPart2 + effectiveChar + endPart2;
966
+ if (separator) {
967
+ return `${startPart2}${separator}${effectiveChar}${separator}${endPart2}`;
968
+ }
969
+ return masked2;
946
970
  } else {
947
971
  return toMask;
948
972
  }
949
- } else {
950
- return toMask;
951
973
  }
974
+ return toMask;
952
975
  }
953
- const startPart = toMask.substring(0, start);
954
- const endPart = toMask.substring(toMask.length - end);
955
- const maskLength = toMask.length - start - end;
956
- const masked = startPart + char.repeat(maskLength) + endPart;
976
+ const startPart = toMask.substring(0, effectiveStart);
977
+ const endPart = toMask.substring(toMask.length - effectiveEnd);
978
+ const maskLength = toMask.length - effectiveStart - effectiveEnd;
979
+ const masked = startPart + effectiveChar.repeat(maskLength) + endPart;
957
980
  if (separator) {
958
- return `${masked.substring(0, start)}${separator}${masked.substring(start, masked.length - end)}${separator}${masked.substring(masked.length - end)}`;
981
+ return `${masked.substring(0, effectiveStart)}${separator}${masked.substring(effectiveStart, masked.length - effectiveEnd)}${separator}${masked.substring(masked.length - effectiveEnd)}`;
959
982
  }
960
983
  return masked;
961
984
  }
@@ -1047,6 +1070,15 @@ function isProvider(phone, providerName) {
1047
1070
  return operator.toLowerCase() === providerName.toLowerCase();
1048
1071
  }
1049
1072
 
1073
+ // src/phone/errors.ts
1074
+ var InvalidPhoneError = class extends Error {
1075
+ constructor(message = "Invalid phone number provided") {
1076
+ super(message);
1077
+ this.code = "INVALID_PHONE";
1078
+ this.name = "InvalidPhoneError";
1079
+ }
1080
+ };
1081
+
1050
1082
  // src/npwp/validate.ts
1051
1083
  function validateNPWP(npwp) {
1052
1084
  if (!npwp || typeof npwp !== "string") {
@@ -1134,6 +1166,15 @@ function maskNPWP(npwp, options) {
1134
1166
  return `${start}${middle}${end}`;
1135
1167
  }
1136
1168
 
1169
+ // src/npwp/errors.ts
1170
+ var InvalidNPWPError = class extends Error {
1171
+ constructor(message = "Invalid NPWP provided") {
1172
+ super(message);
1173
+ this.code = "INVALID_NPWP";
1174
+ this.name = "InvalidNPWPError";
1175
+ }
1176
+ };
1177
+
1137
1178
  // src/plate/regions.ts
1138
1179
  var PLATE_REGIONS = {
1139
1180
  A: "Banten",
@@ -1225,6 +1266,61 @@ function formatPlate(plate) {
1225
1266
  return `${match[1]} ${match[2]} ${match[3]}`;
1226
1267
  }
1227
1268
 
1269
+ // src/plate/errors.ts
1270
+ var InvalidPlateError = class extends Error {
1271
+ constructor(message = "Invalid plate provided") {
1272
+ super(message);
1273
+ this.code = "INVALID_PLATE";
1274
+ this.name = "InvalidPlateError";
1275
+ }
1276
+ };
1277
+
1278
+ // src/plate/parse.ts
1279
+ function parsePlate(plate) {
1280
+ if (!plate || typeof plate !== "string") {
1281
+ return null;
1282
+ }
1283
+ const cleaned = plate.replace(/\s+/g, "").toUpperCase();
1284
+ const privatePlateRegex = /^[A-Z]{1,2}\d{1,4}[A-Z]{1,3}$/;
1285
+ const publicPlateRegex = /^[A-Z]{1,2}\d{1,4}[A-Z]{0,3}$/;
1286
+ if (!privatePlateRegex.test(cleaned) && !publicPlateRegex.test(cleaned)) {
1287
+ return null;
1288
+ }
1289
+ const isValid = validatePlate(plate);
1290
+ const match = cleaned.match(/^([A-Z]{1,2})(\d{1,4})([A-Z]{0,3})$/);
1291
+ if (!match) {
1292
+ return null;
1293
+ }
1294
+ const prefix = match[1];
1295
+ const number = match[2];
1296
+ const suffix = match[3] || "";
1297
+ const type = determinePlateType(cleaned);
1298
+ return {
1299
+ prefix,
1300
+ number,
1301
+ suffix,
1302
+ type,
1303
+ formatted: formatPlate(plate),
1304
+ isValid
1305
+ };
1306
+ }
1307
+ function determinePlateType(plate) {
1308
+ const cleaned = plate.replace(/\s+/g, "").toUpperCase();
1309
+ if (cleaned.startsWith("CD") || cleaned.startsWith("CC") || cleaned.startsWith("KL")) {
1310
+ return "diplomat";
1311
+ }
1312
+ if (/^[A-Z]{1,2}\d{1,4}[A-Z]{0,3}$/.test(cleaned)) {
1313
+ const numDigits = cleaned.match(/\d+/)?.[0].length || 0;
1314
+ if (numDigits <= 4) {
1315
+ return "private";
1316
+ }
1317
+ }
1318
+ if (/^[A-Z]{1,2}\d{1,4}[A-Z]{0,3}$/.test(cleaned)) {
1319
+ return "public";
1320
+ }
1321
+ return null;
1322
+ }
1323
+
1228
1324
  // src/vin/constants.ts
1229
1325
  var VIN_LENGTH = 17;
1230
1326
  var VIN_CHECK_DIGIT_INDEX = 8;
@@ -1295,6 +1391,68 @@ function validateVIN(vin) {
1295
1391
  return actualCheckDigit === expectedCheckDigit;
1296
1392
  }
1297
1393
 
1394
+ // src/vin/errors.ts
1395
+ var InvalidVINError = class extends Error {
1396
+ constructor(message = "Invalid VIN provided") {
1397
+ super(message);
1398
+ this.code = "INVALID_VIN";
1399
+ this.name = "InvalidVINError";
1400
+ }
1401
+ };
1402
+
1403
+ // src/vin/parse.ts
1404
+ function parseVIN(vin) {
1405
+ if (!vin || typeof vin !== "string") {
1406
+ return null;
1407
+ }
1408
+ const normalizedVIN = vin.toUpperCase();
1409
+ if (normalizedVIN.length !== VIN_LENGTH) {
1410
+ return null;
1411
+ }
1412
+ for (const char of EXCLUDED_VIN_CHARS) {
1413
+ if (normalizedVIN.includes(char)) {
1414
+ return null;
1415
+ }
1416
+ }
1417
+ for (const char of normalizedVIN) {
1418
+ if (VIN_CHAR_VALUES[char] === void 0) {
1419
+ return null;
1420
+ }
1421
+ }
1422
+ const isValid = validateCheckDigit(normalizedVIN);
1423
+ const wmi = normalizedVIN.substring(0, 3);
1424
+ const vds = normalizedVIN.substring(3, 9);
1425
+ const checkDigit = normalizedVIN[VIN_CHECK_DIGIT_INDEX];
1426
+ const modelYearCode = normalizedVIN[9];
1427
+ const plantCode = normalizedVIN[10];
1428
+ const serialNumber = normalizedVIN.substring(11, 17);
1429
+ return {
1430
+ wmi,
1431
+ vds,
1432
+ checkDigit,
1433
+ modelYearCode,
1434
+ plantCode,
1435
+ serialNumber,
1436
+ isValid
1437
+ };
1438
+ }
1439
+ function validateCheckDigit(vin) {
1440
+ let sum = 0;
1441
+ for (let i = 0; i < VIN_LENGTH; i++) {
1442
+ const char = vin[i];
1443
+ const weight = VIN_WEIGHTS[i];
1444
+ const val = VIN_CHAR_VALUES[char];
1445
+ if (val === void 0) {
1446
+ return false;
1447
+ }
1448
+ sum += val * weight;
1449
+ }
1450
+ const checkDigitValue = sum % VIN_MODULUS;
1451
+ const expectedCheckDigit = checkDigitValue === 10 ? VIN_CHECK_DIGIT_X : checkDigitValue.toString();
1452
+ const actualCheckDigit = vin[VIN_CHECK_DIGIT_INDEX];
1453
+ return actualCheckDigit === expectedCheckDigit;
1454
+ }
1455
+
1298
1456
  // src/email-validator/constants.ts
1299
1457
  var EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$/;
1300
1458
  var DISPOSABLE_DOMAINS = [
@@ -1368,6 +1526,15 @@ function normalizeEmail(email) {
1368
1526
  return email.trim().toLowerCase();
1369
1527
  }
1370
1528
 
1529
+ // src/email-validator/errors.ts
1530
+ var InvalidEmailError = class extends Error {
1531
+ constructor(message = "Invalid email provided") {
1532
+ super(message);
1533
+ this.code = "INVALID_EMAIL";
1534
+ this.name = "InvalidEmailError";
1535
+ }
1536
+ };
1537
+
1371
1538
  // src/currency/format.ts
1372
1539
  function formatRupiah(amount, options) {
1373
1540
  const {
@@ -3366,6 +3533,78 @@ function similarity(str1, str2) {
3366
3533
  return 1 - distance / maxLength;
3367
3534
  }
3368
3535
 
3536
+ // src/text/mask.ts
3537
+ function maskText(text, options) {
3538
+ if (!text) return text;
3539
+ const {
3540
+ pattern = "middle",
3541
+ maskChar,
3542
+ visibleStart,
3543
+ visibleEnd,
3544
+ separator,
3545
+ start,
3546
+ end,
3547
+ char
3548
+ } = options || {};
3549
+ const hasLegacyOptions = start !== void 0 || end !== void 0 || char !== void 0;
3550
+ if (hasLegacyOptions) {
3551
+ console.warn(
3552
+ "[DEPRECATED] Mask options start/end/char are deprecated. Use visibleStart/visibleEnd/maskChar instead. These old names will be removed in v1.0.0."
3553
+ );
3554
+ }
3555
+ const effectivePattern = pattern || "middle";
3556
+ const effectiveStart = visibleStart !== void 0 ? visibleStart : start !== void 0 ? start : 2;
3557
+ const effectiveEnd = visibleEnd !== void 0 ? visibleEnd : end !== void 0 ? end : 2;
3558
+ const effectiveChar = maskChar !== void 0 ? maskChar : char !== void 0 ? char : "*";
3559
+ switch (effectivePattern) {
3560
+ case "all":
3561
+ return maskAll(text, effectiveChar);
3562
+ case "email":
3563
+ return maskEmail2(text, effectiveChar);
3564
+ case "middle":
3565
+ default:
3566
+ return maskMiddle(
3567
+ text,
3568
+ effectiveChar,
3569
+ effectiveStart,
3570
+ effectiveEnd,
3571
+ separator
3572
+ );
3573
+ }
3574
+ }
3575
+ function maskAll(text, maskChar) {
3576
+ return text.split("").map((char) => char === " " ? " " : maskChar).join("");
3577
+ }
3578
+ function maskMiddle(text, maskChar, visibleStart, visibleEnd, separator) {
3579
+ const length = text.length;
3580
+ const totalVisible = visibleStart + visibleEnd;
3581
+ if (length < totalVisible) {
3582
+ return maskChar.repeat(length);
3583
+ }
3584
+ const start = text.slice(0, visibleStart);
3585
+ const middle = maskChar.repeat(length - totalVisible);
3586
+ const end = text.slice(length - visibleEnd);
3587
+ if (separator) {
3588
+ return `${start}${separator}${middle}${separator}${end}`;
3589
+ }
3590
+ return start + middle + end;
3591
+ }
3592
+ function maskEmail2(text, maskChar) {
3593
+ const atIndex = text.indexOf("@");
3594
+ if (atIndex === -1) {
3595
+ return maskMiddle(text, maskChar, 2, 0);
3596
+ }
3597
+ const localPart = text.slice(0, atIndex);
3598
+ const domain = text.slice(atIndex);
3599
+ if (localPart.length <= 2) {
3600
+ const maskedLocal2 = localPart + maskChar.repeat(Math.max(0, 2 - localPart.length));
3601
+ return maskedLocal2 + domain;
3602
+ }
3603
+ const visibleLocal = localPart.slice(0, 2);
3604
+ const maskedLocal = visibleLocal + maskChar.repeat(localPart.length - 2);
3605
+ return maskedLocal + domain;
3606
+ }
3607
+
3369
3608
  // src/datetime/types.ts
3370
3609
  var InvalidDateError = class extends Error {
3371
3610
  constructor(message = "Invalid date provided") {
@@ -3789,6 +4028,11 @@ exports.DAY_NAMES = DAY_NAMES;
3789
4028
  exports.DAY_NAMES_SHORT = DAY_NAMES_SHORT;
3790
4029
  exports.InvalidDateError = InvalidDateError;
3791
4030
  exports.InvalidDateRangeError = InvalidDateRangeError;
4031
+ exports.InvalidEmailError = InvalidEmailError;
4032
+ exports.InvalidNPWPError = InvalidNPWPError;
4033
+ exports.InvalidPhoneError = InvalidPhoneError;
4034
+ exports.InvalidPlateError = InvalidPlateError;
4035
+ exports.InvalidVINError = InvalidVINError;
3792
4036
  exports.MONTH_NAMES = MONTH_NAMES;
3793
4037
  exports.MONTH_NAMES_SHORT = MONTH_NAMES_SHORT;
3794
4038
  exports.TIMEZONE_MAP = TIMEZONE_MAP;
@@ -3835,13 +4079,16 @@ exports.maskEmail = maskEmail;
3835
4079
  exports.maskNIK = maskNIK;
3836
4080
  exports.maskNPWP = maskNPWP;
3837
4081
  exports.maskPhoneNumber = maskPhoneNumber;
4082
+ exports.maskText = maskText;
3838
4083
  exports.normalizeEmail = normalizeEmail;
3839
4084
  exports.normalizeWhitespace = normalizeWhitespace;
3840
4085
  exports.parseDate = parseDate;
3841
4086
  exports.parseNIK = parseNIK;
3842
4087
  exports.parseNPWP = parseNPWP;
3843
4088
  exports.parsePhoneNumber = parsePhoneNumber;
4089
+ exports.parsePlate = parsePlate;
3844
4090
  exports.parseRupiah = parseRupiah;
4091
+ exports.parseVIN = parseVIN;
3845
4092
  exports.profanityFilter = profanityFilter;
3846
4093
  exports.removeAccents = removeAccents;
3847
4094
  exports.removeStopwords = removeStopwords;