@ztimson/utils 0.27.3 → 0.27.5
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/cache.d.ts +8 -2
- package/dist/index.cjs +157 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +157 -66
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cache.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export type CacheOptions = {
|
|
|
9
9
|
} | string;
|
|
10
10
|
/** Keep or delete cached items once expired, defaults to delete */
|
|
11
11
|
expiryPolicy?: 'delete' | 'keep';
|
|
12
|
+
/** Least Recently Used size limit */
|
|
13
|
+
sizeLimit?: number;
|
|
12
14
|
};
|
|
13
15
|
export type CachedValue<T> = T & {
|
|
14
16
|
_expired?: boolean;
|
|
@@ -19,12 +21,14 @@ export type CachedValue<T> = T & {
|
|
|
19
21
|
export declare class Cache<K extends string | number | symbol, T> {
|
|
20
22
|
readonly key?: keyof T | undefined;
|
|
21
23
|
readonly options: CacheOptions;
|
|
24
|
+
private _loading;
|
|
22
25
|
private store;
|
|
26
|
+
private timers;
|
|
27
|
+
private lruOrder;
|
|
23
28
|
/** Support index lookups */
|
|
24
29
|
[key: string | number | symbol]: CachedValue<T> | any;
|
|
25
30
|
/** Whether cache is complete */
|
|
26
31
|
complete: boolean;
|
|
27
|
-
private _loading;
|
|
28
32
|
/** Await initial loading */
|
|
29
33
|
loading: Promise<void>;
|
|
30
34
|
/**
|
|
@@ -35,6 +39,8 @@ export declare class Cache<K extends string | number | symbol, T> {
|
|
|
35
39
|
constructor(key?: keyof T | undefined, options?: CacheOptions);
|
|
36
40
|
private getKey;
|
|
37
41
|
private save;
|
|
42
|
+
private clearTimer;
|
|
43
|
+
private touchLRU;
|
|
38
44
|
/**
|
|
39
45
|
* Get all cached items
|
|
40
46
|
* @return {T[]} Array of items
|
|
@@ -109,5 +115,5 @@ export declare class Cache<K extends string | number | symbol, T> {
|
|
|
109
115
|
* Get all cached items
|
|
110
116
|
* @return {T[]} Array of items
|
|
111
117
|
*/
|
|
112
|
-
values: CachedValue<T>[];
|
|
118
|
+
values: (expired?: boolean) => CachedValue<T>[];
|
|
113
119
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -456,17 +456,19 @@ ${opts.message || this.desc}`;
|
|
|
456
456
|
* @param options
|
|
457
457
|
*/
|
|
458
458
|
constructor(key, options = {}) {
|
|
459
|
-
__publicField(this, "
|
|
459
|
+
__publicField(this, "_loading");
|
|
460
|
+
__publicField(this, "store", /* @__PURE__ */ new Map());
|
|
461
|
+
__publicField(this, "timers", /* @__PURE__ */ new Map());
|
|
462
|
+
__publicField(this, "lruOrder", []);
|
|
460
463
|
/** Whether cache is complete */
|
|
461
464
|
__publicField(this, "complete", false);
|
|
462
|
-
__publicField(this, "_loading");
|
|
463
465
|
/** Await initial loading */
|
|
464
466
|
__publicField(this, "loading", new Promise((r) => this._loading = r));
|
|
465
467
|
/**
|
|
466
468
|
* Get all cached items
|
|
467
469
|
* @return {T[]} Array of items
|
|
468
470
|
*/
|
|
469
|
-
__publicField(this, "values", this.all
|
|
471
|
+
__publicField(this, "values", this.all);
|
|
470
472
|
var _a, _b, _c, _d;
|
|
471
473
|
this.key = key;
|
|
472
474
|
this.options = options;
|
|
@@ -478,14 +480,18 @@ ${opts.message || this.desc}`;
|
|
|
478
480
|
const persists = this.options.persistentStorage;
|
|
479
481
|
const table = await persists.storage.createTable({ name: persists.key, key: this.key });
|
|
480
482
|
const rows = await table.getAll();
|
|
481
|
-
|
|
483
|
+
for (const row of rows) this.store.set(this.getKey(row), row);
|
|
482
484
|
this._loading();
|
|
483
485
|
})();
|
|
484
486
|
} else if (((_d = (_c = this.options.persistentStorage) == null ? void 0 : _c.storage) == null ? void 0 : _d.getItem) != void 0) {
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
487
|
+
const { storage, key: key2 } = this.options.persistentStorage;
|
|
488
|
+
const stored = storage.getItem(key2);
|
|
489
|
+
if (stored != null) {
|
|
490
|
+
try {
|
|
491
|
+
const obj = JSON.parse(stored);
|
|
492
|
+
for (const k of Object.keys(obj)) this.store.set(k, obj[k]);
|
|
493
|
+
} catch {
|
|
494
|
+
}
|
|
489
495
|
}
|
|
490
496
|
this._loading();
|
|
491
497
|
}
|
|
@@ -515,26 +521,50 @@ ${opts.message || this.desc}`;
|
|
|
515
521
|
if (!!(persists == null ? void 0 : persists.storage)) {
|
|
516
522
|
if (((_a = persists.storage) == null ? void 0 : _a.database) != void 0) {
|
|
517
523
|
persists.storage.createTable({ name: persists.key, key: this.key }).then((table) => {
|
|
518
|
-
if (key) {
|
|
519
|
-
const value = this.get(key);
|
|
524
|
+
if (key !== void 0) {
|
|
525
|
+
const value = this.get(key, true);
|
|
520
526
|
if (value != null) table.set(value, key);
|
|
521
527
|
else table.delete(key);
|
|
522
528
|
} else {
|
|
523
529
|
table.clear();
|
|
524
|
-
this.all().forEach((row) => table.add(row));
|
|
530
|
+
this.all(true).forEach((row) => table.add(row));
|
|
525
531
|
}
|
|
526
532
|
});
|
|
527
533
|
} else if (((_b = persists.storage) == null ? void 0 : _b.setItem) != void 0) {
|
|
528
|
-
|
|
534
|
+
const obj = {};
|
|
535
|
+
for (const [k, v] of this.store.entries()) obj[k] = v;
|
|
536
|
+
persists.storage.setItem(persists.key, JSONSanitize(obj));
|
|
529
537
|
}
|
|
530
538
|
}
|
|
531
539
|
}
|
|
540
|
+
clearTimer(key) {
|
|
541
|
+
const t = this.timers.get(key);
|
|
542
|
+
if (t) {
|
|
543
|
+
clearTimeout(t);
|
|
544
|
+
this.timers.delete(key);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
touchLRU(key) {
|
|
548
|
+
if (!this.options.sizeLimit || this.options.sizeLimit <= 0) return;
|
|
549
|
+
const idx = this.lruOrder.indexOf(key);
|
|
550
|
+
if (idx >= 0) this.lruOrder.splice(idx, 1);
|
|
551
|
+
this.lruOrder.push(key);
|
|
552
|
+
while (this.lruOrder.length > (this.options.sizeLimit || 0)) {
|
|
553
|
+
const lru = this.lruOrder.shift();
|
|
554
|
+
if (lru !== void 0) this.delete(lru);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
532
557
|
/**
|
|
533
558
|
* Get all cached items
|
|
534
559
|
* @return {T[]} Array of items
|
|
535
560
|
*/
|
|
536
561
|
all(expired) {
|
|
537
|
-
|
|
562
|
+
const out = [];
|
|
563
|
+
for (const v of this.store.values()) {
|
|
564
|
+
const val = v;
|
|
565
|
+
if (expired || !(val == null ? void 0 : val._expired)) out.push(deepCopy(val));
|
|
566
|
+
}
|
|
567
|
+
return out;
|
|
538
568
|
}
|
|
539
569
|
/**
|
|
540
570
|
* Add a new item to the cache. Like set, but finds key automatically
|
|
@@ -564,7 +594,10 @@ ${opts.message || this.desc}`;
|
|
|
564
594
|
*/
|
|
565
595
|
clear() {
|
|
566
596
|
this.complete = false;
|
|
567
|
-
this.
|
|
597
|
+
for (const [k, t] of this.timers) clearTimeout(t);
|
|
598
|
+
this.timers.clear();
|
|
599
|
+
this.lruOrder = [];
|
|
600
|
+
this.store.clear();
|
|
568
601
|
this.save();
|
|
569
602
|
return this;
|
|
570
603
|
}
|
|
@@ -573,7 +606,10 @@ ${opts.message || this.desc}`;
|
|
|
573
606
|
* @param {K} key Item's primary key
|
|
574
607
|
*/
|
|
575
608
|
delete(key) {
|
|
576
|
-
|
|
609
|
+
this.clearTimer(key);
|
|
610
|
+
const idx = this.lruOrder.indexOf(key);
|
|
611
|
+
if (idx >= 0) this.lruOrder.splice(idx, 1);
|
|
612
|
+
this.store.delete(key);
|
|
577
613
|
this.save(key);
|
|
578
614
|
return this;
|
|
579
615
|
}
|
|
@@ -582,7 +618,12 @@ ${opts.message || this.desc}`;
|
|
|
582
618
|
* @return {[K, T][]} Key-value pairs array
|
|
583
619
|
*/
|
|
584
620
|
entries(expired) {
|
|
585
|
-
|
|
621
|
+
const out = [];
|
|
622
|
+
for (const [k, v] of this.store.entries()) {
|
|
623
|
+
const val = v;
|
|
624
|
+
if (expired || !(val == null ? void 0 : val._expired)) out.push([k, deepCopy(val)]);
|
|
625
|
+
}
|
|
626
|
+
return out;
|
|
586
627
|
}
|
|
587
628
|
/**
|
|
588
629
|
* Manually expire a cached item
|
|
@@ -591,8 +632,12 @@ ${opts.message || this.desc}`;
|
|
|
591
632
|
expire(key) {
|
|
592
633
|
this.complete = false;
|
|
593
634
|
if (this.options.expiryPolicy == "keep") {
|
|
594
|
-
this.store
|
|
595
|
-
|
|
635
|
+
const v = this.store.get(key);
|
|
636
|
+
if (v) {
|
|
637
|
+
v._expired = true;
|
|
638
|
+
this.store.set(key, v);
|
|
639
|
+
this.save(key);
|
|
640
|
+
}
|
|
596
641
|
} else this.delete(key);
|
|
597
642
|
return this;
|
|
598
643
|
}
|
|
@@ -603,7 +648,11 @@ ${opts.message || this.desc}`;
|
|
|
603
648
|
* @returns {T | undefined} Cached item or undefined if nothing matched
|
|
604
649
|
*/
|
|
605
650
|
find(filter, expired) {
|
|
606
|
-
|
|
651
|
+
for (const v of this.store.values()) {
|
|
652
|
+
const row = v;
|
|
653
|
+
if ((expired || !row._expired) && includes(row, filter)) return deepCopy(row);
|
|
654
|
+
}
|
|
655
|
+
return void 0;
|
|
607
656
|
}
|
|
608
657
|
/**
|
|
609
658
|
* Get item from the cache
|
|
@@ -612,7 +661,10 @@ ${opts.message || this.desc}`;
|
|
|
612
661
|
* @return {T} Cached item
|
|
613
662
|
*/
|
|
614
663
|
get(key, expired) {
|
|
615
|
-
const
|
|
664
|
+
const raw = this.store.get(key);
|
|
665
|
+
if (raw == null) return null;
|
|
666
|
+
const cached = deepCopy(raw);
|
|
667
|
+
this.touchLRU(key);
|
|
616
668
|
if (expired || !(cached == null ? void 0 : cached._expired)) return cached;
|
|
617
669
|
return null;
|
|
618
670
|
}
|
|
@@ -621,17 +673,23 @@ ${opts.message || this.desc}`;
|
|
|
621
673
|
* @return {K[]} Array of keys
|
|
622
674
|
*/
|
|
623
675
|
keys(expired) {
|
|
624
|
-
|
|
676
|
+
const out = [];
|
|
677
|
+
for (const [k, v] of this.store.entries()) {
|
|
678
|
+
const val = v;
|
|
679
|
+
if (expired || !(val == null ? void 0 : val._expired)) out.push(k);
|
|
680
|
+
}
|
|
681
|
+
return out;
|
|
625
682
|
}
|
|
626
683
|
/**
|
|
627
684
|
* Get map of cached items
|
|
628
685
|
* @return {Record<K, T>}
|
|
629
686
|
*/
|
|
630
687
|
map(expired) {
|
|
631
|
-
const copy =
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
688
|
+
const copy = {};
|
|
689
|
+
for (const [k, v] of this.store.entries()) {
|
|
690
|
+
const val = v;
|
|
691
|
+
if (expired || !(val == null ? void 0 : val._expired)) copy[k] = deepCopy(val);
|
|
692
|
+
}
|
|
635
693
|
return copy;
|
|
636
694
|
}
|
|
637
695
|
/**
|
|
@@ -643,12 +701,17 @@ ${opts.message || this.desc}`;
|
|
|
643
701
|
*/
|
|
644
702
|
set(key, value, ttl = this.options.ttl) {
|
|
645
703
|
if (this.options.expiryPolicy == "keep") delete value._expired;
|
|
646
|
-
this.
|
|
704
|
+
this.clearTimer(key);
|
|
705
|
+
this.store.set(key, value);
|
|
706
|
+
this.touchLRU(key);
|
|
647
707
|
this.save(key);
|
|
648
|
-
if (ttl)
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
708
|
+
if (ttl) {
|
|
709
|
+
const t = setTimeout(() => {
|
|
710
|
+
this.expire(key);
|
|
711
|
+
this.save(key);
|
|
712
|
+
}, (ttl || 0) * 1e3);
|
|
713
|
+
this.timers.set(key, t);
|
|
714
|
+
}
|
|
652
715
|
return this;
|
|
653
716
|
}
|
|
654
717
|
}
|
|
@@ -893,33 +956,6 @@ ${opts.message || this.desc}`;
|
|
|
893
956
|
}).join(","))
|
|
894
957
|
].join("\n");
|
|
895
958
|
}
|
|
896
|
-
function dec2Frac(num, maxDen = 1e3) {
|
|
897
|
-
let sign = Math.sign(num);
|
|
898
|
-
num = Math.abs(num);
|
|
899
|
-
if (Number.isInteger(num)) return sign * num + "";
|
|
900
|
-
let closest = { n: 0, d: 1, diff: Math.abs(num) };
|
|
901
|
-
for (let d = 1; d <= maxDen; d++) {
|
|
902
|
-
let n = Math.round(num * d);
|
|
903
|
-
let diff = Math.abs(num - n / d);
|
|
904
|
-
if (diff < closest.diff) {
|
|
905
|
-
closest = { n, d, diff };
|
|
906
|
-
if (diff < 1e-8) break;
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
let integer = Math.floor(closest.n / closest.d);
|
|
910
|
-
let numerator = closest.n - integer * closest.d;
|
|
911
|
-
return (sign < 0 ? "-" : "") + (integer ? integer + " " : "") + (numerator ? numerator + "/" + closest.d : "");
|
|
912
|
-
}
|
|
913
|
-
function fracToDec(frac) {
|
|
914
|
-
let split = frac.split(" ");
|
|
915
|
-
const whole = split.length == 2 ? Number(split[0]) : 0;
|
|
916
|
-
split = split.pop().split("/");
|
|
917
|
-
return whole + Number(split[0]) / Number(split[1]);
|
|
918
|
-
}
|
|
919
|
-
function numSuffix(n) {
|
|
920
|
-
const s = ["th", "st", "nd", "rd"], v = n % 100;
|
|
921
|
-
return `${n}${s[(v - 20) % 10] || s[v] || s[0]}`;
|
|
922
|
-
}
|
|
923
959
|
function adjustedInterval(cb, ms) {
|
|
924
960
|
let cancel = false, timeout = null;
|
|
925
961
|
const p = async () => {
|
|
@@ -957,28 +993,56 @@ ${opts.message || this.desc}`;
|
|
|
957
993
|
}
|
|
958
994
|
}
|
|
959
995
|
let zonedDate = new Date(date);
|
|
996
|
+
let get;
|
|
997
|
+
const partsMap = {};
|
|
960
998
|
if (!numericTz && tzName !== "UTC") {
|
|
961
999
|
const parts = new Intl.DateTimeFormat("en-US", {
|
|
962
1000
|
timeZone: tzName,
|
|
963
1001
|
year: "numeric",
|
|
964
1002
|
month: "2-digit",
|
|
965
1003
|
day: "2-digit",
|
|
1004
|
+
weekday: "long",
|
|
966
1005
|
hour: "2-digit",
|
|
967
1006
|
minute: "2-digit",
|
|
968
1007
|
second: "2-digit",
|
|
969
1008
|
hour12: false
|
|
970
1009
|
}).formatToParts(date);
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1010
|
+
parts.forEach((p) => {
|
|
1011
|
+
partsMap[p.type] = p.value;
|
|
1012
|
+
});
|
|
1013
|
+
const monthValue = parseInt(partsMap.month) - 1;
|
|
1014
|
+
const dayOfWeekValue = (/* @__PURE__ */ new Date(`${partsMap.year}-${partsMap.month}-${partsMap.day}`)).getDay();
|
|
1015
|
+
const hourValue = parseInt(partsMap.hour);
|
|
1016
|
+
get = (fn2) => {
|
|
1017
|
+
switch (fn2) {
|
|
1018
|
+
case "FullYear":
|
|
1019
|
+
return parseInt(partsMap.year);
|
|
1020
|
+
case "Month":
|
|
1021
|
+
return monthValue;
|
|
1022
|
+
case "Date":
|
|
1023
|
+
return parseInt(partsMap.day);
|
|
1024
|
+
case "Day":
|
|
1025
|
+
return dayOfWeekValue;
|
|
1026
|
+
case "Hours":
|
|
1027
|
+
return hourValue;
|
|
1028
|
+
case "Minutes":
|
|
1029
|
+
return parseInt(partsMap.minute);
|
|
1030
|
+
case "Seconds":
|
|
1031
|
+
return parseInt(partsMap.second);
|
|
1032
|
+
default:
|
|
1033
|
+
return 0;
|
|
1034
|
+
}
|
|
974
1035
|
};
|
|
975
|
-
|
|
976
|
-
zonedDate = new Date(build);
|
|
977
|
-
} else if (numericTz || tzName === "UTC") {
|
|
1036
|
+
} else {
|
|
978
1037
|
const offset = numericTz ? tz : 0;
|
|
979
1038
|
zonedDate = new Date(date.getTime() + offset * 60 * 60 * 1e3);
|
|
1039
|
+
get = (fn2) => zonedDate[`getUTC${fn2}`]();
|
|
1040
|
+
}
|
|
1041
|
+
function numSuffix2(n) {
|
|
1042
|
+
const s = ["th", "st", "nd", "rd"];
|
|
1043
|
+
const v = n % 100;
|
|
1044
|
+
return n + (s[(v - 20) % 10] || s[v] || s[0]);
|
|
980
1045
|
}
|
|
981
|
-
const get = (fn2) => numericTz || tzName === "UTC" ? zonedDate[`getUTC${fn2}`]() : zonedDate[`get${fn2}`]();
|
|
982
1046
|
function getTZOffset() {
|
|
983
1047
|
var _a2, _b;
|
|
984
1048
|
if (numericTz) {
|
|
@@ -1012,7 +1076,7 @@ ${opts.message || this.desc}`;
|
|
|
1012
1076
|
M: (get("Month") + 1).toString(),
|
|
1013
1077
|
DDD: dayOfYear(zonedDate).toString(),
|
|
1014
1078
|
DD: get("Date").toString().padStart(2, "0"),
|
|
1015
|
-
Do:
|
|
1079
|
+
Do: numSuffix2(get("Date")),
|
|
1016
1080
|
D: get("Date").toString(),
|
|
1017
1081
|
dddd: dayOfWeek(get("Day")),
|
|
1018
1082
|
ddd: dayOfWeek(get("Day")).slice(0, 3),
|
|
@@ -1024,7 +1088,7 @@ ${opts.message || this.desc}`;
|
|
|
1024
1088
|
m: get("Minutes").toString(),
|
|
1025
1089
|
ss: get("Seconds").toString().padStart(2, "0"),
|
|
1026
1090
|
s: get("Seconds").toString(),
|
|
1027
|
-
SSS:
|
|
1091
|
+
SSS: zonedDate[`getUTC${"Milliseconds"}`]().toString().padStart(3, "0"),
|
|
1028
1092
|
A: get("Hours") >= 12 ? "PM" : "AM",
|
|
1029
1093
|
a: get("Hours") >= 12 ? "pm" : "am",
|
|
1030
1094
|
ZZ: getTZOffset().replace(":", ""),
|
|
@@ -1788,6 +1852,33 @@ ${opts.message || this.desc}`;
|
|
|
1788
1852
|
};
|
|
1789
1853
|
__publicField(_Logger, "LOG_LEVEL", 4);
|
|
1790
1854
|
let Logger = _Logger;
|
|
1855
|
+
function dec2Frac(num, maxDen = 1e3) {
|
|
1856
|
+
let sign = Math.sign(num);
|
|
1857
|
+
num = Math.abs(num);
|
|
1858
|
+
if (Number.isInteger(num)) return sign * num + "";
|
|
1859
|
+
let closest = { n: 0, d: 1, diff: Math.abs(num) };
|
|
1860
|
+
for (let d = 1; d <= maxDen; d++) {
|
|
1861
|
+
let n = Math.round(num * d);
|
|
1862
|
+
let diff = Math.abs(num - n / d);
|
|
1863
|
+
if (diff < closest.diff) {
|
|
1864
|
+
closest = { n, d, diff };
|
|
1865
|
+
if (diff < 1e-8) break;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
let integer = Math.floor(closest.n / closest.d);
|
|
1869
|
+
let numerator = closest.n - integer * closest.d;
|
|
1870
|
+
return (sign < 0 ? "-" : "") + (integer ? integer + " " : "") + (numerator ? numerator + "/" + closest.d : "");
|
|
1871
|
+
}
|
|
1872
|
+
function fracToDec(frac) {
|
|
1873
|
+
let split = frac.split(" ");
|
|
1874
|
+
const whole = split.length == 2 ? Number(split[0]) : 0;
|
|
1875
|
+
split = split.pop().split("/");
|
|
1876
|
+
return whole + Number(split[0]) / Number(split[1]);
|
|
1877
|
+
}
|
|
1878
|
+
function numSuffix(n) {
|
|
1879
|
+
const s = ["th", "st", "nd", "rd"], v = n % 100;
|
|
1880
|
+
return `${n}${s[(v - 20) % 10] || s[v] || s[0]}`;
|
|
1881
|
+
}
|
|
1791
1882
|
function compareVersions(target, vs) {
|
|
1792
1883
|
const [tMajor, tMinor, tPatch] = target.split(".").map((v) => +v.replace(/[^0-9]/g, ""));
|
|
1793
1884
|
const [vMajor, vMinor, vPatch] = vs.split(".").map((v) => +v.replace(/[^0-9]/g, ""));
|