vivth 1.3.5 → 1.3.7

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/README.md CHANGED
@@ -73,11 +73,13 @@ npm i vivth
73
73
  - [SafeExit](#safeexit)
74
74
  - [Setup](#setup)
75
75
  - [Signal](#signal)
76
+ - [WalkThrough](#walkthrough)
76
77
  - [WorkerMainThread](#workermainthread)
77
78
  - [WorkerResult](#workerresult)
78
79
  - [WorkerThread](#workerthread)
79
80
  - [Base64URL](#base64url)
80
81
  - [Base64URLFromFile](#base64urlfromfile)
82
+ - [CreateStringID](#createstringid)
81
83
  - [Dev](#dev)
82
84
  - [EventNameSpace](#eventnamespace)
83
85
  - [Trace](#trace)
@@ -666,12 +668,13 @@ const effect = new Effect(async ({ isLastCalled }) => {
666
668
 
667
669
  #### reference:`Effect_instance.options.subscribe`
668
670
 
671
+ - subscribe to `Signal_instance`;
669
672
  - normally it's passed as argument to constructor, however it is also accessible from `options` property;
670
673
 
671
674
  ```js
672
675
  /**
673
676
  * @template V
674
- * @param {Signal<V>} signal
677
+ * @param {Signal<V>} signalInstance
675
678
  * @returns {Signal<V>}
676
679
  */
677
680
  ```
@@ -708,6 +711,33 @@ const effect = new Effect(async () => {
708
711
  effect.options.removeEffect();
709
712
  ```
710
713
 
714
+ #### reference:`Effect_instance.removeSignal`
715
+
716
+ - remove inputed signal from this `Effect_instance`;
717
+ - if effect signal has no other `Signal_instance` to listen to, it will then completely rendered non reactive;
718
+ - normally it's passed as argument to constructor, however it is also accessible from `options` property;
719
+
720
+ ```js
721
+ /**
722
+ * @param {Signal<any>} signalInstance
723
+ * @returns {void}
724
+ */
725
+ ```
726
+
727
+ - <i>example</i>:
728
+
729
+ ```js
730
+ import { Effect, Signal } from "vivth";
731
+
732
+ const count = new Signal(0);
733
+ const effect = new Effect(async ({ subscribe }) => {
734
+ console.log(subscribe(count).value); // will subscribe count changes;
735
+ });
736
+ count.value++; // will increase the count and trigger effect;
737
+ effect.options.removeSignal(count);
738
+ count.value++; // will increase the count but will no longer trigger effect;
739
+ ```
740
+
711
741
  #### reference:`new Effect`
712
742
 
713
743
  ```js
@@ -1100,7 +1130,7 @@ eventSignal_instance.remove.ref();
1100
1130
  import { join } from "node:path";
1101
1131
  import { FileSafe, Paths } from "vivth";
1102
1132
 
1103
- const [, error] = await FileSafe.write(join(Paths.root, "/some/path.mjs"));
1133
+ const [, error] = await FileSafe.exist(join(Paths.root, "/some/path.mjs"));
1104
1134
  if (!error) {
1105
1135
  // file exists
1106
1136
  } else {
@@ -1871,7 +1901,7 @@ resume();
1871
1901
  /**
1872
1902
  * @template RESULT
1873
1903
  * @param {()=>Promise<RESULT>} asyncCallback
1874
- * @returns {Promise<[RESULT|undefined, Error|undefined]>}
1904
+ * @returns {ReturnType<typeof TryAsync<RESULT>>}
1875
1905
  */
1876
1906
  ```
1877
1907
 
@@ -2347,6 +2377,108 @@ count.value = 9;
2347
2377
 
2348
2378
  \*) <sub>[go to list of exported API and typehelpers](#list-of-exported-api-and-typehelpers)</sub>
2349
2379
 
2380
+ <h2 id="walkthrough">WalkThrough</h2>
2381
+
2382
+ #### reference:`WalkThrough`
2383
+
2384
+ - collection of static `methods` to walktrhough things, instead of regular looping;
2385
+ - usefull to iterator that might be modified during iteration;
2386
+ - mostlikely to be less performant, but with better result clarity;
2387
+
2388
+ #### reference:`WalkThrough.set`
2389
+
2390
+ - method helper to WalkThrough `Set`;
2391
+
2392
+ ```js
2393
+ /**
2394
+ * @template VAL
2395
+ * @param {Set<VAL>} setInstance
2396
+ * @param {(value:VAL)=>void} callback
2397
+ * @returns {void}
2398
+ */
2399
+ ```
2400
+
2401
+ - <i>example</i>:
2402
+
2403
+ ```js
2404
+ import { WalkThrough } from "vivth";
2405
+
2406
+ WalkThrough.set(setOfSomething, (value) => {
2407
+ // code
2408
+ });
2409
+ ```
2410
+
2411
+ #### reference:`WalkThrough.map`
2412
+
2413
+ - method helper to WalkThrough `Map`;
2414
+
2415
+ ```js
2416
+ /**
2417
+ * @template KEY, VAL
2418
+ * @param {Map<KEY, VAL>} mapInstance
2419
+ * @param {(res:[key: KEY, value: VAL]) => void} callback
2420
+ * @returns {void}
2421
+ */
2422
+ ```
2423
+
2424
+ - <i>example</i>:
2425
+
2426
+ ```js
2427
+ import { WalkThrough } from "vivth";
2428
+
2429
+ WalkThrough.map(mapOfSomething, ([key, value]) => {
2430
+ // code
2431
+ });
2432
+ ```
2433
+
2434
+ #### reference:`WalkThrough.array`
2435
+
2436
+ - method helper to WalkThrough `Array`;
2437
+
2438
+ ```js
2439
+ /**
2440
+ * @template VAL
2441
+ * @param {VAL[]} arrayInstance
2442
+ * @param {(res:[value: VAL, index: number]) => void} callback
2443
+ * @returns {void}
2444
+ */
2445
+ ```
2446
+
2447
+ - <i>example</i>:
2448
+
2449
+ ```js
2450
+ import { WalkThrough } from "vivth";
2451
+
2452
+ WalkThrough.array(arrayOfSomething, ([value, index]) => {
2453
+ // code
2454
+ });
2455
+ ```
2456
+
2457
+ #### reference:`WalkThrough.generator`
2458
+
2459
+ - method helper to WalkThrough `Generator`;
2460
+
2461
+ ```js
2462
+ /**
2463
+ * @template T
2464
+ * @param {Generator<T, any, any>} generatorInstance
2465
+ * @param {(value: T) => void} callback
2466
+ * @returns {void}
2467
+ */
2468
+ ```
2469
+
2470
+ - <i>example</i>:
2471
+
2472
+ ```js
2473
+ import { WalkThrough } from "vivth";
2474
+
2475
+ WalkThrough.generator(generatorOfSomething, (value) => {
2476
+ // code
2477
+ });
2478
+ ```
2479
+
2480
+ \*) <sub>[go to list of exported API and typehelpers](#list-of-exported-api-and-typehelpers)</sub>
2481
+
2350
2482
  <h2 id="workermainthread">WorkerMainThread</h2>
2351
2483
 
2352
2484
  #### reference:`WorkerMainThread`
@@ -2681,6 +2813,37 @@ await Base64URLFromFile(join(Paths.root, "/path/to/file"));
2681
2813
 
2682
2814
  \*) <sub>[go to list of exported API and typehelpers](#list-of-exported-api-and-typehelpers)</sub>
2683
2815
 
2816
+ <h2 id="createstringid">CreateStringID</h2>
2817
+
2818
+ #### reference:`CreateStringID`
2819
+
2820
+ - function helper to generate absolute unique ID;
2821
+ - the asynchrounous nature is to prevent race condition that might resulting same Id being generated;
2822
+ > - queued using QChannel;
2823
+
2824
+ ```js
2825
+ /**
2826
+ * @param {string} [prefix]
2827
+ * @returns {ReturnType<typeof TryAsync<string>>}
2828
+ */
2829
+ ```
2830
+
2831
+ - <i>example</i>:
2832
+
2833
+ ```js
2834
+ import { CreateStringID } from "vivth";
2835
+
2836
+ (async () => {
2837
+ const [myUniqueID, errorCreatingUniqueID] = await CreateStringID("myPrefix");
2838
+ if (errorCreatingUniqueID) {
2839
+ return;
2840
+ }
2841
+ Console.log(myUniqueID); // `myPrefix${Date.now()}`
2842
+ })();
2843
+ ```
2844
+
2845
+ \*) <sub>[go to list of exported API and typehelpers](#list-of-exported-api-and-typehelpers)</sub>
2846
+
2684
2847
  <h2 id="dev">Dev</h2>
2685
2848
 
2686
2849
  #### reference:`Dev`
@@ -3134,13 +3297,13 @@ test();
3134
3297
  import { Try } from "vivth";
3135
3298
 
3136
3299
  const [[key, result], error] = await Try({
3137
- someRuntime: async (prevError) => {
3300
+ someRuntime: async ({ prevError }) => {
3138
3301
  // asuming on this one doesn't naturally throw error,
3139
3302
  // yet you need to continue to next key,
3140
3303
  // instead of returning,
3141
3304
  // you should throw new Error(something);
3142
3305
  },
3143
- browser: async (prevError) => {
3306
+ browser: async ({ prevError }) => {
3144
3307
  return location?.origin;
3145
3308
  // if no error, stop other key function from running;
3146
3309
  // key = 'browser'
@@ -3149,7 +3312,7 @@ const [[key, result], error] = await Try({
3149
3312
  // if error;
3150
3313
  // run nodeOrBun;
3151
3314
  },
3152
- nodeOrBun: async (prevError) => {
3315
+ nodeOrBun: async ({ prevError }) => {
3153
3316
  return process?.env?.INIT_CWD ?? process?.cwd();
3154
3317
  // if no error;
3155
3318
  // key = 'nodeOrBun'
package/index.mjs CHANGED
@@ -26,11 +26,13 @@ export { QChannel } from './src/class/QChannel.mjs';
26
26
  export { SafeExit } from './src/class/SafeExit.mjs';
27
27
  export { Setup } from './src/class/Setup.mjs';
28
28
  export { Signal } from './src/class/Signal.mjs';
29
+ export { WalkThrough } from './src/class/WalkThrough.mjs';
29
30
  export { WorkerMainThread } from './src/class/WorkerMainThread.mjs';
30
31
  export { WorkerResult } from './src/class/WorkerResult.mjs';
31
32
  export { WorkerThread } from './src/class/WorkerThread.mjs';
32
33
  export { Base64URL } from './src/common/Base64URL.mjs';
33
34
  export { Base64URLFromFile } from './src/common/Base64URLFromFile.mjs';
35
+ export { CreateStringID } from './src/common/CreateStringID.mjs';
34
36
  export { Dev } from './src/common/Dev.mjs';
35
37
  export { EventNameSpace } from './src/common/EventNameSpace.mjs';
36
38
  export { Trace } from './src/common/Trace.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vivth",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "description": "library primitives",
5
5
  "main": "index.mjs",
6
6
  "types": "./types/index.d.mts",
@@ -1,6 +1,7 @@
1
1
  // @ts-check
2
2
 
3
3
  import { unwrapLazy } from '../common/lazie.mjs';
4
+ import { WalkThrough } from './WalkThrough.mjs';
4
5
  import { LazyFactory } from '../function/LazyFactory.mjs';
5
6
  import { Timeout } from '../function/Timeout.mjs';
6
7
  import { TryAsync } from '../function/TryAsync.mjs';
@@ -8,9 +9,9 @@ import { Console } from './Console.mjs';
8
9
  import { Signal } from './Signal.mjs';
9
10
 
10
11
  /**
11
- * @type {Set<Effect>}
12
+ * @type {Map<Effect, Set<Signal<any>>>}
12
13
  */
13
- export const setOfEffects = new Set();
14
+ export const mapOfEffects = new Map();
14
15
 
15
16
  /**
16
17
  * @description
@@ -68,9 +69,10 @@ export class Effect {
68
69
  /**
69
70
  * @instance options
70
71
  * @description
72
+ * - subscribe to `Signal_instance`;
71
73
  * - normally it's passed as argument to constructor, however it is also accessible from `options` property;
72
74
  * @template V
73
- * @param {Signal<V>} signal
75
+ * @param {Signal<V>} signalInstance
74
76
  * @returns {Signal<V>}
75
77
  * @example
76
78
  * import { Effect } from 'vivth';
@@ -80,13 +82,13 @@ export class Effect {
80
82
  * })
81
83
  * effect.options.subscribe(signalInstance);
82
84
  */
83
- subscribe: (signal) => {
84
- if (signal instanceof Signal === false) {
85
+ subscribe: (signalInstance) => {
86
+ if (signalInstance instanceof Signal === false) {
85
87
  // @ts-expect-error
86
- signal = signal[unwrapLazy]();
88
+ signalInstance = signalInstance[unwrapLazy]();
87
89
  }
88
- signal.subscribers.setOf.add(this_);
89
- return signal;
90
+ signalInstance.subscribers.setOf.add(this_);
91
+ return signalInstance;
90
92
  },
91
93
  /**
92
94
  * @instance options
@@ -102,7 +104,44 @@ export class Effect {
102
104
  * effect.options.removeEffect();
103
105
  */
104
106
  removeEffect: () => {
105
- setOfEffects.delete(this);
107
+ const setOfSignal = mapOfEffects.get(this);
108
+ if (!setOfSignal) {
109
+ return;
110
+ }
111
+ WalkThrough.set(setOfSignal, (signalInstance) => {
112
+ this.options.removeSignal(signalInstance);
113
+ });
114
+ mapOfEffects.delete(this);
115
+ },
116
+ /**
117
+ * @description
118
+ * - remove inputed signal from this `Effect_instance`;
119
+ * - if effect signal has no other `Signal_instance` to listen to, it will then completely rendered non reactive;
120
+ * - normally it's passed as argument to constructor, however it is also accessible from `options` property;
121
+ * @param {Signal<any>} signalInstance
122
+ * @returns {void}
123
+ * @example
124
+ * import { Effect, Signal } from 'vivth';
125
+ *
126
+ * const count = new Signal(0);
127
+ * const effect = new Effect(async ({ subscribe }) => {
128
+ * console.log(subscribe(count).value); // will subscribe count changes;
129
+ * })
130
+ * count.value++; // will increase the count and trigger effect;
131
+ * effect.options.removeSignal(count);
132
+ * count.value++; // will increase the count but will no longer trigger effect;
133
+ */
134
+ removeSignal: (signalInstance) => {
135
+ signalInstance.subscribers.setOf.delete(this);
136
+ const setOfSignal = mapOfEffects.get(this);
137
+ if (!setOfSignal) {
138
+ return;
139
+ }
140
+ setOfSignal.delete(signalInstance);
141
+ if (setOfSignal.size) {
142
+ return;
143
+ }
144
+ mapOfEffects.delete(this);
106
145
  },
107
146
  };
108
147
  });
@@ -130,7 +169,7 @@ export class Effect {
130
169
  */
131
170
  constructor(effect) {
132
171
  this.#effect = effect;
133
- setOfEffects.add(this);
172
+ mapOfEffects.set(this, new Set());
134
173
  this.run();
135
174
  }
136
175
  /**
@@ -156,6 +195,13 @@ export class Effect {
156
195
  */
157
196
  run = () => {
158
197
  TryAsync(async () => {
198
+ if (
199
+ //
200
+ !mapOfEffects.has(this)
201
+ ) {
202
+ this.options.removeEffect();
203
+ return;
204
+ }
159
205
  await this.#effect(this.options[unwrapLazy]());
160
206
  }).then(([, error]) => {
161
207
  if (error === undefined) {
@@ -27,7 +27,7 @@ export class EventSignal {
27
27
  /**
28
28
  * @type {QChannel<string>}
29
29
  */
30
- static #qChannelEventSignal = new QChannel('EventSignal');
30
+ static #qChannelEventSignal = LazyFactory(() => new QChannel('EventSignal'));
31
31
  /**
32
32
  * @description
33
33
  * - the constructor it self is set to `private`;
@@ -114,6 +114,7 @@ export class EventSignal {
114
114
  */
115
115
  listen = LazyFactory(() => {
116
116
  const dispatch = this.dispatch;
117
+ // @ts-expect-error
117
118
  const _ = dispatch.value;
118
119
  if (this.#isList) {
119
120
  return new ListDerived(async ({ subscribe }) => {
@@ -22,7 +22,7 @@ export class FileSafe {
22
22
  * import { join } from 'node:path';
23
23
  * import { FileSafe, Paths } from 'vivth';
24
24
  *
25
- * const [, error] = await FileSafe.write(
25
+ * const [, error] = await FileSafe.exist(
26
26
  * join(Paths.root, '/some/path.mjs'),
27
27
  * );
28
28
  * if (!error) {
@@ -209,11 +209,6 @@ export class LitExp {
209
209
  return new RegExp(`\(${regExpToMatchStringCache}\)`, flags);
210
210
  });
211
211
  };
212
- /**
213
- * @typedef {ReturnType<LitExp<KEYS>["evaluate"]["execGroups"]>} ExecGroups
214
- * @typedef {ExecGroups extends [infer First, ...any] ? First : undefined} FirstGroup
215
- * @typedef {FirstGroup extends { result: any } ? Partial<FirstGroup["result"]> : undefined} Overrides
216
- */
217
212
  /**
218
213
  * @description
219
214
  * - instance methods for generating things;
@@ -114,7 +114,7 @@ export class QChannel {
114
114
  * - blocks execution for subsequent calls until the current one finishes.
115
115
  * @template RESULT
116
116
  * @param {()=>Promise<RESULT>} asyncCallback
117
- * @returns {Promise<[RESULT|undefined, Error|undefined]>}
117
+ * @returns {ReturnType<typeof TryAsync<RESULT>>}
118
118
  * @example
119
119
  * const [result, error] = await QChannel.fifo.callback(async () = > {
120
120
  * // code
@@ -2,8 +2,9 @@
2
2
 
3
3
  import { TryAsync } from '../function/TryAsync.mjs';
4
4
  import { TrySync } from '../function/TrySync.mjs';
5
+ import { WalkThrough } from './WalkThrough.mjs';
5
6
  import { Console } from './Console.mjs';
6
- import { Effect, setOfEffects } from './Effect.mjs';
7
+ import { Effect, mapOfEffects } from './Effect.mjs';
7
8
  import { EnvSignal } from './EnvSignal.mjs';
8
9
  import { setOFSignals } from './Signal.mjs';
9
10
 
@@ -150,6 +151,7 @@ export class SafeExit {
150
151
  * @type {()=>void}
151
152
  */
152
153
  #exit = () => {};
154
+ // @ts-expect-error
153
155
  #autoCleanUp = new Effect(async ({ subscribe }) => {
154
156
  if (
155
157
  //
@@ -157,10 +159,10 @@ export class SafeExit {
157
159
  ) {
158
160
  return;
159
161
  }
160
- setOFSignals.forEach((signal) => {
162
+ WalkThrough.set(setOFSignals, (signal) => {
161
163
  signal.remove.ref();
162
164
  });
163
- setOfEffects.forEach((effect) => {
165
+ WalkThrough.map(mapOfEffects, ([effect, _]) => {
164
166
  effect.options.removeEffect();
165
167
  });
166
168
  for await (const cleanup of safeCleanUpCBs) {
@@ -1,10 +1,11 @@
1
1
  // @ts-check
2
2
 
3
+ import { WalkThrough } from './WalkThrough.mjs';
3
4
  import { LazyFactory } from '../function/LazyFactory.mjs';
4
5
  import { TryAsync } from '../function/TryAsync.mjs';
5
6
  import { TrySync } from '../function/TrySync.mjs';
6
7
  import { Console } from './Console.mjs';
7
- import { Effect, setOfEffects } from './Effect.mjs';
8
+ import { Effect, mapOfEffects } from './Effect.mjs';
8
9
 
9
10
  /**
10
11
  * @type {Set<Signal<any>>}
@@ -65,7 +66,7 @@ export class Signal {
65
66
  */
66
67
  notify: (callback = undefined) => {
67
68
  if (callback === undefined) {
68
- Signal.#notify(this.subscribers.setOf);
69
+ Signal.#notify(this);
69
70
  return;
70
71
  }
71
72
  TryAsync(async () => {
@@ -75,25 +76,27 @@ export class Signal {
75
76
  Console.error({ message: 'unable to run callback', callback, error });
76
77
  return;
77
78
  }
78
- Signal.#notify(this.subscribers.setOf);
79
+ Signal.#notify(this);
79
80
  });
80
81
  },
81
82
  }));
82
83
  /**
83
- * @param {Set<Effect>} setOfSubscribers
84
+ * @param {Signal<any>} signalInstance
84
85
  */
85
- static #notify = (setOfSubscribers) => {
86
+ static #notify = (signalInstance) => {
86
87
  const [, error] = TrySync(() => {
87
- const effects = setOfSubscribers;
88
- effects.forEach((effect) => {
89
- if (setOfEffects.has(effect) === false) {
90
- effects.delete(effect);
88
+ WalkThrough.set(signalInstance.subscribers.setOf, (effectInstance) => {
89
+ if (
90
+ //
91
+ !mapOfEffects.has(effectInstance)
92
+ ) {
93
+ effectInstance.options.removeSignal(signalInstance);
91
94
  return;
92
95
  }
93
96
  /**
94
- * effect.run is already TryAsync
97
+ * effect.run is already wrapped with TryAsync
95
98
  */
96
- effect.run();
99
+ effectInstance.run();
97
100
  });
98
101
  });
99
102
  if (error === undefined) {
@@ -118,7 +121,7 @@ export class Signal {
118
121
  * this part is not needed, as the effect might need to react to other signals
119
122
  // effectInstance.options.removeEffect();
120
123
  */
121
- this.subscribers.setOf.delete(effectInstance);
124
+ effectInstance.options.removeSignal(this);
122
125
  },
123
126
  /**
124
127
  * @instance remove
@@ -127,8 +130,9 @@ export class Signal {
127
130
  * @type {()=>void}
128
131
  */
129
132
  allSubscribers: () => {
130
- const $ = this.subscribers.setOf;
131
- $.forEach(this.remove.subscriber);
133
+ WalkThrough.set(this.subscribers.setOf, (effectInstance) => {
134
+ this.remove.subscriber(effectInstance);
135
+ });
132
136
  },
133
137
  /**
134
138
  * @instance remove
@@ -0,0 +1,90 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @description
5
+ * - collection of static `methods` to walktrhough things, instead of regular looping;
6
+ * - usefull to iterator that might be modified during iteration;
7
+ * - mostlikely to be less performant, but with better result clarity;
8
+ */
9
+ export class WalkThrough {
10
+ /**
11
+ * @param {Iterator<any, any, any>} iterator
12
+ * @param {(...any:any[])=>void} callback
13
+ * @returns {void}
14
+ */
15
+ static #handler = (iterator, callback) => {
16
+ let result = iterator.next();
17
+ while (!result.done) {
18
+ callback(result.value);
19
+ result = iterator.next();
20
+ }
21
+ };
22
+ /**
23
+ * @description
24
+ * - method helper to WalkThrough `Set`;
25
+ * @template VAL
26
+ * @param {Set<VAL>} setInstance
27
+ * @param {(value:VAL)=>void} callback
28
+ * @returns {void}
29
+ * @example
30
+ * import { WalkThrough } from 'vivth';
31
+ *
32
+ * WalkThrough.set(setOfSomething, (value) => {
33
+ * // code
34
+ * })
35
+ */
36
+ static set(setInstance, callback) {
37
+ WalkThrough.#handler(setInstance.values(), callback);
38
+ };
39
+ /**
40
+ * @description
41
+ * - method helper to WalkThrough `Map`;
42
+ * @template KEY, VAL
43
+ * @param {Map<KEY, VAL>} mapInstance
44
+ * @param {(res:[key: KEY, value: VAL]) => void} callback
45
+ * @returns {void}
46
+ * @example
47
+ * import { WalkThrough } from 'vivth';
48
+ *
49
+ * WalkThrough.map(mapOfSomething, ([key, value]) => {
50
+ * // code
51
+ * })
52
+ */
53
+ static map(mapInstance, callback) {
54
+ WalkThrough.#handler(mapInstance.entries(), callback);
55
+ };
56
+ /**
57
+ * @description
58
+ * - method helper to WalkThrough `Array`;
59
+ * @template VAL
60
+ * @param {VAL[]} arrayInstance
61
+ * @param {(res:[value: VAL, index: number]) => void} callback
62
+ * @returns {void}
63
+ * @example
64
+ * import { WalkThrough } from 'vivth';
65
+ *
66
+ * WalkThrough.array(arrayOfSomething, ([value, index]) => {
67
+ * // code
68
+ * })
69
+ */
70
+ static array(arrayInstance, callback) {
71
+ WalkThrough.#handler(arrayInstance.values(), callback);
72
+ };
73
+ /**
74
+ * @description
75
+ * - method helper to WalkThrough `Generator`;
76
+ * @template T
77
+ * @param {Generator<T, any, any>} generatorInstance
78
+ * @param {(value: T) => void} callback
79
+ * @returns {void}
80
+ * @example
81
+ * import { WalkThrough } from 'vivth';
82
+ *
83
+ * WalkThrough.generator(generatorOfSomething, (value) => {
84
+ * // code
85
+ * })
86
+ */
87
+ static generator(generatorInstance, callback) {
88
+ WalkThrough.#handler(generatorInstance, callback);
89
+ };
90
+ }
@@ -0,0 +1,33 @@
1
+ // @ts-check
2
+
3
+ import { QChannel } from '../class/QChannel.mjs';
4
+ import { LazyFactory } from '../function/LazyFactory.mjs';
5
+ import { Timeout } from '../function/Timeout.mjs';
6
+ import { TryAsync } from '../function/TryAsync.mjs';
7
+
8
+ const qchannel = LazyFactory(() => new QChannel('CreateStringID'));
9
+
10
+ /**
11
+ * @description
12
+ * - function helper to generate absolute unique ID;
13
+ * - the asynchrounous nature is to prevent race condition that might resulting same Id being generated;
14
+ * >- queued using QChannel;
15
+ * @param {string} [prefix]
16
+ * @returns {ReturnType<typeof TryAsync<string>>}
17
+ * @example
18
+ * import { CreateStringID } from 'vivth';
19
+ *
20
+ * (async () => {
21
+ * const [myUniqueID, errorCreatingUniqueID] = await CreateStringID('myPrefix');
22
+ * if(errorCreatingUniqueID) {
23
+ * return;
24
+ * }
25
+ * Console.log(myUniqueID); // `myPrefix${Date.now()}`
26
+ * })()
27
+ */
28
+ export async function CreateStringID(prefix = '') {
29
+ return await qchannel.callback('newStringID', async () => {
30
+ await Timeout(1);
31
+ return `${prefix}${Date.now()}`;
32
+ });
33
+ }
@@ -186,6 +186,7 @@ export class JSautoDOC {
186
186
  * @type {Signal<string>}
187
187
  */
188
188
  #readMESRCContent = LazyFactory(() => new Signal(''));
189
+ // @ts-expect-error
189
190
  #generatedREADME_md = new Effect(async ({ subscribe, isLastCalled }) => {
190
191
  const contentSRC = subscribe(this.#readMESRCContent).value;
191
192
  const filepaths = subscribe(this.#filePaths).value;
@@ -1,4 +1,5 @@
1
1
  // @ts-check
2
+
2
3
  import { EventNameSpace } from '../common/EventNameSpace.mjs';
3
4
 
4
5
  /**
@@ -1,7 +1,5 @@
1
1
  // @ts-check
2
2
 
3
- import { Console } from '../class/Console.mjs';
4
-
5
3
  /**
6
4
  * @description
7
5
  * - regex helper for:
@@ -1,6 +1,5 @@
1
1
  // @ts-check
2
2
 
3
- import { Console } from '../class/Console.mjs';
4
3
  import { TryAsync } from './TryAsync.mjs';
5
4
 
6
5
  /**
@@ -25,13 +24,13 @@ import { TryAsync } from './TryAsync.mjs';
25
24
  * import { Try } from 'vivth';
26
25
  *
27
26
  * const [[key, result], error] = await Try({
28
- * someRuntime: async ( prevError ) => {
27
+ * someRuntime: async ({ prevError }) => {
29
28
  * // asuming on this one doesn't naturally throw error,
30
29
  * // yet you need to continue to next key,
31
30
  * // instead of returning,
32
31
  * // you should throw new Error(something);
33
32
  * },
34
- * browser: async ( prevError ) => {
33
+ * browser: async ({ prevError }) => {
35
34
  * return location?.origin;
36
35
  * // if no error, stop other key function from running;
37
36
  * // key = 'browser'
@@ -40,7 +39,7 @@ import { TryAsync } from './TryAsync.mjs';
40
39
  * // if error;
41
40
  * // run nodeOrBun;
42
41
  * },
43
- * nodeOrBun: async ( prevError ) => {
42
+ * nodeOrBun: async ({ prevError }) => {
44
43
  * return process?.env?.INIT_CWD ?? process?.cwd();
45
44
  * // if no error;
46
45
  * // key = 'nodeOrBun'
package/tsconfig.json CHANGED
@@ -28,7 +28,7 @@
28
28
  "noImplicitOverride": true,
29
29
 
30
30
  // Some stricter flags (disabled by default)
31
- "noUnusedLocals": false,
31
+ "noUnusedLocals": true,
32
32
  "noUnusedParameters": false,
33
33
  "noPropertyAccessFromIndexSignature": false
34
34
  },
package/types/index.d.mts CHANGED
@@ -18,11 +18,13 @@ export { QChannel } from "./src/class/QChannel.mjs";
18
18
  export { SafeExit } from "./src/class/SafeExit.mjs";
19
19
  export { Setup } from "./src/class/Setup.mjs";
20
20
  export { Signal } from "./src/class/Signal.mjs";
21
+ export { WalkThrough } from "./src/class/WalkThrough.mjs";
21
22
  export { WorkerMainThread } from "./src/class/WorkerMainThread.mjs";
22
23
  export { WorkerResult } from "./src/class/WorkerResult.mjs";
23
24
  export { WorkerThread } from "./src/class/WorkerThread.mjs";
24
25
  export { Base64URL } from "./src/common/Base64URL.mjs";
25
26
  export { Base64URLFromFile } from "./src/common/Base64URLFromFile.mjs";
27
+ export { CreateStringID } from "./src/common/CreateStringID.mjs";
26
28
  export { Dev } from "./src/common/Dev.mjs";
27
29
  export { EventNameSpace } from "./src/common/EventNameSpace.mjs";
28
30
  export { Trace } from "./src/common/Trace.mjs";
@@ -1,7 +1,7 @@
1
1
  /**
2
- * @type {Set<Effect>}
2
+ * @type {Map<Effect, Set<Signal<any>>>}
3
3
  */
4
- export const setOfEffects: Set<Effect>;
4
+ export const mapOfEffects: Map<Effect, Set<Signal<any>>>;
5
5
  /**
6
6
  * @description
7
7
  * - a class for creating effect;
@@ -70,9 +70,10 @@ export class Effect {
70
70
  /**
71
71
  * @instance options
72
72
  * @description
73
+ * - subscribe to `Signal_instance`;
73
74
  * - normally it's passed as argument to constructor, however it is also accessible from `options` property;
74
75
  * @template V
75
- * @param {Signal<V>} signal
76
+ * @param {Signal<V>} signalInstance
76
77
  * @returns {Signal<V>}
77
78
  * @example
78
79
  * import { Effect } from 'vivth';
@@ -82,7 +83,7 @@ export class Effect {
82
83
  * })
83
84
  * effect.options.subscribe(signalInstance);
84
85
  */
85
- subscribe: <V>(signal: Signal<V>) => Signal<V>;
86
+ subscribe: <V>(signalInstance: Signal<V>) => Signal<V>;
86
87
  /**
87
88
  * @instance options
88
89
  * @description
@@ -97,6 +98,25 @@ export class Effect {
97
98
  * effect.options.removeEffect();
98
99
  */
99
100
  removeEffect: () => void;
101
+ /**
102
+ * @description
103
+ * - remove inputed signal from this `Effect_instance`;
104
+ * - if effect signal has no other `Signal_instance` to listen to, it will then completely rendered non reactive;
105
+ * - normally it's passed as argument to constructor, however it is also accessible from `options` property;
106
+ * @param {Signal<any>} signalInstance
107
+ * @returns {void}
108
+ * @example
109
+ * import { Effect, Signal } from 'vivth';
110
+ *
111
+ * const count = new Signal(0);
112
+ * const effect = new Effect(async ({ subscribe }) => {
113
+ * console.log(subscribe(count).value); // will subscribe count changes;
114
+ * })
115
+ * count.value++; // will increase the count and trigger effect;
116
+ * effect.options.removeSignal(count);
117
+ * count.value++; // will increase the count but will no longer trigger effect;
118
+ */
119
+ removeSignal: (signalInstance: Signal<any>) => void;
100
120
  } & {
101
121
  "vivth:unwrapLazy;": () => {
102
122
  /**
@@ -126,9 +146,10 @@ export class Effect {
126
146
  /**
127
147
  * @instance options
128
148
  * @description
149
+ * - subscribe to `Signal_instance`;
129
150
  * - normally it's passed as argument to constructor, however it is also accessible from `options` property;
130
151
  * @template V
131
- * @param {Signal<V>} signal
152
+ * @param {Signal<V>} signalInstance
132
153
  * @returns {Signal<V>}
133
154
  * @example
134
155
  * import { Effect } from 'vivth';
@@ -138,7 +159,7 @@ export class Effect {
138
159
  * })
139
160
  * effect.options.subscribe(signalInstance);
140
161
  */
141
- subscribe: <V>(signal: Signal<V>) => Signal<V>;
162
+ subscribe: <V>(signalInstance: Signal<V>) => Signal<V>;
142
163
  /**
143
164
  * @instance options
144
165
  * @description
@@ -153,6 +174,25 @@ export class Effect {
153
174
  * effect.options.removeEffect();
154
175
  */
155
176
  removeEffect: () => void;
177
+ /**
178
+ * @description
179
+ * - remove inputed signal from this `Effect_instance`;
180
+ * - if effect signal has no other `Signal_instance` to listen to, it will then completely rendered non reactive;
181
+ * - normally it's passed as argument to constructor, however it is also accessible from `options` property;
182
+ * @param {Signal<any>} signalInstance
183
+ * @returns {void}
184
+ * @example
185
+ * import { Effect, Signal } from 'vivth';
186
+ *
187
+ * const count = new Signal(0);
188
+ * const effect = new Effect(async ({ subscribe }) => {
189
+ * console.log(subscribe(count).value); // will subscribe count changes;
190
+ * })
191
+ * count.value++; // will increase the count and trigger effect;
192
+ * effect.options.removeSignal(count);
193
+ * count.value++; // will increase the count but will no longer trigger effect;
194
+ */
195
+ removeSignal: (signalInstance: Signal<any>) => void;
156
196
  };
157
197
  };
158
198
  /**
@@ -14,7 +14,7 @@ export class FileSafe {
14
14
  * import { join } from 'node:path';
15
15
  * import { FileSafe, Paths } from 'vivth';
16
16
  *
17
- * const [, error] = await FileSafe.write(
17
+ * const [, error] = await FileSafe.exist(
18
18
  * join(Paths.root, '/some/path.mjs'),
19
19
  * );
20
20
  * if (!error) {
@@ -90,11 +90,6 @@ export class LitExp<KEYS extends import("../types/LitExpKeyType.mjs").LitExpKeyT
90
90
  * @param {...(keyof KEYS)} values
91
91
  */
92
92
  private constructor();
93
- /**
94
- * @typedef {ReturnType<LitExp<KEYS>["evaluate"]["execGroups"]>} ExecGroups
95
- * @typedef {ExecGroups extends [infer First, ...any] ? First : undefined} FirstGroup
96
- * @typedef {FirstGroup extends { result: any } ? Partial<FirstGroup["result"]> : undefined} Overrides
97
- */
98
93
  /**
99
94
  * @description
100
95
  * - instance methods for generating things;
@@ -56,13 +56,13 @@ export class QChannel<DEFINEDANY extends import("../types/AnyButUndefined.mjs").
56
56
  * - blocks execution for subsequent calls until the current one finishes.
57
57
  * @template RESULT
58
58
  * @param {()=>Promise<RESULT>} asyncCallback
59
- * @returns {Promise<[RESULT|undefined, Error|undefined]>}
59
+ * @returns {ReturnType<typeof TryAsync<RESULT>>}
60
60
  * @example
61
61
  * const [result, error] = await QChannel.fifo.callback(async () = > {
62
62
  * // code
63
63
  * })
64
64
  */
65
- callback: <RESULT>(asyncCallback: () => Promise<RESULT>) => Promise<[RESULT | undefined, Error | undefined]>;
65
+ callback: <RESULT>(asyncCallback: () => Promise<RESULT>) => ReturnType<typeof TryAsync<RESULT>>;
66
66
  } & {
67
67
  "vivth:unwrapLazy;": () => {
68
68
  /**
@@ -82,13 +82,13 @@ export class QChannel<DEFINEDANY extends import("../types/AnyButUndefined.mjs").
82
82
  * - blocks execution for subsequent calls until the current one finishes.
83
83
  * @template RESULT
84
84
  * @param {()=>Promise<RESULT>} asyncCallback
85
- * @returns {Promise<[RESULT|undefined, Error|undefined]>}
85
+ * @returns {ReturnType<typeof TryAsync<RESULT>>}
86
86
  * @example
87
87
  * const [result, error] = await QChannel.fifo.callback(async () = > {
88
88
  * // code
89
89
  * })
90
90
  */
91
- callback: <RESULT>(asyncCallback: () => Promise<RESULT>) => Promise<[RESULT | undefined, Error | undefined]>;
91
+ callback: <RESULT>(asyncCallback: () => Promise<RESULT>) => ReturnType<typeof TryAsync<RESULT>>;
92
92
  };
93
93
  };
94
94
  /**
@@ -9,9 +9,9 @@ export const setOFSignals: Set<Signal<any>>;
9
9
  */
10
10
  export class Signal<VALUE> {
11
11
  /**
12
- * @param {Set<Effect>} setOfSubscribers
12
+ * @param {Signal<any>} signalInstance
13
13
  */
14
- static #notify: (setOfSubscribers: Set<Effect>) => void;
14
+ static #notify: (signalInstance: Signal<any>) => void;
15
15
  /**
16
16
  * @description
17
17
  * - create a `Signal`;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @description
3
+ * - collection of static `methods` to walktrhough things, instead of regular looping;
4
+ * - usefull to iterator that might be modified during iteration;
5
+ * - mostlikely to be less performant, but with better result clarity;
6
+ */
7
+ export class WalkThrough {
8
+ /**
9
+ * @param {Iterator<any, any, any>} iterator
10
+ * @param {(...any:any[])=>void} callback
11
+ * @returns {void}
12
+ */
13
+ static #handler: (iterator: Iterator<any, any, any>, callback: (...any: any[]) => void) => void;
14
+ /**
15
+ * @description
16
+ * - method helper to WalkThrough `Set`;
17
+ * @template VAL
18
+ * @param {Set<VAL>} setInstance
19
+ * @param {(value:VAL)=>void} callback
20
+ * @returns {void}
21
+ * @example
22
+ * import { WalkThrough } from 'vivth';
23
+ *
24
+ * WalkThrough.set(setOfSomething, (value) => {
25
+ * // code
26
+ * })
27
+ */
28
+ static set<VAL>(setInstance: Set<VAL>, callback: (value: VAL) => void): void;
29
+ /**
30
+ * @description
31
+ * - method helper to WalkThrough `Map`;
32
+ * @template KEY, VAL
33
+ * @param {Map<KEY, VAL>} mapInstance
34
+ * @param {(res:[key: KEY, value: VAL]) => void} callback
35
+ * @returns {void}
36
+ * @example
37
+ * import { WalkThrough } from 'vivth';
38
+ *
39
+ * WalkThrough.map(mapOfSomething, ([key, value]) => {
40
+ * // code
41
+ * })
42
+ */
43
+ static map<KEY, VAL>(mapInstance: Map<KEY, VAL>, callback: (res: [key: KEY, value: VAL]) => void): void;
44
+ /**
45
+ * @description
46
+ * - method helper to WalkThrough `Array`;
47
+ * @template VAL
48
+ * @param {VAL[]} arrayInstance
49
+ * @param {(res:[value: VAL, index: number]) => void} callback
50
+ * @returns {void}
51
+ * @example
52
+ * import { WalkThrough } from 'vivth';
53
+ *
54
+ * WalkThrough.array(arrayOfSomething, ([value, index]) => {
55
+ * // code
56
+ * })
57
+ */
58
+ static array<VAL>(arrayInstance: VAL[], callback: (res: [value: VAL, index: number]) => void): void;
59
+ /**
60
+ * @description
61
+ * - method helper to WalkThrough `Generator`;
62
+ * @template T
63
+ * @param {Generator<T, any, any>} generatorInstance
64
+ * @param {(value: T) => void} callback
65
+ * @returns {void}
66
+ * @example
67
+ * import { WalkThrough } from 'vivth';
68
+ *
69
+ * WalkThrough.generator(generatorOfSomething, (value) => {
70
+ * // code
71
+ * })
72
+ */
73
+ static generator<T>(generatorInstance: Generator<T, any, any>, callback: (value: T) => void): void;
74
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @description
3
+ * - function helper to generate absolute unique ID;
4
+ * - the asynchrounous nature is to prevent race condition that might resulting same Id being generated;
5
+ * >- queued using QChannel;
6
+ * @param {string} [prefix]
7
+ * @returns {ReturnType<typeof TryAsync<string>>}
8
+ * @example
9
+ * import { CreateStringID } from 'vivth';
10
+ *
11
+ * (async () => {
12
+ * const [myUniqueID, errorCreatingUniqueID] = await CreateStringID('myPrefix');
13
+ * if(errorCreatingUniqueID) {
14
+ * return;
15
+ * }
16
+ * Console.log(myUniqueID); // `myPrefix${Date.now()}`
17
+ * })()
18
+ */
19
+ export function CreateStringID(prefix?: string): ReturnType<typeof TryAsync<string>>;
20
+ import { TryAsync } from '../function/TryAsync.mjs';
@@ -20,13 +20,13 @@
20
20
  * import { Try } from 'vivth';
21
21
  *
22
22
  * const [[key, result], error] = await Try({
23
- * someRuntime: async ( prevError ) => {
23
+ * someRuntime: async ({ prevError }) => {
24
24
  * // asuming on this one doesn't naturally throw error,
25
25
  * // yet you need to continue to next key,
26
26
  * // instead of returning,
27
27
  * // you should throw new Error(something);
28
28
  * },
29
- * browser: async ( prevError ) => {
29
+ * browser: async ({ prevError }) => {
30
30
  * return location?.origin;
31
31
  * // if no error, stop other key function from running;
32
32
  * // key = 'browser'
@@ -35,7 +35,7 @@
35
35
  * // if error;
36
36
  * // run nodeOrBun;
37
37
  * },
38
- * nodeOrBun: async ( prevError ) => {
38
+ * nodeOrBun: async ({ prevError }) => {
39
39
  * return process?.env?.INIT_CWD ?? process?.cwd();
40
40
  * // if no error;
41
41
  * // key = 'nodeOrBun'
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,7 +0,0 @@
1
- /**
2
- * @type {WorkerThread<{a:number}, number>}
3
- */
4
- export const testWorker: WorkerThread<{
5
- a: number;
6
- }, number>;
7
- import { WorkerThread } from '../index.mjs';
@@ -1 +0,0 @@
1
- export {};
@@ -1,13 +0,0 @@
1
- /**
2
- * @description
3
- * `workerThreadClass` description placeholder;
4
- */
5
- export const workerThreadClass: {
6
- new (handler: (ev: any, isLastOnQ: () => boolean) => any): WorkerThread<any, any>;
7
- #refs: Parameters<(typeof WorkerThread)["setup"]>[0] | undefined;
8
- setup<RECEIVE, POST>(refs: {
9
- parentPort: typeof import("worker_threads")["parentPort"];
10
- }): typeof WorkerThread<RECEIVE, POST>;
11
- #isCloseWorkerEvent: (ev: any) => boolean;
12
- };
13
- import { WorkerThread } from '../index.mjs';
@@ -1,10 +0,0 @@
1
- /**
2
- * Description
3
- * @param {(
4
- * this:{defer:(tobeDefered:()=>Promise<void>)=>void}
5
- * )=>Promise<void>} cb
6
- * @returns {void}
7
- */
8
- export function WithDefer(cb: (this: {
9
- defer: (tobeDefered: () => Promise<void>) => void;
10
- }) => Promise<void>): void;
@@ -1,4 +0,0 @@
1
- /**
2
- * - closing helper for `Dev.IsDevCB`;
3
- */
4
- export type IsDevCBStringType = "IsDevCB";