@byloth/core 2.0.0-rc.1 → 2.0.0-rc.11

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.
Files changed (43) hide show
  1. package/dist/core.js +1395 -894
  2. package/dist/core.js.map +1 -1
  3. package/dist/core.umd.cjs +3 -3
  4. package/dist/core.umd.cjs.map +1 -1
  5. package/package.json +8 -10
  6. package/src/helpers.ts +7 -0
  7. package/src/index.ts +19 -14
  8. package/src/models/aggregators/aggregated-async-iterator.ts +129 -81
  9. package/src/models/aggregators/aggregated-iterator.ts +128 -82
  10. package/src/models/aggregators/index.ts +1 -3
  11. package/src/models/aggregators/reduced-iterator.ts +118 -30
  12. package/src/models/aggregators/types.ts +15 -10
  13. package/src/models/callbacks/callable-object.ts +25 -0
  14. package/src/models/callbacks/index.ts +5 -0
  15. package/src/models/callbacks/publisher.ts +64 -0
  16. package/src/models/callbacks/switchable-callback.ts +110 -0
  17. package/src/models/callbacks/types.ts +1 -0
  18. package/src/models/exceptions/core.ts +3 -3
  19. package/src/models/exceptions/index.ts +13 -13
  20. package/src/models/game-loop.ts +9 -9
  21. package/src/models/index.ts +3 -6
  22. package/src/models/iterators/smart-async-iterator.ts +109 -23
  23. package/src/models/iterators/smart-iterator.ts +105 -12
  24. package/src/models/iterators/types.ts +17 -7
  25. package/src/models/json/json-storage.ts +2 -3
  26. package/src/models/json/types.ts +3 -1
  27. package/src/models/promises/deferred-promise.ts +1 -1
  28. package/src/models/promises/index.ts +3 -1
  29. package/src/models/promises/long-running-task.ts +294 -0
  30. package/src/models/promises/smart-promise.ts +6 -1
  31. package/src/models/promises/thenable.ts +97 -0
  32. package/src/models/promises/timed-promise.ts +1 -1
  33. package/src/models/promises/types.ts +2 -0
  34. package/src/models/timers/clock.ts +29 -7
  35. package/src/models/timers/countdown.ts +56 -20
  36. package/src/models/types.ts +12 -10
  37. package/src/utils/async.ts +9 -4
  38. package/src/utils/date.ts +3 -0
  39. package/src/utils/index.ts +1 -1
  40. package/src/utils/random.ts +4 -3
  41. package/src/models/aggregators/aggregator.ts +0 -46
  42. package/src/models/aggregators/async-aggregator.ts +0 -56
  43. package/src/models/publisher.ts +0 -39
@@ -27,5 +27,5 @@ export default class TimedPromise<T = void> extends SmartPromise<T>
27
27
  });
28
28
  }
29
29
 
30
- public get [Symbol.toStringTag]() { return "TimedPromise"; }
30
+ public readonly [Symbol.toStringTag]: string = "TimedPromise";
31
31
  }
@@ -1,3 +1,5 @@
1
+ export type { LongRunningTaskOptions } from "./long-running-task.js";
2
+
1
3
  export type MaybePromise<T> = T | PromiseLike<T>;
2
4
 
3
5
  export type FulfilledHandler<T = void, R = T> = (value: T) => MaybePromise<R>;
@@ -1,16 +1,23 @@
1
1
  import { TimeUnit } from "../../utils/date.js";
2
-
3
2
  import { RangeException, RuntimeException } from "../exceptions/index.js";
3
+
4
+ import Publisher from "../callbacks/publisher.js";
4
5
  import GameLoop from "../game-loop.js";
5
- import Publisher from "../publisher.js";
6
+
7
+ interface ClockEventMap
8
+ {
9
+ start: () => void;
10
+ stop: () => void;
11
+ tick: (elapsedTime: number) => void;
12
+ }
6
13
 
7
14
  export default class Clock extends GameLoop
8
15
  {
9
- protected _publisher: Publisher<[number], void>;
16
+ protected _publisher: Publisher<ClockEventMap>;
10
17
 
11
- public constructor(fpsIfNotBrowser = TimeUnit.Second)
18
+ public constructor(msIfNotBrowser: number = TimeUnit.Second)
12
19
  {
13
- super((elapsedTime) => this._publisher.publish(elapsedTime), fpsIfNotBrowser);
20
+ super((elapsedTime) => this._publisher.publish("tick", elapsedTime), msIfNotBrowser);
14
21
 
15
22
  this._publisher = new Publisher();
16
23
  }
@@ -20,6 +27,8 @@ export default class Clock extends GameLoop
20
27
  if (this._isRunning) { throw new RuntimeException("The clock has already been started."); }
21
28
 
22
29
  super.start(elapsedTime);
30
+
31
+ this._publisher.publish("start");
23
32
  }
24
33
 
25
34
  public stop(): void
@@ -27,16 +36,27 @@ export default class Clock extends GameLoop
27
36
  if (!(this._isRunning)) { throw new RuntimeException("The clock hadn't yet started."); }
28
37
 
29
38
  super.stop();
39
+
40
+ this._publisher.publish("stop");
41
+ }
42
+
43
+ public onStart(callback: () => void): () => void
44
+ {
45
+ return this._publisher.subscribe("start", callback);
46
+ }
47
+ public onStop(callback: () => void): () => void
48
+ {
49
+ return this._publisher.subscribe("stop", callback);
30
50
  }
31
51
 
32
52
  public onTick(callback: (elapsedTime: number) => void, tickStep = 0): () => void
33
53
  {
34
54
  if (tickStep < 0) { throw new RangeException("The tick step must be a non-negative number."); }
35
- if (tickStep === 0) { return this._publisher.subscribe(callback); }
55
+ if (tickStep === 0) { return this._publisher.subscribe("tick", callback); }
36
56
 
37
57
  let lastTick = 0;
38
58
 
39
- return this._publisher.subscribe((elapsedTime: number) =>
59
+ return this._publisher.subscribe("tick", (elapsedTime: number) =>
40
60
  {
41
61
  if ((elapsedTime - lastTick) < tickStep) { return; }
42
62
 
@@ -44,4 +64,6 @@ export default class Clock extends GameLoop
44
64
  lastTick = elapsedTime;
45
65
  });
46
66
  }
67
+
68
+ public readonly [Symbol.toStringTag]: string = "Clock";
47
69
  }
@@ -1,15 +1,23 @@
1
1
  import { TimeUnit } from "../../utils/date.js";
2
2
 
3
3
  import { FatalErrorException, RangeException, RuntimeException } from "../exceptions/index.js";
4
- import { DeferredPromise } from "../promises/index.js";
4
+ import { DeferredPromise, SmartPromise } from "../promises/index.js";
5
5
 
6
+ import Publisher from "../callbacks/publisher.js";
6
7
  import GameLoop from "../game-loop.js";
7
- import Publisher from "../publisher.js";
8
+
9
+ interface CountdownEventMap
10
+ {
11
+ start: () => void;
12
+ stop: (reason: unknown) => void;
13
+ tick: (remainingTime: number) => void;
14
+ expire: () => void;
15
+ }
8
16
 
9
17
  export default class Countdown extends GameLoop
10
18
  {
11
19
  protected _deferrer?: DeferredPromise<void>;
12
- protected _publisher: Publisher<[number], void>;
20
+ protected _publisher: Publisher<CountdownEventMap>;
13
21
 
14
22
  protected _duration: number;
15
23
  public get duration(): number
@@ -22,55 +30,81 @@ export default class Countdown extends GameLoop
22
30
  return this._duration - this.elapsedTime;
23
31
  }
24
32
 
25
- public constructor(duration: number, fpsIfNotBrowser = TimeUnit.Second)
33
+ public constructor(duration: number, msIfNotBrowser: number = TimeUnit.Second)
26
34
  {
27
- const callback = (elapsedTime: number) =>
35
+ const callback = () =>
28
36
  {
29
- this._duration -= elapsedTime;
30
-
31
37
  const remainingTime = this.remainingTime;
32
- this._publisher.publish(remainingTime);
38
+ this._publisher.publish("tick", remainingTime);
33
39
 
34
- if (remainingTime <= 0) { this.stop(); }
40
+ if (remainingTime <= 0)
41
+ {
42
+ this._deferrerStop();
43
+
44
+ this._publisher.publish("expire");
45
+ }
35
46
  };
36
47
 
37
- super(callback, fpsIfNotBrowser);
48
+ super(callback, msIfNotBrowser);
38
49
 
39
50
  this._publisher = new Publisher();
40
51
  this._duration = duration;
41
52
  }
42
53
 
43
- public start(remainingTime: number = this.duration): DeferredPromise<void>
54
+ protected _deferrerStop(reason?: unknown): void
55
+ {
56
+ if (!(this._isRunning)) { throw new RuntimeException("The countdown hadn't yet started."); }
57
+ if (!(this._deferrer)) { throw new FatalErrorException(); }
58
+
59
+ super.stop();
60
+
61
+ if (reason !== undefined) { this._deferrer.reject(reason); }
62
+ else { this._deferrer.resolve(); }
63
+
64
+ this._deferrer = undefined;
65
+ }
66
+
67
+ public start(remainingTime: number = this.duration): SmartPromise<void>
44
68
  {
45
69
  if (this._isRunning) { throw new RuntimeException("The countdown has already been started."); }
46
70
  if (this._deferrer) { throw new FatalErrorException(); }
47
71
 
48
- this._deferrer = new DeferredPromise(() => this.stop());
72
+ this._deferrer = new DeferredPromise();
49
73
  super.start(this.duration - remainingTime);
50
74
 
75
+ this._publisher.publish("start");
76
+
51
77
  return this._deferrer;
52
78
  }
53
79
  public stop(reason?: unknown): void
54
80
  {
55
- if (!(this._isRunning)) { throw new RuntimeException("The countdown hadn't yet started."); }
56
- if (!(this._deferrer)) { throw new FatalErrorException(); }
81
+ this._deferrerStop(reason);
57
82
 
58
- super.stop();
83
+ this._publisher.publish("stop", reason);
84
+ }
59
85
 
60
- if (reason !== undefined) { this._deferrer.reject(reason); }
61
- else { this._deferrer.resolve(); }
86
+ public onExpire(callback: () => void): () => void
87
+ {
88
+ return this._publisher.subscribe("expire", callback);
89
+ }
62
90
 
63
- this._deferrer = undefined;
91
+ public onStart(callback: () => void): () => void
92
+ {
93
+ return this._publisher.subscribe("start", callback);
94
+ }
95
+ public onStop(callback: (reason?: unknown) => void): () => void
96
+ {
97
+ return this._publisher.subscribe("stop", callback);
64
98
  }
65
99
 
66
100
  public onTick(callback: (remainingTime: number) => void, tickStep = 0): () => void
67
101
  {
68
102
  if (tickStep < 0) { throw new RangeException("The tick step must be a non-negative number."); }
69
- if (tickStep === 0) { return this._publisher.subscribe(callback); }
103
+ if (tickStep === 0) { return this._publisher.subscribe("tick", callback); }
70
104
 
71
105
  let lastTick = 0;
72
106
 
73
- return this._publisher.subscribe((remainingTime: number) =>
107
+ return this._publisher.subscribe("tick", (remainingTime: number) =>
74
108
  {
75
109
  if ((lastTick - remainingTime) < tickStep) { return; }
76
110
 
@@ -78,4 +112,6 @@ export default class Countdown extends GameLoop
78
112
  lastTick = remainingTime;
79
113
  });
80
114
  }
115
+
116
+ public readonly [Symbol.toStringTag]: string = "Countdown";
81
117
  }
@@ -1,25 +1,26 @@
1
1
  export type {
2
- KeyIteratee,
3
- MaybeAsyncKeyIteratee,
4
- KeyTypeGuardIteratee,
5
- MaybeAsyncKeyTypeGuardIteratee,
6
- KeyReducer,
7
- MaybeAsyncKeyReducer
2
+ KeyedIteratee,
3
+ MaybeAsyncKeyedIteratee,
4
+ KeyedTypeGuardIteratee,
5
+ MaybeAsyncKeyedTypeGuardIteratee,
6
+ KeyedReducer,
7
+ MaybeAsyncKeyedReducer
8
8
 
9
9
  } from "./aggregators/types.js";
10
10
 
11
11
  export type {
12
12
  GeneratorFunction,
13
13
  AsyncGeneratorFunction,
14
+ MaybeAsyncGeneratorFunction,
14
15
  Iteratee,
15
16
  MaybeAsyncIteratee,
16
17
  TypeGuardIteratee,
17
18
  MaybeAsyncTypeGuardIteratee,
18
19
  Reducer,
19
20
  MaybeAsyncReducer,
20
- IterLike,
21
- AsyncIterLike,
22
- MaybeAsyncIterLike
21
+ IteratorLike,
22
+ AsyncIteratorLike,
23
+ MaybeAsyncIteratorLike
23
24
 
24
25
  } from "./iterators/types.js";
25
26
 
@@ -31,6 +32,7 @@ export type {
31
32
  } from "./json/types.js";
32
33
 
33
34
  export type {
35
+ LongRunningTaskOptions,
34
36
  MaybePromise,
35
37
  FulfilledHandler,
36
38
  RejectedHandler,
@@ -40,4 +42,4 @@ export type {
40
42
 
41
43
  } from "./promises/types.js";
42
44
 
43
- export type { Subscriber } from "./publisher.js";
45
+ export type { Callback } from "./callbacks/types.js";
@@ -1,9 +1,14 @@
1
- export async function delay(milliseconds: number): Promise<void>
1
+ export function delay(milliseconds: number): Promise<void>
2
2
  {
3
- return new Promise<void>((resolve, reject) => setTimeout(resolve, milliseconds));
3
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
4
4
  }
5
5
 
6
- export async function nextAnimationFrame(): Promise<void>
6
+ export function nextAnimationFrame(): Promise<void>
7
7
  {
8
- return new Promise<void>((resolve, reject) => requestAnimationFrame(() => resolve()));
8
+ return new Promise((resolve) => requestAnimationFrame(() => resolve()));
9
+ }
10
+
11
+ export function yieldToEventLoop(): Promise<void>
12
+ {
13
+ return new Promise((resolve) => setTimeout(resolve));
9
14
  }
package/src/utils/date.ts CHANGED
@@ -1,7 +1,10 @@
1
+
1
2
  import { SmartIterator } from "../models/index.js";
2
3
 
3
4
  export enum TimeUnit
4
5
  {
6
+ /* eslint-disable @typescript-eslint/prefer-literal-enum-member */
7
+
5
8
  Millisecond = 1,
6
9
  Second = 1000,
7
10
  Minute = 60 * Second,
@@ -1,6 +1,6 @@
1
1
  import Random from "./random.js";
2
2
 
3
- export { delay, nextAnimationFrame } from "./async.js";
3
+ export { delay, nextAnimationFrame, yieldToEventLoop } from "./async.js";
4
4
  export { dateDifference, dateRange, dateRound, TimeUnit } from "./date.js";
5
5
  export { loadScript } from "./dom.js";
6
6
  export { chain, count, enumerate, range, shuffle, unique, zip } from "./iterator.js";
@@ -2,7 +2,7 @@ import { ValueException } from "../models/index.js";
2
2
 
3
3
  export default class Random
4
4
  {
5
- public static Boolean(ratio: number = 0.5): boolean
5
+ public static Boolean(ratio = 0.5): boolean
6
6
  {
7
7
  return (Math.random() < ratio);
8
8
  }
@@ -38,6 +38,7 @@ export default class Random
38
38
  return elements[Random.Index(elements)];
39
39
  }
40
40
 
41
- // eslint-disable-next-line no-useless-constructor
42
- private constructor() { }
41
+ private constructor() { /* ... */ }
42
+
43
+ public readonly [Symbol.toStringTag]: string = "Random";
43
44
  }
@@ -1,46 +0,0 @@
1
- import AggregatedIterator from "./aggregated-iterator.js";
2
-
3
- import { SmartIterator } from "../iterators/index.js";
4
- import type { GeneratorFunction, Iteratee, IterLike, TypeGuardIteratee } from "../iterators/types.js";
5
-
6
- export default class Aggregator<T>
7
- {
8
- protected _elements: SmartIterator<T>;
9
-
10
- public constructor(iterable: Iterable<T>);
11
- public constructor(iterator: Iterator<T>);
12
- public constructor(generatorFn: GeneratorFunction<T>);
13
- public constructor(argument: IterLike<T>);
14
- public constructor(argument: IterLike<T>)
15
- {
16
- this._elements = new SmartIterator(argument);
17
- }
18
-
19
- public filter(predicate: Iteratee<T, boolean>): Aggregator<T>;
20
- public filter<S extends T>(predicate: TypeGuardIteratee<T, S>): Aggregator<S>;
21
- public filter(predicate: Iteratee<T, boolean>): Aggregator<T>
22
- {
23
- return new Aggregator(this._elements.filter(predicate));
24
- }
25
- public map<V>(iteratee: Iteratee<T, V>): Aggregator<V>
26
- {
27
- return new Aggregator(this._elements.map(iteratee));
28
- }
29
-
30
- public unique(): Aggregator<T>
31
- {
32
- return new Aggregator(this._elements.unique());
33
- }
34
-
35
- public groupBy<K extends PropertyKey>(iteratee: Iteratee<T, K>): AggregatedIterator<K, T>
36
- {
37
- return new AggregatedIterator(this._elements.map((element, index) =>
38
- {
39
- const key = iteratee(element, index);
40
-
41
- return [key, element] as [K, T];
42
- }));
43
- }
44
-
45
- public get [Symbol.toStringTag]() { return "Aggregator"; }
46
- }
@@ -1,56 +0,0 @@
1
- import AggregatedAsyncIterator from "./aggregated-async-iterator.js";
2
-
3
- import { SmartAsyncIterator } from "../iterators/index.js";
4
- import type {
5
- AsyncGeneratorFunction,
6
- GeneratorFunction,
7
- MaybeAsyncIterLike,
8
- MaybeAsyncIteratee,
9
- MaybeAsyncTypeGuardIteratee
10
-
11
- } from "../iterators/types.js";
12
-
13
- export default class AsyncAggregator<T>
14
- {
15
- protected _elements: SmartAsyncIterator<T>;
16
-
17
- public constructor(iterable: Iterable<T>);
18
- public constructor(iterable: AsyncIterable<T>);
19
- public constructor(iterator: Iterator<T>);
20
- public constructor(iterator: AsyncIterator<T>);
21
- public constructor(generatorFn: GeneratorFunction<T>);
22
- public constructor(generatorFn: AsyncGeneratorFunction<T>);
23
- public constructor(argument: MaybeAsyncIterLike<T>);
24
- public constructor(argument: MaybeAsyncIterLike<T>)
25
- {
26
- this._elements = new SmartAsyncIterator(argument);
27
- }
28
-
29
- public filter(predicate: MaybeAsyncIteratee<T, boolean>): AsyncAggregator<T>;
30
- public filter<S extends T>(predicate: MaybeAsyncTypeGuardIteratee<T, S>): AsyncAggregator<S>;
31
- public filter(predicate: MaybeAsyncIteratee<T, boolean>): AsyncAggregator<T>
32
- {
33
- return new AsyncAggregator(this._elements.filter(predicate));
34
- }
35
- public map<V>(iteratee: MaybeAsyncIteratee<T, V>): AsyncAggregator<V>
36
- {
37
- return new AsyncAggregator(this._elements.map(iteratee));
38
- }
39
-
40
- public unique(): AsyncAggregator<T>
41
- {
42
- return new AsyncAggregator(this._elements.unique());
43
- }
44
-
45
- public groupBy<K extends PropertyKey>(iteratee: MaybeAsyncIteratee<T, K>): AggregatedAsyncIterator<K, T>
46
- {
47
- return new AggregatedAsyncIterator(this._elements.map(async (element, index) =>
48
- {
49
- const key = await iteratee(element, index);
50
-
51
- return [key, element] as [K, T];
52
- }));
53
- }
54
-
55
- public get [Symbol.toStringTag]() { return "AsyncAggregator"; }
56
- }
@@ -1,39 +0,0 @@
1
- import { ReferenceException } from "./exceptions/index.js";
2
-
3
- export type Subscriber<A extends unknown[] = [], R = void> = (...args: A) => R;
4
-
5
- export default class Publisher<A extends unknown[] = [], R = void>
6
- {
7
- protected _subscribers: Subscriber<A, R>[];
8
-
9
- public constructor()
10
- {
11
- this._subscribers = [];
12
- }
13
-
14
- public subscribe(subscriber: Subscriber<A, R>): () => void
15
- {
16
- this._subscribers.push(subscriber);
17
-
18
- return () =>
19
- {
20
- const index = this._subscribers.indexOf(subscriber);
21
- if (index < 0)
22
- {
23
- throw new ReferenceException("Unable to unsubscribe the required subscriber. " +
24
- "The subscription was already unsubscribed.");
25
- }
26
-
27
- this._subscribers.splice(index, 1);
28
- };
29
- }
30
-
31
- public publish(...args: A): R[]
32
- {
33
- return this._subscribers
34
- .slice()
35
- .map((subscriber) => subscriber(...args));
36
- }
37
-
38
- public get [Symbol.toStringTag]() { return "Publisher"; }
39
- }