@adviser/cement 0.5.2 → 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 +58 -39
- package/cjs/resolve-once.cjs.map +1 -1
- package/cjs/resolve-once.d.ts +29 -19
- package/cjs/resolve-once.d.ts.map +1 -1
- package/cjs/resolve-once.test.cjs +50 -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 +30 -0
- 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 +29 -19
- package/esm/resolve-once.d.ts.map +1 -1
- package/esm/resolve-once.js +58 -39
- package/esm/resolve-once.js.map +1 -1
- package/esm/resolve-once.test.js +50 -27
- 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 +31 -1
- 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 +189 -113
- 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 +29 -19
- package/ts/cjs/resolve-once.d.ts.map +1 -1
- package/ts/cjs/resolve-once.js +58 -39
- package/ts/cjs/resolve-once.js.map +1 -1
- package/ts/cjs/resolve-once.test.js +50 -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 +30 -0
- 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 +29 -19
- package/ts/esm/resolve-once.d.ts.map +1 -1
- package/ts/esm/resolve-once.js +58 -39
- package/ts/esm/resolve-once.js.map +1 -1
- package/ts/esm/resolve-once.test.js +50 -27
- 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 +31 -1
- 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
|
/**
|
|
@@ -549,20 +576,24 @@ class StateInstance {
|
|
|
549
576
|
}
|
|
550
577
|
}
|
|
551
578
|
|
|
552
|
-
type SyncOrAsync<T, CTX> = Option<SyncResolveOnce<T, CTX> | AsyncResolveOnce<T, CTX>>;
|
|
579
|
+
// type SyncOrAsync<T, CTX> = Option<SyncResolveOnce<T, CTX> | AsyncResolveOnce<T, CTX>>;
|
|
553
580
|
|
|
554
581
|
export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
|
|
555
582
|
#state = new StateInstance();
|
|
556
583
|
|
|
557
|
-
#syncOrAsync: SyncOrAsync<T
|
|
584
|
+
#syncOrAsync: SyncOrAsync<T> = Option.None();
|
|
558
585
|
|
|
559
|
-
readonly #opts: ResolveOnceOpts
|
|
586
|
+
readonly #opts: Writable<ResolveOnceOpts>;
|
|
560
587
|
resetAfterTimer?: ReturnType<typeof setTimeout>;
|
|
561
588
|
|
|
562
|
-
readonly
|
|
589
|
+
readonly _onceArg: OnceActionArg<T, CTX>;
|
|
590
|
+
|
|
563
591
|
constructor(ctx?: CTX, opts?: ResolveOnceOpts) {
|
|
564
|
-
this
|
|
565
|
-
this
|
|
592
|
+
this.#opts = { ...(opts ?? {}) };
|
|
593
|
+
this._onceArg = {
|
|
594
|
+
ctx: ctx as CTX,
|
|
595
|
+
self: this,
|
|
596
|
+
};
|
|
566
597
|
}
|
|
567
598
|
|
|
568
599
|
get state(): ResolveState {
|
|
@@ -584,15 +615,47 @@ export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
|
|
|
584
615
|
this.#state.setProcessed();
|
|
585
616
|
if (typeof this.#opts.resetAfter === "number" && this.#opts.resetAfter > 0) {
|
|
586
617
|
this.resetAfterTimer = setTimeout(() => {
|
|
587
|
-
this.reset();
|
|
618
|
+
void this.reset();
|
|
588
619
|
}, this.#opts.resetAfter);
|
|
589
|
-
if (!this.#opts.skipUnref) {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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;
|
|
596
659
|
}
|
|
597
660
|
}
|
|
598
661
|
}
|
|
@@ -603,11 +666,11 @@ export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
|
|
|
603
666
|
return !this.#state.isInitial();
|
|
604
667
|
}
|
|
605
668
|
|
|
606
|
-
get value():
|
|
669
|
+
get value(): T | undefined {
|
|
607
670
|
if (this.#state.isInitial()) {
|
|
608
671
|
return undefined;
|
|
609
672
|
}
|
|
610
|
-
return this.#syncOrAsync.Unwrap().value
|
|
673
|
+
return this.#syncOrAsync.Unwrap().value;
|
|
611
674
|
}
|
|
612
675
|
|
|
613
676
|
get queueLength(): number {
|
|
@@ -644,58 +707,69 @@ export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
|
|
|
644
707
|
// this.#state = value;
|
|
645
708
|
// }
|
|
646
709
|
|
|
647
|
-
once<
|
|
648
|
-
let resultFn: (
|
|
710
|
+
once<RET extends T | Promise<T>>(fn: (arg: OnceActionArg<T, CTX>) => RET): ResultOnce<RET> {
|
|
711
|
+
let resultFn: () => RET;
|
|
649
712
|
if (this.#state.isInitial()) {
|
|
650
713
|
const state = this.#state;
|
|
651
714
|
try {
|
|
652
715
|
state.setProcessing();
|
|
653
|
-
let prev: T | undefined = undefined;
|
|
654
|
-
if (this.#syncOrAsync.IsSome()) {
|
|
655
|
-
|
|
656
|
-
}
|
|
657
|
-
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);
|
|
658
721
|
if (isPromise(isSyncOrAsync)) {
|
|
659
722
|
this.#syncOrAsync = Option.Some(new AsyncResolveOnce<T, CTX>(this, state, this.#syncOrAsync));
|
|
660
723
|
} else {
|
|
661
724
|
this.#syncOrAsync = Option.Some(new SyncResolveOnce<T, CTX>(this, state));
|
|
662
725
|
}
|
|
663
|
-
resultFn = ():
|
|
726
|
+
resultFn = (): RET => isSyncOrAsync;
|
|
664
727
|
} catch (e) {
|
|
665
728
|
this.#syncOrAsync = Option.Some(new SyncResolveOnce<T, CTX>(this, state));
|
|
666
|
-
resultFn = ():
|
|
729
|
+
resultFn = (): RET => {
|
|
667
730
|
throw e;
|
|
668
731
|
};
|
|
669
732
|
}
|
|
670
733
|
} else {
|
|
671
|
-
resultFn = fn;
|
|
734
|
+
resultFn = (): RET => fn(this._onceArg);
|
|
672
735
|
}
|
|
673
736
|
if (!this.#syncOrAsync) {
|
|
674
737
|
throw new Error(`ResolveOnce.once impossible: state=${this.#state.getResolveState()}`);
|
|
675
738
|
}
|
|
676
|
-
return this.#syncOrAsync.Unwrap().resolve(resultFn
|
|
739
|
+
return this.#syncOrAsync.Unwrap().resolve(resultFn);
|
|
677
740
|
}
|
|
678
741
|
|
|
679
|
-
reset<
|
|
742
|
+
reset<RET extends T | Promise<T>>(fn?: (arg: OnceActionArg<T, CTX>) => RET): ResultOnce<RET> {
|
|
680
743
|
if (this.#state.isInitial()) {
|
|
681
744
|
if (!fn) {
|
|
682
|
-
return undefined as ResultOnce<
|
|
745
|
+
return undefined as ResultOnce<RET>;
|
|
683
746
|
}
|
|
684
|
-
return this.once(fn
|
|
747
|
+
return this.once(fn);
|
|
685
748
|
}
|
|
686
749
|
if (this.#state.isProcessing()) {
|
|
687
750
|
// eslint-disable-next-line no-console
|
|
688
751
|
console.warn("ResolveOnce.reset dropped was called while processing");
|
|
689
|
-
return undefined as ResultOnce<
|
|
752
|
+
return undefined as ResultOnce<RET>;
|
|
690
753
|
}
|
|
691
|
-
let ret = undefined as ResultOnce<
|
|
754
|
+
let ret = undefined as ResultOnce<RET>;
|
|
692
755
|
this.#state = new StateInstance();
|
|
693
756
|
if (fn) {
|
|
694
|
-
ret = this.once(fn
|
|
757
|
+
ret = this.once(fn);
|
|
695
758
|
// ret = this.#syncOrAsync.Unwrap().reset(fn as (c?: CTX) => never) as ResultOnce<R>
|
|
696
759
|
}
|
|
697
760
|
return ret;
|
|
698
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
|
+
}
|
|
699
773
|
}
|
|
700
774
|
|
|
701
775
|
// /**
|
|
@@ -798,19 +872,21 @@ export interface KeyedResolveOnceItem<K, T, CTX extends NonNullable<object>> {
|
|
|
798
872
|
* .once(({ givenKey, ctx }) => fetchUser(givenKey, ctx));
|
|
799
873
|
* ```
|
|
800
874
|
*/
|
|
801
|
-
export class KeyedResolvOnce<
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
+
> {
|
|
814
890
|
/** @internal */
|
|
815
891
|
readonly _keyed: KeyedNg<K, ResolveOnce<WithOptionalReset<T>, KeyedNgItemWithoutValue<K, CTX>>, CTX>;
|
|
816
892
|
|
|
@@ -991,7 +1067,7 @@ export class KeyedResolvOnce<T extends WithOptionalReset<PT>, K = string, CTX ex
|
|
|
991
1067
|
*/
|
|
992
1068
|
unget(key: K): void {
|
|
993
1069
|
const item = this._keyed.getItem(key);
|
|
994
|
-
item.value.reset?.();
|
|
1070
|
+
void item.value.reset?.();
|
|
995
1071
|
return this._keyed.delete(item.givenKey);
|
|
996
1072
|
}
|
|
997
1073
|
|
|
@@ -1003,7 +1079,7 @@ export class KeyedResolvOnce<T extends WithOptionalReset<PT>, K = string, CTX ex
|
|
|
1003
1079
|
*/
|
|
1004
1080
|
reset(): void {
|
|
1005
1081
|
for (const v of this._keyed.values()) {
|
|
1006
|
-
v.value.reset?.();
|
|
1082
|
+
void v.value.reset?.();
|
|
1007
1083
|
}
|
|
1008
1084
|
}
|
|
1009
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
|
}
|