@sv443-network/userutils 10.0.6 → 10.2.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 +27 -0
- package/README.md +40 -32
- package/dist/UserUtils.cjs +600 -404
- package/dist/UserUtils.mjs +602 -404
- package/dist/UserUtils.umd.js +486 -309
- package/dist/lib/consts.d.ts +2 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/translation.d.ts +80 -2
- package/package.json +4 -5
package/dist/UserUtils.cjs
CHANGED
|
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
9
|
var __export = (target, all) => {
|
|
9
10
|
for (var name in all)
|
|
10
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -26,6 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
27
|
mod
|
|
27
28
|
));
|
|
28
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
29
31
|
|
|
30
32
|
// lib/index.ts
|
|
31
33
|
var lib_exports = {};
|
|
@@ -62,6 +64,7 @@ __export(lib_exports, {
|
|
|
62
64
|
consumeGen: () => consumeGen,
|
|
63
65
|
consumeStringGen: () => consumeStringGen,
|
|
64
66
|
createProgressBar: () => createProgressBar,
|
|
67
|
+
createRecurringTask: () => createRecurringTask,
|
|
65
68
|
currentDialogId: () => currentDialogId,
|
|
66
69
|
darkenColor: () => darkenColor,
|
|
67
70
|
debounce: () => debounce,
|
|
@@ -110,11 +113,12 @@ __export(lib_exports, {
|
|
|
110
113
|
takeRandomItemIndex: () => takeRandomItemIndex,
|
|
111
114
|
tr: () => tr,
|
|
112
115
|
truncStr: () => truncStr,
|
|
113
|
-
valsWithin: () => valsWithin
|
|
116
|
+
valsWithin: () => valsWithin,
|
|
117
|
+
versions: () => versions
|
|
114
118
|
});
|
|
115
119
|
module.exports = __toCommonJS(lib_exports);
|
|
116
120
|
|
|
117
|
-
// node_modules/.pnpm/@sv443-network+coreutils@3.0
|
|
121
|
+
// node_modules/.pnpm/@sv443-network+coreutils@3.4.0/node_modules/@sv443-network/coreutils/dist/CoreUtils.mjs
|
|
118
122
|
function bitSetHas(bitSet, checkVal) {
|
|
119
123
|
return (bitSet & checkVal) === checkVal;
|
|
120
124
|
}
|
|
@@ -260,7 +264,7 @@ function darkenColor(color, percent, upperCase = false) {
|
|
|
260
264
|
if (isHexCol)
|
|
261
265
|
return rgbToHex(r, g, b, a, color.startsWith("#"), upperCase);
|
|
262
266
|
else if (color.startsWith("rgba"))
|
|
263
|
-
return `rgba(${r}, ${g}, ${b}, ${a
|
|
267
|
+
return `rgba(${r}, ${g}, ${b}, ${a != null ? a : NaN})`;
|
|
264
268
|
else
|
|
265
269
|
return `rgb(${r}, ${g}, ${b})`;
|
|
266
270
|
}
|
|
@@ -293,7 +297,8 @@ function atoab(str) {
|
|
|
293
297
|
return Uint8Array.from(atob(str), (c) => c.charCodeAt(0));
|
|
294
298
|
}
|
|
295
299
|
async function compress(input, compressionFormat, outputType = "string") {
|
|
296
|
-
|
|
300
|
+
var _a;
|
|
301
|
+
const byteArray = input instanceof Uint8Array ? input : new TextEncoder().encode((_a = input == null ? void 0 : input.toString()) != null ? _a : String(input));
|
|
297
302
|
const comp = new CompressionStream(compressionFormat);
|
|
298
303
|
const writer = comp.writable.getWriter();
|
|
299
304
|
writer.write(byteArray);
|
|
@@ -302,7 +307,8 @@ async function compress(input, compressionFormat, outputType = "string") {
|
|
|
302
307
|
return outputType === "arrayBuffer" ? uintArr : abtoa(uintArr);
|
|
303
308
|
}
|
|
304
309
|
async function decompress(input, compressionFormat, outputType = "string") {
|
|
305
|
-
|
|
310
|
+
var _a;
|
|
311
|
+
const byteArray = input instanceof Uint8Array ? input : atoab((_a = input == null ? void 0 : input.toString()) != null ? _a : String(input));
|
|
306
312
|
const decomp = new DecompressionStream(compressionFormat);
|
|
307
313
|
const writer = decomp.writable.getWriter();
|
|
308
314
|
writer.write(byteArray);
|
|
@@ -347,9 +353,9 @@ function randomId(length = 16, radix = 16, enhancedEntropy = false, randomCase =
|
|
|
347
353
|
return arr.map((v) => caseArr[randRange(0, caseArr.length - 1, enhancedEntropy)] === 1 ? v.toUpperCase() : v).join("");
|
|
348
354
|
}
|
|
349
355
|
var DatedError = class extends Error {
|
|
350
|
-
date;
|
|
351
356
|
constructor(message, options) {
|
|
352
357
|
super(message, options);
|
|
358
|
+
__publicField(this, "date");
|
|
353
359
|
this.name = this.constructor.name;
|
|
354
360
|
this.date = /* @__PURE__ */ new Date();
|
|
355
361
|
}
|
|
@@ -432,7 +438,7 @@ function pauseFor(time, signal, rejectOnAbort = false) {
|
|
|
432
438
|
});
|
|
433
439
|
}
|
|
434
440
|
function pureObj(obj) {
|
|
435
|
-
return Object.assign(/* @__PURE__ */ Object.create(null), obj
|
|
441
|
+
return Object.assign(/* @__PURE__ */ Object.create(null), obj != null ? obj : {});
|
|
436
442
|
}
|
|
437
443
|
function setImmediateInterval(callback, interval, signal) {
|
|
438
444
|
let intervalId;
|
|
@@ -471,15 +477,50 @@ function scheduleExit(code = 0, timeout = 0) {
|
|
|
471
477
|
setTimeout(exit, timeout);
|
|
472
478
|
}
|
|
473
479
|
function getCallStack(asArray, lines = Infinity) {
|
|
480
|
+
var _a;
|
|
474
481
|
if (typeof lines !== "number" || isNaN(lines) || lines < 0)
|
|
475
482
|
throw new TypeError("lines parameter must be a non-negative number");
|
|
476
483
|
try {
|
|
477
|
-
throw new
|
|
484
|
+
throw new CustomError("GetCallStack", "Capturing a stack trace with CoreUtils.getCallStack(). If you see this anywhere, you can safely ignore it.");
|
|
478
485
|
} catch (err) {
|
|
479
|
-
const stack = (err.stack
|
|
486
|
+
const stack = ((_a = err.stack) != null ? _a : "").split("\n").map((line) => line.trim()).slice(2, lines + 2);
|
|
480
487
|
return asArray !== false ? stack : stack.join("\n");
|
|
481
488
|
}
|
|
482
489
|
}
|
|
490
|
+
function createRecurringTask(options) {
|
|
491
|
+
var _a;
|
|
492
|
+
let iterations = 0;
|
|
493
|
+
let aborted = false;
|
|
494
|
+
(_a = options.signal) == null ? void 0 : _a.addEventListener("abort", () => {
|
|
495
|
+
aborted = true;
|
|
496
|
+
}, { once: true });
|
|
497
|
+
const runRecurringTask = async (initial = false) => {
|
|
498
|
+
var _a3, _b;
|
|
499
|
+
var _a2;
|
|
500
|
+
if (aborted)
|
|
501
|
+
return;
|
|
502
|
+
try {
|
|
503
|
+
if (((_a3 = options.immediate) != null ? _a3 : true) || !initial) {
|
|
504
|
+
iterations++;
|
|
505
|
+
if ((_b = await ((_a2 = options.condition) == null ? void 0 : _a2.call(options, iterations - 1))) != null ? _b : true) {
|
|
506
|
+
const val = await options.task(iterations - 1);
|
|
507
|
+
if (options.onSuccess)
|
|
508
|
+
await options.onSuccess(val, iterations - 1);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
} catch (err) {
|
|
512
|
+
if (options.onError)
|
|
513
|
+
await options.onError(err, iterations - 1);
|
|
514
|
+
if (options.abortOnError)
|
|
515
|
+
aborted = true;
|
|
516
|
+
if (!options.onError && !options.abortOnError)
|
|
517
|
+
throw err;
|
|
518
|
+
}
|
|
519
|
+
if (!aborted && (typeof options.maxIterations !== "number" || iterations < options.maxIterations))
|
|
520
|
+
setTimeout(runRecurringTask, options.timeout);
|
|
521
|
+
};
|
|
522
|
+
return runRecurringTask(true);
|
|
523
|
+
}
|
|
483
524
|
function autoPlural(term, num, pluralType = "auto") {
|
|
484
525
|
if (typeof num !== "number") {
|
|
485
526
|
if ("length" in num)
|
|
@@ -529,9 +570,10 @@ function createProgressBar(percentage, barLength, chars = defaultPbChars) {
|
|
|
529
570
|
}
|
|
530
571
|
function insertValues(input, ...values) {
|
|
531
572
|
return input.replace(/%\d/gm, (match) => {
|
|
573
|
+
var _a2;
|
|
532
574
|
var _a;
|
|
533
575
|
const argIndex = Number(match.substring(1)) - 1;
|
|
534
|
-
return (_a = values[argIndex]
|
|
576
|
+
return (_a = (_a2 = values[argIndex]) != null ? _a2 : match) == null ? void 0 : _a.toString();
|
|
535
577
|
});
|
|
536
578
|
}
|
|
537
579
|
function joinArrayReadable(array, separators = ", ", lastSeparator = " and ") {
|
|
@@ -562,31 +604,209 @@ function secsToTimeStr(seconds) {
|
|
|
562
604
|
].join("");
|
|
563
605
|
}
|
|
564
606
|
function truncStr(input, length, endStr = "...") {
|
|
565
|
-
|
|
607
|
+
var _a;
|
|
608
|
+
const str = (_a = input == null ? void 0 : input.toString()) != null ? _a : String(input);
|
|
566
609
|
const finalStr = str.length > length ? str.substring(0, length - endStr.length) + endStr : str;
|
|
567
610
|
return finalStr.length > length ? finalStr.substring(0, length) : finalStr;
|
|
568
611
|
}
|
|
569
|
-
var
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
612
|
+
var createNanoEvents = () => ({
|
|
613
|
+
emit(event, ...args) {
|
|
614
|
+
for (let callbacks = this.events[event] || [], i = 0, length = callbacks.length; i < length; i++) {
|
|
615
|
+
callbacks[i](...args);
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
events: {},
|
|
619
|
+
on(event, cb) {
|
|
620
|
+
var _a;
|
|
621
|
+
;
|
|
622
|
+
((_a = this.events)[event] || (_a[event] = [])).push(cb);
|
|
623
|
+
return () => {
|
|
624
|
+
var _a2;
|
|
625
|
+
this.events[event] = (_a2 = this.events[event]) == null ? void 0 : _a2.filter((i) => cb !== i);
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
var NanoEmitter = class {
|
|
630
|
+
/** Creates a new instance of NanoEmitter - a lightweight event emitter with helper methods and a strongly typed event map */
|
|
631
|
+
constructor(options = {}) {
|
|
632
|
+
__publicField(this, "events", createNanoEvents());
|
|
633
|
+
__publicField(this, "eventUnsubscribes", []);
|
|
634
|
+
__publicField(this, "emitterOptions");
|
|
635
|
+
this.emitterOptions = {
|
|
636
|
+
publicEmit: false,
|
|
637
|
+
...options
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
//#region on
|
|
641
|
+
/**
|
|
642
|
+
* Subscribes to an event and calls the callback when it's emitted.
|
|
643
|
+
* @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 "_")
|
|
644
|
+
* @returns Returns a function that can be called to unsubscribe the event listener
|
|
645
|
+
* @example ```ts
|
|
646
|
+
* const emitter = new NanoEmitter<{
|
|
647
|
+
* foo: (bar: string) => void;
|
|
648
|
+
* }>({
|
|
649
|
+
* publicEmit: true,
|
|
650
|
+
* });
|
|
651
|
+
*
|
|
652
|
+
* let i = 0;
|
|
653
|
+
* const unsub = emitter.on("foo", (bar) => {
|
|
654
|
+
* // unsubscribe after 10 events:
|
|
655
|
+
* if(++i === 10) unsub();
|
|
656
|
+
* console.log(bar);
|
|
657
|
+
* });
|
|
658
|
+
*
|
|
659
|
+
* emitter.emit("foo", "bar");
|
|
660
|
+
* ```
|
|
661
|
+
*/
|
|
662
|
+
on(event, cb) {
|
|
663
|
+
let unsub;
|
|
664
|
+
const unsubProxy = () => {
|
|
665
|
+
if (!unsub)
|
|
666
|
+
return;
|
|
667
|
+
unsub();
|
|
668
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => u !== unsub);
|
|
669
|
+
};
|
|
670
|
+
unsub = this.events.on(event, cb);
|
|
671
|
+
this.eventUnsubscribes.push(unsub);
|
|
672
|
+
return unsubProxy;
|
|
673
|
+
}
|
|
674
|
+
//#region once
|
|
675
|
+
/**
|
|
676
|
+
* Subscribes to an event and calls the callback or resolves the Promise only once when it's emitted.
|
|
677
|
+
* @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 "_")
|
|
678
|
+
* @param cb The callback to call when the event is emitted - if provided or not, the returned Promise will resolve with the event arguments
|
|
679
|
+
* @returns Returns a Promise that resolves with the event arguments when the event is emitted
|
|
680
|
+
* @example ```ts
|
|
681
|
+
* const emitter = new NanoEmitter<{
|
|
682
|
+
* foo: (bar: string) => void;
|
|
683
|
+
* }>();
|
|
684
|
+
*
|
|
685
|
+
* // Promise syntax:
|
|
686
|
+
* const [bar] = await emitter.once("foo");
|
|
687
|
+
* console.log(bar);
|
|
688
|
+
*
|
|
689
|
+
* // Callback syntax:
|
|
690
|
+
* emitter.once("foo", (bar) => console.log(bar));
|
|
691
|
+
* ```
|
|
692
|
+
*/
|
|
693
|
+
once(event, cb) {
|
|
694
|
+
return new Promise((resolve) => {
|
|
695
|
+
let unsub;
|
|
696
|
+
const onceProxy = ((...args) => {
|
|
697
|
+
cb == null ? void 0 : cb(...args);
|
|
698
|
+
unsub == null ? void 0 : unsub();
|
|
699
|
+
resolve(args);
|
|
700
|
+
});
|
|
701
|
+
unsub = this.events.on(event, onceProxy);
|
|
702
|
+
this.eventUnsubscribes.push(unsub);
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
//#region onMulti
|
|
706
|
+
/**
|
|
707
|
+
* Allows subscribing to multiple events and calling the callback only when one of, all of, or a subset of the events are emitted, either continuously or only once.
|
|
708
|
+
* @param options An object or array of objects with the following properties:
|
|
709
|
+
* `callback` (required) is the function that will be called when the conditions are met.
|
|
710
|
+
*
|
|
711
|
+
* Set `once` to true to call the callback only once for the first event (or set of events) that match the criteria, then stop listening.
|
|
712
|
+
* If `signal` is provided, the subscription will be canceled when the given signal is aborted.
|
|
713
|
+
*
|
|
714
|
+
* If `oneOf` is used, the callback will be called when any of the matching events are emitted.
|
|
715
|
+
* If `allOf` is used, the callback will be called after all of the matching events are emitted at least once, then any time any of them are emitted.
|
|
716
|
+
* If both `oneOf` and `allOf` are used together, the callback will be called when any of the `oneOf` events are emitted AND all of the `allOf` events have been emitted at least once.
|
|
717
|
+
* At least one of `oneOf` or `allOf` must be provided.
|
|
718
|
+
*
|
|
719
|
+
* @returns Returns a function that can be called to unsubscribe all listeners created by this call. Alternatively, pass an `AbortSignal` to all options objects to achieve the same effect or for finer control.
|
|
720
|
+
*/
|
|
721
|
+
onMulti(options) {
|
|
722
|
+
const allUnsubs = [];
|
|
723
|
+
const unsubAll = () => {
|
|
724
|
+
for (const unsub of allUnsubs)
|
|
725
|
+
unsub();
|
|
726
|
+
allUnsubs.splice(0, allUnsubs.length);
|
|
727
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !allUnsubs.includes(u));
|
|
728
|
+
};
|
|
729
|
+
for (const opts of Array.isArray(options) ? options : [options]) {
|
|
730
|
+
const optsWithDefaults = {
|
|
731
|
+
allOf: [],
|
|
732
|
+
oneOf: [],
|
|
733
|
+
once: false,
|
|
734
|
+
...opts
|
|
735
|
+
};
|
|
736
|
+
const {
|
|
737
|
+
oneOf,
|
|
738
|
+
allOf,
|
|
739
|
+
once,
|
|
740
|
+
signal,
|
|
741
|
+
callback
|
|
742
|
+
} = optsWithDefaults;
|
|
743
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
744
|
+
return unsubAll;
|
|
745
|
+
if (oneOf.length === 0 && allOf.length === 0)
|
|
746
|
+
throw new TypeError("NanoEmitter.onMulti(): Either `oneOf` or `allOf` or both must be provided in the options");
|
|
747
|
+
const curEvtUnsubs = [];
|
|
748
|
+
const checkUnsubAllEvt = (force = false) => {
|
|
749
|
+
if (!(signal == null ? void 0 : signal.aborted) && !force)
|
|
750
|
+
return;
|
|
751
|
+
for (const unsub of curEvtUnsubs)
|
|
752
|
+
unsub();
|
|
753
|
+
curEvtUnsubs.splice(0, curEvtUnsubs.length);
|
|
754
|
+
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !curEvtUnsubs.includes(u));
|
|
755
|
+
};
|
|
756
|
+
const allOfEmitted = /* @__PURE__ */ new Set();
|
|
757
|
+
const allOfConditionMet = () => allOf.length === 0 || allOfEmitted.size === allOf.length;
|
|
758
|
+
for (const event of oneOf) {
|
|
759
|
+
const unsub = this.events.on(event, ((...args) => {
|
|
760
|
+
checkUnsubAllEvt();
|
|
761
|
+
if (allOfConditionMet()) {
|
|
762
|
+
callback(event, ...args);
|
|
763
|
+
if (once)
|
|
764
|
+
checkUnsubAllEvt(true);
|
|
765
|
+
}
|
|
766
|
+
}));
|
|
767
|
+
curEvtUnsubs.push(unsub);
|
|
768
|
+
}
|
|
769
|
+
for (const event of allOf) {
|
|
770
|
+
const unsub = this.events.on(event, ((...args) => {
|
|
771
|
+
checkUnsubAllEvt();
|
|
772
|
+
allOfEmitted.add(event);
|
|
773
|
+
if (allOfConditionMet() && (oneOf.length === 0 || oneOf.includes(event))) {
|
|
774
|
+
callback(event, ...args);
|
|
775
|
+
if (once)
|
|
776
|
+
checkUnsubAllEvt(true);
|
|
777
|
+
}
|
|
778
|
+
}));
|
|
779
|
+
curEvtUnsubs.push(unsub);
|
|
780
|
+
}
|
|
781
|
+
allUnsubs.push(() => checkUnsubAllEvt(true));
|
|
782
|
+
}
|
|
783
|
+
return unsubAll;
|
|
784
|
+
}
|
|
785
|
+
//#region emit
|
|
580
786
|
/**
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
787
|
+
* Emits an event on this instance.
|
|
788
|
+
* - ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
789
|
+
* @param event The event to emit
|
|
790
|
+
* @param args The arguments to pass to the event listeners
|
|
791
|
+
* @returns Returns true if `publicEmit` is true and the event was emitted successfully
|
|
584
792
|
*/
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
793
|
+
emit(event, ...args) {
|
|
794
|
+
if (this.emitterOptions.publicEmit) {
|
|
795
|
+
this.events.emit(event, ...args);
|
|
796
|
+
return true;
|
|
797
|
+
}
|
|
798
|
+
return false;
|
|
799
|
+
}
|
|
800
|
+
//#region unsubscribeAll
|
|
801
|
+
/** Unsubscribes all event listeners from this instance */
|
|
802
|
+
unsubscribeAll() {
|
|
803
|
+
for (const unsub of this.eventUnsubscribes)
|
|
804
|
+
unsub();
|
|
805
|
+
this.eventUnsubscribes = [];
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
var dsFmtVer = 1;
|
|
809
|
+
var DataStore = class extends NanoEmitter {
|
|
590
810
|
//#region constructor
|
|
591
811
|
/**
|
|
592
812
|
* Creates an instance of DataStore to manage a sync & async database that is cached in memory and persistently saved across sessions.
|
|
@@ -598,20 +818,43 @@ var DataStore = class {
|
|
|
598
818
|
* @param opts The options for this DataStore instance
|
|
599
819
|
*/
|
|
600
820
|
constructor(opts) {
|
|
821
|
+
var _a, _b, _c;
|
|
822
|
+
super(opts.nanoEmitterOptions);
|
|
823
|
+
__publicField(this, "id");
|
|
824
|
+
__publicField(this, "formatVersion");
|
|
825
|
+
__publicField(this, "defaultData");
|
|
826
|
+
__publicField(this, "encodeData");
|
|
827
|
+
__publicField(this, "decodeData");
|
|
828
|
+
__publicField(this, "compressionFormat", "deflate-raw");
|
|
829
|
+
__publicField(this, "memoryCache");
|
|
830
|
+
__publicField(this, "engine");
|
|
831
|
+
__publicField(this, "keyPrefix");
|
|
832
|
+
__publicField(this, "options");
|
|
833
|
+
/**
|
|
834
|
+
* Whether all first-init checks should be done.
|
|
835
|
+
* This includes migrating the internal DataStore format, migrating data from the UserUtils format, and anything similar.
|
|
836
|
+
* This is set to `true` by default. Create a subclass and set it to `false` before calling {@linkcode loadData()} if you want to explicitly skip these checks.
|
|
837
|
+
*/
|
|
838
|
+
__publicField(this, "firstInit", true);
|
|
839
|
+
/** In-memory cached copy of the data that is saved in persistent storage used for synchronous read access. */
|
|
840
|
+
__publicField(this, "cachedData");
|
|
841
|
+
__publicField(this, "migrations");
|
|
842
|
+
__publicField(this, "migrateIds", []);
|
|
601
843
|
this.id = opts.id;
|
|
602
844
|
this.formatVersion = opts.formatVersion;
|
|
603
845
|
this.defaultData = opts.defaultData;
|
|
604
|
-
this.memoryCache = opts.memoryCache
|
|
846
|
+
this.memoryCache = (_a = opts.memoryCache) != null ? _a : true;
|
|
605
847
|
this.cachedData = this.memoryCache ? opts.defaultData : {};
|
|
606
848
|
this.migrations = opts.migrations;
|
|
607
849
|
if (opts.migrateIds)
|
|
608
850
|
this.migrateIds = Array.isArray(opts.migrateIds) ? opts.migrateIds : [opts.migrateIds];
|
|
609
851
|
this.engine = typeof opts.engine === "function" ? opts.engine() : opts.engine;
|
|
852
|
+
this.keyPrefix = (_b = opts.keyPrefix) != null ? _b : "__ds-";
|
|
610
853
|
this.options = opts;
|
|
611
854
|
if ("encodeData" in opts && "decodeData" in opts && Array.isArray(opts.encodeData) && Array.isArray(opts.decodeData)) {
|
|
612
855
|
this.encodeData = [opts.encodeData[0], opts.encodeData[1]];
|
|
613
856
|
this.decodeData = [opts.decodeData[0], opts.decodeData[1]];
|
|
614
|
-
this.compressionFormat = opts.encodeData[0]
|
|
857
|
+
this.compressionFormat = (_c = opts.encodeData[0]) != null ? _c : null;
|
|
615
858
|
} else if (opts.compressionFormat === null) {
|
|
616
859
|
this.encodeData = void 0;
|
|
617
860
|
this.decodeData = void 0;
|
|
@@ -635,6 +878,7 @@ var DataStore = class {
|
|
|
635
878
|
* Also runs all necessary migration functions if the data format has changed since the last time the data was saved.
|
|
636
879
|
*/
|
|
637
880
|
async loadData() {
|
|
881
|
+
var _a;
|
|
638
882
|
try {
|
|
639
883
|
if (this.firstInit) {
|
|
640
884
|
this.firstInit = false;
|
|
@@ -648,13 +892,13 @@ var DataStore = class {
|
|
|
648
892
|
promises.push(this.engine.setValue(newKey, value));
|
|
649
893
|
promises.push(this.engine.deleteValue(oldKey));
|
|
650
894
|
};
|
|
651
|
-
migrateFmt(`_uucfg-${this.id}`,
|
|
895
|
+
migrateFmt(`_uucfg-${this.id}`, `${this.keyPrefix}${this.id}-dat`, oldData);
|
|
652
896
|
if (!isNaN(oldVer))
|
|
653
|
-
migrateFmt(`_uucfgver-${this.id}`,
|
|
897
|
+
migrateFmt(`_uucfgver-${this.id}`, `${this.keyPrefix}${this.id}-ver`, oldVer);
|
|
654
898
|
if (typeof oldEnc === "boolean" || oldEnc === "true" || oldEnc === "false" || typeof oldEnc === "number" || oldEnc === "0" || oldEnc === "1")
|
|
655
|
-
migrateFmt(`_uucfgenc-${this.id}`,
|
|
899
|
+
migrateFmt(`_uucfgenc-${this.id}`, `${this.keyPrefix}${this.id}-enf`, [0, "0", true, "true"].includes(oldEnc) ? (_a = this.compressionFormat) != null ? _a : null : null);
|
|
656
900
|
else {
|
|
657
|
-
promises.push(this.engine.setValue(
|
|
901
|
+
promises.push(this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat));
|
|
658
902
|
promises.push(this.engine.deleteValue(`_uucfgenc-${this.id}`));
|
|
659
903
|
}
|
|
660
904
|
await Promise.allSettled(promises);
|
|
@@ -666,31 +910,27 @@ var DataStore = class {
|
|
|
666
910
|
await this.migrateId(this.migrateIds);
|
|
667
911
|
this.migrateIds = [];
|
|
668
912
|
}
|
|
669
|
-
const storedDataRaw = await this.engine.getValue(
|
|
670
|
-
|
|
671
|
-
if (typeof storedDataRaw !== "string") {
|
|
672
|
-
await this.saveDefaultData();
|
|
673
|
-
|
|
913
|
+
const storedDataRaw = await this.engine.getValue(`${this.keyPrefix}${this.id}-dat`, null);
|
|
914
|
+
const storedFmtVer = Number(await this.engine.getValue(`${this.keyPrefix}${this.id}-ver`, NaN));
|
|
915
|
+
if (typeof storedDataRaw !== "string" && typeof storedDataRaw !== "object" || storedDataRaw === null || isNaN(storedFmtVer)) {
|
|
916
|
+
await this.saveDefaultData(false);
|
|
917
|
+
const data = this.engine.deepCopy(this.defaultData);
|
|
918
|
+
this.events.emit("loadData", data);
|
|
919
|
+
return data;
|
|
674
920
|
}
|
|
675
|
-
const storedData = storedDataRaw
|
|
676
|
-
const encodingFmt = String(await this.engine.getValue(
|
|
921
|
+
const storedData = storedDataRaw != null ? storedDataRaw : JSON.stringify(this.defaultData);
|
|
922
|
+
const encodingFmt = String(await this.engine.getValue(`${this.keyPrefix}${this.id}-enf`, null));
|
|
677
923
|
const isEncoded = encodingFmt !== "null" && encodingFmt !== "false" && encodingFmt !== "0" && encodingFmt !== "" && encodingFmt !== null;
|
|
678
|
-
let
|
|
679
|
-
if (isNaN(storedFmtVer)) {
|
|
680
|
-
await this.engine.setValue(`__ds-${this.id}-ver`, storedFmtVer = this.formatVersion);
|
|
681
|
-
saveData = true;
|
|
682
|
-
}
|
|
683
|
-
let parsed = await this.engine.deserializeData(storedData, isEncoded);
|
|
924
|
+
let parsed = typeof storedData === "string" ? await this.engine.deserializeData(storedData, isEncoded) : storedData;
|
|
684
925
|
if (storedFmtVer < this.formatVersion && this.migrations)
|
|
685
926
|
parsed = await this.runMigrations(parsed, storedFmtVer);
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
return this.cachedData = this.engine.deepCopy(parsed);
|
|
690
|
-
else
|
|
691
|
-
return this.engine.deepCopy(parsed);
|
|
927
|
+
const result = this.memoryCache ? this.cachedData = this.engine.deepCopy(parsed) : this.engine.deepCopy(parsed);
|
|
928
|
+
this.events.emit("loadData", result);
|
|
929
|
+
return result;
|
|
692
930
|
} catch (err) {
|
|
931
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
693
932
|
console.warn("Error while parsing JSON data, resetting it to the default value.", err);
|
|
933
|
+
this.events.emit("error", error);
|
|
694
934
|
await this.saveDefaultData();
|
|
695
935
|
return this.defaultData;
|
|
696
936
|
}
|
|
@@ -709,27 +949,47 @@ var DataStore = class {
|
|
|
709
949
|
//#region setData
|
|
710
950
|
/** Saves the data synchronously to the in-memory cache and asynchronously to the persistent storage */
|
|
711
951
|
setData(data) {
|
|
712
|
-
|
|
952
|
+
const dataCopy = this.engine.deepCopy(data);
|
|
953
|
+
if (this.memoryCache) {
|
|
713
954
|
this.cachedData = data;
|
|
955
|
+
this.events.emit("updateDataSync", dataCopy);
|
|
956
|
+
}
|
|
714
957
|
return new Promise(async (resolve) => {
|
|
715
|
-
await Promise.allSettled([
|
|
716
|
-
this.engine.setValue(
|
|
717
|
-
this.engine.setValue(
|
|
718
|
-
this.engine.setValue(
|
|
958
|
+
const results = await Promise.allSettled([
|
|
959
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-dat`, await this.engine.serializeData(data, this.encodingEnabled())),
|
|
960
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, this.formatVersion),
|
|
961
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat)
|
|
719
962
|
]);
|
|
963
|
+
if (results.every((r) => r.status === "fulfilled"))
|
|
964
|
+
this.events.emit("updateData", dataCopy);
|
|
965
|
+
else {
|
|
966
|
+
const error = new Error("Error while saving data to persistent storage: " + results.map((r) => r.status === "rejected" ? r.reason : null).filter(Boolean).join("; "));
|
|
967
|
+
console.error(error);
|
|
968
|
+
this.events.emit("error", error);
|
|
969
|
+
}
|
|
720
970
|
resolve();
|
|
721
971
|
});
|
|
722
972
|
}
|
|
723
973
|
//#region saveDefaultData
|
|
724
|
-
/**
|
|
725
|
-
|
|
974
|
+
/**
|
|
975
|
+
* Saves the default data passed in the constructor synchronously to the in-memory cache and asynchronously to persistent storage.
|
|
976
|
+
* @param emitEvent Whether to emit the `setDefaultData` event - set to `false` to prevent event emission (used internally during initial population in {@linkcode loadData()})
|
|
977
|
+
*/
|
|
978
|
+
async saveDefaultData(emitEvent = true) {
|
|
726
979
|
if (this.memoryCache)
|
|
727
980
|
this.cachedData = this.defaultData;
|
|
728
|
-
await Promise.allSettled([
|
|
729
|
-
this.engine.setValue(
|
|
730
|
-
this.engine.setValue(
|
|
731
|
-
this.engine.setValue(
|
|
981
|
+
const results = await Promise.allSettled([
|
|
982
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-dat`, await this.engine.serializeData(this.defaultData, this.encodingEnabled())),
|
|
983
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, this.formatVersion),
|
|
984
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat)
|
|
732
985
|
]);
|
|
986
|
+
if (results.every((r) => r.status === "fulfilled"))
|
|
987
|
+
emitEvent && this.events.emit("setDefaultData", this.defaultData);
|
|
988
|
+
else {
|
|
989
|
+
const error = new Error("Error while saving default data to persistent storage: " + results.map((r) => r.status === "rejected" ? r.reason : null).filter(Boolean).join("; "));
|
|
990
|
+
console.error(error);
|
|
991
|
+
this.events.emit("error", error);
|
|
992
|
+
}
|
|
733
993
|
}
|
|
734
994
|
//#region deleteData
|
|
735
995
|
/**
|
|
@@ -740,11 +1000,12 @@ var DataStore = class {
|
|
|
740
1000
|
async deleteData() {
|
|
741
1001
|
var _a, _b;
|
|
742
1002
|
await Promise.allSettled([
|
|
743
|
-
this.engine.deleteValue(
|
|
744
|
-
this.engine.deleteValue(
|
|
745
|
-
this.engine.deleteValue(
|
|
1003
|
+
this.engine.deleteValue(`${this.keyPrefix}${this.id}-dat`),
|
|
1004
|
+
this.engine.deleteValue(`${this.keyPrefix}${this.id}-ver`),
|
|
1005
|
+
this.engine.deleteValue(`${this.keyPrefix}${this.id}-enf`)
|
|
746
1006
|
]);
|
|
747
1007
|
await ((_b = (_a = this.engine).deleteStorage) == null ? void 0 : _b.call(_a));
|
|
1008
|
+
this.events.emit("deleteData");
|
|
748
1009
|
}
|
|
749
1010
|
//#region encodingEnabled
|
|
750
1011
|
/** Returns whether encoding and decoding are enabled for this DataStore instance */
|
|
@@ -765,30 +1026,35 @@ var DataStore = class {
|
|
|
765
1026
|
let newData = oldData;
|
|
766
1027
|
const sortedMigrations = Object.entries(this.migrations).sort(([a], [b]) => Number(a) - Number(b));
|
|
767
1028
|
let lastFmtVer = oldFmtVer;
|
|
768
|
-
for (
|
|
1029
|
+
for (let i = 0; i < sortedMigrations.length; i++) {
|
|
1030
|
+
const [fmtVer, migrationFunc] = sortedMigrations[i];
|
|
769
1031
|
const ver = Number(fmtVer);
|
|
770
1032
|
if (oldFmtVer < this.formatVersion && oldFmtVer < ver) {
|
|
771
1033
|
try {
|
|
772
1034
|
const migRes = migrationFunc(newData);
|
|
773
1035
|
newData = migRes instanceof Promise ? await migRes : migRes;
|
|
774
1036
|
lastFmtVer = oldFmtVer = ver;
|
|
1037
|
+
const isFinal = ver >= this.formatVersion || i === sortedMigrations.length - 1;
|
|
1038
|
+
this.events.emit("migrateData", ver, newData, isFinal);
|
|
775
1039
|
} catch (err) {
|
|
1040
|
+
const migError = new MigrationError(`Error while running migration function for format version '${fmtVer}'`, { cause: err });
|
|
1041
|
+
this.events.emit("migrationError", ver, migError);
|
|
1042
|
+
this.events.emit("error", migError);
|
|
776
1043
|
if (!resetOnError)
|
|
777
|
-
throw
|
|
1044
|
+
throw migError;
|
|
778
1045
|
await this.saveDefaultData();
|
|
779
1046
|
return this.engine.deepCopy(this.defaultData);
|
|
780
1047
|
}
|
|
781
1048
|
}
|
|
782
1049
|
}
|
|
783
1050
|
await Promise.allSettled([
|
|
784
|
-
this.engine.setValue(
|
|
785
|
-
this.engine.setValue(
|
|
786
|
-
this.engine.setValue(
|
|
1051
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-dat`, await this.engine.serializeData(newData, this.encodingEnabled())),
|
|
1052
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, lastFmtVer),
|
|
1053
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat)
|
|
787
1054
|
]);
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
return this.engine.deepCopy(newData);
|
|
1055
|
+
const result = this.memoryCache ? this.cachedData = this.engine.deepCopy(newData) : this.engine.deepCopy(newData);
|
|
1056
|
+
this.events.emit("updateData", result);
|
|
1057
|
+
return result;
|
|
792
1058
|
}
|
|
793
1059
|
//#region migrateId
|
|
794
1060
|
/**
|
|
@@ -800,9 +1066,9 @@ var DataStore = class {
|
|
|
800
1066
|
await Promise.all(ids.map(async (id) => {
|
|
801
1067
|
const [data, fmtVer, isEncoded] = await (async () => {
|
|
802
1068
|
const [d, f, e] = await Promise.all([
|
|
803
|
-
this.engine.getValue(
|
|
804
|
-
this.engine.getValue(
|
|
805
|
-
this.engine.getValue(
|
|
1069
|
+
this.engine.getValue(`${this.keyPrefix}${id}-dat`, JSON.stringify(this.defaultData)),
|
|
1070
|
+
this.engine.getValue(`${this.keyPrefix}${id}-ver`, NaN),
|
|
1071
|
+
this.engine.getValue(`${this.keyPrefix}${id}-enf`, null)
|
|
806
1072
|
]);
|
|
807
1073
|
return [d, Number(f), Boolean(e) && String(e) !== "null"];
|
|
808
1074
|
})();
|
|
@@ -810,20 +1076,21 @@ var DataStore = class {
|
|
|
810
1076
|
return;
|
|
811
1077
|
const parsed = await this.engine.deserializeData(data, isEncoded);
|
|
812
1078
|
await Promise.allSettled([
|
|
813
|
-
this.engine.setValue(
|
|
814
|
-
this.engine.setValue(
|
|
815
|
-
this.engine.setValue(
|
|
816
|
-
this.engine.deleteValue(
|
|
817
|
-
this.engine.deleteValue(
|
|
818
|
-
this.engine.deleteValue(
|
|
1079
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-dat`, await this.engine.serializeData(parsed, this.encodingEnabled())),
|
|
1080
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-ver`, fmtVer),
|
|
1081
|
+
this.engine.setValue(`${this.keyPrefix}${this.id}-enf`, this.compressionFormat),
|
|
1082
|
+
this.engine.deleteValue(`${this.keyPrefix}${id}-dat`),
|
|
1083
|
+
this.engine.deleteValue(`${this.keyPrefix}${id}-ver`),
|
|
1084
|
+
this.engine.deleteValue(`${this.keyPrefix}${id}-enf`)
|
|
819
1085
|
]);
|
|
1086
|
+
this.events.emit("migrateId", id, this.id);
|
|
820
1087
|
}));
|
|
821
1088
|
}
|
|
822
1089
|
};
|
|
823
1090
|
var DataStoreEngine = class {
|
|
824
|
-
dataStoreOptions;
|
|
825
1091
|
// setDataStoreOptions() is called from inside the DataStore constructor to set this value
|
|
826
1092
|
constructor(options) {
|
|
1093
|
+
__publicField(this, "dataStoreOptions");
|
|
827
1094
|
if (options)
|
|
828
1095
|
this.dataStoreOptions = options;
|
|
829
1096
|
}
|
|
@@ -851,7 +1118,7 @@ var DataStoreEngine = class {
|
|
|
851
1118
|
let decRes = ((_a = this.dataStoreOptions) == null ? void 0 : _a.decodeData) && useEncoding ? (_c = (_b = this.dataStoreOptions.decodeData) == null ? void 0 : _b[1]) == null ? void 0 : _c.call(_b, data) : void 0;
|
|
852
1119
|
if (decRes instanceof Promise)
|
|
853
1120
|
decRes = await decRes;
|
|
854
|
-
return JSON.parse(decRes
|
|
1121
|
+
return JSON.parse(decRes != null ? decRes : data);
|
|
855
1122
|
}
|
|
856
1123
|
//#region misc api
|
|
857
1124
|
/** Throws an error if the DataStoreOptions are not set or invalid */
|
|
@@ -869,13 +1136,12 @@ var DataStoreEngine = class {
|
|
|
869
1136
|
try {
|
|
870
1137
|
if ("structuredClone" in globalThis)
|
|
871
1138
|
return structuredClone(obj);
|
|
872
|
-
} catch {
|
|
1139
|
+
} catch (e) {
|
|
873
1140
|
}
|
|
874
1141
|
return JSON.parse(JSON.stringify(obj));
|
|
875
1142
|
}
|
|
876
1143
|
};
|
|
877
1144
|
var BrowserStorageEngine = class extends DataStoreEngine {
|
|
878
|
-
options;
|
|
879
1145
|
/**
|
|
880
1146
|
* Creates an instance of `BrowserStorageEngine`.
|
|
881
1147
|
*
|
|
@@ -884,6 +1150,7 @@ var BrowserStorageEngine = class extends DataStoreEngine {
|
|
|
884
1150
|
*/
|
|
885
1151
|
constructor(options) {
|
|
886
1152
|
super(options == null ? void 0 : options.dataStoreOptions);
|
|
1153
|
+
__publicField(this, "options");
|
|
887
1154
|
this.options = {
|
|
888
1155
|
type: "localStorage",
|
|
889
1156
|
...options
|
|
@@ -912,8 +1179,6 @@ var BrowserStorageEngine = class extends DataStoreEngine {
|
|
|
912
1179
|
};
|
|
913
1180
|
var fs;
|
|
914
1181
|
var FileStorageEngine = class extends DataStoreEngine {
|
|
915
|
-
options;
|
|
916
|
-
fileAccessQueue = Promise.resolve();
|
|
917
1182
|
/**
|
|
918
1183
|
* Creates an instance of `FileStorageEngine`.
|
|
919
1184
|
*
|
|
@@ -922,6 +1187,8 @@ var FileStorageEngine = class extends DataStoreEngine {
|
|
|
922
1187
|
*/
|
|
923
1188
|
constructor(options) {
|
|
924
1189
|
super(options == null ? void 0 : options.dataStoreOptions);
|
|
1190
|
+
__publicField(this, "options");
|
|
1191
|
+
__publicField(this, "fileAccessQueue", Promise.resolve());
|
|
925
1192
|
this.options = {
|
|
926
1193
|
filePath: (id) => `.ds-${id}`,
|
|
927
1194
|
...options
|
|
@@ -930,6 +1197,7 @@ var FileStorageEngine = class extends DataStoreEngine {
|
|
|
930
1197
|
//#region json file
|
|
931
1198
|
/** Reads the file contents */
|
|
932
1199
|
async readFile() {
|
|
1200
|
+
var _a2;
|
|
933
1201
|
var _a, _b, _c, _d;
|
|
934
1202
|
this.ensureDataStoreOptions();
|
|
935
1203
|
try {
|
|
@@ -937,15 +1205,16 @@ var FileStorageEngine = class extends DataStoreEngine {
|
|
|
937
1205
|
fs = (_a = await import("fs/promises")) == null ? void 0 : _a.default;
|
|
938
1206
|
if (!fs)
|
|
939
1207
|
throw new ScriptContextError("FileStorageEngine requires Node.js or Deno with Node compatibility (v1.31+)", { cause: new DatedError("'node:fs/promises' module not available") });
|
|
940
|
-
const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id);
|
|
1208
|
+
const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id, this.dataStoreOptions);
|
|
941
1209
|
const data = await fs.readFile(path, "utf-8");
|
|
942
|
-
return data ? JSON.parse(await ((_d = (_c = (_b = this.dataStoreOptions) == null ? void 0 : _b.decodeData) == null ? void 0 : _c[1]) == null ? void 0 : _d.call(_c, data))
|
|
943
|
-
} catch {
|
|
1210
|
+
return data ? JSON.parse((_a2 = await ((_d = (_c = (_b = this.dataStoreOptions) == null ? void 0 : _b.decodeData) == null ? void 0 : _c[1]) == null ? void 0 : _d.call(_c, data))) != null ? _a2 : data) : void 0;
|
|
1211
|
+
} catch (e) {
|
|
944
1212
|
return void 0;
|
|
945
1213
|
}
|
|
946
1214
|
}
|
|
947
1215
|
/** Overwrites the file contents */
|
|
948
1216
|
async writeFile(data) {
|
|
1217
|
+
var _a2;
|
|
949
1218
|
var _a, _b, _c, _d;
|
|
950
1219
|
this.ensureDataStoreOptions();
|
|
951
1220
|
try {
|
|
@@ -953,9 +1222,9 @@ var FileStorageEngine = class extends DataStoreEngine {
|
|
|
953
1222
|
fs = (_a = await import("fs/promises")) == null ? void 0 : _a.default;
|
|
954
1223
|
if (!fs)
|
|
955
1224
|
throw new ScriptContextError("FileStorageEngine requires Node.js or Deno with Node compatibility (v1.31+)", { cause: new DatedError("'node:fs/promises' module not available") });
|
|
956
|
-
const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id);
|
|
1225
|
+
const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id, this.dataStoreOptions);
|
|
957
1226
|
await fs.mkdir(path.slice(0, path.lastIndexOf(path.includes("/") ? "/" : "\\")), { recursive: true });
|
|
958
|
-
await fs.writeFile(path, await ((_d = (_c = (_b = this.dataStoreOptions) == null ? void 0 : _b.encodeData) == null ? void 0 : _c[1]) == null ? void 0 : _d.call(_c, JSON.stringify(data)))
|
|
1227
|
+
await fs.writeFile(path, (_a2 = await ((_d = (_c = (_b = this.dataStoreOptions) == null ? void 0 : _b.encodeData) == null ? void 0 : _c[1]) == null ? void 0 : _d.call(_c, JSON.stringify(data)))) != null ? _a2 : JSON.stringify(data, void 0, 2), "utf-8");
|
|
959
1228
|
} catch (err) {
|
|
960
1229
|
console.error("Error writing file:", err);
|
|
961
1230
|
}
|
|
@@ -969,8 +1238,21 @@ var FileStorageEngine = class extends DataStoreEngine {
|
|
|
969
1238
|
const value = data == null ? void 0 : data[name];
|
|
970
1239
|
if (typeof value === "undefined")
|
|
971
1240
|
return defaultValue;
|
|
972
|
-
if (typeof
|
|
973
|
-
|
|
1241
|
+
if (typeof defaultValue === "string") {
|
|
1242
|
+
if (typeof value === "object" && value !== null)
|
|
1243
|
+
return JSON.stringify(value);
|
|
1244
|
+
if (typeof value === "string")
|
|
1245
|
+
return value;
|
|
1246
|
+
return String(value);
|
|
1247
|
+
}
|
|
1248
|
+
if (typeof value === "string") {
|
|
1249
|
+
try {
|
|
1250
|
+
const parsed = JSON.parse(value);
|
|
1251
|
+
return parsed;
|
|
1252
|
+
} catch (e) {
|
|
1253
|
+
return defaultValue;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
974
1256
|
return value;
|
|
975
1257
|
}
|
|
976
1258
|
/** Sets a value in persistent storage */
|
|
@@ -979,7 +1261,18 @@ var FileStorageEngine = class extends DataStoreEngine {
|
|
|
979
1261
|
let data = await this.readFile();
|
|
980
1262
|
if (!data)
|
|
981
1263
|
data = {};
|
|
982
|
-
|
|
1264
|
+
let storeVal = value;
|
|
1265
|
+
if (typeof value === "string") {
|
|
1266
|
+
try {
|
|
1267
|
+
if (value.startsWith("{") || value.startsWith("[")) {
|
|
1268
|
+
const parsed = JSON.parse(value);
|
|
1269
|
+
if (typeof parsed === "object" && parsed !== null)
|
|
1270
|
+
storeVal = parsed;
|
|
1271
|
+
}
|
|
1272
|
+
} catch (e) {
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
data[name] = storeVal;
|
|
983
1276
|
await this.writeFile(data);
|
|
984
1277
|
}).catch((err) => {
|
|
985
1278
|
console.error("Error in setValue:", err);
|
|
@@ -1012,7 +1305,7 @@ var FileStorageEngine = class extends DataStoreEngine {
|
|
|
1012
1305
|
fs = (_a = await import("fs/promises")) == null ? void 0 : _a.default;
|
|
1013
1306
|
if (!fs)
|
|
1014
1307
|
throw new ScriptContextError("FileStorageEngine requires Node.js or Deno with Node compatibility (v1.31+)", { cause: new DatedError("'node:fs/promises' module not available") });
|
|
1015
|
-
const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id);
|
|
1308
|
+
const path = typeof this.options.filePath === "string" ? this.options.filePath : this.options.filePath(this.dataStoreOptions.id, this.dataStoreOptions);
|
|
1016
1309
|
return await fs.unlink(path);
|
|
1017
1310
|
} catch (err) {
|
|
1018
1311
|
console.error("Error deleting file:", err);
|
|
@@ -1020,9 +1313,9 @@ var FileStorageEngine = class extends DataStoreEngine {
|
|
|
1020
1313
|
}
|
|
1021
1314
|
};
|
|
1022
1315
|
var DataStoreSerializer = class _DataStoreSerializer {
|
|
1023
|
-
stores;
|
|
1024
|
-
options;
|
|
1025
1316
|
constructor(stores, options = {}) {
|
|
1317
|
+
__publicField(this, "stores");
|
|
1318
|
+
__publicField(this, "options");
|
|
1026
1319
|
if (!crypto || !crypto.subtle)
|
|
1027
1320
|
throw new ScriptContextError("DataStoreSerializer has to run in a secure context (HTTPS) or in another environment that implements the subtleCrypto API!");
|
|
1028
1321
|
this.stores = stores;
|
|
@@ -1033,7 +1326,10 @@ var DataStoreSerializer = class _DataStoreSerializer {
|
|
|
1033
1326
|
...options
|
|
1034
1327
|
};
|
|
1035
1328
|
}
|
|
1036
|
-
/**
|
|
1329
|
+
/**
|
|
1330
|
+
* Calculates the checksum of a string. Uses {@linkcode computeHash()} with SHA-256 and digests as a hex string by default.
|
|
1331
|
+
* Override this in a subclass if a custom checksum method is needed.
|
|
1332
|
+
*/
|
|
1037
1333
|
async calcChecksum(input) {
|
|
1038
1334
|
return computeHash(input, "SHA-256");
|
|
1039
1335
|
}
|
|
@@ -1078,8 +1374,9 @@ var DataStoreSerializer = class _DataStoreSerializer {
|
|
|
1078
1374
|
if (!Array.isArray(deserStores) || !deserStores.every(_DataStoreSerializer.isSerializedDataStoreObj))
|
|
1079
1375
|
throw new TypeError("Invalid serialized data format! Expected an array of SerializedDataStore objects.");
|
|
1080
1376
|
const resolveStoreId = (id) => {
|
|
1377
|
+
var _a2;
|
|
1081
1378
|
var _a;
|
|
1082
|
-
return ((_a = Object.entries(this.options.remapIds).find(([, v]) => v.includes(id))) == null ? void 0 : _a[0])
|
|
1379
|
+
return (_a2 = (_a = Object.entries(this.options.remapIds).find(([, v]) => v.includes(id))) == null ? void 0 : _a[0]) != null ? _a2 : id;
|
|
1083
1380
|
};
|
|
1084
1381
|
const matchesFilter = (id) => typeof stores === "function" ? stores(id) : stores.includes(id);
|
|
1085
1382
|
for (const storeData of deserStores) {
|
|
@@ -1156,218 +1453,23 @@ Has: ${checksum}`);
|
|
|
1156
1453
|
return this.stores.filter((s) => typeof stores === "undefined" ? true : Array.isArray(stores) ? stores.includes(s.id) : stores(s.id));
|
|
1157
1454
|
}
|
|
1158
1455
|
};
|
|
1159
|
-
var createNanoEvents = () => ({
|
|
1160
|
-
emit(event, ...args) {
|
|
1161
|
-
for (let callbacks = this.events[event] || [], i = 0, length = callbacks.length; i < length; i++) {
|
|
1162
|
-
callbacks[i](...args);
|
|
1163
|
-
}
|
|
1164
|
-
},
|
|
1165
|
-
events: {},
|
|
1166
|
-
on(event, cb) {
|
|
1167
|
-
;
|
|
1168
|
-
(this.events[event] ||= []).push(cb);
|
|
1169
|
-
return () => {
|
|
1170
|
-
var _a;
|
|
1171
|
-
this.events[event] = (_a = this.events[event]) == null ? void 0 : _a.filter((i) => cb !== i);
|
|
1172
|
-
};
|
|
1173
|
-
}
|
|
1174
|
-
});
|
|
1175
|
-
var NanoEmitter = class {
|
|
1176
|
-
events = createNanoEvents();
|
|
1177
|
-
eventUnsubscribes = [];
|
|
1178
|
-
emitterOptions;
|
|
1179
|
-
/** Creates a new instance of NanoEmitter - a lightweight event emitter with helper methods and a strongly typed event map */
|
|
1180
|
-
constructor(options = {}) {
|
|
1181
|
-
this.emitterOptions = {
|
|
1182
|
-
publicEmit: false,
|
|
1183
|
-
...options
|
|
1184
|
-
};
|
|
1185
|
-
}
|
|
1186
|
-
//#region on
|
|
1187
|
-
/**
|
|
1188
|
-
* Subscribes to an event and calls the callback when it's emitted.
|
|
1189
|
-
* @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 "_")
|
|
1190
|
-
* @returns Returns a function that can be called to unsubscribe the event listener
|
|
1191
|
-
* @example ```ts
|
|
1192
|
-
* const emitter = new NanoEmitter<{
|
|
1193
|
-
* foo: (bar: string) => void;
|
|
1194
|
-
* }>({
|
|
1195
|
-
* publicEmit: true,
|
|
1196
|
-
* });
|
|
1197
|
-
*
|
|
1198
|
-
* let i = 0;
|
|
1199
|
-
* const unsub = emitter.on("foo", (bar) => {
|
|
1200
|
-
* // unsubscribe after 10 events:
|
|
1201
|
-
* if(++i === 10) unsub();
|
|
1202
|
-
* console.log(bar);
|
|
1203
|
-
* });
|
|
1204
|
-
*
|
|
1205
|
-
* emitter.emit("foo", "bar");
|
|
1206
|
-
* ```
|
|
1207
|
-
*/
|
|
1208
|
-
on(event, cb) {
|
|
1209
|
-
let unsub;
|
|
1210
|
-
const unsubProxy = () => {
|
|
1211
|
-
if (!unsub)
|
|
1212
|
-
return;
|
|
1213
|
-
unsub();
|
|
1214
|
-
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => u !== unsub);
|
|
1215
|
-
};
|
|
1216
|
-
unsub = this.events.on(event, cb);
|
|
1217
|
-
this.eventUnsubscribes.push(unsub);
|
|
1218
|
-
return unsubProxy;
|
|
1219
|
-
}
|
|
1220
|
-
//#region once
|
|
1221
|
-
/**
|
|
1222
|
-
* Subscribes to an event and calls the callback or resolves the Promise only once when it's emitted.
|
|
1223
|
-
* @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 "_")
|
|
1224
|
-
* @param cb The callback to call when the event is emitted - if provided or not, the returned Promise will resolve with the event arguments
|
|
1225
|
-
* @returns Returns a Promise that resolves with the event arguments when the event is emitted
|
|
1226
|
-
* @example ```ts
|
|
1227
|
-
* const emitter = new NanoEmitter<{
|
|
1228
|
-
* foo: (bar: string) => void;
|
|
1229
|
-
* }>();
|
|
1230
|
-
*
|
|
1231
|
-
* // Promise syntax:
|
|
1232
|
-
* const [bar] = await emitter.once("foo");
|
|
1233
|
-
* console.log(bar);
|
|
1234
|
-
*
|
|
1235
|
-
* // Callback syntax:
|
|
1236
|
-
* emitter.once("foo", (bar) => console.log(bar));
|
|
1237
|
-
* ```
|
|
1238
|
-
*/
|
|
1239
|
-
once(event, cb) {
|
|
1240
|
-
return new Promise((resolve) => {
|
|
1241
|
-
let unsub;
|
|
1242
|
-
const onceProxy = ((...args) => {
|
|
1243
|
-
cb == null ? void 0 : cb(...args);
|
|
1244
|
-
unsub == null ? void 0 : unsub();
|
|
1245
|
-
resolve(args);
|
|
1246
|
-
});
|
|
1247
|
-
unsub = this.events.on(event, onceProxy);
|
|
1248
|
-
this.eventUnsubscribes.push(unsub);
|
|
1249
|
-
});
|
|
1250
|
-
}
|
|
1251
|
-
//#region onMulti
|
|
1252
|
-
/**
|
|
1253
|
-
* Allows subscribing to multiple events and calling the callback only when one of, all of, or a subset of the events are emitted, either continuously or only once.
|
|
1254
|
-
* @param options An object or array of objects with the following properties:
|
|
1255
|
-
* `callback` (required) is the function that will be called when the conditions are met.
|
|
1256
|
-
*
|
|
1257
|
-
* Set `once` to true to call the callback only once for the first event (or set of events) that match the criteria, then stop listening.
|
|
1258
|
-
* If `signal` is provided, the subscription will be canceled when the given signal is aborted.
|
|
1259
|
-
*
|
|
1260
|
-
* If `oneOf` is used, the callback will be called when any of the matching events are emitted.
|
|
1261
|
-
* If `allOf` is used, the callback will be called after all of the matching events are emitted at least once, then any time any of them are emitted.
|
|
1262
|
-
* If both `oneOf` and `allOf` are used together, the callback will be called when any of the `oneOf` events are emitted AND all of the `allOf` events have been emitted at least once.
|
|
1263
|
-
* At least one of `oneOf` or `allOf` must be provided.
|
|
1264
|
-
*
|
|
1265
|
-
* @returns Returns a function that can be called to unsubscribe all listeners created by this call. Alternatively, pass an `AbortSignal` to all options objects to achieve the same effect or for finer control.
|
|
1266
|
-
*/
|
|
1267
|
-
onMulti(options) {
|
|
1268
|
-
const allUnsubs = [];
|
|
1269
|
-
const unsubAll = () => {
|
|
1270
|
-
for (const unsub of allUnsubs)
|
|
1271
|
-
unsub();
|
|
1272
|
-
allUnsubs.splice(0, allUnsubs.length);
|
|
1273
|
-
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !allUnsubs.includes(u));
|
|
1274
|
-
};
|
|
1275
|
-
for (const opts of Array.isArray(options) ? options : [options]) {
|
|
1276
|
-
const optsWithDefaults = {
|
|
1277
|
-
allOf: [],
|
|
1278
|
-
oneOf: [],
|
|
1279
|
-
once: false,
|
|
1280
|
-
...opts
|
|
1281
|
-
};
|
|
1282
|
-
const {
|
|
1283
|
-
oneOf,
|
|
1284
|
-
allOf,
|
|
1285
|
-
once,
|
|
1286
|
-
signal,
|
|
1287
|
-
callback
|
|
1288
|
-
} = optsWithDefaults;
|
|
1289
|
-
if (signal == null ? void 0 : signal.aborted)
|
|
1290
|
-
return unsubAll;
|
|
1291
|
-
if (oneOf.length === 0 && allOf.length === 0)
|
|
1292
|
-
throw new TypeError("NanoEmitter.onMulti(): Either `oneOf` or `allOf` or both must be provided in the options");
|
|
1293
|
-
const curEvtUnsubs = [];
|
|
1294
|
-
const checkUnsubAllEvt = (force = false) => {
|
|
1295
|
-
if (!(signal == null ? void 0 : signal.aborted) && !force)
|
|
1296
|
-
return;
|
|
1297
|
-
for (const unsub of curEvtUnsubs)
|
|
1298
|
-
unsub();
|
|
1299
|
-
curEvtUnsubs.splice(0, curEvtUnsubs.length);
|
|
1300
|
-
this.eventUnsubscribes = this.eventUnsubscribes.filter((u) => !curEvtUnsubs.includes(u));
|
|
1301
|
-
};
|
|
1302
|
-
const allOfEmitted = /* @__PURE__ */ new Set();
|
|
1303
|
-
const allOfConditionMet = () => allOf.length === 0 || allOfEmitted.size === allOf.length;
|
|
1304
|
-
for (const event of oneOf) {
|
|
1305
|
-
const unsub = this.events.on(event, ((...args) => {
|
|
1306
|
-
checkUnsubAllEvt();
|
|
1307
|
-
if (allOfConditionMet()) {
|
|
1308
|
-
callback(event, ...args);
|
|
1309
|
-
if (once)
|
|
1310
|
-
checkUnsubAllEvt(true);
|
|
1311
|
-
}
|
|
1312
|
-
}));
|
|
1313
|
-
curEvtUnsubs.push(unsub);
|
|
1314
|
-
}
|
|
1315
|
-
for (const event of allOf) {
|
|
1316
|
-
const unsub = this.events.on(event, ((...args) => {
|
|
1317
|
-
checkUnsubAllEvt();
|
|
1318
|
-
allOfEmitted.add(event);
|
|
1319
|
-
if (allOfConditionMet() && (oneOf.length === 0 || oneOf.includes(event))) {
|
|
1320
|
-
callback(event, ...args);
|
|
1321
|
-
if (once)
|
|
1322
|
-
checkUnsubAllEvt(true);
|
|
1323
|
-
}
|
|
1324
|
-
}));
|
|
1325
|
-
curEvtUnsubs.push(unsub);
|
|
1326
|
-
}
|
|
1327
|
-
allUnsubs.push(() => checkUnsubAllEvt(true));
|
|
1328
|
-
}
|
|
1329
|
-
return unsubAll;
|
|
1330
|
-
}
|
|
1331
|
-
//#region emit
|
|
1332
|
-
/**
|
|
1333
|
-
* Emits an event on this instance.
|
|
1334
|
-
* - ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
1335
|
-
* @param event The event to emit
|
|
1336
|
-
* @param args The arguments to pass to the event listeners
|
|
1337
|
-
* @returns Returns true if `publicEmit` is true and the event was emitted successfully
|
|
1338
|
-
*/
|
|
1339
|
-
emit(event, ...args) {
|
|
1340
|
-
if (this.emitterOptions.publicEmit) {
|
|
1341
|
-
this.events.emit(event, ...args);
|
|
1342
|
-
return true;
|
|
1343
|
-
}
|
|
1344
|
-
return false;
|
|
1345
|
-
}
|
|
1346
|
-
//#region unsubscribeAll
|
|
1347
|
-
/** Unsubscribes all event listeners from this instance */
|
|
1348
|
-
unsubscribeAll() {
|
|
1349
|
-
for (const unsub of this.eventUnsubscribes)
|
|
1350
|
-
unsub();
|
|
1351
|
-
this.eventUnsubscribes = [];
|
|
1352
|
-
}
|
|
1353
|
-
};
|
|
1354
1456
|
var Debouncer = class extends NanoEmitter {
|
|
1355
1457
|
/**
|
|
1356
1458
|
* Creates a new debouncer with the specified timeout and edge type.
|
|
1357
1459
|
* @param timeout Timeout in milliseconds between letting through calls - defaults to 200
|
|
1358
1460
|
* @param type The edge type to use for the debouncer - see {@linkcode DebouncerType} for details or [the documentation for an explanation and diagram](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#debouncer) - defaults to "immediate"
|
|
1359
1461
|
*/
|
|
1360
|
-
constructor(timeout = 200, type = "immediate") {
|
|
1361
|
-
super();
|
|
1462
|
+
constructor(timeout = 200, type = "immediate", nanoEmitterOptions) {
|
|
1463
|
+
super(nanoEmitterOptions);
|
|
1464
|
+
/** All registered listener functions and the time they were attached */
|
|
1465
|
+
__publicField(this, "listeners", []);
|
|
1466
|
+
/** The currently active timeout */
|
|
1467
|
+
__publicField(this, "activeTimeout");
|
|
1468
|
+
/** The latest queued call */
|
|
1469
|
+
__publicField(this, "queuedCall");
|
|
1362
1470
|
this.timeout = timeout;
|
|
1363
1471
|
this.type = type;
|
|
1364
1472
|
}
|
|
1365
|
-
/** All registered listener functions and the time they were attached */
|
|
1366
|
-
listeners = [];
|
|
1367
|
-
/** The currently active timeout */
|
|
1368
|
-
activeTimeout;
|
|
1369
|
-
/** The latest queued call */
|
|
1370
|
-
queuedCall;
|
|
1371
1473
|
//#region listeners
|
|
1372
1474
|
/** Adds a listener function that will be called on timeout */
|
|
1373
1475
|
addListener(fn) {
|
|
@@ -1389,7 +1491,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1389
1491
|
//#region timeout
|
|
1390
1492
|
/** Sets the timeout for the debouncer */
|
|
1391
1493
|
setTimeout(timeout) {
|
|
1392
|
-
this.emit("change", this.timeout = timeout, this.type);
|
|
1494
|
+
this.events.emit("change", this.timeout = timeout, this.type);
|
|
1393
1495
|
}
|
|
1394
1496
|
/** Returns the current timeout */
|
|
1395
1497
|
getTimeout() {
|
|
@@ -1402,7 +1504,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1402
1504
|
//#region type
|
|
1403
1505
|
/** Sets the edge type for the debouncer */
|
|
1404
1506
|
setType(type) {
|
|
1405
|
-
this.emit("change", this.timeout, this.type = type);
|
|
1507
|
+
this.events.emit("change", this.timeout, this.type = type);
|
|
1406
1508
|
}
|
|
1407
1509
|
/** Returns the current edge type */
|
|
1408
1510
|
getType() {
|
|
@@ -1413,7 +1515,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1413
1515
|
call(...args) {
|
|
1414
1516
|
const cl = (...a) => {
|
|
1415
1517
|
this.queuedCall = void 0;
|
|
1416
|
-
this.emit("call", ...a);
|
|
1518
|
+
this.events.emit("call", ...a);
|
|
1417
1519
|
this.listeners.forEach((l) => l.call(this, ...a));
|
|
1418
1520
|
};
|
|
1419
1521
|
const setRepeatTimeout = () => {
|
|
@@ -1446,14 +1548,30 @@ var Debouncer = class extends NanoEmitter {
|
|
|
1446
1548
|
}
|
|
1447
1549
|
}
|
|
1448
1550
|
};
|
|
1449
|
-
function debounce(fn, timeout = 200, type = "immediate") {
|
|
1450
|
-
const debouncer = new Debouncer(timeout, type);
|
|
1551
|
+
function debounce(fn, timeout = 200, type = "immediate", nanoEmitterOptions) {
|
|
1552
|
+
const debouncer = new Debouncer(timeout, type, nanoEmitterOptions);
|
|
1451
1553
|
debouncer.addListener(fn);
|
|
1452
1554
|
const func = ((...args) => debouncer.call(...args));
|
|
1453
1555
|
func.debouncer = debouncer;
|
|
1454
1556
|
return func;
|
|
1455
1557
|
}
|
|
1456
1558
|
|
|
1559
|
+
// lib/consts.ts
|
|
1560
|
+
var rawConsts = {
|
|
1561
|
+
coreUtilsVersion: "3.4.0",
|
|
1562
|
+
userUtilsVersion: "10.2.0"
|
|
1563
|
+
};
|
|
1564
|
+
function getConst(constKey, defaultVal) {
|
|
1565
|
+
const val = rawConsts[constKey];
|
|
1566
|
+
return val.match(/^#\{\{.+\}\}$/) ? defaultVal : val;
|
|
1567
|
+
}
|
|
1568
|
+
var versions = {
|
|
1569
|
+
/** Semver version string of the bundled library CoreUtils. */
|
|
1570
|
+
CoreUtils: getConst("coreUtilsVersion", "ERR:unknown"),
|
|
1571
|
+
/** Semver version string of UserUtils. */
|
|
1572
|
+
UserUtils: getConst("userUtilsVersion", "ERR:unknown")
|
|
1573
|
+
};
|
|
1574
|
+
|
|
1457
1575
|
// lib/Errors.ts
|
|
1458
1576
|
var PlatformError = class extends DatedError {
|
|
1459
1577
|
constructor(message, options) {
|
|
@@ -1466,7 +1584,7 @@ var PlatformError = class extends DatedError {
|
|
|
1466
1584
|
function getUnsafeWindow() {
|
|
1467
1585
|
try {
|
|
1468
1586
|
return unsafeWindow;
|
|
1469
|
-
} catch {
|
|
1587
|
+
} catch (e) {
|
|
1470
1588
|
return window;
|
|
1471
1589
|
}
|
|
1472
1590
|
}
|
|
@@ -1497,7 +1615,7 @@ function openInNewTab(href, background, additionalProps) {
|
|
|
1497
1615
|
try {
|
|
1498
1616
|
if (typeof window.GM === "object")
|
|
1499
1617
|
GM.openInTab(href, background);
|
|
1500
|
-
} catch {
|
|
1618
|
+
} catch (e) {
|
|
1501
1619
|
const openElem = document.createElement("a");
|
|
1502
1620
|
Object.assign(openElem, {
|
|
1503
1621
|
className: "userutils-open-in-new-tab",
|
|
@@ -1517,7 +1635,7 @@ function openInNewTab(href, background, additionalProps) {
|
|
|
1517
1635
|
setTimeout(() => {
|
|
1518
1636
|
try {
|
|
1519
1637
|
openElem.remove();
|
|
1520
|
-
} catch {
|
|
1638
|
+
} catch (e2) {
|
|
1521
1639
|
}
|
|
1522
1640
|
}, 0);
|
|
1523
1641
|
}
|
|
@@ -1533,8 +1651,8 @@ function interceptEvent(eventObject, eventName, predicate = () => true) {
|
|
|
1533
1651
|
}
|
|
1534
1652
|
(function(original) {
|
|
1535
1653
|
eventObject.__proto__.addEventListener = function(...args) {
|
|
1536
|
-
var _a2;
|
|
1537
|
-
const origListener = typeof args[1] === "function" ? args[1] : ((_a2 = args[1]) == null ? void 0 : _a2.handleEvent)
|
|
1654
|
+
var _a2, _b;
|
|
1655
|
+
const origListener = typeof args[1] === "function" ? args[1] : (_b = (_a2 = args[1]) == null ? void 0 : _a2.handleEvent) != null ? _b : (() => void 0);
|
|
1538
1656
|
args[1] = function(...a) {
|
|
1539
1657
|
if (args[0] === eventName && predicate(Array.isArray(a) ? a[0] : a))
|
|
1540
1658
|
return;
|
|
@@ -1577,8 +1695,8 @@ function observeElementProp(element, property, callback) {
|
|
|
1577
1695
|
}
|
|
1578
1696
|
}
|
|
1579
1697
|
function getSiblingsFrame(refElement, siblingAmount, refElementAlignment = "center-top", includeRef = true) {
|
|
1580
|
-
var _a;
|
|
1581
|
-
const siblings = [...((_a = refElement.parentNode) == null ? void 0 : _a.childNodes)
|
|
1698
|
+
var _a, _b;
|
|
1699
|
+
const siblings = [...(_b = (_a = refElement.parentNode) == null ? void 0 : _a.childNodes) != null ? _b : []];
|
|
1582
1700
|
const elemSiblIdx = siblings.indexOf(refElement);
|
|
1583
1701
|
if (elemSiblIdx === -1)
|
|
1584
1702
|
throw new Error("Element doesn't have a parent node");
|
|
@@ -1599,13 +1717,13 @@ function getSiblingsFrame(refElement, siblingAmount, refElementAlignment = "cent
|
|
|
1599
1717
|
}
|
|
1600
1718
|
var ttPolicy;
|
|
1601
1719
|
function setInnerHtmlUnsafe(element, html) {
|
|
1602
|
-
var _a, _b;
|
|
1720
|
+
var _a, _b, _c;
|
|
1603
1721
|
if (!ttPolicy && typeof ((_a = window == null ? void 0 : window.trustedTypes) == null ? void 0 : _a.createPolicy) === "function") {
|
|
1604
1722
|
ttPolicy = window.trustedTypes.createPolicy("_uu_set_innerhtml_unsafe", {
|
|
1605
1723
|
createHTML: (unsafeHtml) => unsafeHtml
|
|
1606
1724
|
});
|
|
1607
1725
|
}
|
|
1608
|
-
element.innerHTML = ((_b = ttPolicy == null ? void 0 : ttPolicy.createHTML) == null ? void 0 : _b.call(ttPolicy, html))
|
|
1726
|
+
element.innerHTML = (_c = (_b = ttPolicy == null ? void 0 : ttPolicy.createHTML) == null ? void 0 : _b.call(ttPolicy, html)) != null ? _c : html;
|
|
1609
1727
|
return element;
|
|
1610
1728
|
}
|
|
1611
1729
|
function probeElementStyle(probeStyle, element, hideOffscreen = true, parentElement = document.body) {
|
|
@@ -1798,20 +1916,20 @@ var defaultStrings = {
|
|
|
1798
1916
|
closeDialogTooltip: "Click to close the dialog"
|
|
1799
1917
|
};
|
|
1800
1918
|
var Dialog = class _Dialog extends NanoEmitter {
|
|
1801
|
-
/** Options passed to the dialog in the constructor */
|
|
1802
|
-
options;
|
|
1803
|
-
/** ID that gets added to child element IDs - has to be unique and conform to HTML ID naming rules! */
|
|
1804
|
-
id;
|
|
1805
|
-
/** Strings used in the dialog (used for translations) */
|
|
1806
|
-
strings;
|
|
1807
|
-
dialogOpen = false;
|
|
1808
|
-
dialogMounted = false;
|
|
1809
1919
|
constructor(options) {
|
|
1810
1920
|
super();
|
|
1921
|
+
/** Options passed to the dialog in the constructor */
|
|
1922
|
+
__publicField(this, "options");
|
|
1923
|
+
/** ID that gets added to child element IDs - has to be unique and conform to HTML ID naming rules! */
|
|
1924
|
+
__publicField(this, "id");
|
|
1925
|
+
/** Strings used in the dialog (used for translations) */
|
|
1926
|
+
__publicField(this, "strings");
|
|
1927
|
+
__publicField(this, "dialogOpen", false);
|
|
1928
|
+
__publicField(this, "dialogMounted", false);
|
|
1811
1929
|
const { strings, ...opts } = options;
|
|
1812
1930
|
this.strings = {
|
|
1813
1931
|
...defaultStrings,
|
|
1814
|
-
...strings
|
|
1932
|
+
...strings != null ? strings : {}
|
|
1815
1933
|
};
|
|
1816
1934
|
this.options = {
|
|
1817
1935
|
closeOnBgClick: true,
|
|
@@ -1828,11 +1946,12 @@ var Dialog = class _Dialog extends NanoEmitter {
|
|
|
1828
1946
|
//#region public
|
|
1829
1947
|
/** Call after DOMContentLoaded to pre-render the dialog and invisibly mount it in the DOM */
|
|
1830
1948
|
async mount() {
|
|
1949
|
+
var _a;
|
|
1831
1950
|
if (this.dialogMounted)
|
|
1832
1951
|
return;
|
|
1833
1952
|
this.dialogMounted = true;
|
|
1834
1953
|
if (!document.querySelector("style.uu-dialog-css"))
|
|
1835
|
-
addGlobalStyle(this.options.dialogCss
|
|
1954
|
+
addGlobalStyle((_a = this.options.dialogCss) != null ? _a : defaultDialogCss).classList.add("uu-dialog-css");
|
|
1836
1955
|
const bgElem = document.createElement("div");
|
|
1837
1956
|
bgElem.id = `uu-${this.id}-dialog-bg`;
|
|
1838
1957
|
bgElem.classList.add("uu-dialog-bg");
|
|
@@ -1900,7 +2019,7 @@ var Dialog = class _Dialog extends NanoEmitter {
|
|
|
1900
2019
|
}
|
|
1901
2020
|
/** Closes the dialog - prevents default action and immediate propagation of the passed event */
|
|
1902
2021
|
close(e) {
|
|
1903
|
-
var _a;
|
|
2022
|
+
var _a, _b;
|
|
1904
2023
|
e == null ? void 0 : e.preventDefault();
|
|
1905
2024
|
e == null ? void 0 : e.stopImmediatePropagation();
|
|
1906
2025
|
if (!this.isOpen())
|
|
@@ -1913,9 +2032,9 @@ var Dialog = class _Dialog extends NanoEmitter {
|
|
|
1913
2032
|
dialogBg.style.display = "none";
|
|
1914
2033
|
dialogBg.inert = true;
|
|
1915
2034
|
openDialogs.splice(openDialogs.indexOf(this.id), 1);
|
|
1916
|
-
currentDialogId = openDialogs[0]
|
|
2035
|
+
currentDialogId = (_a = openDialogs[0]) != null ? _a : null;
|
|
1917
2036
|
if (currentDialogId)
|
|
1918
|
-
(
|
|
2037
|
+
(_b = document.querySelector(`#uu-${currentDialogId}-dialog-bg`)) == null ? void 0 : _b.removeAttribute("inert");
|
|
1919
2038
|
if (openDialogs.length === 0) {
|
|
1920
2039
|
document.body.classList.add("uu-no-select");
|
|
1921
2040
|
document.body.removeAttribute("inert");
|
|
@@ -1951,7 +2070,8 @@ var Dialog = class _Dialog extends NanoEmitter {
|
|
|
1951
2070
|
}
|
|
1952
2071
|
//#region protected
|
|
1953
2072
|
getString(key) {
|
|
1954
|
-
|
|
2073
|
+
var _a;
|
|
2074
|
+
return (_a = this.strings[key]) != null ? _a : defaultStrings[key];
|
|
1955
2075
|
}
|
|
1956
2076
|
/** Called once to attach all generic event listeners */
|
|
1957
2077
|
attachListeners(bgElem) {
|
|
@@ -1976,7 +2096,7 @@ var Dialog = class _Dialog extends NanoEmitter {
|
|
|
1976
2096
|
* @param listenerOptions Provide a {@linkcode listenerOptions} object to configure the listeners
|
|
1977
2097
|
*/
|
|
1978
2098
|
onInteraction(elem, listener, listenerOptions) {
|
|
1979
|
-
const { preventDefault = true, stopPropagation = true, ...listenerOpts } = listenerOptions
|
|
2099
|
+
const { preventDefault = true, stopPropagation = true, ...listenerOpts } = listenerOptions != null ? listenerOptions : {};
|
|
1980
2100
|
const interactionKeys = ["Enter", " ", "Space"];
|
|
1981
2101
|
const proxListener = (e) => {
|
|
1982
2102
|
if (e instanceof KeyboardEvent) {
|
|
@@ -2056,7 +2176,6 @@ var Dialog = class _Dialog extends NanoEmitter {
|
|
|
2056
2176
|
|
|
2057
2177
|
// lib/GMStorageEngine.ts
|
|
2058
2178
|
var GMStorageEngine = class extends DataStoreEngine {
|
|
2059
|
-
options;
|
|
2060
2179
|
/**
|
|
2061
2180
|
* Creates an instance of `GMStorageEngine`.
|
|
2062
2181
|
*
|
|
@@ -2065,6 +2184,7 @@ var GMStorageEngine = class extends DataStoreEngine {
|
|
|
2065
2184
|
*/
|
|
2066
2185
|
constructor(options) {
|
|
2067
2186
|
super(options == null ? void 0 : options.dataStoreOptions);
|
|
2187
|
+
__publicField(this, "options");
|
|
2068
2188
|
this.options = {
|
|
2069
2189
|
...options
|
|
2070
2190
|
};
|
|
@@ -2120,25 +2240,26 @@ var GMStorageEngine = class extends DataStoreEngine {
|
|
|
2120
2240
|
|
|
2121
2241
|
// lib/Mixins.ts
|
|
2122
2242
|
var Mixins = class {
|
|
2123
|
-
/** List of all registered mixins */
|
|
2124
|
-
mixins = [];
|
|
2125
|
-
/** Default configuration object for mixins */
|
|
2126
|
-
defaultMixinCfg;
|
|
2127
|
-
/** Whether the priorities should auto-increment if not specified */
|
|
2128
|
-
autoIncPrioEnabled;
|
|
2129
|
-
/** The current auto-increment priority counter */
|
|
2130
|
-
autoIncPrioCounter = /* @__PURE__ */ new Map();
|
|
2131
2243
|
/**
|
|
2132
2244
|
* Creates a new Mixins instance.
|
|
2133
2245
|
* @param config Configuration object to customize the behavior.
|
|
2134
2246
|
*/
|
|
2135
2247
|
constructor(config = {}) {
|
|
2248
|
+
/** List of all registered mixins */
|
|
2249
|
+
__publicField(this, "mixins", []);
|
|
2250
|
+
/** Default configuration object for mixins */
|
|
2251
|
+
__publicField(this, "defaultMixinCfg");
|
|
2252
|
+
/** Whether the priorities should auto-increment if not specified */
|
|
2253
|
+
__publicField(this, "autoIncPrioEnabled");
|
|
2254
|
+
/** The current auto-increment priority counter */
|
|
2255
|
+
__publicField(this, "autoIncPrioCounter", /* @__PURE__ */ new Map());
|
|
2256
|
+
var _a, _b, _c;
|
|
2136
2257
|
this.defaultMixinCfg = pureObj({
|
|
2137
|
-
priority: config.defaultPriority
|
|
2138
|
-
stopPropagation: config.defaultStopPropagation
|
|
2258
|
+
priority: (_a = config.defaultPriority) != null ? _a : 0,
|
|
2259
|
+
stopPropagation: (_b = config.defaultStopPropagation) != null ? _b : false,
|
|
2139
2260
|
signal: config.defaultSignal
|
|
2140
2261
|
});
|
|
2141
|
-
this.autoIncPrioEnabled = config.autoIncrementPriority
|
|
2262
|
+
this.autoIncPrioEnabled = (_c = config.autoIncrementPriority) != null ? _c : false;
|
|
2142
2263
|
}
|
|
2143
2264
|
//#region public
|
|
2144
2265
|
/**
|
|
@@ -2203,10 +2324,11 @@ var Mixins = class {
|
|
|
2203
2324
|
//#region protected
|
|
2204
2325
|
/** Calculates the priority for a mixin based on the given configuration and the current auto-increment state of the instance */
|
|
2205
2326
|
calcPriority(mixinKey, config) {
|
|
2327
|
+
var _a;
|
|
2206
2328
|
if (config.priority !== void 0)
|
|
2207
2329
|
return void 0;
|
|
2208
2330
|
if (!this.autoIncPrioEnabled)
|
|
2209
|
-
return config.priority
|
|
2331
|
+
return (_a = config.priority) != null ? _a : this.defaultMixinCfg.priority;
|
|
2210
2332
|
if (!this.autoIncPrioCounter.has(mixinKey))
|
|
2211
2333
|
this.autoIncPrioCounter.set(mixinKey, this.defaultMixinCfg.priority);
|
|
2212
2334
|
let prio = this.autoIncPrioCounter.get(mixinKey);
|
|
@@ -2227,13 +2349,13 @@ var Mixins = class {
|
|
|
2227
2349
|
|
|
2228
2350
|
// lib/SelectorObserver.ts
|
|
2229
2351
|
var SelectorObserver = class {
|
|
2230
|
-
enabled = false;
|
|
2231
|
-
baseElement;
|
|
2232
|
-
observer;
|
|
2233
|
-
observerOptions;
|
|
2234
|
-
customOptions;
|
|
2235
|
-
listenerMap;
|
|
2236
2352
|
constructor(baseElement, options = {}) {
|
|
2353
|
+
__publicField(this, "enabled", false);
|
|
2354
|
+
__publicField(this, "baseElement");
|
|
2355
|
+
__publicField(this, "observer");
|
|
2356
|
+
__publicField(this, "observerOptions");
|
|
2357
|
+
__publicField(this, "customOptions");
|
|
2358
|
+
__publicField(this, "listenerMap");
|
|
2237
2359
|
this.baseElement = baseElement;
|
|
2238
2360
|
this.listenerMap = /* @__PURE__ */ new Map();
|
|
2239
2361
|
const {
|
|
@@ -2249,10 +2371,10 @@ var SelectorObserver = class {
|
|
|
2249
2371
|
...observerOptions
|
|
2250
2372
|
};
|
|
2251
2373
|
this.customOptions = {
|
|
2252
|
-
defaultDebounce: defaultDebounce
|
|
2253
|
-
defaultDebounceType: defaultDebounceType
|
|
2254
|
-
disableOnNoListeners: disableOnNoListeners
|
|
2255
|
-
enableOnAddListener: enableOnAddListener
|
|
2374
|
+
defaultDebounce: defaultDebounce != null ? defaultDebounce : 0,
|
|
2375
|
+
defaultDebounceType: defaultDebounceType != null ? defaultDebounceType : "immediate",
|
|
2376
|
+
disableOnNoListeners: disableOnNoListeners != null ? disableOnNoListeners : false,
|
|
2377
|
+
enableOnAddListener: enableOnAddListener != null ? enableOnAddListener : true
|
|
2256
2378
|
};
|
|
2257
2379
|
if (typeof this.customOptions.checkInterval !== "number") {
|
|
2258
2380
|
this.observer = new MutationObserver(() => this.checkAllSelectors());
|
|
@@ -2403,9 +2525,9 @@ var valTransforms = [];
|
|
|
2403
2525
|
var fallbackLang;
|
|
2404
2526
|
function translate(language, key, ...trArgs) {
|
|
2405
2527
|
if (typeof language !== "string")
|
|
2406
|
-
language = fallbackLang
|
|
2528
|
+
language = fallbackLang != null ? fallbackLang : "";
|
|
2407
2529
|
const trObj = trans[language];
|
|
2408
|
-
if (typeof language !== "string" ||
|
|
2530
|
+
if (typeof language !== "string" || typeof trObj !== "object" || trObj === null)
|
|
2409
2531
|
return fallbackLang && language !== fallbackLang ? translate(fallbackLang, key, ...trArgs) : key;
|
|
2410
2532
|
const transformTrVal = (trKey, trValue) => {
|
|
2411
2533
|
const tfs = valTransforms.filter(({ regex }) => new RegExp(regex).test(String(trValue)));
|
|
@@ -2457,15 +2579,18 @@ function trFor(language, key, ...args) {
|
|
|
2457
2579
|
function useTr(language) {
|
|
2458
2580
|
return (key, ...args) => translate(language, key, ...args);
|
|
2459
2581
|
}
|
|
2460
|
-
function hasKey(language = fallbackLang
|
|
2582
|
+
function hasKey(language = fallbackLang != null ? fallbackLang : "", key) {
|
|
2461
2583
|
return tr.for(language, key) !== key;
|
|
2462
2584
|
}
|
|
2463
2585
|
function addTranslations(language, translations) {
|
|
2464
2586
|
trans[language] = JSON.parse(JSON.stringify(translations));
|
|
2465
2587
|
}
|
|
2466
|
-
function getTranslations(language = fallbackLang
|
|
2588
|
+
function getTranslations(language = fallbackLang != null ? fallbackLang : "") {
|
|
2467
2589
|
return trans[language];
|
|
2468
2590
|
}
|
|
2591
|
+
function getAllTranslations(asCopy = true) {
|
|
2592
|
+
return asCopy ? JSON.parse(JSON.stringify(trans)) : trans;
|
|
2593
|
+
}
|
|
2469
2594
|
var deleteTranslations = (language) => {
|
|
2470
2595
|
if (language in trans) {
|
|
2471
2596
|
delete trans[language];
|
|
@@ -2496,51 +2621,55 @@ function deleteTransform(patternOrFn) {
|
|
|
2496
2621
|
}
|
|
2497
2622
|
return false;
|
|
2498
2623
|
}
|
|
2499
|
-
var
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
const
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
const repl = match[1] !== void 0 ? trArgs[0][match[1]] : void 0;
|
|
2510
|
-
if (typeof repl !== "undefined")
|
|
2511
|
-
str = str.replace(match[0], String(repl));
|
|
2512
|
-
}
|
|
2513
|
-
};
|
|
2514
|
-
const positionalMapping = () => {
|
|
2515
|
-
if (!patternRegex.test(str) || !trArgs[0])
|
|
2516
|
-
return;
|
|
2517
|
-
let matchNum = -1;
|
|
2518
|
-
for (const match of matches) {
|
|
2519
|
-
matchNum++;
|
|
2520
|
-
if (typeof trArgs[matchNum] !== "undefined")
|
|
2521
|
-
str = str.replace(match[0], String(trArgs[matchNum]));
|
|
2522
|
-
}
|
|
2523
|
-
};
|
|
2524
|
-
let notStringifiable = false;
|
|
2525
|
-
try {
|
|
2526
|
-
String(trArgs[0]);
|
|
2527
|
-
} catch {
|
|
2528
|
-
notStringifiable = true;
|
|
2624
|
+
var commonKeyedTransform = ({ matches, trArgs, trValue }, patternRegex, quickMatchPattern) => {
|
|
2625
|
+
let str = String(trValue);
|
|
2626
|
+
const someMatchKeyInArgs = (obj) => matches.some((match) => match[1] !== void 0 && match[1] in obj);
|
|
2627
|
+
const namedMapping = () => {
|
|
2628
|
+
if (!str.includes(quickMatchPattern) || typeof trArgs[0] === "undefined" || typeof trArgs[0] !== "object" || !someMatchKeyInArgs(trArgs[0]))
|
|
2629
|
+
return;
|
|
2630
|
+
for (const match of matches) {
|
|
2631
|
+
const repl = match[1] !== void 0 ? trArgs[0][match[1]] : void 0;
|
|
2632
|
+
if (typeof repl !== "undefined")
|
|
2633
|
+
str = str.replace(match[0], String(repl));
|
|
2529
2634
|
}
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2635
|
+
};
|
|
2636
|
+
const positionalMapping = () => {
|
|
2637
|
+
if (!patternRegex.test(str) || typeof trArgs[0] === "undefined")
|
|
2638
|
+
return;
|
|
2639
|
+
let matchNum = -1;
|
|
2640
|
+
for (const match of matches) {
|
|
2641
|
+
matchNum++;
|
|
2642
|
+
if (typeof trArgs[matchNum] !== "undefined")
|
|
2643
|
+
str = str.replace(match[0], String(trArgs[matchNum]));
|
|
2644
|
+
}
|
|
2645
|
+
};
|
|
2646
|
+
let notStringifiable = false;
|
|
2647
|
+
try {
|
|
2648
|
+
void `${trArgs[0]}`;
|
|
2649
|
+
} catch (e) {
|
|
2650
|
+
notStringifiable = true;
|
|
2536
2651
|
}
|
|
2652
|
+
const isArgsObject = trArgs[0] && typeof trArgs[0] === "object" && trArgs[0] !== null && (notStringifiable || String(trArgs[0]).startsWith("[object"));
|
|
2653
|
+
if (isArgsObject && someMatchKeyInArgs(trArgs[0]))
|
|
2654
|
+
namedMapping();
|
|
2655
|
+
else
|
|
2656
|
+
positionalMapping();
|
|
2657
|
+
return str;
|
|
2658
|
+
};
|
|
2659
|
+
var templateLiteralTransform = [
|
|
2660
|
+
/\$\{([a-zA-Z0-9$_-]+)\}/gm,
|
|
2661
|
+
(tfProps) => commonKeyedTransform(tfProps, /\$\{.+\}/m, "${")
|
|
2662
|
+
];
|
|
2663
|
+
var i18nTransform = [
|
|
2664
|
+
/\{\{([a-zA-Z0-9$_-]+)\}\}/gm,
|
|
2665
|
+
(tfProps) => commonKeyedTransform(tfProps, /\{\{.+\}\}/m, "{{")
|
|
2537
2666
|
];
|
|
2538
2667
|
var percentTransform = [
|
|
2539
2668
|
/%(\d+)/gm,
|
|
2540
2669
|
({ matches, trArgs, trValue }) => {
|
|
2541
2670
|
let str = String(trValue);
|
|
2542
2671
|
for (const match of matches) {
|
|
2543
|
-
const repl =
|
|
2672
|
+
const repl = trArgs == null ? void 0 : trArgs[Number(match[1]) - 1];
|
|
2544
2673
|
if (typeof repl !== "undefined")
|
|
2545
2674
|
str = str.replace(match[0], String(repl));
|
|
2546
2675
|
}
|
|
@@ -2550,17 +2679,84 @@ var percentTransform = [
|
|
|
2550
2679
|
var tr = {
|
|
2551
2680
|
for: (...params) => trFor(...params),
|
|
2552
2681
|
use: (...params) => useTr(...params),
|
|
2553
|
-
hasKey: (language = fallbackLang
|
|
2682
|
+
hasKey: (language = fallbackLang != null ? fallbackLang : "", key) => hasKey(language, key),
|
|
2554
2683
|
addTranslations,
|
|
2555
2684
|
getTranslations,
|
|
2685
|
+
getAllTranslations,
|
|
2556
2686
|
deleteTranslations,
|
|
2557
2687
|
setFallbackLanguage,
|
|
2558
2688
|
getFallbackLanguage,
|
|
2559
2689
|
addTransform,
|
|
2560
2690
|
deleteTransform,
|
|
2691
|
+
/** Collection of predefined transform functions that can be added via {@linkcode tr.addTransform()} */
|
|
2561
2692
|
transforms: {
|
|
2693
|
+
/**
|
|
2694
|
+
* This transform will replace placeholders matching `${key}` with the value of the passed argument(s).
|
|
2695
|
+
* The arguments can be passed in keyed object form or positionally via the spread operator:
|
|
2696
|
+
* - Keyed: If the first argument is an object and `key` is found in it, the value will be used for the replacement.
|
|
2697
|
+
* - Positional: If the first argument is not an object or has a `toString()` method that returns something that doesn't start with `[object`, the values will be positionally inserted in the order they were passed.
|
|
2698
|
+
*
|
|
2699
|
+
* @example ```ts
|
|
2700
|
+
* tr.addTranslations("en", {
|
|
2701
|
+
* "greeting": "Hello, ${user}!\nYou have ${notifs} notifications.",
|
|
2702
|
+
* });
|
|
2703
|
+
* tr.addTransform(tr.transforms.templateLiteral);
|
|
2704
|
+
*
|
|
2705
|
+
* const t = tr.use("en");
|
|
2706
|
+
*
|
|
2707
|
+
* // both calls return the same result:
|
|
2708
|
+
* t("greeting", { user: "John", notifs: 5 }); // "Hello, John!\nYou have 5 notifications."
|
|
2709
|
+
* t("greeting", "John", 5); // "Hello, John!\nYou have 5 notifications."
|
|
2710
|
+
*
|
|
2711
|
+
* // when a key isn't found in the object, it will be left as-is:
|
|
2712
|
+
* t("greeting", { user: "John" }); // "Hello, John!\nYou have ${notifs} notifications."
|
|
2713
|
+
* ```
|
|
2714
|
+
*/
|
|
2562
2715
|
templateLiteral: templateLiteralTransform,
|
|
2716
|
+
/**
|
|
2717
|
+
* This transform will replace placeholders matching `{{key}}` with the value of the passed argument(s).
|
|
2718
|
+
* This format is commonly used in i18n libraries. Note that advanced syntax is not supported, only simple key replacement.
|
|
2719
|
+
* The arguments can be passed in keyed object form or positionally via the spread operator:
|
|
2720
|
+
* - Keyed: If the first argument is an object and `key` is found in it, the value will be used for the replacement.
|
|
2721
|
+
* - Positional: If the first argument is not an object or has a `toString()` method that returns something that doesn't start with `[object`, the values will be positionally inserted in the order they were passed.
|
|
2722
|
+
*
|
|
2723
|
+
* @example ```ts
|
|
2724
|
+
* tr.addTranslations("en", {
|
|
2725
|
+
* "greeting": "Hello, {{user}}!\nYou have {{notifs}} notifications.",
|
|
2726
|
+
* });
|
|
2727
|
+
* tr.addTransform(tr.transforms.i18n);
|
|
2728
|
+
*
|
|
2729
|
+
* const t = tr.use("en");
|
|
2730
|
+
*
|
|
2731
|
+
* // both calls return the same result:
|
|
2732
|
+
* t("greeting", { user: "Alice", notifs: 5 }); // "Hello, Alice!\nYou have 5 notifications."
|
|
2733
|
+
* t("greeting", "Alice", 5); // "Hello, Alice!\nYou have 5 notifications."
|
|
2734
|
+
*
|
|
2735
|
+
* // when a key isn't found in the object, it will be left as-is:
|
|
2736
|
+
* t("greeting", { user: "Alice" }); // "Hello, Alice!\nYou have {{notifs}} notifications."
|
|
2737
|
+
* ```
|
|
2738
|
+
*/
|
|
2739
|
+
i18n: i18nTransform,
|
|
2740
|
+
/**
|
|
2741
|
+
* This transform will replace `%n` placeholders with the value of the passed arguments.
|
|
2742
|
+
* The `%n` placeholders are 1-indexed, meaning `%1` will be replaced by the first argument (index 0), `%2` by the second (index 1), and so on.
|
|
2743
|
+
* Objects will be stringified via `String()` before being inserted.
|
|
2744
|
+
*
|
|
2745
|
+
* @example ```ts
|
|
2746
|
+
* tr.addTranslations("en", {
|
|
2747
|
+
* "greeting": "Hello, %1!\nYou have %2 notifications.",
|
|
2748
|
+
* });
|
|
2749
|
+
* tr.addTransform(tr.transforms.percent);
|
|
2750
|
+
*
|
|
2751
|
+
* const t = tr.use("en");
|
|
2752
|
+
*
|
|
2753
|
+
* // arguments are inserted in the order they're passed:
|
|
2754
|
+
* t("greeting", "Bob", 5); // "Hello, Bob!\nYou have 5 notifications."
|
|
2755
|
+
*
|
|
2756
|
+
* // when a value isn't found, the placeholder will be left as-is:
|
|
2757
|
+
* t("greeting", "Bob"); // "Hello, Bob!\nYou have %2 notifications."
|
|
2758
|
+
* ```
|
|
2759
|
+
*/
|
|
2563
2760
|
percent: percentTransform
|
|
2564
2761
|
}
|
|
2565
2762
|
};
|
|
2566
|
-
//# sourceMappingURL=UserUtils.cjs.map
|