yummies 7.19.4 → 7.20.1
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/assert.cjs +1 -1
- package/assert.cjs.map +1 -1
- package/assert.js +1 -1
- package/assert.js.map +1 -1
- package/async.cjs +147 -137
- package/async.cjs.map +1 -1
- package/async.d.ts +98 -131
- package/async.js +147 -137
- package/async.js.map +1 -1
- package/common.cjs +3 -1
- package/common.cjs.map +1 -1
- package/common.d.ts +18 -24
- package/common.js +3 -1
- package/common.js.map +1 -1
- package/complex.cjs +1 -0
- package/complex.cjs.map +1 -1
- package/complex.js +1 -0
- package/complex.js.map +1 -1
- package/cookie.cjs +1 -1
- package/cookie.cjs.map +1 -1
- package/cookie.d.ts +0 -18
- package/cookie.js +1 -1
- package/cookie.js.map +1 -1
- package/css-cx.cjs +78 -0
- package/css-cx.cjs.map +1 -0
- package/css-cx.d.ts +69 -0
- package/css-cx.js +74 -0
- package/css-cx.js.map +1 -0
- package/css.cjs +32 -111
- package/css.cjs.map +1 -1
- package/css.d.ts +32 -42
- package/css.js +30 -107
- package/css.js.map +1 -1
- package/data.cjs +60 -50
- package/data.cjs.map +1 -1
- package/data.d.ts +21 -34
- package/data.js +60 -50
- package/data.js.map +1 -1
- package/date-time.cjs +104 -98
- package/date-time.cjs.map +1 -1
- package/date-time.d.ts +51 -57
- package/date-time.js +104 -97
- package/date-time.js.map +1 -1
- package/device.cjs +14 -19
- package/device.cjs.map +1 -1
- package/device.d.ts +15 -26
- package/device.js +14 -19
- package/device.js.map +1 -1
- package/encodings.cjs +1 -1
- package/encodings.cjs.map +1 -1
- package/encodings.d.ts +0 -17
- package/encodings.js +1 -1
- package/encodings.js.map +1 -1
- package/errors.cjs +1 -18
- package/errors.cjs.map +1 -1
- package/errors.d.ts +0 -17
- package/errors.js +1 -17
- package/errors.js.map +1 -1
- package/file.cjs +3 -17
- package/file.cjs.map +1 -1
- package/file.d.ts +1 -16
- package/file.js +3 -17
- package/file.js.map +1 -1
- package/format.cjs +1 -1
- package/format.cjs.map +1 -1
- package/format.js +1 -1
- package/format.js.map +1 -1
- package/html.cjs +112 -175
- package/html.cjs.map +1 -1
- package/html.d.ts +58 -57
- package/html.js +111 -172
- package/html.js.map +1 -1
- package/id-nanoid.cjs +36 -0
- package/id-nanoid.cjs.map +1 -0
- package/id-nanoid.d.ts +26 -0
- package/id-nanoid.js +32 -0
- package/id-nanoid.js.map +1 -0
- package/id.cjs +10 -45
- package/id.cjs.map +1 -1
- package/id.d.ts +27 -36
- package/id.js +6 -40
- package/id.js.map +1 -1
- package/imports.cjs +3 -18
- package/imports.cjs.map +1 -1
- package/imports.d.ts +1 -16
- package/imports.js +3 -17
- package/imports.js.map +1 -1
- package/math.cjs +16 -12
- package/math.cjs.map +1 -1
- package/math.d.ts +9 -24
- package/math.js +16 -12
- package/math.js.map +1 -1
- package/media.cjs +88 -89
- package/media.cjs.map +1 -1
- package/media.d.ts +72 -80
- package/media.js +88 -88
- package/media.js.map +1 -1
- package/mobx.cjs +0 -1
- package/mobx.cjs.map +1 -1
- package/mobx.js.map +1 -1
- package/ms.cjs +3 -17
- package/ms.cjs.map +1 -1
- package/ms.d.ts +1 -16
- package/ms.js +3 -17
- package/ms.js.map +1 -1
- package/number.cjs +1 -17
- package/number.cjs.map +1 -1
- package/number.d.ts +0 -16
- package/number.js +1 -17
- package/number.js.map +1 -1
- package/package.json +6 -6
- package/parser.cjs +1 -1
- package/parser.cjs.map +1 -1
- package/parser.js +1 -1
- package/parser.js.map +1 -1
- package/price.cjs +1 -1
- package/price.cjs.map +1 -1
- package/price.d.ts +0 -16
- package/price.js +1 -1
- package/price.js.map +1 -1
- package/random.cjs +37 -39
- package/random.cjs.map +1 -1
- package/random.d.ts +31 -40
- package/random.js +37 -39
- package/random.js.map +1 -1
- package/react.cjs +0 -1
- package/react.cjs.map +1 -1
- package/react.js.map +1 -1
- package/sanitize-html.cjs +82 -0
- package/sanitize-html.cjs.map +1 -0
- package/sanitize-html.d.ts +28 -0
- package/sanitize-html.js +79 -0
- package/sanitize-html.js.map +1 -0
- package/sound.cjs +1 -17
- package/sound.cjs.map +1 -1
- package/sound.d.ts +0 -16
- package/sound.js +1 -17
- package/sound.js.map +1 -1
- package/storage.cjs +7 -5
- package/storage.cjs.map +1 -1
- package/storage.d.ts +3 -17
- package/storage.js +7 -5
- package/storage.js.map +1 -1
- package/text.cjs +3 -17
- package/text.cjs.map +1 -1
- package/text.d.ts +1 -16
- package/text.js +3 -17
- package/text.js.map +1 -1
- package/type-guard.cjs +38 -1
- package/type-guard.cjs.map +1 -1
- package/type-guard.d.ts +38 -0
- package/type-guard.js +38 -1
- package/type-guard.js.map +1 -1
- package/types.d.ts +20 -1
- package/types.global.d.ts +19 -0
- package/vibrate.cjs +1 -17
- package/vibrate.cjs.map +1 -1
- package/vibrate.d.ts +0 -16
- package/vibrate.js +1 -17
- package/vibrate.js.map +1 -1
- /package/{chunk-pbuEa-1d.js → chunk-D7D4PA-g.js} +0 -0
- /package/{chunk-CZWwpsFl.cjs → chunk-DakpK96I.cjs} +0 -0
package/async.d.ts
CHANGED
|
@@ -1,83 +1,74 @@
|
|
|
1
|
+
import { MaybeFn, Primitive, MaybePromise } from 'yummies/types';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* @returns Union of all primitive types
|
|
5
|
-
*/
|
|
6
|
-
type Primitive = null | undefined | string | number | boolean | symbol | bigint;
|
|
7
|
-
type Fn<T, TArgs extends any[] = any[]> = (...args: TArgs) => T;
|
|
8
|
-
/**
|
|
9
|
-
* Represents a type that can be either the specified type or a function returning that type.
|
|
10
|
-
*
|
|
11
|
-
* @template T - The type to make possibly a function
|
|
12
|
-
* @template TArgs - Arguments type for the function
|
|
13
|
-
* @returns T or a function that returns T
|
|
14
|
-
*/
|
|
15
|
-
type MaybeFn<T, TArgs extends any[] = any[]> = T | Fn<T, TArgs>;
|
|
16
|
-
/**
|
|
17
|
-
* Represents a type that can be either the specified type or a Promise resolving to that type.
|
|
4
|
+
* A single interpolated segment in {@link asyncTemplate}.
|
|
18
5
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
6
|
+
* - **Primitives** use `String(value)` for output, except that values matching
|
|
7
|
+
* `value === null || value === undefined || value === false` yield no text (early return in `processTemplatePiece`).
|
|
8
|
+
* Other falsy values such as `0` or `''` are still stringified.
|
|
9
|
+
* - **Arrays** are flattened recursively in order.
|
|
10
|
+
* - **Promises** are awaited; the resolved value is processed the same way.
|
|
11
|
+
* - **Async iterables of primitives** are streamed in order; each yielded value uses the same rules
|
|
12
|
+
* as a standalone primitive (`String(...)`, with `null` / `undefined` / `false` omitted).
|
|
13
|
+
* - **Functions** (thunks): if the piece is a function, it is invoked with **no arguments** (`piece()`), and the return
|
|
14
|
+
* value is processed recursively—so you can defer work or return any other {@link AsyncTemplatePiece} shape
|
|
15
|
+
* (see {@link MaybeFn}). At runtime a thunk may also return a `Promise` of a piece; that is covered by
|
|
16
|
+
* {@link MaybePromise} on each template interpolation.
|
|
21
17
|
*/
|
|
22
|
-
type
|
|
18
|
+
type AsyncTemplatePiece = MaybeFn<Primitive | void | AsyncIterable<Primitive> | Promise<Primitive> | AsyncTemplatePiece[]>;
|
|
23
19
|
|
|
24
20
|
/**
|
|
25
|
-
*
|
|
26
|
-
* # yummies/async
|
|
21
|
+
* Tagged template that builds an async iterable of string chunks (like a streaming template engine).
|
|
27
22
|
*
|
|
28
|
-
*
|
|
23
|
+
* Static template parts are yielded as-is. Each interpolated “piece” can be a primitive, a nested array of pieces,
|
|
24
|
+
* a `Promise` of a piece (including a resolved primitive), an async iterable of primitives, or a
|
|
25
|
+
* **zero-arg function** whose result is processed the same way (see {@link AsyncTemplatePiece} / `MaybeFn`).
|
|
29
26
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* `
|
|
33
|
-
* Import only what you need from `yummies/async` so bundlers can drop unused helpers.
|
|
27
|
+
* Interpolation handling matches `processTemplatePiece`: `null`, `undefined`, and `false` add nothing; any other value
|
|
28
|
+
* becomes text via `String(...)`; functions are called once with no arguments before further processing. Collect chunks
|
|
29
|
+
* with `for await...of` or utilities like `Array.fromAsync` where available.
|
|
34
30
|
*
|
|
35
|
-
*
|
|
31
|
+
* @param strings - Cooked template segments from the tag (`strings[0]`, `strings[1]`, …).
|
|
32
|
+
* @param pieces - Values between segments (`pieces[i]` sits between `strings[i]` and `strings[i + 1]`).
|
|
33
|
+
* @returns An async generator yielding string fragments in document order.
|
|
36
34
|
*
|
|
35
|
+
* @example
|
|
36
|
+
* Plain values and promises:
|
|
37
37
|
* ```ts
|
|
38
|
-
*
|
|
38
|
+
* const gen = asyncTemplate`Hello, ${'world'}! Status: ${Promise.resolve(200)}`;
|
|
39
|
+
* let out = '';
|
|
40
|
+
* for await (const chunk of gen) out += chunk;
|
|
41
|
+
* // out === 'Hello, world! Status: 200'
|
|
39
42
|
* ```
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Returns a promise that resolves after `time` milliseconds.
|
|
44
|
-
*
|
|
45
|
-
* When `signal` is passed and becomes aborted before the delay elapses, the promise
|
|
46
|
-
* rejects with `signal.reason` (same as native `fetch` / `AbortController` usage).
|
|
47
|
-
* The timeout is cleared on abort so no resolve happens after cancellation.
|
|
48
|
-
*
|
|
49
|
-
* @param time - Delay in milliseconds. Defaults to `0` (next macrotask tick, same idea as `setTimeout(0)`).
|
|
50
|
-
* @param signal - Optional `AbortSignal` to cancel the wait early.
|
|
51
|
-
* @returns A promise that resolves with `void` when the delay completes, or rejects if aborted.
|
|
52
43
|
*
|
|
53
44
|
* @example
|
|
54
|
-
*
|
|
45
|
+
* Falsy pieces are omitted (`null`, `undefined`, `false`); arrays flatten recursively:
|
|
55
46
|
* ```ts
|
|
56
|
-
*
|
|
57
|
-
*
|
|
47
|
+
* const gen = asyncTemplate`${null}${false}A${['B', ['C']]}`;
|
|
48
|
+
* const out = await Array.fromAsync(gen).then((parts) => parts.join(''));
|
|
49
|
+
* // out === 'ABC'
|
|
58
50
|
* ```
|
|
59
51
|
*
|
|
60
52
|
* @example
|
|
61
|
-
*
|
|
53
|
+
* Stream from an async iterable (e.g. chunked upstream text):
|
|
62
54
|
* ```ts
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* } catch (e) {
|
|
67
|
-
* // aborted — e is signal.reason
|
|
55
|
+
* async function* lines() {
|
|
56
|
+
* yield 'line1\n';
|
|
57
|
+
* yield 'line2\n';
|
|
68
58
|
* }
|
|
69
|
-
*
|
|
59
|
+
* const gen = asyncTemplate`Header\n${lines()}Footer`;
|
|
70
60
|
* ```
|
|
71
|
-
*/
|
|
72
|
-
declare const sleep: (time?: number, signal?: AbortSignal) => Promise<void>;
|
|
73
|
-
/**
|
|
74
|
-
* Creates a promise that resolves after the specified number of milliseconds.
|
|
75
61
|
*
|
|
76
|
-
* @
|
|
77
|
-
*
|
|
78
|
-
*
|
|
62
|
+
* @example
|
|
63
|
+
* Lazy piece via a thunk (invoked as `piece()`):
|
|
64
|
+
* ```ts
|
|
65
|
+
* let n = 0;
|
|
66
|
+
* const gen = asyncTemplate`count=${() => ++n}`;
|
|
67
|
+
* // first consumption yields "count=1", etc.
|
|
68
|
+
* ```
|
|
79
69
|
*/
|
|
80
|
-
declare
|
|
70
|
+
declare function asyncTemplate(strings: TemplateStringsArray, ...pieces: MaybePromise<AsyncTemplatePiece>[]): AsyncGenerator<string, void, unknown>;
|
|
71
|
+
|
|
81
72
|
/**
|
|
82
73
|
* Runs a loop driven by `requestAnimationFrame`: on each frame, `quitFunction` is called first.
|
|
83
74
|
* If it returns a truthy value, the loop stops and no further frames are scheduled.
|
|
@@ -115,32 +106,7 @@ declare const waitAsync: (ms?: number) => Promise<unknown>;
|
|
|
115
106
|
* ```
|
|
116
107
|
*/
|
|
117
108
|
declare const endlessRAF: (quitFunction: () => boolean | void, asMicrotask?: boolean) => void;
|
|
118
|
-
|
|
119
|
-
* Like `setTimeout`, but if `signal` aborts before the delay fires, the timer is cleared
|
|
120
|
-
* and `callback` is never run. If the callback runs normally, the abort listener is removed.
|
|
121
|
-
*
|
|
122
|
-
* Does nothing special if `signal` is omitted — behaves like a plain timeout.
|
|
123
|
-
*
|
|
124
|
-
* @param callback - Function to run once after `delayInMs` (same as `setTimeout` callback).
|
|
125
|
-
* @param delayInMs - Milliseconds to wait. Passed through to `setTimeout` (browser/Node semantics apply).
|
|
126
|
-
* @param signal - When aborted, clears the pending timeout so `callback` is not invoked.
|
|
127
|
-
*
|
|
128
|
-
* @example
|
|
129
|
-
* ```ts
|
|
130
|
-
* const controller = new AbortController();
|
|
131
|
-
* setAbortableTimeout(() => console.log('done'), 500, controller.signal);
|
|
132
|
-
* // later: controller.abort(); // timeout cancelled, log never runs
|
|
133
|
-
* ```
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
* Zero-delay scheduling that can still be cancelled before the macrotask runs:
|
|
137
|
-
* ```ts
|
|
138
|
-
* const ac = new AbortController();
|
|
139
|
-
* setAbortableTimeout(() => startIntro(), 0, ac.signal);
|
|
140
|
-
* // e.g. on teardown: ac.abort();
|
|
141
|
-
* ```
|
|
142
|
-
*/
|
|
143
|
-
declare function setAbortableTimeout(callback: VoidFunction, delayInMs?: number, signal?: AbortSignal): void;
|
|
109
|
+
|
|
144
110
|
/**
|
|
145
111
|
* Like `setInterval`, but when `signal` aborts, the interval is cleared with `clearInterval`
|
|
146
112
|
* and `callback` stops being called. If `signal` is omitted, behaves like a normal interval
|
|
@@ -165,73 +131,74 @@ declare function setAbortableTimeout(callback: VoidFunction, delayInMs?: number,
|
|
|
165
131
|
* ```
|
|
166
132
|
*/
|
|
167
133
|
declare function setAbortableInterval(callback: VoidFunction, delayInMs?: number, signal?: AbortSignal): void;
|
|
134
|
+
|
|
168
135
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* - **Primitives** use `String(value)` for output, except that values matching
|
|
172
|
-
* `value === null || value === undefined || value === false` yield no text (early return in `processTemplatePiece`).
|
|
173
|
-
* Other falsy values such as `0` or `''` are still stringified.
|
|
174
|
-
* - **Arrays** are flattened recursively in order.
|
|
175
|
-
* - **Promises** are awaited; the resolved value is processed the same way.
|
|
176
|
-
* - **Async iterables of primitives** are streamed in order; each yielded value uses the same rules
|
|
177
|
-
* as a standalone primitive (`String(...)`, with `null` / `undefined` / `false` omitted).
|
|
178
|
-
* - **Functions** (thunks): if the piece is a function, it is invoked with **no arguments** (`piece()`), and the return
|
|
179
|
-
* value is processed recursively—so you can defer work or return any other {@link AsyncTemplatePiece} shape
|
|
180
|
-
* (see {@link MaybeFn}). At runtime a thunk may also return a `Promise` of a piece; that is covered by
|
|
181
|
-
* {@link MaybePromise} on each template interpolation.
|
|
182
|
-
*/
|
|
183
|
-
type AsyncTemplatePiece = MaybeFn<Primitive | void | AsyncIterable<Primitive> | Promise<Primitive> | AsyncTemplatePiece[]>;
|
|
184
|
-
/**
|
|
185
|
-
* Tagged template that builds an async iterable of string chunks (like a streaming template engine).
|
|
186
|
-
*
|
|
187
|
-
* Static template parts are yielded as-is. Each interpolated “piece” can be a primitive, a nested array of pieces,
|
|
188
|
-
* a `Promise` of a piece (including a resolved primitive), an async iterable of primitives, or a
|
|
189
|
-
* **zero-arg function** whose result is processed the same way (see {@link AsyncTemplatePiece} / `MaybeFn`).
|
|
136
|
+
* Like `setTimeout`, but if `signal` aborts before the delay fires, the timer is cleared
|
|
137
|
+
* and `callback` is never run. If the callback runs normally, the abort listener is removed.
|
|
190
138
|
*
|
|
191
|
-
*
|
|
192
|
-
* becomes text via `String(...)`; functions are called once with no arguments before further processing. Collect chunks
|
|
193
|
-
* with `for await...of` or utilities like `Array.fromAsync` where available.
|
|
139
|
+
* Does nothing special if `signal` is omitted — behaves like a plain timeout.
|
|
194
140
|
*
|
|
195
|
-
* @param
|
|
196
|
-
* @param
|
|
197
|
-
* @
|
|
141
|
+
* @param callback - Function to run once after `delayInMs` (same as `setTimeout` callback).
|
|
142
|
+
* @param delayInMs - Milliseconds to wait. Passed through to `setTimeout` (browser/Node semantics apply).
|
|
143
|
+
* @param signal - When aborted, clears the pending timeout so `callback` is not invoked.
|
|
198
144
|
*
|
|
199
145
|
* @example
|
|
200
|
-
* Plain values and promises:
|
|
201
146
|
* ```ts
|
|
202
|
-
* const
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* // out === 'Hello, world! Status: 200'
|
|
147
|
+
* const controller = new AbortController();
|
|
148
|
+
* setAbortableTimeout(() => console.log('done'), 500, controller.signal);
|
|
149
|
+
* // later: controller.abort(); // timeout cancelled, log never runs
|
|
206
150
|
* ```
|
|
207
151
|
*
|
|
208
152
|
* @example
|
|
209
|
-
*
|
|
153
|
+
* Zero-delay scheduling that can still be cancelled before the macrotask runs:
|
|
210
154
|
* ```ts
|
|
211
|
-
* const
|
|
212
|
-
*
|
|
213
|
-
* //
|
|
155
|
+
* const ac = new AbortController();
|
|
156
|
+
* setAbortableTimeout(() => startIntro(), 0, ac.signal);
|
|
157
|
+
* // e.g. on teardown: ac.abort();
|
|
214
158
|
* ```
|
|
159
|
+
*/
|
|
160
|
+
declare function setAbortableTimeout(callback: VoidFunction, delayInMs?: number, signal?: AbortSignal): void;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Returns a promise that resolves after `time` milliseconds.
|
|
164
|
+
*
|
|
165
|
+
* When `signal` is passed and becomes aborted before the delay elapses, the promise
|
|
166
|
+
* rejects with `signal.reason` (same as native `fetch` / `AbortController` usage).
|
|
167
|
+
* The timeout is cleared on abort so no resolve happens after cancellation.
|
|
168
|
+
*
|
|
169
|
+
* @param time - Delay in milliseconds. Defaults to `0` (next macrotask tick, same idea as `setTimeout(0)`).
|
|
170
|
+
* @param signal - Optional `AbortSignal` to cancel the wait early.
|
|
171
|
+
* @returns A promise that resolves with `void` when the delay completes, or rejects if aborted.
|
|
215
172
|
*
|
|
216
173
|
* @example
|
|
217
|
-
*
|
|
174
|
+
* Basic pause in an async function:
|
|
218
175
|
* ```ts
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* yield 'line2\n';
|
|
222
|
-
* }
|
|
223
|
-
* const gen = asyncTemplate`Header\n${lines()}Footer`;
|
|
176
|
+
* await sleep(250);
|
|
177
|
+
* console.log('after 250ms');
|
|
224
178
|
* ```
|
|
225
179
|
*
|
|
226
180
|
* @example
|
|
227
|
-
*
|
|
181
|
+
* Cancellable delay tied to component unmount or user action:
|
|
228
182
|
* ```ts
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
183
|
+
* const ac = new AbortController();
|
|
184
|
+
* try {
|
|
185
|
+
* await sleep(5000, ac.signal);
|
|
186
|
+
* } catch (e) {
|
|
187
|
+
* // aborted — e is signal.reason
|
|
188
|
+
* }
|
|
189
|
+
* ac.abort('user cancelled');
|
|
232
190
|
* ```
|
|
233
191
|
*/
|
|
234
|
-
declare
|
|
192
|
+
declare const sleep: (time?: number, signal?: AbortSignal) => Promise<void>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Creates a promise that resolves after the specified number of milliseconds.
|
|
196
|
+
*
|
|
197
|
+
* @deprecated Use `sleep` instead.
|
|
198
|
+
* @param ms Delay in milliseconds.
|
|
199
|
+
* @returns Promise
|
|
200
|
+
*/
|
|
201
|
+
declare const waitAsync: (ms?: number) => Promise<void>;
|
|
235
202
|
|
|
236
203
|
export { asyncTemplate, endlessRAF, setAbortableInterval, setAbortableTimeout, sleep, waitAsync };
|
|
237
204
|
export type { AsyncTemplatePiece };
|
package/async.js
CHANGED
|
@@ -1,55 +1,92 @@
|
|
|
1
|
-
//#region src/async.ts
|
|
1
|
+
//#region src/async/async-template.ts
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Tagged template that builds an async iterable of string chunks (like a streaming template engine).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Static template parts are yielded as-is. Each interpolated “piece” can be a primitive, a nested array of pieces,
|
|
6
|
+
* a `Promise` of a piece (including a resolved primitive), an async iterable of primitives, or a
|
|
7
|
+
* **zero-arg function** whose result is processed the same way (see {@link AsyncTemplatePiece} / `MaybeFn`).
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Interpolation handling matches `processTemplatePiece`: `null`, `undefined`, and `false` add nothing; any other value
|
|
10
|
+
* becomes text via `String(...)`; functions are called once with no arguments before further processing. Collect chunks
|
|
11
|
+
* with `for await...of` or utilities like `Array.fromAsync` where available.
|
|
12
|
+
*
|
|
13
|
+
* @param strings - Cooked template segments from the tag (`strings[0]`, `strings[1]`, …).
|
|
14
|
+
* @param pieces - Values between segments (`pieces[i]` sits between `strings[i]` and `strings[i + 1]`).
|
|
15
|
+
* @returns An async generator yielding string fragments in document order.
|
|
12
16
|
*
|
|
13
17
|
* @example
|
|
14
|
-
*
|
|
18
|
+
* Plain values and promises:
|
|
15
19
|
* ```ts
|
|
16
|
-
*
|
|
17
|
-
*
|
|
20
|
+
* const gen = asyncTemplate`Hello, ${'world'}! Status: ${Promise.resolve(200)}`;
|
|
21
|
+
* let out = '';
|
|
22
|
+
* for await (const chunk of gen) out += chunk;
|
|
23
|
+
* // out === 'Hello, world! Status: 200'
|
|
18
24
|
* ```
|
|
19
25
|
*
|
|
20
26
|
* @example
|
|
21
|
-
*
|
|
27
|
+
* Falsy pieces are omitted (`null`, `undefined`, `false`); arrays flatten recursively:
|
|
22
28
|
* ```ts
|
|
23
|
-
* const
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
29
|
+
* const gen = asyncTemplate`${null}${false}A${['B', ['C']]}`;
|
|
30
|
+
* const out = await Array.fromAsync(gen).then((parts) => parts.join(''));
|
|
31
|
+
* // out === 'ABC'
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* Stream from an async iterable (e.g. chunked upstream text):
|
|
36
|
+
* ```ts
|
|
37
|
+
* async function* lines() {
|
|
38
|
+
* yield 'line1\n';
|
|
39
|
+
* yield 'line2\n';
|
|
28
40
|
* }
|
|
29
|
-
*
|
|
41
|
+
* const gen = asyncTemplate`Header\n${lines()}Footer`;
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* Lazy piece via a thunk (invoked as `piece()`):
|
|
46
|
+
* ```ts
|
|
47
|
+
* let n = 0;
|
|
48
|
+
* const gen = asyncTemplate`count=${() => ++n}`;
|
|
49
|
+
* // first consumption yields "count=1", etc.
|
|
30
50
|
* ```
|
|
31
51
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}, time);
|
|
42
|
-
signal.addEventListener("abort", abortListener, { once: true });
|
|
43
|
-
} else setTimeout(resolve, time);
|
|
44
|
-
});
|
|
52
|
+
async function* asyncTemplate(strings, ...pieces) {
|
|
53
|
+
for (let i = 0; i < strings.length; i++) {
|
|
54
|
+
yield strings[i];
|
|
55
|
+
if (i < pieces.length) {
|
|
56
|
+
const piece = pieces[i];
|
|
57
|
+
yield* processTemplatePiece(piece);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
45
61
|
/**
|
|
46
|
-
*
|
|
62
|
+
* Resolves a template piece into yielded string chunks.
|
|
47
63
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
64
|
+
* Skips output when `value === null || value === undefined || value === false`.
|
|
65
|
+
* Otherwise awaits promises, flattens arrays, streams async iterables, invokes **functions** with no arguments and
|
|
66
|
+
* recurses on the return value, and uses `String(value)` for primitives.
|
|
51
67
|
*/
|
|
52
|
-
|
|
68
|
+
async function* processTemplatePiece(piece) {
|
|
69
|
+
if (piece === null || piece === void 0 || piece === false) return;
|
|
70
|
+
if (piece instanceof Promise) {
|
|
71
|
+
yield* processTemplatePiece(await piece);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (Array.isArray(piece)) {
|
|
75
|
+
for (const item of piece) yield* processTemplatePiece(item);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (typeof piece === "object" && piece !== null && typeof piece[Symbol.asyncIterator] === "function") {
|
|
79
|
+
for await (const item of piece) yield* processTemplatePiece(item);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (typeof piece === "function") {
|
|
83
|
+
yield* processTemplatePiece(piece());
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
yield String(piece);
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/async/endless-raf.ts
|
|
53
90
|
/**
|
|
54
91
|
* Runs a loop driven by `requestAnimationFrame`: on each frame, `quitFunction` is called first.
|
|
55
92
|
* If it returns a truthy value, the loop stops and no further frames are scheduled.
|
|
@@ -92,44 +129,8 @@ var endlessRAF = (quitFunction, asMicrotask) => {
|
|
|
92
129
|
if (asMicrotask) queueMicrotask(raf);
|
|
93
130
|
else raf();
|
|
94
131
|
};
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
* and `callback` is never run. If the callback runs normally, the abort listener is removed.
|
|
98
|
-
*
|
|
99
|
-
* Does nothing special if `signal` is omitted — behaves like a plain timeout.
|
|
100
|
-
*
|
|
101
|
-
* @param callback - Function to run once after `delayInMs` (same as `setTimeout` callback).
|
|
102
|
-
* @param delayInMs - Milliseconds to wait. Passed through to `setTimeout` (browser/Node semantics apply).
|
|
103
|
-
* @param signal - When aborted, clears the pending timeout so `callback` is not invoked.
|
|
104
|
-
*
|
|
105
|
-
* @example
|
|
106
|
-
* ```ts
|
|
107
|
-
* const controller = new AbortController();
|
|
108
|
-
* setAbortableTimeout(() => console.log('done'), 500, controller.signal);
|
|
109
|
-
* // later: controller.abort(); // timeout cancelled, log never runs
|
|
110
|
-
* ```
|
|
111
|
-
*
|
|
112
|
-
* @example
|
|
113
|
-
* Zero-delay scheduling that can still be cancelled before the macrotask runs:
|
|
114
|
-
* ```ts
|
|
115
|
-
* const ac = new AbortController();
|
|
116
|
-
* setAbortableTimeout(() => startIntro(), 0, ac.signal);
|
|
117
|
-
* // e.g. on teardown: ac.abort();
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
|
-
function setAbortableTimeout(callback, delayInMs, signal) {
|
|
121
|
-
let internalTimer = null;
|
|
122
|
-
const handleAbort = () => {
|
|
123
|
-
if (internalTimer == null) return;
|
|
124
|
-
clearTimeout(internalTimer);
|
|
125
|
-
internalTimer = null;
|
|
126
|
-
};
|
|
127
|
-
signal?.addEventListener("abort", handleAbort, { once: true });
|
|
128
|
-
internalTimer = setTimeout(() => {
|
|
129
|
-
signal?.removeEventListener("abort", handleAbort);
|
|
130
|
-
callback();
|
|
131
|
-
}, delayInMs);
|
|
132
|
-
}
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/async/set-abortable-interval.ts
|
|
133
134
|
/**
|
|
134
135
|
* Like `setInterval`, but when `signal` aborts, the interval is cleared with `clearInterval`
|
|
135
136
|
* and `callback` stops being called. If `signal` is omitted, behaves like a normal interval
|
|
@@ -163,92 +164,101 @@ function setAbortableInterval(callback, delayInMs, signal) {
|
|
|
163
164
|
signal?.addEventListener("abort", handleAbort, { once: true });
|
|
164
165
|
timer = setInterval(callback, delayInMs);
|
|
165
166
|
}
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/async/set-abortable-timeout.ts
|
|
166
169
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* Static template parts are yielded as-is. Each interpolated “piece” can be a primitive, a nested array of pieces,
|
|
170
|
-
* a `Promise` of a piece (including a resolved primitive), an async iterable of primitives, or a
|
|
171
|
-
* **zero-arg function** whose result is processed the same way (see {@link AsyncTemplatePiece} / `MaybeFn`).
|
|
170
|
+
* Like `setTimeout`, but if `signal` aborts before the delay fires, the timer is cleared
|
|
171
|
+
* and `callback` is never run. If the callback runs normally, the abort listener is removed.
|
|
172
172
|
*
|
|
173
|
-
*
|
|
174
|
-
* becomes text via `String(...)`; functions are called once with no arguments before further processing. Collect chunks
|
|
175
|
-
* with `for await...of` or utilities like `Array.fromAsync` where available.
|
|
173
|
+
* Does nothing special if `signal` is omitted — behaves like a plain timeout.
|
|
176
174
|
*
|
|
177
|
-
* @param
|
|
178
|
-
* @param
|
|
179
|
-
* @
|
|
175
|
+
* @param callback - Function to run once after `delayInMs` (same as `setTimeout` callback).
|
|
176
|
+
* @param delayInMs - Milliseconds to wait. Passed through to `setTimeout` (browser/Node semantics apply).
|
|
177
|
+
* @param signal - When aborted, clears the pending timeout so `callback` is not invoked.
|
|
180
178
|
*
|
|
181
179
|
* @example
|
|
182
|
-
* Plain values and promises:
|
|
183
180
|
* ```ts
|
|
184
|
-
* const
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* // out === 'Hello, world! Status: 200'
|
|
181
|
+
* const controller = new AbortController();
|
|
182
|
+
* setAbortableTimeout(() => console.log('done'), 500, controller.signal);
|
|
183
|
+
* // later: controller.abort(); // timeout cancelled, log never runs
|
|
188
184
|
* ```
|
|
189
185
|
*
|
|
190
186
|
* @example
|
|
191
|
-
*
|
|
187
|
+
* Zero-delay scheduling that can still be cancelled before the macrotask runs:
|
|
192
188
|
* ```ts
|
|
193
|
-
* const
|
|
194
|
-
*
|
|
195
|
-
* //
|
|
189
|
+
* const ac = new AbortController();
|
|
190
|
+
* setAbortableTimeout(() => startIntro(), 0, ac.signal);
|
|
191
|
+
* // e.g. on teardown: ac.abort();
|
|
196
192
|
* ```
|
|
193
|
+
*/
|
|
194
|
+
function setAbortableTimeout(callback, delayInMs, signal) {
|
|
195
|
+
let internalTimer = null;
|
|
196
|
+
const handleAbort = () => {
|
|
197
|
+
if (internalTimer == null) return;
|
|
198
|
+
clearTimeout(internalTimer);
|
|
199
|
+
internalTimer = null;
|
|
200
|
+
};
|
|
201
|
+
signal?.addEventListener("abort", handleAbort, { once: true });
|
|
202
|
+
internalTimer = setTimeout(() => {
|
|
203
|
+
signal?.removeEventListener("abort", handleAbort);
|
|
204
|
+
callback();
|
|
205
|
+
}, delayInMs);
|
|
206
|
+
}
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/async/sleep.ts
|
|
209
|
+
/**
|
|
210
|
+
* Returns a promise that resolves after `time` milliseconds.
|
|
211
|
+
*
|
|
212
|
+
* When `signal` is passed and becomes aborted before the delay elapses, the promise
|
|
213
|
+
* rejects with `signal.reason` (same as native `fetch` / `AbortController` usage).
|
|
214
|
+
* The timeout is cleared on abort so no resolve happens after cancellation.
|
|
215
|
+
*
|
|
216
|
+
* @param time - Delay in milliseconds. Defaults to `0` (next macrotask tick, same idea as `setTimeout(0)`).
|
|
217
|
+
* @param signal - Optional `AbortSignal` to cancel the wait early.
|
|
218
|
+
* @returns A promise that resolves with `void` when the delay completes, or rejects if aborted.
|
|
197
219
|
*
|
|
198
220
|
* @example
|
|
199
|
-
*
|
|
221
|
+
* Basic pause in an async function:
|
|
200
222
|
* ```ts
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
* yield 'line2\n';
|
|
204
|
-
* }
|
|
205
|
-
* const gen = asyncTemplate`Header\n${lines()}Footer`;
|
|
223
|
+
* await sleep(250);
|
|
224
|
+
* console.log('after 250ms');
|
|
206
225
|
* ```
|
|
207
226
|
*
|
|
208
227
|
* @example
|
|
209
|
-
*
|
|
228
|
+
* Cancellable delay tied to component unmount or user action:
|
|
210
229
|
* ```ts
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
230
|
+
* const ac = new AbortController();
|
|
231
|
+
* try {
|
|
232
|
+
* await sleep(5000, ac.signal);
|
|
233
|
+
* } catch (e) {
|
|
234
|
+
* // aborted — e is signal.reason
|
|
235
|
+
* }
|
|
236
|
+
* ac.abort('user cancelled');
|
|
214
237
|
* ```
|
|
215
238
|
*/
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
239
|
+
var sleep = (time = 0, signal) => new Promise((resolve, reject) => {
|
|
240
|
+
if (signal) {
|
|
241
|
+
const abortListener = () => {
|
|
242
|
+
clearTimeout(timerId);
|
|
243
|
+
reject(signal?.reason);
|
|
244
|
+
};
|
|
245
|
+
const timerId = setTimeout(() => {
|
|
246
|
+
signal.removeEventListener("abort", abortListener);
|
|
247
|
+
resolve();
|
|
248
|
+
}, time);
|
|
249
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
250
|
+
} else setTimeout(resolve, time);
|
|
251
|
+
});
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region src/async/wait-async.ts
|
|
225
254
|
/**
|
|
226
|
-
*
|
|
255
|
+
* Creates a promise that resolves after the specified number of milliseconds.
|
|
227
256
|
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
257
|
+
* @deprecated Use `sleep` instead.
|
|
258
|
+
* @param ms Delay in milliseconds.
|
|
259
|
+
* @returns Promise
|
|
231
260
|
*/
|
|
232
|
-
|
|
233
|
-
if (piece === null || piece === void 0 || piece === false) return;
|
|
234
|
-
if (piece instanceof Promise) {
|
|
235
|
-
yield* processTemplatePiece(await piece);
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
if (Array.isArray(piece)) {
|
|
239
|
-
for (const item of piece) yield* processTemplatePiece(item);
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
if (typeof piece === "object" && piece !== null && typeof piece[Symbol.asyncIterator] === "function") {
|
|
243
|
-
for await (const item of piece) yield* processTemplatePiece(item);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (typeof piece === "function") {
|
|
247
|
-
yield* processTemplatePiece(piece());
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
yield String(piece);
|
|
251
|
-
}
|
|
261
|
+
var waitAsync = (ms = 1e3) => sleep(ms);
|
|
252
262
|
//#endregion
|
|
253
263
|
export { asyncTemplate, endlessRAF, setAbortableInterval, setAbortableTimeout, sleep, waitAsync };
|
|
254
264
|
|