@sv443-network/userutils 9.3.0 → 9.4.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/CHANGELOG.md +13 -0
- package/README.md +9 -6
- package/dist/index.cjs +211 -30
- package/dist/index.global.js +212 -31
- package/dist/index.js +211 -31
- package/dist/lib/DataStoreSerializer.d.ts +22 -11
- package/dist/lib/Debouncer.d.ts +2 -0
- package/dist/lib/Mixins.d.ts +127 -0
- package/dist/lib/NanoEmitter.d.ts +52 -5
- package/dist/lib/dom.d.ts +1 -1
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/translation.d.ts +1 -1
- package/package.json +18 -6
- package/README-summary.md +0 -214
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createNanoEvents } from 'nanoevents';
|
|
2
2
|
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defProps = Object.defineProperties;
|
|
5
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
6
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
@@ -16,6 +18,7 @@ var __spreadValues = (a, b) => {
|
|
|
16
18
|
}
|
|
17
19
|
return a;
|
|
18
20
|
};
|
|
21
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
19
22
|
var __objRest = (source, exclude) => {
|
|
20
23
|
var target = {};
|
|
21
24
|
for (var prop in source)
|
|
@@ -248,16 +251,16 @@ function addGlobalStyle(style) {
|
|
|
248
251
|
function preloadImages(srcUrls, rejects = false) {
|
|
249
252
|
const promises = srcUrls.map((src) => new Promise((res, rej) => {
|
|
250
253
|
const image = new Image();
|
|
251
|
-
image.src = src;
|
|
252
254
|
image.addEventListener("load", () => res(image));
|
|
253
255
|
image.addEventListener("error", (evt) => rejects && rej(evt));
|
|
256
|
+
image.src = src;
|
|
254
257
|
}));
|
|
255
258
|
return Promise.allSettled(promises);
|
|
256
259
|
}
|
|
257
260
|
function openInNewTab(href, background, additionalProps) {
|
|
258
|
-
var _a;
|
|
259
261
|
try {
|
|
260
|
-
(
|
|
262
|
+
if (typeof window.GM === "object")
|
|
263
|
+
GM.openInTab(href, background);
|
|
261
264
|
} catch (e) {
|
|
262
265
|
const openElem = document.createElement("a");
|
|
263
266
|
Object.assign(openElem, __spreadValues({
|
|
@@ -274,12 +277,17 @@ function openInNewTab(href, background, additionalProps) {
|
|
|
274
277
|
});
|
|
275
278
|
document.body.appendChild(openElem);
|
|
276
279
|
openElem.click();
|
|
277
|
-
setTimeout(
|
|
280
|
+
setTimeout(() => {
|
|
281
|
+
try {
|
|
282
|
+
openElem.remove();
|
|
283
|
+
} catch (e2) {
|
|
284
|
+
}
|
|
285
|
+
}, 0);
|
|
278
286
|
}
|
|
279
287
|
}
|
|
280
288
|
function interceptEvent(eventObject, eventName, predicate = () => true) {
|
|
281
289
|
var _a;
|
|
282
|
-
if (((_a = GM == null ? undefined : GM.info) == null ? undefined : _a.scriptHandler) && GM.info.scriptHandler === "FireMonkey" && (eventObject === window || eventObject === getUnsafeWindow()))
|
|
290
|
+
if (typeof window.GM === "object" && ((_a = GM == null ? undefined : GM.info) == null ? undefined : _a.scriptHandler) && GM.info.scriptHandler === "FireMonkey" && (eventObject === window || eventObject === getUnsafeWindow()))
|
|
283
291
|
throw new PlatformError("Intercepting window events is not supported on FireMonkey due to the isolated context the userscript runs in.");
|
|
284
292
|
Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 100);
|
|
285
293
|
if (isNaN(Error.stackTraceLimit))
|
|
@@ -439,6 +447,8 @@ function computeHash(input, algorithm = "SHA-256") {
|
|
|
439
447
|
});
|
|
440
448
|
}
|
|
441
449
|
function randomId(length = 16, radix = 16, enhancedEntropy = false, randomCase = true) {
|
|
450
|
+
if (length < 1)
|
|
451
|
+
throw new RangeError("The length argument must be at least 1");
|
|
442
452
|
if (radix < 2 || radix > 36)
|
|
443
453
|
throw new RangeError("The radix argument must be between 2 and 36");
|
|
444
454
|
let arr = [];
|
|
@@ -783,7 +793,7 @@ var DataStoreSerializer = class _DataStoreSerializer {
|
|
|
783
793
|
deserializePartial(stores, data) {
|
|
784
794
|
return __async(this, null, function* () {
|
|
785
795
|
const deserStores = typeof data === "string" ? JSON.parse(data) : data;
|
|
786
|
-
if (!Array.isArray(deserStores) || !deserStores.every(_DataStoreSerializer.
|
|
796
|
+
if (!Array.isArray(deserStores) || !deserStores.every(_DataStoreSerializer.isSerializedDataStoreObj))
|
|
787
797
|
throw new TypeError("Invalid serialized data format! Expected an array of SerializedDataStore objects.");
|
|
788
798
|
for (const storeData of deserStores.filter((s) => typeof stores === "function" ? stores(s.id) : stores.includes(s.id))) {
|
|
789
799
|
const storeInst = this.stores.find((s) => s.id === storeData.id);
|
|
@@ -816,41 +826,59 @@ Has: ${checksum}`);
|
|
|
816
826
|
/**
|
|
817
827
|
* Loads the persistent data of the DataStore instances into the in-memory cache.
|
|
818
828
|
* Also triggers the migration process if the data format has changed.
|
|
829
|
+
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be loaded
|
|
819
830
|
* @returns Returns a PromiseSettledResult array with the results of each DataStore instance in the format `{ id: string, data: object }`
|
|
820
831
|
*/
|
|
821
|
-
loadStoresData() {
|
|
832
|
+
loadStoresData(stores) {
|
|
822
833
|
return __async(this, null, function* () {
|
|
823
|
-
return Promise.allSettled(
|
|
824
|
-
(store) => __async(this, null, function* () {
|
|
834
|
+
return Promise.allSettled(
|
|
835
|
+
this.getStoresFiltered(stores).map((store) => __async(this, null, function* () {
|
|
825
836
|
return {
|
|
826
837
|
id: store.id,
|
|
827
838
|
data: yield store.loadData()
|
|
828
839
|
};
|
|
829
|
-
})
|
|
830
|
-
)
|
|
840
|
+
}))
|
|
841
|
+
);
|
|
831
842
|
});
|
|
832
843
|
}
|
|
833
|
-
/**
|
|
834
|
-
|
|
844
|
+
/**
|
|
845
|
+
* Resets the persistent and in-memory data of the DataStore instances to their default values.
|
|
846
|
+
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be affected
|
|
847
|
+
*/
|
|
848
|
+
resetStoresData(stores) {
|
|
835
849
|
return __async(this, null, function* () {
|
|
836
|
-
return Promise.allSettled(
|
|
850
|
+
return Promise.allSettled(
|
|
851
|
+
this.getStoresFiltered(stores).map((store) => store.saveDefaultData())
|
|
852
|
+
);
|
|
837
853
|
});
|
|
838
854
|
}
|
|
839
855
|
/**
|
|
840
856
|
* Deletes the persistent data of the DataStore instances.
|
|
841
|
-
* Leaves the in-memory data untouched.
|
|
857
|
+
* Leaves the in-memory data untouched.
|
|
858
|
+
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be affected
|
|
842
859
|
*/
|
|
843
|
-
deleteStoresData() {
|
|
860
|
+
deleteStoresData(stores) {
|
|
844
861
|
return __async(this, null, function* () {
|
|
845
|
-
return Promise.allSettled(
|
|
862
|
+
return Promise.allSettled(
|
|
863
|
+
this.getStoresFiltered(stores).map((store) => store.deleteData())
|
|
864
|
+
);
|
|
846
865
|
});
|
|
847
866
|
}
|
|
867
|
+
/** Checks if a given value is an array of SerializedDataStore objects */
|
|
868
|
+
static isSerializedDataStoreObjArray(obj) {
|
|
869
|
+
return Array.isArray(obj) && obj.every((o) => typeof o === "object" && o !== null && "id" in o && "data" in o && "formatVersion" in o && "encoded" in o);
|
|
870
|
+
}
|
|
848
871
|
/** Checks if a given value is a SerializedDataStore object */
|
|
849
|
-
static
|
|
872
|
+
static isSerializedDataStoreObj(obj) {
|
|
850
873
|
return typeof obj === "object" && obj !== null && "id" in obj && "data" in obj && "formatVersion" in obj && "encoded" in obj;
|
|
851
874
|
}
|
|
875
|
+
/** Returns the DataStore instances whose IDs match the provided array or function */
|
|
876
|
+
getStoresFiltered(stores) {
|
|
877
|
+
return this.stores.filter((s) => typeof stores === "undefined" ? true : Array.isArray(stores) ? stores.includes(s.id) : stores(s.id));
|
|
878
|
+
}
|
|
852
879
|
};
|
|
853
880
|
var NanoEmitter = class {
|
|
881
|
+
/** Creates a new instance of NanoEmitter - a lightweight event emitter with helper methods and a strongly typed event map */
|
|
854
882
|
constructor(options = {}) {
|
|
855
883
|
__publicField(this, "events", createNanoEvents());
|
|
856
884
|
__publicField(this, "eventUnsubscribes", []);
|
|
@@ -859,7 +887,27 @@ var NanoEmitter = class {
|
|
|
859
887
|
publicEmit: false
|
|
860
888
|
}, options);
|
|
861
889
|
}
|
|
862
|
-
/**
|
|
890
|
+
/**
|
|
891
|
+
* Subscribes to an event and calls the callback when it's emitted.
|
|
892
|
+
* @param event The event to subscribe to. Use `as "_"` in case your event names aren't thoroughly typed (like when using a template literal, e.g. \`event-${val}\` as "_")
|
|
893
|
+
* @returns Returns a function that can be called to unsubscribe the event listener
|
|
894
|
+
* @example ```ts
|
|
895
|
+
* const emitter = new NanoEmitter<{
|
|
896
|
+
* foo: (bar: string) => void;
|
|
897
|
+
* }>({
|
|
898
|
+
* publicEmit: true,
|
|
899
|
+
* });
|
|
900
|
+
*
|
|
901
|
+
* let i = 0;
|
|
902
|
+
* const unsub = emitter.on("foo", (bar) => {
|
|
903
|
+
* // unsubscribe after 10 events:
|
|
904
|
+
* if(++i === 10) unsub();
|
|
905
|
+
* console.log(bar);
|
|
906
|
+
* });
|
|
907
|
+
*
|
|
908
|
+
* emitter.emit("foo", "bar");
|
|
909
|
+
* ```
|
|
910
|
+
*/
|
|
863
911
|
on(event, cb) {
|
|
864
912
|
let unsub;
|
|
865
913
|
const unsubProxy = () => {
|
|
@@ -872,19 +920,43 @@ var NanoEmitter = class {
|
|
|
872
920
|
this.eventUnsubscribes.push(unsub);
|
|
873
921
|
return unsubProxy;
|
|
874
922
|
}
|
|
875
|
-
/**
|
|
923
|
+
/**
|
|
924
|
+
* Subscribes to an event and calls the callback or resolves the Promise only once when it's emitted.
|
|
925
|
+
* @param event The event to subscribe to. Use `as "_"` in case your event names aren't thoroughly typed (like when using a template literal, e.g. \`event-${val}\` as "_")
|
|
926
|
+
* @param cb The callback to call when the event is emitted - if provided or not, the returned Promise will resolve with the event arguments
|
|
927
|
+
* @returns Returns a Promise that resolves with the event arguments when the event is emitted
|
|
928
|
+
* @example ```ts
|
|
929
|
+
* const emitter = new NanoEmitter<{
|
|
930
|
+
* foo: (bar: string) => void;
|
|
931
|
+
* }>();
|
|
932
|
+
*
|
|
933
|
+
* // Promise syntax:
|
|
934
|
+
* const [bar] = await emitter.once("foo");
|
|
935
|
+
* console.log(bar);
|
|
936
|
+
*
|
|
937
|
+
* // Callback syntax:
|
|
938
|
+
* emitter.once("foo", (bar) => console.log(bar));
|
|
939
|
+
* ```
|
|
940
|
+
*/
|
|
876
941
|
once(event, cb) {
|
|
877
942
|
return new Promise((resolve) => {
|
|
878
943
|
let unsub;
|
|
879
944
|
const onceProxy = (...args) => {
|
|
880
|
-
unsub();
|
|
881
945
|
cb == null ? undefined : cb(...args);
|
|
946
|
+
unsub == null ? undefined : unsub();
|
|
882
947
|
resolve(args);
|
|
883
948
|
};
|
|
884
|
-
unsub = this.on(event, onceProxy);
|
|
949
|
+
unsub = this.events.on(event, onceProxy);
|
|
950
|
+
this.eventUnsubscribes.push(unsub);
|
|
885
951
|
});
|
|
886
952
|
}
|
|
887
|
-
/**
|
|
953
|
+
/**
|
|
954
|
+
* Emits an event on this instance.
|
|
955
|
+
* ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
956
|
+
* @param event The event to emit
|
|
957
|
+
* @param args The arguments to pass to the event listeners
|
|
958
|
+
* @returns Returns true if `publicEmit` is true and the event was emitted successfully
|
|
959
|
+
*/
|
|
888
960
|
emit(event, ...args) {
|
|
889
961
|
if (this.emitterOptions.publicEmit) {
|
|
890
962
|
this.events.emit(event, ...args);
|
|
@@ -892,7 +964,7 @@ var NanoEmitter = class {
|
|
|
892
964
|
}
|
|
893
965
|
return false;
|
|
894
966
|
}
|
|
895
|
-
/** Unsubscribes all event listeners */
|
|
967
|
+
/** Unsubscribes all event listeners from this instance */
|
|
896
968
|
unsubscribeAll() {
|
|
897
969
|
for (const unsub of this.eventUnsubscribes)
|
|
898
970
|
unsub();
|
|
@@ -932,6 +1004,10 @@ var Debouncer = class extends NanoEmitter {
|
|
|
932
1004
|
removeAllListeners() {
|
|
933
1005
|
this.listeners = [];
|
|
934
1006
|
}
|
|
1007
|
+
/** Returns all registered listeners */
|
|
1008
|
+
getListeners() {
|
|
1009
|
+
return this.listeners;
|
|
1010
|
+
}
|
|
935
1011
|
//#region timeout
|
|
936
1012
|
/** Sets the timeout for the debouncer */
|
|
937
1013
|
setTimeout(timeout) {
|
|
@@ -960,7 +1036,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
960
1036
|
const cl = (...a) => {
|
|
961
1037
|
this.queuedCall = undefined;
|
|
962
1038
|
this.emit("call", ...a);
|
|
963
|
-
this.listeners.forEach((l) => l.
|
|
1039
|
+
this.listeners.forEach((l) => l.call(this, ...a));
|
|
964
1040
|
};
|
|
965
1041
|
const setRepeatTimeout = () => {
|
|
966
1042
|
this.activeTimeout = setTimeout(() => {
|
|
@@ -1434,8 +1510,6 @@ function autoPlural(term, num, pluralType = "auto") {
|
|
|
1434
1510
|
return `${term}${n === 1 ? "" : "s"}`;
|
|
1435
1511
|
case "-ies":
|
|
1436
1512
|
return `${String(term).slice(0, -1)}${n === 1 ? "y" : "ies"}`;
|
|
1437
|
-
default:
|
|
1438
|
-
return String(term);
|
|
1439
1513
|
}
|
|
1440
1514
|
}
|
|
1441
1515
|
function insertValues(input, ...values) {
|
|
@@ -1494,6 +1568,112 @@ function purifyObj(obj) {
|
|
|
1494
1568
|
return Object.assign(/* @__PURE__ */ Object.create(null), obj);
|
|
1495
1569
|
}
|
|
1496
1570
|
|
|
1571
|
+
// lib/Mixins.ts
|
|
1572
|
+
var Mixins = class {
|
|
1573
|
+
/**
|
|
1574
|
+
* Creates a new Mixins instance.
|
|
1575
|
+
* @param config Configuration object to customize the behavior.
|
|
1576
|
+
*/
|
|
1577
|
+
constructor(config = {}) {
|
|
1578
|
+
/** List of all registered mixins */
|
|
1579
|
+
__publicField(this, "mixins", []);
|
|
1580
|
+
/** Default configuration object for mixins */
|
|
1581
|
+
__publicField(this, "defaultMixinCfg");
|
|
1582
|
+
/** Whether the priorities should auto-increment if not specified */
|
|
1583
|
+
__publicField(this, "autoIncPrioEnabled");
|
|
1584
|
+
/** The current auto-increment priority counter */
|
|
1585
|
+
__publicField(this, "autoIncPrioCounter", /* @__PURE__ */ new Map());
|
|
1586
|
+
var _a, _b, _c;
|
|
1587
|
+
this.defaultMixinCfg = purifyObj({
|
|
1588
|
+
priority: (_a = config.defaultPriority) != null ? _a : 0,
|
|
1589
|
+
stopPropagation: (_b = config.defaultStopPropagation) != null ? _b : false,
|
|
1590
|
+
signal: config.defaultSignal
|
|
1591
|
+
});
|
|
1592
|
+
this.autoIncPrioEnabled = (_c = config.autoIncrementPriority) != null ? _c : false;
|
|
1593
|
+
}
|
|
1594
|
+
//#region public
|
|
1595
|
+
/**
|
|
1596
|
+
* Adds a mixin function to the given {@linkcode mixinKey}.
|
|
1597
|
+
* If no priority is specified, it will be calculated via the protected method {@linkcode calcPriority()} based on the constructor configuration, or fall back to the default priority.
|
|
1598
|
+
* @param mixinKey The key to identify the mixin function.
|
|
1599
|
+
* @param mixinFn The function to be called to apply the mixin. The first argument is the input value, the second argument is the context object (if any).
|
|
1600
|
+
* @param config Configuration object to customize the mixin behavior, or just the priority if a number is passed.
|
|
1601
|
+
* @returns Returns a cleanup function, to be called when this mixin is no longer needed.
|
|
1602
|
+
*/
|
|
1603
|
+
add(mixinKey, mixinFn, config = purifyObj({})) {
|
|
1604
|
+
const calcPrio = typeof config === "number" ? config : this.calcPriority(mixinKey, config);
|
|
1605
|
+
const mixin = purifyObj(__spreadValues(__spreadValues(__spreadProps(__spreadValues({}, this.defaultMixinCfg), {
|
|
1606
|
+
key: mixinKey,
|
|
1607
|
+
fn: mixinFn
|
|
1608
|
+
}), typeof config === "object" ? config : {}), typeof calcPrio === "number" && !isNaN(calcPrio) ? { priority: calcPrio } : {}));
|
|
1609
|
+
this.mixins.push(mixin);
|
|
1610
|
+
const rem = () => {
|
|
1611
|
+
this.mixins = this.mixins.filter((m) => m !== mixin);
|
|
1612
|
+
};
|
|
1613
|
+
if (mixin.signal)
|
|
1614
|
+
mixin.signal.addEventListener("abort", rem, { once: true });
|
|
1615
|
+
return rem;
|
|
1616
|
+
}
|
|
1617
|
+
/** Returns a list of all added mixins with their keys and configuration objects, but not their functions */
|
|
1618
|
+
list() {
|
|
1619
|
+
return this.mixins.map((_a) => {
|
|
1620
|
+
var _b = _a, rest = __objRest(_b, ["fn"]);
|
|
1621
|
+
return rest;
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
/**
|
|
1625
|
+
* Applies all mixins with the given key to the input value, respecting the priority and stopPropagation settings.
|
|
1626
|
+
* If additional context is set in the MixinMap, it will need to be passed as the third argument.
|
|
1627
|
+
* @returns The modified value after all mixins have been applied.
|
|
1628
|
+
*/
|
|
1629
|
+
resolve(mixinKey, inputValue, ...inputCtx) {
|
|
1630
|
+
const mixins = this.mixins.filter((m) => m.key === mixinKey);
|
|
1631
|
+
const sortedMixins = [...mixins].sort((a, b) => b.priority - a.priority);
|
|
1632
|
+
let result = inputValue;
|
|
1633
|
+
for (let i = 0; i < sortedMixins.length; i++) {
|
|
1634
|
+
const mixin = sortedMixins[i];
|
|
1635
|
+
result = mixin.fn(result, ...inputCtx);
|
|
1636
|
+
if (result instanceof Promise) {
|
|
1637
|
+
return (() => __async(this, null, function* () {
|
|
1638
|
+
result = yield result;
|
|
1639
|
+
if (mixin.stopPropagation)
|
|
1640
|
+
return result;
|
|
1641
|
+
for (let j = i + 1; j < sortedMixins.length; j++) {
|
|
1642
|
+
const mixin2 = sortedMixins[j];
|
|
1643
|
+
result = yield mixin2.fn(result, ...inputCtx);
|
|
1644
|
+
if (mixin2.stopPropagation)
|
|
1645
|
+
break;
|
|
1646
|
+
}
|
|
1647
|
+
return result;
|
|
1648
|
+
}))();
|
|
1649
|
+
} else if (mixin.stopPropagation)
|
|
1650
|
+
break;
|
|
1651
|
+
}
|
|
1652
|
+
return result;
|
|
1653
|
+
}
|
|
1654
|
+
//#region protected
|
|
1655
|
+
/** Calculates the priority for a mixin based on the given configuration and the current auto-increment state of the instance */
|
|
1656
|
+
calcPriority(mixinKey, config) {
|
|
1657
|
+
var _a;
|
|
1658
|
+
if (config.priority !== undefined)
|
|
1659
|
+
return undefined;
|
|
1660
|
+
if (!this.autoIncPrioEnabled)
|
|
1661
|
+
return (_a = config.priority) != null ? _a : this.defaultMixinCfg.priority;
|
|
1662
|
+
if (!this.autoIncPrioCounter.has(mixinKey))
|
|
1663
|
+
this.autoIncPrioCounter.set(mixinKey, this.defaultMixinCfg.priority);
|
|
1664
|
+
let prio = this.autoIncPrioCounter.get(mixinKey);
|
|
1665
|
+
while (this.mixins.some((m) => m.key === mixinKey && m.priority === prio))
|
|
1666
|
+
prio++;
|
|
1667
|
+
this.autoIncPrioCounter.set(mixinKey, prio + 1);
|
|
1668
|
+
return prio;
|
|
1669
|
+
}
|
|
1670
|
+
/** Removes all mixins with the given key */
|
|
1671
|
+
removeAll(mixinKey) {
|
|
1672
|
+
this.mixins.filter((m) => m.key === mixinKey);
|
|
1673
|
+
this.mixins = this.mixins.filter((m) => m.key !== mixinKey);
|
|
1674
|
+
}
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1497
1677
|
// lib/SelectorObserver.ts
|
|
1498
1678
|
var SelectorObserver = class {
|
|
1499
1679
|
constructor(baseElement, options = {}) {
|
|
@@ -1751,15 +1931,15 @@ function getFallbackLanguage() {
|
|
|
1751
1931
|
return fallbackLang;
|
|
1752
1932
|
}
|
|
1753
1933
|
function addTransform(transform) {
|
|
1754
|
-
const [
|
|
1934
|
+
const [regex, fn] = transform;
|
|
1755
1935
|
valTransforms.push({
|
|
1756
1936
|
fn,
|
|
1757
|
-
regex
|
|
1937
|
+
regex
|
|
1758
1938
|
});
|
|
1759
1939
|
}
|
|
1760
1940
|
function deleteTransform(patternOrFn) {
|
|
1761
1941
|
const idx = valTransforms.findIndex(
|
|
1762
|
-
(t) => typeof patternOrFn === "function" ? t.fn === patternOrFn :
|
|
1942
|
+
(t) => typeof patternOrFn === "function" ? t.fn === patternOrFn : t.regex === patternOrFn
|
|
1763
1943
|
);
|
|
1764
1944
|
if (idx !== -1) {
|
|
1765
1945
|
valTransforms.splice(idx, 1);
|
|
@@ -1830,4 +2010,4 @@ var tr = {
|
|
|
1830
2010
|
}
|
|
1831
2011
|
};
|
|
1832
2012
|
|
|
1833
|
-
export { ChecksumMismatchError, DataStore, DataStoreSerializer, Debouncer, Dialog, MigrationError, NanoEmitter, PlatformError, SelectorObserver, UUError, addGlobalStyle, addParent, autoPlural, bitSetHas, clamp, compress, computeHash, consumeGen, consumeStringGen, currentDialogId, darkenColor, debounce, decompress, defaultDialogCss, defaultStrings, digitCount, fetchAdvanced, getListLength, getSiblingsFrame, getUnsafeWindow, hexToRgb, insertValues, interceptEvent, interceptWindowEvent, isDomLoaded, isScrollable, lightenColor, mapRange, observeElementProp, onDomLoad, openDialogs, openInNewTab, pauseFor, preloadImages, probeElementStyle, purifyObj, randRange, randomId, randomItem, randomItemIndex, randomizeArray, rgbToHex, roundFixed, setInnerHtmlUnsafe, takeRandomItem, tr };
|
|
2013
|
+
export { ChecksumMismatchError, DataStore, DataStoreSerializer, Debouncer, Dialog, MigrationError, Mixins, NanoEmitter, PlatformError, SelectorObserver, UUError, addGlobalStyle, addParent, autoPlural, bitSetHas, clamp, compress, computeHash, consumeGen, consumeStringGen, currentDialogId, darkenColor, debounce, decompress, defaultDialogCss, defaultStrings, digitCount, fetchAdvanced, getListLength, getSiblingsFrame, getUnsafeWindow, hexToRgb, insertValues, interceptEvent, interceptWindowEvent, isDomLoaded, isScrollable, lightenColor, mapRange, observeElementProp, onDomLoad, openDialogs, openInNewTab, pauseFor, preloadImages, probeElementStyle, purifyObj, randRange, randomId, randomItem, randomItemIndex, randomizeArray, rgbToHex, roundFixed, setInnerHtmlUnsafe, takeRandomItem, tr };
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { DataStore } from "./DataStore.js";
|
|
6
6
|
export type DataStoreSerializerOptions = {
|
|
7
|
-
/** Whether to add a checksum to the exported data */
|
|
7
|
+
/** Whether to add a checksum to the exported data. Defaults to `true` */
|
|
8
8
|
addChecksum?: boolean;
|
|
9
|
-
/** Whether to ensure the integrity of the data when importing it by throwing an error (doesn't throw when the checksum property doesn't exist) */
|
|
9
|
+
/** Whether to ensure the integrity of the data when importing it by throwing an error (doesn't throw when the checksum property doesn't exist). Defaults to `true` */
|
|
10
10
|
ensureIntegrity?: boolean;
|
|
11
11
|
};
|
|
12
12
|
/** Serialized data of a DataStore instance */
|
|
@@ -29,6 +29,8 @@ export type LoadStoresDataResult = {
|
|
|
29
29
|
/** The in-memory data object */
|
|
30
30
|
data: object;
|
|
31
31
|
};
|
|
32
|
+
/** A filter for selecting data stores */
|
|
33
|
+
export type StoreFilter = string[] | ((id: string) => boolean);
|
|
32
34
|
/**
|
|
33
35
|
* Allows for easy serialization and deserialization of multiple DataStore instances.
|
|
34
36
|
*
|
|
@@ -49,21 +51,21 @@ export declare class DataStoreSerializer {
|
|
|
49
51
|
* @param useEncoding Whether to encode the data using each DataStore's `encodeData()` method
|
|
50
52
|
* @param stringified Whether to return the result as a string or as an array of `SerializedDataStore` objects
|
|
51
53
|
*/
|
|
52
|
-
serializePartial(stores:
|
|
54
|
+
serializePartial(stores: StoreFilter, useEncoding?: boolean, stringified?: true): Promise<string>;
|
|
53
55
|
/**
|
|
54
56
|
* Serializes only a subset of the data stores into a string.
|
|
55
57
|
* @param stores An array of store IDs or functions that take a store ID and return a boolean
|
|
56
58
|
* @param useEncoding Whether to encode the data using each DataStore's `encodeData()` method
|
|
57
59
|
* @param stringified Whether to return the result as a string or as an array of `SerializedDataStore` objects
|
|
58
60
|
*/
|
|
59
|
-
serializePartial(stores:
|
|
61
|
+
serializePartial(stores: StoreFilter, useEncoding?: boolean, stringified?: false): Promise<SerializedDataStore[]>;
|
|
60
62
|
/**
|
|
61
63
|
* Serializes only a subset of the data stores into a string.
|
|
62
64
|
* @param stores An array of store IDs or functions that take a store ID and return a boolean
|
|
63
65
|
* @param useEncoding Whether to encode the data using each DataStore's `encodeData()` method
|
|
64
66
|
* @param stringified Whether to return the result as a string or as an array of `SerializedDataStore` objects
|
|
65
67
|
*/
|
|
66
|
-
serializePartial(stores:
|
|
68
|
+
serializePartial(stores: StoreFilter, useEncoding?: boolean, stringified?: boolean): Promise<string | SerializedDataStore[]>;
|
|
67
69
|
/**
|
|
68
70
|
* Serializes the data stores into a string.
|
|
69
71
|
* @param useEncoding Whether to encode the data using each DataStore's `encodeData()` method
|
|
@@ -80,7 +82,7 @@ export declare class DataStoreSerializer {
|
|
|
80
82
|
* Deserializes the data exported via {@linkcode serialize()} and imports only a subset into the DataStore instances.
|
|
81
83
|
* Also triggers the migration process if the data format has changed.
|
|
82
84
|
*/
|
|
83
|
-
deserializePartial(stores:
|
|
85
|
+
deserializePartial(stores: StoreFilter, data: string | SerializedDataStore[]): Promise<void>;
|
|
84
86
|
/**
|
|
85
87
|
* Deserializes the data exported via {@linkcode serialize()} and imports the data into all matching DataStore instances.
|
|
86
88
|
* Also triggers the migration process if the data format has changed.
|
|
@@ -89,16 +91,25 @@ export declare class DataStoreSerializer {
|
|
|
89
91
|
/**
|
|
90
92
|
* Loads the persistent data of the DataStore instances into the in-memory cache.
|
|
91
93
|
* Also triggers the migration process if the data format has changed.
|
|
94
|
+
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be loaded
|
|
92
95
|
* @returns Returns a PromiseSettledResult array with the results of each DataStore instance in the format `{ id: string, data: object }`
|
|
93
96
|
*/
|
|
94
|
-
loadStoresData(): Promise<PromiseSettledResult<LoadStoresDataResult>[]>;
|
|
95
|
-
/**
|
|
96
|
-
|
|
97
|
+
loadStoresData(stores?: StoreFilter): Promise<PromiseSettledResult<LoadStoresDataResult>[]>;
|
|
98
|
+
/**
|
|
99
|
+
* Resets the persistent and in-memory data of the DataStore instances to their default values.
|
|
100
|
+
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be affected
|
|
101
|
+
*/
|
|
102
|
+
resetStoresData(stores?: StoreFilter): Promise<PromiseSettledResult<void>[]>;
|
|
97
103
|
/**
|
|
98
104
|
* Deletes the persistent data of the DataStore instances.
|
|
99
105
|
* Leaves the in-memory data untouched.
|
|
106
|
+
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be affected
|
|
100
107
|
*/
|
|
101
|
-
deleteStoresData(): Promise<PromiseSettledResult<void>[]>;
|
|
108
|
+
deleteStoresData(stores?: StoreFilter): Promise<PromiseSettledResult<void>[]>;
|
|
109
|
+
/** Checks if a given value is an array of SerializedDataStore objects */
|
|
110
|
+
static isSerializedDataStoreObjArray(obj: unknown): obj is SerializedDataStore[];
|
|
102
111
|
/** Checks if a given value is a SerializedDataStore object */
|
|
103
|
-
static
|
|
112
|
+
static isSerializedDataStoreObj(obj: unknown): obj is SerializedDataStore;
|
|
113
|
+
/** Returns the DataStore instances whose IDs match the provided array or function */
|
|
114
|
+
protected getStoresFiltered(stores?: StoreFilter): DataStore[];
|
|
104
115
|
}
|
package/dist/lib/Debouncer.d.ts
CHANGED
|
@@ -60,6 +60,8 @@ export declare class Debouncer<TFunc extends AnyFunc> extends NanoEmitter<Deboun
|
|
|
60
60
|
removeListener(fn: TFunc): void;
|
|
61
61
|
/** Removes all listeners */
|
|
62
62
|
removeAllListeners(): void;
|
|
63
|
+
/** Returns all registered listeners */
|
|
64
|
+
getListeners(): TFunc[];
|
|
63
65
|
/** Sets the timeout for the debouncer */
|
|
64
66
|
setTimeout(timeout: number): void;
|
|
65
67
|
/** Returns the current timeout */
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module lib/Mixins
|
|
3
|
+
* Allows for defining and applying mixin functions to allow multiple sources to modify a value in a controlled way.
|
|
4
|
+
*/
|
|
5
|
+
import type { Prettify } from "./types.js";
|
|
6
|
+
/** Full mixin object (either sync or async), as it is stored in the instance's mixin array. */
|
|
7
|
+
export type MixinObj<TArg, TCtx> = Prettify<MixinObjSync<TArg, TCtx> | MixinObjAsync<TArg, TCtx>>;
|
|
8
|
+
/** Asynchronous mixin object, as it is stored in the instance's mixin array. */
|
|
9
|
+
export type MixinObjSync<TArg, TCtx> = Prettify<{
|
|
10
|
+
/** The mixin function */
|
|
11
|
+
fn: (arg: TArg, ctx?: TCtx) => TArg;
|
|
12
|
+
} & MixinObjBase>;
|
|
13
|
+
/** Synchronous mixin object, as it is stored in the instance's mixin array. */
|
|
14
|
+
export type MixinObjAsync<TArg, TCtx> = Prettify<{
|
|
15
|
+
/** The mixin function */
|
|
16
|
+
fn: (arg: TArg, ctx?: TCtx) => TArg | Promise<TArg>;
|
|
17
|
+
} & MixinObjBase>;
|
|
18
|
+
/** Base type for mixin objects */
|
|
19
|
+
type MixinObjBase = Prettify<{
|
|
20
|
+
/** The public identifier key (purpose) of the mixin */
|
|
21
|
+
key: string;
|
|
22
|
+
} & MixinConfig>;
|
|
23
|
+
/** Configuration object for a mixin function */
|
|
24
|
+
export type MixinConfig = {
|
|
25
|
+
/** The higher, the earlier the mixin will be applied. Supports floating-point and negative numbers too. 0 by default. */
|
|
26
|
+
priority: number;
|
|
27
|
+
/** If true, no further mixins will be applied after this one. */
|
|
28
|
+
stopPropagation: boolean;
|
|
29
|
+
/** If set, the mixin will only be applied if the given signal is not aborted. */
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
};
|
|
32
|
+
/** Configuration object for the Mixins class */
|
|
33
|
+
export type MixinsConstructorConfig = {
|
|
34
|
+
/**
|
|
35
|
+
* If true, when no priority is specified, an auto-incrementing integer priority will be used, starting at `defaultPriority` or 0 (unique per mixin key). Defaults to false.
|
|
36
|
+
* If a priority value is already used, it will be incremented until a unique value is found.
|
|
37
|
+
* This is useful to ensure that mixins are applied in the order they were added, even if they don't specify a priority.
|
|
38
|
+
* It also allows for a finer level of interjection when the priority is a floating point number.
|
|
39
|
+
*/
|
|
40
|
+
autoIncrementPriority: boolean;
|
|
41
|
+
/** The default priority for mixins that do not specify one. Defaults to 0. */
|
|
42
|
+
defaultPriority: number;
|
|
43
|
+
/** The default stopPropagation value for mixins that do not specify one. Defaults to false. */
|
|
44
|
+
defaultStopPropagation: boolean;
|
|
45
|
+
/** The default AbortSignal for mixins that do not specify one. Defaults to undefined. */
|
|
46
|
+
defaultSignal?: AbortSignal;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* The mixin class allows for defining and applying mixin functions to allow multiple sources to modify values in a controlled way.
|
|
50
|
+
* Mixins are identified via their string key and can be added with {@linkcode add()}
|
|
51
|
+
* When calling {@linkcode resolve()}, all registered mixin functions with the same key will be applied to the input value in the order of their priority.
|
|
52
|
+
* If a mixin has the stopPropagation flag set to true, no further mixins will be applied after it.
|
|
53
|
+
* @template TMixinMap A map of mixin keys to their respective function signatures. The first argument of the function is the input value, the second argument is an optional context object. If it is defined here, it must be passed as the third argument in {@linkcode resolve()}.
|
|
54
|
+
* @example ```ts
|
|
55
|
+
* const ac = new AbortController();
|
|
56
|
+
* const { abort: removeAllMixins } = ac;
|
|
57
|
+
*
|
|
58
|
+
* const mathMixins = new Mixins<{
|
|
59
|
+
* // supports sync and async functions:
|
|
60
|
+
* foo: (val: number, ctx: { baz: string }) => Promise<number>;
|
|
61
|
+
* // first argument and return value have to be of the same type:
|
|
62
|
+
* bar: (val: bigint) => bigint;
|
|
63
|
+
* // ...
|
|
64
|
+
* }>({
|
|
65
|
+
* autoIncrementPriority: true,
|
|
66
|
+
* defaultPriority: 0,
|
|
67
|
+
* defaultSignal: ac.signal,
|
|
68
|
+
* });
|
|
69
|
+
*
|
|
70
|
+
* // will be applied last due to base priority of 0:
|
|
71
|
+
* mathMixins.add("foo", (val, ctx) => Promise.resolve(val * 2 + ctx.baz.length));
|
|
72
|
+
* // will be applied second due to manually set priority of 1:
|
|
73
|
+
* mathMixins.add("foo", (val) => val + 1, { priority: 1 });
|
|
74
|
+
* // will be applied first, even though the above ones were called first, because of the auto-incrementing priority of 2:
|
|
75
|
+
* mathMixins.add("foo", (val) => val / 2);
|
|
76
|
+
*
|
|
77
|
+
* const result = await mathMixins.resolve("foo", 10, { baz: "this has a length of 23" });
|
|
78
|
+
* // order of application:
|
|
79
|
+
* // input value: 10
|
|
80
|
+
* // 10 / 2 = 5
|
|
81
|
+
* // 5 + 1 = 6
|
|
82
|
+
* // 6 * 2 + 23 = 35
|
|
83
|
+
* // result = 35
|
|
84
|
+
*
|
|
85
|
+
* // removes all mixins added without a `signal` property:
|
|
86
|
+
* removeAllMixins();
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare class Mixins<TMixinMap extends Record<string, (arg: any, ctx?: any) => any>, TMixinKey extends Extract<keyof TMixinMap, string> = Extract<keyof TMixinMap, string>> {
|
|
90
|
+
/** List of all registered mixins */
|
|
91
|
+
protected mixins: MixinObj<any, any>[];
|
|
92
|
+
/** Default configuration object for mixins */
|
|
93
|
+
protected readonly defaultMixinCfg: MixinConfig;
|
|
94
|
+
/** Whether the priorities should auto-increment if not specified */
|
|
95
|
+
protected readonly autoIncPrioEnabled: boolean;
|
|
96
|
+
/** The current auto-increment priority counter */
|
|
97
|
+
protected autoIncPrioCounter: Map<TMixinKey, number>;
|
|
98
|
+
/**
|
|
99
|
+
* Creates a new Mixins instance.
|
|
100
|
+
* @param config Configuration object to customize the behavior.
|
|
101
|
+
*/
|
|
102
|
+
constructor(config?: Partial<MixinsConstructorConfig>);
|
|
103
|
+
/**
|
|
104
|
+
* Adds a mixin function to the given {@linkcode mixinKey}.
|
|
105
|
+
* If no priority is specified, it will be calculated via the protected method {@linkcode calcPriority()} based on the constructor configuration, or fall back to the default priority.
|
|
106
|
+
* @param mixinKey The key to identify the mixin function.
|
|
107
|
+
* @param mixinFn The function to be called to apply the mixin. The first argument is the input value, the second argument is the context object (if any).
|
|
108
|
+
* @param config Configuration object to customize the mixin behavior, or just the priority if a number is passed.
|
|
109
|
+
* @returns Returns a cleanup function, to be called when this mixin is no longer needed.
|
|
110
|
+
*/
|
|
111
|
+
add<TKey extends TMixinKey, TArg extends Parameters<TMixinMap[TKey]>[0], TCtx extends Parameters<TMixinMap[TKey]>[1]>(mixinKey: TKey, mixinFn: (arg: TArg, ...ctx: TCtx extends undefined ? [void] : [TCtx]) => ReturnType<TMixinMap[TKey]> extends Promise<any> ? ReturnType<TMixinMap[TKey]> | Awaited<ReturnType<TMixinMap[TKey]>> : ReturnType<TMixinMap[TKey]>, config?: Partial<MixinConfig> | number): () => void;
|
|
112
|
+
/** Returns a list of all added mixins with their keys and configuration objects, but not their functions */
|
|
113
|
+
list(): ({
|
|
114
|
+
key: string;
|
|
115
|
+
} & MixinConfig)[];
|
|
116
|
+
/**
|
|
117
|
+
* Applies all mixins with the given key to the input value, respecting the priority and stopPropagation settings.
|
|
118
|
+
* If additional context is set in the MixinMap, it will need to be passed as the third argument.
|
|
119
|
+
* @returns The modified value after all mixins have been applied.
|
|
120
|
+
*/
|
|
121
|
+
resolve<TKey extends TMixinKey, TArg extends Parameters<TMixinMap[TKey]>[0], TCtx extends Parameters<TMixinMap[TKey]>[1]>(mixinKey: TKey, inputValue: TArg, ...inputCtx: TCtx extends undefined ? [void] : [TCtx]): ReturnType<TMixinMap[TKey]> extends Promise<any> ? ReturnType<TMixinMap[TKey]> : ReturnType<TMixinMap[TKey]>;
|
|
122
|
+
/** Calculates the priority for a mixin based on the given configuration and the current auto-increment state of the instance */
|
|
123
|
+
protected calcPriority(mixinKey: TMixinKey, config: Partial<MixinConfig>): number | undefined;
|
|
124
|
+
/** Removes all mixins with the given key */
|
|
125
|
+
protected removeAll(mixinKey: TMixinKey): void;
|
|
126
|
+
}
|
|
127
|
+
export {};
|