@oscarpalmer/timer 0.48.0 → 0.50.0
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/constants.d.mts +15 -15
- package/dist/constants.mjs +2 -1
- package/dist/global.d.mts +2 -1
- package/dist/global.mjs +2 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +134 -105
- package/dist/is.d.mts +5 -6
- package/dist/is.mjs +11 -11
- package/dist/misc.d.mts +8 -7
- package/dist/misc.mjs +5 -1
- package/dist/models.d.mts +15 -15
- package/dist/repeat.d.mts +2 -3
- package/dist/timer.d.mts +3 -3
- package/dist/timer.mjs +51 -38
- package/dist/wait.d.mts +2 -3
- package/dist/when.d.mts +3 -3
- package/dist/when.mjs +61 -54
- package/dist/work.d.mts +3 -4
- package/dist/work.mjs +8 -7
- package/package.json +5 -5
- package/src/constants.ts +6 -0
- package/src/global.ts +12 -1
- package/src/is.ts +20 -12
- package/src/misc.ts +15 -0
- package/src/models.ts +9 -4
- package/src/repeat.ts +4 -0
- package/src/timer.ts +86 -43
- package/src/wait.ts +4 -0
- package/src/when.ts +113 -66
- package/src/work.ts +15 -9
package/src/timer.ts
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {WORK_CONTINUE, WORK_PAUSE, WORK_RESTART, WORK_START, WORK_STOP} from './constants';
|
|
1
|
+
import {SYMBOL, WORK_CONTINUE, WORK_PAUSE, WORK_RESTART, WORK_START, WORK_STOP} from './constants';
|
|
3
2
|
import type {Timer, TimerName, TimerOptions, TimerState} from './models';
|
|
4
3
|
import {work} from './work';
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
// #region Types
|
|
6
|
+
|
|
7
|
+
type InternalTimer = {
|
|
8
|
+
[SYMBOL]: TimerState;
|
|
9
|
+
} & Timer;
|
|
10
|
+
|
|
11
|
+
// #endregion
|
|
12
|
+
|
|
13
|
+
// #region Instances
|
|
14
|
+
|
|
15
|
+
function Timer(
|
|
16
|
+
this: any,
|
|
7
17
|
name: TimerName,
|
|
8
|
-
|
|
18
|
+
state: Pick<TimerState, 'callback' | 'trace'>,
|
|
9
19
|
options: TimerOptions,
|
|
10
20
|
start: boolean,
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
...
|
|
21
|
+
) {
|
|
22
|
+
this[SYMBOL] = {
|
|
23
|
+
...state,
|
|
14
24
|
name,
|
|
15
25
|
options,
|
|
16
26
|
active: false,
|
|
@@ -23,43 +33,76 @@ export function createTimer(
|
|
|
23
33
|
total: 0,
|
|
24
34
|
};
|
|
25
35
|
|
|
26
|
-
const instance = {
|
|
27
|
-
continue: () => work(WORK_CONTINUE, state),
|
|
28
|
-
destroy: noop,
|
|
29
|
-
pause: () => work(WORK_PAUSE, state),
|
|
30
|
-
restart: () => work(WORK_RESTART, state),
|
|
31
|
-
start: () => work(WORK_START, state),
|
|
32
|
-
stop: () => work(WORK_STOP, state),
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
Object.defineProperties(instance, {
|
|
36
|
-
$timer: {
|
|
37
|
-
enumerable: false,
|
|
38
|
-
value: name,
|
|
39
|
-
},
|
|
40
|
-
active: {
|
|
41
|
-
enumerable: true,
|
|
42
|
-
get: () => state.active && !state.paused,
|
|
43
|
-
},
|
|
44
|
-
destroyed: {
|
|
45
|
-
enumerable: true,
|
|
46
|
-
value: false,
|
|
47
|
-
},
|
|
48
|
-
paused: {
|
|
49
|
-
enumerable: true,
|
|
50
|
-
get: () => state.paused,
|
|
51
|
-
},
|
|
52
|
-
trace: {
|
|
53
|
-
enumerable: true,
|
|
54
|
-
get: () => ((globalThis._oscarpalmer_timer_debug ?? false) ? state.trace : undefined),
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
state.timer = Object.freeze(instance) as Timer;
|
|
59
|
-
|
|
60
36
|
if (start) {
|
|
61
|
-
|
|
37
|
+
startTimer.call(this);
|
|
62
38
|
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Timer.prototype.continue = continueTimer;
|
|
42
|
+
Timer.prototype.pause = pauseTimer;
|
|
43
|
+
Timer.prototype.restart = restartTimer;
|
|
44
|
+
Timer.prototype.start = startTimer;
|
|
45
|
+
Timer.prototype.stop = stopTimer;
|
|
46
|
+
|
|
47
|
+
Object.defineProperties(Timer.prototype, {
|
|
48
|
+
active: {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: getTimerActive,
|
|
51
|
+
},
|
|
52
|
+
paused: {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
get: getTimerPaused,
|
|
55
|
+
},
|
|
56
|
+
trace: {
|
|
57
|
+
enumerable: true,
|
|
58
|
+
get: getTimerTrace,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// #endregion
|
|
63
|
+
|
|
64
|
+
// #region Functions
|
|
65
|
+
|
|
66
|
+
function continueTimer(this: InternalTimer): Timer {
|
|
67
|
+
return work(WORK_CONTINUE, this[SYMBOL]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function createTimer(
|
|
71
|
+
name: TimerName,
|
|
72
|
+
state: Pick<TimerState, 'callback' | 'trace'>,
|
|
73
|
+
options: TimerOptions,
|
|
74
|
+
start: boolean,
|
|
75
|
+
): Timer {
|
|
76
|
+
// @ts-expect-error All good, no worries :-)
|
|
77
|
+
return new Timer(name, state, options, start);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function getTimerActive(this: InternalTimer): boolean {
|
|
81
|
+
return this[SYMBOL].active && !this[SYMBOL].paused;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function getTimerPaused(this: InternalTimer): boolean {
|
|
85
|
+
return this[SYMBOL].paused;
|
|
86
|
+
}
|
|
63
87
|
|
|
64
|
-
|
|
88
|
+
function getTimerTrace(this: InternalTimer): string | undefined {
|
|
89
|
+
return (globalThis._oscarpalmer_timer_debug ?? false) ? this[SYMBOL].trace : undefined;
|
|
65
90
|
}
|
|
91
|
+
|
|
92
|
+
function pauseTimer(this: InternalTimer): Timer {
|
|
93
|
+
return work(WORK_PAUSE, this[SYMBOL]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function restartTimer(this: InternalTimer): Timer {
|
|
97
|
+
return work(WORK_RESTART, this[SYMBOL]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function startTimer(this: InternalTimer): Timer {
|
|
101
|
+
return work(WORK_START, this[SYMBOL]);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function stopTimer(this: InternalTimer): Timer {
|
|
105
|
+
return work(WORK_STOP, this[SYMBOL]);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// #endregion
|
package/src/wait.ts
CHANGED
|
@@ -4,6 +4,8 @@ import './global';
|
|
|
4
4
|
import {type Timer, TimerTrace} from './models';
|
|
5
5
|
import {createTimer} from './timer';
|
|
6
6
|
|
|
7
|
+
// #region Functions
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* Create a waiting timer
|
|
9
11
|
*
|
|
@@ -28,3 +30,5 @@ export function wait(callback: () => void, time?: number): Timer {
|
|
|
28
30
|
true,
|
|
29
31
|
);
|
|
30
32
|
}
|
|
33
|
+
|
|
34
|
+
// #endregion
|
package/src/when.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
MESSAGE_STARTED,
|
|
3
|
+
SYMBOL,
|
|
4
|
+
TYPE_WHEN,
|
|
5
|
+
WORK_CONTINUE,
|
|
6
|
+
WORK_PAUSE,
|
|
7
|
+
WORK_STOP,
|
|
8
|
+
} from './constants';
|
|
4
9
|
import './global';
|
|
10
|
+
import {getValidNumber, getValidTimeout} from './misc';
|
|
5
11
|
import {
|
|
6
12
|
TimerTrace,
|
|
7
13
|
type When,
|
|
@@ -11,6 +17,95 @@ import {
|
|
|
11
17
|
} from './models';
|
|
12
18
|
import {createTimer} from './timer';
|
|
13
19
|
|
|
20
|
+
// #region Types
|
|
21
|
+
|
|
22
|
+
type InternalWhen = {
|
|
23
|
+
[SYMBOL]: WhenState;
|
|
24
|
+
} & When;
|
|
25
|
+
|
|
26
|
+
// #endregion
|
|
27
|
+
|
|
28
|
+
// #region Instances
|
|
29
|
+
|
|
30
|
+
function When(this: any, condition: () => boolean, options: WhenOptions) {
|
|
31
|
+
const state: WhenState = {
|
|
32
|
+
name: TYPE_WHEN,
|
|
33
|
+
promise: undefined as never,
|
|
34
|
+
result: false,
|
|
35
|
+
started: false,
|
|
36
|
+
timer: undefined as never,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
this[SYMBOL] = state;
|
|
40
|
+
|
|
41
|
+
state.promise = new Promise<void>((resolve, reject) => {
|
|
42
|
+
state.resolver = resolve;
|
|
43
|
+
state.rejecter = reject;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
state.timer = createTimer(
|
|
47
|
+
TYPE_WHEN,
|
|
48
|
+
{
|
|
49
|
+
callback: () => onCallback(condition, state),
|
|
50
|
+
trace: new TimerTrace().stack,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
...options,
|
|
54
|
+
onAfter: () => onAfter(state),
|
|
55
|
+
onError: () => state.rejecter?.(),
|
|
56
|
+
},
|
|
57
|
+
false,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
When.prototype.continue = continueWhen;
|
|
62
|
+
When.prototype.pause = pauseWhen;
|
|
63
|
+
When.prototype.start = startWhen;
|
|
64
|
+
When.prototype.stop = stopWhen;
|
|
65
|
+
|
|
66
|
+
Object.defineProperties(When.prototype, {
|
|
67
|
+
active: {
|
|
68
|
+
get: getWhenActive,
|
|
69
|
+
},
|
|
70
|
+
paused: {
|
|
71
|
+
get: getWhenPaused,
|
|
72
|
+
},
|
|
73
|
+
trace: {
|
|
74
|
+
get: getWhenTrace,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// #endregion
|
|
79
|
+
|
|
80
|
+
// #region Functions
|
|
81
|
+
|
|
82
|
+
function continueWhen(this: InternalWhen): When {
|
|
83
|
+
return onWhen(WORK_CONTINUE, this, this[SYMBOL]);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function getWhenOptions(input: unknown): WhenOptions {
|
|
87
|
+
const options =
|
|
88
|
+
typeof input === 'object' && input !== null ? (input as Partial<WhenOptions>) : {};
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
count: getValidNumber(options?.count),
|
|
92
|
+
interval: getValidNumber(options?.interval),
|
|
93
|
+
timeout: getValidTimeout(options?.timeout),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getWhenActive(this: InternalWhen): boolean {
|
|
98
|
+
return this[SYMBOL].timer.active;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getWhenPaused(this: InternalWhen): boolean {
|
|
102
|
+
return this[SYMBOL].timer.paused;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function getWhenTrace(this: InternalWhen): string | undefined {
|
|
106
|
+
return (globalThis._oscarpalmer_timer_debug ?? false) ? this[SYMBOL].timer?.trace : undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
14
109
|
function onAfter(state: WhenState): void {
|
|
15
110
|
if (state.result) {
|
|
16
111
|
state.resolver?.();
|
|
@@ -37,7 +132,13 @@ function onWhen(type: WorkHandlerType, instance: When, state: WhenState): When {
|
|
|
37
132
|
return instance;
|
|
38
133
|
}
|
|
39
134
|
|
|
40
|
-
function
|
|
135
|
+
function pauseWhen(this: InternalWhen): When {
|
|
136
|
+
return onWhen(WORK_PAUSE, this, this[SYMBOL]);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function startWhen(this: InternalWhen, resolve?: (() => void) | null): Promise<void> {
|
|
140
|
+
const state = this[SYMBOL];
|
|
141
|
+
|
|
41
142
|
if (state.started) {
|
|
42
143
|
throw new Error(MESSAGE_STARTED);
|
|
43
144
|
}
|
|
@@ -49,6 +150,10 @@ function startWhen(state: WhenState, resolve?: (() => void) | null): Promise<voi
|
|
|
49
150
|
return state.promise.then(resolve);
|
|
50
151
|
}
|
|
51
152
|
|
|
153
|
+
function stopWhen(this: InternalWhen): When {
|
|
154
|
+
return onWhen(WORK_STOP, this, this[SYMBOL]);
|
|
155
|
+
}
|
|
156
|
+
|
|
52
157
|
/**
|
|
53
158
|
* Create a conditional timer
|
|
54
159
|
* @param condition Condition to check
|
|
@@ -56,66 +161,8 @@ function startWhen(state: WhenState, resolve?: (() => void) | null): Promise<voi
|
|
|
56
161
|
* @returns Timer instance
|
|
57
162
|
*/
|
|
58
163
|
export function when(condition: () => boolean, options?: Partial<WhenOptions>): When {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
result: false,
|
|
62
|
-
started: false,
|
|
63
|
-
timer: undefined as never,
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
let instance: When;
|
|
67
|
-
|
|
68
|
-
state.promise = new Promise<void>((resolve, reject) => {
|
|
69
|
-
state.resolver = resolve;
|
|
70
|
-
state.rejecter = reject;
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
state.timer = createTimer(
|
|
74
|
-
TYPE_WHEN,
|
|
75
|
-
{
|
|
76
|
-
callback: () => onCallback(condition, state),
|
|
77
|
-
trace: new TimerTrace().stack,
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
onAfter: () => onAfter(state),
|
|
81
|
-
onError: () => state.rejecter?.(),
|
|
82
|
-
count: getValidNumber(options?.count),
|
|
83
|
-
interval: getValidNumber(options?.interval),
|
|
84
|
-
timeout: getValidTimeout(options?.timeout),
|
|
85
|
-
},
|
|
86
|
-
false,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
instance = {
|
|
90
|
-
continue: () => onWhen(WORK_CONTINUE, instance, state),
|
|
91
|
-
destroy: noop,
|
|
92
|
-
pause: () => onWhen(WORK_PAUSE, instance, state),
|
|
93
|
-
start: (resolve: never) => startWhen(state, resolve),
|
|
94
|
-
stop: () => onWhen(WORK_STOP, instance, state),
|
|
95
|
-
} as When;
|
|
96
|
-
|
|
97
|
-
Object.defineProperties(instance, {
|
|
98
|
-
$timer: {
|
|
99
|
-
enumerable: false,
|
|
100
|
-
value: TYPE_WHEN,
|
|
101
|
-
},
|
|
102
|
-
active: {
|
|
103
|
-
enumerable: true,
|
|
104
|
-
get: () => state.timer.active,
|
|
105
|
-
},
|
|
106
|
-
destroyed: {
|
|
107
|
-
enumerable: true,
|
|
108
|
-
value: false,
|
|
109
|
-
},
|
|
110
|
-
paused: {
|
|
111
|
-
enumerable: true,
|
|
112
|
-
get: () => state.timer.paused,
|
|
113
|
-
},
|
|
114
|
-
trace: {
|
|
115
|
-
enumerable: true,
|
|
116
|
-
get: () => ((globalThis._oscarpalmer_timer_debug ?? false) ? state.timer?.trace : undefined),
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
return Object.freeze(instance) as When;
|
|
164
|
+
// @ts-expect-error All good, no worries :-)
|
|
165
|
+
return new When(condition, getWhenOptions(options));
|
|
121
166
|
}
|
|
167
|
+
|
|
168
|
+
// #endregion
|
package/src/work.ts
CHANGED
|
@@ -7,13 +7,15 @@ import {
|
|
|
7
7
|
WORK_START,
|
|
8
8
|
WORK_STOP,
|
|
9
9
|
} from './constants';
|
|
10
|
-
import {updateStates} from './misc';
|
|
10
|
+
import {startTimer, stopTimer, updateStates} from './misc';
|
|
11
11
|
import type {Timer, TimerState, WorkHandlerType} from './models';
|
|
12
12
|
|
|
13
|
+
// #region Functions
|
|
14
|
+
|
|
13
15
|
function finish(state: TimerState, success: boolean): void {
|
|
14
16
|
updateStates(state);
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
stopTimer(state.frame as never);
|
|
17
19
|
|
|
18
20
|
state.active = false;
|
|
19
21
|
state.elapsed = 0;
|
|
@@ -34,14 +36,16 @@ function ignore(type: WorkHandlerType, state: TimerState): boolean {
|
|
|
34
36
|
return state.active && (type === WORK_CONTINUE || type === WORK_START);
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
function run(state: TimerState): (
|
|
38
|
-
let last:
|
|
39
|
+
function run(state: TimerState): () => void {
|
|
40
|
+
let last: number | undefined;
|
|
39
41
|
|
|
40
|
-
return function step(
|
|
42
|
+
return function step(): void {
|
|
41
43
|
if (!state.active) {
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
44
46
|
|
|
47
|
+
const now = performance.now();
|
|
48
|
+
|
|
45
49
|
last ??= now;
|
|
46
50
|
|
|
47
51
|
const difference = now - last;
|
|
@@ -77,7 +81,7 @@ function run(state: TimerState): (now: DOMHighResTimeStamp) => void {
|
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
|
|
80
|
-
state.frame =
|
|
84
|
+
state.frame = startTimer(step);
|
|
81
85
|
};
|
|
82
86
|
}
|
|
83
87
|
|
|
@@ -92,7 +96,7 @@ function setState(type: WorkHandlerType, state: TimerState): void {
|
|
|
92
96
|
export function stop(state: TimerState): Timer {
|
|
93
97
|
updateStates(state);
|
|
94
98
|
|
|
95
|
-
|
|
99
|
+
stopTimer(state.frame as never);
|
|
96
100
|
|
|
97
101
|
state.options.onAfter?.(false);
|
|
98
102
|
|
|
@@ -115,7 +119,7 @@ export function work(type: WorkHandlerType, state: TimerState, hide?: boolean):
|
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
if (type === WORK_PAUSE || type === WORK_RESTART) {
|
|
118
|
-
|
|
122
|
+
stopTimer(state.frame as never);
|
|
119
123
|
|
|
120
124
|
state.frame = undefined;
|
|
121
125
|
}
|
|
@@ -131,7 +135,9 @@ export function work(type: WorkHandlerType, state: TimerState, hide?: boolean):
|
|
|
131
135
|
|
|
132
136
|
const runner = run(state);
|
|
133
137
|
|
|
134
|
-
state.frame =
|
|
138
|
+
state.frame = startTimer(runner);
|
|
135
139
|
|
|
136
140
|
return state.timer;
|
|
137
141
|
}
|
|
142
|
+
|
|
143
|
+
// #endregion
|