@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
package/src/log/logger.ts
CHANGED
|
@@ -1,106 +1,39 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Client side log util
|
|
3
|
-
*
|
|
4
|
-
* This is rather simple logging stuff with the primary focus
|
|
5
|
-
* being easy to debug.
|
|
6
|
-
*
|
|
7
|
-
* Use {@link logger} to create a logger with a name and a color,
|
|
8
|
-
* then use one of the {@link LoggerFactory} methods to setup the logging level.
|
|
9
|
-
*
|
|
10
|
-
* There are 3 levels of logging:
|
|
11
|
-
* 1. (Default) Warnings and Errors only
|
|
12
|
-
* 2. Also log info messages
|
|
13
|
-
* 3. Also log debug messages.
|
|
14
|
-
*
|
|
15
|
-
* Each logger can turn on info and debug logging separately, or it can
|
|
16
|
-
* be turned on at the global level for debugging.
|
|
17
|
-
*
|
|
18
|
-
* You can also turn off each logger individually or at global level for debugging.
|
|
19
|
-
*
|
|
20
|
-
* Due to the nature of JS, all logging calls, even when turned off, will incur
|
|
21
|
-
* some small runtime overhead. While we could remove debug calls
|
|
22
|
-
* for release build, that's currently not done (and it would require
|
|
23
|
-
* bundler to inline the call to remove the call completely, which might
|
|
24
|
-
* not be the case)
|
|
25
|
-
*
|
|
26
|
-
* @module
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
1
|
import { errstr } from "../result/index.ts";
|
|
30
2
|
|
|
31
|
-
export const LogLevel = { Off: 0, High: 1, Info: 2, Debug: 3 } as const;
|
|
32
|
-
export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];
|
|
33
|
-
|
|
34
|
-
let globalLevel: LogLevel = LogLevel.High;
|
|
35
|
-
/**
|
|
36
|
-
* Suppress ALL logging.
|
|
37
|
-
*
|
|
38
|
-
* This overrides logger-level settings
|
|
39
|
-
*/
|
|
40
|
-
export const globalLogOff = () => {
|
|
41
|
-
globalLevel = LogLevel.Off;
|
|
42
|
-
};
|
|
43
3
|
/**
|
|
44
|
-
*
|
|
4
|
+
* String-enum for logging levels
|
|
45
5
|
*
|
|
46
|
-
*
|
|
6
|
+
* off - no logging at all
|
|
7
|
+
* default - warning and errors only
|
|
8
|
+
* info - warning, errors, info
|
|
9
|
+
* debug - warning, errors, info, debug
|
|
47
10
|
*/
|
|
48
|
-
export const globalLogInfo = () => {
|
|
49
|
-
globalLevel = LogLevel.Info;
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Enable +debug logging for ALL loggers
|
|
53
|
-
*
|
|
54
|
-
* This overrides logger-level settings
|
|
55
|
-
*/
|
|
56
|
-
export const globalLogDebug = () => {
|
|
57
|
-
globalLevel = LogLevel.Debug;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/** Create a logger creator. Use the factory methods to finish making the logger */
|
|
61
|
-
export const logger = (name: string, color?: string): LoggerFactory => {
|
|
62
|
-
return {
|
|
63
|
-
default: () => new LoggerImpl(name, color, LogLevel.High),
|
|
64
|
-
debug: () => new LoggerImpl(name, color, LogLevel.Debug),
|
|
65
|
-
info: () => new LoggerImpl(name, color, LogLevel.Info),
|
|
66
|
-
off: () => new LoggerImpl(name, color, LogLevel.Off),
|
|
67
|
-
};
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
/** Create a {@link ResettableLogger} that can be easily reconfigured */
|
|
71
|
-
export const resettableLogger = (name: string, color?: string): ResettableLogger => {
|
|
72
|
-
const logger = new LoggerImpl(name, color, LogLevel.High);
|
|
73
|
-
return {
|
|
74
|
-
logger,
|
|
75
|
-
debug: () => (logger.level = LogLevel.Debug),
|
|
76
|
-
info: () => (logger.level = LogLevel.Info),
|
|
77
|
-
off: () => (logger.level = LogLevel.Off),
|
|
78
|
-
};
|
|
79
|
-
};
|
|
80
11
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
};
|
|
12
|
+
const LogLevel = { off: 0, default: 1, info: 2, debug: 3 } as const;
|
|
13
|
+
export type LogLevelStr = "off" | "default" | "info" | "debug";
|
|
14
|
+
if (import.meta.vitest) {
|
|
15
|
+
const { test, expectTypeOf } = import.meta.vitest;
|
|
16
|
+
test("type LogLevelStr", () => {
|
|
17
|
+
expectTypeOf<LogLevelStr>().toEqualTypeOf<keyof typeof LogLevel>();
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
type LogLevel = (typeof LogLevel)[LogLevelStr];
|
|
91
21
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
default
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
22
|
+
/** Args for constructing a logger */
|
|
23
|
+
export interface LoggerConstructor {
|
|
24
|
+
/** CSS Color for the logger, default is 'gray' */
|
|
25
|
+
color?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Logging level, default is "default".
|
|
28
|
+
* The level can still be changed later with setLevel
|
|
29
|
+
*/
|
|
30
|
+
level?: LogLevelStr;
|
|
31
|
+
}
|
|
102
32
|
|
|
103
|
-
|
|
33
|
+
/** The logger type */
|
|
34
|
+
export interface Logger {
|
|
35
|
+
/** Set the level of the logger */
|
|
36
|
+
setLevel(level: LogLevelStr): void;
|
|
104
37
|
/** Log a debug message */
|
|
105
38
|
debug(obj: unknown): void;
|
|
106
39
|
/** Log an info message */
|
|
@@ -109,21 +42,69 @@ export type Logger = {
|
|
|
109
42
|
warn(obj: unknown): void;
|
|
110
43
|
/** Log an error message */
|
|
111
44
|
error(obj: unknown): void;
|
|
112
|
-
}
|
|
45
|
+
}
|
|
113
46
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
color
|
|
117
|
-
level
|
|
47
|
+
/** Create a logger creator. Use the factory methods to finish making the logger */
|
|
48
|
+
export const logger = (name: string, args: LoggerConstructor): Logger => {
|
|
49
|
+
const { color, level } = args;
|
|
50
|
+
const levelObj = LogLevel[level || "off"] || LogLevel.off;
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
52
|
+
if ((globalThis as any).process) {
|
|
53
|
+
return new BareLoggerImpl(name, levelObj);
|
|
54
|
+
}
|
|
55
|
+
const color2 = color || "gray";
|
|
56
|
+
return new CssLoggerImpl(name, color2, levelObj);
|
|
57
|
+
};
|
|
118
58
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
59
|
+
class BareLoggerImpl implements Logger {
|
|
60
|
+
constructor(
|
|
61
|
+
private name: string,
|
|
62
|
+
private level: LogLevel,
|
|
63
|
+
) {}
|
|
64
|
+
setLevel(level: LogLevelStr): void {
|
|
65
|
+
this.level = LogLevel[level] || LogLevel["off"];
|
|
66
|
+
}
|
|
67
|
+
debug(obj: unknown): void {
|
|
68
|
+
if (this.level !== LogLevel.debug) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
console.debug(`DEBUG [${this.name}] ${obj}`);
|
|
72
|
+
}
|
|
73
|
+
info(obj: unknown): void {
|
|
74
|
+
if (this.level < LogLevel.info) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.info(`INFO [${this.name}] ${obj}`);
|
|
78
|
+
}
|
|
79
|
+
warn(obj: unknown): void {
|
|
80
|
+
if (this.level < LogLevel.default) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.warn(`WARN [${this.name}] ${obj}`);
|
|
84
|
+
}
|
|
85
|
+
error(obj: unknown): void {
|
|
86
|
+
if (this.level < LogLevel.default) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const msg = errstr(obj);
|
|
90
|
+
console.error(`ERROR [${this.name}] ${msg}`);
|
|
91
|
+
if (msg !== obj) {
|
|
92
|
+
console.error(obj);
|
|
93
|
+
}
|
|
123
94
|
}
|
|
95
|
+
}
|
|
124
96
|
|
|
125
|
-
|
|
126
|
-
|
|
97
|
+
class CssLoggerImpl implements Logger {
|
|
98
|
+
constructor(
|
|
99
|
+
private name: string,
|
|
100
|
+
private color: string,
|
|
101
|
+
private level: LogLevel,
|
|
102
|
+
) {}
|
|
103
|
+
setLevel(level: LogLevelStr): void {
|
|
104
|
+
this.level = LogLevel[level] || LogLevel["off"];
|
|
105
|
+
}
|
|
106
|
+
debug(obj: unknown): void {
|
|
107
|
+
if (this.level !== LogLevel.debug) {
|
|
127
108
|
return;
|
|
128
109
|
}
|
|
129
110
|
console.debug(
|
|
@@ -133,9 +114,8 @@ export class LoggerImpl implements Logger {
|
|
|
133
114
|
"color:inherit;background:inherit",
|
|
134
115
|
);
|
|
135
116
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (globalLevel < LogLevel.Info && this.level < LogLevel.Info) {
|
|
117
|
+
info(obj: unknown): void {
|
|
118
|
+
if (this.level < LogLevel.info) {
|
|
139
119
|
return;
|
|
140
120
|
}
|
|
141
121
|
console.info(
|
|
@@ -145,9 +125,8 @@ export class LoggerImpl implements Logger {
|
|
|
145
125
|
"color:inherit;background:inherit",
|
|
146
126
|
);
|
|
147
127
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (globalLevel < LogLevel.High || this.level < LogLevel.High) {
|
|
128
|
+
warn(obj: unknown): void {
|
|
129
|
+
if (this.level < LogLevel.default) {
|
|
151
130
|
return;
|
|
152
131
|
}
|
|
153
132
|
console.warn(
|
|
@@ -157,9 +136,8 @@ export class LoggerImpl implements Logger {
|
|
|
157
136
|
"color:inherit;background:inherit",
|
|
158
137
|
);
|
|
159
138
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (globalLevel < LogLevel.High || this.level < LogLevel.High) {
|
|
139
|
+
error(obj: unknown): void {
|
|
140
|
+
if (this.level < LogLevel.default) {
|
|
163
141
|
return;
|
|
164
142
|
}
|
|
165
143
|
const msg = errstr(obj);
|
package/src/memory/cell.ts
CHANGED
|
@@ -1,21 +1,31 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function cell<T>({ initial }: CellConstructor<T>): Cell<T> {
|
|
6
|
-
return new CellImpl(initial);
|
|
7
|
-
}
|
|
1
|
+
/** Create a {@link Cell} */
|
|
2
|
+
export const cell = <T>(args: CellConstructor<T>): Cell<T> => {
|
|
3
|
+
return new CellImpl(args.initial);
|
|
4
|
+
};
|
|
8
5
|
|
|
9
|
-
|
|
6
|
+
/** Args for constructing a cell */
|
|
7
|
+
export interface CellConstructor<T> {
|
|
10
8
|
/** Initial value */
|
|
11
9
|
initial: T;
|
|
12
|
-
}
|
|
10
|
+
}
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
/**
|
|
13
|
+
* A light weight storage wrapper around a value
|
|
14
|
+
* that can be subscribed to for changes
|
|
15
|
+
*
|
|
16
|
+
* Created via `cell()`
|
|
17
|
+
*
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { cell } from "@pistonite/pure/memory";
|
|
20
|
+
*
|
|
21
|
+
* const myCell = cell(true);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export interface Cell<T> {
|
|
15
25
|
get(): T;
|
|
16
26
|
set(value: T): void;
|
|
17
27
|
subscribe(callback: (value: T) => void, notifyImmediately?: boolean): () => void;
|
|
18
|
-
}
|
|
28
|
+
}
|
|
19
29
|
|
|
20
30
|
class CellImpl<T> implements Cell<T> {
|
|
21
31
|
private subscribers: ((value: T) => void)[] = [];
|
package/src/memory/emp.ts
CHANGED
|
@@ -39,31 +39,41 @@
|
|
|
39
39
|
* In 32-bit context like WASM32, the inner value can be a `number`.
|
|
40
40
|
* In 64-bit context, `number` might be fine for some systems, but `bigint`
|
|
41
41
|
* is recommended.
|
|
42
|
+
*
|
|
43
|
+
* ## Usage
|
|
44
|
+
*
|
|
45
|
+
* ```typescript
|
|
46
|
+
* // First create a marker to distinguish between different Emp types for TypeScript.
|
|
47
|
+
* // This is not used at runtime
|
|
48
|
+
* const MyNativeType = Symbol("MyNativeType");
|
|
49
|
+
* export type MyNativeType = typeof MyNativeType;
|
|
50
|
+
*
|
|
51
|
+
* // Then use makeEmpType to create a factory function
|
|
52
|
+
* const makeMyNativeTypeEmp = makeEmpType({
|
|
53
|
+
* marker: MyNativeType,
|
|
54
|
+
* free: (ptr) => freeMyNativeType(ptr),
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* // Now acquire ownership of an object from external native code
|
|
58
|
+
* // and assign it to an Emp
|
|
59
|
+
* const myObjRawPtr = allocMyNativeType();
|
|
60
|
+
* const myObj = makeMyNativeTypeEmp(myObjRawPtr);
|
|
61
|
+
*
|
|
62
|
+
* // when myObj is GC'ed, it will be freed by calling freeMyNativeType
|
|
63
|
+
* ```
|
|
42
64
|
*/
|
|
43
|
-
export
|
|
65
|
+
export interface Emp<T, TRepr> {
|
|
44
66
|
/** The type marker for T. This only marks the type for TypeScript and does not exist at runtime */
|
|
45
67
|
readonly __phantom: T;
|
|
46
68
|
/** The underlying pointer value */
|
|
47
69
|
readonly value: TRepr;
|
|
48
|
-
}
|
|
70
|
+
}
|
|
49
71
|
|
|
50
|
-
|
|
72
|
+
/** Args for constructing a Emp type */
|
|
73
|
+
export interface EmpConstructor<T, TRepr> {
|
|
51
74
|
/**
|
|
52
|
-
* The marker for the Emp type, used to distinguish between multiple types
|
|
53
|
-
*
|
|
54
|
-
* Typically, this is a unique symbol:
|
|
55
|
-
* ```typescript
|
|
56
|
-
* const MyNativeType = Symbol("MyNativeType");
|
|
57
|
-
* export type MyNativeType = typeof MyNativeType;
|
|
58
|
-
*
|
|
59
|
-
* const makeMyNativeTypeEmp = makeEmpType({
|
|
60
|
-
* marker: MyNativeType,
|
|
61
|
-
* free: (ptr) => void freeMyNativeType(ptr)
|
|
62
|
-
* })
|
|
63
|
-
* ```
|
|
64
|
-
*
|
|
65
|
-
* Note that this is not used in runtime, but just used for type inference,
|
|
66
|
-
* so you can also skip passing it and specify the type parameter instead
|
|
75
|
+
* The marker for the Emp type, used to distinguish between multiple Emp types
|
|
76
|
+
* in TypeScript
|
|
67
77
|
*/
|
|
68
78
|
marker?: T;
|
|
69
79
|
|
|
@@ -71,14 +81,15 @@ export type EmpConstructor<T, TRepr> = {
|
|
|
71
81
|
* Function to free the underlying object. Called when this Emp is garbage-collected
|
|
72
82
|
*/
|
|
73
83
|
free: (ptr: TRepr) => void | Promise<void>;
|
|
74
|
-
}
|
|
84
|
+
}
|
|
75
85
|
|
|
76
86
|
/**
|
|
77
|
-
* Create a factory function for an {@link Emp}
|
|
87
|
+
* Create a factory function for an Emp type. See {@link Emp}
|
|
78
88
|
*/
|
|
79
|
-
export const makeEmpType = <T, TRepr>(
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
export const makeEmpType = <T, TRepr>(
|
|
90
|
+
args: EmpConstructor<T, TRepr>,
|
|
91
|
+
): ((ptr: TRepr) => Emp<T, TRepr>) => {
|
|
92
|
+
const { free } = args;
|
|
82
93
|
const registry = new FinalizationRegistry(free);
|
|
83
94
|
return (ptr: TRepr) => {
|
|
84
95
|
const obj = Object.freeze({ value: ptr });
|
package/src/memory/idgen.test.ts
CHANGED
package/src/memory/index.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* JS memory utilities
|
|
2
|
+
* Memory utilities
|
|
4
3
|
*
|
|
5
4
|
* @module
|
|
6
5
|
*/
|
|
7
6
|
export { cell, type CellConstructor, type Cell } from "./cell.ts";
|
|
8
7
|
export { persist, type PersistConstructor, type Persist } from "./persist.ts";
|
|
9
|
-
export * from "./async_erc.ts";
|
|
10
8
|
export * from "./emp.ts";
|
|
11
|
-
export * from "./erc.ts";
|
|
12
9
|
export * from "./idgen.ts";
|
package/src/memory/persist.ts
CHANGED
|
@@ -3,13 +3,8 @@ import { cell, type Cell, type CellConstructor } from "./cell.ts";
|
|
|
3
3
|
/**
|
|
4
4
|
* Create a cell that persists its value to a web storage
|
|
5
5
|
*/
|
|
6
|
-
export function persist<T>({
|
|
7
|
-
storage,
|
|
8
|
-
key,
|
|
9
|
-
serialize = JSON.stringify,
|
|
10
|
-
deserialize,
|
|
11
|
-
initial,
|
|
12
|
-
}: PersistConstructor<T>): Persist<T> {
|
|
6
|
+
export function persist<T>(args: PersistConstructor<T>): Persist<T> {
|
|
7
|
+
const { storage, key, serialize = JSON.stringify, deserialize, initial } = args;
|
|
13
8
|
const deser =
|
|
14
9
|
deserialize ??
|
|
15
10
|
((value: string) => {
|
|
@@ -22,7 +17,8 @@ export function persist<T>({
|
|
|
22
17
|
return new PersistImpl(storage, key, serialize, deser, initial);
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
|
|
20
|
+
/** Args for creating a persisted cell */
|
|
21
|
+
export interface PersistConstructor<T> extends CellConstructor<T> {
|
|
26
22
|
/** The web storage to use */
|
|
27
23
|
storage: Storage;
|
|
28
24
|
|
|
@@ -41,9 +37,10 @@ export type PersistConstructor<T> = CellConstructor<T> & {
|
|
|
41
37
|
* By default, it will use `JSON.parse` wrapped with try-catch
|
|
42
38
|
*/
|
|
43
39
|
deserialize?(value: string): T | null;
|
|
44
|
-
}
|
|
40
|
+
}
|
|
45
41
|
|
|
46
|
-
|
|
42
|
+
/** A cell that also persists its value */
|
|
43
|
+
export interface Persist<T> extends Cell<T> {
|
|
47
44
|
/**
|
|
48
45
|
* Load the value initially, and notify all the current subscribers
|
|
49
46
|
*
|
|
@@ -52,9 +49,9 @@ export type Persist<T> = Cell<T> & {
|
|
|
52
49
|
init(initial?: T): T;
|
|
53
50
|
/** Clear the value from the storage */
|
|
54
51
|
clear(): void;
|
|
55
|
-
/**
|
|
52
|
+
/** Clear the value and disable the persistence */
|
|
56
53
|
disable(): void;
|
|
57
|
-
}
|
|
54
|
+
}
|
|
58
55
|
|
|
59
56
|
class PersistImpl<T> implements Persist<T> {
|
|
60
57
|
private cell: Cell<T>;
|
package/src/result/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Rust-like `Result<T, E>` type and error handling utils
|
|
3
|
+
*
|
|
2
4
|
* **I once had a fancy error object with TypeScript magic that tries
|
|
3
5
|
* to reduce allocation while maintaining Result-safety. It turns out
|
|
4
6
|
* that was slower than allocating plain objects for every return, because
|
|
@@ -163,9 +165,15 @@ export type Result<T, E> = Ok<T> | Err<E>;
|
|
|
163
165
|
// This is to get type narrowing to work most of the time
|
|
164
166
|
|
|
165
167
|
/** A success value */
|
|
166
|
-
export
|
|
168
|
+
export interface Ok<T> {
|
|
169
|
+
val: T;
|
|
170
|
+
err?: never;
|
|
171
|
+
}
|
|
167
172
|
/** An error value */
|
|
168
|
-
export
|
|
173
|
+
export interface Err<E> {
|
|
174
|
+
err: E;
|
|
175
|
+
val?: never;
|
|
176
|
+
}
|
|
169
177
|
|
|
170
178
|
/**
|
|
171
179
|
* A value that is either `void` or an error
|
|
@@ -177,7 +185,7 @@ export type Void<E> = { val?: never; err?: never } | { err: E };
|
|
|
177
185
|
export type VoidOk = Record<string, never>;
|
|
178
186
|
|
|
179
187
|
/** Wrap a function with try-catch and return a Result. */
|
|
180
|
-
export function tryCatch<T, E =
|
|
188
|
+
export function tryCatch<T, E = Error>(fn: () => T): Result<T, E> {
|
|
181
189
|
try {
|
|
182
190
|
return { val: fn() };
|
|
183
191
|
} catch (e) {
|
|
@@ -186,7 +194,7 @@ export function tryCatch<T, E = unknown>(fn: () => T): Result<T, E> {
|
|
|
186
194
|
}
|
|
187
195
|
|
|
188
196
|
/** Wrap an async function with try-catch and return a Promise<Result>. */
|
|
189
|
-
export async function tryAsync<T, E =
|
|
197
|
+
export async function tryAsync<T, E = Error>(fn: () => Promise<T>): Promise<Result<T, E>> {
|
|
190
198
|
try {
|
|
191
199
|
return { val: await fn() };
|
|
192
200
|
} catch (e) {
|
package/src/sync/batch.test.ts
CHANGED
package/src/sync/batch.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { type AnyFn, makePromise, type PromiseHandle, type AwaitRet } from "./util.ts";
|
|
2
2
|
|
|
3
|
+
/** Factory for batched function. See {@link BatchConstructor} for usage. */
|
|
4
|
+
export function batch<TFn extends AnyFn>(args: BatchConstructor<TFn>) {
|
|
5
|
+
const { fn, batch, unbatch, interval, disregardExecutionTime } = args;
|
|
6
|
+
const impl = new BatchImpl(fn, batch, unbatch, interval, !!disregardExecutionTime);
|
|
7
|
+
return (...args: Parameters<TFn>) => impl.invoke(...args);
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
/**
|
|
4
|
-
*
|
|
11
|
+
* Options to construct a `batch` function
|
|
12
|
+
*
|
|
13
|
+
* A batch function is an async event wrapper that allows multiple calls in an interval
|
|
5
14
|
* to be batched together, and only call the underlying function once.
|
|
6
15
|
*
|
|
7
16
|
* Optionally, the output can be unbatched to match the inputs.
|
|
@@ -87,21 +96,7 @@ import { type AnyFn, makePromise, type PromiseHandle, type AwaitRet } from "./ut
|
|
|
87
96
|
* ```
|
|
88
97
|
*
|
|
89
98
|
*/
|
|
90
|
-
export
|
|
91
|
-
fn,
|
|
92
|
-
batch,
|
|
93
|
-
unbatch,
|
|
94
|
-
interval,
|
|
95
|
-
disregardExecutionTime,
|
|
96
|
-
}: BatchConstructor<TFn>) {
|
|
97
|
-
const impl = new BatchImpl(fn, batch, unbatch, interval, !!disregardExecutionTime);
|
|
98
|
-
return (...args: Parameters<TFn>) => impl.invoke(...args);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Options to construct a `batch` function
|
|
103
|
-
*/
|
|
104
|
-
export type BatchConstructor<TFn extends AnyFn> = {
|
|
99
|
+
export interface BatchConstructor<TFn extends AnyFn> {
|
|
105
100
|
/** Function to be wrapped */
|
|
106
101
|
fn: TFn;
|
|
107
102
|
/** Function to batch the inputs across multiple calls */
|
|
@@ -122,7 +117,7 @@ export type BatchConstructor<TFn extends AnyFn> = {
|
|
|
122
117
|
|
|
123
118
|
/** See `debounce` for more information */
|
|
124
119
|
disregardExecutionTime?: boolean;
|
|
125
|
-
}
|
|
120
|
+
}
|
|
126
121
|
|
|
127
122
|
class BatchImpl<TFn extends AnyFn> {
|
|
128
123
|
private idle: boolean;
|
package/src/sync/capture.ts
CHANGED
package/src/sync/debounce.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { type AnyFn, type AwaitRet, makePromise, type PromiseHandle } from "./util.ts";
|
|
2
2
|
|
|
3
|
+
/** Factory for debounced function. See {@link DebounceConstructor} for usage */
|
|
4
|
+
export function debounce<TFn extends AnyFn>(args: DebounceConstructor<TFn>) {
|
|
5
|
+
const { fn, interval, disregardExecutionTime } = args;
|
|
6
|
+
const impl = new DebounceImpl(fn, interval, !!disregardExecutionTime);
|
|
7
|
+
return (...args: Parameters<TFn>) => impl.invoke(...args);
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
/**
|
|
4
|
-
*
|
|
11
|
+
* Options for `debounce` function
|
|
12
|
+
*
|
|
13
|
+
* A debounced function is an async event wrapper that is guaranteed to:
|
|
5
14
|
* - Not re-fire in a minimal interval after it's initialially fired.
|
|
6
15
|
* - All calls will eventually fire
|
|
7
16
|
*
|
|
@@ -78,19 +87,7 @@ import { type AnyFn, type AwaitRet, makePromise, type PromiseHandle } from "./ut
|
|
|
78
87
|
* });
|
|
79
88
|
* ```
|
|
80
89
|
*/
|
|
81
|
-
export
|
|
82
|
-
fn,
|
|
83
|
-
interval,
|
|
84
|
-
disregardExecutionTime,
|
|
85
|
-
}: DebounceConstructor<TFn>) {
|
|
86
|
-
const impl = new DebounceImpl(fn, interval, !!disregardExecutionTime);
|
|
87
|
-
return (...args: Parameters<TFn>) => impl.invoke(...args);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Options for `debounce` function
|
|
92
|
-
*/
|
|
93
|
-
export type DebounceConstructor<TFn> = {
|
|
90
|
+
export interface DebounceConstructor<TFn> {
|
|
94
91
|
/** Function to be debounced */
|
|
95
92
|
fn: TFn;
|
|
96
93
|
/**
|
|
@@ -111,7 +108,7 @@ export type DebounceConstructor<TFn> = {
|
|
|
111
108
|
* set this to true.
|
|
112
109
|
*/
|
|
113
110
|
disregardExecutionTime?: boolean;
|
|
114
|
-
}
|
|
111
|
+
}
|
|
115
112
|
|
|
116
113
|
class DebounceImpl<TFn extends AnyFn> {
|
|
117
114
|
private idle: boolean;
|
package/src/sync/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* JS synchronization utilities
|
|
2
|
+
* Synchronization utilities
|
|
4
3
|
*
|
|
5
4
|
* @module
|
|
6
5
|
*/
|
|
@@ -10,7 +9,7 @@ export {
|
|
|
10
9
|
type SerialEventCancelCallback,
|
|
11
10
|
type SerialCancelToken,
|
|
12
11
|
} from "./serial.ts";
|
|
13
|
-
export { latest, type LatestConstructor, type
|
|
12
|
+
export { latest, type LatestConstructor, type LatestUpdateArgsFn } from "./latest.ts";
|
|
14
13
|
export { debounce, type DebounceConstructor } from "./debounce.ts";
|
|
15
14
|
export { batch, type BatchConstructor } from "./batch.ts";
|
|
16
15
|
export { once, type OnceConstructor } from "./once.ts";
|
package/src/sync/latest.test.ts
CHANGED