@byloth/core 2.0.0-rc.7 → 2.0.0-rc.8
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.js +822 -609
- package/dist/core.js.map +1 -1
- package/dist/core.umd.cjs +2 -2
- package/dist/core.umd.cjs.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +9 -3
- package/src/models/callbacks/callable-object.ts +23 -0
- package/src/models/callbacks/index.ts +5 -0
- package/src/models/{publisher.ts → callbacks/publisher.ts} +9 -10
- package/src/models/callbacks/switchable-callback.ts +104 -0
- package/src/models/callbacks/types.ts +1 -0
- package/src/models/index.ts +3 -4
- package/src/models/json/types.ts +2 -4
- package/src/models/promises/index.ts +2 -1
- package/src/models/promises/long-running-task.ts +294 -0
- package/src/models/promises/types.ts +2 -0
- package/src/models/timers/clock.ts +6 -8
- package/src/models/timers/countdown.ts +7 -10
- package/src/models/types.ts +3 -1
- package/src/utils/async.ts +7 -2
- package/src/utils/index.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byloth/core",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.8",
|
|
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",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
},
|
|
48
48
|
"types": "./src/index.ts",
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@byloth/eslint-config-typescript": "^3.0.
|
|
51
|
-
"@types/node": "^22.
|
|
52
|
-
"husky": "^9.1.
|
|
53
|
-
"typescript": "^5.
|
|
50
|
+
"@byloth/eslint-config-typescript": "^3.0.3",
|
|
51
|
+
"@types/node": "^22.10.1",
|
|
52
|
+
"husky": "^9.1.7",
|
|
53
|
+
"typescript": "^5.7.2",
|
|
54
54
|
"vite": "^5.4.11"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const VERSION = "2.0.0-rc.
|
|
1
|
+
export const VERSION = "2.0.0-rc.8";
|
|
2
2
|
|
|
3
3
|
export type { Constructor, Interval, Timeout } from "./core/types.js";
|
|
4
4
|
|
|
@@ -7,6 +7,7 @@ export { isBrowser, isNode, isWebWorker } from "./helpers.js";
|
|
|
7
7
|
export {
|
|
8
8
|
AggregatedIterator,
|
|
9
9
|
AggregatedAsyncIterator,
|
|
10
|
+
CallableObject,
|
|
10
11
|
Clock,
|
|
11
12
|
Countdown,
|
|
12
13
|
DeferredPromise,
|
|
@@ -18,6 +19,7 @@ export {
|
|
|
18
19
|
GameLoop,
|
|
19
20
|
JSONStorage,
|
|
20
21
|
KeyException,
|
|
22
|
+
LongRunningTask,
|
|
21
23
|
NotImplementedException,
|
|
22
24
|
NetworkException,
|
|
23
25
|
PermissionException,
|
|
@@ -29,6 +31,7 @@ export {
|
|
|
29
31
|
SmartIterator,
|
|
30
32
|
SmartAsyncIterator,
|
|
31
33
|
SmartPromise,
|
|
34
|
+
SwitchableCallback,
|
|
32
35
|
Thenable,
|
|
33
36
|
TimeoutException,
|
|
34
37
|
TimedPromise,
|
|
@@ -40,6 +43,7 @@ export {
|
|
|
40
43
|
export type {
|
|
41
44
|
AsyncGeneratorFunction,
|
|
42
45
|
AsyncIteratorLike,
|
|
46
|
+
Callback,
|
|
43
47
|
FulfilledHandler,
|
|
44
48
|
GeneratorFunction,
|
|
45
49
|
Iteratee,
|
|
@@ -50,12 +54,14 @@ export type {
|
|
|
50
54
|
KeyedIteratee,
|
|
51
55
|
KeyedReducer,
|
|
52
56
|
KeyedTypeGuardIteratee,
|
|
57
|
+
LongRunningTaskOptions,
|
|
53
58
|
MaybeAsyncKeyedIteratee,
|
|
54
59
|
MaybeAsyncKeyedReducer,
|
|
55
60
|
MaybeAsyncKeyedTypeGuardIteratee,
|
|
56
|
-
|
|
61
|
+
MaybeAsyncGeneratorFunction,
|
|
57
62
|
MaybeAsyncIteratee,
|
|
58
63
|
MaybeAsyncIteratorLike,
|
|
64
|
+
MaybeAsyncReducer,
|
|
59
65
|
MaybeAsyncTypeGuardIteratee,
|
|
60
66
|
MaybePromise,
|
|
61
67
|
PromiseExecutor,
|
|
@@ -63,7 +69,6 @@ export type {
|
|
|
63
69
|
PromiseResolver,
|
|
64
70
|
Reducer,
|
|
65
71
|
RejectedHandler,
|
|
66
|
-
Subscriber,
|
|
67
72
|
TypeGuardIteratee
|
|
68
73
|
|
|
69
74
|
} from "./models/types.js";
|
|
@@ -87,6 +92,7 @@ export {
|
|
|
87
92
|
shuffle,
|
|
88
93
|
sum,
|
|
89
94
|
unique,
|
|
95
|
+
yieldToEventLoop,
|
|
90
96
|
zip
|
|
91
97
|
|
|
92
98
|
} from "./utils/index.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
import type { Callback } from "./types.js";
|
|
4
|
+
|
|
5
|
+
export const SmartFunction = (Function as unknown) as
|
|
6
|
+
new<T extends Callback<any[], any> = () => void>(...args: string[]) =>
|
|
7
|
+
(...args: Parameters<T>) => ReturnType<T>;
|
|
8
|
+
|
|
9
|
+
export default abstract class CallableObject<T extends Callback<any[], any> = () => void>
|
|
10
|
+
extends SmartFunction<T>
|
|
11
|
+
{
|
|
12
|
+
public constructor()
|
|
13
|
+
{
|
|
14
|
+
super(`return this.invoke(...arguments);`);
|
|
15
|
+
|
|
16
|
+
const self = this.bind(this);
|
|
17
|
+
Object.setPrototypeOf(this, self);
|
|
18
|
+
|
|
19
|
+
return self as this;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public abstract invoke(...args: Parameters<T>): ReturnType<T>;
|
|
23
|
+
}
|
|
@@ -1,28 +1,27 @@
|
|
|
1
|
-
import { ReferenceException } from "
|
|
1
|
+
import { ReferenceException } from "../exceptions/index.js";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import type { Callback } from "./types.js";
|
|
4
4
|
|
|
5
|
-
// eslint-disable-next-line @typescript-eslint/no-
|
|
6
|
-
export default class Publisher<T extends { [K in keyof T]: [
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
+
export default class Publisher<T extends { [K in keyof T]: Callback<any[], any> } = Record<string, Callback>>
|
|
7
7
|
{
|
|
8
|
-
protected _subscribers: Map<keyof T,
|
|
8
|
+
protected _subscribers: Map<keyof T, Callback<unknown[], unknown>[]>;
|
|
9
9
|
|
|
10
10
|
public constructor()
|
|
11
11
|
{
|
|
12
12
|
this._subscribers = new Map();
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
public subscribe<K extends keyof T,
|
|
16
|
-
: () => void
|
|
15
|
+
public subscribe<K extends keyof T, S extends T[K]>(event: K, subscriber: S): () => void
|
|
17
16
|
{
|
|
18
17
|
if (!(this._subscribers.has(event))) { this._subscribers.set(event, []); }
|
|
19
18
|
|
|
20
19
|
const subscribers = this._subscribers.get(event)!;
|
|
21
|
-
subscribers.push(subscriber
|
|
20
|
+
subscribers.push(subscriber);
|
|
22
21
|
|
|
23
22
|
return () =>
|
|
24
23
|
{
|
|
25
|
-
const index = subscribers.indexOf(subscriber
|
|
24
|
+
const index = subscribers.indexOf(subscriber);
|
|
26
25
|
if (index < 0)
|
|
27
26
|
{
|
|
28
27
|
throw new ReferenceException("Unable to unsubscribe the required subscriber. " +
|
|
@@ -33,7 +32,7 @@ export default class Publisher<T extends { [K in keyof T]: [unknown[], unknown]
|
|
|
33
32
|
};
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
public publish<K extends keyof T, A extends T[K]
|
|
35
|
+
public publish<K extends keyof T, A extends Parameters<T[K]>, R extends ReturnType<T[K]>>(event: K, ...args: A): R[]
|
|
37
36
|
{
|
|
38
37
|
const subscribers = this._subscribers.get(event);
|
|
39
38
|
if (!(subscribers)) { return []; }
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { KeyException, NotImplementedException, RuntimeException } from "../exceptions/index.js";
|
|
2
|
+
|
|
3
|
+
import CallableObject from "./callable-object.js";
|
|
4
|
+
import type { Callback } from "./types.js";
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
export default class SwitchableCallback<T extends Callback<any[], any> = Callback> extends CallableObject<T>
|
|
8
|
+
{
|
|
9
|
+
protected _callback: T;
|
|
10
|
+
protected _callbacks: Map<string, T>;
|
|
11
|
+
|
|
12
|
+
protected _isEnabled: boolean;
|
|
13
|
+
public get isEnabled(): boolean { return this._isEnabled; }
|
|
14
|
+
|
|
15
|
+
protected _key: string;
|
|
16
|
+
public get key(): string { return this._key; }
|
|
17
|
+
|
|
18
|
+
public readonly invoke: (...args: Parameters<T>) => ReturnType<T>;
|
|
19
|
+
|
|
20
|
+
public constructor()
|
|
21
|
+
{
|
|
22
|
+
const _default = () =>
|
|
23
|
+
{
|
|
24
|
+
throw new NotImplementedException(
|
|
25
|
+
"The `SwitchableCallback` has no callback defined yet. " +
|
|
26
|
+
"Did you forget to call the `register` method?"
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
super();
|
|
31
|
+
|
|
32
|
+
this._callback = ((_default) as unknown) as T;
|
|
33
|
+
this._callbacks = new Map<string, T>();
|
|
34
|
+
|
|
35
|
+
this._isEnabled = false;
|
|
36
|
+
this._key = "";
|
|
37
|
+
|
|
38
|
+
this.invoke = (...args: Parameters<T>): ReturnType<T> => this._callback(...args);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public enable(): void
|
|
42
|
+
{
|
|
43
|
+
if (!(this._key))
|
|
44
|
+
{
|
|
45
|
+
throw new KeyException(
|
|
46
|
+
"The `SwitchableCallback` has no callback defined yet. " +
|
|
47
|
+
"Did you forget to call the `register` method?"
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
if (this._isEnabled)
|
|
51
|
+
{
|
|
52
|
+
throw new RuntimeException("The `SwitchableCallback` is already enabled.");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this._callback = this._callbacks.get(this._key)!;
|
|
56
|
+
this._isEnabled = true;
|
|
57
|
+
}
|
|
58
|
+
public disable(): void
|
|
59
|
+
{
|
|
60
|
+
if (!(this._isEnabled))
|
|
61
|
+
{
|
|
62
|
+
throw new RuntimeException("The `SwitchableCallback` is already disabled.");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
66
|
+
this._callback = (() => { }) as T;
|
|
67
|
+
this._isEnabled = false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public register(key: string, callback: T): void
|
|
71
|
+
{
|
|
72
|
+
if (this._callbacks.size === 0)
|
|
73
|
+
{
|
|
74
|
+
this._key = key;
|
|
75
|
+
this._callback = callback;
|
|
76
|
+
}
|
|
77
|
+
else if (this._callbacks.has(key))
|
|
78
|
+
{
|
|
79
|
+
throw new KeyException(`The key '${key}' has already been used for another callback.`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this._callbacks.set(key, callback);
|
|
83
|
+
}
|
|
84
|
+
public unregister(key: string): void
|
|
85
|
+
{
|
|
86
|
+
if (!(this._callbacks.has(key)))
|
|
87
|
+
{
|
|
88
|
+
throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this._callbacks.delete(key);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public switch(key: string): void
|
|
95
|
+
{
|
|
96
|
+
if (!(this._callbacks.has(key)))
|
|
97
|
+
{
|
|
98
|
+
throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this._key = key;
|
|
102
|
+
this._callback = this._callbacks.get(key)!;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Callback<A extends unknown[] = [], R = void> = (...args: A) => R;
|
package/src/models/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export {
|
|
|
5
5
|
|
|
6
6
|
} from "./aggregators/index.js";
|
|
7
7
|
|
|
8
|
+
export { CallableObject, Publisher, SmartFunction, SwitchableCallback } from "./callbacks/index.js";
|
|
8
9
|
export {
|
|
9
10
|
Exception,
|
|
10
11
|
FatalErrorException,
|
|
@@ -28,10 +29,8 @@ import GameLoop from "./game-loop.js";
|
|
|
28
29
|
|
|
29
30
|
export { SmartIterator, SmartAsyncIterator } from "./iterators/index.js";
|
|
30
31
|
export { JSONStorage } from "./json/index.js";
|
|
31
|
-
export { DeferredPromise, SmartPromise, Thenable, TimedPromise } from "./promises/index.js";
|
|
32
|
-
|
|
33
|
-
import Publisher from "./publisher.js";
|
|
32
|
+
export { DeferredPromise, LongRunningTask, SmartPromise, Thenable, TimedPromise } from "./promises/index.js";
|
|
34
33
|
|
|
35
34
|
export { Clock, Countdown } from "./timers/index.js";
|
|
36
35
|
|
|
37
|
-
export { GameLoop
|
|
36
|
+
export { GameLoop };
|
package/src/models/json/types.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export type JSONArray = JSONValue[];
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
// @ts-expect-error - This is a circular reference to itself.
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
|
|
4
|
+
export interface JSONObject { [key: string]: JSONValue }
|
|
7
5
|
export type JSONValue = boolean | number | string | null | JSONObject | JSONArray;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import DeferredPromise from "./deferred-promise.js";
|
|
2
|
+
import LongRunningTask from "./long-running-task.js";
|
|
2
3
|
import SmartPromise from "./smart-promise.js";
|
|
3
4
|
import Thenable from "./thenable.js";
|
|
4
5
|
import TimedPromise from "./timed-promise.js";
|
|
5
6
|
|
|
6
|
-
export { DeferredPromise, SmartPromise, Thenable, TimedPromise };
|
|
7
|
+
export { DeferredPromise, LongRunningTask, SmartPromise, Thenable, TimedPromise };
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { yieldToEventLoop } from "../../utils/async.js";
|
|
2
|
+
|
|
3
|
+
import Publisher from "../callbacks/publisher.js";
|
|
4
|
+
import { RuntimeException } from "../exceptions/index.js";
|
|
5
|
+
|
|
6
|
+
import type { MaybeAsyncGeneratorFunction } from "../iterators/types.js";
|
|
7
|
+
import type { FulfilledHandler, PromiseExecutor, RejectedHandler } from "./types.js";
|
|
8
|
+
|
|
9
|
+
export interface LongRunningTaskOptions
|
|
10
|
+
{
|
|
11
|
+
ignoreErrors?: boolean;
|
|
12
|
+
stepIncrement?: number;
|
|
13
|
+
totalSteps?: number | null;
|
|
14
|
+
trackProgress?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default class LongRunningTask<T = void> implements Promise<T>
|
|
18
|
+
{
|
|
19
|
+
private static get _DefaultOptions(): Required<LongRunningTaskOptions>
|
|
20
|
+
{
|
|
21
|
+
return {
|
|
22
|
+
ignoreErrors: false,
|
|
23
|
+
stepIncrement: 1,
|
|
24
|
+
totalSteps: null,
|
|
25
|
+
trackProgress: false
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
protected _startTime: number;
|
|
30
|
+
protected _estimatedTime: number;
|
|
31
|
+
protected _endTime?: number;
|
|
32
|
+
|
|
33
|
+
protected _currentStep: number;
|
|
34
|
+
protected _percentage: number;
|
|
35
|
+
|
|
36
|
+
protected _isRunning: boolean;
|
|
37
|
+
protected _hasCompleted: boolean;
|
|
38
|
+
protected _hasFailed: boolean;
|
|
39
|
+
|
|
40
|
+
protected _promise: Promise<T>;
|
|
41
|
+
protected _publisher?: Publisher;
|
|
42
|
+
|
|
43
|
+
public constructor(executor: MaybeAsyncGeneratorFunction<undefined, T>, options?: LongRunningTaskOptions);
|
|
44
|
+
public constructor(executor: MaybeAsyncGeneratorFunction<number, T>, options?: LongRunningTaskOptions);
|
|
45
|
+
public constructor(executor: MaybeAsyncGeneratorFunction<number | undefined, T>, options?: LongRunningTaskOptions)
|
|
46
|
+
{
|
|
47
|
+
this._startTime = 0;
|
|
48
|
+
this._estimatedTime = 0;
|
|
49
|
+
|
|
50
|
+
this._currentStep = 0;
|
|
51
|
+
this._percentage = 0;
|
|
52
|
+
|
|
53
|
+
this._isRunning = true;
|
|
54
|
+
this._hasCompleted = false;
|
|
55
|
+
this._hasFailed = false;
|
|
56
|
+
|
|
57
|
+
const _onFulfilled = (result: T): T =>
|
|
58
|
+
{
|
|
59
|
+
this._estimatedTime = 0;
|
|
60
|
+
this._endTime = Date.now();
|
|
61
|
+
|
|
62
|
+
this._percentage = 100;
|
|
63
|
+
|
|
64
|
+
this._isRunning = false;
|
|
65
|
+
this._hasCompleted = true;
|
|
66
|
+
|
|
67
|
+
return result;
|
|
68
|
+
};
|
|
69
|
+
const _onRejected = (reason: unknown): never =>
|
|
70
|
+
{
|
|
71
|
+
this._endTime = Date.now();
|
|
72
|
+
|
|
73
|
+
this._isRunning = false;
|
|
74
|
+
this._hasFailed = true;
|
|
75
|
+
|
|
76
|
+
throw reason;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
let _executor: PromiseExecutor<T>;
|
|
80
|
+
|
|
81
|
+
options = { ...LongRunningTask._DefaultOptions, ...options };
|
|
82
|
+
if ((options.trackProgress))
|
|
83
|
+
{
|
|
84
|
+
let _trackProgress: (steps: number | undefined) => void;
|
|
85
|
+
|
|
86
|
+
this._publisher = new Publisher();
|
|
87
|
+
|
|
88
|
+
if (options.totalSteps)
|
|
89
|
+
{
|
|
90
|
+
if (options.stepIncrement)
|
|
91
|
+
{
|
|
92
|
+
_trackProgress = (steps: number | undefined) =>
|
|
93
|
+
{
|
|
94
|
+
if (steps) { this._currentStep += steps; }
|
|
95
|
+
else { this._currentStep += options.stepIncrement!; }
|
|
96
|
+
|
|
97
|
+
this._percentage = (this._currentStep / options.totalSteps!) * 100;
|
|
98
|
+
|
|
99
|
+
const elapsedTime = Date.now() - this._startTime;
|
|
100
|
+
const remainingSteps = options.totalSteps! - this._currentStep;
|
|
101
|
+
this._estimatedTime = (elapsedTime / this._currentStep) * remainingSteps;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
else
|
|
105
|
+
{
|
|
106
|
+
_trackProgress = (steps: number | undefined) =>
|
|
107
|
+
{
|
|
108
|
+
if (steps)
|
|
109
|
+
{
|
|
110
|
+
this._currentStep += steps;
|
|
111
|
+
this._percentage = (this._currentStep / options.totalSteps!) * 100;
|
|
112
|
+
|
|
113
|
+
const elapsedTime = Date.now() - this._startTime;
|
|
114
|
+
const remainingSteps = options.totalSteps! - this._currentStep;
|
|
115
|
+
this._estimatedTime = (elapsedTime / this._currentStep) * remainingSteps;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else if (options.stepIncrement)
|
|
121
|
+
{
|
|
122
|
+
_trackProgress = (steps: number | undefined) =>
|
|
123
|
+
{
|
|
124
|
+
if (steps) { this._currentStep += steps; }
|
|
125
|
+
else { this._currentStep += options.stepIncrement!; }
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
else
|
|
129
|
+
{
|
|
130
|
+
_trackProgress = (steps: number | undefined) =>
|
|
131
|
+
{
|
|
132
|
+
if (steps) { this._currentStep += steps; }
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (options.ignoreErrors)
|
|
137
|
+
{
|
|
138
|
+
_executor = async (resolve) =>
|
|
139
|
+
{
|
|
140
|
+
const generator = executor();
|
|
141
|
+
this._startTime = Date.now();
|
|
142
|
+
|
|
143
|
+
while (true)
|
|
144
|
+
{
|
|
145
|
+
try
|
|
146
|
+
{
|
|
147
|
+
const { done, value } = await generator.next();
|
|
148
|
+
|
|
149
|
+
if (done) { return resolve(value); }
|
|
150
|
+
else { _trackProgress(value); }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// eslint-disable-next-line no-console
|
|
154
|
+
catch (error) { console.error(error); }
|
|
155
|
+
|
|
156
|
+
this._publisher!.publish("progress");
|
|
157
|
+
|
|
158
|
+
await yieldToEventLoop();
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
else
|
|
163
|
+
{
|
|
164
|
+
_executor = async (resolve, reject) =>
|
|
165
|
+
{
|
|
166
|
+
try
|
|
167
|
+
{
|
|
168
|
+
const generator = executor();
|
|
169
|
+
this._startTime = Date.now();
|
|
170
|
+
|
|
171
|
+
while (true)
|
|
172
|
+
{
|
|
173
|
+
const { done, value } = await generator.next();
|
|
174
|
+
if (done) { return resolve(value); }
|
|
175
|
+
else { _trackProgress(value); }
|
|
176
|
+
|
|
177
|
+
this._publisher!.publish("progress");
|
|
178
|
+
|
|
179
|
+
await yieldToEventLoop();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (error) { reject(error); }
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else if (options.ignoreErrors)
|
|
187
|
+
{
|
|
188
|
+
_executor = async (resolve) =>
|
|
189
|
+
{
|
|
190
|
+
const generator = executor();
|
|
191
|
+
this._startTime = Date.now();
|
|
192
|
+
|
|
193
|
+
while (true)
|
|
194
|
+
{
|
|
195
|
+
try
|
|
196
|
+
{
|
|
197
|
+
const { done, value } = await generator.next();
|
|
198
|
+
if (done) { return resolve(value); }
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// eslint-disable-next-line no-console
|
|
202
|
+
catch (error) { console.error(error); }
|
|
203
|
+
|
|
204
|
+
await yieldToEventLoop();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
else
|
|
209
|
+
{
|
|
210
|
+
_executor = async (resolve, reject) =>
|
|
211
|
+
{
|
|
212
|
+
try
|
|
213
|
+
{
|
|
214
|
+
const generator = executor();
|
|
215
|
+
this._startTime = Date.now();
|
|
216
|
+
|
|
217
|
+
while (true)
|
|
218
|
+
{
|
|
219
|
+
const { done, value } = await generator.next();
|
|
220
|
+
if (done) { return resolve(value); }
|
|
221
|
+
|
|
222
|
+
await yieldToEventLoop();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch (error) { reject(error); }
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
this._promise = new Promise(_executor)
|
|
230
|
+
.then(_onFulfilled, _onRejected);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
public get startTime(): number { return this._startTime; }
|
|
234
|
+
public get elapsedTime(): number
|
|
235
|
+
{
|
|
236
|
+
if (this._isRunning) { return Date.now() - this._startTime; }
|
|
237
|
+
|
|
238
|
+
return this._endTime! - this._startTime;
|
|
239
|
+
}
|
|
240
|
+
public get estimatedTime(): number { return this._estimatedTime; }
|
|
241
|
+
public get endTime(): number
|
|
242
|
+
{
|
|
243
|
+
if (this._isRunning)
|
|
244
|
+
{
|
|
245
|
+
throw new RuntimeException("The task is still running and has no end time yet.");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return this._endTime!;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
public get currentStep(): number { return this._currentStep; }
|
|
252
|
+
public get percentage(): number { return this._percentage; }
|
|
253
|
+
|
|
254
|
+
public get isRunning(): boolean { return this._isRunning; }
|
|
255
|
+
public get hasCompleted(): boolean { return this._hasCompleted; }
|
|
256
|
+
public get hasFailed(): boolean { return this._hasFailed; }
|
|
257
|
+
|
|
258
|
+
public then(onFulfilled?: null): Promise<T>;
|
|
259
|
+
public then<F = T>(onFulfilled: FulfilledHandler<T, F>, onRejected?: null): Promise<F>;
|
|
260
|
+
public then<F = T, R = never>(onFulfilled: FulfilledHandler<T, F>, onRejected: RejectedHandler<unknown, R>)
|
|
261
|
+
: Promise<F | R>;
|
|
262
|
+
public then<F = T, R = never>(
|
|
263
|
+
onFulfilled?: FulfilledHandler<T, F> | null,
|
|
264
|
+
onRejected?: RejectedHandler<unknown, R> | null): Promise<F | R>
|
|
265
|
+
{
|
|
266
|
+
return this._promise.then(onFulfilled, onRejected);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
public catch(onRejected?: null): Promise<T>;
|
|
270
|
+
public catch<R = never>(onRejected: RejectedHandler<unknown, R>): Promise<T | R>;
|
|
271
|
+
public catch<R = never>(onRejected?: RejectedHandler<unknown, R> | null): Promise<T | R>
|
|
272
|
+
{
|
|
273
|
+
return this._promise.catch(onRejected);
|
|
274
|
+
}
|
|
275
|
+
public finally(onFinally?: (() => void) | null): Promise<T>
|
|
276
|
+
{
|
|
277
|
+
return this._promise.finally(onFinally);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
public onProgress(callback: () => void): () => void
|
|
281
|
+
{
|
|
282
|
+
if (!(this._publisher))
|
|
283
|
+
{
|
|
284
|
+
throw new RuntimeException(
|
|
285
|
+
"You cannot subscribe to progress events without enabling progress tracking. " +
|
|
286
|
+
"Did you forget to set the `trackProgress` option to `true` when creating the task?"
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return this._publisher.subscribe("progress", callback);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
public readonly [Symbol.toStringTag]: string = "LongRunningTask";
|
|
294
|
+
}
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import { TimeUnit } from "../../utils/date.js";
|
|
2
2
|
import { RangeException, RuntimeException } from "../exceptions/index.js";
|
|
3
3
|
|
|
4
|
+
import Publisher from "../callbacks/publisher.js";
|
|
4
5
|
import GameLoop from "../game-loop.js";
|
|
5
|
-
import Publisher from "../publisher.js";
|
|
6
6
|
|
|
7
|
-
interface
|
|
7
|
+
interface ClockEventMap
|
|
8
8
|
{
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
stop: [[], void];
|
|
13
|
-
tick: [[number], void];
|
|
9
|
+
start: () => void;
|
|
10
|
+
stop: () => void;
|
|
11
|
+
tick: (elapsedTime: number) => void;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
export default class Clock extends GameLoop
|
|
17
15
|
{
|
|
18
|
-
protected _publisher: Publisher<
|
|
16
|
+
protected _publisher: Publisher<ClockEventMap>;
|
|
19
17
|
|
|
20
18
|
public constructor(msIfNotBrowser: number = TimeUnit.Second)
|
|
21
19
|
{
|
|
@@ -3,24 +3,21 @@ import { TimeUnit } from "../../utils/date.js";
|
|
|
3
3
|
import { FatalErrorException, RangeException, RuntimeException } from "../exceptions/index.js";
|
|
4
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
8
|
|
|
9
|
-
interface
|
|
9
|
+
interface CountdownEventMap
|
|
10
10
|
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
tick: [[number], void];
|
|
16
|
-
expire: [[], void];
|
|
11
|
+
start: () => void;
|
|
12
|
+
stop: (reason: unknown) => void;
|
|
13
|
+
tick: (remainingTime: number) => void;
|
|
14
|
+
expire: () => void;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
export default class Countdown extends GameLoop
|
|
20
18
|
{
|
|
21
19
|
protected _deferrer?: DeferredPromise<void>;
|
|
22
|
-
|
|
23
|
-
protected _publisher: Publisher<CountdownEvents>;
|
|
20
|
+
protected _publisher: Publisher<CountdownEventMap>;
|
|
24
21
|
|
|
25
22
|
protected _duration: number;
|
|
26
23
|
public get duration(): number
|