@byloth/core 2.2.2 → 2.2.3
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 +262 -220
- 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 +1 -1
- package/src/models/aggregators/index.ts +3 -5
- package/src/models/callbacks/callback-chain.ts +8 -1
- package/src/models/callbacks/index.ts +4 -6
- package/src/models/callbacks/publisher.ts +8 -2
- package/src/models/collections/index.ts +2 -4
- package/src/models/iterators/index.ts +2 -4
- package/src/models/json/index.ts +1 -3
- package/src/models/promises/index.ts +4 -6
- package/src/models/timers/index.ts +3 -5
- package/src/utils/index.ts +2 -4
- package/src/utils/random.ts +121 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byloth/core",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"description": "An unopinionated collection of useful functions and classes that I use widely in all my projects. 🔧",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Core",
|
|
@@ -51,14 +51,14 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@byloth/eslint-config-typescript": "^3.2.2",
|
|
53
53
|
"@eslint/compat": "^2.0.0",
|
|
54
|
-
"@types/node": "^22.19.
|
|
55
|
-
"@vitest/coverage-v8": "^4.0.
|
|
56
|
-
"eslint": "^9.39.
|
|
54
|
+
"@types/node": "^22.19.3",
|
|
55
|
+
"@vitest/coverage-v8": "^4.0.16",
|
|
56
|
+
"eslint": "^9.39.2",
|
|
57
57
|
"husky": "^9.1.7",
|
|
58
|
-
"jsdom": "^27.
|
|
58
|
+
"jsdom": "^27.4.0",
|
|
59
59
|
"typescript": "^5.9.3",
|
|
60
|
-
"vite": "^7.
|
|
61
|
-
"vitest": "^4.0.
|
|
60
|
+
"vite": "^7.3.0",
|
|
61
|
+
"vitest": "^4.0.16"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"dev": "vite",
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export { AggregatedIterator, AggregatedAsyncIterator, ReducedIterator };
|
|
1
|
+
export { default as AggregatedIterator } from "./aggregated-iterator.js";
|
|
2
|
+
export { default as AggregatedAsyncIterator } from "./aggregated-async-iterator.js";
|
|
3
|
+
export { default as ReducedIterator } from "./reduced-iterator.js";
|
|
@@ -79,7 +79,14 @@ export default class CallbackChain<
|
|
|
79
79
|
*/
|
|
80
80
|
protected override _invoke(...args: Parameters<T>): ReturnType<T>[]
|
|
81
81
|
{
|
|
82
|
-
|
|
82
|
+
const length = this._callbacks.length;
|
|
83
|
+
const results = new Array<ReturnType<T>>(length);
|
|
84
|
+
for (let i = 0; i < length; i += 1)
|
|
85
|
+
{
|
|
86
|
+
results[i] = this._callbacks[i](...args);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return results;
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
/**
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export { CallableObject, CallbackChain, Publisher, SwitchableCallback };
|
|
1
|
+
export { default as CallableObject } from "./callable-object.js";
|
|
2
|
+
export { default as CallbackChain } from "./callback-chain.js";
|
|
3
|
+
export { default as Publisher } from "./publisher.js";
|
|
4
|
+
export { default as SwitchableCallback } from "./switchable-callback.js";
|
|
@@ -170,8 +170,14 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
|
|
|
170
170
|
let subscribers = this._subscribers.get(event);
|
|
171
171
|
if (subscribers)
|
|
172
172
|
{
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
const _subscribers = subscribers.slice();
|
|
174
|
+
const _length = _subscribers.length;
|
|
175
|
+
|
|
176
|
+
results = new Array<unknown>(_length);
|
|
177
|
+
for (let i = 0; i < _length; i += 1)
|
|
178
|
+
{
|
|
179
|
+
results[i] = _subscribers[i](...args);
|
|
180
|
+
}
|
|
175
181
|
}
|
|
176
182
|
else { results = []; }
|
|
177
183
|
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export { SmartIterator, SmartAsyncIterator };
|
|
1
|
+
export { default as SmartIterator } from "./smart-iterator.js";
|
|
2
|
+
export { default as SmartAsyncIterator } from "./smart-async-iterator.js";
|
package/src/models/json/index.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export { DeferredPromise, PromiseQueue, SmartPromise, TimedPromise };
|
|
1
|
+
export { default as DeferredPromise } from "./deferred-promise.js";
|
|
2
|
+
export { default as PromiseQueue } from "./promise-queue.js";
|
|
3
|
+
export { default as SmartPromise } from "./smart-promise.js";
|
|
4
|
+
export { default as TimedPromise } from "./timed-promise.js";
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export { Clock, Countdown, GameLoop };
|
|
1
|
+
export { default as Clock } from "./clock.js";
|
|
2
|
+
export { default as Countdown } from "./countdown.js";
|
|
3
|
+
export { default as GameLoop } from "./game-loop.js";
|
package/src/utils/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export { default as Curve } from "./curve.js";
|
|
2
|
+
export { default as Random } from "./random.js";
|
|
3
3
|
|
|
4
4
|
export { delay, nextAnimationFrame, yieldToEventLoop } from "./async.js";
|
|
5
5
|
export { dateDifference, dateRange, dateRound, getWeek, TimeUnit, WeekDay } from "./date.js";
|
|
@@ -7,5 +7,3 @@ export { loadScript } from "./dom.js";
|
|
|
7
7
|
export { chain, count, enumerate, range, shuffle, unique, zip } from "./iterator.js";
|
|
8
8
|
export { average, hash, sum } from "./math.js";
|
|
9
9
|
export { capitalize } from "./string.js";
|
|
10
|
-
|
|
11
|
-
export { Curve, Random };
|
package/src/utils/random.ts
CHANGED
|
@@ -179,6 +179,127 @@ export default class Random
|
|
|
179
179
|
return elements[Random.Index(elements)];
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Picks a random sample of elements from a given array without replacement.
|
|
184
|
+
*
|
|
185
|
+
* Uses the Fisher-Yates shuffle algorithm for uniform sampling,
|
|
186
|
+
* which is O(count) instead of O(n log n) for a full shuffle.
|
|
187
|
+
*
|
|
188
|
+
* ---
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* Random.Sample([1, 2, 3, 4, 5], 3); // e.g., [4, 1, 5]
|
|
193
|
+
* ```
|
|
194
|
+
*
|
|
195
|
+
* ---
|
|
196
|
+
*
|
|
197
|
+
* @template T The type of the elements in the array.
|
|
198
|
+
*
|
|
199
|
+
* @param elements
|
|
200
|
+
* The array of elements to sample from.
|
|
201
|
+
*
|
|
202
|
+
* It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.
|
|
203
|
+
*
|
|
204
|
+
* @param count
|
|
205
|
+
* The number of elements to sample.
|
|
206
|
+
*
|
|
207
|
+
* It must be between `0` and `elements.length`. Otherwise, a {@link ValueException} will be thrown.
|
|
208
|
+
*
|
|
209
|
+
* @returns An array containing the randomly sampled elements.
|
|
210
|
+
*/
|
|
211
|
+
public static Sample<T>(elements: readonly T[], count: number): T[];
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Picks a weighted random sample of elements from a given array without replacement.
|
|
215
|
+
*
|
|
216
|
+
* Uses the Efraimidis-Spirakis algorithm for weighted sampling.
|
|
217
|
+
* Elements with higher weights have a higher probability of being selected.
|
|
218
|
+
*
|
|
219
|
+
* ---
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```ts
|
|
223
|
+
* // Element "a" is 3x more likely to be picked than "b" or "c"
|
|
224
|
+
* Random.Sample(["a", "b", "c"], 2, [3, 1, 1]);
|
|
225
|
+
* ```
|
|
226
|
+
*
|
|
227
|
+
* ---
|
|
228
|
+
*
|
|
229
|
+
* @template T The type of the elements in the array.
|
|
230
|
+
*
|
|
231
|
+
* @param elements
|
|
232
|
+
* The array of elements to sample from.
|
|
233
|
+
*
|
|
234
|
+
* It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.
|
|
235
|
+
*
|
|
236
|
+
* @param count
|
|
237
|
+
* The number of elements to sample.
|
|
238
|
+
*
|
|
239
|
+
* It must be between `0` and `elements.length`. Otherwise, a {@link ValueException} will be thrown.
|
|
240
|
+
*
|
|
241
|
+
* @param weights
|
|
242
|
+
* The weights associated with each element.
|
|
243
|
+
*
|
|
244
|
+
* It must have the same length as the elements array.
|
|
245
|
+
* All weights must be greater than zero. Otherwise, a {@link ValueException} will be thrown.
|
|
246
|
+
*
|
|
247
|
+
* @returns An array containing the randomly sampled elements.
|
|
248
|
+
*/
|
|
249
|
+
public static Sample<T>(elements: readonly T[], count: number, weights: readonly number[]): T[];
|
|
250
|
+
public static Sample<T>(elements: readonly T[], count: number, weights?: readonly number[]): T[]
|
|
251
|
+
{
|
|
252
|
+
const length = elements.length;
|
|
253
|
+
|
|
254
|
+
if (length === 0) { throw new ValueException("You must provide at least one element."); }
|
|
255
|
+
if (count < 0) { throw new ValueException("Count must be non-negative."); }
|
|
256
|
+
if (count > length) { throw new ValueException("Count cannot exceed the number of elements."); }
|
|
257
|
+
|
|
258
|
+
if (count === 0) { return []; }
|
|
259
|
+
|
|
260
|
+
if (weights === undefined)
|
|
261
|
+
{
|
|
262
|
+
const pool = [...elements];
|
|
263
|
+
const result: T[] = new Array(count);
|
|
264
|
+
|
|
265
|
+
for (let index = 0; index < count; index += 1)
|
|
266
|
+
{
|
|
267
|
+
const randomIndex = this.Integer(index, length);
|
|
268
|
+
|
|
269
|
+
result[index] = pool[randomIndex];
|
|
270
|
+
pool[randomIndex] = pool[index];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (weights.length !== length)
|
|
277
|
+
{
|
|
278
|
+
throw new ValueException("Weights array must have the same length as elements array.");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const keys: ({ index: number, key: number })[] = new Array(length);
|
|
282
|
+
for (let index = 0; index < length; index += 1)
|
|
283
|
+
{
|
|
284
|
+
if (weights[index] <= 0)
|
|
285
|
+
{
|
|
286
|
+
throw new ValueException(`Weight for element #${index} must be greater than zero.`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
keys[index] = { index: index, key: Math.pow(Math.random(), 1 / weights[index]) };
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
keys.sort((a, b) => b.key - a.key);
|
|
293
|
+
|
|
294
|
+
const result: T[] = new Array(count);
|
|
295
|
+
for (let index = 0; index < count; index += 1)
|
|
296
|
+
{
|
|
297
|
+
result[index] = elements[keys[index].index];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
|
|
182
303
|
private constructor() { /* ... */ }
|
|
183
304
|
|
|
184
305
|
public readonly [Symbol.toStringTag]: string = "Random";
|