@pistonite/pure 0.28.0 → 0.29.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/LICENSE +1 -1
- package/README.md +23 -4
- package/dist/_dts_/src/log/index.d.ts +37 -0
- package/dist/_dts_/src/log/index.d.ts.map +1 -0
- package/dist/_dts_/src/log/logger.d.ts +27 -0
- package/dist/_dts_/src/log/logger.d.ts.map +1 -0
- package/dist/_dts_/src/memory/cell.d.ts +25 -0
- package/dist/_dts_/src/memory/cell.d.ts.map +1 -0
- package/dist/_dts_/src/memory/emp.d.ts +87 -0
- package/dist/_dts_/src/memory/emp.d.ts.map +1 -0
- package/dist/_dts_/src/memory/idgen.d.ts +18 -0
- package/dist/_dts_/src/memory/idgen.d.ts.map +1 -0
- package/dist/_dts_/src/memory/index.d.ts +10 -0
- package/dist/_dts_/src/memory/index.d.ts.map +1 -0
- package/dist/_dts_/src/memory/persist.d.ts +38 -0
- package/dist/_dts_/src/memory/persist.d.ts.map +1 -0
- package/dist/_dts_/src/result/index.d.ts +191 -0
- package/dist/_dts_/src/result/index.d.ts.map +1 -0
- package/dist/_dts_/src/sync/RwLock.d.ts +30 -0
- package/dist/_dts_/src/sync/RwLock.d.ts.map +1 -0
- package/dist/_dts_/src/sync/batch.d.ts +112 -0
- package/dist/_dts_/src/sync/batch.d.ts.map +1 -0
- package/dist/_dts_/src/sync/capture.d.ts +11 -0
- package/dist/_dts_/src/sync/capture.d.ts.map +1 -0
- package/dist/_dts_/src/sync/debounce.d.ts +105 -0
- package/dist/_dts_/src/sync/debounce.d.ts.map +1 -0
- package/dist/_dts_/src/sync/index.d.ts +15 -0
- package/dist/_dts_/src/sync/index.d.ts.map +1 -0
- package/dist/_dts_/src/sync/latest.d.ts +86 -0
- package/dist/_dts_/src/sync/latest.d.ts.map +1 -0
- package/dist/_dts_/src/sync/mutex.d.ts +14 -0
- package/dist/_dts_/src/sync/mutex.d.ts.map +1 -0
- package/dist/_dts_/src/sync/once.d.ts +84 -0
- package/dist/_dts_/src/sync/once.d.ts.map +1 -0
- package/dist/_dts_/src/sync/serial.d.ts +162 -0
- package/dist/_dts_/src/sync/serial.d.ts.map +1 -0
- package/dist/_dts_/src/sync/util.d.ts +19 -0
- package/dist/_dts_/src/sync/util.d.ts.map +1 -0
- package/dist/log/index.js +57 -0
- package/dist/log/index.js.map +1 -0
- package/dist/memory/index.js +92 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/result/index.js +29 -0
- package/dist/result/index.js.map +1 -0
- package/dist/sync/index.js +252 -0
- package/dist/sync/index.js.map +1 -0
- package/package.json +22 -13
- package/src/env.d.ts +1 -0
- package/src/log/index.ts +36 -11
- package/src/log/logger.ts +93 -115
- package/src/memory/cell.ts +21 -11
- package/src/memory/emp.ts +34 -23
- package/src/memory/idgen.test.ts +1 -1
- package/src/memory/index.ts +1 -4
- package/src/memory/persist.ts +9 -12
- package/src/result/index.ts +12 -4
- package/src/sync/batch.test.ts +1 -1
- package/src/sync/batch.ts +12 -17
- package/src/sync/capture.ts +2 -0
- package/src/sync/debounce.test.ts +1 -1
- package/src/sync/debounce.ts +12 -15
- package/src/sync/index.ts +2 -3
- package/src/sync/latest.test.ts +1 -1
- package/src/sync/latest.ts +19 -16
- package/src/sync/once.test.ts +1 -1
- package/src/sync/once.ts +13 -8
- package/src/sync/serial.test.ts +1 -1
- package/src/sync/serial.ts +14 -12
- package/src/sync/util.ts +2 -2
- package/src/fs/FsError.ts +0 -55
- package/src/fs/FsFile.ts +0 -67
- package/src/fs/FsFileImpl.ts +0 -219
- package/src/fs/FsFileMgr.ts +0 -29
- package/src/fs/FsFileStandalone.ts +0 -21
- package/src/fs/FsFileStandaloneImplFileAPI.ts +0 -54
- package/src/fs/FsFileStandaloneImplHandleAPI.ts +0 -147
- package/src/fs/FsFileSystem.ts +0 -71
- package/src/fs/FsFileSystemInternal.ts +0 -30
- package/src/fs/FsImplEntryAPI.ts +0 -149
- package/src/fs/FsImplFileAPI.ts +0 -116
- package/src/fs/FsImplHandleAPI.ts +0 -199
- package/src/fs/FsOpen.ts +0 -271
- package/src/fs/FsOpenFile.ts +0 -256
- package/src/fs/FsPath.ts +0 -137
- package/src/fs/FsSave.ts +0 -216
- package/src/fs/FsSupportStatus.ts +0 -87
- package/src/fs/index.ts +0 -123
- package/src/log/internal.ts +0 -14
- package/src/memory/async_erc.ts +0 -186
- package/src/memory/erc.test.ts +0 -258
- package/src/memory/erc.ts +0 -320
- package/src/pref/dark.ts +0 -151
- package/src/pref/device.ts +0 -118
- package/src/pref/index.ts +0 -13
- package/src/pref/inject_style.ts +0 -22
- package/src/pref/locale.ts +0 -296
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute an async closure `fn`, and guarantee that `obj` will not be
|
|
3
|
+
* garbage-collected, until the promise is resolved.
|
|
4
|
+
*/
|
|
5
|
+
export declare const scopedCapture: <T>(fn: () => Promise<T>, obj: unknown) => Promise<T>;
|
|
6
|
+
/**
|
|
7
|
+
* Execute a closure `fn`, and guarantee that `obj` will not be
|
|
8
|
+
* garbage-collected during the execution
|
|
9
|
+
*/
|
|
10
|
+
export declare const scopedCaptureSync: <T>(fn: () => T, obj: unknown) => T;
|
|
11
|
+
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../../../src/sync/capture.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAU,CAAC,EAAE,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,KAAG,OAAO,CAAC,CAAC,CAYpF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,EAAE,IAAI,MAAM,CAAC,EAAE,KAAK,OAAO,KAAG,CAQhE,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { type AnyFn, type AwaitRet } from "./util.ts";
|
|
2
|
+
/** Factory for debounced function. See {@link DebounceConstructor} for usage */
|
|
3
|
+
export declare function debounce<TFn extends AnyFn>(args: DebounceConstructor<TFn>): (...args: Parameters<TFn>) => Promise<AwaitRet<TFn>>;
|
|
4
|
+
/**
|
|
5
|
+
* Options for `debounce` function
|
|
6
|
+
*
|
|
7
|
+
* A debounced function is an async event wrapper that is guaranteed to:
|
|
8
|
+
* - Not re-fire in a minimal interval after it's initialially fired.
|
|
9
|
+
* - All calls will eventually fire
|
|
10
|
+
*
|
|
11
|
+
* The caller will get a promise that resolves the next time the event is fired
|
|
12
|
+
* and resolved.
|
|
13
|
+
*
|
|
14
|
+
* Unlike the naive implementation with a setTimeout, this implementation
|
|
15
|
+
* will not starve the event. If it's constantly being called,
|
|
16
|
+
* it will keep firing the event at at least the minimum interval (might
|
|
17
|
+
* take longer if the underlying function takes longer to execute
|
|
18
|
+
*
|
|
19
|
+
* ## Simple Example
|
|
20
|
+
*
|
|
21
|
+
* Multiple calls will be debounced to the minimum interval
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { debounce } from "@pistonite/pure/sync";
|
|
24
|
+
*
|
|
25
|
+
* const execute = debounce({
|
|
26
|
+
* fn: () => {
|
|
27
|
+
* console.log("called");
|
|
28
|
+
* }
|
|
29
|
+
* interval: 100,
|
|
30
|
+
* });
|
|
31
|
+
* await execute(); // resolved immediately
|
|
32
|
+
* await execute(); // resolved after 100ms
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* ## Discarding extra calls
|
|
36
|
+
* When making multiple calls, if the call is currently being debounced
|
|
37
|
+
* (i.e. executed and the minimum interval hasn't passed), new calls
|
|
38
|
+
* will replace the previous call.
|
|
39
|
+
*
|
|
40
|
+
* If you want to the in-between calls to be preserved,
|
|
41
|
+
* use `batch` instead.
|
|
42
|
+
*
|
|
43
|
+
* ```typescript
|
|
44
|
+
* import { debounce } from "@pistonite/pure/sync";
|
|
45
|
+
*
|
|
46
|
+
* const execute = debounce({
|
|
47
|
+
* fn: (n: number) => {
|
|
48
|
+
* console.log(n);
|
|
49
|
+
* }
|
|
50
|
+
* interval: 100,
|
|
51
|
+
* });
|
|
52
|
+
* await execute(1); // logs 1 immediately
|
|
53
|
+
* const p1 = execute(2); // will be resolved at 100ms
|
|
54
|
+
* await new Promise((resolve) => setTimeout(resolve, 50));
|
|
55
|
+
* await Promise.all[p1, execute(3)]; // will be resolved at 100ms, discarding the 2nd call
|
|
56
|
+
* // 1, 3 will be logged
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* ## Slow function
|
|
60
|
+
* By default, the debouncer takes into account the time
|
|
61
|
+
* it takes for the underlying function to execute. It starts
|
|
62
|
+
* the next cycle as soon as both the minimul interval has passed
|
|
63
|
+
* and the function has finished executing. This ensures only
|
|
64
|
+
* 1 call is being executed at a time.
|
|
65
|
+
*
|
|
66
|
+
* However, if you want the debouncer to always debounce at the set interval,
|
|
67
|
+
* regardless of if the previous call has finished, set `disregardExecutionTime`
|
|
68
|
+
* to true.
|
|
69
|
+
*
|
|
70
|
+
* ```typescript
|
|
71
|
+
* import { debounce } from "@pistonite/pure/sync";
|
|
72
|
+
*
|
|
73
|
+
* const execute = debounce({
|
|
74
|
+
* fn: async (n: number) => {
|
|
75
|
+
* await new Promise((resolve) => setTimeout(resolve, 150));
|
|
76
|
+
* console.log(n);
|
|
77
|
+
* },
|
|
78
|
+
* interval: 100,
|
|
79
|
+
* // without this, will debounce at the interval of 150ms
|
|
80
|
+
* disregardExecutionTime: true,
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export interface DebounceConstructor<TFn> {
|
|
85
|
+
/** Function to be debounced */
|
|
86
|
+
fn: TFn;
|
|
87
|
+
/**
|
|
88
|
+
* Minimum interval between each call
|
|
89
|
+
*
|
|
90
|
+
* Setting this to <= 0 will make the debounce function
|
|
91
|
+
* a pure pass-through, not actually debouncing the function
|
|
92
|
+
*/
|
|
93
|
+
interval: number;
|
|
94
|
+
/**
|
|
95
|
+
* By default, the debouncer takes in account the time
|
|
96
|
+
* the underlying function executes. i.e. the actual debounce
|
|
97
|
+
* interval is `max(interval, executionTime)`. This default
|
|
98
|
+
* behavior guanrantees that no 2 calls will be executed concurrently.
|
|
99
|
+
*
|
|
100
|
+
* If you want the debouncer to always debounce at the set interval,
|
|
101
|
+
* set this to true.
|
|
102
|
+
*/
|
|
103
|
+
disregardExecutionTime?: boolean;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=debounce.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debounce.d.ts","sourceRoot":"","sources":["../../../../src/sync/debounce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAmC,MAAM,WAAW,CAAC;AAEvF,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,GAAG,SAAS,KAAK,EAAE,IAAI,EAAE,mBAAmB,CAAC,GAAG,CAAC,IAG9D,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,4BACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,MAAM,WAAW,mBAAmB,CAAC,GAAG;IACpC,+BAA+B;IAC/B,EAAE,EAAE,GAAG,CAAC;IACR;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;;;;OAQG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACpC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronization utilities
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
export { serial, type SerialConstructor, type SerialEventCancelCallback, type SerialCancelToken, } from "./serial.ts";
|
|
7
|
+
export { latest, type LatestConstructor, type LatestUpdateArgsFn } from "./latest.ts";
|
|
8
|
+
export { debounce, type DebounceConstructor } from "./debounce.ts";
|
|
9
|
+
export { batch, type BatchConstructor } from "./batch.ts";
|
|
10
|
+
export { once, type OnceConstructor } from "./once.ts";
|
|
11
|
+
export { makePromise, type PromiseHandle } from "./util.ts";
|
|
12
|
+
export { scopedCapture, scopedCaptureSync } from "./capture.ts";
|
|
13
|
+
export type { AnyFn, AwaitRet } from "./util.ts";
|
|
14
|
+
export { RwLock } from "./RwLock.ts";
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACH,MAAM,EACN,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,KAAK,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGhE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGjD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type AnyFn, type AwaitRet } from "./util.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Factory for `latest`. See {@link LatestConstructor} for usage.
|
|
4
|
+
*/
|
|
5
|
+
export declare function latest<TFn extends AnyFn>(args: LatestConstructor<TFn>): (...args: Parameters<TFn>) => Promise<AwaitRet<TFn>>;
|
|
6
|
+
/**
|
|
7
|
+
* Args for constructing `latest`
|
|
8
|
+
*
|
|
9
|
+
* `latest` is an async event wrapper that always resolve to the result of the latest
|
|
10
|
+
* call
|
|
11
|
+
*
|
|
12
|
+
* ## Example
|
|
13
|
+
* In the example below, both call will return the result
|
|
14
|
+
* of the second call (2)
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { latest } from "@pistonite/pure/sync";
|
|
17
|
+
*
|
|
18
|
+
* let counter = 0;
|
|
19
|
+
*
|
|
20
|
+
* const execute = latest({
|
|
21
|
+
* fn: async () => {
|
|
22
|
+
* counter++;
|
|
23
|
+
* await new Promise((resolve) => setTimeout(() => {
|
|
24
|
+
* resolve(counter);
|
|
25
|
+
* }, 1000));
|
|
26
|
+
* }
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* const result1 = execute();
|
|
30
|
+
* const result2 = execute();
|
|
31
|
+
* console.log(await result1); // 2
|
|
32
|
+
* console.log(await result2); // 2
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* ## Advanced Usage
|
|
36
|
+
* See the constructor options for more advanced usage, for example,
|
|
37
|
+
* control how arguments are updated when new calls are made.
|
|
38
|
+
*/
|
|
39
|
+
export interface LatestConstructor<TFn extends AnyFn> {
|
|
40
|
+
/** Function to be wrapped */
|
|
41
|
+
fn: TFn;
|
|
42
|
+
/**
|
|
43
|
+
* Optional function to compare if arguments of 2 calls are equal.
|
|
44
|
+
*
|
|
45
|
+
* By default, separate calls are considered different, and the result
|
|
46
|
+
* of the latest call will be returned. However, if the function is pure,
|
|
47
|
+
* and the argument of a new call is the same as the call being executed,
|
|
48
|
+
* then the result of the call being executed will be returned. In other words,
|
|
49
|
+
* the new call will not result in another execution of the function.
|
|
50
|
+
*/
|
|
51
|
+
areArgsEqual?: (a: Parameters<TFn>, b: Parameters<TFn>) => boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Optional function to update the arguments.
|
|
54
|
+
*
|
|
55
|
+
* By default, when new calls are made while the previous call is being executed,
|
|
56
|
+
* The function will be executed again with the latest arguments. This function
|
|
57
|
+
* is used to change this behavior and is called when new calls are made. In other words,
|
|
58
|
+
* the default value for this function is `(_current, _middle, latest) => latest`.
|
|
59
|
+
*
|
|
60
|
+
* The arguments are:
|
|
61
|
+
* - `current`: The arguments of the call currently being executed
|
|
62
|
+
* - `latest`: The argument of this new call
|
|
63
|
+
* - `middle`: If more than one call is made while the previous call is being executed,
|
|
64
|
+
* this array contains arguments of the calls between `current` and `latest`
|
|
65
|
+
* - `next`: This is the returned value of the previous call to updateArgs, i.e. the args
|
|
66
|
+
* to be executed next.
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
69
|
+
updateArgs?: LatestUpdateArgsFn<TFn>;
|
|
70
|
+
}
|
|
71
|
+
/** See {@link LatestConstructor} */
|
|
72
|
+
export type LatestUpdateArgsFn<TFn extends AnyFn> = (current: Parameters<TFn>, middle: Parameters<TFn>[], latest: Parameters<TFn>, next: Parameters<TFn> | undefined) => Parameters<TFn>;
|
|
73
|
+
export declare class LatestImpl<TFn extends AnyFn> {
|
|
74
|
+
private fn;
|
|
75
|
+
private pending?;
|
|
76
|
+
/** current arguments. undefined means no current call */
|
|
77
|
+
private currentArgs?;
|
|
78
|
+
/** next arguments. undefined means no newer call */
|
|
79
|
+
private nextArgs?;
|
|
80
|
+
private middleArgs;
|
|
81
|
+
private areArgsEqual;
|
|
82
|
+
private updateArgs;
|
|
83
|
+
constructor(fn: TFn, areArgsEqual?: (a: Parameters<TFn>, b: Parameters<TFn>) => boolean, updateArgs?: LatestUpdateArgsFn<TFn>);
|
|
84
|
+
invoke(...args: Parameters<TFn>): Promise<AwaitRet<TFn>>;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=latest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latest.d.ts","sourceRoot":"","sources":["../../../../src/sync/latest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAmC,MAAM,WAAW,CAAC;AAEvF;;GAEG;AACH,wBAAgB,MAAM,CAAC,GAAG,SAAS,KAAK,EAAE,IAAI,EAAE,iBAAiB,CAAC,GAAG,CAAC,IAG1D,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,4BACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,WAAW,iBAAiB,CAAC,GAAG,SAAS,KAAK;IAChD,6BAA6B;IAC7B,EAAE,EAAE,GAAG,CAAC;IAER;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC;IAEnE;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAAC,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;CACxC;AACD,oCAAoC;AACpC,MAAM,MAAM,kBAAkB,CAAC,GAAG,SAAS,KAAK,IAAI,CAChD,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,EACxB,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,EACzB,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,EACvB,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,SAAS,KAChC,UAAU,CAAC,GAAG,CAAC,CAAC;AACrB,qBAAa,UAAU,CAAC,GAAG,SAAS,KAAK;IAcjC,OAAO,CAAC,EAAE;IAbd,OAAO,CAAC,OAAO,CAAC,CAA+B;IAE/C,yDAAyD;IACzD,OAAO,CAAC,WAAW,CAAC,CAAkB;IACtC,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,CAAkB;IAEnC,OAAO,CAAC,UAAU,CAAoB;IAEtC,OAAO,CAAC,YAAY,CAAsD;IAC1E,OAAO,CAAC,UAAU,CAA0B;gBAGhC,EAAE,EAAE,GAAG,EACf,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,KAAK,OAAO,EAClE,UAAU,CAAC,EAAE,kBAAkB,CAAC,GAAG,CAAC;IAO3B,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;CAyCxE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
/**
|
|
3
|
+
* Non-reentrant mutex
|
|
4
|
+
*
|
|
5
|
+
* This allows only one context to enter a block at a time in a FIFO manner.
|
|
6
|
+
*
|
|
7
|
+
* This mutex is non-reentrant. Trying to lock it again while the same
|
|
8
|
+
* context already owns the lock will cause a dead lock.
|
|
9
|
+
*
|
|
10
|
+
* While a context id can be used to implement reentrant locks,
|
|
11
|
+
* it is very cumbersome to use. https://github.com/tc39/proposal-async-context
|
|
12
|
+
* will allow for a cleaner implementation.
|
|
13
|
+
*/
|
|
14
|
+
//# sourceMappingURL=mutex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutex.d.ts","sourceRoot":"","sources":["../../../../src/sync/mutex.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type AnyFn, type AwaitRet } from "./util.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Factory function for `once`. See {@link OnceConstructor} for usage
|
|
4
|
+
*/
|
|
5
|
+
export declare function once<TFn extends AnyFn>(args: OnceConstructor<TFn>): (...args: Parameters<TFn>) => Promise<AwaitRet<TFn>>;
|
|
6
|
+
/**
|
|
7
|
+
* Args for constructing a `once`
|
|
8
|
+
*
|
|
9
|
+
* `once` is an async event wrapper that ensures an async initialization is only ran once.
|
|
10
|
+
* Any subsequent calls after the first call will return a promise that resolves/rejects
|
|
11
|
+
* with the result of the first call.
|
|
12
|
+
*
|
|
13
|
+
* ## Example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { once } from "@pistonite/pure/sync";
|
|
16
|
+
*
|
|
17
|
+
* const getLuckyNumber = once({
|
|
18
|
+
* fn: async () => {
|
|
19
|
+
* console.log("running expensive initialization...")
|
|
20
|
+
* await new Promise((resolve) => setTimeout(resolve, 100));
|
|
21
|
+
* console.log("done")
|
|
22
|
+
* return 42;
|
|
23
|
+
* }
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* const result1 = getLuckyNumber();
|
|
27
|
+
* const result2 = getLuckyNumber();
|
|
28
|
+
* console.log(await result1);
|
|
29
|
+
* console.log(await result2);
|
|
30
|
+
* // logs:
|
|
31
|
+
* // running expensive initialization...
|
|
32
|
+
* // done
|
|
33
|
+
* // 42
|
|
34
|
+
* // 42
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* ## Caveat with HMR
|
|
38
|
+
* Some initialization might require clean up, such as unregister
|
|
39
|
+
* event handlers and/or timers. In this case, a production build might
|
|
40
|
+
* work fine but a HMR (Hot Module Reload) development server might not
|
|
41
|
+
* do this for you automatically.
|
|
42
|
+
*
|
|
43
|
+
* One way to work around this during development is to store the cleanup
|
|
44
|
+
* as a global object
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const getResourceThatNeedsCleanup = once({
|
|
47
|
+
* fn: async () => {
|
|
48
|
+
* if (__DEV__) { // Configure your bundler to inject this
|
|
49
|
+
* // await if you need async clean up
|
|
50
|
+
* await (window as any).cleanupMyResource?.();
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* let resource: MyResource;
|
|
54
|
+
* if (__DEV__) {
|
|
55
|
+
* (window as any).cleanupMyResource = async () => {
|
|
56
|
+
* await resource?.cleanup();
|
|
57
|
+
* };
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* resource = await initResource();
|
|
61
|
+
* return resource;
|
|
62
|
+
* }
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* An alternative solution is to not use `once` but instead tie the initialization
|
|
67
|
+
* of the resource to some other lifecycle event that gets cleaned up during HMR.
|
|
68
|
+
* For example, A framework that supports HMR for React components might unmount
|
|
69
|
+
* the component before reloading, which gives you a chance to clean up the resource.
|
|
70
|
+
*
|
|
71
|
+
* This is not an issue if the resource doesn't leak other resources,
|
|
72
|
+
* since it will eventually be GC'd.
|
|
73
|
+
*/
|
|
74
|
+
export interface OnceConstructor<TFn> {
|
|
75
|
+
/** Function to be called only once */
|
|
76
|
+
fn: TFn;
|
|
77
|
+
}
|
|
78
|
+
export declare class OnceImpl<TFn extends AnyFn> {
|
|
79
|
+
private fn;
|
|
80
|
+
private promise;
|
|
81
|
+
constructor(fn: TFn);
|
|
82
|
+
invoke(...args: Parameters<TFn>): Promise<AwaitRet<TFn>>;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=once.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"once.d.ts","sourceRoot":"","sources":["../../../../src/sync/once.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAe,MAAM,WAAW,CAAC;AAEnE;;GAEG;AACH,wBAAgB,IAAI,CAAC,GAAG,SAAS,KAAK,EAAE,IAAI,EAAE,eAAe,CAAC,GAAG,CAAC,IAEtD,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,4BACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AACH,MAAM,WAAW,eAAe,CAAC,GAAG;IAChC,sCAAsC;IACtC,EAAE,EAAE,GAAG,CAAC;CACX;AAED,qBAAa,QAAQ,CAAC,GAAG,SAAS,KAAK;IAGvB,OAAO,CAAC,EAAE;IAFtB,OAAO,CAAC,OAAO,CAAqC;gBAEhC,EAAE,EAAE,GAAG;IAId,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;CAexE"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { Result } from "../result/index.ts";
|
|
2
|
+
import type { AnyFn } from "./util.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Factory function for `serial`. See {@link SerialConstructor} for usage
|
|
5
|
+
*/
|
|
6
|
+
export declare const serial: <TFn extends AnyFn>(args: SerialConstructor<TFn>) => (...args: Parameters<TFn>) => Promise<Result<Awaited<ReturnType<TFn>>, "cancel">>;
|
|
7
|
+
/**
|
|
8
|
+
* Options for `serial` function
|
|
9
|
+
*
|
|
10
|
+
* `serial` is an async event wrapper that is cancelled when a new one starts.
|
|
11
|
+
* When a new event is started, the previous caller will receive a
|
|
12
|
+
* cancellation error, instead of being hung up indefinitely.
|
|
13
|
+
*
|
|
14
|
+
* If you want every caller to receive the latest result
|
|
15
|
+
* instead of a cancellation error, use `latest` instead.
|
|
16
|
+
*
|
|
17
|
+
* ## Example
|
|
18
|
+
*
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { serial } from "@pistonite/pure/sync";
|
|
21
|
+
*
|
|
22
|
+
* // helper function to simulate async work
|
|
23
|
+
* const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
24
|
+
*
|
|
25
|
+
* // Create the wrapped function
|
|
26
|
+
* const execute = serial({
|
|
27
|
+
* // This has to be curried for type inferrence
|
|
28
|
+
* fn: (checkCancel) => async () => {
|
|
29
|
+
* for (let i = 0; i < 10; i++) {
|
|
30
|
+
* await wait(1000);
|
|
31
|
+
* // The cancellation mechanism throws an error if is cancelled
|
|
32
|
+
* checkCancel();
|
|
33
|
+
* }
|
|
34
|
+
* return 42;
|
|
35
|
+
* }
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* // execute it the first time
|
|
39
|
+
* const promise1 = execute();
|
|
40
|
+
* await wait(3000);
|
|
41
|
+
*
|
|
42
|
+
* // calling event.run a second time will cause `checkCancel` to return false
|
|
43
|
+
* // the next time it's called by the first event
|
|
44
|
+
* const promise2 = execute();
|
|
45
|
+
*
|
|
46
|
+
* console.log(await promise1); // { err: "cancel" }
|
|
47
|
+
* console.log(await promise2); // { val: 42 }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* ## Passing in arguments
|
|
51
|
+
* TypeScript magic is used to ensure full type-safety when passing in arguments.
|
|
52
|
+
*
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import { serial, type SerialCancelToken } from "@pistonite/pure/sync";
|
|
55
|
+
* import type { Result } from "@pistonite/pure/result";
|
|
56
|
+
*
|
|
57
|
+
* const execute = serial({
|
|
58
|
+
* fn: (checkCancel) => async (arg1: number, arg2: string) => {
|
|
59
|
+
*
|
|
60
|
+
* // do something with arg1 and arg2
|
|
61
|
+
* console.log(arg1, arg2);
|
|
62
|
+
*
|
|
63
|
+
* // ...
|
|
64
|
+
* }
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* expectTypeOf(execute)
|
|
68
|
+
* .toEqualTypeOf<
|
|
69
|
+
* (arg1: number, arg2: string) => Promise<Result<void, SerialCancelToken>>
|
|
70
|
+
* >();
|
|
71
|
+
*
|
|
72
|
+
* await execute(42, "hello"); // no type error!
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* ## Getting the current serial number
|
|
76
|
+
* The serial number has type `bigint` and is incremented every time `run` is called.
|
|
77
|
+
*
|
|
78
|
+
* You can have an extra argument after `checkCancel`, that will receive the current serial number,
|
|
79
|
+
* if you need it for some reason.
|
|
80
|
+
* ```typescript
|
|
81
|
+
* import { serial } from "@pistonite/pure/sync";
|
|
82
|
+
*
|
|
83
|
+
* const execute = serial({
|
|
84
|
+
* fn: (checkCancel, serial) => () => { console.log(serial); }
|
|
85
|
+
* });
|
|
86
|
+
*
|
|
87
|
+
* await execute(); // 1n
|
|
88
|
+
* await execute(); // 2n
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* ## Checking for cancel
|
|
92
|
+
* It's the event handler's responsibility to check if the event is cancelled by
|
|
93
|
+
* calling the `checkCancel` function. This function will throw if the event
|
|
94
|
+
* is cancelled, and the error will be caught by the wrapper and returned as an `Err`
|
|
95
|
+
*
|
|
96
|
+
* Note that even if you don't check it, there is one final check before the result is returned.
|
|
97
|
+
* So you will never get a result from a cancelled event. Also note that you only need to check
|
|
98
|
+
* after any `await` calls. If there's no `await`, everything is executed synchronously,
|
|
99
|
+
* and it's theoretically impossible to cancel the event. However, this depends on
|
|
100
|
+
* the runtime's implementation of promises.
|
|
101
|
+
*
|
|
102
|
+
* ## Handling cancelled event
|
|
103
|
+
* To check if an event is completed or cancelled, simply `await`
|
|
104
|
+
* on the promise check the `err`
|
|
105
|
+
* ```typescript
|
|
106
|
+
* import { serial } from "@pistonite/pure/sync";
|
|
107
|
+
*
|
|
108
|
+
* const execute = serial({
|
|
109
|
+
* fn: (checkCancel) => async () => {
|
|
110
|
+
* // your code here ...
|
|
111
|
+
* }
|
|
112
|
+
* });
|
|
113
|
+
* const result = await execute();
|
|
114
|
+
* if (result.err === "cancel") {
|
|
115
|
+
* console.log("event was cancelled");
|
|
116
|
+
* } else {
|
|
117
|
+
* console.log("event completed");
|
|
118
|
+
* }
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* You can also pass in a callback to the constructor, which will be called
|
|
122
|
+
* when the event is cancelled. The cancel callback is guaranteed to only fire at most once per run
|
|
123
|
+
* ```typescript
|
|
124
|
+
* import { serial } from "@pistonite/pure/sync";
|
|
125
|
+
*
|
|
126
|
+
* const onCancel = (current: bigint, latest: bigint) => {
|
|
127
|
+
* console.log(`Event with serial ${current} is cancelled because the latest serial is ${latest}`);
|
|
128
|
+
* };
|
|
129
|
+
*
|
|
130
|
+
* const execute = new Serial({
|
|
131
|
+
* fn: ...,
|
|
132
|
+
* onCancel,
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* ## Exception handling
|
|
137
|
+
*
|
|
138
|
+
* If the underlying function throws, the exception will be re-thrown to the caller.
|
|
139
|
+
*/
|
|
140
|
+
export interface SerialConstructor<TFn> {
|
|
141
|
+
/**
|
|
142
|
+
* Function creator that returns the async function to be wrapped
|
|
143
|
+
*/
|
|
144
|
+
fn: (checkCancel: CheckCancelFn, current: SerialId) => TFn;
|
|
145
|
+
/**
|
|
146
|
+
* Optional callback to be called when the event is cancelled
|
|
147
|
+
*
|
|
148
|
+
* This is guaranteed to be only called at most once per execution
|
|
149
|
+
*/
|
|
150
|
+
onCancel?: SerialEventCancelCallback;
|
|
151
|
+
}
|
|
152
|
+
type SerialId = bigint;
|
|
153
|
+
type CheckCancelFn = () => void;
|
|
154
|
+
/**
|
|
155
|
+
* The callback type passed to SerialEvent constructor to be called
|
|
156
|
+
* when the event is cancelled
|
|
157
|
+
*/
|
|
158
|
+
export type SerialEventCancelCallback = (current: SerialId, latest: SerialId) => void;
|
|
159
|
+
/** The error type received by caller when an event is cancelled */
|
|
160
|
+
export type SerialCancelToken = "cancel";
|
|
161
|
+
export {};
|
|
162
|
+
//# sourceMappingURL=serial.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serial.d.ts","sourceRoot":"","sources":["../../../../src/sync/serial.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAEvC;;GAEG;AACH,eAAO,MAAM,MAAM,GAAI,GAAG,SAAS,KAAK,EAAE,MAAM,iBAAiB,CAAC,GAAG,CAAC,MAG1D,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,wDACnC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoIG;AACH,MAAM,WAAW,iBAAiB,CAAC,GAAG;IAClC;;OAEG;IACH,EAAE,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,KAAK,GAAG,CAAC;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,EAAE,yBAAyB,CAAC;CACxC;AA8CD,KAAK,QAAQ,GAAG,MAAM,CAAC;AACvB,KAAK,aAAa,GAAG,MAAM,IAAI,CAAC;AAGhC;;;GAGG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC;AAEtF,mEAAmE;AACnE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Make a {@link PromiseHandle} with the promise object separate from
|
|
3
|
+
* its resolve and reject methods
|
|
4
|
+
*/
|
|
5
|
+
export declare const makePromise: <T>() => PromiseHandle<T>;
|
|
6
|
+
/**
|
|
7
|
+
* A handle of the promise that breaks down the promise object
|
|
8
|
+
* and its resolve and reject functions
|
|
9
|
+
*/
|
|
10
|
+
export interface PromiseHandle<T> {
|
|
11
|
+
promise: Promise<T>;
|
|
12
|
+
resolve: (value: T | PromiseLike<T>) => void;
|
|
13
|
+
reject: (reason?: unknown) => void;
|
|
14
|
+
}
|
|
15
|
+
/** Shorthand for Awaited<ReturnType<T>> */
|
|
16
|
+
export type AwaitRet<T> = T extends (...args: any[]) => infer R ? Awaited<R> : never;
|
|
17
|
+
/** Type for any function */
|
|
18
|
+
export type AnyFn = (...args: any[]) => any;
|
|
19
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../src/sync/util.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,OAAK,aAAa,CAAC,CAAC,CAUhD,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC7C,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC;AAED,2CAA2C;AAE3C,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAErF,4BAA4B;AAE5B,MAAM,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { errstr as e } from "../result/index.js";
|
|
2
|
+
//#region src/log/logger.ts
|
|
3
|
+
var t = {
|
|
4
|
+
off: 0,
|
|
5
|
+
default: 1,
|
|
6
|
+
info: 2,
|
|
7
|
+
debug: 3
|
|
8
|
+
}, n = (e, n) => {
|
|
9
|
+
let { color: a, level: o } = n, s = t[o || "off"] || t.off;
|
|
10
|
+
return globalThis.process ? new r(e, s) : new i(e, a || "gray", s);
|
|
11
|
+
}, r = class {
|
|
12
|
+
constructor(e, t) {
|
|
13
|
+
this.name = e, this.level = t;
|
|
14
|
+
}
|
|
15
|
+
setLevel(e) {
|
|
16
|
+
this.level = t[e] || t.off;
|
|
17
|
+
}
|
|
18
|
+
debug(e) {
|
|
19
|
+
this.level === t.debug && console.debug(`DEBUG [${this.name}] ${e}`);
|
|
20
|
+
}
|
|
21
|
+
info(e) {
|
|
22
|
+
this.level < t.info || console.info(`INFO [${this.name}] ${e}`);
|
|
23
|
+
}
|
|
24
|
+
warn(e) {
|
|
25
|
+
this.level < t.default || console.warn(`WARN [${this.name}] ${e}`);
|
|
26
|
+
}
|
|
27
|
+
error(n) {
|
|
28
|
+
if (this.level < t.default) return;
|
|
29
|
+
let r = e(n);
|
|
30
|
+
console.error(`ERROR [${this.name}] ${r}`), r !== n && console.error(n);
|
|
31
|
+
}
|
|
32
|
+
}, i = class {
|
|
33
|
+
constructor(e, t, n) {
|
|
34
|
+
this.name = e, this.color = t, this.level = n;
|
|
35
|
+
}
|
|
36
|
+
setLevel(e) {
|
|
37
|
+
this.level = t[e] || t.off;
|
|
38
|
+
}
|
|
39
|
+
debug(e) {
|
|
40
|
+
this.level === t.debug && console.debug(`%cDEBUG%c${this.name}%c ${e}`, "background:gray;color:white;padding:0 3px", this.color, "color:inherit;background:inherit");
|
|
41
|
+
}
|
|
42
|
+
info(e) {
|
|
43
|
+
this.level < t.info || console.info(`%cINFO%c${this.name}%c ${e}`, "background:green;color:white;padding:0 3px", this.color, "color:inherit;background:inherit");
|
|
44
|
+
}
|
|
45
|
+
warn(e) {
|
|
46
|
+
this.level < t.default || console.warn(`%cWARN%c${this.name}%c ${e}`, "background:orange;color:white;padding:0 3px", this.color, "color:inherit;background:inherit");
|
|
47
|
+
}
|
|
48
|
+
error(n) {
|
|
49
|
+
if (this.level < t.default) return;
|
|
50
|
+
let r = e(n);
|
|
51
|
+
console.error(`%cERROR%c${this.name}%c ${r}`, "background:darkred;color:white;padding:0 3px", this.color, "color:inherit;background:inherit"), r !== n && console.error(n);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
export { n as logger };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/log/logger.ts"],"sourcesContent":["import { errstr } from \"../result/index.ts\";\n\n/**\n * String-enum for logging levels\n *\n * off - no logging at all\n * default - warning and errors only\n * info - warning, errors, info\n * debug - warning, errors, info, debug\n */\n\nconst LogLevel = { off: 0, default: 1, info: 2, debug: 3 } as const;\nexport type LogLevelStr = \"off\" | \"default\" | \"info\" | \"debug\";\nif (import.meta.vitest) {\n const { test, expectTypeOf } = import.meta.vitest;\n test(\"type LogLevelStr\", () => {\n expectTypeOf<LogLevelStr>().toEqualTypeOf<keyof typeof LogLevel>();\n });\n}\ntype LogLevel = (typeof LogLevel)[LogLevelStr];\n\n/** Args for constructing a logger */\nexport interface LoggerConstructor {\n /** CSS Color for the logger, default is 'gray' */\n color?: string;\n /**\n * Logging level, default is \"default\".\n * The level can still be changed later with setLevel\n */\n level?: LogLevelStr;\n}\n\n/** The logger type */\nexport interface Logger {\n /** Set the level of the logger */\n setLevel(level: LogLevelStr): void;\n /** Log a debug message */\n debug(obj: unknown): void;\n /** Log an info message */\n info(obj: unknown): void;\n /** Log a warning message */\n warn(obj: unknown): void;\n /** Log an error message */\n error(obj: unknown): void;\n}\n\n/** Create a logger creator. Use the factory methods to finish making the logger */\nexport const logger = (name: string, args: LoggerConstructor): Logger => {\n const { color, level } = args;\n const levelObj = LogLevel[level || \"off\"] || LogLevel.off;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if ((globalThis as any).process) {\n return new BareLoggerImpl(name, levelObj);\n }\n const color2 = color || \"gray\";\n return new CssLoggerImpl(name, color2, levelObj);\n};\n\nclass BareLoggerImpl implements Logger {\n constructor(\n private name: string,\n private level: LogLevel,\n ) {}\n setLevel(level: LogLevelStr): void {\n this.level = LogLevel[level] || LogLevel[\"off\"];\n }\n debug(obj: unknown): void {\n if (this.level !== LogLevel.debug) {\n return;\n }\n console.debug(`DEBUG [${this.name}] ${obj}`);\n }\n info(obj: unknown): void {\n if (this.level < LogLevel.info) {\n return;\n }\n console.info(`INFO [${this.name}] ${obj}`);\n }\n warn(obj: unknown): void {\n if (this.level < LogLevel.default) {\n return;\n }\n console.warn(`WARN [${this.name}] ${obj}`);\n }\n error(obj: unknown): void {\n if (this.level < LogLevel.default) {\n return;\n }\n const msg = errstr(obj);\n console.error(`ERROR [${this.name}] ${msg}`);\n if (msg !== obj) {\n console.error(obj);\n }\n }\n}\n\nclass CssLoggerImpl implements Logger {\n constructor(\n private name: string,\n private color: string,\n private level: LogLevel,\n ) {}\n setLevel(level: LogLevelStr): void {\n this.level = LogLevel[level] || LogLevel[\"off\"];\n }\n debug(obj: unknown): void {\n if (this.level !== LogLevel.debug) {\n return;\n }\n console.debug(\n `%cDEBUG%c${this.name}%c ${obj}`,\n \"background:gray;color:white;padding:0 3px\",\n this.color,\n \"color:inherit;background:inherit\",\n );\n }\n info(obj: unknown): void {\n if (this.level < LogLevel.info) {\n return;\n }\n console.info(\n `%cINFO%c${this.name}%c ${obj}`,\n \"background:green;color:white;padding:0 3px\",\n this.color,\n \"color:inherit;background:inherit\",\n );\n }\n warn(obj: unknown): void {\n if (this.level < LogLevel.default) {\n return;\n }\n console.warn(\n `%cWARN%c${this.name}%c ${obj}`,\n \"background:orange;color:white;padding:0 3px\",\n this.color,\n \"color:inherit;background:inherit\",\n );\n }\n error(obj: unknown): void {\n if (this.level < LogLevel.default) {\n return;\n }\n const msg = errstr(obj);\n console.error(\n `%cERROR%c${this.name}%c ${msg}`,\n \"background:darkred;color:white;padding:0 3px\",\n this.color,\n \"color:inherit;background:inherit\",\n );\n if (msg !== obj) {\n console.error(obj);\n }\n }\n}\n"],"mappings":";;AAWA,IAAM,IAAW;CAAE,KAAK;CAAG,SAAS;CAAG,MAAM;CAAG,OAAO;CAAG,EAoC7C,KAAU,GAAc,MAAoC;CACrE,IAAM,EAAE,UAAO,aAAU,GACnB,IAAW,EAAS,KAAS,UAAU,EAAS;AAMtD,QAJK,WAAmB,UACb,IAAI,EAAe,GAAM,EAAS,GAGtC,IAAI,EAAc,GADV,KAAS,QACe,EAAS;GAG9C,IAAN,MAAuC;CACnC,YACI,GACA,GACF;AADU,EADA,KAAA,OAAA,GACA,KAAA,QAAA;;CAEZ,SAAS,GAA0B;AAC/B,OAAK,QAAQ,EAAS,MAAU,EAAS;;CAE7C,MAAM,GAAoB;AAClB,OAAK,UAAU,EAAS,SAG5B,QAAQ,MAAM,UAAU,KAAK,KAAK,IAAI,IAAM;;CAEhD,KAAK,GAAoB;AACjB,OAAK,QAAQ,EAAS,QAG1B,QAAQ,KAAK,SAAS,KAAK,KAAK,IAAI,IAAM;;CAE9C,KAAK,GAAoB;AACjB,OAAK,QAAQ,EAAS,WAG1B,QAAQ,KAAK,SAAS,KAAK,KAAK,IAAI,IAAM;;CAE9C,MAAM,GAAoB;AACtB,MAAI,KAAK,QAAQ,EAAS,QACtB;EAEJ,IAAM,IAAM,EAAO,EAAI;AAEvB,EADA,QAAQ,MAAM,UAAU,KAAK,KAAK,IAAI,IAAM,EACxC,MAAQ,KACR,QAAQ,MAAM,EAAI;;GAKxB,IAAN,MAAsC;CAClC,YACI,GACA,GACA,GACF;AADU,EAFA,KAAA,OAAA,GACA,KAAA,QAAA,GACA,KAAA,QAAA;;CAEZ,SAAS,GAA0B;AAC/B,OAAK,QAAQ,EAAS,MAAU,EAAS;;CAE7C,MAAM,GAAoB;AAClB,OAAK,UAAU,EAAS,SAG5B,QAAQ,MACJ,YAAY,KAAK,KAAK,KAAK,KAC3B,6CACA,KAAK,OACL,mCACH;;CAEL,KAAK,GAAoB;AACjB,OAAK,QAAQ,EAAS,QAG1B,QAAQ,KACJ,WAAW,KAAK,KAAK,KAAK,KAC1B,8CACA,KAAK,OACL,mCACH;;CAEL,KAAK,GAAoB;AACjB,OAAK,QAAQ,EAAS,WAG1B,QAAQ,KACJ,WAAW,KAAK,KAAK,KAAK,KAC1B,+CACA,KAAK,OACL,mCACH;;CAEL,MAAM,GAAoB;AACtB,MAAI,KAAK,QAAQ,EAAS,QACtB;EAEJ,IAAM,IAAM,EAAO,EAAI;AAOvB,EANA,QAAQ,MACJ,YAAY,KAAK,KAAK,KAAK,KAC3B,gDACA,KAAK,OACL,mCACH,EACG,MAAQ,KACR,QAAQ,MAAM,EAAI"}
|