@oscarpalmer/timer 0.19.0 → 0.21.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/src/timer.ts ADDED
@@ -0,0 +1,186 @@
1
+ import {milliseconds} from './constants';
2
+ import {getOptions, work} from './functions';
3
+ import type {
4
+ AnyCallback,
5
+ IndexedCallback,
6
+ RepeatOptions,
7
+ TimerOptions,
8
+ TimerState,
9
+ WaitOptions,
10
+ } from './models';
11
+
12
+ export abstract class BasicTimer<State> {
13
+ protected declare readonly $timer: string;
14
+ protected declare readonly state: State;
15
+
16
+ constructor(type: 'repeat' | 'wait' | 'when', state: State) {
17
+ this.$timer = type;
18
+ this.state = state;
19
+ }
20
+
21
+ /**
22
+ * Is the timer running?
23
+ */
24
+ abstract readonly active: boolean;
25
+
26
+ /**
27
+ * Is the timer paused?
28
+ */
29
+ abstract readonly paused: boolean;
30
+ }
31
+
32
+ /**
33
+ * A timer that can be started, stopped, and restarted as neeeded
34
+ */
35
+ export class Timer extends BasicTimer<TimerState> {
36
+ private declare readonly options: TimerOptions;
37
+
38
+ get active() {
39
+ return this.state.active;
40
+ }
41
+
42
+ get paused() {
43
+ return this.state.paused;
44
+ }
45
+
46
+ /**
47
+ * Gets the traced location of the timer
48
+ */
49
+ get trace() {
50
+ return globalThis._oscarpalmer_timer_debug ? this.state.trace : undefined;
51
+ }
52
+
53
+ constructor(
54
+ type: 'repeat' | 'wait',
55
+ state: TimerState,
56
+ options: TimerOptions,
57
+ ) {
58
+ super(type, state);
59
+
60
+ this.options = options;
61
+ }
62
+
63
+ /**
64
+ * Continues the timer _(if it was paused)_
65
+ */
66
+ continue(): Timer {
67
+ return work('continue', this, this.state, this.options);
68
+ }
69
+
70
+ /**
71
+ * Pauses the timer _(if it was running)_
72
+ */
73
+ pause(): Timer {
74
+ return work('pause', this, this.state, this.options);
75
+ }
76
+
77
+ /**
78
+ * Restarts the timer _(if it was running)_
79
+ */
80
+ restart(): Timer {
81
+ return work('restart', this, this.state, this.options);
82
+ }
83
+
84
+ /**
85
+ * Starts the timer _(if it was stopped)_
86
+ */
87
+ start(): Timer {
88
+ return work('start', this, this.state, this.options);
89
+ }
90
+
91
+ /**
92
+ * Stops the timer _(if it was running)_
93
+ */
94
+ stop(): Timer {
95
+ return work('stop', this, this.state, this.options);
96
+ }
97
+ }
98
+
99
+ class TimerTrace extends Error {
100
+ constructor() {
101
+ super();
102
+
103
+ this.name = 'TimerTrace';
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Creates a timer which:
109
+ * - calls a callback after a certain amount of time...
110
+ * - ... and repeats it a certain amount of times
111
+ * ---
112
+ * - `options.count` defaults to `Infinity`
113
+ * - `options.interval` defaults to `1000/60` _(1 frame)_
114
+ * - `options.timeout` defaults to `Infinity`
115
+ */
116
+ export function repeat(
117
+ callback: IndexedCallback,
118
+ options?: Partial<RepeatOptions>,
119
+ ): Timer {
120
+ return timer('repeat', callback, options ?? {}, true);
121
+ }
122
+
123
+ export function timer(
124
+ type: 'repeat' | 'wait',
125
+ callback: AnyCallback,
126
+ partial: Partial<TimerOptions>,
127
+ start: boolean,
128
+ ): Timer {
129
+ const isRepeated = type === 'repeat';
130
+ const options = getOptions(partial, isRepeated);
131
+
132
+ const instance = new Timer(
133
+ type,
134
+ {
135
+ callback,
136
+ isRepeated,
137
+ active: false,
138
+ minimum: options.interval - (options.interval % milliseconds) / 2,
139
+ paused: false,
140
+ trace: new TimerTrace(),
141
+ },
142
+ options,
143
+ );
144
+
145
+ if (start) {
146
+ instance.start();
147
+ }
148
+
149
+ return instance;
150
+ }
151
+
152
+ /**
153
+ * Creates a timer which calls a callback after a certain amount of time
154
+ */
155
+ export function wait(callback: () => void): Timer;
156
+
157
+ /**
158
+ * Creates a timer which calls a callback after a certain amount of time
159
+ */
160
+ export function wait(callback: () => void, time: number): Timer;
161
+
162
+ /**
163
+ * Creates a timer which calls a callback after a certain amount of time
164
+ * - `options.interval` defaults to `1000/60` _(1 frame)_
165
+ * - `options.timeout` defaults to `30_000` _(30 seconds)_
166
+ */
167
+ export function wait(
168
+ callback: () => void,
169
+ options: Partial<WaitOptions>,
170
+ ): Timer;
171
+
172
+ export function wait(
173
+ callback: () => void,
174
+ options?: number | Partial<WaitOptions>,
175
+ ): Timer {
176
+ return timer(
177
+ 'wait',
178
+ callback,
179
+ options == null || typeof options === 'number'
180
+ ? {
181
+ interval: options,
182
+ }
183
+ : options,
184
+ true,
185
+ );
186
+ }
package/src/when.ts ADDED
@@ -0,0 +1,111 @@
1
+ import {noop} from '@oscarpalmer/atoms/function';
2
+ import type {WhenOptions, WhenState} from './models';
3
+ import {BasicTimer, timer} from './timer';
4
+
5
+ export class When extends BasicTimer<WhenState> {
6
+ get active() {
7
+ return this.state.timer.active;
8
+ }
9
+
10
+ get paused() {
11
+ return this.state.timer.paused;
12
+ }
13
+
14
+ constructor(state: WhenState) {
15
+ super('when', state);
16
+ }
17
+
18
+ /**
19
+ * Continues the timer _(if it was paused)_
20
+ */
21
+ continue(): When {
22
+ this.state.timer.continue();
23
+
24
+ return this;
25
+ }
26
+
27
+ /**
28
+ * Pauses the timer _(if it was running)_
29
+ */
30
+ pause(): When {
31
+ this.state.timer.pause();
32
+
33
+ return this;
34
+ }
35
+
36
+ /**
37
+ * Stops the timer _(if it was running)_
38
+ */
39
+ stop(): When {
40
+ if (this.state.timer.active) {
41
+ this.state.timer.stop();
42
+
43
+ this.state.rejecter?.();
44
+ }
45
+
46
+ return this;
47
+ }
48
+
49
+ /**
50
+ * Starts the timer and returns a promise that resolves when the condition is met
51
+ */
52
+
53
+ // biome-ignore lint/suspicious/noThenProperty: returning a promise-like object, so it's ok ;)
54
+ then(
55
+ resolve?: (() => void) | null,
56
+ reject?: (() => void) | null,
57
+ ): Promise<void> {
58
+ this.state.timer.start();
59
+
60
+ return this.state.promise.then(resolve ?? noop, reject ?? noop);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * - Creates a promise that resolves when a condition is met
66
+ * - If the condition is never met in a timely manner, the promise will reject
67
+ */
68
+ export function when(
69
+ condition: () => boolean,
70
+ options?: Partial<WhenOptions>,
71
+ ): When {
72
+ const repeated = timer(
73
+ 'repeat',
74
+ () => {
75
+ if (condition()) {
76
+ repeated.stop();
77
+
78
+ state.resolver?.();
79
+ }
80
+ },
81
+ {
82
+ afterCallback() {
83
+ if (!repeated.paused) {
84
+ if (condition()) {
85
+ state.resolver?.();
86
+ } else {
87
+ state.rejecter?.();
88
+ }
89
+ }
90
+ },
91
+ errorCallback() {
92
+ state.rejecter?.();
93
+ },
94
+ count: options?.count,
95
+ interval: options?.interval,
96
+ timeout: options?.timeout,
97
+ },
98
+ false,
99
+ );
100
+
101
+ const state: WhenState = {} as never;
102
+
103
+ state.promise = new Promise((resolve, reject) => {
104
+ state.resolver = resolve;
105
+ state.rejecter = reject;
106
+ });
107
+
108
+ state.timer = repeated;
109
+
110
+ return new When(state);
111
+ }
@@ -0,0 +1,13 @@
1
+ import type { Timer } from './timer';
2
+ /**
3
+ * A set of all active timers
4
+ */
5
+ export declare const activeTimers: Set<Timer>;
6
+ /**
7
+ * A set of timers that were paused due to the document being hidden
8
+ */
9
+ export declare const hiddenTimers: Set<Timer>;
10
+ /**
11
+ * Milliseconds in a frame, probably ;-)
12
+ */
13
+ export declare const milliseconds: number;
@@ -0,0 +1,5 @@
1
+ import type { TimerOptions, TimerState, WorkType } from './models';
2
+ import type { Timer } from './timer';
3
+ export declare function getOptions(options: Partial<TimerOptions>, isRepeated: boolean): TimerOptions;
4
+ export declare function getValueOrDefault(value: unknown, defaultValue: number, minimum?: number): number;
5
+ export declare function work(type: WorkType, timer: Timer, state: TimerState, options: TimerOptions): Timer;
@@ -0,0 +1,5 @@
1
+ declare global {
2
+ var _oscarpalmer_timer_debug: boolean | undefined;
3
+ var _oscarpalmer_timers: Timer[] | undefined;
4
+ }
5
+ export {};
@@ -0,0 +1,184 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ /**
4
+ * Callback that runs after the timer has finished (or is stopped)
5
+ * - `finished` is `true` if the timer was allowed to finish, and `false` if it was stopped
6
+ */
7
+ export type AfterCallback = (finished: boolean) => void;
8
+ export type AnyCallback = (() => void) | IndexedCallback;
9
+ /**
10
+ * Callback that runs for each iteration of the timer
11
+ */
12
+ export type IndexedCallback = (index: number) => void;
13
+ export type BaseOptions = {
14
+ /**
15
+ * Interval between each callback
16
+ */
17
+ interval: number;
18
+ /**
19
+ * Maximum amount of time the timer may run for
20
+ */
21
+ timeout: number;
22
+ };
23
+ export type OptionsWithCount = {
24
+ /**
25
+ * How many times the timer should repeat
26
+ */
27
+ count: number;
28
+ } & BaseOptions;
29
+ export type OptionsWithError = {
30
+ /**
31
+ * Callback to run when an error occurs _(usually a timeout)_
32
+ */
33
+ errorCallback?: () => void;
34
+ };
35
+ export type RepeatOptions = {
36
+ /**
37
+ * Callback to run after the timer has finished (or is stopped)
38
+ * - `finished` is `true` if the timer was allowed to finish, and `false` if it was stopped
39
+ */
40
+ afterCallback?: AfterCallback;
41
+ } & OptionsWithCount & OptionsWithError;
42
+ export type TimerOptions = {} & RepeatOptions;
43
+ export type TimerState = {
44
+ active: boolean;
45
+ callback: AnyCallback;
46
+ count?: number;
47
+ elapsed?: number;
48
+ frame?: number;
49
+ index?: number;
50
+ isRepeated: boolean;
51
+ minimum: number;
52
+ paused: boolean;
53
+ trace: unknown;
54
+ };
55
+ export type WaitOptions = {} & BaseOptions & OptionsWithError;
56
+ export type WhenOptions = {} & OptionsWithCount;
57
+ export type WhenState = {
58
+ promise: Promise<void>;
59
+ rejecter?: () => void;
60
+ resolver?: () => void;
61
+ timer: Timer$1;
62
+ };
63
+ declare abstract class BasicTimer<State> {
64
+ protected readonly $timer: string;
65
+ protected readonly state: State;
66
+ constructor(type: "repeat" | "wait" | "when", state: State);
67
+ /**
68
+ * Is the timer running?
69
+ */
70
+ abstract readonly active: boolean;
71
+ /**
72
+ * Is the timer paused?
73
+ */
74
+ abstract readonly paused: boolean;
75
+ }
76
+ /**
77
+ * A timer that can be started, stopped, and restarted as neeeded
78
+ */
79
+ declare class Timer$1 extends BasicTimer<TimerState> {
80
+ private readonly options;
81
+ get active(): boolean;
82
+ get paused(): boolean;
83
+ /**
84
+ * Gets the traced location of the timer
85
+ */
86
+ get trace(): unknown;
87
+ constructor(type: "repeat" | "wait", state: TimerState, options: TimerOptions);
88
+ /**
89
+ * Continues the timer _(if it was paused)_
90
+ */
91
+ continue(): Timer$1;
92
+ /**
93
+ * Pauses the timer _(if it was running)_
94
+ */
95
+ pause(): Timer$1;
96
+ /**
97
+ * Restarts the timer _(if it was running)_
98
+ */
99
+ restart(): Timer$1;
100
+ /**
101
+ * Starts the timer _(if it was stopped)_
102
+ */
103
+ start(): Timer$1;
104
+ /**
105
+ * Stops the timer _(if it was running)_
106
+ */
107
+ stop(): Timer$1;
108
+ }
109
+ /**
110
+ * Creates a timer which:
111
+ * - calls a callback after a certain amount of time...
112
+ * - ... and repeats it a certain amount of times
113
+ * ---
114
+ * - `options.count` defaults to `Infinity`
115
+ * - `options.interval` defaults to `1000/60` _(1 frame)_
116
+ * - `options.timeout` defaults to `Infinity`
117
+ */
118
+ export declare function repeat(callback: IndexedCallback, options?: Partial<RepeatOptions>): Timer$1;
119
+ /**
120
+ * Creates a timer which calls a callback after a certain amount of time
121
+ */
122
+ export declare function wait(callback: () => void): Timer$1;
123
+ /**
124
+ * Creates a timer which calls a callback after a certain amount of time
125
+ */
126
+ export declare function wait(callback: () => void, time: number): Timer$1;
127
+ /**
128
+ * Creates a timer which calls a callback after a certain amount of time
129
+ * - `options.interval` defaults to `1000/60` _(1 frame)_
130
+ * - `options.timeout` defaults to `30_000` _(30 seconds)_
131
+ */
132
+ export declare function wait(callback: () => void, options: Partial<WaitOptions>): Timer$1;
133
+ export declare class When extends BasicTimer<WhenState> {
134
+ get active(): boolean;
135
+ get paused(): boolean;
136
+ constructor(state: WhenState);
137
+ /**
138
+ * Continues the timer _(if it was paused)_
139
+ */
140
+ continue(): When;
141
+ /**
142
+ * Pauses the timer _(if it was running)_
143
+ */
144
+ pause(): When;
145
+ /**
146
+ * Stops the timer _(if it was running)_
147
+ */
148
+ stop(): When;
149
+ /**
150
+ * Starts the timer and returns a promise that resolves when the condition is met
151
+ */
152
+ then(resolve?: (() => void) | null, reject?: (() => void) | null): Promise<void>;
153
+ }
154
+ /**
155
+ * - Creates a promise that resolves when a condition is met
156
+ * - If the condition is never met in a timely manner, the promise will reject
157
+ */
158
+ export declare function when(condition: () => boolean, options?: Partial<WhenOptions>): When;
159
+ /**
160
+ * Is the value a repeating timer?
161
+ */
162
+ export declare function isRepeated(value: unknown): value is Timer$1;
163
+ /**
164
+ * Is the value a timer?
165
+ */
166
+ export declare function isTimer(value: unknown): value is Timer$1;
167
+ /**
168
+ * Is the value a waiting timer?
169
+ */
170
+ export declare function isWaited(value: unknown): value is Timer$1;
171
+ /**
172
+ * Is the value a conditional timer?
173
+ */
174
+ export declare function isWhen(value: unknown): value is When;
175
+ /**
176
+ * Creates a delayed promise that resolves after a certain amount of time _(or rejects when timed out)_
177
+ */
178
+ export declare function delay(time: number, timeout?: number): Promise<void>;
179
+
180
+ export {
181
+ Timer$1 as Timer,
182
+ };
183
+
184
+ export {};
package/types/index.d.ts CHANGED
@@ -1,72 +1,8 @@
1
+ import './global';
1
2
  /**
2
- * @param {boolean} finished Did the timer finish?
3
+ * Creates a delayed promise that resolves after a certain amount of time _(or rejects when timed out)_
3
4
  */
4
- export type AfterCallback = (finished: boolean) => void;
5
-
6
- /**
7
- * @param {number} index The index of the current iteration
8
- */
9
- export type RepeatedCallback = (index: number) => void;
10
-
11
- declare class Timed<Type, Callback> {
12
- get active(): boolean;
13
- get finished(): boolean;
14
-
15
- /**
16
- * @param {Callback} callback
17
- * @param {number} time
18
- * @param {number} count
19
- * @param {AfterCallback=} afterCallback
20
- */
21
-
22
- constructor(
23
- callback: () => void | ((index: number) => void),
24
- time: number,
25
- count: number,
26
- afterCallback?: AfterCallback,
27
- );
28
-
29
- restart(): Type;
30
- start(): Type;
31
- stop(): Type;
32
- }
33
-
34
- /**
35
- * A timer that waits and runs repeatedly
36
- */
37
- export declare class Repeated extends Timed<Repeated, RepeatedCallback> {}
38
-
39
- /**
40
- * A timer that waits and runs once
41
- */
42
- export declare class Waited extends Timed<Waited, () => void> {
43
- /**
44
- * Creates a new waited timer
45
- * @param {() => void} callback
46
- * @param {number} time
47
- */
48
- constructor(callback: () => void, time: number);
49
- }
50
-
51
- /**
52
- * Creates and starts a new repeated timer
53
- * @param {RepeatedCallback} callback
54
- * @param {number} time
55
- * @param {number} count
56
- * @param {AfterCallback=} afterCallback
57
- * @return {Repeated}
58
- */
59
- export declare function repeat(
60
- callback: RepeatedCallback,
61
- time: number,
62
- count: number,
63
- afterCallback?: AfterCallback,
64
- ): Repeated;
65
-
66
- /**
67
- * Creates and starts a new waited timer
68
- * @param {() => void} callback
69
- * @param {number} time
70
- * @return {Waited}
71
- */
72
- export declare function wait(callback: () => void, time: number): Waited;
5
+ export declare function delay(time: number, timeout?: number): Promise<void>;
6
+ export { isRepeated, isTimer, isWaited, isWhen } from './is';
7
+ export { repeat, wait, type Timer } from './timer';
8
+ export { when, type When } from './when';
package/types/is.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import type { Timer } from './timer';
2
+ import type { When } from './when';
3
+ /**
4
+ * Is the value a repeating timer?
5
+ */
6
+ export declare function isRepeated(value: unknown): value is Timer;
7
+ /**
8
+ * Is the value a timer?
9
+ */
10
+ export declare function isTimer(value: unknown): value is Timer;
11
+ /**
12
+ * Is the value a waiting timer?
13
+ */
14
+ export declare function isWaited(value: unknown): value is Timer;
15
+ /**
16
+ * Is the value a conditional timer?
17
+ */
18
+ export declare function isWhen(value: unknown): value is When;
@@ -0,0 +1,62 @@
1
+ import type { Timer } from './timer';
2
+ /**
3
+ * Callback that runs after the timer has finished (or is stopped)
4
+ * - `finished` is `true` if the timer was allowed to finish, and `false` if it was stopped
5
+ */
6
+ export type AfterCallback = (finished: boolean) => void;
7
+ export type AnyCallback = (() => void) | IndexedCallback;
8
+ /**
9
+ * Callback that runs for each iteration of the timer
10
+ */
11
+ export type IndexedCallback = (index: number) => void;
12
+ export type BaseOptions = {
13
+ /**
14
+ * Interval between each callback
15
+ */
16
+ interval: number;
17
+ /**
18
+ * Maximum amount of time the timer may run for
19
+ */
20
+ timeout: number;
21
+ };
22
+ export type OptionsWithCount = {
23
+ /**
24
+ * How many times the timer should repeat
25
+ */
26
+ count: number;
27
+ } & BaseOptions;
28
+ export type OptionsWithError = {
29
+ /**
30
+ * Callback to run when an error occurs _(usually a timeout)_
31
+ */
32
+ errorCallback?: () => void;
33
+ };
34
+ export type RepeatOptions = {
35
+ /**
36
+ * Callback to run after the timer has finished (or is stopped)
37
+ * - `finished` is `true` if the timer was allowed to finish, and `false` if it was stopped
38
+ */
39
+ afterCallback?: AfterCallback;
40
+ } & OptionsWithCount & OptionsWithError;
41
+ export type TimerOptions = {} & RepeatOptions;
42
+ export type TimerState = {
43
+ active: boolean;
44
+ callback: AnyCallback;
45
+ count?: number;
46
+ elapsed?: number;
47
+ frame?: number;
48
+ index?: number;
49
+ isRepeated: boolean;
50
+ minimum: number;
51
+ paused: boolean;
52
+ trace: unknown;
53
+ };
54
+ export type WaitOptions = {} & BaseOptions & OptionsWithError;
55
+ export type WhenOptions = {} & OptionsWithCount;
56
+ export type WhenState = {
57
+ promise: Promise<void>;
58
+ rejecter?: () => void;
59
+ resolver?: () => void;
60
+ timer: Timer;
61
+ };
62
+ export type WorkType = 'continue' | 'pause' | 'restart' | 'start' | 'stop';