@byloth/core 2.2.3 → 2.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.esm.js +507 -225
- package/dist/core.esm.js.map +1 -1
- package/dist/core.global.js +1 -1
- package/dist/core.global.js.map +1 -1
- package/dist/core.umd.cjs +1 -1
- package/dist/core.umd.cjs.map +1 -1
- package/package.json +7 -7
- package/src/index.ts +4 -1
- package/src/models/callbacks/callback-chain.ts +3 -3
- package/src/models/callbacks/publisher.ts +1 -1
- package/src/models/collections/array-view.ts +348 -0
- package/src/models/collections/index.ts +1 -0
- package/src/models/collections/map-view.ts +7 -5
- package/src/models/collections/set-view.ts +9 -7
- package/src/models/collections/types.ts +4 -4
- package/src/models/exceptions/index.ts +51 -10
- package/src/models/index.ts +2 -1
- package/src/models/iterators/smart-async-iterator.ts +1 -1
- package/src/models/iterators/smart-iterator.ts +1 -1
- package/src/models/promises/smart-promise.ts +10 -10
- package/src/models/promises/timed-promise.ts +1 -1
- package/src/utils/index.ts +1 -1
- package/src/utils/math.ts +35 -2
- package/src/utils/random.ts +126 -1
|
@@ -580,7 +580,7 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
580
580
|
* const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
|
|
581
581
|
* const result = iterator.take(3);
|
|
582
582
|
*
|
|
583
|
-
* console.log(result.toArray());
|
|
583
|
+
* console.log(result.toArray()); // [-2, -1, 0]
|
|
584
584
|
* console.log(iterator.toArray()); // [1, 2]
|
|
585
585
|
* ```
|
|
586
586
|
*
|
|
@@ -17,12 +17,12 @@ import type { FulfilledHandler, PromiseExecutor, RejectedHandler } from "./types
|
|
|
17
17
|
* setTimeout(() => resolve("Hello, World!"), 1_000);
|
|
18
18
|
* });
|
|
19
19
|
*
|
|
20
|
-
* console.log(promise.isPending);
|
|
20
|
+
* console.log(promise.isPending); // true
|
|
21
21
|
* console.log(promise.isFulfilled); // false
|
|
22
22
|
*
|
|
23
23
|
* console.log(await promise); // "Hello, World!"
|
|
24
24
|
*
|
|
25
|
-
* console.log(promise.isPending);
|
|
25
|
+
* console.log(promise.isPending); // false
|
|
26
26
|
* console.log(promise.isFulfilled); // true
|
|
27
27
|
* ```
|
|
28
28
|
*
|
|
@@ -39,14 +39,14 @@ export default class SmartPromise<T = void> implements Promise<T>
|
|
|
39
39
|
*
|
|
40
40
|
* @example
|
|
41
41
|
* ```ts
|
|
42
|
-
* const
|
|
43
|
-
* const
|
|
42
|
+
* const response = fetch("https://api.example.com/data");
|
|
43
|
+
* const smartResponse = SmartPromise.FromPromise(response);
|
|
44
44
|
*
|
|
45
|
-
* console.log(
|
|
46
|
-
* console.log(
|
|
45
|
+
* console.log(response.isPending); // Throws an error: `isPending` is not a property of `Promise`.
|
|
46
|
+
* console.log(smartResponse.isPending); // true
|
|
47
47
|
*
|
|
48
|
-
* const response = await
|
|
49
|
-
* console.log(
|
|
48
|
+
* const response = await response;
|
|
49
|
+
* console.log(smartResponse.isFulfilled); // true
|
|
50
50
|
* ```
|
|
51
51
|
*
|
|
52
52
|
* ---
|
|
@@ -323,8 +323,8 @@ export default class SmartPromise<T = void> implements Promise<T>
|
|
|
323
323
|
*
|
|
324
324
|
*
|
|
325
325
|
* promise
|
|
326
|
-
* .then(() => console.log("OK!"))
|
|
327
|
-
* .catch(() => console.log("KO!"))
|
|
326
|
+
* .then(() => console.log("OK!")) // Logs "OK!" if the promise is fulfilled.
|
|
327
|
+
* .catch(() => console.log("KO!")) // Logs "KO!" if the promise is rejected.
|
|
328
328
|
* .finally(() => console.log("Done!")); // Always logs "Done!".
|
|
329
329
|
* ```
|
|
330
330
|
*
|
|
@@ -20,7 +20,7 @@ import type { MaybePromise, PromiseExecutor } from "./types.js";
|
|
|
20
20
|
* }, 5_000);
|
|
21
21
|
*
|
|
22
22
|
* promise
|
|
23
|
-
* .then((result) => console.log(result))
|
|
23
|
+
* .then((result) => console.log(result)) // "Hello, World!"
|
|
24
24
|
* .catch((error) => console.error(error)); // "Uncaught TimeoutException: The operation has timed out."
|
|
25
25
|
* ```
|
|
26
26
|
*
|
package/src/utils/index.ts
CHANGED
|
@@ -5,5 +5,5 @@ export { delay, nextAnimationFrame, yieldToEventLoop } from "./async.js";
|
|
|
5
5
|
export { dateDifference, dateRange, dateRound, getWeek, TimeUnit, WeekDay } from "./date.js";
|
|
6
6
|
export { loadScript } from "./dom.js";
|
|
7
7
|
export { chain, count, enumerate, range, shuffle, unique, zip } from "./iterator.js";
|
|
8
|
-
export { average, hash, sum } from "./math.js";
|
|
8
|
+
export { average, clamp, hash, sum } from "./math.js";
|
|
9
9
|
export { capitalize } from "./string.js";
|
package/src/utils/math.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { zip } from "./iterator.js";
|
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```ts
|
|
12
|
-
* average([1, 2, 3, 4, 5]);
|
|
12
|
+
* average([1, 2, 3, 4, 5]); // 3
|
|
13
13
|
* average([6, 8.5, 4], [3, 2, 1]); // 6.5
|
|
14
14
|
* ```
|
|
15
15
|
*
|
|
@@ -71,6 +71,39 @@ export function average<T extends number>(values: Iterable<T>, weights?: Iterabl
|
|
|
71
71
|
return _sum / _count;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Clamps a given value between a minimum and a maximum bound.
|
|
76
|
+
*
|
|
77
|
+
* ---
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* clamp(5, 0, 10); // 5
|
|
82
|
+
* clamp(-3, 0, 10); // 0
|
|
83
|
+
* clamp(15, 0, 10); // 10
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* ---
|
|
87
|
+
*
|
|
88
|
+
* @param value The value to clamp.
|
|
89
|
+
* @param min The minimum bound.
|
|
90
|
+
* @param max The maximum bound.
|
|
91
|
+
*
|
|
92
|
+
* @returns The clamped value between the specified bounds.
|
|
93
|
+
*/
|
|
94
|
+
export function clamp(value: number, min: number, max: number): number
|
|
95
|
+
{
|
|
96
|
+
if (min > max)
|
|
97
|
+
{
|
|
98
|
+
throw new ValueException("The minimum bound must be less than or equal to the maximum bound.");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (value < min) { return min; }
|
|
102
|
+
if (value > max) { return max; }
|
|
103
|
+
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
|
|
74
107
|
/**
|
|
75
108
|
* An utility function to compute the hash of a given string.
|
|
76
109
|
*
|
|
@@ -83,7 +116,7 @@ export function average<T extends number>(values: Iterable<T>, weights?: Iterabl
|
|
|
83
116
|
* @example
|
|
84
117
|
* ```ts
|
|
85
118
|
* hash("Hello, world!"); // -1880044555
|
|
86
|
-
* hash("How are you?");
|
|
119
|
+
* hash("How are you?"); // 1761539132
|
|
87
120
|
* ```
|
|
88
121
|
*
|
|
89
122
|
* ---
|
package/src/utils/random.ts
CHANGED
|
@@ -259,7 +259,7 @@ export default class Random
|
|
|
259
259
|
|
|
260
260
|
if (weights === undefined)
|
|
261
261
|
{
|
|
262
|
-
const pool =
|
|
262
|
+
const pool = Array.from(elements);
|
|
263
263
|
const result: T[] = new Array(count);
|
|
264
264
|
|
|
265
265
|
for (let index = 0; index < count; index += 1)
|
|
@@ -300,6 +300,131 @@ export default class Random
|
|
|
300
300
|
return result;
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
+
static #Split(total: number, parts: number): number[]
|
|
304
|
+
{
|
|
305
|
+
const cuts: number[] = new Array(parts - 1);
|
|
306
|
+
for (let index = 0; index < cuts.length; index += 1)
|
|
307
|
+
{
|
|
308
|
+
cuts[index] = Math.random() * total;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
cuts.sort((a, b) => (a - b));
|
|
312
|
+
|
|
313
|
+
const boundaries = [0, ...cuts, total];
|
|
314
|
+
const values: number[] = new Array(parts);
|
|
315
|
+
|
|
316
|
+
for (let index = 0; index < parts; index += 1)
|
|
317
|
+
{
|
|
318
|
+
values[index] = Math.floor(boundaries[index + 1] - boundaries[index]);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
let remainder = total - values.reduce((sum, val) => (sum + val), 0);
|
|
322
|
+
while (remainder > 0)
|
|
323
|
+
{
|
|
324
|
+
values[this.Integer(parts)] += 1;
|
|
325
|
+
|
|
326
|
+
remainder -= 1;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return values;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Splits a total amount into a given number of randomly balanced integer parts that sum to the total.
|
|
334
|
+
*
|
|
335
|
+
* Uses random cut-points to generate a uniform distribution of parts.
|
|
336
|
+
*
|
|
337
|
+
* ---
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
* ```ts
|
|
341
|
+
* Random.Split(100, 3); // [28, 41, 31]
|
|
342
|
+
* Random.Split(10, 4); // [3, 1, 4, 2]
|
|
343
|
+
* ```
|
|
344
|
+
*
|
|
345
|
+
* ---
|
|
346
|
+
*
|
|
347
|
+
* @param total
|
|
348
|
+
* The total amount to split.
|
|
349
|
+
*
|
|
350
|
+
* It must be non-negative. Otherwise, a {@link ValueException} will be thrown.
|
|
351
|
+
*
|
|
352
|
+
* @param parts
|
|
353
|
+
* The number of parts to split the total into.
|
|
354
|
+
*
|
|
355
|
+
* It must be at least `1`. Otherwise, a {@link ValueException} will be thrown.
|
|
356
|
+
*
|
|
357
|
+
* @returns An array of integers that sum to the given total.
|
|
358
|
+
*/
|
|
359
|
+
public static Split(total: number, parts: number): number[];
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Splits an iterable of elements into a given number of randomly balanced groups.
|
|
363
|
+
*
|
|
364
|
+
* The elements are distributed into groups whose sizes are
|
|
365
|
+
* determined by a random split of the total number of elements.
|
|
366
|
+
*
|
|
367
|
+
* ---
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```ts
|
|
371
|
+
* Random.Split([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4, 5]]
|
|
372
|
+
* Random.Split([1, 2, 3, 4, 5], 2); // [[1, 2, 3, 4], [5]]
|
|
373
|
+
* Random.Split("abcdef", 3); // [["a"], ["b", "c", "d"], ["e", "f"]]
|
|
374
|
+
* ```
|
|
375
|
+
*
|
|
376
|
+
* ---
|
|
377
|
+
*
|
|
378
|
+
* @template T The type of the elements in the iterable.
|
|
379
|
+
*
|
|
380
|
+
* @param elements
|
|
381
|
+
* The iterable of elements to split into groups.
|
|
382
|
+
*
|
|
383
|
+
* It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.
|
|
384
|
+
*
|
|
385
|
+
* @param groups
|
|
386
|
+
* The number of groups to split the elements into.
|
|
387
|
+
*
|
|
388
|
+
* It must be between `1` and the number of elements.
|
|
389
|
+
* Otherwise, a {@link ValueException} will be thrown.
|
|
390
|
+
*
|
|
391
|
+
* @returns An array of arrays, each containing a subset of the original elements.
|
|
392
|
+
*/
|
|
393
|
+
public static Split<T>(elements: Iterable<T>, groups: number): T[][];
|
|
394
|
+
public static Split<T>(totalOrElements: number | Iterable<T>, parts: number): number[] | T[][]
|
|
395
|
+
{
|
|
396
|
+
if (parts < 1) { throw new ValueException("The number of splits must be greater than zero."); }
|
|
397
|
+
|
|
398
|
+
if (typeof totalOrElements === "number")
|
|
399
|
+
{
|
|
400
|
+
if (totalOrElements < 0) { throw new ValueException("The total must be a non-negative number."); }
|
|
401
|
+
|
|
402
|
+
return this.#Split(totalOrElements, parts);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const elements = Array.from(totalOrElements);
|
|
406
|
+
const length = elements.length;
|
|
407
|
+
|
|
408
|
+
if (length === 0) { throw new ValueException("You must provide at least one element."); }
|
|
409
|
+
if (parts > length)
|
|
410
|
+
{
|
|
411
|
+
throw new ValueException("The number of splits cannot exceed the number of elements.");
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const sizes = this.#Split(length, parts);
|
|
415
|
+
const groups: T[][] = new Array(parts);
|
|
416
|
+
|
|
417
|
+
let offset = 0;
|
|
418
|
+
for (let index = 0; index < parts; index += 1)
|
|
419
|
+
{
|
|
420
|
+
groups[index] = elements.slice(offset, offset + sizes[index]);
|
|
421
|
+
|
|
422
|
+
offset += sizes[index];
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return groups;
|
|
426
|
+
}
|
|
427
|
+
|
|
303
428
|
private constructor() { /* ... */ }
|
|
304
429
|
|
|
305
430
|
public readonly [Symbol.toStringTag]: string = "Random";
|