superjs-core 0.5.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.
package/dist/index.js CHANGED
@@ -78,6 +78,7 @@ function deepMerge(...objects) {
78
78
  const keys = Object.keys(obj);
79
79
  for (let j = 0; j < keys.length; j++) {
80
80
  const key = keys[j];
81
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
81
82
  const val = obj[key];
82
83
  const existing = result[key];
83
84
  if (val !== void 0 && isPlainObject(val) && isPlainObject(existing)) {
@@ -265,6 +266,54 @@ function once(fn) {
265
266
  return result;
266
267
  };
267
268
  }
269
+ function deepEqual(a, b) {
270
+ if (Object.is(a, b)) return true;
271
+ if (a === null || b === null || typeof a !== typeof b) return false;
272
+ if (typeof a !== "object") return false;
273
+ const aObj = a;
274
+ const bObj = b;
275
+ if (Array.isArray(a) && Array.isArray(b)) {
276
+ if (a.length !== b.length) return false;
277
+ for (let i = 0; i < a.length; i++) {
278
+ if (!deepEqual(a[i], b[i])) return false;
279
+ }
280
+ return true;
281
+ }
282
+ if (a instanceof Date && b instanceof Date) {
283
+ return a.getTime() === b.getTime();
284
+ }
285
+ if (a instanceof RegExp && b instanceof RegExp) {
286
+ return a.source === b.source && a.flags === b.flags;
287
+ }
288
+ if (a instanceof Map && b instanceof Map) {
289
+ if (a.size !== b.size) return false;
290
+ for (const [k, v] of a) {
291
+ if (!b.has(k) || !deepEqual(v, b.get(k))) return false;
292
+ }
293
+ return true;
294
+ }
295
+ if (a instanceof Set && b instanceof Set) {
296
+ if (a.size !== b.size) return false;
297
+ for (const v of a) {
298
+ if (!b.has(v)) return false;
299
+ }
300
+ return true;
301
+ }
302
+ const keysA = Object.keys(aObj);
303
+ const keysB = Object.keys(bObj);
304
+ if (keysA.length !== keysB.length) return false;
305
+ for (const key of keysA) {
306
+ if (!Object.prototype.hasOwnProperty.call(bObj, key)) return false;
307
+ if (!deepEqual(aObj[key], bObj[key])) return false;
308
+ }
309
+ return true;
310
+ }
311
+ function pipe(initial, ...fns) {
312
+ return fns.reduce((acc, fn) => fn(acc), initial);
313
+ }
314
+ function compose(...fns) {
315
+ return (initial) => fns.reduceRight((acc, fn) => fn(acc), initial);
316
+ }
268
317
 
269
318
  // src/math/index.ts
270
319
  var DivisionByZeroError = class extends Error {
@@ -354,6 +403,250 @@ function randomInt(min, max) {
354
403
  function inRange(value, min, max) {
355
404
  return value >= min && value <= max;
356
405
  }
406
+ function median(values) {
407
+ if (values.length === 0) throw new RangeError("Cannot compute median of an empty array");
408
+ const sorted = [...values].sort((a, b) => a - b);
409
+ const mid = Math.floor(sorted.length / 2);
410
+ return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
411
+ }
412
+ function stddev(values) {
413
+ if (values.length < 2) throw new RangeError("Need at least 2 values for stddev");
414
+ const mean = sum(values) / values.length;
415
+ const sqDiffs = values.map((v) => (v - mean) ** 2);
416
+ return Math.sqrt(sqDiffs.reduce((a, b) => a + b, 0) / values.length);
417
+ }
418
+ function sampleStddev(values) {
419
+ if (values.length < 2) throw new RangeError("Need at least 2 values for sample stddev");
420
+ const mean = sum(values) / values.length;
421
+ const sqDiffs = values.map((v) => (v - mean) ** 2);
422
+ return Math.sqrt(sqDiffs.reduce((a, b) => a + b, 0) / (values.length - 1));
423
+ }
424
+ function percentile(values, p) {
425
+ if (values.length === 0) throw new RangeError("Cannot compute percentile of empty array");
426
+ if (p < 0 || p > 100) throw new RangeError("Percentile must be between 0 and 100");
427
+ const sorted = [...values].sort((a, b) => a - b);
428
+ const rank = p / 100 * (sorted.length - 1);
429
+ const lower = Math.floor(rank);
430
+ const upper = Math.ceil(rank);
431
+ if (lower === upper) return sorted[lower];
432
+ return sorted[lower] + (sorted[upper] - sorted[lower]) * (rank - lower);
433
+ }
434
+ function correlation(x, y) {
435
+ if (x.length !== y.length) throw new RangeError("Arrays must have the same length");
436
+ if (x.length < 2) throw new RangeError("Need at least 2 pairs for correlation");
437
+ const n = x.length;
438
+ const meanX = sum(x) / n;
439
+ const meanY = sum(y) / n;
440
+ let num = 0;
441
+ let denX = 0;
442
+ let denY = 0;
443
+ for (let i = 0; i < n; i++) {
444
+ const dx = x[i] - meanX;
445
+ const dy = y[i] - meanY;
446
+ num += dx * dy;
447
+ denX += dx * dx;
448
+ denY += dy * dy;
449
+ }
450
+ if (denX === 0 || denY === 0) return 0;
451
+ return num / Math.sqrt(denX * denY);
452
+ }
453
+ function formatCurrency(value, options) {
454
+ const locale = options?.locale ?? "id-ID";
455
+ const currency = options?.currency ?? "IDR";
456
+ const notation = options?.notation ?? "standard";
457
+ try {
458
+ return new Intl.NumberFormat(locale, {
459
+ style: "currency",
460
+ currency,
461
+ notation,
462
+ minimumFractionDigits: 0,
463
+ maximumFractionDigits: 2
464
+ }).format(value);
465
+ } catch {
466
+ return `${currency} ${value.toLocaleString(locale)}`;
467
+ }
468
+ }
469
+ function isEven(n) {
470
+ return n % 2 === 0;
471
+ }
472
+ function isOdd(n) {
473
+ return n % 2 !== 0;
474
+ }
475
+ function gcd(a, b) {
476
+ if (!Number.isInteger(a) || !Number.isInteger(b)) {
477
+ throw new RangeError("Arguments must be integers");
478
+ }
479
+ a = Math.abs(a);
480
+ b = Math.abs(b);
481
+ while (b !== 0) {
482
+ const t = b;
483
+ b = a % b;
484
+ a = t;
485
+ }
486
+ return a;
487
+ }
488
+ function lcm(a, b) {
489
+ if (!Number.isInteger(a) || !Number.isInteger(b)) {
490
+ throw new RangeError("Arguments must be integers");
491
+ }
492
+ if (a === 0 || b === 0) {
493
+ throw new RangeError("Arguments must be non-zero");
494
+ }
495
+ return Math.abs(a * b) / gcd(a, b);
496
+ }
497
+ function factorial(n) {
498
+ if (!Number.isInteger(n)) {
499
+ throw new RangeError("Argument must be an integer");
500
+ }
501
+ if (n < 0) {
502
+ throw new RangeError("Factorial is not defined for negative numbers");
503
+ }
504
+ let result = 1;
505
+ for (let i = 2; i <= n; i++) {
506
+ result *= i;
507
+ }
508
+ return result;
509
+ }
510
+ function isPrime(n) {
511
+ if (!Number.isInteger(n)) {
512
+ throw new RangeError("Argument must be an integer");
513
+ }
514
+ if (n < 2) return false;
515
+ if (n === 2 || n === 3) return true;
516
+ if (n % 2 === 0 || n % 3 === 0) return false;
517
+ const limit = Math.sqrt(n);
518
+ for (let i = 5; i <= limit; i += 6) {
519
+ if (n % i === 0 || n % (i + 2) === 0) return false;
520
+ }
521
+ return true;
522
+ }
523
+ function toRadians(degrees) {
524
+ return degrees * Math.PI / 180;
525
+ }
526
+ function toDegrees(radians) {
527
+ return radians * 180 / Math.PI;
528
+ }
529
+ function lerp(a, b, t) {
530
+ return a + (b - a) * t;
531
+ }
532
+ function percentageOf(value, total) {
533
+ if (total === 0) {
534
+ throw new RangeError("Total must be non-zero");
535
+ }
536
+ return value / total * 100;
537
+ }
538
+ function mapRange(value, inMin, inMax, outMin, outMax) {
539
+ if (inMin === inMax) {
540
+ throw new RangeError("Input range must not be zero");
541
+ }
542
+ return (value - inMin) / (inMax - inMin) * (outMax - outMin) + outMin;
543
+ }
544
+ function mode(values) {
545
+ if (values.length === 0) {
546
+ throw new RangeError("Cannot compute mode of an empty array");
547
+ }
548
+ const freq = /* @__PURE__ */ new Map();
549
+ let maxFreq = 0;
550
+ for (const v of values) {
551
+ const count = (freq.get(v) ?? 0) + 1;
552
+ freq.set(v, count);
553
+ if (count > maxFreq) maxFreq = count;
554
+ }
555
+ const result = [];
556
+ for (const [v, count] of freq) {
557
+ if (count === maxFreq) result.push(v);
558
+ }
559
+ return result;
560
+ }
561
+ function range(start, end, step) {
562
+ const dir = end >= start ? 1 : -1;
563
+ const s = step ?? dir;
564
+ if (s === 0) {
565
+ throw new RangeError("Step must not be zero");
566
+ }
567
+ if ((end - start) * s < 0) {
568
+ return [];
569
+ }
570
+ const result = [];
571
+ let i = start;
572
+ if (s > 0) {
573
+ while (i <= end) {
574
+ result.push(i);
575
+ i += s;
576
+ }
577
+ } else {
578
+ while (i >= end) {
579
+ result.push(i);
580
+ i += s;
581
+ }
582
+ }
583
+ return result;
584
+ }
585
+ function weightedAverage(values, weights) {
586
+ if (values.length === 0 || weights.length === 0) {
587
+ throw new RangeError("Arrays must not be empty");
588
+ }
589
+ if (values.length !== weights.length) {
590
+ throw new RangeError("Values and weights must have the same length");
591
+ }
592
+ let weightedSum = 0;
593
+ let weightSum = 0;
594
+ for (let i = 0; i < values.length; i++) {
595
+ weightedSum += values[i] * weights[i];
596
+ weightSum += weights[i];
597
+ }
598
+ if (weightSum === 0) {
599
+ throw new RangeError("Sum of weights must be non-zero");
600
+ }
601
+ return weightedSum / weightSum;
602
+ }
603
+ function geometricMean(values) {
604
+ if (values.length === 0) {
605
+ throw new RangeError("Cannot compute geometric mean of an empty array");
606
+ }
607
+ for (const v of values) {
608
+ if (v < 0) {
609
+ throw new RangeError("Values must be non-negative for geometric mean");
610
+ }
611
+ }
612
+ const logSum = values.reduce((acc, v) => v === 0 ? acc : acc + Math.log(v), 0);
613
+ if (logSum === -Infinity) return 0;
614
+ return Math.exp(logSum / values.length);
615
+ }
616
+ function combinations(n, k) {
617
+ if (!Number.isInteger(n) || !Number.isInteger(k)) {
618
+ throw new RangeError("Arguments must be integers");
619
+ }
620
+ if (n < 0 || k < 0) {
621
+ throw new RangeError("Arguments must be non-negative");
622
+ }
623
+ if (k > n) {
624
+ throw new RangeError("k must not exceed n");
625
+ }
626
+ if (k === 0 || k === n) return 1;
627
+ const r = Math.min(k, n - k);
628
+ let result = 1;
629
+ for (let i = 1; i <= r; i++) {
630
+ result = result * (n - r + i) / i;
631
+ }
632
+ return result;
633
+ }
634
+ function permutations(n, k) {
635
+ if (!Number.isInteger(n) || !Number.isInteger(k)) {
636
+ throw new RangeError("Arguments must be integers");
637
+ }
638
+ if (n < 0 || k < 0) {
639
+ throw new RangeError("Arguments must be non-negative");
640
+ }
641
+ if (k > n) {
642
+ throw new RangeError("k must not exceed n");
643
+ }
644
+ let result = 1;
645
+ for (let i = n; i > n - k; i--) {
646
+ result *= i;
647
+ }
648
+ return result;
649
+ }
357
650
 
358
651
  // src/date/index.ts
359
652
  var InvalidDateError = class extends Error {
@@ -610,6 +903,427 @@ function calculateAge(birthDate) {
610
903
  }
611
904
  return age;
612
905
  }
906
+ var LOCALE_LABELS = {
907
+ id: {
908
+ years: { single: "tahun", plural: "tahun" },
909
+ months: { single: "bulan", plural: "bulan" },
910
+ weeks: { single: "minggu", plural: "minggu" },
911
+ days: { single: "hari", plural: "hari" },
912
+ hours: { single: "jam", plural: "jam" },
913
+ minutes: { single: "menit", plural: "menit" },
914
+ seconds: { single: "detik", plural: "detik" }
915
+ },
916
+ en: {
917
+ years: { single: "year", plural: "years" },
918
+ months: { single: "month", plural: "months" },
919
+ weeks: { single: "week", plural: "weeks" },
920
+ days: { single: "day", plural: "days" },
921
+ hours: { single: "hour", plural: "hours" },
922
+ minutes: { single: "minute", plural: "minutes" },
923
+ seconds: { single: "second", plural: "seconds" }
924
+ }
925
+ };
926
+ function getSuffix(diffMs, kind, locale) {
927
+ if (diffMs < 0) {
928
+ return locale === "en" ? "ago" : "yang lalu";
929
+ }
930
+ if (kind === "remaining") {
931
+ return locale === "en" ? "remaining" : "lagi";
932
+ }
933
+ return locale === "en" ? "ago" : "yang lalu";
934
+ }
935
+ function formatRelativeTime(absDiffMs, suffix, locale) {
936
+ const labels = LOCALE_LABELS[locale] ?? LOCALE_LABELS.id;
937
+ const seconds = Math.floor(absDiffMs / 1e3);
938
+ const minutes = Math.floor(seconds / 60);
939
+ const hours = Math.floor(minutes / 60);
940
+ const days = Math.floor(hours / 24);
941
+ const weeks = Math.floor(days / 7);
942
+ const months = Math.floor(days / 30.4375);
943
+ const years = Math.floor(days / 365.25);
944
+ let count;
945
+ let unit;
946
+ if (years >= 1) {
947
+ count = years;
948
+ unit = "years";
949
+ } else if (months >= 1) {
950
+ count = months;
951
+ unit = "months";
952
+ } else if (weeks >= 1) {
953
+ count = weeks;
954
+ unit = "weeks";
955
+ } else if (days >= 1) {
956
+ count = days;
957
+ unit = "days";
958
+ } else if (hours >= 1) {
959
+ count = hours;
960
+ unit = "hours";
961
+ } else if (minutes >= 1) {
962
+ count = minutes;
963
+ unit = "minutes";
964
+ } else {
965
+ count = Math.max(1, seconds);
966
+ unit = "seconds";
967
+ }
968
+ const label = count === 1 ? labels[unit].single : labels[unit].plural;
969
+ return `${count} ${label} ${suffix}`;
970
+ }
971
+ function timeAgo(date, options) {
972
+ const diff = Date.now() - date.getTime();
973
+ const locale = options?.locale ?? "id";
974
+ const suffix = getSuffix(diff, "ago", locale);
975
+ return formatRelativeTime(Math.abs(diff), suffix, locale);
976
+ }
977
+ function timeRemaining(target, options) {
978
+ const diff = target.getTime() - Date.now();
979
+ const locale = options?.locale ?? "id";
980
+ const suffix = getSuffix(diff, "remaining", locale);
981
+ return formatRelativeTime(Math.abs(diff), suffix, locale);
982
+ }
983
+ function formatDuration(duration, options) {
984
+ const locale = options?.locale ?? "id";
985
+ const labels = LOCALE_LABELS[locale] ?? LOCALE_LABELS.id;
986
+ const parts = [];
987
+ const entries = [
988
+ ["years", duration.years],
989
+ ["months", duration.months],
990
+ ["days", duration.days],
991
+ ["hours", duration.hours],
992
+ ["minutes", duration.minutes],
993
+ ["seconds", duration.seconds]
994
+ ];
995
+ for (const [key, value] of entries) {
996
+ if (value > 0) {
997
+ const label = value === 1 ? labels[key].single : labels[key].plural;
998
+ parts.push(`${value} ${label}`);
999
+ }
1000
+ }
1001
+ if (parts.length === 0) {
1002
+ const label = labels.seconds.plural;
1003
+ return `0 ${label}`;
1004
+ }
1005
+ return parts.join(" ");
1006
+ }
1007
+ var TIMEZONE_WIB = 7;
1008
+ var TIMEZONE_WITA = 8;
1009
+ var TIMEZONE_WIT = 9;
1010
+ function toTimezone(date, offsetHours) {
1011
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1012
+ const utcMs = date.getTime() + date.getTimezoneOffset() * 6e4;
1013
+ return new Date(utcMs + offsetHours * 36e5);
1014
+ }
1015
+ function formatInTimezone(date, format2, offsetHours) {
1016
+ return formatDate(toTimezone(date, offsetHours), format2);
1017
+ }
1018
+ function isToday(date) {
1019
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1020
+ const now = /* @__PURE__ */ new Date();
1021
+ return date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate();
1022
+ }
1023
+ function isYesterday(date) {
1024
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1025
+ const yesterday = /* @__PURE__ */ new Date();
1026
+ yesterday.setDate(yesterday.getDate() - 1);
1027
+ return date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === yesterday.getDate();
1028
+ }
1029
+ function isTomorrow(date) {
1030
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1031
+ const tomorrow = /* @__PURE__ */ new Date();
1032
+ tomorrow.setDate(tomorrow.getDate() + 1);
1033
+ return date.getFullYear() === tomorrow.getFullYear() && date.getMonth() === tomorrow.getMonth() && date.getDate() === tomorrow.getDate();
1034
+ }
1035
+ function isPast(date) {
1036
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1037
+ return date.getTime() < Date.now();
1038
+ }
1039
+ function isFuture(date) {
1040
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1041
+ return date.getTime() > Date.now();
1042
+ }
1043
+ function isSameDay(date1, date2) {
1044
+ if (!isValidDate(date1) || !isValidDate(date2)) {
1045
+ throw new InvalidDateError("Invalid date provided to isSameDay");
1046
+ }
1047
+ return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
1048
+ }
1049
+ function daysInMonth(date) {
1050
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1051
+ return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
1052
+ }
1053
+ function dayOfYear(date) {
1054
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1055
+ const start = new Date(date.getFullYear(), 0, 0);
1056
+ return Math.floor((date.getTime() - start.getTime()) / MS_IN_DAY);
1057
+ }
1058
+ function weekOfYear(date) {
1059
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1060
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
1061
+ const dayNum = d.getUTCDay() || 7;
1062
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
1063
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
1064
+ const weekNum = Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
1065
+ return weekNum;
1066
+ }
1067
+ function quarter(date) {
1068
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1069
+ return Math.floor(date.getMonth() / 3) + 1;
1070
+ }
1071
+ function maxDate(dates) {
1072
+ if (dates.length === 0) throw new Error("maxDate requires at least one date");
1073
+ const ms = Math.max(...dates.map((d) => {
1074
+ if (!isValidDate(d)) throw new InvalidDateError(d);
1075
+ return d.getTime();
1076
+ }));
1077
+ return new Date(ms);
1078
+ }
1079
+ function minDate(dates) {
1080
+ if (dates.length === 0) throw new Error("minDate requires at least one date");
1081
+ const ms = Math.min(...dates.map((d) => {
1082
+ if (!isValidDate(d)) throw new InvalidDateError(d);
1083
+ return d.getTime();
1084
+ }));
1085
+ return new Date(ms);
1086
+ }
1087
+ function getNextWeekday(date, targetDay) {
1088
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1089
+ const result = new Date(date);
1090
+ const currentDay = result.getDay();
1091
+ let diff = targetDay - currentDay;
1092
+ if (diff <= 0) diff += 7;
1093
+ result.setDate(result.getDate() + diff);
1094
+ return result;
1095
+ }
1096
+ function getLastWeekday(date, targetDay) {
1097
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1098
+ const result = new Date(date);
1099
+ const currentDay = result.getDay();
1100
+ let diff = currentDay - targetDay;
1101
+ if (diff <= 0) diff += 7;
1102
+ result.setDate(result.getDate() - diff);
1103
+ return result;
1104
+ }
1105
+ function nextMonday(date) {
1106
+ return getNextWeekday(date, 1);
1107
+ }
1108
+ function nextTuesday(date) {
1109
+ return getNextWeekday(date, 2);
1110
+ }
1111
+ function nextWednesday(date) {
1112
+ return getNextWeekday(date, 3);
1113
+ }
1114
+ function nextThursday(date) {
1115
+ return getNextWeekday(date, 4);
1116
+ }
1117
+ function nextFriday(date) {
1118
+ return getNextWeekday(date, 5);
1119
+ }
1120
+ function nextSaturday(date) {
1121
+ return getNextWeekday(date, 6);
1122
+ }
1123
+ function nextSunday(date) {
1124
+ return getNextWeekday(date, 0);
1125
+ }
1126
+ function lastMonday(date) {
1127
+ return getLastWeekday(date, 1);
1128
+ }
1129
+ function lastTuesday(date) {
1130
+ return getLastWeekday(date, 2);
1131
+ }
1132
+ function lastWednesday(date) {
1133
+ return getLastWeekday(date, 3);
1134
+ }
1135
+ function lastThursday(date) {
1136
+ return getLastWeekday(date, 4);
1137
+ }
1138
+ function lastFriday(date) {
1139
+ return getLastWeekday(date, 5);
1140
+ }
1141
+ function lastSaturday(date) {
1142
+ return getLastWeekday(date, 6);
1143
+ }
1144
+ function lastSunday(date) {
1145
+ return getLastWeekday(date, 0);
1146
+ }
1147
+ function parseDuration(input) {
1148
+ const regex = /(\d+)\s*([wdhms])/g;
1149
+ let ms = 0;
1150
+ let match;
1151
+ while ((match = regex.exec(input)) !== null) {
1152
+ const val = parseInt(match[1], 10);
1153
+ switch (match[2]) {
1154
+ case "w":
1155
+ ms += val * 7 * MS_IN_DAY;
1156
+ break;
1157
+ case "d":
1158
+ ms += val * MS_IN_DAY;
1159
+ break;
1160
+ case "h":
1161
+ ms += val * MS_IN_HOUR;
1162
+ break;
1163
+ case "m":
1164
+ ms += val * MS_IN_MINUTE;
1165
+ break;
1166
+ case "s":
1167
+ ms += val * MS_IN_SECOND;
1168
+ break;
1169
+ }
1170
+ }
1171
+ return ms;
1172
+ }
1173
+ var INDONESIAN_FIXED_HOLIDAYS = [
1174
+ { name: "New Year", month: 0, day: 1 },
1175
+ { name: "Labor Day", month: 4, day: 1 },
1176
+ { name: "Pancasila Day", month: 5, day: 1 },
1177
+ { name: "Independence Day", month: 7, day: 17 },
1178
+ { name: "National Awakening Day", month: 4, day: 20 },
1179
+ { name: "National Heroes Day", month: 10, day: 10 },
1180
+ { name: "Christmas", month: 11, day: 25 }
1181
+ ];
1182
+ function computeEaster(year) {
1183
+ const a = year % 19;
1184
+ const b = Math.floor(year / 100);
1185
+ const c = year % 100;
1186
+ const d = Math.floor(b / 4);
1187
+ const e = b % 4;
1188
+ const f = Math.floor((b + 8) / 25);
1189
+ const g = Math.floor((b - f + 1) / 3);
1190
+ const h = (19 * a + b - d - g + 15) % 30;
1191
+ const i = Math.floor(c / 4);
1192
+ const k = c % 4;
1193
+ const l = (32 + 2 * e + 2 * i - h - k) % 7;
1194
+ const m = Math.floor((a + 11 * h + 22 * l) / 451);
1195
+ const month = Math.floor((h + l - 7 * m + 114) / 31);
1196
+ const day = (h + l - 7 * m + 114) % 31 + 1;
1197
+ return new Date(year, month - 1, day);
1198
+ }
1199
+ var CHINESE_NEW_YEAR = {
1200
+ 2024: { month: 1, day: 10 },
1201
+ 2025: { month: 0, day: 29 },
1202
+ 2026: { month: 1, day: 17 },
1203
+ 2027: { month: 1, day: 6 },
1204
+ 2028: { month: 0, day: 26 },
1205
+ 2029: { month: 1, day: 13 },
1206
+ 2030: { month: 2, day: 3 }
1207
+ };
1208
+ var NYEPI = {
1209
+ 2024: { month: 2, day: 11 },
1210
+ 2025: { month: 2, day: 29 },
1211
+ 2026: { month: 2, day: 19 },
1212
+ 2027: { month: 2, day: 7 },
1213
+ 2028: { month: 2, day: 26 },
1214
+ 2029: { month: 2, day: 15 },
1215
+ 2030: { month: 2, day: 5 }
1216
+ };
1217
+ var VESAK = {
1218
+ 2024: { month: 4, day: 23 },
1219
+ 2025: { month: 4, day: 12 },
1220
+ 2026: { month: 4, day: 31 },
1221
+ 2027: { month: 4, day: 20 },
1222
+ 2028: { month: 4, day: 9 },
1223
+ 2029: { month: 4, day: 28 },
1224
+ 2030: { month: 4, day: 18 }
1225
+ };
1226
+ var EID_AL_FITR = {
1227
+ 2024: [{ month: 3, day: 10 }, { month: 3, day: 11 }],
1228
+ 2025: [{ month: 2, day: 31 }, { month: 3, day: 1 }],
1229
+ 2026: [{ month: 2, day: 21 }, { month: 2, day: 22 }],
1230
+ 2027: [{ month: 2, day: 10 }, { month: 2, day: 11 }],
1231
+ 2028: [{ month: 2, day: 28 }, { month: 2, day: 29 }],
1232
+ 2029: [{ month: 2, day: 17 }, { month: 2, day: 18 }],
1233
+ 2030: [{ month: 2, day: 7 }, { month: 2, day: 8 }]
1234
+ };
1235
+ var EID_AL_ADHA = {
1236
+ 2024: { month: 5, day: 17 },
1237
+ 2025: { month: 5, day: 7 },
1238
+ 2026: { month: 4, day: 27 },
1239
+ 2027: { month: 4, day: 17 },
1240
+ 2028: { month: 5, day: 5 },
1241
+ 2029: { month: 4, day: 25 },
1242
+ 2030: { month: 4, day: 15 }
1243
+ };
1244
+ var ISLAMIC_NEW_YEAR = {
1245
+ 2024: { month: 6, day: 7 },
1246
+ 2025: { month: 5, day: 27 },
1247
+ 2026: { month: 5, day: 16 },
1248
+ 2027: { month: 5, day: 6 },
1249
+ 2028: { month: 6, day: 24 },
1250
+ 2029: { month: 6, day: 13 },
1251
+ 2030: { month: 6, day: 3 }
1252
+ };
1253
+ var PROPHETS_BIRTHDAY = {
1254
+ 2024: { month: 8, day: 16 },
1255
+ 2025: { month: 8, day: 5 },
1256
+ 2026: { month: 7, day: 26 },
1257
+ 2027: { month: 7, day: 16 },
1258
+ 2028: { month: 8, day: 3 },
1259
+ 2029: { month: 7, day: 23 },
1260
+ 2030: { month: 7, day: 13 }
1261
+ };
1262
+ var ISRA_MIRAJ = {
1263
+ 2024: { month: 1, day: 8 },
1264
+ 2025: { month: 0, day: 28 },
1265
+ 2026: { month: 0, day: 17 },
1266
+ 2027: { month: 0, day: 6 },
1267
+ 2028: { month: 0, day: 26 },
1268
+ 2029: { month: 1, day: 14 },
1269
+ 2030: { month: 1, day: 3 }
1270
+ };
1271
+ function addHolidayEntry(entries, name, month, day) {
1272
+ entries.push({ name, month, day });
1273
+ }
1274
+ function getIndonesianHolidaysForYear(year) {
1275
+ const holidays = [...INDONESIAN_FIXED_HOLIDAYS];
1276
+ const easter = computeEaster(year);
1277
+ addHolidayEntry(holidays, "Good Friday", easter.getMonth(), easter.getDate() - 2);
1278
+ addHolidayEntry(holidays, "Easter", easter.getMonth(), easter.getDate());
1279
+ const ascension = new Date(easter);
1280
+ ascension.setDate(ascension.getDate() + 39);
1281
+ addHolidayEntry(holidays, "Ascension of Jesus Christ", ascension.getMonth(), ascension.getDate());
1282
+ const cny = CHINESE_NEW_YEAR[year];
1283
+ if (cny) addHolidayEntry(holidays, "Chinese New Year", cny.month, cny.day);
1284
+ const nyepi = NYEPI[year];
1285
+ if (nyepi) addHolidayEntry(holidays, "Nyepi (Day of Silence)", nyepi.month, nyepi.day);
1286
+ const vesak = VESAK[year];
1287
+ if (vesak) addHolidayEntry(holidays, "Vesak (Buddha's Birthday)", vesak.month, vesak.day);
1288
+ const eidDays = EID_AL_FITR[year];
1289
+ if (eidDays) {
1290
+ eidDays.forEach((entry, idx) => {
1291
+ addHolidayEntry(holidays, idx === 0 ? "Eid al-Fitr" : "Eid al-Fitr (Day 2)", entry.month, entry.day);
1292
+ });
1293
+ }
1294
+ const eidAdha = EID_AL_ADHA[year];
1295
+ if (eidAdha) addHolidayEntry(holidays, "Eid al-Adha", eidAdha.month, eidAdha.day);
1296
+ const islNewYear = ISLAMIC_NEW_YEAR[year];
1297
+ if (islNewYear) addHolidayEntry(holidays, "Islamic New Year", islNewYear.month, islNewYear.day);
1298
+ const prophetBday = PROPHETS_BIRTHDAY[year];
1299
+ if (prophetBday) addHolidayEntry(holidays, "Prophet Muhammad's Birthday", prophetBday.month, prophetBday.day);
1300
+ const isra = ISRA_MIRAJ[year];
1301
+ if (isra) addHolidayEntry(holidays, "Isra' Mi'raj (Ascension of Prophet Muhammad)", isra.month, isra.day);
1302
+ return holidays;
1303
+ }
1304
+ function isHolidayIndonesia(date) {
1305
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1306
+ const year = date.getFullYear();
1307
+ const holidays = getIndonesianHolidaysForYear(year);
1308
+ for (const h of holidays) {
1309
+ if (h.month === date.getMonth() && h.day === date.getDate()) {
1310
+ return true;
1311
+ }
1312
+ }
1313
+ return false;
1314
+ }
1315
+ function getIndonesianHolidayNames(date) {
1316
+ if (!isValidDate(date)) throw new InvalidDateError(date);
1317
+ const year = date.getFullYear();
1318
+ const holidays = getIndonesianHolidaysForYear(year);
1319
+ const names = [];
1320
+ for (const h of holidays) {
1321
+ if (h.month === date.getMonth() && h.day === date.getDate()) {
1322
+ names.push(h.name);
1323
+ }
1324
+ }
1325
+ return names;
1326
+ }
613
1327
 
614
1328
  // src/crypto/index.ts
615
1329
  function hash(str) {
@@ -635,15 +1349,12 @@ function simpleHash(str) {
635
1349
  return toHex(h1) + toHex(h2) + toHex(h3) + toHex(h4);
636
1350
  }
637
1351
  function getRandomBytes(size) {
638
- const bytes = new Uint8Array(size);
639
1352
  if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
1353
+ const bytes = new Uint8Array(size);
640
1354
  crypto.getRandomValues(bytes);
641
- } else {
642
- for (let i = 0; i < size; i++) {
643
- bytes[i] = Math.floor(Math.random() * 256);
644
- }
1355
+ return bytes;
645
1356
  }
646
- return bytes;
1357
+ throw new Error("Crypto API unavailable. Cannot generate secure random bytes.");
647
1358
  }
648
1359
  function randomHex(size = 16) {
649
1360
  const bytes = getRandomBytes(size);
@@ -988,6 +1699,217 @@ function isEmpty(value) {
988
1699
  if (value !== null && typeof value === "object") return Object.keys(value).length === 0;
989
1700
  return false;
990
1701
  }
1702
+ function topoSort(items) {
1703
+ const adj = /* @__PURE__ */ new Map();
1704
+ const inDegree = /* @__PURE__ */ new Map();
1705
+ const itemMap = /* @__PURE__ */ new Map();
1706
+ for (const item of items) {
1707
+ itemMap.set(item.id, item);
1708
+ if (!adj.has(item.id)) adj.set(item.id, []);
1709
+ if (!inDegree.has(item.id)) inDegree.set(item.id, 0);
1710
+ }
1711
+ for (const item of items) {
1712
+ if (item.dependencies) {
1713
+ for (const depId of item.dependencies) {
1714
+ adj.get(depId)?.push(item.id);
1715
+ inDegree.set(item.id, (inDegree.get(item.id) ?? 0) + 1);
1716
+ }
1717
+ }
1718
+ }
1719
+ const queue = [];
1720
+ for (const [id, degree] of inDegree) {
1721
+ if (degree === 0) queue.push(id);
1722
+ }
1723
+ const sorted = [];
1724
+ while (queue.length > 0) {
1725
+ const id = queue.shift();
1726
+ sorted.push(id);
1727
+ for (const neighbor of adj.get(id) ?? []) {
1728
+ const newDegree = (inDegree.get(neighbor) ?? 1) - 1;
1729
+ inDegree.set(neighbor, newDegree);
1730
+ if (newDegree === 0) queue.push(neighbor);
1731
+ }
1732
+ }
1733
+ if (sorted.length !== items.length) {
1734
+ throw new Error("Circular dependency detected");
1735
+ }
1736
+ return sorted.map((id) => itemMap.get(id));
1737
+ }
1738
+ function slidingWindows(items, size, step = 1) {
1739
+ if (size <= 0 || items.length === 0 || step <= 0) return [];
1740
+ const result = [];
1741
+ for (let i = 0; i + size <= items.length; i += step) {
1742
+ result.push(items.slice(i, i + size));
1743
+ }
1744
+ return result;
1745
+ }
1746
+ function tumblingWindows(items, size) {
1747
+ if (size <= 0 || items.length === 0) return [];
1748
+ const result = [];
1749
+ for (let i = 0; i < items.length; i += size) {
1750
+ result.push(items.slice(i, i + size));
1751
+ }
1752
+ return result;
1753
+ }
1754
+ function deepGet(obj, path, default_) {
1755
+ const keys = path.split(".");
1756
+ let current = obj;
1757
+ for (const key of keys) {
1758
+ if (current === null || current === void 0) return default_;
1759
+ if (typeof current !== "object") return default_;
1760
+ const curObj = current;
1761
+ if (!(key in curObj)) return default_;
1762
+ current = curObj[key];
1763
+ }
1764
+ return current ?? default_;
1765
+ }
1766
+ function deepSet(obj, path, value) {
1767
+ const keys = path.split(".");
1768
+ const PROTO_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1769
+ for (const key of keys) {
1770
+ if (PROTO_KEYS.has(key)) {
1771
+ return { ...obj };
1772
+ }
1773
+ }
1774
+ const result = { ...obj };
1775
+ let current = result;
1776
+ for (let i = 0; i < keys.length - 1; i++) {
1777
+ const key = keys[i];
1778
+ const next = current[key];
1779
+ if (next === null || next === void 0 || typeof next !== "object") {
1780
+ const isArray2 = /^\d+$/.test(keys[i + 1]);
1781
+ current[key] = isArray2 ? [] : {};
1782
+ }
1783
+ current = current[key];
1784
+ }
1785
+ current[keys[keys.length - 1]] = value;
1786
+ return result;
1787
+ }
1788
+ function partition(items, predicate) {
1789
+ const pass = [];
1790
+ const fail = [];
1791
+ for (const item of items) {
1792
+ if (predicate(item)) pass.push(item);
1793
+ else fail.push(item);
1794
+ }
1795
+ return [pass, fail];
1796
+ }
1797
+ function compact(items) {
1798
+ return items.filter(Boolean);
1799
+ }
1800
+ function difference(a, b) {
1801
+ const setB = new Set(b);
1802
+ return a.filter((item) => !setB.has(item));
1803
+ }
1804
+ function intersection(a, b) {
1805
+ const setB = new Set(b);
1806
+ return a.filter((item) => setB.has(item));
1807
+ }
1808
+ function union(...arrays) {
1809
+ const set = /* @__PURE__ */ new Set();
1810
+ for (const arr of arrays) {
1811
+ for (const item of arr) {
1812
+ set.add(item);
1813
+ }
1814
+ }
1815
+ return [...set];
1816
+ }
1817
+ function zip(...arrays) {
1818
+ if (arrays.length === 0) return [];
1819
+ const minLen = Math.min(...arrays.map((a) => a.length));
1820
+ const result = [];
1821
+ for (let i = 0; i < minLen; i++) {
1822
+ const tuple = [];
1823
+ for (const arr of arrays) {
1824
+ tuple.push(arr[i]);
1825
+ }
1826
+ result.push(tuple);
1827
+ }
1828
+ return result;
1829
+ }
1830
+ function unzip(paired) {
1831
+ if (paired.length === 0) return [];
1832
+ const tupleLen = paired.reduce((max, t) => Math.max(max, t.length), 0);
1833
+ const result = Array.from({ length: tupleLen }, () => []);
1834
+ for (const tuple of paired) {
1835
+ for (let i = 0; i < tupleLen; i++) {
1836
+ result[i].push(tuple[i]);
1837
+ }
1838
+ }
1839
+ return result;
1840
+ }
1841
+ function countBy(items, keyFn) {
1842
+ const result = {};
1843
+ for (const item of items) {
1844
+ const key = keyFn(item);
1845
+ result[key] = (result[key] ?? 0) + 1;
1846
+ }
1847
+ return result;
1848
+ }
1849
+ function maxBy(items, keyFn) {
1850
+ if (items.length === 0) return void 0;
1851
+ let maxItem = items[0];
1852
+ let maxVal = keyFn(maxItem);
1853
+ for (let i = 1; i < items.length; i++) {
1854
+ const val = keyFn(items[i]);
1855
+ if (val > maxVal) {
1856
+ maxVal = val;
1857
+ maxItem = items[i];
1858
+ }
1859
+ }
1860
+ return maxItem;
1861
+ }
1862
+ function minBy(items, keyFn) {
1863
+ if (items.length === 0) return void 0;
1864
+ let minItem = items[0];
1865
+ let minVal = keyFn(minItem);
1866
+ for (let i = 1; i < items.length; i++) {
1867
+ const val = keyFn(items[i]);
1868
+ if (val < minVal) {
1869
+ minVal = val;
1870
+ minItem = items[i];
1871
+ }
1872
+ }
1873
+ return minItem;
1874
+ }
1875
+ function sumBy(items, keyFn) {
1876
+ let total = 0;
1877
+ for (const item of items) {
1878
+ total += keyFn(item);
1879
+ }
1880
+ return total;
1881
+ }
1882
+ function findIndex(items, predicate, fromIndex = 0) {
1883
+ for (let i = fromIndex; i < items.length; i++) {
1884
+ if (predicate(items[i])) return i;
1885
+ }
1886
+ return -1;
1887
+ }
1888
+ function findLast(items, predicate) {
1889
+ for (let i = items.length - 1; i >= 0; i--) {
1890
+ if (predicate(items[i])) return items[i];
1891
+ }
1892
+ return void 0;
1893
+ }
1894
+ function drop(items, n = 1) {
1895
+ return items.slice(Math.max(0, n));
1896
+ }
1897
+ function dropRight(items, n = 1) {
1898
+ return items.slice(0, Math.max(0, items.length - n));
1899
+ }
1900
+ function take(items, n = 1) {
1901
+ return items.slice(0, Math.max(0, n));
1902
+ }
1903
+ function takeRight(items, n = 1) {
1904
+ return items.slice(Math.max(0, items.length - n));
1905
+ }
1906
+ function without(items, ...values) {
1907
+ const exclude = new Set(values);
1908
+ return items.filter((item) => !exclude.has(item));
1909
+ }
1910
+ function nth(items, index) {
1911
+ return index < 0 ? items[items.length + index] : items[index];
1912
+ }
991
1913
 
992
1914
  // src/string/index.ts
993
1915
  var WORD_SPLIT_RE = /[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|\d|\b)|\d+/g;
@@ -1018,7 +1940,8 @@ function truncate(str, maxLength, suffix = "...") {
1018
1940
  return str.slice(0, Math.max(0, maxLength - suffix.length)) + suffix;
1019
1941
  }
1020
1942
  function template(str, data) {
1021
- return str.replace(/\{\{(\w+)\}\}/g, (_, key) => {
1943
+ return str.replace(/\{\{(\w+)\}\}/g, (_2, key) => {
1944
+ if (key === "__proto__" || key === "constructor" || key === "prototype") return `{{${key}}}`;
1022
1945
  const value = data[key];
1023
1946
  return value !== void 0 ? String(value) : `{{${key}}}`;
1024
1947
  });
@@ -1044,9 +1967,15 @@ function uuid() {
1044
1967
  }
1045
1968
  function nanoid(size = 21, alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-") {
1046
1969
  const len = alphabet.length;
1970
+ const bytes = new Uint8Array(size);
1971
+ if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
1972
+ crypto.getRandomValues(bytes);
1973
+ } else {
1974
+ throw new Error("Crypto API unavailable. Cannot generate secure random ID.");
1975
+ }
1047
1976
  let result = "";
1048
1977
  for (let i = 0; i < size; i++) {
1049
- result += alphabet[Math.floor(Math.random() * len)];
1978
+ result += alphabet[bytes[i] % len];
1050
1979
  }
1051
1980
  return result;
1052
1981
  }
@@ -1055,7 +1984,9 @@ var HTML_ESCAPE_MAP = {
1055
1984
  "<": "&lt;",
1056
1985
  ">": "&gt;",
1057
1986
  '"': "&quot;",
1058
- "'": "&#39;"
1987
+ "'": "&#39;",
1988
+ "`": "&#96;",
1989
+ "/": "&#x2F;"
1059
1990
  };
1060
1991
  var HTML_UNESCAPE_MAP = {
1061
1992
  "&amp;": "&",
@@ -1063,13 +1994,15 @@ var HTML_UNESCAPE_MAP = {
1063
1994
  "&gt;": ">",
1064
1995
  "&quot;": '"',
1065
1996
  "&#39;": "'",
1066
- "&#x27;": "'"
1997
+ "&#x27;": "'",
1998
+ "&#96;": "`",
1999
+ "&#x2F;": "/"
1067
2000
  };
1068
2001
  function escapeHtml(str) {
1069
- return str.replace(/[&<>"']/g, (ch) => HTML_ESCAPE_MAP[ch] ?? ch);
2002
+ return str.replace(/[&<>"'`\/]/g, (ch) => HTML_ESCAPE_MAP[ch] ?? ch);
1070
2003
  }
1071
2004
  function unescapeHtml(str) {
1072
- return str.replace(/&(?:amp|lt|gt|quot|#39|#x27);/g, (entity) => HTML_UNESCAPE_MAP[entity] ?? entity);
2005
+ return str.replace(/&(?:amp|lt|gt|quot|#39|#x27|#96|#x2F);/g, (entity) => HTML_UNESCAPE_MAP[entity] ?? entity);
1073
2006
  }
1074
2007
  function trim(str) {
1075
2008
  return str.trim();
@@ -1111,6 +2044,494 @@ function countOccurrences(str, substring) {
1111
2044
  }
1112
2045
  return count;
1113
2046
  }
2047
+ function levenshtein(a, b) {
2048
+ const an = a.length;
2049
+ const bn = b.length;
2050
+ if (an === 0) return bn;
2051
+ if (bn === 0) return an;
2052
+ if (an < bn) return levenshtein(b, a);
2053
+ let prev = new Uint32Array(bn + 1);
2054
+ let curr = new Uint32Array(bn + 1);
2055
+ for (let j = 0; j <= bn; j++) prev[j] = j;
2056
+ for (let i = 1; i <= an; i++) {
2057
+ curr[0] = i;
2058
+ for (let j = 1; j <= bn; j++) {
2059
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
2060
+ curr[j] = Math.min(
2061
+ prev[j] + 1,
2062
+ curr[j - 1] + 1,
2063
+ prev[j - 1] + cost
2064
+ );
2065
+ }
2066
+ ;
2067
+ [prev, curr] = [curr, prev];
2068
+ }
2069
+ return prev[bn];
2070
+ }
2071
+ function fuzzyMatch(str, query) {
2072
+ if (query.length === 0) return true;
2073
+ if (str.length === 0) return false;
2074
+ const sl = str.toLowerCase();
2075
+ const ql = query.toLowerCase();
2076
+ let si = 0;
2077
+ for (let qi = 0; qi < ql.length; qi++) {
2078
+ si = sl.indexOf(ql[qi], si);
2079
+ if (si === -1) return false;
2080
+ si++;
2081
+ }
2082
+ return true;
2083
+ }
2084
+ function maskString(str, options) {
2085
+ if (str.length === 0) return str;
2086
+ const maskChar = options?.char ?? "*";
2087
+ const start = options?.start ?? Math.ceil(str.length * 0.25);
2088
+ const end = options?.end ?? Math.floor(str.length * 0.75);
2089
+ if (start >= end || start < 0) return str;
2090
+ const clampedStart = Math.max(0, start);
2091
+ const clampedEnd = Math.min(str.length, end);
2092
+ return str.slice(0, clampedStart) + maskChar.repeat(clampedEnd - clampedStart) + str.slice(clampedEnd);
2093
+ }
2094
+ var SATUAN = ["", "satu", "dua", "tiga", "empat", "lima", "enam", "tujuh", "delapan", "sembilan"];
2095
+ var BELASAN = ["sepuluh", "sebelas", "dua belas", "tiga belas", "empat belas", "lima belas", "enam belas", "tujuh belas", "delapan belas", "sembilan belas"];
2096
+ var PULUHAN = ["", "", "dua puluh", "tiga puluh", "empat puluh", "lima puluh", "enam puluh", "tujuh puluh", "delapan puluh", "sembilan puluh"];
2097
+ function _terbilang(n) {
2098
+ if (n < 0) return "minus " + _terbilang(-n);
2099
+ if (n === 0) return "nol";
2100
+ if (n < 10) return SATUAN[n];
2101
+ if (n < 20) return n === 10 ? "sepuluh" : n === 11 ? "sebelas" : BELASAN[n - 10];
2102
+ if (n < 100) {
2103
+ const pul = Math.floor(n / 10);
2104
+ const sat = n % 10;
2105
+ return PULUHAN[pul] + (sat > 0 ? " " + SATUAN[sat] : "");
2106
+ }
2107
+ if (n < 1e3) {
2108
+ const ratus = Math.floor(n / 100);
2109
+ const sis2 = n % 100;
2110
+ const ratusStr = ratus === 1 ? "seratus" : SATUAN[ratus] + " ratus";
2111
+ return ratusStr + (sis2 > 0 ? " " + _terbilang(sis2) : "");
2112
+ }
2113
+ if (n < 1e6) {
2114
+ const rib = Math.floor(n / 1e3);
2115
+ const sis2 = n % 1e3;
2116
+ const ribStr = rib === 1 ? "seribu" : _terbilang(rib) + " ribu";
2117
+ return ribStr + (sis2 > 0 ? " " + _terbilang(sis2) : "");
2118
+ }
2119
+ if (n < 1e9) {
2120
+ const jut = Math.floor(n / 1e6);
2121
+ const sis2 = n % 1e6;
2122
+ return _terbilang(jut) + " juta" + (sis2 > 0 ? " " + _terbilang(sis2) : "");
2123
+ }
2124
+ if (n < 1e12) {
2125
+ const mil = Math.floor(n / 1e9);
2126
+ const sis2 = n % 1e9;
2127
+ return _terbilang(mil) + " miliar" + (sis2 > 0 ? " " + _terbilang(sis2) : "");
2128
+ }
2129
+ const tril = Math.floor(n / 1e12);
2130
+ const sis = n % 1e12;
2131
+ return _terbilang(tril) + " triliun" + (sis > 0 ? " " + _terbilang(sis) : "");
2132
+ }
2133
+ function terbilang(value) {
2134
+ if (!Number.isFinite(value)) throw new RangeError("Input must be a finite number");
2135
+ if (value > Number.MAX_SAFE_INTEGER) throw new RangeError("Input terlalu besar");
2136
+ return _terbilang(Math.floor(Math.abs(value)));
2137
+ }
2138
+ function formatRupiah(value, options) {
2139
+ return formatCurrency(value, { locale: "id-ID", currency: "IDR", notation: options?.notation });
2140
+ }
2141
+ function formatBytes(bytes, options) {
2142
+ if (bytes === 0) return "0 B";
2143
+ if (!Number.isFinite(bytes) || bytes < 0) return "0 B";
2144
+ const k = 1024;
2145
+ const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB"];
2146
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
2147
+ const dm = options?.decimals ?? (i === 0 ? 0 : 1);
2148
+ const index = Math.min(i, sizes.length - 1);
2149
+ return parseFloat((bytes / Math.pow(k, index)).toFixed(dm)) + " " + sizes[index];
2150
+ }
2151
+ function randomString(length = 16) {
2152
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
2153
+ const bytes = new Uint8Array(length);
2154
+ if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
2155
+ crypto.getRandomValues(bytes);
2156
+ } else {
2157
+ throw new Error("Crypto API unavailable. Cannot generate secure random string.");
2158
+ }
2159
+ let result = "";
2160
+ for (let i = 0; i < length; i++) {
2161
+ result += chars[bytes[i] % chars.length];
2162
+ }
2163
+ return result;
2164
+ }
2165
+ function randomBoolean() {
2166
+ return Math.random() >= 0.5;
2167
+ }
2168
+ function pluralize(count, singular) {
2169
+ if (count === 1) return singular;
2170
+ const last2 = singular[singular.length - 1];
2171
+ const lastTwo = singular.slice(-2);
2172
+ if (last2 === "s" || last2 === "x" || last2 === "z" || lastTwo === "ch" || lastTwo === "sh") {
2173
+ return singular + "es";
2174
+ }
2175
+ if (last2 === "y" && singular.length > 2 && !"aeiou".includes(singular[singular.length - 2])) {
2176
+ return singular.slice(0, -1) + "ies";
2177
+ }
2178
+ return singular + "s";
2179
+ }
2180
+ function stripHtml(str) {
2181
+ return str.replace(/<[^>]*>/g, "");
2182
+ }
2183
+ function truncateWords(str, count, suffix = "...") {
2184
+ const words2 = str.split(/\s+/).filter(Boolean);
2185
+ if (words2.length <= count) return str;
2186
+ return words2.slice(0, count).join(" ") + suffix;
2187
+ }
2188
+ function isPalindrome(str) {
2189
+ const cleaned = str.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
2190
+ if (cleaned.length <= 1) return true;
2191
+ let left = 0;
2192
+ let right = cleaned.length - 1;
2193
+ while (left < right) {
2194
+ if (cleaned[left] !== cleaned[right]) return false;
2195
+ left++;
2196
+ right--;
2197
+ }
2198
+ return true;
2199
+ }
2200
+ function isAnagram(str1, str2) {
2201
+ const clean = (s) => s.replace(/\s/g, "").toLowerCase().split("").sort().join("");
2202
+ return clean(str1) === clean(str2);
2203
+ }
2204
+ function similarity(a, b) {
2205
+ if (a === b) return 1;
2206
+ if (a.length < 2 || b.length < 2) return 0;
2207
+ const bigrams = /* @__PURE__ */ new Map();
2208
+ for (let i = 0; i < a.length - 1; i++) {
2209
+ const bg = a.slice(i, i + 2);
2210
+ bigrams.set(bg, (bigrams.get(bg) ?? 0) + 1);
2211
+ }
2212
+ let intersection2 = 0;
2213
+ for (let i = 0; i < b.length - 1; i++) {
2214
+ const bg = b.slice(i, i + 2);
2215
+ const count = bigrams.get(bg) ?? 0;
2216
+ if (count > 0) {
2217
+ bigrams.set(bg, count - 1);
2218
+ intersection2++;
2219
+ }
2220
+ }
2221
+ return 2 * intersection2 / (a.length + b.length - 2);
2222
+ }
2223
+ function dedent(str) {
2224
+ const lines = str.split("\n");
2225
+ if (lines.length === 0) return str;
2226
+ const indent = lines.reduce((min, line) => {
2227
+ if (line.trim().length === 0) return min;
2228
+ const leading = line.match(/^[ \t]*/)?.[0]?.length ?? 0;
2229
+ return min === null ? leading : Math.min(min, leading);
2230
+ }, null);
2231
+ if (indent === null || indent === 0) return str;
2232
+ return lines.map((line) => line.slice(indent)).join("\n");
2233
+ }
2234
+ function wordCount(str) {
2235
+ const match = str.match(/[a-zA-Z0-9]+(?:['\u2019][a-zA-Z]+)?/g);
2236
+ return match ? match.length : 0;
2237
+ }
2238
+ function swapCase(str) {
2239
+ let result = "";
2240
+ for (let i = 0; i < str.length; i++) {
2241
+ const ch = str[i];
2242
+ if (ch >= "a" && ch <= "z") {
2243
+ result += ch.toUpperCase();
2244
+ } else if (ch >= "A" && ch <= "Z") {
2245
+ result += ch.toLowerCase();
2246
+ } else {
2247
+ result += ch;
2248
+ }
2249
+ }
2250
+ return result;
2251
+ }
2252
+ function toCobolCase(str) {
2253
+ const words2 = splitWords(str);
2254
+ return words2.map((w) => w.toUpperCase()).join("_");
2255
+ }
2256
+ function charCount(str) {
2257
+ const result = {};
2258
+ for (let i = 0; i < str.length; i++) {
2259
+ const ch = str[i];
2260
+ result[ch] = (result[ch] ?? 0) + 1;
2261
+ }
2262
+ return result;
2263
+ }
2264
+
2265
+ // src/async/queue.ts
2266
+ var Queue = class {
2267
+ _tasks = [];
2268
+ _running = 0;
2269
+ _paused = false;
2270
+ _idleResolve = null;
2271
+ _maxConcurrency;
2272
+ constructor(options) {
2273
+ this._maxConcurrency = options?.concurrency ?? 1;
2274
+ if (this._maxConcurrency < 1) this._maxConcurrency = 1;
2275
+ }
2276
+ get pending() {
2277
+ return this._tasks.length;
2278
+ }
2279
+ get running() {
2280
+ return this._running;
2281
+ }
2282
+ add(task, options) {
2283
+ return new Promise((resolve2, reject) => {
2284
+ this._tasks.push({
2285
+ priority: options?.priority ?? 0,
2286
+ task,
2287
+ resolve: resolve2,
2288
+ reject
2289
+ });
2290
+ this._tasks.sort((a, b) => b.priority - a.priority);
2291
+ this._process();
2292
+ });
2293
+ }
2294
+ pause() {
2295
+ this._paused = true;
2296
+ }
2297
+ resume() {
2298
+ this._paused = false;
2299
+ this._process();
2300
+ }
2301
+ clear() {
2302
+ const err = new Error("Queue cleared");
2303
+ for (const t of this._tasks) t.reject(err);
2304
+ this._tasks = [];
2305
+ }
2306
+ onIdle() {
2307
+ if (this._running === 0 && this._tasks.length === 0) return Promise.resolve();
2308
+ return new Promise((resolve2) => {
2309
+ this._idleResolve = resolve2;
2310
+ });
2311
+ }
2312
+ _process() {
2313
+ if (this._paused) return;
2314
+ while (this._running < this._maxConcurrency && this._tasks.length > 0) {
2315
+ const item = this._tasks.shift();
2316
+ this._running++;
2317
+ item.task().then((result) => item.resolve(result)).catch((err) => item.reject(err)).finally(() => {
2318
+ this._running--;
2319
+ this._process();
2320
+ if (this._running === 0 && this._tasks.length === 0 && this._idleResolve) {
2321
+ this._idleResolve();
2322
+ this._idleResolve = null;
2323
+ }
2324
+ });
2325
+ }
2326
+ }
2327
+ };
2328
+
2329
+ // src/async/semaphore.ts
2330
+ var Semaphore = class {
2331
+ _available;
2332
+ _waiting = [];
2333
+ constructor(concurrency) {
2334
+ if (concurrency < 1) throw new RangeError("Semaphore concurrency must be >= 1");
2335
+ this._available = concurrency;
2336
+ }
2337
+ get available() {
2338
+ return this._available;
2339
+ }
2340
+ acquire() {
2341
+ if (this._available > 0) {
2342
+ this._available--;
2343
+ return Promise.resolve(this._release.bind(this));
2344
+ }
2345
+ return new Promise((resolve2) => {
2346
+ this._waiting.push(() => {
2347
+ this._available--;
2348
+ resolve2(this._release.bind(this));
2349
+ });
2350
+ });
2351
+ }
2352
+ async use(fn) {
2353
+ const release = await this.acquire();
2354
+ try {
2355
+ return await fn();
2356
+ } finally {
2357
+ release();
2358
+ }
2359
+ }
2360
+ _release() {
2361
+ this._available++;
2362
+ if (this._waiting.length > 0) {
2363
+ const next = this._waiting.shift();
2364
+ if (next) next();
2365
+ }
2366
+ }
2367
+ };
2368
+
2369
+ // src/async/memoize.ts
2370
+ function memoizeAsync(fn, options) {
2371
+ const {
2372
+ ttl = 6e4,
2373
+ staleWhileRevalidate = false,
2374
+ maxSize = 100,
2375
+ resolver = (...args) => JSON.stringify(args)
2376
+ } = options ?? {};
2377
+ const cache = /* @__PURE__ */ new Map();
2378
+ const memoized = (async (...args) => {
2379
+ const key = resolver(...args);
2380
+ const now = Date.now();
2381
+ const entry = cache.get(key);
2382
+ if (entry && now - entry.timestamp < ttl) {
2383
+ return entry.value;
2384
+ }
2385
+ if (entry && staleWhileRevalidate && now - entry.timestamp >= ttl) {
2386
+ if (entry.promise) {
2387
+ return entry.value;
2388
+ }
2389
+ entry.promise = fn(...args).then((result2) => {
2390
+ entry.value = result2;
2391
+ entry.timestamp = now;
2392
+ entry.promise = void 0;
2393
+ return result2;
2394
+ }).catch((err) => {
2395
+ entry.promise = void 0;
2396
+ throw err;
2397
+ });
2398
+ return entry.value;
2399
+ }
2400
+ const result = await fn(...args);
2401
+ cache.set(key, { value: result, timestamp: now });
2402
+ if (cache.size > maxSize) {
2403
+ const firstKey = cache.keys().next().value;
2404
+ if (firstKey !== void 0) cache.delete(firstKey);
2405
+ }
2406
+ return result;
2407
+ });
2408
+ memoized.cache = cache;
2409
+ memoized.clear = () => cache.clear();
2410
+ return memoized;
2411
+ }
2412
+
2413
+ // src/async/ratelimit.ts
2414
+ var RateLimiter = class {
2415
+ _maxRequests;
2416
+ _perWindow;
2417
+ _timestamps = [];
2418
+ constructor(options) {
2419
+ if (options.maxRequests < 1) throw new RangeError("maxRequests must be >= 1");
2420
+ if (options.perWindow < 1) throw new RangeError("perWindow must be >= 1");
2421
+ this._maxRequests = options.maxRequests;
2422
+ this._perWindow = options.perWindow;
2423
+ }
2424
+ _prune() {
2425
+ const now = Date.now();
2426
+ const cutoff = now - this._perWindow;
2427
+ while (this._timestamps.length > 0) {
2428
+ const ts = this._timestamps[0];
2429
+ if (ts === void 0 || ts > cutoff) break;
2430
+ this._timestamps.shift();
2431
+ }
2432
+ }
2433
+ /**
2434
+ * Check if a request is allowed without waiting.
2435
+ */
2436
+ tryAcquire() {
2437
+ this._prune();
2438
+ if (this._timestamps.length < this._maxRequests) {
2439
+ this._timestamps.push(Date.now());
2440
+ return true;
2441
+ }
2442
+ return false;
2443
+ }
2444
+ /**
2445
+ * Wait until a request is allowed.
2446
+ */
2447
+ async acquire() {
2448
+ while (true) {
2449
+ this._prune();
2450
+ if (this._timestamps.length < this._maxRequests) {
2451
+ this._timestamps.push(Date.now());
2452
+ return;
2453
+ }
2454
+ const oldest = this._timestamps[0] ?? Date.now();
2455
+ const waitMs = oldest + this._perWindow - Date.now();
2456
+ if (waitMs > 0) {
2457
+ await new Promise((resolve2) => setTimeout(resolve2, waitMs));
2458
+ }
2459
+ }
2460
+ }
2461
+ /**
2462
+ * Current number of pending requests in the window.
2463
+ */
2464
+ get pending() {
2465
+ this._prune();
2466
+ return this._timestamps.length;
2467
+ }
2468
+ };
2469
+
2470
+ // src/async/mutex.ts
2471
+ var Mutex = class {
2472
+ _locked = false;
2473
+ _waiting = [];
2474
+ /**
2475
+ * Acquire the lock. Returns a release function to be called when done.
2476
+ */
2477
+ acquire() {
2478
+ if (!this._locked) {
2479
+ this._locked = true;
2480
+ return Promise.resolve(this._release.bind(this));
2481
+ }
2482
+ return new Promise((resolve2) => {
2483
+ this._waiting.push(() => {
2484
+ resolve2(this._release.bind(this));
2485
+ });
2486
+ });
2487
+ }
2488
+ /**
2489
+ * Run a function with the lock held and automatically release it.
2490
+ */
2491
+ async use(fn) {
2492
+ const release = await this.acquire();
2493
+ try {
2494
+ return await fn();
2495
+ } finally {
2496
+ release();
2497
+ }
2498
+ }
2499
+ /**
2500
+ * Whether the mutex is currently locked.
2501
+ */
2502
+ get locked() {
2503
+ return this._locked;
2504
+ }
2505
+ _release() {
2506
+ if (this._waiting.length > 0) {
2507
+ const next = this._waiting.shift();
2508
+ if (next) next();
2509
+ } else {
2510
+ this._locked = false;
2511
+ }
2512
+ }
2513
+ };
2514
+
2515
+ // src/async/batch.ts
2516
+ async function batch(items, batchSize, fn) {
2517
+ if (batchSize < 1) throw new RangeError("batchSize must be >= 1");
2518
+ const results = [];
2519
+ for (let i = 0; i < items.length; i += batchSize) {
2520
+ const chunk2 = items.slice(i, i + batchSize);
2521
+ const batchResults = await fn(chunk2);
2522
+ results.push(...batchResults);
2523
+ }
2524
+ return results;
2525
+ }
2526
+
2527
+ // src/async/waterfall.ts
2528
+ async function waterfall(tasks, initial) {
2529
+ let result = initial;
2530
+ for (const task of tasks) {
2531
+ result = await task(result);
2532
+ }
2533
+ return result;
2534
+ }
1114
2535
 
1115
2536
  // src/async/index.ts
1116
2537
  function sleep(ms) {
@@ -1118,7 +2539,7 @@ function sleep(ms) {
1118
2539
  }
1119
2540
  async function timeout(promise, ms, errorMessage) {
1120
2541
  let timer;
1121
- const timeoutPromise = new Promise((_, reject) => {
2542
+ const timeoutPromise = new Promise((_2, reject) => {
1122
2543
  timer = setTimeout(() => reject(new Error(errorMessage ?? `Promise timed out after ${ms}ms`)), ms);
1123
2544
  });
1124
2545
  try {
@@ -1208,6 +2629,7 @@ function parseCsv(input, options) {
1208
2629
  return body.map((row) => {
1209
2630
  const record = {};
1210
2631
  for (let i = 0; i < head.length; i++) {
2632
+ if (head[i] === "__proto__" || head[i] === "constructor" || head[i] === "prototype") continue;
1211
2633
  record[head[i]] = row[i] ?? "";
1212
2634
  }
1213
2635
  return record;
@@ -1348,9 +2770,7 @@ function assertType(value, guard, message) {
1348
2770
  function ensureArray(value) {
1349
2771
  return Array.isArray(value) ? value : [value];
1350
2772
  }
1351
- function castArray(value) {
1352
- return ensureArray(value);
1353
- }
2773
+ var castArray = ensureArray;
1354
2774
  function getType2(value) {
1355
2775
  if (value === null) return "null";
1356
2776
  if (value === void 0) return "undefined";
@@ -1668,27 +3088,40 @@ async function scanProject(config) {
1668
3088
  }
1669
3089
 
1670
3090
  // src/dep-exray/reporter/index.ts
1671
- import pc from "picocolors";
3091
+ var _ = {
3092
+ reset: "\x1B[0m",
3093
+ bold: "\x1B[1m",
3094
+ dim: "\x1B[2m",
3095
+ red: "\x1B[31m",
3096
+ green: "\x1B[32m",
3097
+ yellow: "\x1B[33m",
3098
+ blue: "\x1B[34m",
3099
+ cyan: "\x1B[36m",
3100
+ white: "\x1B[37m"
3101
+ };
3102
+ function style(text, codes) {
3103
+ return codes.join("") + text + _.reset;
3104
+ }
1672
3105
  function severityColor(severity) {
1673
3106
  switch (severity) {
1674
3107
  case "critical":
1675
- return pc.bold(pc.red(severity.toUpperCase()));
3108
+ return style(severity.toUpperCase(), [_.bold, _.red]);
1676
3109
  case "high":
1677
- return pc.red(severity.toUpperCase());
3110
+ return style(severity.toUpperCase(), [_.red]);
1678
3111
  case "medium":
1679
- return pc.yellow(severity.toUpperCase());
3112
+ return style(severity.toUpperCase(), [_.yellow]);
1680
3113
  case "low":
1681
- return pc.dim(severity.toUpperCase());
3114
+ return style(severity.toUpperCase(), [_.dim]);
1682
3115
  }
1683
3116
  }
1684
3117
  function confidenceIcon(confidence) {
1685
3118
  switch (confidence) {
1686
3119
  case "high":
1687
- return pc.green("\u25CF");
3120
+ return style("\u25CF", [_.green]);
1688
3121
  case "medium":
1689
- return pc.yellow("\u25CF");
3122
+ return style("\u25CF", [_.yellow]);
1690
3123
  case "low":
1691
- return pc.red("\u25CF");
3124
+ return style("\u25CF", [_.red]);
1692
3125
  }
1693
3126
  }
1694
3127
  function generateReport(result, jsonOutput) {
@@ -1696,46 +3129,47 @@ function generateReport(result, jsonOutput) {
1696
3129
  return JSON.stringify(result, null, 2);
1697
3130
  }
1698
3131
  const lines = [];
1699
- lines.push(pc.bold(pc.cyan(`\u250C${"\u2500".repeat(58)}\u2510`)));
1700
- lines.push(pc.bold(pc.cyan(`\u2502${" ".repeat(18)}dep-exray Report${" ".repeat(21)}\u2502`)));
1701
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
1702
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.white("\u{1F4E6} PROJECT:")} ${pc.bold(result.projectName)}${" ".repeat(Math.max(1, 47 - result.projectName.length))}\u2502`)));
1703
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.white("\u{1F4CA} DEPENDENCIES:")} ${pc.bold(String(result.directDeps))} direct + ${pc.bold(String(result.transitiveDeps))} transitive${" ".repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}\u2502`)));
1704
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.white("\u{1F4BE} TOTAL SIZE:")} ${pc.bold(result.totalEstimatedSize)}${" ".repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}\u2502`)));
1705
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
3132
+ const t = (text, codes = [_.cyan]) => style(text, [_.bold, ...codes]);
3133
+ lines.push(t(`\u250C${"\u2500".repeat(58)}\u2510`));
3134
+ lines.push(t(`\u2502${" ".repeat(18)}dep-exray Report${" ".repeat(21)}\u2502`));
3135
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
3136
+ lines.push(t(`\u2502 ${style("\u{1F4E6} PROJECT:", [_.white])} ${style(result.projectName, [_.bold])}${" ".repeat(Math.max(1, 47 - result.projectName.length))}\u2502`));
3137
+ lines.push(t(`\u2502 ${style("\u{1F4CA} DEPENDENCIES:", [_.white])} ${style(String(result.directDeps), [_.bold])} direct + ${style(String(result.transitiveDeps), [_.bold])} transitive${" ".repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}\u2502`));
3138
+ lines.push(t(`\u2502 ${style("\u{1F4BE} TOTAL SIZE:", [_.white])} ${style(result.totalEstimatedSize, [_.bold])}${" ".repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}\u2502`));
3139
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
1706
3140
  if (result.highImpactReplacements.length > 0) {
1707
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.green("\u{1F7E2}")} ${pc.bold(pc.green("HIGH IMPACT REPLACEMENTS"))}${" ".repeat(23)}\u2502`)));
3141
+ lines.push(t(`\u2502 ${style("\u{1F7E2}", [_.green])} ${style("HIGH IMPACT REPLACEMENTS", [_.bold, _.green])}${" ".repeat(23)}\u2502`));
1708
3142
  for (const item of result.highImpactReplacements) {
1709
- const autoPr = item.autoPrReady ? pc.green("\u2713 Auto-PR ready") : pc.dim("Manual review needed");
3143
+ const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
1710
3144
  const confIcon = confidenceIcon(item.confidence);
1711
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
1712
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u2717")} ${pc.bold(item.packageName)} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`)));
1713
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${pc.cyan(item.replacement)}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`)));
1714
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2514\u2500")} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`)));
3145
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
3146
+ lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
3147
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
3148
+ lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
1715
3149
  }
1716
3150
  }
1717
3151
  if (result.mediumImpactReplacements.length > 0) {
1718
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
1719
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.yellow("\u{1F7E1}")} ${pc.bold(pc.yellow("MEDIUM IMPACT REPLACEMENTS"))}${" ".repeat(20)}\u2502`)));
3152
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
3153
+ lines.push(t(`\u2502 ${style("\u{1F7E1}", [_.yellow])} ${style("MEDIUM IMPACT REPLACEMENTS", [_.bold, _.yellow])}${" ".repeat(20)}\u2502`));
1720
3154
  for (const item of result.mediumImpactReplacements) {
1721
- const autoPr = item.autoPrReady ? pc.green("\u2713 Auto-PR ready") : pc.dim("Manual review needed");
3155
+ const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
1722
3156
  const confIcon = confidenceIcon(item.confidence);
1723
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
1724
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u2717")} ${pc.bold(item.packageName)} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`)));
1725
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${pc.cyan(item.replacement)}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`)));
1726
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2514\u2500")} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`)));
3157
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
3158
+ lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
3159
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
3160
+ lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
1727
3161
  }
1728
3162
  }
1729
3163
  if (result.securityIssues.length > 0) {
1730
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
1731
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u{1F534}")} ${pc.bold(pc.red("SECURITY ISSUES"))}${" ".repeat(33)}\u2502`)));
3164
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
3165
+ lines.push(t(`\u2502 ${style("\u{1F534}", [_.red])} ${style("SECURITY ISSUES", [_.bold, _.red])}${" ".repeat(33)}\u2502`));
1732
3166
  for (const issue of result.securityIssues) {
1733
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
1734
- lines.push(pc.bold(pc.cyan(`\u2502 ${severityColor(issue.severity)} ${pc.bold(issue.cveId)} in ${issue.packageName}${" ".repeat(Math.max(1, 40 - issue.packageName.length))}\u2502`)));
1735
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${issue.fix}${" ".repeat(Math.max(1, 52 - issue.fix.length))}\u2502`)));
3167
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
3168
+ lines.push(t(`\u2502 ${severityColor(issue.severity)} ${style(issue.cveId, [_.bold])} in ${issue.packageName}${" ".repeat(Math.max(1, 40 - issue.packageName.length))}\u2502`));
3169
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${issue.fix}${" ".repeat(Math.max(1, 52 - issue.fix.length))}\u2502`));
1736
3170
  }
1737
3171
  }
1738
- lines.push(pc.bold(pc.cyan(`\u2514${"\u2500".repeat(58)}\u2518`)));
3172
+ lines.push(t(`\u2514${"\u2500".repeat(58)}\u2518`));
1739
3173
  return lines.join("\n");
1740
3174
  }
1741
3175
 
@@ -2168,6 +3602,29 @@ function isNoRekening(value) {
2168
3602
  return true;
2169
3603
  }
2170
3604
 
3605
+ // src/validation/isNoSIM.ts
3606
+ function isNoSIM(value) {
3607
+ const digits = value.replace(/\D/g, "");
3608
+ return digits.length === 12;
3609
+ }
3610
+
3611
+ // src/validation/isPassport.ts
3612
+ function isPassport(value) {
3613
+ return /^[A-Za-z]{2}\d{7}$/.test(value.trim());
3614
+ }
3615
+
3616
+ // src/validation/isNoBPJS.ts
3617
+ function isNoBPJS(value) {
3618
+ const digits = value.replace(/\D/g, "");
3619
+ return digits.length === 13;
3620
+ }
3621
+
3622
+ // src/validation/isNoKK.ts
3623
+ function isNoKK(value) {
3624
+ const digits = value.replace(/\D/g, "");
3625
+ return digits.length === 16;
3626
+ }
3627
+
2171
3628
  // src/error/createError.ts
2172
3629
  var defaultStatus = {
2173
3630
  "BAD_REQUEST": 400,
@@ -2531,6 +3988,98 @@ function meetsWCAG(hex1, hex2, level) {
2531
3988
  const threshold = level === "AAA" ? 7 : 4.5;
2532
3989
  return ratio >= threshold;
2533
3990
  }
3991
+ function isValidHex(value) {
3992
+ return /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value);
3993
+ }
3994
+ function hexToHsl(hex) {
3995
+ const rgb = hexToRgb(hex);
3996
+ if (!rgb) return null;
3997
+ const r = rgb.r / 255;
3998
+ const g = rgb.g / 255;
3999
+ const b = rgb.b / 255;
4000
+ const max = Math.max(r, g, b);
4001
+ const min = Math.min(r, g, b);
4002
+ const l = (max + min) / 2;
4003
+ if (max === min) return { h: 0, s: 0, l: Math.round(l * 100) };
4004
+ const d = max - min;
4005
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
4006
+ let h = 0;
4007
+ switch (max) {
4008
+ case r:
4009
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
4010
+ break;
4011
+ case g:
4012
+ h = ((b - r) / d + 2) / 6;
4013
+ break;
4014
+ case b:
4015
+ h = ((r - g) / d + 4) / 6;
4016
+ break;
4017
+ }
4018
+ return {
4019
+ h: Math.round(h * 360),
4020
+ s: Math.round(s * 100),
4021
+ l: Math.round(l * 100)
4022
+ };
4023
+ }
4024
+ function hslToHex(h, s, l) {
4025
+ const hue = h / 360;
4026
+ const sat = s / 100;
4027
+ const lig = l / 100;
4028
+ if (sat === 0) {
4029
+ const val = Math.round(lig * 255);
4030
+ return rgbToHex(val, val, val);
4031
+ }
4032
+ const hue2rgb = (p2, q2, t) => {
4033
+ let tt = t;
4034
+ if (tt < 0) tt += 1;
4035
+ if (tt > 1) tt -= 1;
4036
+ if (tt < 1 / 6) return p2 + (q2 - p2) * 6 * tt;
4037
+ if (tt < 1 / 2) return q2;
4038
+ if (tt < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - tt) * 6;
4039
+ return p2;
4040
+ };
4041
+ const q = lig < 0.5 ? lig * (1 + sat) : lig + sat - lig * sat;
4042
+ const p = 2 * lig - q;
4043
+ return rgbToHex(
4044
+ Math.round(hue2rgb(p, q, hue + 1 / 3) * 255),
4045
+ Math.round(hue2rgb(p, q, hue) * 255),
4046
+ Math.round(hue2rgb(p, q, hue - 1 / 3) * 255)
4047
+ );
4048
+ }
4049
+ function mix(color1, color2, weight = 0.5) {
4050
+ const rgb1 = hexToRgb(color1);
4051
+ const rgb2 = hexToRgb(color2);
4052
+ if (!rgb1 || !rgb2) return color1;
4053
+ const w = Math.max(0, Math.min(1, weight));
4054
+ const lerp2 = (a, b) => Math.floor(a + (b - a) * w);
4055
+ return rgbToHex(lerp2(rgb1.r, rgb2.r), lerp2(rgb1.g, rgb2.g), lerp2(rgb1.b, rgb2.b));
4056
+ }
4057
+ function randomColor() {
4058
+ const r = Math.floor(Math.random() * 256);
4059
+ const g = Math.floor(Math.random() * 256);
4060
+ const b = Math.floor(Math.random() * 256);
4061
+ return rgbToHex(r, g, b);
4062
+ }
4063
+ function isLight(hex) {
4064
+ const rgb = hexToRgb(hex);
4065
+ if (!rgb) return false;
4066
+ return (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255 > 0.5;
4067
+ }
4068
+ function isDark(hex) {
4069
+ return !isLight(hex);
4070
+ }
4071
+ function complementary(hex) {
4072
+ const hsl = hexToHsl(hex);
4073
+ if (!hsl) return hex;
4074
+ return hslToHex((hsl.h + 180) % 360, hsl.s, hsl.l);
4075
+ }
4076
+ function alpha(hex, opacity) {
4077
+ const rgb = hexToRgb(hex);
4078
+ if (!rgb) return hex;
4079
+ const a = Math.max(0, Math.min(1, opacity));
4080
+ const alphaHex = Math.round(a * 255).toString(16).padStart(2, "0");
4081
+ return rgbToHex(rgb.r, rgb.g, rgb.b) + alphaHex;
4082
+ }
2534
4083
  export {
2535
4084
  DivisionByZeroError,
2536
4085
  InvalidDateError,
@@ -2538,6 +4087,13 @@ export {
2538
4087
  KNOWN_MAPPINGS,
2539
4088
  Logger,
2540
4089
  MultiError,
4090
+ Mutex,
4091
+ Queue,
4092
+ RateLimiter,
4093
+ Semaphore,
4094
+ TIMEZONE_WIB,
4095
+ TIMEZONE_WIT,
4096
+ TIMEZONE_WITA,
2541
4097
  TypedError,
2542
4098
  add,
2543
4099
  addBusinessDays,
@@ -2545,6 +4101,7 @@ export {
2545
4101
  addMonths,
2546
4102
  addYears,
2547
4103
  allSettledMap,
4104
+ alpha,
2548
4105
  analyzeUsage,
2549
4106
  approxEqual,
2550
4107
  assertDefined,
@@ -2553,18 +4110,26 @@ export {
2553
4110
  base64Decode,
2554
4111
  base64Encode,
2555
4112
  basename,
4113
+ batch,
2556
4114
  calculateAge,
2557
4115
  camelCase,
2558
4116
  capitalize,
2559
4117
  castArray,
2560
4118
  ceil,
4119
+ charCount,
2561
4120
  checksum,
2562
4121
  chunk,
2563
4122
  clamp,
2564
4123
  collectErrors,
4124
+ combinations,
4125
+ compact,
4126
+ complementary,
4127
+ compose,
2565
4128
  consoleTransport,
2566
4129
  constantTimeEqual,
2567
4130
  contrastRatio,
4131
+ correlation,
4132
+ countBy,
2568
4133
  countOccurrences,
2569
4134
  createBufferedTransport,
2570
4135
  createConsoleTransport,
@@ -2573,12 +4138,21 @@ export {
2573
4138
  createJsonTransport,
2574
4139
  darken,
2575
4140
  dateDiff,
4141
+ dayOfYear,
4142
+ daysInMonth,
2576
4143
  debounce,
4144
+ dedent,
2577
4145
  deepClone,
4146
+ deepEqual,
4147
+ deepGet,
2578
4148
  deepMerge,
4149
+ deepSet,
2579
4150
  deferred,
4151
+ difference,
2580
4152
  dirname,
2581
4153
  div,
4154
+ drop,
4155
+ dropRight,
2582
4156
  endOfDay,
2583
4157
  endOfMonth,
2584
4158
  endOfYear,
@@ -2588,63 +4162,125 @@ export {
2588
4162
  envInt,
2589
4163
  escapeHtml,
2590
4164
  extname,
4165
+ factorial,
4166
+ findIndex,
4167
+ findLast,
2591
4168
  first,
2592
4169
  flatten,
2593
4170
  floor,
2594
4171
  format,
4172
+ formatBytes,
4173
+ formatCurrency,
2595
4174
  formatDate,
4175
+ formatDuration,
4176
+ formatInTimezone,
4177
+ formatRupiah,
4178
+ fuzzyMatch,
4179
+ gcd,
2596
4180
  generateOTP,
2597
4181
  generateReport,
2598
4182
  generateToken,
4183
+ geometricMean,
4184
+ getIndonesianHolidayNames,
2599
4185
  getType2 as getType,
2600
4186
  groupBy,
2601
4187
  hash,
4188
+ hexToHsl,
2602
4189
  hexToRgb,
4190
+ hslToHex,
2603
4191
  identity,
2604
4192
  inRange,
4193
+ intersection,
2605
4194
  isAbsolute,
2606
4195
  isAfter,
4196
+ isAnagram,
2607
4197
  isArray,
2608
4198
  isBefore,
2609
4199
  isBetween,
2610
4200
  isBoolean,
2611
4201
  isBusinessDay,
4202
+ isDark,
2612
4203
  isDate,
2613
4204
  isEmail,
2614
4205
  isEmpty,
4206
+ isEven,
2615
4207
  isFunction,
4208
+ isFuture,
4209
+ isHolidayIndonesia,
2616
4210
  isKodepos,
2617
4211
  isLeapYear,
4212
+ isLight,
2618
4213
  isMap,
2619
4214
  isNIK,
2620
4215
  isNPWP,
2621
4216
  isNil,
4217
+ isNoBPJS,
4218
+ isNoKK,
2622
4219
  isNoRekening,
4220
+ isNoSIM,
2623
4221
  isNull,
2624
4222
  isNumber,
2625
4223
  isObject,
4224
+ isOdd,
4225
+ isPalindrome,
4226
+ isPassport,
4227
+ isPast,
2626
4228
  isPhone,
2627
4229
  isPlatNomor,
4230
+ isPrime,
2628
4231
  isPromise,
2629
4232
  isRegExp,
4233
+ isSameDay,
2630
4234
  isSet,
2631
4235
  isString,
4236
+ isToday,
4237
+ isTomorrow,
2632
4238
  isTypedError,
2633
4239
  isURL,
2634
4240
  isUndefined,
4241
+ isValidHex,
2635
4242
  isWeekend,
4243
+ isYesterday,
2636
4244
  join,
2637
4245
  kebabCase,
2638
4246
  keyBy,
2639
4247
  last,
4248
+ lastFriday,
4249
+ lastMonday,
4250
+ lastSaturday,
4251
+ lastSunday,
4252
+ lastThursday,
4253
+ lastTuesday,
4254
+ lastWednesday,
4255
+ lcm,
4256
+ lerp,
4257
+ levenshtein,
2640
4258
  lighten,
2641
4259
  logger,
4260
+ mapRange,
4261
+ maskString,
4262
+ maxBy,
4263
+ maxDate,
4264
+ median,
2642
4265
  meetsWCAG,
2643
4266
  memoize,
4267
+ memoizeAsync,
4268
+ minBy,
4269
+ minDate,
4270
+ mix,
4271
+ mode,
2644
4272
  mul,
2645
4273
  nanoid,
4274
+ nextFriday,
4275
+ nextMonday,
4276
+ nextSaturday,
4277
+ nextSunday,
4278
+ nextThursday,
4279
+ nextTuesday,
4280
+ nextWednesday,
2646
4281
  noop,
2647
4282
  normalize,
4283
+ nth,
2648
4284
  omit,
2649
4285
  once,
2650
4286
  orderBy,
@@ -2655,14 +4291,26 @@ export {
2655
4291
  parse,
2656
4292
  parseCsv,
2657
4293
  parseDate,
4294
+ parseDuration,
2658
4295
  parseNIK,
4296
+ partition,
2659
4297
  pascalCase,
4298
+ percentageOf,
4299
+ percentile,
4300
+ permutations,
2660
4301
  pick,
4302
+ pipe,
2661
4303
  pipeline,
2662
4304
  pluck,
4305
+ pluralize,
4306
+ quarter,
2663
4307
  raceWithTimeout,
4308
+ randomBoolean,
4309
+ randomColor,
2664
4310
  randomHex,
2665
4311
  randomInt,
4312
+ randomString,
4313
+ range,
2666
4314
  relative,
2667
4315
  resolve,
2668
4316
  retry,
@@ -2673,31 +4321,58 @@ export {
2673
4321
  safeJsonParse,
2674
4322
  sample,
2675
4323
  sampleSize,
4324
+ sampleStddev,
2676
4325
  scanProject,
2677
4326
  shuffle,
4327
+ similarity,
2678
4328
  simpleHash,
2679
4329
  sleep,
4330
+ slidingWindows,
2680
4331
  slugify,
2681
4332
  snakeCase,
2682
4333
  sortBy,
2683
4334
  startOfDay,
2684
4335
  startOfMonth,
2685
4336
  startOfYear,
4337
+ stddev,
2686
4338
  stringifyCsv,
4339
+ stripHtml,
2687
4340
  sub,
2688
4341
  sum,
4342
+ sumBy,
4343
+ swapCase,
4344
+ take,
4345
+ takeRight,
2689
4346
  template,
4347
+ terbilang,
2690
4348
  throttle,
4349
+ timeAgo,
4350
+ timeRemaining,
2691
4351
  timeout,
4352
+ toCobolCase,
4353
+ toDegrees,
4354
+ toRadians,
4355
+ toTimezone,
4356
+ topoSort,
2692
4357
  trim,
2693
4358
  trimEnd,
2694
4359
  trimStart,
2695
4360
  truncate,
4361
+ truncateWords,
4362
+ tumblingWindows,
2696
4363
  unescapeHtml,
4364
+ union,
2697
4365
  uniq,
2698
4366
  uniqueBy,
4367
+ unzip,
2699
4368
  uuid,
4369
+ waterfall,
4370
+ weekOfYear,
4371
+ weightedAverage,
4372
+ without,
4373
+ wordCount,
2700
4374
  words,
2701
- xorCipher
4375
+ xorCipher,
4376
+ zip
2702
4377
  };
2703
4378
  //# sourceMappingURL=index.js.map