@oscarpalmer/timer 0.30.0 → 0.32.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/when.ts CHANGED
@@ -1,13 +1,19 @@
1
1
  import {noop} from '@oscarpalmer/atoms/function';
2
2
  import {destroyedMessage, milliseconds, startedMessage} from './constants';
3
3
  import {getValidNumber} from './get';
4
+ import './global';
4
5
  import {TimerTrace, type WhenOptions, type WhenState} from './models';
5
6
  import {Timer} from './timer';
6
- import {work} from './work';
7
7
 
8
8
  class When {
9
9
  private readonly $timer = 'when';
10
- private readonly state: WhenState;
10
+ private readonly state: WhenState = {
11
+ promise: undefined as never,
12
+ rejecter: undefined as never,
13
+ resolver: undefined as never,
14
+ started: false,
15
+ timer: undefined as never,
16
+ };
11
17
 
12
18
  /**
13
19
  * Is the timer active?
@@ -39,8 +45,53 @@ class When {
39
45
  : undefined;
40
46
  }
41
47
 
42
- constructor(state: WhenState) {
43
- this.state = state;
48
+ constructor(condition: () => boolean, options?: Partial<WhenOptions>) {
49
+ const {state} = this;
50
+
51
+ state.promise = new Promise<void>((resolve, reject) => {
52
+ state.resolver = resolve;
53
+ state.rejecter = reject;
54
+ });
55
+
56
+ let result = false;
57
+
58
+ this.state.timer = new Timer(
59
+ 'when',
60
+ {
61
+ callback(): void {
62
+ try {
63
+ if (condition()) {
64
+ result = true;
65
+
66
+ state.timer.stop();
67
+ }
68
+ } catch {
69
+ state.timer.stop();
70
+ }
71
+ },
72
+ trace: new TimerTrace().stack,
73
+ },
74
+ {
75
+ onAfter: () => {
76
+ if (result) {
77
+ state.resolver?.();
78
+ } else {
79
+ state.rejecter?.();
80
+ }
81
+
82
+ this.destroy();
83
+ },
84
+ onError: () => {
85
+ state.rejecter?.();
86
+
87
+ this.destroy();
88
+ },
89
+ count: getValidNumber(options?.count),
90
+ interval: getValidNumber(options?.interval, milliseconds),
91
+ timeout: getValidNumber(options?.timeout),
92
+ },
93
+ false,
94
+ );
44
95
  }
45
96
 
46
97
  /**
@@ -56,12 +107,14 @@ class When {
56
107
  * Destroys the timer _(and stops it,if it was running)_
57
108
  */
58
109
  destroy(): void {
59
- this.state.timer?.destroy();
110
+ const {state} = this;
60
111
 
61
- this.state.promise = undefined as never;
62
- this.state.resolver = noop;
63
- this.state.rejecter = noop;
64
- this.state.timer = undefined as never;
112
+ state.timer?.destroy();
113
+
114
+ state.promise = undefined as never;
115
+ state.resolver = noop;
116
+ state.rejecter = noop;
117
+ state.timer = undefined as never;
65
118
  }
66
119
 
67
120
  /**
@@ -90,17 +143,21 @@ class When {
90
143
  resolve?: (() => void) | null,
91
144
  reject?: (() => void) | null,
92
145
  ): Promise<void> {
93
- if (this.state.timer == null || this.state?.started) {
94
- throw new Error(
95
- this.state.timer == null ? destroyedMessage : startedMessage,
96
- );
146
+ const {state} = this;
147
+
148
+ if (state.timer == null) {
149
+ throw new Error(destroyedMessage);
150
+ }
151
+
152
+ if (state.started) {
153
+ throw new Error(startedMessage);
97
154
  }
98
155
 
99
- this.state.started = true;
156
+ state.started = true;
100
157
 
101
- this.state.timer.start();
158
+ state.timer.start();
102
159
 
103
- return this.state.promise.then(resolve ?? noop, reject ?? noop);
160
+ return state.promise.then(resolve ?? noop, reject ?? noop);
104
161
  }
105
162
  }
106
163
 
@@ -111,61 +168,7 @@ export function when(
111
168
  condition: () => boolean,
112
169
  options?: Partial<WhenOptions>,
113
170
  ): When {
114
- let called = false;
115
- let result = false;
116
-
117
- const state: WhenState = {
118
- started: false,
119
- timer: new Timer(
120
- 'when',
121
- work,
122
- {
123
- callback() {
124
- if (condition()) {
125
- result = true;
126
-
127
- state.timer.stop();
128
- }
129
- },
130
- trace: new TimerTrace().stack,
131
- },
132
- {
133
- onAfter() {
134
- if (!(state.timer?.paused ?? false) && !called) {
135
- called = true;
136
-
137
- if (result) {
138
- state.resolver?.();
139
- } else {
140
- state.rejecter?.();
141
- }
142
-
143
- instance.destroy();
144
- }
145
- },
146
- onError() {
147
- state.rejecter?.();
148
-
149
- instance.destroy();
150
- },
151
- count: getValidNumber(options?.count),
152
- interval: getValidNumber(options?.interval, milliseconds),
153
- timeout: getValidNumber(options?.timeout),
154
- },
155
- false,
156
- ),
157
- } as never;
158
-
159
- const promise = new Promise<void>((resolve, reject) => {
160
- state.resolver = resolve;
161
- state.rejecter = reject;
162
- });
163
-
164
- state.promise = promise;
165
-
166
- const instance = new When(state);
167
-
168
- return instance;
171
+ return new When(condition, options);
169
172
  }
170
173
 
171
174
  export type {When};
package/src/work.ts CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  beginTypes,
4
4
  endOrRestartTypes,
5
5
  endTypes,
6
+ intervalBuffer,
6
7
  milliseconds,
7
8
  pauseTypes,
8
9
  } from './constants';
@@ -14,6 +15,27 @@ import type {
14
15
  } from './models';
15
16
  import type {Timer} from './timer';
16
17
 
18
+ function endOrRestart(
19
+ type: WorkHandlerType,
20
+ timer: WorkHandlerTimer,
21
+ state: TimerState,
22
+ options: TimerOptions,
23
+ ): Timer {
24
+ cancelAnimationFrame(state.frame as never);
25
+
26
+ if (type === 'stop') {
27
+ options.onAfter?.(false);
28
+ }
29
+
30
+ state.active = false;
31
+ state.frame = undefined;
32
+ state.paused = type === 'pause';
33
+
34
+ return type === 'restart'
35
+ ? work('start', timer, state, options)
36
+ : timer.instance;
37
+ }
38
+
17
39
  function finish(
18
40
  timer: WorkHandlerTimer,
19
41
  state: TimerState,
@@ -33,49 +55,21 @@ function finish(
33
55
  }
34
56
  }
35
57
 
36
- export function work(
37
- type: WorkHandlerType,
38
- timer: WorkHandlerTimer,
39
- state: TimerState,
40
- options: TimerOptions,
41
- ): Timer {
42
- if (
58
+ function ignore(type: WorkHandlerType, state: TimerState): boolean {
59
+ return (
43
60
  (state.destroyed && type !== 'stop') ||
44
61
  (state.active ? beginTypes.has(type) : endTypes.has(type))
45
- ) {
46
- return timer.instance;
47
- }
48
-
49
- const pausable = pauseTypes.has(type);
50
-
51
- state.elapsed = pausable ? state.elapsed : 0;
52
- state.index = pausable ? state.index : 0;
53
- state.total = pausable ? state.total : 0;
54
-
55
- if (endOrRestartTypes.has(type)) {
56
- activeTimers.delete(timer.instance);
57
-
58
- cancelAnimationFrame(state.frame as never);
59
-
60
- if (type === 'stop') {
61
- options.onAfter?.(false);
62
- }
63
-
64
- state.active = false;
65
- state.frame = undefined;
66
- state.paused = type === 'pause';
67
-
68
- return type === 'restart'
69
- ? work('start', timer, state, options)
70
- : timer.instance;
71
- }
72
-
73
- state.active = true;
74
- state.paused = false;
62
+ );
63
+ }
75
64
 
65
+ function run(
66
+ timer: WorkHandlerTimer,
67
+ state: TimerState,
68
+ options: TimerOptions,
69
+ ): (now: DOMHighResTimeStamp) => void {
76
70
  let start: DOMHighResTimeStamp | undefined;
77
71
 
78
- function step(now: DOMHighResTimeStamp): void {
72
+ return function step(now: DOMHighResTimeStamp): void {
79
73
  if (!state.active) {
80
74
  return;
81
75
  }
@@ -97,7 +91,7 @@ export function work(
97
91
 
98
92
  if (
99
93
  options.interval === milliseconds ||
100
- state.elapsed >= options.interval - 5
94
+ state.elapsed >= options.interval - intervalBuffer
101
95
  ) {
102
96
  if (options.count > -1) {
103
97
  (state.callback as (index: number) => void)(state.index);
@@ -119,11 +113,49 @@ export function work(
119
113
  }
120
114
 
121
115
  state.frame = requestAnimationFrame(step);
116
+ };
117
+ }
118
+
119
+ function setState(type: WorkHandlerType, state: TimerState): void {
120
+ const pausable = pauseTypes.has(type);
121
+
122
+ state.elapsed = pausable ? state.elapsed : 0;
123
+ state.index = pausable ? state.index : 0;
124
+ state.total = pausable ? state.total : 0;
125
+ }
126
+
127
+ export function stop(
128
+ timer: WorkHandlerTimer,
129
+ state: TimerState,
130
+ options: TimerOptions,
131
+ ): void {
132
+ endOrRestart('stop', timer, state, options);
133
+ }
134
+
135
+ export function work(
136
+ type: WorkHandlerType,
137
+ timer: WorkHandlerTimer,
138
+ state: TimerState,
139
+ options: TimerOptions,
140
+ ): Timer {
141
+ if (ignore(type, state)) {
142
+ return timer.instance;
143
+ }
144
+
145
+ setState(type, state);
146
+
147
+ if (endOrRestartTypes.has(type)) {
148
+ return endOrRestart(type, timer, state, options);
122
149
  }
123
150
 
151
+ state.active = true;
152
+ state.paused = false;
153
+
124
154
  activeTimers.add(timer.instance);
125
155
 
126
- state.frame = requestAnimationFrame(step);
156
+ const runner = run(timer, state, options);
157
+
158
+ state.frame = requestAnimationFrame(runner);
127
159
 
128
160
  return timer.instance;
129
161
  }
@@ -2,7 +2,6 @@
2
2
 
3
3
  declare class Timer {
4
4
  #private;
5
- protected readonly worker: WorkHandler;
6
5
  protected readonly options: TimerOptions;
7
6
  private readonly $timer;
8
7
  protected readonly state: TimerState;
@@ -22,7 +21,7 @@ declare class Timer {
22
21
  * Get the timer's origin _(if debugging is enabled)_
23
22
  */
24
23
  get trace(): string | undefined;
25
- constructor(type: TimerType, worker: WorkHandler, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
24
+ constructor(type: TimerType, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
26
25
  /**
27
26
  * Continue running the timer _(if it's paused)_
28
27
  */
@@ -67,11 +66,6 @@ export type TimerState = {
67
66
  trace: string | undefined;
68
67
  };
69
68
  export type TimerType = "repeat" | "wait" | "when";
70
- export type WorkHandler = (type: WorkHandlerType, timer: WorkHandlerTimer, state: TimerState, options: TimerOptions) => Timer;
71
- export type WorkHandlerTimer = {
72
- instance: Timer;
73
- type: TimerType;
74
- };
75
69
  export type WorkHandlerType = "continue" | "pause" | "restart" | "start" | "stop";
76
70
  /**
77
71
  * A set of all active timers
@@ -81,6 +75,10 @@ export declare const activeTimers: Set<Timer>;
81
75
  * A set of types that allow work to begin
82
76
  */
83
77
  export declare const beginTypes: Set<WorkHandlerType>;
78
+ /**
79
+ * Buffer value to use when evaluating if a specific time is within a certain range
80
+ */
81
+ export declare const intervalBuffer = 5;
84
82
  /**
85
83
  * Message to show when a when-timer is destroyed
86
84
  */
@@ -8,6 +8,10 @@ export declare const activeTimers: Set<Timer>;
8
8
  * A set of types that allow work to begin
9
9
  */
10
10
  export declare const beginTypes: Set<WorkHandlerType>;
11
+ /**
12
+ * Buffer value to use when evaluating if a specific time is within a certain range
13
+ */
14
+ export declare const intervalBuffer = 5;
11
15
  /**
12
16
  * Message to show when a when-timer is destroyed
13
17
  */
package/types/index.d.cts CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  export declare class Timer {
4
4
  #private;
5
- protected readonly worker: WorkHandler;
6
5
  protected readonly options: TimerOptions;
7
6
  private readonly $timer;
8
7
  protected readonly state: TimerState;
@@ -22,7 +21,7 @@ export declare class Timer {
22
21
  * Get the timer's origin _(if debugging is enabled)_
23
22
  */
24
23
  get trace(): string | undefined;
25
- constructor(type: TimerType, worker: WorkHandler, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
24
+ constructor(type: TimerType, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
26
25
  /**
27
26
  * Continue running the timer _(if it's paused)_
28
27
  */
@@ -101,19 +100,6 @@ export type WhenOptions = {
101
100
  */
102
101
  timeout: number;
103
102
  };
104
- export type WhenState = {
105
- promise: Promise<void>;
106
- rejecter?: () => void;
107
- resolver?: () => void;
108
- started: boolean;
109
- timer: Timer;
110
- };
111
- export type WorkHandler = (type: WorkHandlerType, timer: WorkHandlerTimer, state: TimerState, options: TimerOptions) => Timer;
112
- export type WorkHandlerTimer = {
113
- instance: Timer;
114
- type: TimerType;
115
- };
116
- export type WorkHandlerType = "continue" | "pause" | "restart" | "start" | "stop";
117
103
  export declare class When {
118
104
  private readonly $timer;
119
105
  private readonly state;
@@ -133,7 +119,7 @@ export declare class When {
133
119
  * Get the timer's origin _(if debugging is enabled)_
134
120
  */
135
121
  get trace(): string | undefined;
136
- constructor(state: WhenState);
122
+ constructor(condition: () => boolean, options?: Partial<WhenOptions>);
137
123
  /**
138
124
  * Continues the timer _(if it was paused)_
139
125
  */
package/types/is.d.cts CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  declare class Timer {
4
4
  #private;
5
- protected readonly worker: WorkHandler;
6
5
  protected readonly options: TimerOptions;
7
6
  private readonly $timer;
8
7
  protected readonly state: TimerState;
@@ -22,7 +21,7 @@ declare class Timer {
22
21
  * Get the timer's origin _(if debugging is enabled)_
23
22
  */
24
23
  get trace(): string | undefined;
25
- constructor(type: TimerType, worker: WorkHandler, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
24
+ constructor(type: TimerType, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
26
25
  /**
27
26
  * Continue running the timer _(if it's paused)_
28
27
  */
@@ -67,19 +66,23 @@ export type TimerState = {
67
66
  trace: string | undefined;
68
67
  };
69
68
  export type TimerType = "repeat" | "wait" | "when";
70
- export type WhenState = {
71
- promise: Promise<void>;
72
- rejecter?: () => void;
73
- resolver?: () => void;
74
- started: boolean;
75
- timer: Timer;
76
- };
77
- export type WorkHandler = (type: WorkHandlerType, timer: WorkHandlerTimer, state: TimerState, options: TimerOptions) => Timer;
78
- export type WorkHandlerTimer = {
79
- instance: Timer;
80
- type: TimerType;
69
+ /**
70
+ * Options for a conditional timer
71
+ */
72
+ export type WhenOptions = {
73
+ /**
74
+ * How many times the timer should check the condition
75
+ */
76
+ count: number;
77
+ /**
78
+ * Then interval between each condtional check
79
+ */
80
+ interval: number;
81
+ /**
82
+ * The timeout for the timer
83
+ */
84
+ timeout: number;
81
85
  };
82
- export type WorkHandlerType = "continue" | "pause" | "restart" | "start" | "stop";
83
86
  declare class When {
84
87
  private readonly $timer;
85
88
  private readonly state;
@@ -99,7 +102,7 @@ declare class When {
99
102
  * Get the timer's origin _(if debugging is enabled)_
100
103
  */
101
104
  get trace(): string | undefined;
102
- constructor(state: WhenState);
105
+ constructor(condition: () => boolean, options?: Partial<WhenOptions>);
103
106
  /**
104
107
  * Continues the timer _(if it was paused)_
105
108
  */
@@ -2,7 +2,6 @@
2
2
 
3
3
  declare class Timer {
4
4
  #private;
5
- protected readonly worker: WorkHandler;
6
5
  protected readonly options: TimerOptions;
7
6
  private readonly $timer;
8
7
  protected readonly state: TimerState;
@@ -22,7 +21,7 @@ declare class Timer {
22
21
  * Get the timer's origin _(if debugging is enabled)_
23
22
  */
24
23
  get trace(): string | undefined;
25
- constructor(type: TimerType, worker: WorkHandler, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
24
+ constructor(type: TimerType, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
26
25
  /**
27
26
  * Continue running the timer _(if it's paused)_
28
27
  */
@@ -2,7 +2,6 @@
2
2
 
3
3
  export declare class Timer {
4
4
  #private;
5
- protected readonly worker: WorkHandler;
6
5
  protected readonly options: TimerOptions;
7
6
  private readonly $timer;
8
7
  protected readonly state: TimerState;
@@ -22,7 +21,7 @@ export declare class Timer {
22
21
  * Get the timer's origin _(if debugging is enabled)_
23
22
  */
24
23
  get trace(): string | undefined;
25
- constructor(type: TimerType, worker: WorkHandler, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
24
+ constructor(type: TimerType, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
26
25
  /**
27
26
  * Continue running the timer _(if it's paused)_
28
27
  */
@@ -84,12 +83,6 @@ export type TimerState = {
84
83
  trace: string | undefined;
85
84
  };
86
85
  export type TimerType = "repeat" | "wait" | "when";
87
- export type WorkHandler = (type: WorkHandlerType, timer: WorkHandlerTimer, state: TimerState, options: TimerOptions) => Timer;
88
- export type WorkHandlerTimer = {
89
- instance: Timer;
90
- type: TimerType;
91
- };
92
- export type WorkHandlerType = "continue" | "pause" | "restart" | "start" | "stop";
93
86
  /**
94
87
  * Create a repeating timer
95
88
  */
package/types/repeat.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import './global';
1
2
  import { type RepeatOptions } from './models';
2
3
  import { Timer } from './timer';
3
4
  /**
package/types/timer.d.cts CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  export declare class Timer {
4
4
  #private;
5
- protected readonly worker: WorkHandler;
6
5
  protected readonly options: TimerOptions;
7
6
  private readonly $timer;
8
7
  protected readonly state: TimerState;
@@ -22,7 +21,7 @@ export declare class Timer {
22
21
  * Get the timer's origin _(if debugging is enabled)_
23
22
  */
24
23
  get trace(): string | undefined;
25
- constructor(type: TimerType, worker: WorkHandler, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
24
+ constructor(type: TimerType, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
26
25
  /**
27
26
  * Continue running the timer _(if it's paused)_
28
27
  */
@@ -67,11 +66,5 @@ export type TimerState = {
67
66
  trace: string | undefined;
68
67
  };
69
68
  export type TimerType = "repeat" | "wait" | "when";
70
- export type WorkHandler = (type: WorkHandlerType, timer: WorkHandlerTimer, state: TimerState, options: TimerOptions) => Timer;
71
- export type WorkHandlerTimer = {
72
- instance: Timer;
73
- type: TimerType;
74
- };
75
- export type WorkHandlerType = "continue" | "pause" | "restart" | "start" | "stop";
76
69
 
77
70
  export {};
package/types/timer.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import type { TimerOptions, TimerState, TimerType, WorkHandler } from './models';
1
+ import type { TimerOptions, TimerState, TimerType } from './models';
2
2
  export declare class Timer {
3
3
  #private;
4
- protected readonly worker: WorkHandler;
5
4
  protected readonly options: TimerOptions;
6
5
  private readonly $timer;
7
6
  protected readonly state: TimerState;
@@ -21,7 +20,7 @@ export declare class Timer {
21
20
  * Get the timer's origin _(if debugging is enabled)_
22
21
  */
23
22
  get trace(): string | undefined;
24
- constructor(type: TimerType, worker: WorkHandler, state: Pick<TimerState, 'callback' | 'trace'>, options: TimerOptions, start: boolean);
23
+ constructor(type: TimerType, state: Pick<TimerState, 'callback' | 'trace'>, options: TimerOptions, start: boolean);
25
24
  /**
26
25
  * Continue running the timer _(if it's paused)_
27
26
  */
package/types/wait.d.cts CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  export declare class Timer {
4
4
  #private;
5
- protected readonly worker: WorkHandler;
6
5
  protected readonly options: TimerOptions;
7
6
  private readonly $timer;
8
7
  protected readonly state: TimerState;
@@ -22,7 +21,7 @@ export declare class Timer {
22
21
  * Get the timer's origin _(if debugging is enabled)_
23
22
  */
24
23
  get trace(): string | undefined;
25
- constructor(type: TimerType, worker: WorkHandler, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
24
+ constructor(type: TimerType, state: Pick<TimerState, "callback" | "trace">, options: TimerOptions, start: boolean);
26
25
  /**
27
26
  * Continue running the timer _(if it's paused)_
28
27
  */
@@ -67,12 +66,6 @@ export type TimerState = {
67
66
  trace: string | undefined;
68
67
  };
69
68
  export type TimerType = "repeat" | "wait" | "when";
70
- export type WorkHandler = (type: WorkHandlerType, timer: WorkHandlerTimer, state: TimerState, options: TimerOptions) => Timer;
71
- export type WorkHandlerTimer = {
72
- instance: Timer;
73
- type: TimerType;
74
- };
75
- export type WorkHandlerType = "continue" | "pause" | "restart" | "start" | "stop";
76
69
  /**
77
70
  * Create a waiting timer
78
71
  * @param callback Callback to run when the timer has finished
package/types/wait.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import './global';
1
2
  import { Timer } from './timer';
2
3
  /**
3
4
  * Create a waiting timer