@adviser/cement 0.5.1 → 0.5.3
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/cjs/keyed-ng.test.cjs +6 -5
- package/cjs/keyed-ng.test.cjs.map +1 -1
- package/cjs/on-func.cjs +15 -1
- package/cjs/on-func.cjs.map +1 -1
- package/cjs/on-func.d.ts +1 -0
- package/cjs/on-func.d.ts.map +1 -1
- package/cjs/on-func.test.cjs +34 -0
- package/cjs/on-func.test.cjs.map +1 -1
- package/cjs/resolve-once.cjs +60 -32
- package/cjs/resolve-once.cjs.map +1 -1
- package/cjs/resolve-once.d.ts +30 -19
- package/cjs/resolve-once.d.ts.map +1 -1
- package/cjs/resolve-once.test.cjs +105 -27
- package/cjs/resolve-once.test.cjs.map +1 -1
- package/cjs/result.cjs +6 -0
- package/cjs/result.cjs.map +1 -1
- package/cjs/result.d.ts +2 -0
- package/cjs/result.d.ts.map +1 -1
- package/cjs/timeouted.cjs +13 -18
- package/cjs/timeouted.cjs.map +1 -1
- package/cjs/timeouted.d.ts +23 -27
- package/cjs/timeouted.d.ts.map +1 -1
- package/cjs/timeouted.test.cjs +31 -1
- package/cjs/timeouted.test.cjs.map +1 -1
- package/cjs/utils/to-sorted.d.ts +1 -1
- package/cjs/utils/to-sorted.d.ts.map +1 -1
- package/cjs/version.cjs +1 -1
- package/deno.json +1 -1
- package/esm/keyed-ng.test.js +6 -5
- package/esm/keyed-ng.test.js.map +1 -1
- package/esm/on-func.d.ts +1 -0
- package/esm/on-func.d.ts.map +1 -1
- package/esm/on-func.js +15 -1
- package/esm/on-func.js.map +1 -1
- package/esm/on-func.test.js +34 -0
- package/esm/on-func.test.js.map +1 -1
- package/esm/resolve-once.d.ts +30 -19
- package/esm/resolve-once.d.ts.map +1 -1
- package/esm/resolve-once.js +60 -32
- package/esm/resolve-once.js.map +1 -1
- package/esm/resolve-once.test.js +73 -28
- package/esm/resolve-once.test.js.map +1 -1
- package/esm/result.d.ts +2 -0
- package/esm/result.d.ts.map +1 -1
- package/esm/result.js +6 -0
- package/esm/result.js.map +1 -1
- package/esm/timeouted.d.ts +23 -27
- package/esm/timeouted.d.ts.map +1 -1
- package/esm/timeouted.js +13 -18
- package/esm/timeouted.js.map +1 -1
- package/esm/timeouted.test.js +32 -2
- package/esm/timeouted.test.js.map +1 -1
- package/esm/utils/to-sorted.d.ts +1 -1
- package/esm/utils/to-sorted.d.ts.map +1 -1
- package/esm/version.js +1 -1
- package/package.json +2 -2
- package/src/on-func.ts +39 -1
- package/src/resolve-once.ts +192 -106
- package/src/result.ts +7 -0
- package/src/timeouted.ts +39 -65
- package/src/utils/to-sorted.ts +1 -1
- package/ts/cjs/keyed-ng.test.js +6 -5
- package/ts/cjs/keyed-ng.test.js.map +1 -1
- package/ts/cjs/on-func.d.ts +1 -0
- package/ts/cjs/on-func.d.ts.map +1 -1
- package/ts/cjs/on-func.js +15 -1
- package/ts/cjs/on-func.js.map +1 -1
- package/ts/cjs/on-func.test.js +34 -0
- package/ts/cjs/on-func.test.js.map +1 -1
- package/ts/cjs/resolve-once.d.ts +30 -19
- package/ts/cjs/resolve-once.d.ts.map +1 -1
- package/ts/cjs/resolve-once.js +60 -32
- package/ts/cjs/resolve-once.js.map +1 -1
- package/ts/cjs/resolve-once.test.js +105 -27
- package/ts/cjs/resolve-once.test.js.map +1 -1
- package/ts/cjs/result.d.ts +2 -0
- package/ts/cjs/result.d.ts.map +1 -1
- package/ts/cjs/result.js +6 -0
- package/ts/cjs/result.js.map +1 -1
- package/ts/cjs/timeouted.d.ts +23 -27
- package/ts/cjs/timeouted.d.ts.map +1 -1
- package/ts/cjs/timeouted.js +13 -18
- package/ts/cjs/timeouted.js.map +1 -1
- package/ts/cjs/timeouted.test.js +31 -1
- package/ts/cjs/timeouted.test.js.map +1 -1
- package/ts/cjs/utils/to-sorted.d.ts +1 -1
- package/ts/cjs/utils/to-sorted.d.ts.map +1 -1
- package/ts/cjs/version.js +1 -1
- package/ts/esm/keyed-ng.test.js +6 -5
- package/ts/esm/keyed-ng.test.js.map +1 -1
- package/ts/esm/on-func.d.ts +1 -0
- package/ts/esm/on-func.d.ts.map +1 -1
- package/ts/esm/on-func.js +15 -1
- package/ts/esm/on-func.js.map +1 -1
- package/ts/esm/on-func.test.js +34 -0
- package/ts/esm/on-func.test.js.map +1 -1
- package/ts/esm/resolve-once.d.ts +30 -19
- package/ts/esm/resolve-once.d.ts.map +1 -1
- package/ts/esm/resolve-once.js +60 -32
- package/ts/esm/resolve-once.js.map +1 -1
- package/ts/esm/resolve-once.test.js +73 -28
- package/ts/esm/resolve-once.test.js.map +1 -1
- package/ts/esm/result.d.ts +2 -0
- package/ts/esm/result.d.ts.map +1 -1
- package/ts/esm/result.js +6 -0
- package/ts/esm/result.js.map +1 -1
- package/ts/esm/timeouted.d.ts +23 -27
- package/ts/esm/timeouted.d.ts.map +1 -1
- package/ts/esm/timeouted.js +13 -18
- package/ts/esm/timeouted.js.map +1 -1
- package/ts/esm/timeouted.test.js +32 -2
- package/ts/esm/timeouted.test.js.map +1 -1
- package/ts/esm/utils/to-sorted.d.ts +1 -1
- package/ts/esm/utils/to-sorted.d.ts.map +1 -1
- package/ts/esm/version.js +1 -1
package/src/resolve-once.ts
CHANGED
|
@@ -15,11 +15,13 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { Future } from "./future.js";
|
|
18
|
-
import {
|
|
18
|
+
import { isPromise } from "./is-promise.js";
|
|
19
19
|
import { UnregFn } from "./lru-map-set.js";
|
|
20
20
|
import { Result } from "./result.js";
|
|
21
21
|
import { Option } from "./option.js";
|
|
22
22
|
import { KeyedIf, KeyedNg, KeyedNgItem, KeyedNgItemWithoutValue, KeyedNgOptions } from "./keyed-ng.js";
|
|
23
|
+
import { runtimeFn } from "./runtime.js";
|
|
24
|
+
import { Writable } from "ts-essentials";
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
* Internal item representing a queued function in a ResolveSeq sequence.
|
|
@@ -143,33 +145,58 @@ export class ResolveSeq<T, CTX extends NonNullable<object> = object> {
|
|
|
143
145
|
type ResolveState = "initial" | "processed" | "waiting" | "processing";
|
|
144
146
|
|
|
145
147
|
/**
|
|
146
|
-
* Type helper that
|
|
148
|
+
* Type helper that awaits Promise types and passes through non-Promise types.
|
|
149
|
+
* This ensures that if a function returns a Promise<T>, the once method also returns Promise<T>,
|
|
150
|
+
* and if the function returns T (non-Promise), once returns T directly.
|
|
147
151
|
*
|
|
148
|
-
*
|
|
152
|
+
* Uses the built-in Awaited utility type to properly handle nested Promises and thenable objects.
|
|
153
|
+
*
|
|
154
|
+
* @template R - The type to process
|
|
149
155
|
*
|
|
150
156
|
* @example
|
|
151
157
|
* ```typescript
|
|
152
158
|
* type A = ResultOnce<Promise<number>>; // Promise<number>
|
|
153
159
|
* type B = ResultOnce<string>; // string
|
|
160
|
+
* type C = ResultOnce<number>; // number
|
|
161
|
+
* type D = ResultOnce<Promise<Promise<number>>>; // Promise<number>
|
|
154
162
|
* ```
|
|
155
163
|
*/
|
|
156
|
-
export type ResultOnce<R> = R extends Promise<
|
|
164
|
+
export type ResultOnce<R> = R extends Promise<unknown> ? Promise<Awaited<R>> : R;
|
|
165
|
+
|
|
166
|
+
export interface OnceActionArg<R, CTX> {
|
|
167
|
+
readonly ctx: CTX;
|
|
168
|
+
readonly self: ResolveOnceIf<R, CTX>;
|
|
169
|
+
}
|
|
157
170
|
|
|
171
|
+
// export type OnceAction<R, CTX, RET> = (arg: OnceActionArg<R, CTX>) => RET extends Promise<R> ? Promise<R> : R;
|
|
158
172
|
/**
|
|
159
173
|
* Interface defining the contract for ResolveOnce-like objects.
|
|
160
174
|
* @template R - The return type
|
|
161
175
|
* @template CTX - Optional context type
|
|
162
176
|
*/
|
|
163
|
-
export interface ResolveOnceIf<R, CTX
|
|
177
|
+
export interface ResolveOnceIf<R, CTX> {
|
|
164
178
|
get ready(): boolean;
|
|
165
|
-
get value():
|
|
179
|
+
get value(): R | undefined;
|
|
166
180
|
get error(): Error | undefined;
|
|
167
181
|
get state(): ResolveState;
|
|
168
182
|
|
|
169
|
-
|
|
170
|
-
|
|
183
|
+
setResetAfter(ms?: number): void;
|
|
184
|
+
|
|
185
|
+
once<RET extends R | Promise<R>>(fn: (arg: OnceActionArg<R, CTX>) => RET): ResultOnce<RET>;
|
|
186
|
+
reset<RET extends R | Promise<R>>(fn?: (arg: OnceActionArg<R, CTX>) => RET): ResultOnce<RET>;
|
|
187
|
+
|
|
188
|
+
setProcessed(state: StateInstance): void;
|
|
171
189
|
}
|
|
172
190
|
|
|
191
|
+
export interface SyncOrAsyncIf<T> {
|
|
192
|
+
get value(): T | undefined;
|
|
193
|
+
get error(): Error | undefined;
|
|
194
|
+
get queueLength(): number;
|
|
195
|
+
|
|
196
|
+
resolve<RET extends T | Promise<T>>(fn: () => RET): ResultOnce<RET>;
|
|
197
|
+
}
|
|
198
|
+
export type SyncOrAsync<T> = Option<SyncOrAsyncIf<T>>;
|
|
199
|
+
|
|
173
200
|
/**
|
|
174
201
|
* Synchronous version of ResolveOnce for functions that return non-promise values.
|
|
175
202
|
*
|
|
@@ -180,7 +207,7 @@ export interface ResolveOnceIf<R, CTX = void> {
|
|
|
180
207
|
* @template CTX - Optional context type
|
|
181
208
|
* @internal
|
|
182
209
|
*/
|
|
183
|
-
export class SyncResolveOnce<T, CTX
|
|
210
|
+
export class SyncResolveOnce<T, CTX> implements SyncOrAsyncIf<T> {
|
|
184
211
|
#value?: T;
|
|
185
212
|
#error?: Error;
|
|
186
213
|
|
|
@@ -223,10 +250,10 @@ export class SyncResolveOnce<T, CTX = void> {
|
|
|
223
250
|
* @returns The result of the function
|
|
224
251
|
* @throws Error if the function returned a promise (use AsyncResolveOnce instead)
|
|
225
252
|
*/
|
|
226
|
-
resolve(fn: (
|
|
253
|
+
resolve<RET extends T | Promise<T>>(fn: () => RET): ResultOnce<RET> {
|
|
227
254
|
if (this.#state.isProcessing()) {
|
|
228
255
|
try {
|
|
229
|
-
this.#value = fn(
|
|
256
|
+
this.#value = fn() as unknown as T;
|
|
230
257
|
} catch (e) {
|
|
231
258
|
this.#error = e as Error;
|
|
232
259
|
} finally {
|
|
@@ -240,24 +267,24 @@ export class SyncResolveOnce<T, CTX = void> {
|
|
|
240
267
|
if (this.#error) {
|
|
241
268
|
throw this.#error;
|
|
242
269
|
}
|
|
243
|
-
return this.#value as
|
|
270
|
+
return this.#value as ResultOnce<RET>;
|
|
244
271
|
}
|
|
245
272
|
|
|
246
|
-
/**
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
reset(fn?: (
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
273
|
+
// /**
|
|
274
|
+
// * Resets the cached state, allowing the function to be executed again.
|
|
275
|
+
// *
|
|
276
|
+
// * @param fn - Optional function to execute immediately after reset
|
|
277
|
+
// * @returns The result if fn provided, undefined otherwise
|
|
278
|
+
// */
|
|
279
|
+
// reset(fn?: () => RET): T | undefined {
|
|
280
|
+
// this.#value = undefined;
|
|
281
|
+
// this.#error = undefined;
|
|
282
|
+
// if (fn) {
|
|
283
|
+
// this.#state.setProcessing();
|
|
284
|
+
// return this.resolve(fn);
|
|
285
|
+
// }
|
|
286
|
+
// return undefined as T;
|
|
287
|
+
// }
|
|
261
288
|
}
|
|
262
289
|
|
|
263
290
|
/**
|
|
@@ -267,19 +294,19 @@ export class SyncResolveOnce<T, CTX = void> {
|
|
|
267
294
|
*/
|
|
268
295
|
class AsyncResolveItem<T, CTX> {
|
|
269
296
|
readonly id: number = Math.random();
|
|
270
|
-
readonly #toResolve: Promise<
|
|
271
|
-
#value: Option<
|
|
297
|
+
readonly #toResolve: Promise<T>;
|
|
298
|
+
#value: Option<T> = Option.None();
|
|
272
299
|
#error?: Error;
|
|
273
300
|
readonly #state: StateInstance;
|
|
274
|
-
readonly #rOnce:
|
|
301
|
+
readonly #rOnce: ResolveOnceIf<T, CTX>;
|
|
275
302
|
|
|
276
|
-
constructor(fn: Promise<
|
|
303
|
+
constructor(fn: Promise<T>, rOnce: ResolveOnceIf<T, CTX>, state: StateInstance) {
|
|
277
304
|
this.#toResolve = fn;
|
|
278
305
|
this.#state = state;
|
|
279
306
|
this.#rOnce = rOnce;
|
|
280
307
|
}
|
|
281
308
|
|
|
282
|
-
get value():
|
|
309
|
+
get value(): T | undefined {
|
|
283
310
|
return this.#value.IsSome() ? this.#value.unwrap() : undefined;
|
|
284
311
|
}
|
|
285
312
|
|
|
@@ -287,7 +314,7 @@ class AsyncResolveItem<T, CTX> {
|
|
|
287
314
|
return this.#error;
|
|
288
315
|
}
|
|
289
316
|
|
|
290
|
-
readonly #queue: Future<
|
|
317
|
+
readonly #queue: Future<T>[] = [];
|
|
291
318
|
|
|
292
319
|
get queuelength(): number {
|
|
293
320
|
return this.#queue.length;
|
|
@@ -300,7 +327,7 @@ class AsyncResolveItem<T, CTX> {
|
|
|
300
327
|
return this.#state.isProcessed() && this.#queue.length === 0;
|
|
301
328
|
}
|
|
302
329
|
|
|
303
|
-
#resolveFuture(future?: Future<
|
|
330
|
+
#resolveFuture(future?: Future<T>): void {
|
|
304
331
|
if (!future) {
|
|
305
332
|
return;
|
|
306
333
|
}
|
|
@@ -313,7 +340,7 @@ class AsyncResolveItem<T, CTX> {
|
|
|
313
340
|
}
|
|
314
341
|
}
|
|
315
342
|
|
|
316
|
-
#promiseResult(): Promise<
|
|
343
|
+
#promiseResult(): Promise<T> {
|
|
317
344
|
if (this.#error) {
|
|
318
345
|
return Promise.reject(this.#error);
|
|
319
346
|
}
|
|
@@ -326,9 +353,9 @@ class AsyncResolveItem<T, CTX> {
|
|
|
326
353
|
/**
|
|
327
354
|
* Resolves the async operation, queuing the request if already in progress.
|
|
328
355
|
*/
|
|
329
|
-
resolve():
|
|
356
|
+
resolve<RET extends T | Promise<T>>(_fn: () => RET): ResultOnce<RET> {
|
|
330
357
|
if (this.#state.isWaiting()) {
|
|
331
|
-
const future = new Future<
|
|
358
|
+
const future = new Future<T>();
|
|
332
359
|
this.#queue.push(future);
|
|
333
360
|
this.#toResolve
|
|
334
361
|
.then((value) => {
|
|
@@ -344,11 +371,11 @@ class AsyncResolveItem<T, CTX> {
|
|
|
344
371
|
this.#resolveFuture(this.#queue.shift());
|
|
345
372
|
}
|
|
346
373
|
});
|
|
347
|
-
return future.asPromise() as
|
|
374
|
+
return future.asPromise() as ResultOnce<RET>;
|
|
348
375
|
}
|
|
349
376
|
|
|
350
377
|
if (this.#state.isProcessed()) {
|
|
351
|
-
return this.#promiseResult() as
|
|
378
|
+
return this.#promiseResult() as ResultOnce<RET>;
|
|
352
379
|
}
|
|
353
380
|
// if (this.#state.isWaiting()) {
|
|
354
381
|
// const future = new Future<UnPromisify<T>>();
|
|
@@ -371,23 +398,23 @@ class AsyncResolveItem<T, CTX> {
|
|
|
371
398
|
* @internal
|
|
372
399
|
*/
|
|
373
400
|
|
|
374
|
-
function isAsyncResolveOnce<T, CTX>(obj: SyncOrAsync<T
|
|
401
|
+
function isAsyncResolveOnce<T, CTX>(obj: SyncOrAsync<T>): obj is Option<AsyncResolveOnce<T, CTX>> {
|
|
375
402
|
return obj.IsSome() && obj.Unwrap() instanceof AsyncResolveOnce;
|
|
376
403
|
}
|
|
377
404
|
|
|
378
|
-
export class AsyncResolveOnce<T, CTX
|
|
405
|
+
export class AsyncResolveOnce<T, CTX> implements SyncOrAsyncIf<T> {
|
|
379
406
|
// #state: ResolveState = "initial";
|
|
380
407
|
readonly #state: StateInstance;
|
|
381
408
|
|
|
382
409
|
readonly #queue: AsyncResolveItem<T, CTX>[];
|
|
383
410
|
|
|
384
|
-
readonly #rOnce:
|
|
385
|
-
//readonly #ctx?:
|
|
386
|
-
constructor(rOnce:
|
|
411
|
+
readonly #rOnce: ResolveOnceIf<T, CTX>;
|
|
412
|
+
//readonly #ctx?: RET;
|
|
413
|
+
constructor(rOnce: ResolveOnceIf<T, CTX>, state: StateInstance, prev: SyncOrAsync<T>) {
|
|
387
414
|
this.#state = state;
|
|
388
415
|
this.#rOnce = rOnce;
|
|
389
416
|
if (isAsyncResolveOnce(prev)) {
|
|
390
|
-
this.#queue = [...prev.unwrap().#queue];
|
|
417
|
+
this.#queue = [...(prev.unwrap().#queue as AsyncResolveItem<T, CTX>[])];
|
|
391
418
|
} else {
|
|
392
419
|
this.#queue = [];
|
|
393
420
|
}
|
|
@@ -411,7 +438,7 @@ export class AsyncResolveOnce<T, CTX = void> {
|
|
|
411
438
|
/**
|
|
412
439
|
* Gets the cached resolved value if available.
|
|
413
440
|
*/
|
|
414
|
-
get value():
|
|
441
|
+
get value(): T | undefined {
|
|
415
442
|
if (this.#state.isInitial()) {
|
|
416
443
|
return undefined;
|
|
417
444
|
}
|
|
@@ -435,16 +462,16 @@ export class AsyncResolveOnce<T, CTX = void> {
|
|
|
435
462
|
* @param fn - The async function to execute
|
|
436
463
|
* @returns A promise that resolves to the function's result
|
|
437
464
|
*/
|
|
438
|
-
resolve(fn: (
|
|
465
|
+
resolve<RET extends T | Promise<T>>(fn: () => RET): ResultOnce<RET> {
|
|
439
466
|
if (this.#state.isProcessing()) {
|
|
440
467
|
this.#state.setWaiting();
|
|
441
|
-
let promiseResult: Promise<
|
|
468
|
+
let promiseResult: Promise<T>;
|
|
442
469
|
try {
|
|
443
|
-
const couldBePromise = fn(
|
|
470
|
+
const couldBePromise = fn();
|
|
444
471
|
if (!isPromise(couldBePromise)) {
|
|
445
|
-
promiseResult = Promise.resolve(couldBePromise as
|
|
472
|
+
promiseResult = Promise.resolve(couldBePromise) as Promise<T>;
|
|
446
473
|
} else {
|
|
447
|
-
promiseResult = couldBePromise as Promise<
|
|
474
|
+
promiseResult = couldBePromise as Promise<T>;
|
|
448
475
|
}
|
|
449
476
|
} catch (e) {
|
|
450
477
|
promiseResult = Promise.reject(e as Error);
|
|
@@ -459,22 +486,22 @@ export class AsyncResolveOnce<T, CTX = void> {
|
|
|
459
486
|
.reverse()
|
|
460
487
|
.forEach((idx) => this.#queue.splice(idx, 1));
|
|
461
488
|
|
|
462
|
-
return this.#active().resolve();
|
|
489
|
+
return this.#active().resolve(fn);
|
|
463
490
|
}
|
|
464
491
|
|
|
465
|
-
/**
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
reset(fn?: (
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
}
|
|
492
|
+
// /**
|
|
493
|
+
// * Resets the cached state, allowing the function to be executed again.
|
|
494
|
+
// *
|
|
495
|
+
// * @param fn - Optional function to execute immediately after reset
|
|
496
|
+
// * @returns The result if fn provided, undefined otherwise
|
|
497
|
+
// */
|
|
498
|
+
// reset(fn?: () => ResultOnce<T>): T {
|
|
499
|
+
// this.#state.setProcessing();
|
|
500
|
+
// if (fn) {
|
|
501
|
+
// return this.resolve(fn);
|
|
502
|
+
// }
|
|
503
|
+
// return undefined as T;
|
|
504
|
+
// }
|
|
478
505
|
}
|
|
479
506
|
|
|
480
507
|
/**
|
|
@@ -504,6 +531,7 @@ export class AsyncResolveOnce<T, CTX = void> {
|
|
|
504
531
|
|
|
505
532
|
export interface ResolveOnceOpts {
|
|
506
533
|
readonly resetAfter?: number; // milliseconds after which to reset the cached value
|
|
534
|
+
readonly skipUnref?: boolean; // skip unref() on the reset timer
|
|
507
535
|
}
|
|
508
536
|
|
|
509
537
|
class StateInstance {
|
|
@@ -548,20 +576,24 @@ class StateInstance {
|
|
|
548
576
|
}
|
|
549
577
|
}
|
|
550
578
|
|
|
551
|
-
type SyncOrAsync<T, CTX> = Option<SyncResolveOnce<T, CTX> | AsyncResolveOnce<T, CTX>>;
|
|
579
|
+
// type SyncOrAsync<T, CTX> = Option<SyncResolveOnce<T, CTX> | AsyncResolveOnce<T, CTX>>;
|
|
552
580
|
|
|
553
581
|
export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
|
|
554
582
|
#state = new StateInstance();
|
|
555
583
|
|
|
556
|
-
#syncOrAsync: SyncOrAsync<T
|
|
584
|
+
#syncOrAsync: SyncOrAsync<T> = Option.None();
|
|
557
585
|
|
|
558
|
-
readonly #opts: ResolveOnceOpts
|
|
586
|
+
readonly #opts: Writable<ResolveOnceOpts>;
|
|
559
587
|
resetAfterTimer?: ReturnType<typeof setTimeout>;
|
|
560
588
|
|
|
561
|
-
readonly
|
|
589
|
+
readonly _onceArg: OnceActionArg<T, CTX>;
|
|
590
|
+
|
|
562
591
|
constructor(ctx?: CTX, opts?: ResolveOnceOpts) {
|
|
563
|
-
this
|
|
564
|
-
this
|
|
592
|
+
this.#opts = { ...(opts ?? {}) };
|
|
593
|
+
this._onceArg = {
|
|
594
|
+
ctx: ctx as CTX,
|
|
595
|
+
self: this,
|
|
596
|
+
};
|
|
565
597
|
}
|
|
566
598
|
|
|
567
599
|
get state(): ResolveState {
|
|
@@ -583,8 +615,49 @@ export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
|
|
|
583
615
|
this.#state.setProcessed();
|
|
584
616
|
if (typeof this.#opts.resetAfter === "number" && this.#opts.resetAfter > 0) {
|
|
585
617
|
this.resetAfterTimer = setTimeout(() => {
|
|
586
|
-
this.reset();
|
|
618
|
+
void this.reset();
|
|
587
619
|
}, this.#opts.resetAfter);
|
|
620
|
+
if (!this.#opts.skipUnref && this.resetAfterTimer) {
|
|
621
|
+
// node solution
|
|
622
|
+
const runtime = runtimeFn();
|
|
623
|
+
switch (true) {
|
|
624
|
+
case runtime.isDeno:
|
|
625
|
+
{
|
|
626
|
+
let id = this.resetAfterTimer as unknown as number;
|
|
627
|
+
if (typeof Deno.unrefTimer === "function") {
|
|
628
|
+
if (typeof this.resetAfterTimer === "number") {
|
|
629
|
+
id = this.resetAfterTimer;
|
|
630
|
+
} else {
|
|
631
|
+
try {
|
|
632
|
+
const ret = Reflect.ownKeys(this.resetAfterTimer).find((key) => {
|
|
633
|
+
return key.toString().includes("timerId");
|
|
634
|
+
});
|
|
635
|
+
if (ret) {
|
|
636
|
+
id = this.resetAfterTimer[ret as keyof typeof this.resetAfterTimer] as unknown as number;
|
|
637
|
+
// eslint-disable-next-line no-console
|
|
638
|
+
console.warn("Deno.unrefTimer timerId from struct:", id, "version:", globalThis.Deno?.version);
|
|
639
|
+
}
|
|
640
|
+
} catch (e) {
|
|
641
|
+
// eslint-disable-next-line no-console
|
|
642
|
+
console.warn(
|
|
643
|
+
"Deno.unrefTimer failed to get timerId",
|
|
644
|
+
e,
|
|
645
|
+
"id:",
|
|
646
|
+
this.resetAfterTimer,
|
|
647
|
+
"version:",
|
|
648
|
+
globalThis.Deno?.version,
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
Deno.unrefTimer(id);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
break;
|
|
656
|
+
case runtime.isNodeIsh:
|
|
657
|
+
(this.resetAfterTimer as unknown as { unref: () => void }).unref();
|
|
658
|
+
break;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
588
661
|
}
|
|
589
662
|
}
|
|
590
663
|
}
|
|
@@ -593,11 +666,11 @@ export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
|
|
|
593
666
|
return !this.#state.isInitial();
|
|
594
667
|
}
|
|
595
668
|
|
|
596
|
-
get value():
|
|
669
|
+
get value(): T | undefined {
|
|
597
670
|
if (this.#state.isInitial()) {
|
|
598
671
|
return undefined;
|
|
599
672
|
}
|
|
600
|
-
return this.#syncOrAsync.Unwrap().value
|
|
673
|
+
return this.#syncOrAsync.Unwrap().value;
|
|
601
674
|
}
|
|
602
675
|
|
|
603
676
|
get queueLength(): number {
|
|
@@ -634,58 +707,69 @@ export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
|
|
|
634
707
|
// this.#state = value;
|
|
635
708
|
// }
|
|
636
709
|
|
|
637
|
-
once<
|
|
638
|
-
let resultFn: (
|
|
710
|
+
once<RET extends T | Promise<T>>(fn: (arg: OnceActionArg<T, CTX>) => RET): ResultOnce<RET> {
|
|
711
|
+
let resultFn: () => RET;
|
|
639
712
|
if (this.#state.isInitial()) {
|
|
640
713
|
const state = this.#state;
|
|
641
714
|
try {
|
|
642
715
|
state.setProcessing();
|
|
643
|
-
let prev: T | undefined = undefined;
|
|
644
|
-
if (this.#syncOrAsync.IsSome()) {
|
|
645
|
-
|
|
646
|
-
}
|
|
647
|
-
const isSyncOrAsync = fn(this.
|
|
716
|
+
// let prev: T | undefined = undefined;
|
|
717
|
+
// if (this.#syncOrAsync.IsSome()) {
|
|
718
|
+
// prev = this.#syncOrAsync.Unwrap().value as T;
|
|
719
|
+
// }
|
|
720
|
+
const isSyncOrAsync = fn(this._onceArg);
|
|
648
721
|
if (isPromise(isSyncOrAsync)) {
|
|
649
722
|
this.#syncOrAsync = Option.Some(new AsyncResolveOnce<T, CTX>(this, state, this.#syncOrAsync));
|
|
650
723
|
} else {
|
|
651
724
|
this.#syncOrAsync = Option.Some(new SyncResolveOnce<T, CTX>(this, state));
|
|
652
725
|
}
|
|
653
|
-
resultFn = ():
|
|
726
|
+
resultFn = (): RET => isSyncOrAsync;
|
|
654
727
|
} catch (e) {
|
|
655
728
|
this.#syncOrAsync = Option.Some(new SyncResolveOnce<T, CTX>(this, state));
|
|
656
|
-
resultFn = ():
|
|
729
|
+
resultFn = (): RET => {
|
|
657
730
|
throw e;
|
|
658
731
|
};
|
|
659
732
|
}
|
|
660
733
|
} else {
|
|
661
|
-
resultFn = fn;
|
|
734
|
+
resultFn = (): RET => fn(this._onceArg);
|
|
662
735
|
}
|
|
663
736
|
if (!this.#syncOrAsync) {
|
|
664
737
|
throw new Error(`ResolveOnce.once impossible: state=${this.#state.getResolveState()}`);
|
|
665
738
|
}
|
|
666
|
-
return this.#syncOrAsync.Unwrap().resolve(resultFn
|
|
739
|
+
return this.#syncOrAsync.Unwrap().resolve(resultFn);
|
|
667
740
|
}
|
|
668
741
|
|
|
669
|
-
reset<
|
|
742
|
+
reset<RET extends T | Promise<T>>(fn?: (arg: OnceActionArg<T, CTX>) => RET): ResultOnce<RET> {
|
|
670
743
|
if (this.#state.isInitial()) {
|
|
671
744
|
if (!fn) {
|
|
672
|
-
return undefined as ResultOnce<
|
|
745
|
+
return undefined as ResultOnce<RET>;
|
|
673
746
|
}
|
|
674
|
-
return this.once(fn
|
|
747
|
+
return this.once(fn);
|
|
675
748
|
}
|
|
676
749
|
if (this.#state.isProcessing()) {
|
|
677
750
|
// eslint-disable-next-line no-console
|
|
678
751
|
console.warn("ResolveOnce.reset dropped was called while processing");
|
|
679
|
-
return undefined as ResultOnce<
|
|
752
|
+
return undefined as ResultOnce<RET>;
|
|
680
753
|
}
|
|
681
|
-
let ret = undefined as ResultOnce<
|
|
754
|
+
let ret = undefined as ResultOnce<RET>;
|
|
682
755
|
this.#state = new StateInstance();
|
|
683
756
|
if (fn) {
|
|
684
|
-
ret = this.once(fn
|
|
757
|
+
ret = this.once(fn);
|
|
685
758
|
// ret = this.#syncOrAsync.Unwrap().reset(fn as (c?: CTX) => never) as ResultOnce<R>
|
|
686
759
|
}
|
|
687
760
|
return ret;
|
|
688
761
|
}
|
|
762
|
+
|
|
763
|
+
setResetAfter(ms?: number): void {
|
|
764
|
+
if (this.resetAfterTimer) {
|
|
765
|
+
clearTimeout(this.resetAfterTimer);
|
|
766
|
+
}
|
|
767
|
+
if (typeof ms === "number" && ms > 0) {
|
|
768
|
+
this.#opts.resetAfter = ms;
|
|
769
|
+
} else {
|
|
770
|
+
this.#opts.resetAfter = undefined;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
689
773
|
}
|
|
690
774
|
|
|
691
775
|
// /**
|
|
@@ -788,19 +872,21 @@ export interface KeyedResolveOnceItem<K, T, CTX extends NonNullable<object>> {
|
|
|
788
872
|
* .once(({ givenKey, ctx }) => fetchUser(givenKey, ctx));
|
|
789
873
|
* ```
|
|
790
874
|
*/
|
|
791
|
-
export class KeyedResolvOnce<
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
875
|
+
export class KeyedResolvOnce<
|
|
876
|
+
T extends WithOptionalReset<PT>,
|
|
877
|
+
K = string,
|
|
878
|
+
CTX extends NonNullable<object> = object,
|
|
879
|
+
PT = T,
|
|
880
|
+
> implements Omit<
|
|
881
|
+
// KeyedIf<ResolveOnce<T, KeyedNgItemWithoutValue<K, CTX>>, WithOptionalReset<T>, K>
|
|
882
|
+
KeyedIf<
|
|
883
|
+
KeyedNgItem<K, ResolveOnce<T, KeyedNgItemWithoutValue<K, CTX>>, CTX>,
|
|
884
|
+
ResolveOnce<T, KeyedNgItemWithoutValue<K, CTX>>,
|
|
885
|
+
K,
|
|
886
|
+
CTX
|
|
887
|
+
>,
|
|
888
|
+
"entries" | "forEach" | "onSet" | "onDelete" | "values" | "setParam"
|
|
889
|
+
> {
|
|
804
890
|
/** @internal */
|
|
805
891
|
readonly _keyed: KeyedNg<K, ResolveOnce<WithOptionalReset<T>, KeyedNgItemWithoutValue<K, CTX>>, CTX>;
|
|
806
892
|
|
|
@@ -981,7 +1067,7 @@ export class KeyedResolvOnce<T extends WithOptionalReset<PT>, K = string, CTX ex
|
|
|
981
1067
|
*/
|
|
982
1068
|
unget(key: K): void {
|
|
983
1069
|
const item = this._keyed.getItem(key);
|
|
984
|
-
item.value.reset?.();
|
|
1070
|
+
void item.value.reset?.();
|
|
985
1071
|
return this._keyed.delete(item.givenKey);
|
|
986
1072
|
}
|
|
987
1073
|
|
|
@@ -993,7 +1079,7 @@ export class KeyedResolvOnce<T extends WithOptionalReset<PT>, K = string, CTX ex
|
|
|
993
1079
|
*/
|
|
994
1080
|
reset(): void {
|
|
995
1081
|
for (const v of this._keyed.values()) {
|
|
996
|
-
v.value.reset?.();
|
|
1082
|
+
void v.value.reset?.();
|
|
997
1083
|
}
|
|
998
1084
|
}
|
|
999
1085
|
|
package/src/result.ts
CHANGED
|
@@ -57,6 +57,13 @@ export abstract class Result<T, E = Error> {
|
|
|
57
57
|
return false;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
static AsyncOk<T = void, E = Error>(...args: T[]): Promise<Result<T, E>> {
|
|
61
|
+
return Promise.resolve(Result.Ok<T, E>(...args));
|
|
62
|
+
}
|
|
63
|
+
static AsyncErr<T, E extends Error = Error>(t: E | string | Result<unknown, E>): Promise<Result<T, E>> {
|
|
64
|
+
return Promise.resolve(Result.Err<T, E>(t));
|
|
65
|
+
}
|
|
66
|
+
|
|
60
67
|
isOk(): boolean {
|
|
61
68
|
return this.is_ok();
|
|
62
69
|
}
|