vivth 1.1.2 → 1.2.0
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/.vivth-temp/README.src.md +35 -0
- package/README.md +1215 -433
- package/README.src.md +5 -2
- package/bun.lock +228 -0
- package/index.mjs +17 -4
- package/package.json +6 -3
- package/src/bundler/CompileJS.mjs +258 -0
- package/src/bundler/CreateESPlugin.mjs +24 -0
- package/src/bundler/EsBundler.mjs +27 -13
- package/src/bundler/FSInline.mjs +57 -0
- package/src/bundler/FSInlineAnalyzer.mjs +197 -0
- package/src/bundler/FSInlineBundled.mjs +34 -0
- package/src/bundler/adds/ToBundledJSPlugin.mjs +77 -0
- package/src/bundler/adds/externals.mjs +8 -0
- package/src/bundler/adds/pluginVivthBundle.mjs +5 -0
- package/src/class/Console.mjs +48 -27
- package/src/class/Derived.mjs +55 -7
- package/src/class/Effect.mjs +100 -39
- package/src/class/EnvSignal.mjs +5 -5
- package/src/class/EventSignal.mjs +55 -5
- package/src/class/FileSafe.mjs +124 -0
- package/src/class/ListDerived.mjs +6 -3
- package/src/class/ListSignal.mjs +11 -11
- package/src/class/LitExp.mjs +405 -0
- package/src/class/Paths.mjs +27 -1
- package/src/class/QChannel.mjs +79 -28
- package/src/class/SafeExit.mjs +31 -11
- package/src/class/Setup.mjs +5 -2
- package/src/class/Signal.mjs +26 -24
- package/src/class/WorkerMainThread.mjs +100 -133
- package/src/class/WorkerMainThreadBundled.mjs +216 -0
- package/src/class/WorkerThread.mjs +38 -32
- package/src/common/Base64URL.mjs +10 -5
- package/src/common/Base64URLFromFile.mjs +24 -0
- package/src/common/keys.mjs +3 -0
- package/src/doc/JSautoDOC.mjs +32 -56
- package/src/doc/parsedFile.mjs +37 -36
- package/src/function/CreateImmutable.mjs +9 -9
- package/src/function/EventCheck.mjs +2 -2
- package/src/function/EventObject.mjs +5 -5
- package/src/function/GetRuntime.mjs +38 -0
- package/src/function/IsAsync.mjs +2 -2
- package/src/function/LazyFactory.mjs +13 -13
- package/src/function/Timeout.mjs +2 -2
- package/src/function/Try.mjs +17 -12
- package/src/function/TryAsync.mjs +5 -5
- package/src/function/TrySync.mjs +5 -5
- package/src/function/TsToMjs.mjs +5 -4
- package/src/types/LitExpKeyType.mjs +5 -0
- package/src/types/QCBReturn.mjs +1 -1
- package/src/types/Runtime.mjs +7 -0
- package/types/dev/fsInline.d.mts +1 -0
- package/types/dev/test.d.mts +1 -0
- package/types/dev/testWorker.d.mts +7 -0
- package/types/dev/testbundle.d.mts +1 -0
- package/types/dev/workerThreadClass.d.mts +13 -0
- package/types/index.d.mts +13 -4
- package/types/src/bundler/CompileJS.d.mts +78 -0
- package/types/src/bundler/CreateESPlugin.d.mts +17 -0
- package/types/src/bundler/EsBundler.d.mts +33 -4
- package/types/src/bundler/FSInline.d.mts +43 -0
- package/types/src/bundler/FSInlineAnalyzer.d.mts +36 -0
- package/types/src/bundler/FSInlineBundled.d.mts +22 -0
- package/types/src/bundler/adds/ToBundledJSPlugin.d.mts +16 -0
- package/types/src/bundler/adds/externals.d.mts +1 -0
- package/types/src/bundler/adds/pluginVivthBundle.d.mts +1 -0
- package/types/src/class/Console.d.mts +36 -5
- package/types/src/class/Derived.d.mts +132 -5
- package/types/src/class/Effect.d.mts +106 -7
- package/types/src/class/EnvSignal.d.mts +8 -8
- package/types/src/class/EventSignal.d.mts +151 -7
- package/types/src/class/FileSafe.d.mts +90 -0
- package/types/src/class/ListDerived.d.mts +8 -5
- package/types/src/class/ListSignal.d.mts +123 -18
- package/types/src/class/LitExp.d.mts +361 -0
- package/types/src/class/Paths.d.mts +18 -1
- package/types/src/class/QChannel.d.mts +69 -22
- package/types/src/class/SafeExit.d.mts +24 -9
- package/types/src/class/Setup.d.mts +6 -5
- package/types/src/class/Signal.d.mts +73 -17
- package/types/src/class/WorkerMainThread.d.mts +39 -37
- package/types/src/class/WorkerMainThreadBundled.d.mts +85 -0
- package/types/src/class/WorkerThread.d.mts +32 -27
- package/types/src/common/Base64URL.d.mts +22 -1
- package/types/src/common/Base64URLFromFile.d.mts +16 -0
- package/types/src/common/keys.d.mts +1 -0
- package/types/src/doc/JSautoDOC.d.mts +3 -19
- package/types/src/doc/parsedFile.d.mts +72 -13
- package/types/src/function/CreateImmutable.d.mts +27 -2
- package/types/src/function/EventCheck.d.mts +15 -0
- package/types/src/function/EventObject.d.mts +17 -2
- package/types/src/function/GetRuntime.d.mts +2 -0
- package/types/src/function/IsAsync.d.mts +18 -0
- package/types/src/function/LazyFactory.d.mts +35 -2
- package/types/src/function/Timeout.d.mts +16 -0
- package/types/src/function/Try.d.mts +52 -1
- package/types/src/function/TryAsync.d.mts +22 -1
- package/types/src/function/TrySync.d.mts +16 -1
- package/types/src/function/TsToMjs.d.mts +19 -0
- package/types/src/types/LitExpKeyType.d.mts +1 -0
- package/types/src/types/QCBReturn.d.mts +1 -1
- package/types/src/types/Runtime.d.mts +1 -0
- package/dev/index.mjs +0 -28
- package/src/bundler/CompileMJS.mjs +0 -110
- package/src/function/WriteFileSafe.mjs +0 -37
- package/types/src/bundler/A.d.mts +0 -1
- package/types/src/bundler/CompileMJS.d.mts +0 -8
- package/types/src/function/WriteFileSafe.d.mts +0 -2
package/src/class/QChannel.mjs
CHANGED
|
@@ -2,13 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
import { LazyFactory } from '../function/LazyFactory.mjs';
|
|
4
4
|
import { TryAsync } from '../function/TryAsync.mjs';
|
|
5
|
+
import { TrySync } from '../function/TrySync.mjs';
|
|
6
|
+
import { Console } from './Console.mjs';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* @description
|
|
8
10
|
* - class for `Queue` handling;
|
|
9
|
-
* @template {AnyButUndefined}
|
|
11
|
+
* @template {AnyButUndefined} DEFINEDANY
|
|
10
12
|
*/
|
|
11
13
|
export class QChannel {
|
|
14
|
+
/**
|
|
15
|
+
* @param {string} name
|
|
16
|
+
* - only used as helper for logging, and has nothing to do with runtime behaviour;
|
|
17
|
+
*/
|
|
18
|
+
constructor(name) {
|
|
19
|
+
this.name = name;
|
|
20
|
+
this.open();
|
|
21
|
+
}
|
|
12
22
|
/**
|
|
13
23
|
* @typedef {import('../types/AnyButUndefined.mjs').AnyButUndefined} AnyButUndefined
|
|
14
24
|
* @typedef {import('../types/QCBReturn.mjs').QCBReturn} QCBReturn
|
|
@@ -20,6 +30,11 @@ export class QChannel {
|
|
|
20
30
|
* @param {Map<AnyButUndefined, [Promise<any>, {}]>} uniqueMap
|
|
21
31
|
* @returns {typeof QChannel}
|
|
22
32
|
* - usefull for Queue primitive on multiple library but single reference, like the Web by making the `Map` on `window` object;
|
|
33
|
+
* @example
|
|
34
|
+
* import { QChannel } from 'vivth';
|
|
35
|
+
*
|
|
36
|
+
* const myMappedQref = (window['myMappedQref'] = new Map());
|
|
37
|
+
* export const MyQClass = QChannel.makeQClass(myMappedQref);
|
|
23
38
|
*/
|
|
24
39
|
static makeQClass = (uniqueMap) => {
|
|
25
40
|
QChannel.#uniquePromiser = uniqueMap;
|
|
@@ -33,9 +48,10 @@ export class QChannel {
|
|
|
33
48
|
* - ensures that each id has only one task running at a time.
|
|
34
49
|
* - calls with the same id will wait for the previous call to finish.
|
|
35
50
|
* @param {AnyButUndefined} id
|
|
51
|
+
* @param {QChannel} instance
|
|
36
52
|
* @returns {Promise<QCBReturn>} Resolves when it's safe to proceed for the given id, returning a cleanup function
|
|
37
53
|
*/
|
|
38
|
-
static #uniqueCB = async (id) => {
|
|
54
|
+
static #uniqueCB = async (id, instance) => {
|
|
39
55
|
const existing = QChannel.#uniquePromiser.get(id);
|
|
40
56
|
let resolveFn;
|
|
41
57
|
const nextPromise = new Promise((resolve) => {
|
|
@@ -56,9 +72,12 @@ export class QChannel {
|
|
|
56
72
|
};
|
|
57
73
|
return {
|
|
58
74
|
resume,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
isLastOnQ: () => {
|
|
76
|
+
if (!QChannel.#uniquePromiser.has(id)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const [, lastContext] = QChannel.#uniquePromiser.get(id);
|
|
80
|
+
return instance.#shouldRun && lastContext === context;
|
|
62
81
|
},
|
|
63
82
|
};
|
|
64
83
|
};
|
|
@@ -67,7 +86,7 @@ export class QChannel {
|
|
|
67
86
|
* - first in first out handler
|
|
68
87
|
*/
|
|
69
88
|
static fifo = LazyFactory(() => {
|
|
70
|
-
const qfifo = new QChannel();
|
|
89
|
+
const qfifo = new QChannel('main fifo');
|
|
71
90
|
return {
|
|
72
91
|
/**
|
|
73
92
|
* @static fifo
|
|
@@ -91,15 +110,20 @@ export class QChannel {
|
|
|
91
110
|
* @static fifo
|
|
92
111
|
* @description
|
|
93
112
|
* - blocks execution for subsequent calls until the current one finishes.
|
|
94
|
-
* @template
|
|
95
|
-
* @param {()=>Promise<
|
|
96
|
-
* @returns {Promise<[
|
|
113
|
+
* @template RESULT
|
|
114
|
+
* @param {()=>Promise<RESULT>} asyncCallback
|
|
115
|
+
* @returns {Promise<[RESULT|undefined, Error|undefined]>}
|
|
97
116
|
* @example
|
|
98
117
|
* const [result, error] = await QChannel.fifo.callback(async () = > {
|
|
99
118
|
* // code
|
|
100
119
|
* })
|
|
101
120
|
*/
|
|
102
|
-
callback: async (
|
|
121
|
+
callback: async (
|
|
122
|
+
/**
|
|
123
|
+
* @type {()=>Promise<RESULT>}
|
|
124
|
+
*/
|
|
125
|
+
asyncCallback
|
|
126
|
+
) => {
|
|
103
127
|
return await TryAsync(async () => {
|
|
104
128
|
const { resume } = await this.fifo.key();
|
|
105
129
|
const result = await asyncCallback();
|
|
@@ -110,17 +134,42 @@ export class QChannel {
|
|
|
110
134
|
};
|
|
111
135
|
});
|
|
112
136
|
/**
|
|
113
|
-
* @type {Map<
|
|
137
|
+
* @type {Map<DEFINEDANY, WeakKey>}
|
|
114
138
|
*/
|
|
115
139
|
#mapped = new Map();
|
|
140
|
+
/**
|
|
141
|
+
* @type {boolean}
|
|
142
|
+
*/
|
|
143
|
+
#shouldRun_;
|
|
144
|
+
/**
|
|
145
|
+
* @returns {boolean}
|
|
146
|
+
*/
|
|
147
|
+
get #shouldRun() {
|
|
148
|
+
const shoulRun = this.#shouldRun_;
|
|
149
|
+
if (!shoulRun) {
|
|
150
|
+
Console.warn({ qChannel_name: this.name, message: 'is closed' });
|
|
151
|
+
}
|
|
152
|
+
return shoulRun;
|
|
153
|
+
}
|
|
116
154
|
/**
|
|
117
155
|
* @description
|
|
118
|
-
* -
|
|
119
|
-
* -
|
|
156
|
+
* - disable queue;
|
|
157
|
+
* - when `closed`, `isLastOnQ` will allways return `false`;
|
|
120
158
|
* @returns {void}
|
|
121
159
|
*/
|
|
122
|
-
|
|
123
|
-
this.#
|
|
160
|
+
close = () => {
|
|
161
|
+
this.#shouldRun_ = false;
|
|
162
|
+
Console.info({ qChannel_name: this.name, message: 'closed' });
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* @description
|
|
166
|
+
* - enable queue;
|
|
167
|
+
* - when `opened`, `isLastOnQ` will evaluate whether calls are actually the last of queue;
|
|
168
|
+
* @returns {void}
|
|
169
|
+
*/
|
|
170
|
+
open = () => {
|
|
171
|
+
this.#shouldRun_ = true;
|
|
172
|
+
Console.info({ qChannel_name: this.name, message: 'opened' });
|
|
124
173
|
};
|
|
125
174
|
/**
|
|
126
175
|
* @description
|
|
@@ -128,13 +177,13 @@ export class QChannel {
|
|
|
128
177
|
* - caveat:
|
|
129
178
|
* >- need to manually call resume();
|
|
130
179
|
* >- slightly more performant than `callback`;
|
|
131
|
-
* @param {
|
|
180
|
+
* @param {DEFINEDANY} keyID
|
|
132
181
|
* @returns {Promise<QCBReturn>}
|
|
133
182
|
* @example
|
|
134
|
-
* const q = new QChannel();
|
|
183
|
+
* const q = new QChannel('channel name');
|
|
135
184
|
* const handler = async () => {
|
|
136
185
|
* const { resume, isLastOnQ } = await q.key(keyID);
|
|
137
|
-
* // if (!isLastOnQ) { // imperative debounce if needed
|
|
186
|
+
* // if (!isLastOnQ()) { // imperative debounce if needed
|
|
138
187
|
* // resume();
|
|
139
188
|
* // return;
|
|
140
189
|
* // }
|
|
@@ -146,13 +195,13 @@ export class QChannel {
|
|
|
146
195
|
* handler();
|
|
147
196
|
*/
|
|
148
197
|
key = async (keyID) => {
|
|
149
|
-
const { resume } = await QChannel.#uniqueCB(this);
|
|
198
|
+
const { resume } = await QChannel.#uniqueCB(this, this);
|
|
150
199
|
const mapped = this.#mapped;
|
|
151
200
|
if (!mapped.has(keyID)) {
|
|
152
201
|
mapped.set(keyID, {});
|
|
153
202
|
}
|
|
154
203
|
resume();
|
|
155
|
-
return await QChannel.#uniqueCB(mapped.get(keyID));
|
|
204
|
+
return await QChannel.#uniqueCB(mapped.get(keyID), this);
|
|
156
205
|
};
|
|
157
206
|
/**
|
|
158
207
|
* @description
|
|
@@ -160,25 +209,27 @@ export class QChannel {
|
|
|
160
209
|
* - caveat:
|
|
161
210
|
* >- no need to manually call resume();
|
|
162
211
|
* >- slightly less performant than `callback`;
|
|
163
|
-
* @template
|
|
164
|
-
* @param {
|
|
165
|
-
* @param {(options:Omit<QCBReturn,
|
|
166
|
-
*
|
|
212
|
+
* @template RESULT
|
|
213
|
+
* @param {DEFINEDANY} keyID
|
|
214
|
+
* @param {(options:Omit<QCBReturn,
|
|
215
|
+
* "resume">) =>
|
|
216
|
+
* Promise<RESULT>} asyncCallback
|
|
217
|
+
* @returns {ReturnType<typeof TryAsync<RESULT>>}
|
|
167
218
|
* @example
|
|
168
|
-
* const q = new QChannel();
|
|
219
|
+
* const q = new QChannel('channel name');
|
|
169
220
|
* const [result, error] = await q.callback(keyID, async ({ isLastOnQ }) = > {
|
|
170
|
-
* // if (!isLastOnQ) { // imperative debounce if needed
|
|
221
|
+
* // if (!isLastOnQ()) { // imperative debounce if needed
|
|
171
222
|
* // return;
|
|
172
223
|
* // }
|
|
173
224
|
* // code
|
|
174
225
|
* })
|
|
175
226
|
*/
|
|
176
|
-
|
|
227
|
+
async callback(keyID, asyncCallback) {
|
|
177
228
|
return await TryAsync(async () => {
|
|
178
229
|
const { resume, isLastOnQ } = await this.key(keyID);
|
|
179
230
|
const result = await asyncCallback({ isLastOnQ });
|
|
180
231
|
resume();
|
|
181
232
|
return result;
|
|
182
233
|
});
|
|
183
|
-
}
|
|
234
|
+
}
|
|
184
235
|
}
|
package/src/class/SafeExit.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import { TryAsync } from '../function/TryAsync.mjs';
|
|
4
|
+
import { TrySync } from '../function/TrySync.mjs';
|
|
4
5
|
import { Console } from './Console.mjs';
|
|
5
6
|
import { Effect, setOfEffects } from './Effect.mjs';
|
|
6
7
|
import { EnvSignal } from './EnvSignal.mjs';
|
|
@@ -15,7 +16,7 @@ export const safeCleanUpCBs = new Set();
|
|
|
15
16
|
* @description
|
|
16
17
|
* - class helper for describing how to Safely Response on exit events
|
|
17
18
|
* - singleton;
|
|
18
|
-
*
|
|
19
|
+
* - most of functionality might need to access `SafeExit.instance.exiting`, if you get warning, you can instantiate `SafeExit` before running anything;
|
|
19
20
|
*/
|
|
20
21
|
export class SafeExit {
|
|
21
22
|
/**
|
|
@@ -27,7 +28,13 @@ export class SafeExit {
|
|
|
27
28
|
/**
|
|
28
29
|
* @description
|
|
29
30
|
* @param {Object} options
|
|
30
|
-
* @param {
|
|
31
|
+
* @param {[string, ...string[]]} options.eventNames
|
|
32
|
+
* - eventNames are blank by default, you need to manually name them all;
|
|
33
|
+
* - 'exit' will be omited, as it might cause async callbacks failed to execute;
|
|
34
|
+
* - example:
|
|
35
|
+
* ```js
|
|
36
|
+
* ['SIGINT', 'SIGTERM']
|
|
37
|
+
* ```
|
|
31
38
|
* @param {()=>void} options.terminator
|
|
32
39
|
* - standard node/bun:
|
|
33
40
|
* ```js
|
|
@@ -47,17 +54,26 @@ export class SafeExit {
|
|
|
47
54
|
* });
|
|
48
55
|
* };
|
|
49
56
|
* ```
|
|
57
|
+
* - example Deno:
|
|
58
|
+
* ```js
|
|
59
|
+
* (eventName) => {
|
|
60
|
+
* const sig = Deno.signal(eventName);
|
|
61
|
+
* for await (const _ of sig) {
|
|
62
|
+
* exiting.correction(true);
|
|
63
|
+
* sig.dispose();
|
|
64
|
+
* Console.log(`safe exit via "${eventName}"`);
|
|
65
|
+
* }
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
50
68
|
* - if your exit callback doesn't uses `process` global object you need to input on the SafeExit instantiation
|
|
51
69
|
* @example
|
|
52
70
|
* import { SafeExit, Console } from 'vivth';
|
|
53
71
|
*
|
|
54
72
|
* new SafeExit({
|
|
55
|
-
* // eventNames are blank by default, you need to manually name them all;
|
|
56
|
-
* // 'exit' will be omited, as it might cause async callbacks failed to execute;
|
|
57
73
|
* eventNames: ['SIGINT', 'SIGTERM', ...eventNames],
|
|
58
|
-
* terminator
|
|
74
|
+
* terminator : () => process.exit(0), // OR on deno () => Deno.exit(0),
|
|
59
75
|
* // optional deno example
|
|
60
|
-
* listener
|
|
76
|
+
* listener : (eventName) => {
|
|
61
77
|
* const sig = Deno.signal(eventName);
|
|
62
78
|
* for await (const _ of sig) {
|
|
63
79
|
* exiting.correction(true);
|
|
@@ -86,12 +102,12 @@ export class SafeExit {
|
|
|
86
102
|
*/
|
|
87
103
|
exiting = new EnvSignal(false);
|
|
88
104
|
/**
|
|
89
|
-
* @param {eventNames} eventNames
|
|
105
|
+
* @param {ConstructorParameters<typeof SafeExit>[0]["eventNames"]} eventNames
|
|
90
106
|
* @returns {void}
|
|
91
107
|
*/
|
|
92
108
|
#register = (eventNames) => {
|
|
93
109
|
eventNames.forEach((eventName) => {
|
|
94
|
-
if (eventName
|
|
110
|
+
if (eventName.toLowerCase() === 'exit') {
|
|
95
111
|
return;
|
|
96
112
|
}
|
|
97
113
|
this.#listener(eventName);
|
|
@@ -137,14 +153,18 @@ export class SafeExit {
|
|
|
137
153
|
effect.options.removeEffect();
|
|
138
154
|
});
|
|
139
155
|
for await (const cleanup of safeCleanUpCBs) {
|
|
140
|
-
const [
|
|
156
|
+
const [, error] = await TryAsync(async () => {
|
|
141
157
|
await cleanup();
|
|
142
158
|
});
|
|
143
159
|
if (!error) {
|
|
144
160
|
continue;
|
|
145
161
|
}
|
|
146
|
-
Console.
|
|
162
|
+
Console.warn(error);
|
|
163
|
+
}
|
|
164
|
+
const [, errorExitting] = TrySync(this.#exit);
|
|
165
|
+
if (!errorExitting) {
|
|
166
|
+
return;
|
|
147
167
|
}
|
|
148
|
-
|
|
168
|
+
Console.error(errorExitting);
|
|
149
169
|
});
|
|
150
170
|
}
|
package/src/class/Setup.mjs
CHANGED
|
@@ -49,9 +49,10 @@ export class Setup {
|
|
|
49
49
|
* - proxy `WorkerMainThread_instance` for Setup;
|
|
50
50
|
* @example
|
|
51
51
|
* import { Setup } from 'vivth';
|
|
52
|
+
* import { Worker } from 'node:worker_threads';
|
|
52
53
|
*
|
|
53
54
|
* Setup.workerMain({
|
|
54
|
-
* workerClass:
|
|
55
|
+
* workerClass: Worker,
|
|
55
56
|
* basePath: 'public/assets/js/workers',
|
|
56
57
|
* pathValidator: async (workerPath, root, base) => {
|
|
57
58
|
* const res = await fetch(`${root}/${base}/${workerPath}`);
|
|
@@ -64,10 +65,12 @@ export class Setup {
|
|
|
64
65
|
/**
|
|
65
66
|
* @description
|
|
66
67
|
* - correct `parentPort` reference when needed;
|
|
68
|
+
* - export to create new reference to be use to create new WorkerThread instance;
|
|
67
69
|
* @example
|
|
68
70
|
* import { Setup } from 'vivth';
|
|
71
|
+
* import { parentPort } from 'node:worker_threads';
|
|
69
72
|
*
|
|
70
|
-
* Setup.workerThread({
|
|
73
|
+
* export const MyWorkerThreadRef = Setup.workerThread({parentPort});
|
|
71
74
|
* // that is the default value, if your parentPort/equivalent API is not that;
|
|
72
75
|
* // you need to call this method;
|
|
73
76
|
*/
|
package/src/class/Signal.mjs
CHANGED
|
@@ -14,9 +14,22 @@ export const setOFSignals = new Set();
|
|
|
14
14
|
/**
|
|
15
15
|
* @description
|
|
16
16
|
* - a class for creating effect to signals;
|
|
17
|
-
* @template
|
|
17
|
+
* @template VALUE
|
|
18
18
|
*/
|
|
19
19
|
export class Signal {
|
|
20
|
+
/**
|
|
21
|
+
* @description
|
|
22
|
+
* - create a `Signal`;
|
|
23
|
+
* @param {VALUE} value
|
|
24
|
+
* @example
|
|
25
|
+
* import { Signal, Effect } from 'vivth';
|
|
26
|
+
*
|
|
27
|
+
* const count = new Signal(0);
|
|
28
|
+
*/
|
|
29
|
+
constructor(value) {
|
|
30
|
+
this.#value = value;
|
|
31
|
+
setOFSignals.add(this);
|
|
32
|
+
}
|
|
20
33
|
/**
|
|
21
34
|
* @description
|
|
22
35
|
* - subsrcibers reference of this instance;
|
|
@@ -33,17 +46,17 @@ export class Signal {
|
|
|
33
46
|
* @instance subscribers
|
|
34
47
|
* @description
|
|
35
48
|
* - manually notify on non primitive value or value that have depths;
|
|
36
|
-
* @param {(options:{signalInstance:Signal<
|
|
49
|
+
* @param {(options:{signalInstance:Signal<VALUE>})=>Promise<void>} [callback]
|
|
37
50
|
* @returns {void}
|
|
38
51
|
* @example
|
|
39
|
-
*
|
|
52
|
+
* import { Signal } from 'vivth';
|
|
40
53
|
*
|
|
54
|
+
* // for deep signal like array or object you can:
|
|
41
55
|
* const arraySignal = new Signal([1,2]);
|
|
42
56
|
* arraySignal.value.push(3);
|
|
43
57
|
* arraySignal.subscribers.notify();
|
|
44
58
|
*
|
|
45
59
|
* // OR for more complex mutation:
|
|
46
|
-
*
|
|
47
60
|
* const objectSignal = new Signal({a:'test', b:'test'});
|
|
48
61
|
* objectSignal.subscribers.notify(async ({ signalInstance }) => {
|
|
49
62
|
* signalInstance.value['c'] = 'testc';
|
|
@@ -57,7 +70,7 @@ export class Signal {
|
|
|
57
70
|
}
|
|
58
71
|
TryAsync(async () => {
|
|
59
72
|
await callback({ signalInstance: this });
|
|
60
|
-
}).then(([
|
|
73
|
+
}).then(([, error]) => {
|
|
61
74
|
if (error) {
|
|
62
75
|
Console.error({ message: 'unable to run callback', callback, error });
|
|
63
76
|
return;
|
|
@@ -70,7 +83,7 @@ export class Signal {
|
|
|
70
83
|
* @param {Set<Effect>} setOfSubscribers
|
|
71
84
|
*/
|
|
72
85
|
static #notify = (setOfSubscribers) => {
|
|
73
|
-
const [
|
|
86
|
+
const [, error] = TrySync(() => {
|
|
74
87
|
const effects = setOfSubscribers;
|
|
75
88
|
effects.forEach((effect) => {
|
|
76
89
|
if (!setOfEffects.has(effect)) {
|
|
@@ -126,38 +139,27 @@ export class Signal {
|
|
|
126
139
|
setOFSignals.delete(this);
|
|
127
140
|
},
|
|
128
141
|
}));
|
|
142
|
+
|
|
129
143
|
/**
|
|
130
|
-
* @
|
|
131
|
-
* @param {Value} value
|
|
132
|
-
* @example
|
|
133
|
-
* import { Signal, Effect } from 'vivth';
|
|
134
|
-
*
|
|
135
|
-
* const count = new Signal(0);
|
|
136
|
-
*/
|
|
137
|
-
constructor(value) {
|
|
138
|
-
this.#value = value;
|
|
139
|
-
setOFSignals.add(this);
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* @type {Value}
|
|
144
|
+
* @type {VALUE}
|
|
143
145
|
*/
|
|
144
146
|
#prev = undefined;
|
|
145
147
|
/**
|
|
146
148
|
* @description
|
|
147
149
|
* - value before change;
|
|
148
|
-
* @
|
|
150
|
+
* @returns {VALUE}
|
|
149
151
|
*/
|
|
150
152
|
get prev() {
|
|
151
153
|
return this.#prev;
|
|
152
154
|
}
|
|
153
155
|
/**
|
|
154
|
-
* @type {
|
|
156
|
+
* @type {VALUE}
|
|
155
157
|
*/
|
|
156
158
|
#value;
|
|
157
159
|
/**
|
|
158
160
|
* @description
|
|
159
161
|
* - value after change;
|
|
160
|
-
* @
|
|
162
|
+
* @returns {VALUE}
|
|
161
163
|
* @example
|
|
162
164
|
* import { Signal, Effect, Derived } from 'vivth';
|
|
163
165
|
*
|
|
@@ -167,7 +169,7 @@ export class Signal {
|
|
|
167
169
|
* new Effect(async ({ subscribe }) =>{
|
|
168
170
|
* const countValue = subscribe(count).value; // reactive
|
|
169
171
|
* })
|
|
170
|
-
* const oneMoreThanCount = new
|
|
172
|
+
* const oneMoreThanCount = new Derived(async ({ subscribe }) =>{
|
|
171
173
|
* return subscribe(count).value + 1; // reactive
|
|
172
174
|
* })
|
|
173
175
|
*/
|
|
@@ -177,7 +179,7 @@ export class Signal {
|
|
|
177
179
|
/**
|
|
178
180
|
* @description
|
|
179
181
|
* - assign new value then automatically notify all subscribers;
|
|
180
|
-
* @type {
|
|
182
|
+
* @type {VALUE}
|
|
181
183
|
* @example
|
|
182
184
|
* import { Signal } from 'vivth';
|
|
183
185
|
*
|