qznt 1.0.37 → 2.0.1
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/README.md +29 -58
- package/dist/index.cjs +497 -646
- package/dist/index.d.cts +368 -530
- package/dist/index.d.ts +368 -530
- package/dist/index.js +453 -607
- package/package.json +3 -4
package/dist/index.cjs
CHANGED
|
@@ -30,114 +30,325 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
$: () => $,
|
|
34
33
|
Cache: () => Cache,
|
|
34
|
+
FormatNumberCompact: () => FormatNumberCompact,
|
|
35
35
|
Loop: () => Loop,
|
|
36
36
|
Pipe: () => Pipe,
|
|
37
37
|
Storage: () => Storage,
|
|
38
|
-
chance: () => chance,
|
|
39
|
-
choice: () => choice,
|
|
40
38
|
chunk: () => chunk,
|
|
41
39
|
chunkAdj: () => chunkAdj,
|
|
42
|
-
|
|
40
|
+
clampNumber: () => clampNumber,
|
|
43
41
|
cluster: () => cluster,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
currency: () => currency,
|
|
42
|
+
compactArray: () => compactArray,
|
|
43
|
+
createSampler: () => createSampler,
|
|
47
44
|
debounce: () => debounce,
|
|
48
|
-
default: () => index_default,
|
|
49
|
-
defined: () => defined,
|
|
50
|
-
duration: () => duration,
|
|
51
|
-
empty: () => empty,
|
|
52
45
|
escapeRegex: () => escapeRegex,
|
|
53
|
-
eta: () => eta,
|
|
54
|
-
float: () => float,
|
|
55
46
|
forceArray: () => forceArray,
|
|
56
|
-
|
|
47
|
+
formatCurrency: () => formatCurrency,
|
|
48
|
+
formatDuration: () => formatDuration,
|
|
49
|
+
formatETA: () => formatETA,
|
|
50
|
+
formatMemory: () => formatMemory,
|
|
51
|
+
formatNumber: () => formatNumber,
|
|
52
|
+
formatOrdinal: () => formatOrdinal,
|
|
57
53
|
getAge: () => getAge,
|
|
58
54
|
getFlag: () => getFlag,
|
|
59
|
-
|
|
55
|
+
getProp: () => getProp,
|
|
60
56
|
hasFlag: () => hasFlag,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
hasProp: () => hasProp,
|
|
58
|
+
inverseLerp: () => inverseLerp,
|
|
59
|
+
isDefined: () => isDefined,
|
|
60
|
+
isEmpty: () => isEmpty,
|
|
61
|
+
isInRange: () => isInRange,
|
|
62
|
+
isObject: () => isObject,
|
|
63
|
+
isSortedArray: () => isSortedArray,
|
|
64
|
+
isString: () => isString,
|
|
65
|
+
isToday: () => isToday,
|
|
65
66
|
lerp: () => lerp,
|
|
66
67
|
memoize: () => memoize,
|
|
67
|
-
memory: () => memory,
|
|
68
68
|
merge: () => merge,
|
|
69
|
-
|
|
70
|
-
number: () => number,
|
|
71
|
-
object: () => object,
|
|
69
|
+
msToSecs: () => msToSecs,
|
|
72
70
|
omit: () => omit,
|
|
73
|
-
|
|
74
|
-
parse: () => parse,
|
|
71
|
+
parseTime: () => parseTime,
|
|
75
72
|
percent: () => percent,
|
|
76
73
|
pick: () => pick,
|
|
74
|
+
pluralize: () => pluralize,
|
|
77
75
|
prng: () => prng,
|
|
78
76
|
readDir: () => readDir,
|
|
79
|
-
record: () => record,
|
|
80
77
|
remap: () => remap,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
retryPromise: () => retryPromise,
|
|
79
|
+
rndChance: () => rndChance,
|
|
80
|
+
rndChoice: () => rndChoice,
|
|
81
|
+
rndFloat: () => rndFloat,
|
|
82
|
+
rndIndex: () => rndIndex,
|
|
83
|
+
rndInt: () => rndInt,
|
|
84
|
+
rndString: () => rndString,
|
|
85
|
+
searchSorted: () => searchSorted,
|
|
86
|
+
secsToMs: () => secsToMs,
|
|
85
87
|
seqMap: () => seqMap,
|
|
86
|
-
|
|
88
|
+
setProp: () => setProp,
|
|
87
89
|
shuffle: () => shuffle,
|
|
88
90
|
sortBy: () => sortBy,
|
|
89
|
-
sorted: () => sorted,
|
|
90
|
-
str: () => str,
|
|
91
|
-
string: () => string,
|
|
92
91
|
sum: () => sum,
|
|
93
92
|
throttle: () => throttle,
|
|
94
93
|
toTitleCase: () => toTitleCase,
|
|
95
|
-
today: () => today,
|
|
96
94
|
unique: () => unique,
|
|
97
95
|
wait: () => wait,
|
|
98
|
-
|
|
96
|
+
weightedRnd: () => weightedRnd,
|
|
99
97
|
wrap: () => wrap
|
|
100
98
|
});
|
|
101
99
|
module.exports = __toCommonJS(index_exports);
|
|
102
100
|
|
|
103
|
-
// src/
|
|
104
|
-
var
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
101
|
+
// src/Cache.ts
|
|
102
|
+
var Cache = class {
|
|
103
|
+
cache = /* @__PURE__ */ new Map();
|
|
104
|
+
interval;
|
|
105
|
+
/**
|
|
106
|
+
* A lightweight, high-performant in-memory cache.
|
|
107
|
+
* Uses Map for O(1) lookups and an optional cleanup interval.
|
|
108
|
+
* @param cleanupMs The interval in milliseconds to run the cleanup function. [default: 60000 (1 minute)]
|
|
109
|
+
*/
|
|
110
|
+
constructor(cleanupMs = 6e4) {
|
|
111
|
+
if (cleanupMs > 0) {
|
|
112
|
+
this.interval = setInterval(() => this.cleanup(), cleanupMs);
|
|
113
|
+
if (this.interval.unref) this.interval.unref();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
set(key, value, ttlMs) {
|
|
117
|
+
this.cache.set(key, {
|
|
118
|
+
value,
|
|
119
|
+
expiresAt: ttlMs ? Date.now() + ttlMs : null
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
get(key) {
|
|
123
|
+
const data = this.cache.get(key);
|
|
124
|
+
if (!data) return null;
|
|
125
|
+
if (data.expiresAt && Date.now() > data.expiresAt) {
|
|
126
|
+
this.cache.delete(key);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
return data.value;
|
|
130
|
+
}
|
|
131
|
+
cleanup() {
|
|
132
|
+
if (this.cache.size === 0) return;
|
|
133
|
+
const now = Date.now();
|
|
134
|
+
let keysProcessed = 0;
|
|
135
|
+
const maxKeysToScan = 20;
|
|
136
|
+
for (const [key, data] of this.cache) {
|
|
137
|
+
if (data.expiresAt && now > data.expiresAt) {
|
|
138
|
+
this.cache.delete(key);
|
|
139
|
+
}
|
|
140
|
+
keysProcessed++;
|
|
141
|
+
if (keysProcessed >= maxKeysToScan) break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
clear() {
|
|
145
|
+
this.cache.clear();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
117
148
|
|
|
118
|
-
// src/
|
|
119
|
-
var
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
149
|
+
// src/Loop.ts
|
|
150
|
+
var import_node_events = __toESM(require("events"), 1);
|
|
151
|
+
var TypedEmitterBase = import_node_events.default;
|
|
152
|
+
var Loop = class extends TypedEmitterBase {
|
|
153
|
+
_state = "stopped";
|
|
154
|
+
timeoutId = null;
|
|
155
|
+
delay;
|
|
156
|
+
fn;
|
|
157
|
+
startTime = 0;
|
|
158
|
+
remaining = 0;
|
|
159
|
+
async run() {
|
|
160
|
+
const currentState = this._state;
|
|
161
|
+
if (currentState === "stopped" || currentState === "paused") return;
|
|
162
|
+
try {
|
|
163
|
+
const result = await this.fn(this);
|
|
164
|
+
this.emit("tick", result);
|
|
165
|
+
} catch (err) {
|
|
166
|
+
try {
|
|
167
|
+
this.emit("error", err);
|
|
168
|
+
} catch {
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (this._state === "running") {
|
|
172
|
+
this.startTime = Date.now();
|
|
173
|
+
this.remaining = 0;
|
|
174
|
+
this.clearTimer();
|
|
175
|
+
this.timeoutId = setTimeout(() => this.run(), this.delay);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
clearTimer() {
|
|
179
|
+
if (this.timeoutId) {
|
|
180
|
+
clearTimeout(this.timeoutId);
|
|
181
|
+
this.timeoutId = null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Creates an interval. If the function is async, it will wait for it to complete before scheduling the next run.
|
|
186
|
+
* @param fn The function to run.
|
|
187
|
+
* @param delay The delay between runs in milliseconds.
|
|
188
|
+
* @param immediate Whether to start the loop immediately. [default: true]
|
|
189
|
+
*/
|
|
190
|
+
constructor(fn, delay, immediate = true) {
|
|
191
|
+
super();
|
|
192
|
+
this.fn = fn;
|
|
193
|
+
this.delay = delay;
|
|
194
|
+
if (immediate) this.start();
|
|
195
|
+
}
|
|
196
|
+
get state() {
|
|
197
|
+
return this._state;
|
|
198
|
+
}
|
|
199
|
+
/** Starts the loop. */
|
|
200
|
+
start() {
|
|
201
|
+
if (this._state !== "stopped") return;
|
|
202
|
+
this._state = "running";
|
|
203
|
+
this.emit("start");
|
|
204
|
+
this.run();
|
|
205
|
+
}
|
|
206
|
+
/** Resumes a paused loop. */
|
|
207
|
+
resume() {
|
|
208
|
+
if (this._state !== "paused") return;
|
|
209
|
+
this._state = "running";
|
|
210
|
+
this.emit("resume");
|
|
211
|
+
if (this.remaining <= 0) {
|
|
212
|
+
this.run();
|
|
213
|
+
} else {
|
|
214
|
+
this.timeoutId = setTimeout(() => this.run(), this.remaining);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/** Stops the loop. */
|
|
218
|
+
stop() {
|
|
219
|
+
const wasRunning = this._state !== "stopped";
|
|
220
|
+
this._state = "stopped";
|
|
221
|
+
this.remaining = 0;
|
|
222
|
+
this.clearTimer();
|
|
223
|
+
if (wasRunning) this.emit("stop");
|
|
224
|
+
}
|
|
225
|
+
/** Pauses the execution. */
|
|
226
|
+
pause() {
|
|
227
|
+
if (this._state !== "running") return;
|
|
228
|
+
this._state = "paused";
|
|
229
|
+
const elapsed = Date.now() - this.startTime;
|
|
230
|
+
this.remaining = Math.max(0, this.delay - elapsed);
|
|
231
|
+
this.emit("pause", { remaining: this.remaining });
|
|
232
|
+
this.clearTimer();
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Sets the delay between runs
|
|
236
|
+
* @param ms The new delay in milliseconds.
|
|
237
|
+
*/
|
|
238
|
+
setDelay(ms) {
|
|
239
|
+
this.delay = ms;
|
|
240
|
+
}
|
|
241
|
+
/** Manually trigger the function once without affecting the loop. */
|
|
242
|
+
async execute() {
|
|
243
|
+
await this.fn(this);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// src/Pipe.ts
|
|
248
|
+
function Pipe(value, ...fns) {
|
|
249
|
+
return fns.reduce((acc, fn) => fn(acc), value);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/Storage.ts
|
|
253
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
254
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
255
|
+
var Storage = class {
|
|
256
|
+
isNode = typeof window === "undefined";
|
|
257
|
+
filePath = null;
|
|
258
|
+
memoryCache = /* @__PURE__ */ new Map();
|
|
259
|
+
loadFromFile() {
|
|
260
|
+
if (this.filePath && import_node_fs.default.existsSync(this.filePath)) {
|
|
261
|
+
try {
|
|
262
|
+
const data = JSON.parse(import_node_fs.default.readFileSync(this.filePath, "utf-8"));
|
|
263
|
+
Object.entries(data).forEach(([k, v]) => this.memoryCache.set(k, JSON.stringify(v)));
|
|
264
|
+
} catch (err) {
|
|
265
|
+
console.error(`Store: Failed to load file '${this.filePath}'`, err);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
persist() {
|
|
270
|
+
if (this.isNode && this.filePath) {
|
|
271
|
+
const out = {};
|
|
272
|
+
this.memoryCache.forEach((v, k) => out[k] = JSON.parse(v));
|
|
273
|
+
import_node_fs.default.writeFileSync(this.filePath, JSON.stringify(out, null, 2));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* A lightweight, high-performant persistent storage system.
|
|
278
|
+
* Uses JSON files in Node.js, localStorage in the browser
|
|
279
|
+
* @param fileName Only used in Node.js to create a persistent .json file
|
|
280
|
+
* @param directory The directory for the file. Defaults to current working directory
|
|
281
|
+
*/
|
|
282
|
+
constructor(fileName, directory = process.cwd()) {
|
|
283
|
+
if (this.isNode && fileName) {
|
|
284
|
+
this.filePath = import_node_path.default.join(directory, fileName.endsWith(".json") ? fileName : `${fileName}.json`);
|
|
285
|
+
this.loadFromFile();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
has(key) {
|
|
289
|
+
if (!this.isNode && window.localStorage) {
|
|
290
|
+
return localStorage.getItem(key) !== null;
|
|
291
|
+
}
|
|
292
|
+
return this.memoryCache.has(key);
|
|
293
|
+
}
|
|
294
|
+
get(key) {
|
|
295
|
+
let raw = null;
|
|
296
|
+
if (!this.isNode && window.localStorage) {
|
|
297
|
+
raw = localStorage.getItem(key);
|
|
298
|
+
} else {
|
|
299
|
+
raw = this.memoryCache.get(key) || null;
|
|
300
|
+
}
|
|
301
|
+
if (!raw) return null;
|
|
302
|
+
const payload = JSON.parse(raw);
|
|
303
|
+
if (payload.expiry && Date.now() > payload.expiry) {
|
|
304
|
+
this.remove(key);
|
|
305
|
+
this.persist();
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
return payload.value;
|
|
309
|
+
}
|
|
310
|
+
set(key, value, ttl) {
|
|
311
|
+
const payload = {
|
|
312
|
+
value,
|
|
313
|
+
expiry: ttl ? Date.now() + ttl : null
|
|
314
|
+
};
|
|
315
|
+
const serialized = JSON.stringify(payload);
|
|
316
|
+
if (!this.isNode && window.localStorage) {
|
|
317
|
+
localStorage.setItem(key, serialized);
|
|
318
|
+
} else {
|
|
319
|
+
this.memoryCache.set(key, serialized);
|
|
320
|
+
this.persist();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
remove(key) {
|
|
324
|
+
if (!this.isNode && window.localStorage) {
|
|
325
|
+
localStorage.removeItem(key);
|
|
326
|
+
} else {
|
|
327
|
+
this.memoryCache.delete(key);
|
|
328
|
+
this.persist();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
clear() {
|
|
332
|
+
if (!this.isNode && window.localStorage) {
|
|
333
|
+
localStorage.clear();
|
|
334
|
+
} else {
|
|
335
|
+
this.memoryCache.clear();
|
|
336
|
+
this.persist();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
// src/random.ts
|
|
131
342
|
var LOWER = "abcdefghijklmnopqrstuvwxyz";
|
|
132
343
|
var UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
133
344
|
var NUM = "0123456789";
|
|
134
|
-
function
|
|
345
|
+
function rndChance(percent2 = 0.5, seed) {
|
|
135
346
|
if (percent2 <= 0) return false;
|
|
136
347
|
if (percent2 >= 1) return true;
|
|
137
348
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
138
349
|
return random() < percent2;
|
|
139
350
|
}
|
|
140
|
-
function
|
|
351
|
+
function rndChoice(array, options = {}) {
|
|
141
352
|
const { seed, not, maxRerolls = 10 } = options;
|
|
142
353
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
143
354
|
const rnd = () => array[Math.floor(random() * array.length)];
|
|
@@ -152,19 +363,19 @@ function choice(array, options = {}) {
|
|
|
152
363
|
}
|
|
153
364
|
return result;
|
|
154
365
|
}
|
|
155
|
-
function
|
|
366
|
+
function weightedRnd(array, predicate, seed) {
|
|
156
367
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
157
368
|
const cumulativeWeights = [];
|
|
158
369
|
let currentSum = 0;
|
|
159
370
|
for (const item of array) {
|
|
160
|
-
const weight =
|
|
371
|
+
const weight = predicate(item);
|
|
161
372
|
currentSum += weight;
|
|
162
373
|
cumulativeWeights.push(currentSum);
|
|
163
374
|
}
|
|
164
375
|
const decider = random() * currentSum;
|
|
165
|
-
let
|
|
376
|
+
let index;
|
|
166
377
|
if (array.length < 20) {
|
|
167
|
-
|
|
378
|
+
index = cumulativeWeights.findIndex((w) => w >= decider);
|
|
168
379
|
} else {
|
|
169
380
|
let low = 0;
|
|
170
381
|
let high = cumulativeWeights.length - 1;
|
|
@@ -176,16 +387,16 @@ function weighted(array, selector, seed) {
|
|
|
176
387
|
high = mid;
|
|
177
388
|
}
|
|
178
389
|
}
|
|
179
|
-
|
|
390
|
+
index = low;
|
|
180
391
|
}
|
|
181
|
-
return array[
|
|
392
|
+
return array[index];
|
|
182
393
|
}
|
|
183
|
-
function
|
|
394
|
+
function createSampler(items, predicate, seed) {
|
|
184
395
|
const callRandom = seed ? prng(seed) : void 0;
|
|
185
396
|
const len = items.length;
|
|
186
397
|
const prob = new Array(len);
|
|
187
398
|
const alias = new Array(len);
|
|
188
|
-
const weights = items.map(
|
|
399
|
+
const weights = items.map(predicate);
|
|
189
400
|
const totalWeight = weights.reduce((a, b) => a + b, 0);
|
|
190
401
|
const scaledWeights = weights.map((w) => w * len / totalWeight);
|
|
191
402
|
const small = [];
|
|
@@ -203,8 +414,8 @@ function sampler(items, selector, seed) {
|
|
|
203
414
|
while (small.length) prob[small.pop()] = 1;
|
|
204
415
|
return {
|
|
205
416
|
/**
|
|
206
|
-
* Returns a random item from the given array in O(1) time
|
|
207
|
-
* @param seed Optional seed for RNG
|
|
417
|
+
* Returns a random item from the given array in O(1) time
|
|
418
|
+
* @param seed Optional seed for RNG
|
|
208
419
|
*/
|
|
209
420
|
pick: (seed2) => {
|
|
210
421
|
const random = seed2 !== void 0 ? prng(seed2) : callRandom || Math.random;
|
|
@@ -221,11 +432,11 @@ function prng(seed) {
|
|
|
221
432
|
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
222
433
|
};
|
|
223
434
|
}
|
|
224
|
-
function
|
|
435
|
+
function rndFloat(min, max, seed) {
|
|
225
436
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
226
437
|
return random() * (max - min) + min;
|
|
227
438
|
}
|
|
228
|
-
function
|
|
439
|
+
function rndIndex(array, options = {}) {
|
|
229
440
|
const { seed, not, maxRerolls = 10 } = options;
|
|
230
441
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
231
442
|
const rnd = () => Math.floor(random() * array.length);
|
|
@@ -240,11 +451,11 @@ function index(array, options = {}) {
|
|
|
240
451
|
}
|
|
241
452
|
return result;
|
|
242
453
|
}
|
|
243
|
-
function
|
|
454
|
+
function rndInt(min, max, seed) {
|
|
244
455
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
245
456
|
return Math.floor(random() * (max - min + 1)) + min;
|
|
246
457
|
}
|
|
247
|
-
function
|
|
458
|
+
function rndString(len, mode, options = {}) {
|
|
248
459
|
const { casing = "lower", seed, customChars = "", exclude = "" } = options;
|
|
249
460
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
250
461
|
const alphaPool = { lower: LOWER, upper: UPPER, mixed: LOWER + UPPER }[casing];
|
|
@@ -262,7 +473,7 @@ function str(len, mode, options = {}) {
|
|
|
262
473
|
return result.join("");
|
|
263
474
|
}
|
|
264
475
|
|
|
265
|
-
// src/
|
|
476
|
+
// src/array.ts
|
|
266
477
|
function chunk(array, size) {
|
|
267
478
|
if (size <= 0) throw new Error("chunk: Size must be a positive integer.");
|
|
268
479
|
const result = [];
|
|
@@ -313,7 +524,7 @@ function cluster(array, iteratee, maxChunkSize) {
|
|
|
313
524
|
}
|
|
314
525
|
return result;
|
|
315
526
|
}
|
|
316
|
-
function
|
|
527
|
+
function compactArray(array, mode = "nullable") {
|
|
317
528
|
if (mode === "falsy") {
|
|
318
529
|
return array.filter(Boolean);
|
|
319
530
|
}
|
|
@@ -322,7 +533,7 @@ function compact(array, mode = "nullable") {
|
|
|
322
533
|
function forceArray(item) {
|
|
323
534
|
return Array.isArray(item) ? item : [item];
|
|
324
535
|
}
|
|
325
|
-
function
|
|
536
|
+
function searchSorted(array, target, comparator = (a, b) => a > b ? 1 : a < b ? -1 : 0) {
|
|
326
537
|
let low = 0;
|
|
327
538
|
let high = array.length - 1;
|
|
328
539
|
while (low <= high) {
|
|
@@ -385,13 +596,8 @@ function unique(array, key) {
|
|
|
385
596
|
}
|
|
386
597
|
|
|
387
598
|
// src/async.ts
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
retry: () => retry,
|
|
391
|
-
wait: () => wait
|
|
392
|
-
});
|
|
393
|
-
async function retry(fn, options = {}) {
|
|
394
|
-
const { retries = 3, delay = 500, timeout, signal } = options;
|
|
599
|
+
async function retryPromise(fn, options = {}) {
|
|
600
|
+
const { attempts = 3, delay = 500, timeout, signal } = options;
|
|
395
601
|
if (signal?.aborted) throw new Error("Operation aborted");
|
|
396
602
|
const executeWithTimeout = async () => {
|
|
397
603
|
if (!timeout) return fn(signal);
|
|
@@ -410,7 +616,7 @@ async function retry(fn, options = {}) {
|
|
|
410
616
|
return await executeWithTimeout();
|
|
411
617
|
} catch (error) {
|
|
412
618
|
if (signal?.aborted) throw error;
|
|
413
|
-
if (
|
|
619
|
+
if (attempts <= 0) throw error;
|
|
414
620
|
const jitter = Math.random() * 200;
|
|
415
621
|
const totalDelay = delay + jitter;
|
|
416
622
|
await new Promise((resolve, reject) => {
|
|
@@ -424,51 +630,14 @@ async function retry(fn, options = {}) {
|
|
|
424
630
|
{ once: true }
|
|
425
631
|
);
|
|
426
632
|
});
|
|
427
|
-
return
|
|
633
|
+
return retryPromise(fn, { ...options, attempts: attempts - 1, delay: delay * 2 });
|
|
428
634
|
}
|
|
429
635
|
}
|
|
430
|
-
function wait(
|
|
431
|
-
return new Promise(
|
|
432
|
-
(resolve) => setTimeout(() => {
|
|
433
|
-
resolve(true);
|
|
434
|
-
}, ms2)
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// src/fn.ts
|
|
439
|
-
var fn_exports = {};
|
|
440
|
-
__export(fn_exports, {
|
|
441
|
-
memoize: () => memoize
|
|
442
|
-
});
|
|
443
|
-
function memoize(fn, options = {}) {
|
|
444
|
-
const cache = /* @__PURE__ */ new Map();
|
|
445
|
-
const { resolver, maxAge } = options;
|
|
446
|
-
const memoized = function(...args) {
|
|
447
|
-
const key = resolver ? resolver(...args) : JSON.stringify(args);
|
|
448
|
-
const now = Date.now();
|
|
449
|
-
const entry = cache.get(key);
|
|
450
|
-
if (entry) {
|
|
451
|
-
if (!maxAge || now - entry.timestamp < maxAge) {
|
|
452
|
-
return entry.value;
|
|
453
|
-
}
|
|
454
|
-
cache.delete(key);
|
|
455
|
-
}
|
|
456
|
-
const result = fn.apply(this, args);
|
|
457
|
-
cache.set(key, { value: result, timestamp: now });
|
|
458
|
-
return result;
|
|
459
|
-
};
|
|
460
|
-
memoized.clear = () => cache.clear();
|
|
461
|
-
return memoized;
|
|
636
|
+
function wait(ms) {
|
|
637
|
+
return new Promise((resolve) => setTimeout(() => resolve(true), ms));
|
|
462
638
|
}
|
|
463
639
|
|
|
464
640
|
// src/date.ts
|
|
465
|
-
var date_exports = {};
|
|
466
|
-
__export(date_exports, {
|
|
467
|
-
duration: () => duration,
|
|
468
|
-
eta: () => eta,
|
|
469
|
-
getAge: () => getAge,
|
|
470
|
-
parse: () => parse
|
|
471
|
-
});
|
|
472
641
|
var MS_MAP = {
|
|
473
642
|
ms: 1,
|
|
474
643
|
s: 1e3,
|
|
@@ -479,64 +648,18 @@ var MS_MAP = {
|
|
|
479
648
|
mth: 24192e5,
|
|
480
649
|
y: 31536e6
|
|
481
650
|
};
|
|
482
|
-
function duration(target, style = "hms", options = {}) {
|
|
483
|
-
const targetMs = target instanceof Date ? target.getTime() : Number(target);
|
|
484
|
-
const sinceMs = options.since instanceof Date ? options.since.getTime() : Number(options.since) || Date.now();
|
|
485
|
-
const diff = Math.abs(targetMs - sinceMs);
|
|
486
|
-
if (diff === 0) return style === "digital" ? "00:00" : "now";
|
|
487
|
-
const s = Math.floor(diff / 1e3) % 60;
|
|
488
|
-
const m = Math.floor(diff / 6e4) % 60;
|
|
489
|
-
const h = Math.floor(diff / 36e5) % 24;
|
|
490
|
-
const d = Math.floor(diff / 864e5);
|
|
491
|
-
if (style === "digital") {
|
|
492
|
-
const parts = [m, s].map((v) => String(v).padStart(2, "0"));
|
|
493
|
-
if (h > 0 || d > 0) parts.unshift(String(h).padStart(2, "0"));
|
|
494
|
-
if (d > 0) parts.unshift(String(d));
|
|
495
|
-
return parts.join(":");
|
|
496
|
-
}
|
|
497
|
-
const result = [];
|
|
498
|
-
const push = (val, label) => {
|
|
499
|
-
if (val > 0) result.push(`${val} ${label}${val === 1 ? "" : "s"}`);
|
|
500
|
-
};
|
|
501
|
-
if (style === "ymdhms") push(d, "day");
|
|
502
|
-
push(h, "hour");
|
|
503
|
-
push(m, "minute");
|
|
504
|
-
push(s, "second");
|
|
505
|
-
if (result.length === 0) return "0 seconds";
|
|
506
|
-
if (result.length === 1) return result[0];
|
|
507
|
-
const last = result.pop();
|
|
508
|
-
return `${result.join(", ")} and ${last}`;
|
|
509
|
-
}
|
|
510
|
-
function eta(date, locale) {
|
|
511
|
-
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
512
|
-
const elapsed = (typeof date === "number" ? date : date.getTime()) - Date.now();
|
|
513
|
-
const units = [
|
|
514
|
-
{ unit: "year", ms: 31536e6 },
|
|
515
|
-
{ unit: "month", ms: 2628e6 },
|
|
516
|
-
{ unit: "day", ms: 864e5 },
|
|
517
|
-
{ unit: "hour", ms: 36e5 },
|
|
518
|
-
{ unit: "minute", ms: 6e4 },
|
|
519
|
-
{ unit: "second", ms: 1e3 }
|
|
520
|
-
];
|
|
521
|
-
for (const { unit, ms: ms2 } of units) {
|
|
522
|
-
if (Math.abs(elapsed) >= ms2 || unit === "second") {
|
|
523
|
-
return rtf.format(Math.round(elapsed / ms2), unit);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
return "";
|
|
527
|
-
}
|
|
528
651
|
function getAge(birthdate) {
|
|
529
|
-
const
|
|
530
|
-
let age =
|
|
531
|
-
const monthDiff =
|
|
532
|
-
if (monthDiff < 0 || monthDiff === 0 &&
|
|
652
|
+
const today = /* @__PURE__ */ new Date();
|
|
653
|
+
let age = today.getFullYear() - birthdate.getFullYear();
|
|
654
|
+
const monthDiff = today.getMonth() - birthdate.getMonth();
|
|
655
|
+
if (monthDiff < 0 || monthDiff === 0 && today.getDate() < birthdate.getDate()) {
|
|
533
656
|
age--;
|
|
534
657
|
}
|
|
535
658
|
return age;
|
|
536
659
|
}
|
|
537
|
-
function
|
|
538
|
-
if (typeof
|
|
539
|
-
const matches =
|
|
660
|
+
function parseTime(str, options = {}) {
|
|
661
|
+
if (typeof str === "number") return str;
|
|
662
|
+
const matches = str.matchAll(/(-?\d+)([a-z]+)/gi);
|
|
540
663
|
let totalMs = 0;
|
|
541
664
|
let found = false;
|
|
542
665
|
for (const [_, value, unit] of matches) {
|
|
@@ -547,39 +670,85 @@ function parse(str2, options = {}) {
|
|
|
547
670
|
found = true;
|
|
548
671
|
}
|
|
549
672
|
}
|
|
550
|
-
if (!found) throw new Error(`parse: Invalid time format: "${
|
|
673
|
+
if (!found) throw new Error(`parse: Invalid time format: "${str}"`);
|
|
551
674
|
const result = options.unit === "s" ? totalMs / 1e3 : totalMs;
|
|
552
675
|
return options.fromNow ? Date.now() + result : result;
|
|
553
676
|
}
|
|
554
677
|
|
|
678
|
+
// src/exec.ts
|
|
679
|
+
function debounce(fn, wait2, options = {}) {
|
|
680
|
+
let timeoutId;
|
|
681
|
+
const leading = options.immediate ?? false;
|
|
682
|
+
const debounced = function(...args) {
|
|
683
|
+
const callNow = leading && !timeoutId;
|
|
684
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
685
|
+
timeoutId = setTimeout(() => {
|
|
686
|
+
timeoutId = void 0;
|
|
687
|
+
if (!leading) fn.apply(this, args);
|
|
688
|
+
}, wait2);
|
|
689
|
+
if (callNow) fn.apply(this, args);
|
|
690
|
+
};
|
|
691
|
+
debounced.cancel = () => {
|
|
692
|
+
if (timeoutId) {
|
|
693
|
+
clearTimeout(timeoutId);
|
|
694
|
+
timeoutId = void 0;
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
return debounced;
|
|
698
|
+
}
|
|
699
|
+
function throttle(fn, limit) {
|
|
700
|
+
let inThrottle = false;
|
|
701
|
+
return function(...args) {
|
|
702
|
+
if (!inThrottle) {
|
|
703
|
+
fn.apply(this, args);
|
|
704
|
+
inThrottle = true;
|
|
705
|
+
setTimeout(() => inThrottle = false, limit);
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// src/fn.ts
|
|
711
|
+
function memoize(fn, options = {}) {
|
|
712
|
+
const cache = /* @__PURE__ */ new Map();
|
|
713
|
+
const { resolver, maxAge } = options;
|
|
714
|
+
const memoized = function(...args) {
|
|
715
|
+
const key = resolver ? resolver(...args) : JSON.stringify(args);
|
|
716
|
+
const now = Date.now();
|
|
717
|
+
const entry = cache.get(key);
|
|
718
|
+
if (entry) {
|
|
719
|
+
if (!maxAge || now - entry.timestamp < maxAge) {
|
|
720
|
+
return entry.value;
|
|
721
|
+
}
|
|
722
|
+
cache.delete(key);
|
|
723
|
+
}
|
|
724
|
+
const result = fn.apply(this, args);
|
|
725
|
+
cache.set(key, { value: result, timestamp: now });
|
|
726
|
+
return result;
|
|
727
|
+
};
|
|
728
|
+
memoized.clear = () => cache.clear();
|
|
729
|
+
return memoized;
|
|
730
|
+
}
|
|
731
|
+
|
|
555
732
|
// src/format.ts
|
|
556
|
-
|
|
557
|
-
__export(format_exports, {
|
|
558
|
-
compactNumber: () => compactNumber,
|
|
559
|
-
currency: () => currency,
|
|
560
|
-
memory: () => memory,
|
|
561
|
-
number: () => number,
|
|
562
|
-
ordinal: () => ordinal
|
|
563
|
-
});
|
|
564
|
-
function currency(num, options = {}) {
|
|
733
|
+
function formatCurrency(num, options = {}) {
|
|
565
734
|
return new Intl.NumberFormat(options.locale, {
|
|
566
735
|
style: "currency",
|
|
567
736
|
currency: options.currency
|
|
568
737
|
}).format(num);
|
|
569
738
|
}
|
|
570
|
-
function
|
|
739
|
+
function formatNumber(num, options = {}) {
|
|
571
740
|
return new Intl.NumberFormat(options.locale, {
|
|
572
741
|
minimumFractionDigits: options.precision,
|
|
573
742
|
maximumFractionDigits: options.precision
|
|
574
743
|
}).format(num);
|
|
575
744
|
}
|
|
576
|
-
function
|
|
745
|
+
function formatMemory(bytes, decimals = 1, units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]) {
|
|
577
746
|
if (bytes <= 0) return `0 ${units[0]}`;
|
|
578
747
|
const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
|
|
579
748
|
const val = bytes / Math.pow(1024, i);
|
|
580
749
|
return `${val.toFixed(i === 0 ? 0 : decimals)} ${units[i]}`;
|
|
581
750
|
}
|
|
582
|
-
function
|
|
751
|
+
function formatOrdinal(num, locale) {
|
|
583
752
|
const _num = Number(num);
|
|
584
753
|
if (isNaN(_num)) throw new TypeError("Invalid input");
|
|
585
754
|
const pr = new Intl.PluralRules(locale, { type: "ordinal" });
|
|
@@ -593,35 +762,77 @@ function ordinal(num, locale) {
|
|
|
593
762
|
const suffix = suffixes[rule] || "th";
|
|
594
763
|
return _num.toLocaleString(locale) + suffix;
|
|
595
764
|
}
|
|
596
|
-
function
|
|
765
|
+
function FormatNumberCompact(num, locale) {
|
|
597
766
|
return new Intl.NumberFormat(locale, {
|
|
598
767
|
notation: "compact",
|
|
599
768
|
compactDisplay: "short",
|
|
600
769
|
maximumFractionDigits: 1
|
|
601
770
|
}).format(num);
|
|
602
771
|
}
|
|
772
|
+
function formatDuration(target, style = "hms", options = {}) {
|
|
773
|
+
const targetMs = target instanceof Date ? target.getTime() : Number(target);
|
|
774
|
+
const sinceMs = options.since instanceof Date ? options.since.getTime() : Number(options.since) || Date.now();
|
|
775
|
+
const diff = Math.abs(targetMs - sinceMs);
|
|
776
|
+
if (diff === 0) return style === "digital" ? "00:00" : "now";
|
|
777
|
+
const s = Math.floor(diff / 1e3) % 60;
|
|
778
|
+
const m = Math.floor(diff / 6e4) % 60;
|
|
779
|
+
const h = Math.floor(diff / 36e5) % 24;
|
|
780
|
+
const d = Math.floor(diff / 864e5);
|
|
781
|
+
if (style === "digital") {
|
|
782
|
+
const parts = [m, s].map((v) => String(v).padStart(2, "0"));
|
|
783
|
+
if (h > 0 || d > 0) parts.unshift(String(h).padStart(2, "0"));
|
|
784
|
+
if (d > 0) parts.unshift(String(d));
|
|
785
|
+
return parts.join(":");
|
|
786
|
+
}
|
|
787
|
+
const result = [];
|
|
788
|
+
const push = (val, label) => {
|
|
789
|
+
if (val > 0) result.push(`${val} ${label}${val === 1 ? "" : "s"}`);
|
|
790
|
+
};
|
|
791
|
+
if (style === "ymdhms") push(d, "day");
|
|
792
|
+
push(h, "hour");
|
|
793
|
+
push(m, "minute");
|
|
794
|
+
push(s, "second");
|
|
795
|
+
if (result.length === 0) return "0 seconds";
|
|
796
|
+
if (result.length === 1) return result[0];
|
|
797
|
+
const last = result.pop();
|
|
798
|
+
return `${result.join(", ")} and ${last}`;
|
|
799
|
+
}
|
|
800
|
+
function formatETA(date, locale) {
|
|
801
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
802
|
+
const elapsed = (typeof date === "number" ? date : date.getTime()) - Date.now();
|
|
803
|
+
const units = [
|
|
804
|
+
{ unit: "year", ms: 31536e6 },
|
|
805
|
+
{ unit: "month", ms: 2628e6 },
|
|
806
|
+
{ unit: "day", ms: 864e5 },
|
|
807
|
+
{ unit: "hour", ms: 36e5 },
|
|
808
|
+
{ unit: "minute", ms: 6e4 },
|
|
809
|
+
{ unit: "second", ms: 1e3 }
|
|
810
|
+
];
|
|
811
|
+
for (const { unit, ms } of units) {
|
|
812
|
+
if (Math.abs(elapsed) >= ms || unit === "second") {
|
|
813
|
+
return rtf.format(Math.round(elapsed / ms), unit);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return "";
|
|
817
|
+
}
|
|
603
818
|
|
|
604
819
|
// src/fs.ts
|
|
605
|
-
var
|
|
606
|
-
|
|
607
|
-
readDir: () => readDir
|
|
608
|
-
});
|
|
609
|
-
var import_node_fs = __toESM(require("fs"), 1);
|
|
610
|
-
var import_node_path = require("path");
|
|
820
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
821
|
+
var import_node_path2 = require("path");
|
|
611
822
|
function readDir(path2, options = {}) {
|
|
612
823
|
const { recursive = true } = options;
|
|
613
|
-
if (!
|
|
824
|
+
if (!import_node_fs2.default.existsSync(path2)) return [];
|
|
614
825
|
if (!recursive) {
|
|
615
|
-
return
|
|
616
|
-
return
|
|
826
|
+
return import_node_fs2.default.readdirSync(path2).filter((fn) => {
|
|
827
|
+
return import_node_fs2.default.statSync((0, import_node_path2.join)(path2, fn)).isFile();
|
|
617
828
|
});
|
|
618
829
|
}
|
|
619
830
|
const walk = (dir, base = "") => {
|
|
620
831
|
const results = [];
|
|
621
|
-
const entries =
|
|
832
|
+
const entries = import_node_fs2.default.readdirSync(dir, { withFileTypes: true });
|
|
622
833
|
for (const entry of entries) {
|
|
623
|
-
const relativePath = base ? (0,
|
|
624
|
-
const fullPath = (0,
|
|
834
|
+
const relativePath = base ? (0, import_node_path2.join)(base, entry.name) : entry.name;
|
|
835
|
+
const fullPath = (0, import_node_path2.join)(dir, entry.name);
|
|
625
836
|
if (entry.isDirectory()) {
|
|
626
837
|
results.push(...walk(fullPath, relativePath));
|
|
627
838
|
} else if (entry.isFile()) {
|
|
@@ -634,77 +845,58 @@ function readDir(path2, options = {}) {
|
|
|
634
845
|
}
|
|
635
846
|
|
|
636
847
|
// src/is.ts
|
|
637
|
-
|
|
638
|
-
__export(is_exports, {
|
|
639
|
-
defined: () => defined,
|
|
640
|
-
empty: () => empty,
|
|
641
|
-
inRange: () => inRange,
|
|
642
|
-
object: () => object,
|
|
643
|
-
sorted: () => sorted,
|
|
644
|
-
string: () => string,
|
|
645
|
-
today: () => today
|
|
646
|
-
});
|
|
647
|
-
function defined(val) {
|
|
848
|
+
function isDefined(val) {
|
|
648
849
|
return val !== void 0 && val !== null;
|
|
649
850
|
}
|
|
650
|
-
function
|
|
651
|
-
if (!
|
|
652
|
-
if (
|
|
653
|
-
if (
|
|
851
|
+
function isEmpty(val) {
|
|
852
|
+
if (!isDefined(val)) return true;
|
|
853
|
+
if (isString(val) || Array.isArray(val)) return val.length === 0;
|
|
854
|
+
if (isObject(val)) return Object.keys(val).length === 0;
|
|
654
855
|
return false;
|
|
655
856
|
}
|
|
656
|
-
function
|
|
857
|
+
function isObject(val) {
|
|
858
|
+
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
859
|
+
}
|
|
860
|
+
function isString(val) {
|
|
861
|
+
return typeof val === "string";
|
|
862
|
+
}
|
|
863
|
+
function isInRange(num, a, b) {
|
|
657
864
|
let min = b !== void 0 ? a : 0;
|
|
658
865
|
let max = b !== void 0 ? b : a;
|
|
659
866
|
if (min > max) [min, max] = [max, min];
|
|
660
867
|
return num >= min && num <= max;
|
|
661
868
|
}
|
|
662
|
-
function
|
|
663
|
-
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
664
|
-
}
|
|
665
|
-
function sorted(arr, comparator) {
|
|
869
|
+
function isSortedArray(arr, comparator) {
|
|
666
870
|
for (let i = 0; i < arr.length - 1; i++) {
|
|
667
871
|
const comp = comparator ? comparator(arr[i], arr[i + 1]) : arr[i] > arr[i + 1] ? 1 : -1;
|
|
668
872
|
if (comp > 0) return false;
|
|
669
873
|
}
|
|
670
874
|
return true;
|
|
671
875
|
}
|
|
672
|
-
function
|
|
673
|
-
return typeof val === "string";
|
|
674
|
-
}
|
|
675
|
-
function today(date) {
|
|
876
|
+
function isToday(date) {
|
|
676
877
|
const d = date instanceof Date ? date : new Date(date);
|
|
677
|
-
const
|
|
678
|
-
return d.getDate() ===
|
|
878
|
+
const today = /* @__PURE__ */ new Date();
|
|
879
|
+
return d.getDate() === today.getDate() && d.getMonth() === today.getMonth() && d.getFullYear() === today.getFullYear();
|
|
679
880
|
}
|
|
680
881
|
|
|
681
882
|
// src/math.ts
|
|
682
|
-
|
|
683
|
-
__export(math_exports, {
|
|
684
|
-
clamp: () => clamp,
|
|
685
|
-
invLerp: () => invLerp,
|
|
686
|
-
lerp: () => lerp,
|
|
687
|
-
ms: () => ms,
|
|
688
|
-
percent: () => percent,
|
|
689
|
-
remap: () => remap,
|
|
690
|
-
secs: () => secs,
|
|
691
|
-
sum: () => sum,
|
|
692
|
-
wrap: () => wrap
|
|
693
|
-
});
|
|
694
|
-
function clamp(num, a, b) {
|
|
883
|
+
function clampNumber(num, a, b) {
|
|
695
884
|
let min = b !== void 0 ? a : 0;
|
|
696
885
|
let max = b !== void 0 ? b : a;
|
|
697
886
|
if (min > max) [min, max] = [max, min];
|
|
698
887
|
return Math.max(min, Math.min(num, max));
|
|
699
888
|
}
|
|
700
|
-
function
|
|
889
|
+
function lerp(start, end, t) {
|
|
890
|
+
return start + (end - start) * t;
|
|
891
|
+
}
|
|
892
|
+
function inverseLerp(start, end, value) {
|
|
701
893
|
if (start === end) return 0;
|
|
702
894
|
return (value - start) / (end - start);
|
|
703
895
|
}
|
|
704
|
-
function
|
|
705
|
-
return
|
|
896
|
+
function msToSecs(num) {
|
|
897
|
+
return Math.floor(num / 1e3);
|
|
706
898
|
}
|
|
707
|
-
function
|
|
899
|
+
function secsToMs(num) {
|
|
708
900
|
return Math.floor(num * 1e3);
|
|
709
901
|
}
|
|
710
902
|
function percent(a, b, round = true) {
|
|
@@ -712,36 +904,19 @@ function percent(a, b, round = true) {
|
|
|
712
904
|
return round ? Math.floor(result) : result;
|
|
713
905
|
}
|
|
714
906
|
function remap(value, inMin, inMax, outMin, outMax) {
|
|
715
|
-
const t =
|
|
907
|
+
const t = inverseLerp(inMin, inMax, value);
|
|
716
908
|
return lerp(outMin, outMax, t);
|
|
717
909
|
}
|
|
718
|
-
function secs(num) {
|
|
719
|
-
return Math.floor(num / 1e3);
|
|
720
|
-
}
|
|
721
910
|
function sum(array, selector) {
|
|
722
911
|
const _array = selector ? array.map(selector) : array;
|
|
723
|
-
|
|
724
|
-
throw new TypeError(`sum: Array must only contain numbers.`);
|
|
725
|
-
}
|
|
726
|
-
return _array.reduce((a, b) => {
|
|
727
|
-
return (isNaN(b) ? 0 : b) < 0 ? a - -b : a + (b || 0);
|
|
728
|
-
}, 0);
|
|
912
|
+
return _array.reduce((a, b) => b < 0 ? a - -b : a + (b || 0), 0);
|
|
729
913
|
}
|
|
730
914
|
function wrap(num, max) {
|
|
731
915
|
return (num % max + max) % max;
|
|
732
916
|
}
|
|
733
917
|
|
|
734
918
|
// src/obj.ts
|
|
735
|
-
|
|
736
|
-
__export(obj_exports, {
|
|
737
|
-
get: () => get,
|
|
738
|
-
has: () => has,
|
|
739
|
-
merge: () => merge,
|
|
740
|
-
omit: () => omit,
|
|
741
|
-
pick: () => pick,
|
|
742
|
-
set: () => set
|
|
743
|
-
});
|
|
744
|
-
function get(obj, path2, defaultValue) {
|
|
919
|
+
function getProp(obj, path2, defaultValue) {
|
|
745
920
|
if (!obj) throw new Error("get: Target object is null or undefined");
|
|
746
921
|
const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
747
922
|
let current = obj;
|
|
@@ -760,7 +935,7 @@ function get(obj, path2, defaultValue) {
|
|
|
760
935
|
}
|
|
761
936
|
return current;
|
|
762
937
|
}
|
|
763
|
-
function
|
|
938
|
+
function hasProp(obj, path2) {
|
|
764
939
|
if (!obj || !path2) return false;
|
|
765
940
|
const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
766
941
|
let current = obj;
|
|
@@ -776,7 +951,7 @@ function has(obj, path2) {
|
|
|
776
951
|
}
|
|
777
952
|
return true;
|
|
778
953
|
}
|
|
779
|
-
function
|
|
954
|
+
function setProp(obj, path2, value) {
|
|
780
955
|
const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
781
956
|
let current = obj;
|
|
782
957
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -828,36 +1003,32 @@ function omit(obj, keys) {
|
|
|
828
1003
|
}
|
|
829
1004
|
|
|
830
1005
|
// src/str.ts
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
escapeRegex: () => escapeRegex,
|
|
834
|
-
getFlag: () => getFlag,
|
|
835
|
-
hasFlag: () => hasFlag,
|
|
836
|
-
toTitleCase: () => toTitleCase
|
|
837
|
-
});
|
|
838
|
-
function escapeRegex(str2) {
|
|
839
|
-
return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1006
|
+
function escapeRegex(str) {
|
|
1007
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
840
1008
|
}
|
|
841
|
-
function getFlag(
|
|
1009
|
+
function getFlag(str, flag, length) {
|
|
842
1010
|
const regex = flag instanceof RegExp ? flag : new RegExp(`${escapeRegex(flag)}\\b`, "g");
|
|
843
|
-
const match = regex.exec(
|
|
1011
|
+
const match = regex.exec(str);
|
|
844
1012
|
if (!match) return null;
|
|
845
1013
|
const startIndex = match.index + match[0].length;
|
|
846
|
-
let result =
|
|
1014
|
+
let result = str.slice(startIndex).trimStart();
|
|
847
1015
|
if (length !== void 0) {
|
|
848
1016
|
return result.split(/\s+/).slice(0, length).join(" ");
|
|
849
1017
|
}
|
|
850
1018
|
return result || null;
|
|
851
1019
|
}
|
|
852
|
-
function hasFlag(
|
|
853
|
-
if (flag instanceof RegExp) return flag.test(
|
|
1020
|
+
function hasFlag(str, flag) {
|
|
1021
|
+
if (flag instanceof RegExp) return flag.test(str);
|
|
854
1022
|
const pattern = new RegExp(`${escapeRegex(flag)}\\b`);
|
|
855
|
-
return pattern.test(
|
|
1023
|
+
return pattern.test(str);
|
|
856
1024
|
}
|
|
857
|
-
function
|
|
1025
|
+
function pluralize(count, singular, plural = `${singular}s`) {
|
|
1026
|
+
return count === 1 ? singular : plural;
|
|
1027
|
+
}
|
|
1028
|
+
function toTitleCase(str, smart = true) {
|
|
858
1029
|
const minorWords = /^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v\.?|via)$/i;
|
|
859
|
-
return
|
|
860
|
-
if (smart &&
|
|
1030
|
+
return str.replace(/\w\S*/g, (txt, index) => {
|
|
1031
|
+
if (smart && index !== 0 && minorWords.test(txt)) {
|
|
861
1032
|
return txt.toLowerCase();
|
|
862
1033
|
}
|
|
863
1034
|
if (smart && txt.length > 1 && txt === txt.toUpperCase()) {
|
|
@@ -866,391 +1037,71 @@ function toTitleCase(str2, smart = true) {
|
|
|
866
1037
|
return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
|
|
867
1038
|
});
|
|
868
1039
|
}
|
|
869
|
-
|
|
870
|
-
// src/timing.ts
|
|
871
|
-
var timing_exports = {};
|
|
872
|
-
__export(timing_exports, {
|
|
873
|
-
debounce: () => debounce,
|
|
874
|
-
throttle: () => throttle
|
|
875
|
-
});
|
|
876
|
-
function debounce(fn, wait2, options = {}) {
|
|
877
|
-
let timeoutId;
|
|
878
|
-
const leading = options.immediate ?? false;
|
|
879
|
-
const debounced = function(...args) {
|
|
880
|
-
const callNow = leading && !timeoutId;
|
|
881
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
882
|
-
timeoutId = setTimeout(() => {
|
|
883
|
-
timeoutId = void 0;
|
|
884
|
-
if (!leading) fn.apply(this, args);
|
|
885
|
-
}, wait2);
|
|
886
|
-
if (callNow) fn.apply(this, args);
|
|
887
|
-
};
|
|
888
|
-
debounced.cancel = () => {
|
|
889
|
-
if (timeoutId) {
|
|
890
|
-
clearTimeout(timeoutId);
|
|
891
|
-
timeoutId = void 0;
|
|
892
|
-
}
|
|
893
|
-
};
|
|
894
|
-
return debounced;
|
|
895
|
-
}
|
|
896
|
-
function throttle(fn, limit) {
|
|
897
|
-
let inThrottle = false;
|
|
898
|
-
return function(...args) {
|
|
899
|
-
if (!inThrottle) {
|
|
900
|
-
fn.apply(this, args);
|
|
901
|
-
inThrottle = true;
|
|
902
|
-
setTimeout(() => inThrottle = false, limit);
|
|
903
|
-
}
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
// src/to.ts
|
|
908
|
-
var to_exports = {};
|
|
909
|
-
__export(to_exports, {
|
|
910
|
-
record: () => record
|
|
911
|
-
});
|
|
912
|
-
function record(array, callback) {
|
|
913
|
-
const result = {};
|
|
914
|
-
let lastValue = void 0;
|
|
915
|
-
for (let i = 0; i < array.length; i++) {
|
|
916
|
-
const { key, value } = callback(array[i], {
|
|
917
|
-
index: i,
|
|
918
|
-
lastValue,
|
|
919
|
-
// NOTE: This is a reference to the object currently being built
|
|
920
|
-
newRecord: result,
|
|
921
|
-
originalArray: array
|
|
922
|
-
});
|
|
923
|
-
result[key] = value;
|
|
924
|
-
lastValue = value;
|
|
925
|
-
}
|
|
926
|
-
return result;
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
// src/Pipe.ts
|
|
930
|
-
function Pipe(value, ...fns) {
|
|
931
|
-
return fns.reduce((acc, fn) => fn(acc), value);
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
// src/Storage.ts
|
|
935
|
-
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
936
|
-
var import_node_path2 = __toESM(require("path"), 1);
|
|
937
|
-
var Storage = class {
|
|
938
|
-
isNode = typeof window === "undefined";
|
|
939
|
-
filePath = null;
|
|
940
|
-
memoryCache = /* @__PURE__ */ new Map();
|
|
941
|
-
loadFromFile() {
|
|
942
|
-
if (this.filePath && import_node_fs2.default.existsSync(this.filePath)) {
|
|
943
|
-
try {
|
|
944
|
-
const data = JSON.parse(import_node_fs2.default.readFileSync(this.filePath, "utf-8"));
|
|
945
|
-
Object.entries(data).forEach(([k, v]) => this.memoryCache.set(k, JSON.stringify(v)));
|
|
946
|
-
} catch (err) {
|
|
947
|
-
console.error(`Store: Failed to load file '${this.filePath}'`, err);
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
persist() {
|
|
952
|
-
if (this.isNode && this.filePath) {
|
|
953
|
-
const out = {};
|
|
954
|
-
this.memoryCache.forEach((v, k) => out[k] = JSON.parse(v));
|
|
955
|
-
import_node_fs2.default.writeFileSync(this.filePath, JSON.stringify(out, null, 2));
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
/**
|
|
959
|
-
* A lightweight, high-performant persistent storage system.
|
|
960
|
-
* Uses JSON files in Node.js, localStorage in the browser.
|
|
961
|
-
* @param fileName Only used in Node.js to create a persistent .json file.
|
|
962
|
-
* @param directory The directory for the file. Defaults to current working directory.
|
|
963
|
-
*/
|
|
964
|
-
constructor(fileName, directory = process.cwd()) {
|
|
965
|
-
if (this.isNode && fileName) {
|
|
966
|
-
this.filePath = import_node_path2.default.join(directory, fileName.endsWith(".json") ? fileName : `${fileName}.json`);
|
|
967
|
-
this.loadFromFile();
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
has(key) {
|
|
971
|
-
if (!this.isNode && window.localStorage) {
|
|
972
|
-
return localStorage.getItem(key) !== null;
|
|
973
|
-
}
|
|
974
|
-
return this.memoryCache.has(key);
|
|
975
|
-
}
|
|
976
|
-
get(key) {
|
|
977
|
-
let raw = null;
|
|
978
|
-
if (!this.isNode && window.localStorage) {
|
|
979
|
-
raw = localStorage.getItem(key);
|
|
980
|
-
} else {
|
|
981
|
-
raw = this.memoryCache.get(key) || null;
|
|
982
|
-
}
|
|
983
|
-
if (!raw) return null;
|
|
984
|
-
const payload = JSON.parse(raw);
|
|
985
|
-
if (payload.expiry && Date.now() > payload.expiry) {
|
|
986
|
-
this.remove(key);
|
|
987
|
-
this.persist();
|
|
988
|
-
return null;
|
|
989
|
-
}
|
|
990
|
-
return payload.value;
|
|
991
|
-
}
|
|
992
|
-
set(key, value, ttl) {
|
|
993
|
-
const payload = {
|
|
994
|
-
value,
|
|
995
|
-
expiry: ttl ? Date.now() + ttl : null
|
|
996
|
-
};
|
|
997
|
-
const serialized = JSON.stringify(payload);
|
|
998
|
-
if (!this.isNode && window.localStorage) {
|
|
999
|
-
localStorage.setItem(key, serialized);
|
|
1000
|
-
} else {
|
|
1001
|
-
this.memoryCache.set(key, serialized);
|
|
1002
|
-
this.persist();
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
remove(key) {
|
|
1006
|
-
if (!this.isNode && window.localStorage) {
|
|
1007
|
-
localStorage.removeItem(key);
|
|
1008
|
-
} else {
|
|
1009
|
-
this.memoryCache.delete(key);
|
|
1010
|
-
this.persist();
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
clear() {
|
|
1014
|
-
if (!this.isNode && window.localStorage) {
|
|
1015
|
-
localStorage.clear();
|
|
1016
|
-
} else {
|
|
1017
|
-
this.memoryCache.clear();
|
|
1018
|
-
this.persist();
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
};
|
|
1022
|
-
|
|
1023
|
-
// src/Cache.ts
|
|
1024
|
-
var Cache = class {
|
|
1025
|
-
cache = /* @__PURE__ */ new Map();
|
|
1026
|
-
interval;
|
|
1027
|
-
/**
|
|
1028
|
-
* A lightweight, high-performant in-memory cache.
|
|
1029
|
-
* Uses Map for O(1) lookups and an optional cleanup interval.
|
|
1030
|
-
* @param cleanupMs The interval in milliseconds to run the cleanup function. [default: 60000 (1 minute)]
|
|
1031
|
-
*/
|
|
1032
|
-
constructor(cleanupMs = 6e4) {
|
|
1033
|
-
if (cleanupMs > 0) {
|
|
1034
|
-
this.interval = setInterval(() => this.cleanup(), cleanupMs);
|
|
1035
|
-
if (this.interval.unref) this.interval.unref();
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
set(key, value, ttlMs) {
|
|
1039
|
-
this.cache.set(key, {
|
|
1040
|
-
value,
|
|
1041
|
-
expiresAt: ttlMs ? Date.now() + ttlMs : null
|
|
1042
|
-
});
|
|
1043
|
-
}
|
|
1044
|
-
get(key) {
|
|
1045
|
-
const data = this.cache.get(key);
|
|
1046
|
-
if (!data) return null;
|
|
1047
|
-
if (data.expiresAt && Date.now() > data.expiresAt) {
|
|
1048
|
-
this.cache.delete(key);
|
|
1049
|
-
return null;
|
|
1050
|
-
}
|
|
1051
|
-
return data.value;
|
|
1052
|
-
}
|
|
1053
|
-
cleanup() {
|
|
1054
|
-
if (this.cache.size === 0) return;
|
|
1055
|
-
const now = Date.now();
|
|
1056
|
-
let keysProcessed = 0;
|
|
1057
|
-
const maxKeysToScan = 20;
|
|
1058
|
-
for (const [key, data] of this.cache) {
|
|
1059
|
-
if (data.expiresAt && now > data.expiresAt) {
|
|
1060
|
-
this.cache.delete(key);
|
|
1061
|
-
}
|
|
1062
|
-
keysProcessed++;
|
|
1063
|
-
if (keysProcessed >= maxKeysToScan) break;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
clear() {
|
|
1067
|
-
this.cache.clear();
|
|
1068
|
-
}
|
|
1069
|
-
};
|
|
1070
|
-
|
|
1071
|
-
// src/Loop.ts
|
|
1072
|
-
var import_node_events = __toESM(require("events"), 1);
|
|
1073
|
-
var TypedEmitterBase = import_node_events.default;
|
|
1074
|
-
var Loop = class extends TypedEmitterBase {
|
|
1075
|
-
_state = "stopped";
|
|
1076
|
-
timeoutId = null;
|
|
1077
|
-
delay;
|
|
1078
|
-
fn;
|
|
1079
|
-
startTime = 0;
|
|
1080
|
-
remaining = 0;
|
|
1081
|
-
async run() {
|
|
1082
|
-
const currentState = this._state;
|
|
1083
|
-
if (currentState === "stopped" || currentState === "paused") return;
|
|
1084
|
-
try {
|
|
1085
|
-
const result = await this.fn(this);
|
|
1086
|
-
this.emit("tick", result);
|
|
1087
|
-
} catch (err) {
|
|
1088
|
-
this.emit("error", err);
|
|
1089
|
-
}
|
|
1090
|
-
if (this._state === "running") {
|
|
1091
|
-
this.startTime = Date.now();
|
|
1092
|
-
this.remaining = 0;
|
|
1093
|
-
this.clearTimer();
|
|
1094
|
-
this.timeoutId = setTimeout(() => this.run(), this.delay);
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
clearTimer() {
|
|
1098
|
-
if (this.timeoutId) {
|
|
1099
|
-
clearTimeout(this.timeoutId);
|
|
1100
|
-
this.timeoutId = null;
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
/**
|
|
1104
|
-
* Creates an interval. If the function is async, it will wait for it to complete before scheduling the next run.
|
|
1105
|
-
* @param fn The function to run.
|
|
1106
|
-
* @param delay The delay between runs in milliseconds.
|
|
1107
|
-
* @param immediate Whether to start the loop immediately. [default: true]
|
|
1108
|
-
*/
|
|
1109
|
-
constructor(fn, delay, immediate = true) {
|
|
1110
|
-
super();
|
|
1111
|
-
this.fn = fn;
|
|
1112
|
-
this.delay = delay;
|
|
1113
|
-
if (immediate) this.start();
|
|
1114
|
-
}
|
|
1115
|
-
get state() {
|
|
1116
|
-
return this._state;
|
|
1117
|
-
}
|
|
1118
|
-
/** Starts the loop. */
|
|
1119
|
-
start() {
|
|
1120
|
-
if (this._state !== "stopped") return;
|
|
1121
|
-
this._state = "running";
|
|
1122
|
-
this.emit("start");
|
|
1123
|
-
this.run();
|
|
1124
|
-
}
|
|
1125
|
-
/** Resumes a paused loop. */
|
|
1126
|
-
resume() {
|
|
1127
|
-
if (this._state !== "paused") return;
|
|
1128
|
-
this._state = "running";
|
|
1129
|
-
this.emit("resume");
|
|
1130
|
-
if (this.remaining <= 0) {
|
|
1131
|
-
this.run();
|
|
1132
|
-
} else {
|
|
1133
|
-
this.timeoutId = setTimeout(() => this.run(), this.remaining);
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
/** Stops the loop. */
|
|
1137
|
-
stop() {
|
|
1138
|
-
const wasRunning = this._state !== "stopped";
|
|
1139
|
-
this._state = "stopped";
|
|
1140
|
-
this.remaining = 0;
|
|
1141
|
-
this.clearTimer();
|
|
1142
|
-
if (wasRunning) this.emit("stop");
|
|
1143
|
-
}
|
|
1144
|
-
/** Pauses the execution. */
|
|
1145
|
-
pause() {
|
|
1146
|
-
if (this._state !== "running") return;
|
|
1147
|
-
this._state = "paused";
|
|
1148
|
-
const elapsed = Date.now() - this.startTime;
|
|
1149
|
-
this.remaining = Math.max(0, this.delay - elapsed);
|
|
1150
|
-
this.emit("pause", { remaining: this.remaining });
|
|
1151
|
-
this.clearTimer();
|
|
1152
|
-
}
|
|
1153
|
-
/**
|
|
1154
|
-
* Sets the delay between runs
|
|
1155
|
-
* @param ms The new delay in milliseconds.
|
|
1156
|
-
*/
|
|
1157
|
-
setDelay(ms2) {
|
|
1158
|
-
this.delay = ms2;
|
|
1159
|
-
}
|
|
1160
|
-
/** Manually trigger the function once without affecting the loop. */
|
|
1161
|
-
async execute() {
|
|
1162
|
-
await this.fn(this);
|
|
1163
|
-
}
|
|
1164
|
-
};
|
|
1165
|
-
|
|
1166
|
-
// src/index.ts
|
|
1167
|
-
var qznt = {
|
|
1168
|
-
arr: arr_exports,
|
|
1169
|
-
async: async_exports,
|
|
1170
|
-
fn: fn_exports,
|
|
1171
|
-
date: date_exports,
|
|
1172
|
-
format: format_exports,
|
|
1173
|
-
fs: fs_exports,
|
|
1174
|
-
is: is_exports,
|
|
1175
|
-
math: math_exports,
|
|
1176
|
-
obj: obj_exports,
|
|
1177
|
-
timing: timing_exports,
|
|
1178
|
-
rnd: rnd_exports,
|
|
1179
|
-
str: str_exports,
|
|
1180
|
-
to: to_exports,
|
|
1181
|
-
Pipe,
|
|
1182
|
-
Storage,
|
|
1183
|
-
Cache,
|
|
1184
|
-
Loop
|
|
1185
|
-
};
|
|
1186
|
-
var $ = qznt;
|
|
1187
|
-
var index_default = qznt;
|
|
1188
1040
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1189
1041
|
0 && (module.exports = {
|
|
1190
|
-
$,
|
|
1191
1042
|
Cache,
|
|
1043
|
+
FormatNumberCompact,
|
|
1192
1044
|
Loop,
|
|
1193
1045
|
Pipe,
|
|
1194
1046
|
Storage,
|
|
1195
|
-
chance,
|
|
1196
|
-
choice,
|
|
1197
1047
|
chunk,
|
|
1198
1048
|
chunkAdj,
|
|
1199
|
-
|
|
1049
|
+
clampNumber,
|
|
1200
1050
|
cluster,
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
currency,
|
|
1051
|
+
compactArray,
|
|
1052
|
+
createSampler,
|
|
1204
1053
|
debounce,
|
|
1205
|
-
defined,
|
|
1206
|
-
duration,
|
|
1207
|
-
empty,
|
|
1208
1054
|
escapeRegex,
|
|
1209
|
-
eta,
|
|
1210
|
-
float,
|
|
1211
1055
|
forceArray,
|
|
1212
|
-
|
|
1056
|
+
formatCurrency,
|
|
1057
|
+
formatDuration,
|
|
1058
|
+
formatETA,
|
|
1059
|
+
formatMemory,
|
|
1060
|
+
formatNumber,
|
|
1061
|
+
formatOrdinal,
|
|
1213
1062
|
getAge,
|
|
1214
1063
|
getFlag,
|
|
1215
|
-
|
|
1064
|
+
getProp,
|
|
1216
1065
|
hasFlag,
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1066
|
+
hasProp,
|
|
1067
|
+
inverseLerp,
|
|
1068
|
+
isDefined,
|
|
1069
|
+
isEmpty,
|
|
1070
|
+
isInRange,
|
|
1071
|
+
isObject,
|
|
1072
|
+
isSortedArray,
|
|
1073
|
+
isString,
|
|
1074
|
+
isToday,
|
|
1221
1075
|
lerp,
|
|
1222
1076
|
memoize,
|
|
1223
|
-
memory,
|
|
1224
1077
|
merge,
|
|
1225
|
-
|
|
1226
|
-
number,
|
|
1227
|
-
object,
|
|
1078
|
+
msToSecs,
|
|
1228
1079
|
omit,
|
|
1229
|
-
|
|
1230
|
-
parse,
|
|
1080
|
+
parseTime,
|
|
1231
1081
|
percent,
|
|
1232
1082
|
pick,
|
|
1083
|
+
pluralize,
|
|
1233
1084
|
prng,
|
|
1234
1085
|
readDir,
|
|
1235
|
-
record,
|
|
1236
1086
|
remap,
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1087
|
+
retryPromise,
|
|
1088
|
+
rndChance,
|
|
1089
|
+
rndChoice,
|
|
1090
|
+
rndFloat,
|
|
1091
|
+
rndIndex,
|
|
1092
|
+
rndInt,
|
|
1093
|
+
rndString,
|
|
1094
|
+
searchSorted,
|
|
1095
|
+
secsToMs,
|
|
1241
1096
|
seqMap,
|
|
1242
|
-
|
|
1097
|
+
setProp,
|
|
1243
1098
|
shuffle,
|
|
1244
1099
|
sortBy,
|
|
1245
|
-
sorted,
|
|
1246
|
-
str,
|
|
1247
|
-
string,
|
|
1248
1100
|
sum,
|
|
1249
1101
|
throttle,
|
|
1250
1102
|
toTitleCase,
|
|
1251
|
-
today,
|
|
1252
1103
|
unique,
|
|
1253
1104
|
wait,
|
|
1254
|
-
|
|
1105
|
+
weightedRnd,
|
|
1255
1106
|
wrap
|
|
1256
1107
|
});
|