@oscarpalmer/timer 0.25.0 → 0.27.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/when.cjs ADDED
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const _function = require("@oscarpalmer/atoms/function");
4
+ const timer = require("./timer.cjs");
5
+ const destroyedMessage = "Timer has already been destroyed";
6
+ const startedMessage = "Timer has already been started";
7
+ class When extends timer.BasicTimer {
8
+ get active() {
9
+ var _a;
10
+ return ((_a = this.state.timer) == null ? void 0 : _a.active) ?? false;
11
+ }
12
+ get destroyed() {
13
+ return this.state.timer == null;
14
+ }
15
+ get paused() {
16
+ var _a;
17
+ return ((_a = this.state.timer) == null ? void 0 : _a.paused) ?? false;
18
+ }
19
+ get trace() {
20
+ var _a;
21
+ return (_a = this.state.timer) == null ? void 0 : _a.trace;
22
+ }
23
+ constructor(state) {
24
+ super("when", state);
25
+ }
26
+ /**
27
+ * Continues the timer _(if it was paused)_
28
+ */
29
+ continue() {
30
+ var _a;
31
+ (_a = this.state.timer) == null ? void 0 : _a.continue();
32
+ return this;
33
+ }
34
+ /**
35
+ * Destroys the timer _(and stops it,if it was running)_
36
+ */
37
+ destroy() {
38
+ var _a;
39
+ (_a = this.state.timer) == null ? void 0 : _a.destroy();
40
+ this.state.promise = void 0;
41
+ this.state.resolver = _function.noop;
42
+ this.state.rejecter = _function.noop;
43
+ this.state.timer = void 0;
44
+ }
45
+ /**
46
+ * Pauses the timer _(if it was running)_
47
+ */
48
+ pause() {
49
+ var _a;
50
+ (_a = this.state.timer) == null ? void 0 : _a.pause();
51
+ return this;
52
+ }
53
+ /**
54
+ * Stops the timer _(if it was running)_
55
+ */
56
+ stop() {
57
+ var _a;
58
+ (_a = this.state.timer) == null ? void 0 : _a.stop();
59
+ return this;
60
+ }
61
+ /**
62
+ * Starts the timer and returns a promise that resolves when the condition is met
63
+ */
64
+ // biome-ignore lint/suspicious/noThenProperty: returning a promise-like object, so it's ok ;)
65
+ then(resolve, reject) {
66
+ var _a;
67
+ if (this.state.timer == null || ((_a = this.state) == null ? void 0 : _a.started)) {
68
+ throw new Error(
69
+ this.state.timer == null ? destroyedMessage : startedMessage
70
+ );
71
+ }
72
+ this.state.started = true;
73
+ this.state.timer.start();
74
+ return this.state.promise.then(resolve ?? _function.noop, reject ?? _function.noop);
75
+ }
76
+ }
77
+ function when(condition, options) {
78
+ let result = false;
79
+ const state = {
80
+ started: false,
81
+ timer: timer.timer(
82
+ "repeat",
83
+ () => {
84
+ if (condition()) {
85
+ result = true;
86
+ state.timer.stop();
87
+ }
88
+ },
89
+ {
90
+ afterCallback() {
91
+ var _a, _b;
92
+ if (!state.timer.paused) {
93
+ if (result) {
94
+ (_a = state.resolver) == null ? void 0 : _a.call(state);
95
+ } else {
96
+ (_b = state.rejecter) == null ? void 0 : _b.call(state);
97
+ }
98
+ instance.destroy();
99
+ }
100
+ },
101
+ errorCallback() {
102
+ var _a;
103
+ (_a = state.rejecter) == null ? void 0 : _a.call(state);
104
+ instance.destroy();
105
+ },
106
+ count: options == null ? void 0 : options.count,
107
+ interval: options == null ? void 0 : options.interval,
108
+ timeout: options == null ? void 0 : options.timeout
109
+ },
110
+ false
111
+ )
112
+ };
113
+ const promise = new Promise((resolve, reject) => {
114
+ state.resolver = resolve;
115
+ state.rejecter = reject;
116
+ });
117
+ state.promise = promise;
118
+ const instance = new When(state);
119
+ return instance;
120
+ }
121
+ exports.When = When;
122
+ exports.when = when;
package/dist/when.js CHANGED
@@ -1,213 +1,112 @@
1
- // node_modules/@oscarpalmer/atoms/dist/js/function.mjs
2
- function noop() {
3
- }
4
-
5
- // src/constants.ts
6
- var activeTimers = new Set;
7
- var beginTypes = new Set(["continue", "start"]);
8
- var endTypes = new Set(["pause", "stop"]);
9
- var endOrRestartTypes = new Set([
10
- "pause",
11
- "restart",
12
- "stop"
13
- ]);
14
- var hiddenTimers = new Set;
15
- var milliseconds = 1000 / 60;
16
-
17
- // src/functions.ts
18
- function getOptions(options, isRepeated) {
19
- return {
20
- afterCallback: options.afterCallback,
21
- count: getValueOrDefault(options.count, isRepeated ? Number.POSITIVE_INFINITY : 1),
22
- errorCallback: options.errorCallback,
23
- interval: getValueOrDefault(options.interval, milliseconds, milliseconds),
24
- timeout: getValueOrDefault(options.timeout, isRepeated ? Number.POSITIVE_INFINITY : 30000)
25
- };
26
- }
27
- function getValueOrDefault(value, defaultValue, minimum) {
28
- return typeof value === "number" && value > (minimum ?? 0) ? value : defaultValue;
29
- }
30
- function work(type, timer, state, options) {
31
- if (state.destroyed && type !== "stop" || beginTypes.has(type) && state.active || endTypes.has(type) && !state.active) {
32
- return timer;
33
- }
34
- const { count, interval, timeout } = options;
35
- const { isRepeated, minimum } = state;
36
- if (endOrRestartTypes.has(type)) {
37
- const isStop = type === "stop";
38
- activeTimers.delete(timer);
39
- cancelAnimationFrame(state.frame);
40
- if (isStop) {
41
- options.afterCallback?.(false);
42
- }
43
- state.active = false;
44
- state.frame = undefined;
45
- state.paused = !isStop;
46
- if (isStop) {
47
- state.elapsed = undefined;
48
- state.index = undefined;
49
- }
50
- return type === "restart" ? work("start", timer, state, options) : timer;
51
- }
52
- state.active = true;
53
- state.paused = false;
54
- const elapsed = type === "continue" ? +(state.elapsed ?? 0) : 0;
55
- let index = type === "continue" ? +(state.index ?? 0) : 0;
56
- state.elapsed = elapsed;
57
- state.index = index;
58
- const total = (count === Number.POSITIVE_INFINITY ? Number.POSITIVE_INFINITY : (count - index) * (interval > 0 ? interval : milliseconds)) - elapsed;
59
- let current;
60
- let start;
61
- function finish(finished, error) {
62
- activeTimers.delete(timer);
63
- state.active = false;
64
- state.elapsed = undefined;
65
- state.frame = undefined;
66
- state.index = undefined;
67
- if (error) {
68
- options.errorCallback?.();
69
- }
70
- options.afterCallback?.(finished);
71
- }
72
- function step(timestamp) {
73
- if (!state.active) {
74
- return;
75
- }
76
- current ??= timestamp;
77
- start ??= timestamp;
78
- const time = timestamp - current;
79
- state.elapsed = elapsed + (current - start);
80
- const finished = time - elapsed >= total;
81
- if (timestamp - start >= timeout - elapsed) {
82
- finish(finished, !finished);
83
- return;
84
- }
85
- if (finished || time >= minimum) {
86
- if (state.active) {
87
- state.callback(isRepeated ? index : undefined);
88
- }
89
- index += 1;
90
- state.index = index;
91
- if (!finished && index < count) {
92
- current = null;
93
- } else {
94
- finish(true, false);
95
- return;
96
- }
97
- }
98
- state.frame = requestAnimationFrame(step);
99
- }
100
- activeTimers.add(timer);
101
- state.frame = requestAnimationFrame(step);
102
- return timer;
103
- }
104
-
105
- // src/models.ts
106
- class TimerTrace extends Error {
107
- constructor() {
108
- super();
109
- this.name = "TimerTrace";
110
- }
111
- }
112
-
113
- // src/timer.ts
114
- function timer(type, callback, partial, start) {
115
- const isRepeated = type === "repeat";
116
- const options = getOptions(partial, isRepeated);
117
- const instance = new Timer(type, {
118
- callback,
119
- isRepeated,
120
- active: false,
121
- destroyed: false,
122
- minimum: options.interval - options.interval % milliseconds / 2,
123
- paused: false,
124
- trace: new TimerTrace
125
- }, options);
126
- if (start) {
127
- instance.start();
128
- }
129
- return instance;
130
- }
131
- class BasicTimer {
132
- constructor(type, state) {
133
- this.$timer = type;
134
- this.state = state;
135
- }
136
- }
137
-
138
- class Timer extends BasicTimer {
1
+ import { noop } from "@oscarpalmer/atoms/function";
2
+ import { BasicTimer, timer } from "./timer.js";
3
+ const destroyedMessage = "Timer has already been destroyed";
4
+ const startedMessage = "Timer has already been started";
5
+ class When extends BasicTimer {
139
6
  get active() {
140
- return this.state.active;
7
+ var _a;
8
+ return ((_a = this.state.timer) == null ? void 0 : _a.active) ?? false;
141
9
  }
142
10
  get destroyed() {
143
- return this.state.destroyed;
11
+ return this.state.timer == null;
144
12
  }
145
13
  get paused() {
146
- return this.state.paused;
14
+ var _a;
15
+ return ((_a = this.state.timer) == null ? void 0 : _a.paused) ?? false;
147
16
  }
148
17
  get trace() {
149
- return globalThis._oscarpalmer_timer_debug ? this.state.trace : undefined;
18
+ var _a;
19
+ return (_a = this.state.timer) == null ? void 0 : _a.trace;
150
20
  }
151
- constructor(type, state, options) {
152
- super(type, state);
153
- this.options = options;
21
+ constructor(state) {
22
+ super("when", state);
154
23
  }
24
+ /**
25
+ * Continues the timer _(if it was paused)_
26
+ */
155
27
  continue() {
156
- return work("continue", this, this.state, this.options);
28
+ var _a;
29
+ (_a = this.state.timer) == null ? void 0 : _a.continue();
30
+ return this;
157
31
  }
32
+ /**
33
+ * Destroys the timer _(and stops it,if it was running)_
34
+ */
158
35
  destroy() {
159
- if (!this.state.destroyed) {
160
- this.state.destroyed = true;
161
- this.stop();
162
- this.options.afterCallback = undefined;
163
- this.options.errorCallback = undefined;
164
- this.state.callback = undefined;
165
- this.state.trace = undefined;
166
- }
36
+ var _a;
37
+ (_a = this.state.timer) == null ? void 0 : _a.destroy();
38
+ this.state.promise = void 0;
39
+ this.state.resolver = noop;
40
+ this.state.rejecter = noop;
41
+ this.state.timer = void 0;
167
42
  }
43
+ /**
44
+ * Pauses the timer _(if it was running)_
45
+ */
168
46
  pause() {
169
- return work("pause", this, this.state, this.options);
170
- }
171
- restart() {
172
- return work("restart", this, this.state, this.options);
173
- }
174
- start() {
175
- return work("start", this, this.state, this.options);
47
+ var _a;
48
+ (_a = this.state.timer) == null ? void 0 : _a.pause();
49
+ return this;
176
50
  }
51
+ /**
52
+ * Stops the timer _(if it was running)_
53
+ */
177
54
  stop() {
178
- return work("stop", this, this.state, this.options);
55
+ var _a;
56
+ (_a = this.state.timer) == null ? void 0 : _a.stop();
57
+ return this;
58
+ }
59
+ /**
60
+ * Starts the timer and returns a promise that resolves when the condition is met
61
+ */
62
+ // biome-ignore lint/suspicious/noThenProperty: returning a promise-like object, so it's ok ;)
63
+ then(resolve, reject) {
64
+ var _a;
65
+ if (this.state.timer == null || ((_a = this.state) == null ? void 0 : _a.started)) {
66
+ throw new Error(
67
+ this.state.timer == null ? destroyedMessage : startedMessage
68
+ );
69
+ }
70
+ this.state.started = true;
71
+ this.state.timer.start();
72
+ return this.state.promise.then(resolve ?? noop, reject ?? noop);
179
73
  }
180
74
  }
181
-
182
- // src/when.ts
183
75
  function when(condition, options) {
184
76
  let result = false;
185
77
  const state = {
186
78
  started: false,
187
- timer: timer("repeat", () => {
188
- if (condition()) {
189
- result = true;
190
- state.timer.stop();
191
- }
192
- }, {
193
- afterCallback() {
194
- if (!state.timer.paused) {
195
- if (result) {
196
- state.resolver?.();
197
- } else {
198
- state.rejecter?.();
199
- }
200
- instance.destroy();
79
+ timer: timer(
80
+ "repeat",
81
+ () => {
82
+ if (condition()) {
83
+ result = true;
84
+ state.timer.stop();
201
85
  }
202
86
  },
203
- errorCallback() {
204
- state.rejecter?.();
205
- instance.destroy();
87
+ {
88
+ afterCallback() {
89
+ var _a, _b;
90
+ if (!state.timer.paused) {
91
+ if (result) {
92
+ (_a = state.resolver) == null ? void 0 : _a.call(state);
93
+ } else {
94
+ (_b = state.rejecter) == null ? void 0 : _b.call(state);
95
+ }
96
+ instance.destroy();
97
+ }
98
+ },
99
+ errorCallback() {
100
+ var _a;
101
+ (_a = state.rejecter) == null ? void 0 : _a.call(state);
102
+ instance.destroy();
103
+ },
104
+ count: options == null ? void 0 : options.count,
105
+ interval: options == null ? void 0 : options.interval,
106
+ timeout: options == null ? void 0 : options.timeout
206
107
  },
207
- count: options?.count,
208
- interval: options?.interval,
209
- timeout: options?.timeout
210
- }, false)
108
+ false
109
+ )
211
110
  };
212
111
  const promise = new Promise((resolve, reject) => {
213
112
  state.resolver = resolve;
@@ -217,54 +116,7 @@ function when(condition, options) {
217
116
  const instance = new When(state);
218
117
  return instance;
219
118
  }
220
- var destroyedMessage = "Timer has already been destroyed";
221
- var startedMessage = "Timer has already been started";
222
-
223
- class When extends BasicTimer {
224
- get active() {
225
- return this.state.timer?.active ?? false;
226
- }
227
- get destroyed() {
228
- return this.state.timer == null;
229
- }
230
- get paused() {
231
- return this.state.timer?.paused ?? false;
232
- }
233
- get trace() {
234
- return this.state.timer?.trace;
235
- }
236
- constructor(state) {
237
- super("when", state);
238
- }
239
- continue() {
240
- this.state.timer?.continue();
241
- return this;
242
- }
243
- destroy() {
244
- this.state.timer?.destroy();
245
- this.state.promise = undefined;
246
- this.state.resolver = noop;
247
- this.state.rejecter = noop;
248
- this.state.timer = undefined;
249
- }
250
- pause() {
251
- this.state.timer?.pause();
252
- return this;
253
- }
254
- stop() {
255
- this.state.timer?.stop();
256
- return this;
257
- }
258
- then(resolve, reject) {
259
- if (this.state.timer == null || this.state?.started) {
260
- throw new Error(this.state.timer == null ? destroyedMessage : startedMessage);
261
- }
262
- this.state.started = true;
263
- this.state.timer.start();
264
- return this.state.promise.then(resolve ?? noop, reject ?? noop);
265
- }
266
- }
267
119
  export {
268
- when,
269
- When
120
+ When,
121
+ when
270
122
  };
package/package.json CHANGED
@@ -4,51 +4,54 @@
4
4
  "url": "https://oscarpalmer.se"
5
5
  },
6
6
  "dependencies": {
7
- "@oscarpalmer/atoms": "0.74.1"
7
+ "@oscarpalmer/atoms": "0.81.0"
8
8
  },
9
9
  "description": "A better solution for timeout- and interval-based timers.",
10
10
  "devDependencies": {
11
- "@biomejs/biome": "^1.9.2",
12
- "@happy-dom/global-registrator": "^15.7.4",
13
- "@types/bun": "^1.1.10",
14
- "bun": "^1.1.29",
15
- "dts-bundle-generator": "9.5.1",
16
- "typescript": "^5.6.2"
11
+ "@biomejs/biome": "^1.9",
12
+ "@rollup/plugin-node-resolve": "^16",
13
+ "@rollup/plugin-typescript": "^12.1",
14
+ "@types/node": "^22.10",
15
+ "@vitest/coverage-istanbul": "^2.1",
16
+ "dts-bundle-generator": "^9.5",
17
+ "happy-dom": "^16.5",
18
+ "tslib": "^2.8",
19
+ "typescript": "^5.7",
20
+ "vite": "^6",
21
+ "vitest": "^2.1"
17
22
  },
18
23
  "exports": {
19
24
  ".": {
20
- "bun": "./src/index.ts",
21
25
  "import": {
22
26
  "types": "./types/index.d.ts",
23
- "default": "./dist/index.mjs"
27
+ "default": "./dist/index.js"
24
28
  },
25
29
  "require": {
26
30
  "types": "./types/index.d.cts",
27
- "default": "./dist/index.js"
31
+ "default": "./dist/index.cjs"
28
32
  }
29
33
  }
30
34
  },
31
35
  "files": ["dist", "src", "types"],
32
36
  "keywords": ["timer", "setTimeout", "setInterval", "requestAnimationFrame"],
33
37
  "license": "MIT",
34
- "main": "dist/index.js",
35
- "module": "dist/index.mjs",
38
+ "main": "dist/index.cjs",
39
+ "module": "dist/index.js",
36
40
  "name": "@oscarpalmer/timer",
37
41
  "repository": {
38
42
  "type": "git",
39
43
  "url": "git+https://github.com/oscarpalmer/timer.git"
40
44
  },
41
45
  "scripts": {
42
- "build": "bun run clean && bun run build:js && bun run types",
43
- "build:js": "bunx bun ./.bun.ts && bunx bun ./.bun.ts --mjs",
46
+ "build": "npm run clean && npm run build:js && npm run rollup && npm run types",
47
+ "build:js": "npx vite build",
44
48
  "clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
45
- "test": "bun test",
46
- "types": "bun run types:cjs && bun run types:esm",
47
- "types:cjs": "bunx dts-bundle-generator --out-file ./types/index.d.cts --external-inlines '@oscarpalmer/atoms' --no-check --silent ./src/index.ts",
48
- "types:esm": "bunx tsc -p ./tsconfig.json",
49
- "watch": "bun build ./src/index.ts --outfile ./dist/index.js --watch"
49
+ "rollup": "npx rollup -c",
50
+ "test": "npx vitest --coverage",
51
+ "types": "npx tsc && npx dts-bundle-generator --config ./dts.config.ts",
52
+ "watch": "npx vite build --watch"
50
53
  },
51
54
  "type": "module",
52
55
  "types": "types/index.d.cts",
53
- "version": "0.25.0"
56
+ "version": "0.27.0"
54
57
  }
package/src/functions.ts CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  endTypes,
6
6
  milliseconds,
7
7
  } from './constants';
8
- import type {TimerOptions, TimerState, WhenState, WorkType} from './models';
8
+ import type {TimerOptions, TimerState, WorkType} from './models';
9
9
  import type {Timer} from './timer';
10
10
 
11
11
  export function getOptions(
package/src/index.ts CHANGED
@@ -45,3 +45,4 @@ document.addEventListener('visibilitychange', () => {
45
45
  export {isRepeated, isTimer, isWaited, isWhen} from './is';
46
46
  export {repeat, wait, type Timer} from './timer';
47
47
  export {when, type When} from './when';
48
+
package/src/models.ts CHANGED
@@ -60,7 +60,7 @@ export type TimerState = {
60
60
  isRepeated: boolean;
61
61
  minimum: number;
62
62
  paused: boolean;
63
- trace: TimerTrace;
63
+ trace?: string;
64
64
  };
65
65
 
66
66
  export class TimerTrace extends Error {
package/src/timer.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import {milliseconds} from './constants';
2
2
  import {getOptions, work} from './functions';
3
3
  import {
4
- TimerTrace,
5
4
  type AnyCallback,
6
5
  type IndexedCallback,
7
6
  type RepeatOptions,
8
7
  type TimerOptions,
9
8
  type TimerState,
9
+ TimerTrace,
10
10
  type WaitOptions,
11
11
  } from './models';
12
12
 
@@ -37,7 +37,7 @@ export abstract class BasicTimer<State> {
37
37
  /**
38
38
  * Gets the traced location of the timer
39
39
  */
40
- abstract readonly trace: TimerTrace | undefined;
40
+ abstract readonly trace: string | undefined;
41
41
  }
42
42
 
43
43
  /**
@@ -159,7 +159,7 @@ export function timer(
159
159
  destroyed: false,
160
160
  minimum: options.interval - (options.interval % milliseconds) / 2,
161
161
  paused: false,
162
- trace: new TimerTrace(),
162
+ trace: new TimerTrace().stack,
163
163
  },
164
164
  options,
165
165
  );