vivth 0.11.2 → 1.0.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/dist/init.mjs +24 -0
- package/README.md +2157 -69
- package/README.src.md +35 -0
- package/bun.lock +57 -3
- package/dev/index.mjs +24 -25
- package/index.mjs +51 -29
- package/package.json +11 -7
- package/src/bundler/CompileMJS.mjs +110 -0
- package/src/bundler/EsBundler.mjs +79 -0
- package/src/class/Console.mjs +62 -0
- package/src/class/Derived.mjs +36 -25
- package/src/class/Effect.mjs +106 -0
- package/src/class/EnvSignal.mjs +88 -0
- package/src/class/EventSignal.mjs +200 -0
- package/src/class/ListDerived.mjs +39 -0
- package/src/class/ListSignal.mjs +256 -0
- package/src/class/Paths.mjs +70 -0
- package/src/class/QChannel.mjs +184 -0
- package/src/class/SafeExit.mjs +131 -0
- package/src/class/Setup.mjs +73 -0
- package/src/class/Signal.mjs +152 -54
- package/src/class/WorkerMainThread.mjs +328 -0
- package/src/class/WorkerResult.mjs +30 -0
- package/src/class/WorkerThread.mjs +151 -0
- package/src/common/Base64URL.mjs +26 -0
- package/src/common/EventNameSpace.mjs +8 -0
- package/src/common/eventObjects.mjs +5 -0
- package/src/common/lazie.mjs +3 -0
- package/src/doc/JSautoDOC.mjs +386 -0
- package/src/doc/parsedFile.mjs +537 -0
- package/src/function/CreateImmutable.mjs +64 -0
- package/src/function/EventCheck.mjs +27 -0
- package/src/function/EventObject.mjs +21 -0
- package/src/function/IsAsync.mjs +23 -0
- package/src/function/LazyFactory.mjs +71 -0
- package/src/function/Timeout.mjs +23 -0
- package/src/function/Try.mjs +64 -0
- package/src/function/TryAsync.mjs +15 -4
- package/src/function/TrySync.mjs +9 -4
- package/src/function/TsToMjs.mjs +67 -0
- package/src/function/WriteFileSafe.mjs +37 -0
- package/src/types/{AnyButUndefined.type.mjs → AnyButUndefined.mjs} +1 -0
- package/src/types/ExtnameType.mjs +6 -0
- package/src/types/IsListSignal.mjs +6 -0
- package/src/types/ListArg.mjs +6 -0
- package/src/types/MutationType.mjs +8 -0
- package/src/types/QCBFIFOReturn.mjs +6 -0
- package/src/types/QCBReturn.mjs +6 -0
- package/tsconfig.json +3 -3
- package/types/dev/index.d.mts +1 -0
- package/types/index.d.mts +34 -8
- package/types/src/bundler/A.d.mts +1 -0
- package/types/src/bundler/CompileMJS.d.mts +8 -0
- package/types/src/bundler/EsBundler.d.mts +7 -0
- package/types/src/class/Console.d.mts +40 -0
- package/types/src/class/Derived.d.mts +21 -9
- package/types/src/class/Effect.d.mts +77 -0
- package/types/src/class/EnvSignal.d.mts +47 -0
- package/types/src/class/EventSignal.d.mts +145 -0
- package/types/src/class/ListDerived.d.mts +35 -0
- package/types/src/class/ListSignal.d.mts +150 -0
- package/types/src/class/Paths.d.mts +50 -0
- package/types/src/class/QChannel.d.mts +115 -0
- package/types/src/class/SafeExit.d.mts +76 -0
- package/types/src/class/Setup.d.mts +76 -0
- package/types/src/class/Signal.d.mts +105 -26
- package/types/src/class/WorkerMainThread.d.mts +149 -0
- package/types/src/class/WorkerResult.d.mts +25 -0
- package/types/src/class/WorkerThread.d.mts +70 -0
- package/types/src/common/Base64URL.d.mts +1 -0
- package/types/src/common/EventNameSpace.d.mts +6 -0
- package/types/src/common/eventObjects.d.mts +3 -0
- package/types/src/common/lazie.d.mts +1 -0
- package/types/src/doc/JSautoDOC.d.mts +76 -0
- package/types/src/doc/parsedFile.d.mts +154 -0
- package/types/src/function/CreateImmutable.d.mts +3 -0
- package/types/src/function/EventCheck.d.mts +2 -0
- package/types/src/function/EventObject.d.mts +4 -0
- package/types/src/function/IsAsync.d.mts +1 -0
- package/types/src/function/LazyFactory.d.mts +4 -0
- package/types/src/function/Timeout.d.mts +1 -0
- package/types/src/function/Try.d.mts +1 -0
- package/types/src/function/TsToMjs.d.mts +4 -0
- package/types/src/function/WriteFileSafe.d.mts +2 -0
- package/types/src/types/{AnyButUndefined.type.d.mts → AnyButUndefined.d.mts} +3 -0
- package/types/src/types/ExtnameType.d.mts +4 -0
- package/types/src/types/IsListSignal.d.mts +4 -0
- package/types/src/types/ListArg.d.mts +4 -0
- package/types/src/types/MutationType.d.mts +5 -0
- package/types/src/types/QCBFIFOReturn.d.mts +4 -0
- package/types/src/types/QCBReturn.d.mts +7 -0
- package/src/class/$.mjs +0 -68
- package/src/class/PingFIFO.mjs +0 -78
- package/src/class/PingUnique.mjs +0 -84
- package/src/class/Q.mjs +0 -98
- package/src/class/QFIFO.mjs +0 -66
- package/src/class/QUnique.mjs +0 -75
- package/src/common.mjs +0 -16
- package/src/function/NewQBlock.mjs +0 -39
- package/types/src/class/$.d.mts +0 -40
- package/types/src/class/PingFIFO.d.mts +0 -57
- package/types/src/class/PingUnique.d.mts +0 -48
- package/types/src/class/Q.d.mts +0 -63
- package/types/src/class/QFIFO.d.mts +0 -47
- package/types/src/class/QUnique.d.mts +0 -46
- package/types/src/common.d.mts +0 -2
- package/types/src/function/NewQBlock.d.mts +0 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { unwrapLazy } from '../common/lazie.mjs';
|
|
4
|
+
import { LazyFactory } from '../function/LazyFactory.mjs';
|
|
5
|
+
import { TryAsync } from '../function/TryAsync.mjs';
|
|
6
|
+
import { Console } from './Console.mjs';
|
|
7
|
+
import { Signal } from './Signal.mjs';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @type {Set<Effect>}
|
|
11
|
+
*/
|
|
12
|
+
export const setOfEffects = new Set();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @description
|
|
16
|
+
* - a class for creating effect;
|
|
17
|
+
* - compared to previous class <b>$</b> reactivity model, `Effect`:
|
|
18
|
+
* >- doesn't autosubscribe at first run;
|
|
19
|
+
* >- it is using passed <b>$</b> named `arg0` options as subscriber;
|
|
20
|
+
* >- doesn't block other queues during first run(previously blocks other queues to safely register signal autoscubscriber);
|
|
21
|
+
* >- now can dynamically subscribes to signal, even on conditionals, that are not run during first run;
|
|
22
|
+
*/
|
|
23
|
+
export class Effect {
|
|
24
|
+
/**
|
|
25
|
+
* @description
|
|
26
|
+
* @param {(arg0:Effect["options"])=>Promise<void>} effect
|
|
27
|
+
* @example
|
|
28
|
+
* import { Signal, Derived, Effect, Console } from 'vivth';
|
|
29
|
+
*
|
|
30
|
+
* const count = new Signal(0);
|
|
31
|
+
* const double = new Derived( async({$}) => $(count).value \* 2); // double listen to count changes
|
|
32
|
+
* new Effect(async ({
|
|
33
|
+
* subscribe, // : registrar callback for this effect instance, immediately return the signal instance
|
|
34
|
+
* removeEffect, // : disable this effect instance from reacting to dependency changes;
|
|
35
|
+
* }) => {
|
|
36
|
+
* Console.log(subscribe(double).value); // effect listen to double changes
|
|
37
|
+
* const a = double.value; // no need to wrap double twice with $
|
|
38
|
+
* })
|
|
39
|
+
*
|
|
40
|
+
* count.value++;
|
|
41
|
+
*/
|
|
42
|
+
constructor(effect) {
|
|
43
|
+
this.#effect = effect;
|
|
44
|
+
setOfEffects.add(this);
|
|
45
|
+
this.run();
|
|
46
|
+
}
|
|
47
|
+
options = LazyFactory(() => ({
|
|
48
|
+
/**
|
|
49
|
+
* @instance options
|
|
50
|
+
* @description
|
|
51
|
+
* - normally it's passed as argument to constructor, however it is also accessible from `options` property;
|
|
52
|
+
* @template {Signal} S
|
|
53
|
+
* @param {S} signal
|
|
54
|
+
* @returns {S}
|
|
55
|
+
* @example
|
|
56
|
+
* const effect = new Effect(async () => {
|
|
57
|
+
* // code
|
|
58
|
+
* })
|
|
59
|
+
* effect.options.subscribe(signalInstance);
|
|
60
|
+
*/
|
|
61
|
+
subscribe: (signal) => {
|
|
62
|
+
if (!(signal instanceof Signal)) {
|
|
63
|
+
signal = signal[unwrapLazy];
|
|
64
|
+
}
|
|
65
|
+
signal.subscribers.setOf.add(this);
|
|
66
|
+
return signal;
|
|
67
|
+
},
|
|
68
|
+
/**
|
|
69
|
+
* @instance options
|
|
70
|
+
* @description
|
|
71
|
+
* - normally it's passed as argument to constructor, however it is also accessible from `options` property;
|
|
72
|
+
* @type {()=>void}
|
|
73
|
+
* @example
|
|
74
|
+
* const effect = new Effect(async () => {
|
|
75
|
+
* // code
|
|
76
|
+
* })
|
|
77
|
+
* effect.options.removeEffect();
|
|
78
|
+
*/
|
|
79
|
+
removeEffect: () => {
|
|
80
|
+
setOfEffects.delete(this);
|
|
81
|
+
},
|
|
82
|
+
}));
|
|
83
|
+
/**
|
|
84
|
+
* @param {Effect["options"]} effectInstance
|
|
85
|
+
* @returns {Promise<void>}
|
|
86
|
+
*/
|
|
87
|
+
#effect;
|
|
88
|
+
/**
|
|
89
|
+
* @description
|
|
90
|
+
* - normally is to let to be automatically run when dependency signals changes, however it's also accessible as instance method;
|
|
91
|
+
* @returns {void}
|
|
92
|
+
* @example
|
|
93
|
+
* const effect = new Effect(async ()=>{
|
|
94
|
+
* // code
|
|
95
|
+
* })
|
|
96
|
+
* effect.run();
|
|
97
|
+
*/
|
|
98
|
+
run = () => {
|
|
99
|
+
TryAsync(async () => await this.#effect(this.options)).then(([_, error]) => {
|
|
100
|
+
if (!error) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
Console.error(error);
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { LazyFactory } from '../function/LazyFactory.mjs';
|
|
4
|
+
import { Console } from './Console.mjs';
|
|
5
|
+
import { Derived } from './Derived.mjs';
|
|
6
|
+
import { Signal } from './Signal.mjs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description
|
|
10
|
+
* - non browser API;
|
|
11
|
+
* - uses [Signal](#signal) and [Derived](#derived) under the hood;
|
|
12
|
+
* @template V
|
|
13
|
+
*/
|
|
14
|
+
export class EnvSignal {
|
|
15
|
+
/**
|
|
16
|
+
* @description
|
|
17
|
+
* - create `EnvSignal` instance;
|
|
18
|
+
* @param {V} initialValue
|
|
19
|
+
*/
|
|
20
|
+
constructor(initialValue) {
|
|
21
|
+
this.#proxyConst = LazyFactory(() => new Signal(initialValue));
|
|
22
|
+
let isRun = false;
|
|
23
|
+
this.env = LazyFactory(
|
|
24
|
+
() =>
|
|
25
|
+
new Derived(async ({ subscribe }) => {
|
|
26
|
+
const derived = subscribe(this.#proxyConst).value;
|
|
27
|
+
if (!isRun) {
|
|
28
|
+
isRun = true;
|
|
29
|
+
return initialValue;
|
|
30
|
+
}
|
|
31
|
+
return derived;
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
#isModified = false;
|
|
36
|
+
/**
|
|
37
|
+
* @type {Signal<V>}
|
|
38
|
+
*/
|
|
39
|
+
#proxyConst;
|
|
40
|
+
/**
|
|
41
|
+
* @description
|
|
42
|
+
* - exposed property to listen to;
|
|
43
|
+
* @type {Derived<V>}
|
|
44
|
+
* @example
|
|
45
|
+
* import { EnvSignal, Effect } from 'vivth';
|
|
46
|
+
*
|
|
47
|
+
* export const myEnv = new EnvSignal(true);
|
|
48
|
+
* new Effect(async ({ subscribe }) => {
|
|
49
|
+
* const myEnvValue = subscribe(myEnv.env).value;
|
|
50
|
+
* // code
|
|
51
|
+
* })
|
|
52
|
+
*/
|
|
53
|
+
env;
|
|
54
|
+
/**
|
|
55
|
+
* @description
|
|
56
|
+
* - call to correct the value of previously declared value;
|
|
57
|
+
* - can only be called once;
|
|
58
|
+
* @param {V} correctedValue
|
|
59
|
+
* @returns {void}
|
|
60
|
+
* @example
|
|
61
|
+
* import { EnvSignal } from 'vivth';
|
|
62
|
+
*
|
|
63
|
+
* export const myEnv = new EnvSignal(true);
|
|
64
|
+
*
|
|
65
|
+
* // somewhere else on the program
|
|
66
|
+
* import { myEnv } from '$src/myEnv'
|
|
67
|
+
*
|
|
68
|
+
* myEnv.correction(false); // this will notify all subscribers;
|
|
69
|
+
*/
|
|
70
|
+
correction = (correctedValue) => {
|
|
71
|
+
if (this.#proxyConst.value === null) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
Console;
|
|
75
|
+
if (this.#isModified) {
|
|
76
|
+
Console.warn({
|
|
77
|
+
correctedValue,
|
|
78
|
+
value: this.#proxyConst.value,
|
|
79
|
+
instance: this,
|
|
80
|
+
message: '"correct" of this instance can only be called once',
|
|
81
|
+
});
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.#isModified = true;
|
|
85
|
+
this.#proxyConst.value = correctedValue;
|
|
86
|
+
this.#proxyConst.remove.ref();
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { LazyFactory } from '../function/LazyFactory.mjs';
|
|
4
|
+
import { Derived } from './Derived.mjs';
|
|
5
|
+
import { ListDerived } from './ListDerived.mjs';
|
|
6
|
+
import { ListSignal } from './ListSignal.mjs';
|
|
7
|
+
import { QChannel } from './QChannel.mjs';
|
|
8
|
+
import { Signal } from './Signal.mjs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @description
|
|
12
|
+
* - Signal implementation for `CustomEvent`, to dispatch and listen;
|
|
13
|
+
* @template {IsListSignal} isList
|
|
14
|
+
* - boolean;
|
|
15
|
+
*/
|
|
16
|
+
export class EventSignal {
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {import('../types/IsListSignal.mjs').IsListSignal} IsListSignal
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* @description
|
|
22
|
+
* - `Map` of `EventSignal`, using the `stringName` of the `EventSignal_instance` as `key`;
|
|
23
|
+
* @type {Map<string, EventSignal>}
|
|
24
|
+
*/
|
|
25
|
+
static map = new Map();
|
|
26
|
+
/**
|
|
27
|
+
* @type {QChannel<string>}
|
|
28
|
+
*/
|
|
29
|
+
static #qChannelEventSignal = new QChannel();
|
|
30
|
+
/**
|
|
31
|
+
* @description
|
|
32
|
+
* - the constructor it self is set to `private`;
|
|
33
|
+
* - it's globally queued:
|
|
34
|
+
* >- the `Promise` nature is to prevent race condition on creating the instance;
|
|
35
|
+
* @param {string} stringName
|
|
36
|
+
* @param {IsListSignal} [isList_]
|
|
37
|
+
* @returns {Promise<EventSignal>}
|
|
38
|
+
* @example
|
|
39
|
+
* import { EventSignal } from 'vivth';
|
|
40
|
+
*
|
|
41
|
+
* const myEventSignal = await EventSignal.get('dataEvent');
|
|
42
|
+
*/
|
|
43
|
+
static async get(stringName, isList_ = false) {
|
|
44
|
+
const { resume } = await EventSignal.#qChannelEventSignal.key(stringName);
|
|
45
|
+
const mapped = EventSignal.map;
|
|
46
|
+
if (!mapped.has(stringName)) {
|
|
47
|
+
let instance = new EventSignal(stringName, isList_);
|
|
48
|
+
mapped.set(stringName, instance);
|
|
49
|
+
}
|
|
50
|
+
resume();
|
|
51
|
+
return mapped.get(stringName);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* @private
|
|
55
|
+
* @param {string} name
|
|
56
|
+
* @param {isList} [isList]
|
|
57
|
+
*/
|
|
58
|
+
// @ts-expect-error
|
|
59
|
+
constructor(name, isList = false) {
|
|
60
|
+
this.name = name;
|
|
61
|
+
this.#isList = isList;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* @type {IsListSignal}
|
|
65
|
+
*/
|
|
66
|
+
#isList;
|
|
67
|
+
/**
|
|
68
|
+
* @type {string}
|
|
69
|
+
*/
|
|
70
|
+
name;
|
|
71
|
+
/**
|
|
72
|
+
* @description
|
|
73
|
+
* - is [Signal](#signal) or [ListSignal](#listsignal) instance, depending on the `isList` argument;
|
|
74
|
+
* - if needed to pass along the messages, it can be used as `dispatcher` and `listener` at the same time;
|
|
75
|
+
* - is `lazily` created;
|
|
76
|
+
* @type {Signal|ListSignal}
|
|
77
|
+
*/
|
|
78
|
+
dispatch = LazyFactory(() => {
|
|
79
|
+
if (this.#isList) {
|
|
80
|
+
return new ListSignal([]);
|
|
81
|
+
}
|
|
82
|
+
return new Signal(undefined);
|
|
83
|
+
});
|
|
84
|
+
/**
|
|
85
|
+
* @description
|
|
86
|
+
* - is [Derived](#derived) or [ListDerived](#listderived) instance, depending on the `isList` argument;
|
|
87
|
+
* - can be used as listener when passed down value shouldn't be modified manually;
|
|
88
|
+
* - is `lazily` created along with `dispatch`, if `listen` is accessed first, then `dispatch` will also be created automatically;
|
|
89
|
+
* @type {Derived|ListDerived}
|
|
90
|
+
*/
|
|
91
|
+
listen = LazyFactory(() => {
|
|
92
|
+
const dispatch = this.dispatch;
|
|
93
|
+
const _ = dispatch.value;
|
|
94
|
+
if (this.#isList) {
|
|
95
|
+
return new ListDerived(async ({ subscribe }) => {
|
|
96
|
+
return subscribe(dispatch).value;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return new Derived(async ({ subscribe }) => {
|
|
100
|
+
return subscribe(dispatch).value;
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
/**
|
|
104
|
+
* @description
|
|
105
|
+
* - methods of this static property is lazily created;
|
|
106
|
+
* - remove signal and effect subscription of the named `EventSignal_instance`;
|
|
107
|
+
*/
|
|
108
|
+
static remove = LazyFactory(() => ({
|
|
109
|
+
/**
|
|
110
|
+
* @static remove
|
|
111
|
+
* @description
|
|
112
|
+
* - remove subscriber from the named `EventSignal_instance`;
|
|
113
|
+
* @param {string} name
|
|
114
|
+
* @param {import('./Effect.mjs').Effect} effect
|
|
115
|
+
* @returns {void}
|
|
116
|
+
* @example
|
|
117
|
+
* import { EventSignal } from 'vivth';
|
|
118
|
+
*
|
|
119
|
+
* EventSignal.remove.subscriber('yourEventSignalName', yourEffectInstance);
|
|
120
|
+
*/
|
|
121
|
+
subscriber: (name, effect) => {
|
|
122
|
+
effect.options.removeEffect();
|
|
123
|
+
EventSignal.get(name).then(({ remove }) => {
|
|
124
|
+
remove.subscriber(effect);
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* @static remove
|
|
129
|
+
* @description
|
|
130
|
+
* - remove all subscribers from the named `EventSignal_instance`;
|
|
131
|
+
* @param {string} name
|
|
132
|
+
* @returns {void}
|
|
133
|
+
* @example
|
|
134
|
+
* import { EventSignal } from 'vivth';
|
|
135
|
+
*
|
|
136
|
+
* EventSignal.remove.allSubscribers('yourEventSignalName');
|
|
137
|
+
*/
|
|
138
|
+
allSubscribers: (name) => {
|
|
139
|
+
EventSignal.get(name).then(({ remove }) => {
|
|
140
|
+
remove.allSubscribers();
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
/**
|
|
144
|
+
* @static remove
|
|
145
|
+
* @description
|
|
146
|
+
* - remove reference of the `proxySignals` of the named `EventSignal_instance`;
|
|
147
|
+
* @param {string} name
|
|
148
|
+
* @returns {void}
|
|
149
|
+
* @example
|
|
150
|
+
* import { EventSignal } from 'vivth';
|
|
151
|
+
*
|
|
152
|
+
* EventSignal.remove.refs('yourEventSignalName');
|
|
153
|
+
*/
|
|
154
|
+
refs: (name) => {
|
|
155
|
+
EventSignal.get(name).then(({ remove }) => {
|
|
156
|
+
remove.ref();
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
}));
|
|
160
|
+
remove = LazyFactory(() => ({
|
|
161
|
+
/**
|
|
162
|
+
* @instance remove
|
|
163
|
+
* @description
|
|
164
|
+
* - remove subscriber from the `EventSignal_instance`;
|
|
165
|
+
* @param {import('./Effect.mjs').Effect} effect
|
|
166
|
+
* @returns {void}
|
|
167
|
+
* @example
|
|
168
|
+
* eventSignal_instance.remove.subscriber(yourEffectInstance);
|
|
169
|
+
*/
|
|
170
|
+
subscriber: (effect) => {
|
|
171
|
+
effect.options.removeEffect();
|
|
172
|
+
this.dispatch.remove.subscriber(effect);
|
|
173
|
+
this.listen.remove.subscriber(effect);
|
|
174
|
+
},
|
|
175
|
+
/**
|
|
176
|
+
* @instance remove
|
|
177
|
+
* @description
|
|
178
|
+
* - remove allSubscribers from the `EventSignal_instance`;
|
|
179
|
+
* @type {()=>void}
|
|
180
|
+
* @example
|
|
181
|
+
* eventSignal_instance.remove.allSubscribers();
|
|
182
|
+
*/
|
|
183
|
+
allSubscribers: () => {
|
|
184
|
+
this.dispatch.remove.allSubscribers();
|
|
185
|
+
this.listen.remove.allSubscribers();
|
|
186
|
+
},
|
|
187
|
+
/**
|
|
188
|
+
* @instance remove
|
|
189
|
+
* @description
|
|
190
|
+
* - remove reference of the `proxySignals` of the `EventSignal_instance`;
|
|
191
|
+
* @type {()=>void}
|
|
192
|
+
* @example
|
|
193
|
+
* eventSignal_instance.remove.ref();
|
|
194
|
+
*/
|
|
195
|
+
ref: () => {
|
|
196
|
+
this.dispatch.remove.ref();
|
|
197
|
+
this.listen.remove.ref();
|
|
198
|
+
},
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { Derived } from './Derived.mjs';
|
|
4
|
+
import { Effect } from './Effect.mjs';
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* - class to create `dervivedList` that satisfy `Array<Record<string, string>>`;
|
|
8
|
+
* - usefull for `derivedLoops`, e.g. temporary search values;
|
|
9
|
+
* - is a `Derived` instance;
|
|
10
|
+
* @template {ListArg} LA
|
|
11
|
+
* @extends {Derived<LA[]>}
|
|
12
|
+
*/
|
|
13
|
+
export class ListDerived extends Derived {
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {import('../types/ListArg.mjs').ListArg} ListArg
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* @description
|
|
19
|
+
* @param {(effectInstanceOptions:Effect["options"])=>Promise<LA[]>} derivedFunction
|
|
20
|
+
* @example
|
|
21
|
+
* import { ListSignal, ListDerived } from 'vivth';
|
|
22
|
+
*
|
|
23
|
+
* const listExample = new ListSignal([
|
|
24
|
+
* {key1: "test1"},
|
|
25
|
+
* {key1: "test2"},
|
|
26
|
+
* ]);
|
|
27
|
+
*
|
|
28
|
+
* export const listDerivedExample = new ListDerived(async({ subscribe }) => {
|
|
29
|
+
* // becarefull to not mutate the reference value
|
|
30
|
+
* return subscribe(listExample).value.filter((val) => {
|
|
31
|
+
* // subscribe(listExample).structuredClone can be used as alternative
|
|
32
|
+
* // filter logic
|
|
33
|
+
* })
|
|
34
|
+
* });
|
|
35
|
+
*/
|
|
36
|
+
constructor(derivedFunction) {
|
|
37
|
+
super(derivedFunction);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { LazyFactory } from '../function/LazyFactory.mjs';
|
|
4
|
+
import { Console } from './Console.mjs';
|
|
5
|
+
import { Signal } from './Signal.mjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('../types/ListArg.mjs').ListArg} ListArg
|
|
9
|
+
* @typedef {import('../types/MutationType.mjs').MutationType} MutationType
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* @description
|
|
13
|
+
* - class to create list that satisfy `Array<Record<string, string>>`.
|
|
14
|
+
* @template {import('../types/ListArg.mjs').ListArg} LA
|
|
15
|
+
* @extends {Signal<LA[]>}
|
|
16
|
+
*/
|
|
17
|
+
export class ListSignal extends Signal {
|
|
18
|
+
/**
|
|
19
|
+
* @description
|
|
20
|
+
* - Checks if the input is an array whose first item (if present) is a plain object
|
|
21
|
+
* - with string keys and string values. Allows empty arrays.
|
|
22
|
+
* @param {unknown} value - The value to validate.
|
|
23
|
+
* @returns {value is Array<Record<string, string>>} True if the first item is a valid string record or array is empty.
|
|
24
|
+
*/
|
|
25
|
+
static isValid = (value) => {
|
|
26
|
+
if (!Array.isArray(value)) return false;
|
|
27
|
+
const first = value[0];
|
|
28
|
+
if (first === undefined) {
|
|
29
|
+
// allow empty array
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return (
|
|
33
|
+
first &&
|
|
34
|
+
typeof first === 'object' &&
|
|
35
|
+
!Array.isArray(first) &&
|
|
36
|
+
Object.entries(first).every(
|
|
37
|
+
([key, val]) => typeof key === 'string' && typeof val === 'string'
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* @description
|
|
43
|
+
* - usefull for `loops`;
|
|
44
|
+
* @param {LA[]} [value]
|
|
45
|
+
* @example
|
|
46
|
+
* import { ListSignal } from 'vivth';
|
|
47
|
+
*
|
|
48
|
+
* const listExample = new ListSignal([
|
|
49
|
+
* {key1: "test1",},
|
|
50
|
+
* {key1: "test2",},
|
|
51
|
+
* ]);
|
|
52
|
+
*/
|
|
53
|
+
constructor(value = []) {
|
|
54
|
+
super(value);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* @description
|
|
58
|
+
* - reference to original inputed `value`;
|
|
59
|
+
* @type {LA[]}
|
|
60
|
+
*/
|
|
61
|
+
get value() {
|
|
62
|
+
return super.value;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* @description
|
|
66
|
+
* - you cannot mannually set`value` `ListSignal_instance`;
|
|
67
|
+
* @private
|
|
68
|
+
* @type {LA[]}
|
|
69
|
+
*/
|
|
70
|
+
set value(_) {
|
|
71
|
+
Console.error('`List.value` `setter` are not available outside the class or instance');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* @description
|
|
75
|
+
* - methods collection that mimics `Array` API;
|
|
76
|
+
* - calling this methods will notify subscribers for changes, except for some;
|
|
77
|
+
*/
|
|
78
|
+
arrayMethods = LazyFactory(() => {
|
|
79
|
+
return {
|
|
80
|
+
/**
|
|
81
|
+
* @instance arrayMethods
|
|
82
|
+
* @description
|
|
83
|
+
* - reference to structuredClone elements of `value`;
|
|
84
|
+
* - calling doesn't notify
|
|
85
|
+
* @type {Array<LA>}
|
|
86
|
+
*/
|
|
87
|
+
get structuredClone() {
|
|
88
|
+
return structuredClone(super.value);
|
|
89
|
+
},
|
|
90
|
+
/**
|
|
91
|
+
* @instance arrayMethods
|
|
92
|
+
* @description
|
|
93
|
+
* - appends new elements to the end;
|
|
94
|
+
* @param {...LA} listArg
|
|
95
|
+
* @returns {void}
|
|
96
|
+
*/
|
|
97
|
+
push: (...listArg) => {
|
|
98
|
+
super.value.push(...listArg);
|
|
99
|
+
this.subscribers.notify();
|
|
100
|
+
},
|
|
101
|
+
/**
|
|
102
|
+
* @instance arrayMethods
|
|
103
|
+
* @description
|
|
104
|
+
* - removes the first element;
|
|
105
|
+
* @type {()=>void}
|
|
106
|
+
*/
|
|
107
|
+
shift: () => {
|
|
108
|
+
super.value.shift();
|
|
109
|
+
this.subscribers.notify();
|
|
110
|
+
},
|
|
111
|
+
/**
|
|
112
|
+
* @instance arrayMethods
|
|
113
|
+
* @description
|
|
114
|
+
* - inserts new element at the start;
|
|
115
|
+
* @param {...LA} listArg
|
|
116
|
+
* @returns {void}
|
|
117
|
+
*/
|
|
118
|
+
unshift: (...listArg) => {
|
|
119
|
+
super.value.unshift(...listArg);
|
|
120
|
+
this.subscribers.notify();
|
|
121
|
+
},
|
|
122
|
+
/**
|
|
123
|
+
* @instance arrayMethods
|
|
124
|
+
* @description
|
|
125
|
+
* - for both start and end, a negative index can be used to indicate an offset from the end of the data. For example, -2 refers to the second to last element of the data;
|
|
126
|
+
* @param {number} [start]
|
|
127
|
+
* - the beginning index of the specified portion of the data. If start is undefined, then the slice begins at index 0.
|
|
128
|
+
* @param {number} [end]
|
|
129
|
+
* - the end index of the specified portion of the data. This is exclusive of the element at the index 'end'. If end is undefined, then the slice extends to the end of the data.
|
|
130
|
+
* @returns {void}
|
|
131
|
+
*/
|
|
132
|
+
slice: (start = 0, end = 0) => {
|
|
133
|
+
const deleteCount = end - start + 1;
|
|
134
|
+
this.arrayMethods.splice(start, deleteCount);
|
|
135
|
+
},
|
|
136
|
+
/**
|
|
137
|
+
* @instance arrayMethods
|
|
138
|
+
* @description
|
|
139
|
+
* - replace whole `List` data with new array.
|
|
140
|
+
* @param {LA[]} listArgs
|
|
141
|
+
* - new array in place of the deleted array.
|
|
142
|
+
* @returns {void}
|
|
143
|
+
*/
|
|
144
|
+
replace: (listArgs) => {
|
|
145
|
+
this.arrayMethods.splice(0, super.value.length, ...listArgs);
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* @instance arrayMethods
|
|
149
|
+
* @description
|
|
150
|
+
* - removes elements from an data and, if necessary, inserts new elements in their place;
|
|
151
|
+
* @param {number} start
|
|
152
|
+
* - The zero-based location in the data from which to start removing elements.
|
|
153
|
+
* @param {number} deleteCount
|
|
154
|
+
* -The number of elements to remove.
|
|
155
|
+
* @param {...LA} listArg
|
|
156
|
+
* - new data in place of the deleted data.
|
|
157
|
+
* @returns {void}
|
|
158
|
+
*/
|
|
159
|
+
splice: (start, deleteCount, ...listArg) => {
|
|
160
|
+
const end = start + deleteCount - 1;
|
|
161
|
+
if (!this.#checkLength('splice', end)) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
super.value.splice(start, deleteCount, ...listArg);
|
|
165
|
+
this.subscribers.notify();
|
|
166
|
+
},
|
|
167
|
+
/**
|
|
168
|
+
* @instance arrayMethods
|
|
169
|
+
* @description
|
|
170
|
+
* - swap `List` data between two indexes;
|
|
171
|
+
* @param {number} indexA
|
|
172
|
+
* @param {number} indexB
|
|
173
|
+
* @returns {void}
|
|
174
|
+
*/
|
|
175
|
+
swap: (indexA, indexB) => {
|
|
176
|
+
if (!this.#checkLength('swap', indexA) || !this.#checkLength('swap', indexB)) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
[super.value[indexA], super.value[indexB]] = [super.value[indexB], super.value[indexA]];
|
|
180
|
+
this.subscribers.notify();
|
|
181
|
+
},
|
|
182
|
+
/**
|
|
183
|
+
* @instance arrayMethods
|
|
184
|
+
* @description
|
|
185
|
+
* - modify `List` element at specific index;
|
|
186
|
+
* @param {number} index
|
|
187
|
+
* @param {Partial<LA>} listArg
|
|
188
|
+
* @returns {void}
|
|
189
|
+
*/
|
|
190
|
+
modify: (index, listArg) => {
|
|
191
|
+
if (!this.#checkLength('modify', index)) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
for (const key in listArg) {
|
|
195
|
+
const listArgKey = listArg[key];
|
|
196
|
+
if (!listArgKey) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
super.value[index][key] = listArgKey;
|
|
200
|
+
}
|
|
201
|
+
this.subscribers.notify();
|
|
202
|
+
},
|
|
203
|
+
/**
|
|
204
|
+
* @instance arrayMethods
|
|
205
|
+
* @description
|
|
206
|
+
* - remove `List` element at specific index;
|
|
207
|
+
* @param {number} index
|
|
208
|
+
* @returns {void}
|
|
209
|
+
*/
|
|
210
|
+
remove: (index) => {
|
|
211
|
+
if (!this.#checkLength('remove', index)) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
this.arrayMethods.splice(index, 1);
|
|
215
|
+
},
|
|
216
|
+
/**
|
|
217
|
+
* @instance arrayMethods
|
|
218
|
+
* @description
|
|
219
|
+
* - reverses the elements in an `List` in place.
|
|
220
|
+
* @returns {void}
|
|
221
|
+
*/
|
|
222
|
+
reverse: () => {
|
|
223
|
+
super.value.reverse();
|
|
224
|
+
this.subscribers.notify();
|
|
225
|
+
},
|
|
226
|
+
/**
|
|
227
|
+
* @instance arrayMethods
|
|
228
|
+
* @description
|
|
229
|
+
* - removes the last element;
|
|
230
|
+
* @returns {void}
|
|
231
|
+
*/
|
|
232
|
+
pop: () => {
|
|
233
|
+
super.value.pop();
|
|
234
|
+
this.subscribers.notify();
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
/**
|
|
239
|
+
* @param {MutationType} mode
|
|
240
|
+
* @param {number} end
|
|
241
|
+
* @returns {boolean}
|
|
242
|
+
*/
|
|
243
|
+
#checkLength = (mode, end) => {
|
|
244
|
+
const dataLength = super.value.length;
|
|
245
|
+
if (end >= dataLength) {
|
|
246
|
+
Console.error({
|
|
247
|
+
mode,
|
|
248
|
+
end,
|
|
249
|
+
dataLength,
|
|
250
|
+
message: 'list modifier, end is out of dataLength',
|
|
251
|
+
});
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
};
|
|
256
|
+
}
|