@adaas/a-utils 0.1.30 → 0.1.32
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/dist/index.cjs +11 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +88 -32
- package/dist/index.d.ts +88 -32
- package/dist/index.mjs +11 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/A-Memory/A-Memory.component.ts +1 -1
- package/src/lib/A-Signal/A-Signal.types.ts +12 -3
- package/src/lib/A-Signal/components/A-SignalBus.component.ts +15 -6
- package/src/lib/A-Signal/context/A-SignalConfig.context.ts +7 -5
- package/src/lib/A-Signal/context/A-SignalState.context.ts +17 -19
- package/src/lib/A-Signal/entities/A-Signal.entity.ts +31 -4
- package/src/lib/A-Signal/entities/A-SignalVector.entity.ts +141 -26
- package/tests/A-Signal.test.ts +73 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaas/a-utils",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.32",
|
|
4
4
|
"description": "A-Utils is a set of utilities that are used across the ADAAS ecosystem. This package is designed to be a collection of utilities that are used across the ADAAS ecosystem.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -64,10 +64,10 @@ export class A_Memory<
|
|
|
64
64
|
context.clear();
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
@A_Feature.Extend()
|
|
68
67
|
/**
|
|
69
68
|
* Handles the 'get' operation for retrieving a value from memory
|
|
70
69
|
*/
|
|
70
|
+
@A_Feature.Extend()
|
|
71
71
|
async [A_MemoryFeatures.onGet](
|
|
72
72
|
@A_Dependency.Required()
|
|
73
73
|
@A_Inject(A_OperationContext) operation: A_MemoryOperationContext,
|
|
@@ -21,10 +21,12 @@ export type A_SignalConfig_Init = {
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
export type A_SignalVector_Init<
|
|
24
|
-
|
|
24
|
+
_TSignals extends Array<A_Signal> = Array<A_Signal>,
|
|
25
|
+
_TVectorStructure extends Array<A_TYPES__Entity_Constructor<_TSignals[number]>> = Array<A_TYPES__Entity_Constructor<_TSignals[number]>>
|
|
26
|
+
|
|
25
27
|
> = {
|
|
26
|
-
structure:
|
|
27
|
-
values:
|
|
28
|
+
structure: _TVectorStructure,
|
|
29
|
+
values: _TSignals
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
|
|
@@ -45,3 +47,10 @@ export type A_Signal_Init<T extends Record<string, any> = Record<string, any>> =
|
|
|
45
47
|
*/
|
|
46
48
|
data: T
|
|
47
49
|
}
|
|
50
|
+
|
|
51
|
+
export type A_Signal_Serialized<T extends Record<string, any> = Record<string, any>> = {
|
|
52
|
+
/**
|
|
53
|
+
* The signal data
|
|
54
|
+
*/
|
|
55
|
+
data: T
|
|
56
|
+
} & A_TYPES__Entity_Serialized
|
|
@@ -32,12 +32,13 @@ export class A_SignalBus extends A_Component {
|
|
|
32
32
|
* @param state
|
|
33
33
|
* @param config
|
|
34
34
|
* @returns
|
|
35
|
-
*/
|
|
35
|
+
*/
|
|
36
36
|
@A_Feature.Extend({
|
|
37
37
|
scope: [A_Signal]
|
|
38
38
|
})
|
|
39
39
|
async [A_SignalFeatures.Emit](
|
|
40
40
|
@A_Inject(A_Caller) signal: A_Signal,
|
|
41
|
+
@A_Inject(A_Scope) scope: A_Scope,
|
|
41
42
|
|
|
42
43
|
@A_Inject(A_Config) globalConfig?: A_Config<['A_SIGNAL_VECTOR_STRUCTURE']>,
|
|
43
44
|
@A_Inject(A_Logger) logger?: A_Logger,
|
|
@@ -45,10 +46,18 @@ export class A_SignalBus extends A_Component {
|
|
|
45
46
|
@A_Inject(A_SignalConfig) config?: A_SignalConfig,
|
|
46
47
|
) {
|
|
47
48
|
|
|
49
|
+
/*
|
|
50
|
+
1) create a signal when it occurs via new A_Signal('somedata')
|
|
51
|
+
2) emit a signal when needed via signal.emit(scope)
|
|
52
|
+
3) the bus should listen for all emitted signals within the scope
|
|
53
|
+
4) when a signal is emitted, the bus should store a signal in some place (probably it's memory)
|
|
54
|
+
*/
|
|
55
|
+
|
|
48
56
|
/**
|
|
49
57
|
* We need a context where component is registered, to prevent any duplicate registrations
|
|
50
58
|
*/
|
|
51
|
-
const componentContext = A_Context.scope(this)
|
|
59
|
+
const componentContext = A_Context.scope(this);
|
|
60
|
+
|
|
52
61
|
|
|
53
62
|
if (!config) {
|
|
54
63
|
config = new A_SignalConfig({
|
|
@@ -66,16 +75,18 @@ export class A_SignalBus extends A_Component {
|
|
|
66
75
|
componentContext.register(state);
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
|
|
69
79
|
if (!state.has(signal))
|
|
70
80
|
return;
|
|
71
81
|
|
|
82
|
+
|
|
72
83
|
// ------------------------------------------------------------------
|
|
73
84
|
// And finally if all checks are passed, we can update the state
|
|
74
85
|
// ------------------------------------------------------------------
|
|
75
86
|
|
|
76
87
|
logger?.debug(`A_SignalBus: Updating state for signal '${signal.constructor.name}' with data:`, signal.data);
|
|
77
88
|
|
|
78
|
-
state.set(signal
|
|
89
|
+
state.set(signal);
|
|
79
90
|
|
|
80
91
|
const vector = state.toVector();
|
|
81
92
|
|
|
@@ -83,8 +94,7 @@ export class A_SignalBus extends A_Component {
|
|
|
83
94
|
name: `A_SignalBus_Next_Scope_of_${this.constructor.name}`,
|
|
84
95
|
entities: [vector]
|
|
85
96
|
})
|
|
86
|
-
.inherit(
|
|
87
|
-
|
|
97
|
+
.inherit(scope);
|
|
88
98
|
|
|
89
99
|
try {
|
|
90
100
|
|
|
@@ -99,5 +109,4 @@ export class A_SignalBus extends A_Component {
|
|
|
99
109
|
throw error;
|
|
100
110
|
}
|
|
101
111
|
}
|
|
102
|
-
|
|
103
112
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A_Context, A_Fragment, A_TYPES__Component_Constructor, A_TYPES__Entity_Constructor } from "@adaas/a-concept";
|
|
1
|
+
import { A_CommonHelper, A_Context, A_Fragment, A_TYPES__Component_Constructor, A_TYPES__Entity_Constructor } from "@adaas/a-concept";
|
|
2
2
|
import { A_SignalConfig_Init } from "../A-Signal.types";
|
|
3
3
|
import { A_Signal } from "../entities/A-Signal.entity";
|
|
4
4
|
|
|
@@ -25,12 +25,14 @@ export class A_SignalConfig extends A_Fragment {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const scope = A_Context.scope(this);
|
|
28
|
-
const signalConfigs = scope.allowedEntities;
|
|
29
28
|
|
|
30
29
|
// just sort by constructor name to have consistent order
|
|
31
|
-
|
|
32
|
-
.
|
|
33
|
-
.
|
|
30
|
+
const constructors = [...scope.allowedEntities]
|
|
31
|
+
.filter(e => A_CommonHelper.isInheritedFrom(e, A_Signal))
|
|
32
|
+
.sort((a, b) => a.constructor.name.localeCompare(b.name))
|
|
33
|
+
.map(s => scope.resolveConstructor<A_Signal>(s.name));
|
|
34
|
+
|
|
35
|
+
return constructors.filter(s => s) as Array<A_TYPES__Entity_Constructor<A_Signal>>;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/**
|
|
@@ -24,7 +24,7 @@ export class A_SignalState<
|
|
|
24
24
|
* Key: Signal constructor function
|
|
25
25
|
* Value: Latest emitted data from that signal type
|
|
26
26
|
*/
|
|
27
|
-
protected _state: Map<A_TYPES__Component_Constructor<A_Signal>,
|
|
27
|
+
protected _state: Map<A_TYPES__Component_Constructor<A_Signal>, A_Signal> = new Map();
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Optional structure defining the ordered list of signal constructors
|
|
@@ -57,9 +57,7 @@ export class A_SignalState<
|
|
|
57
57
|
|
|
58
58
|
// Initialize the state map with undefined values for each signal in the structure
|
|
59
59
|
// This ensures all expected signals have entries in the state map from the start
|
|
60
|
-
|
|
61
|
-
this._state.set(signalConstructor, undefined);
|
|
62
|
-
});
|
|
60
|
+
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
|
|
@@ -71,18 +69,21 @@ export class A_SignalState<
|
|
|
71
69
|
*/
|
|
72
70
|
set(
|
|
73
71
|
signal: A_Signal,
|
|
74
|
-
value:
|
|
72
|
+
value: A_Signal
|
|
73
|
+
): void
|
|
74
|
+
set(
|
|
75
|
+
signal: A_Signal
|
|
75
76
|
): void
|
|
76
77
|
set(
|
|
77
78
|
signal: A_TYPES__Component_Constructor<A_Signal>,
|
|
78
|
-
value:
|
|
79
|
+
value: A_Signal
|
|
79
80
|
): void
|
|
80
81
|
set(
|
|
81
82
|
param1: A_TYPES__Component_Constructor<A_Signal> | A_Signal,
|
|
82
|
-
param2
|
|
83
|
+
param2?: A_Signal
|
|
83
84
|
): void {
|
|
84
85
|
const signal = param1 instanceof A_Signal ? param1.constructor as A_TYPES__Component_Constructor<A_Signal> : param1;
|
|
85
|
-
const value = param2
|
|
86
|
+
const value = param1 instanceof A_Signal ? param1 : param2!;
|
|
86
87
|
|
|
87
88
|
this._state.set(signal, value);
|
|
88
89
|
}
|
|
@@ -95,13 +96,13 @@ export class A_SignalState<
|
|
|
95
96
|
*/
|
|
96
97
|
get(
|
|
97
98
|
signal: A_Signal
|
|
98
|
-
):
|
|
99
|
+
): A_Signal | undefined
|
|
99
100
|
get(
|
|
100
101
|
signal: A_TYPES__Component_Constructor<A_Signal>
|
|
101
|
-
):
|
|
102
|
+
): A_Signal | undefined
|
|
102
103
|
get(
|
|
103
104
|
param: A_TYPES__Component_Constructor<A_Signal> | A_Signal
|
|
104
|
-
):
|
|
105
|
+
): A_Signal | undefined {
|
|
105
106
|
const signal = param instanceof A_Signal ? param.constructor as A_TYPES__Component_Constructor<A_Signal> : param;
|
|
106
107
|
return this._state.get(signal);
|
|
107
108
|
}
|
|
@@ -122,6 +123,7 @@ export class A_SignalState<
|
|
|
122
123
|
param: A_TYPES__Component_Constructor<A_Signal> | A_Signal
|
|
123
124
|
): boolean {
|
|
124
125
|
const signal = param instanceof A_Signal ? param.constructor as A_TYPES__Component_Constructor<A_Signal> : param;
|
|
126
|
+
|
|
125
127
|
return this.structure.includes(signal);
|
|
126
128
|
}
|
|
127
129
|
|
|
@@ -155,13 +157,9 @@ export class A_SignalState<
|
|
|
155
157
|
* @throws Error if structure is not defined or if any signal value is undefined
|
|
156
158
|
*/
|
|
157
159
|
toVector(): A_SignalVector {
|
|
158
|
-
const vector:
|
|
160
|
+
const vector: Array<A_Signal> = [];
|
|
159
161
|
|
|
160
|
-
this.
|
|
161
|
-
const value = this._state.get(signalConstructor);
|
|
162
|
-
if (value === undefined) {
|
|
163
|
-
throw new Error(`Signal ${signalConstructor.name} has no value in state`);
|
|
164
|
-
}
|
|
162
|
+
this._state.forEach((value, key) => {
|
|
165
163
|
vector.push(value);
|
|
166
164
|
});
|
|
167
165
|
|
|
@@ -180,8 +178,8 @@ export class A_SignalState<
|
|
|
180
178
|
* @returns Object mapping signal constructor names to their latest values
|
|
181
179
|
* @throws Error if any signal value is undefined
|
|
182
180
|
*/
|
|
183
|
-
toObject(): Record<string,
|
|
184
|
-
const obj: Record<string,
|
|
181
|
+
toObject(): Record<string, A_Signal> {
|
|
182
|
+
const obj: Record<string, A_Signal> = {};
|
|
185
183
|
|
|
186
184
|
this.structure.forEach((signalConstructor) => {
|
|
187
185
|
const value = this._state.get(signalConstructor);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A_Entity, A_Scope } from "@adaas/a-concept";
|
|
2
|
-
import { A_Signal_Init } from "../A-Signal.types";
|
|
2
|
+
import { A_Signal_Init, A_Signal_Serialized } from "../A-Signal.types";
|
|
3
3
|
import { A_SignalFeatures } from "../A-Signal.constants";
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -15,14 +15,33 @@ import { A_SignalFeatures } from "../A-Signal.constants";
|
|
|
15
15
|
* Signals are typically used in scenarios where the current state is more important than individual events,
|
|
16
16
|
* such as monitoring systems, real-time dashboards, or stateful applications.
|
|
17
17
|
*/
|
|
18
|
-
export class A_Signal
|
|
18
|
+
export class A_Signal<
|
|
19
|
+
_TSignalDataType extends Record<string, any> = Record<string, any>
|
|
20
|
+
> extends A_Entity<A_Signal_Init<_TSignalDataType>, A_Signal_Serialized<_TSignalDataType>> {
|
|
19
21
|
|
|
20
|
-
data!:
|
|
22
|
+
data!: _TSignalDataType;
|
|
21
23
|
|
|
22
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Allows to define default data for the signal.
|
|
27
|
+
*
|
|
28
|
+
* If no data is provided during initialization, the default data will be used.
|
|
29
|
+
*
|
|
30
|
+
* @returns
|
|
31
|
+
*/
|
|
32
|
+
static async default(): Promise<A_Signal | undefined> {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
|
|
24
37
|
|
|
25
|
-
|
|
38
|
+
fromJSON(serializedEntity: A_Signal_Serialized<_TSignalDataType>): void {
|
|
39
|
+
super.fromJSON(serializedEntity);
|
|
40
|
+
this.data = serializedEntity.data;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
fromNew(newEntity: A_Signal_Init<_TSignalDataType>): void {
|
|
26
45
|
this.aseid = this.generateASEID({ entity: newEntity.name });
|
|
27
46
|
this.data = newEntity.data;
|
|
28
47
|
}
|
|
@@ -39,4 +58,12 @@ export class A_Signal extends A_Entity<A_Signal_Init> {
|
|
|
39
58
|
await this.call(A_SignalFeatures.Emit, scope);
|
|
40
59
|
}
|
|
41
60
|
|
|
61
|
+
|
|
62
|
+
toJSON(): A_Signal_Serialized<_TSignalDataType> {
|
|
63
|
+
return {
|
|
64
|
+
...super.toJSON(),
|
|
65
|
+
data: this.data
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
42
69
|
}
|
|
@@ -9,60 +9,174 @@ import { A_Signal } from "./A-Signal.entity";
|
|
|
9
9
|
*
|
|
10
10
|
* Signal Vectors are useful in scenarios where multiple related signals need to be handled together,
|
|
11
11
|
* as a state of the system or a snapshot of various parameters at a given time.
|
|
12
|
+
*
|
|
13
|
+
* @template TSignalsConstructors - Array of signal constructor types (e.g., [typeof MySignal, typeof CustomSignal])
|
|
14
|
+
* @template TSignals - Array of signal instances derived from constructors
|
|
12
15
|
*/
|
|
13
|
-
export class A_SignalVector
|
|
16
|
+
export class A_SignalVector<
|
|
17
|
+
TSignals extends Array<A_Signal> = Array<A_Signal>,
|
|
18
|
+
TSignalsConstructors extends Array<A_TYPES__Entity_Constructor<A_Signal>> = TSignals extends Array<infer U> ? U extends A_Signal ? A_TYPES__Entity_Constructor<U>[] : never : never
|
|
19
|
+
> extends A_Entity<A_SignalVector_Init<TSignals[number][], TSignalsConstructors>, A_SignalVector_Serialized> {
|
|
14
20
|
|
|
15
21
|
/**
|
|
16
22
|
* The structure of the signal vector, defining the types of signals it contains.
|
|
17
23
|
*
|
|
18
24
|
* For example:
|
|
19
25
|
* [UserSignInSignal, UserStatusSignal, UserActivitySignal]
|
|
26
|
+
*
|
|
27
|
+
* [!] if not provided, it will be derived from the signals values.
|
|
20
28
|
*/
|
|
21
|
-
|
|
29
|
+
protected _structure?: TSignalsConstructors;
|
|
22
30
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
31
|
+
* It's actual vector Values of Signals like :
|
|
32
|
+
* [UserActionSignal, UserMousePositionSignal, ExternalDependencySignal]
|
|
33
|
+
*/
|
|
34
|
+
protected _signals!: TSignals[number][]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
fromNew(newEntity: A_SignalVector_Init<TSignals[number][], TSignalsConstructors>): void {
|
|
38
|
+
super.fromNew(newEntity);
|
|
39
|
+
this._structure = newEntity.structure;
|
|
40
|
+
this._signals = newEntity.values;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The structure of the signal vector, defining the types of signals it contains.
|
|
25
45
|
*
|
|
26
46
|
* For example:
|
|
27
|
-
* [
|
|
28
|
-
* { userId: '123', timestamp: '2023-10-01T12:00:00Z' }, // UserSignInSignal data
|
|
29
|
-
* { userId: '123', status: 'online' }, // UserStatusSignal data
|
|
30
|
-
* { userId: '123', activity: 'browsing' } // UserActivitySignal data
|
|
31
|
-
* ]
|
|
47
|
+
* [UserSignInSignal, UserStatusSignal, UserActivitySignal]
|
|
32
48
|
*
|
|
49
|
+
*/
|
|
50
|
+
get structure(): TSignalsConstructors {
|
|
51
|
+
return this._structure || this._signals.map(s => s.constructor as A_TYPES__Entity_Constructor<A_Signal>) as TSignalsConstructors;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
get length(): number {
|
|
56
|
+
return this.structure.length;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Checks if the vector contains a signal of the specified type.
|
|
33
62
|
*
|
|
34
|
-
*
|
|
63
|
+
* @param signal
|
|
35
64
|
*/
|
|
36
|
-
|
|
65
|
+
has(signal: A_Signal): boolean
|
|
66
|
+
has(signalConstructor: A_TYPES__Component_Constructor<A_Signal>): boolean
|
|
67
|
+
has(param1: A_Signal | A_TYPES__Component_Constructor<A_Signal>): boolean {
|
|
68
|
+
let signalConstructor: A_TYPES__Component_Constructor<A_Signal>;
|
|
69
|
+
if (param1 instanceof A_Entity) {
|
|
70
|
+
signalConstructor = param1.constructor as A_TYPES__Component_Constructor<A_Signal>;
|
|
71
|
+
} else {
|
|
72
|
+
signalConstructor = param1;
|
|
73
|
+
}
|
|
74
|
+
return this.structure.includes(signalConstructor);
|
|
75
|
+
}
|
|
37
76
|
|
|
77
|
+
get(signal: A_Signal): Record<string, any> | undefined
|
|
78
|
+
get(signalConstructor: A_TYPES__Component_Constructor<A_Signal>): Record<string, any> | undefined
|
|
79
|
+
get(param1: A_Signal | A_TYPES__Component_Constructor<A_Signal>): Record<string, any> | undefined {
|
|
80
|
+
let signalConstructor: A_TYPES__Component_Constructor<A_Signal>;
|
|
38
81
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
82
|
+
if (param1 instanceof A_Entity) {
|
|
83
|
+
signalConstructor = param1.constructor as A_TYPES__Component_Constructor<A_Signal>;
|
|
84
|
+
} else {
|
|
85
|
+
signalConstructor = param1;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const index = this._signals.findIndex(s => s.constructor === signalConstructor);
|
|
89
|
+
if (index === -1) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
return this._signals[index];
|
|
43
93
|
}
|
|
44
94
|
|
|
45
95
|
|
|
46
96
|
/**
|
|
47
97
|
* Converts to Array of values of signals in the vector
|
|
98
|
+
* Maintains the order specified in the structure/generic type
|
|
48
99
|
*
|
|
49
|
-
* @
|
|
100
|
+
* @param structure - Optional structure to override the default ordering
|
|
101
|
+
* @returns Array of signal instances in the specified order
|
|
50
102
|
*/
|
|
51
|
-
toVector
|
|
52
|
-
|
|
103
|
+
async toVector<
|
|
104
|
+
T extends Array<A_Signal> = TSignals,
|
|
105
|
+
>(
|
|
106
|
+
structure?: { [K in keyof T]: T[K] extends A_Signal ? A_TYPES__Entity_Constructor<T[K]> : never }
|
|
107
|
+
): Promise<{ [K in keyof T]: T[K] }> {
|
|
108
|
+
const usedStructure = structure || this.structure;
|
|
109
|
+
|
|
110
|
+
return usedStructure.map((signalConstructor) => {
|
|
111
|
+
const signalIndex = this._signals.findIndex(s => s.constructor === signalConstructor);
|
|
112
|
+
return signalIndex !== -1 ? this._signals[signalIndex] : undefined;
|
|
113
|
+
}) as { [K in keyof T]: T[K] };
|
|
53
114
|
}
|
|
54
115
|
|
|
116
|
+
|
|
55
117
|
/**
|
|
56
|
-
* Converts to
|
|
118
|
+
* Converts to Array of data of signals in the vector
|
|
119
|
+
* Maintains the order specified in the structure/generic type
|
|
57
120
|
*
|
|
58
|
-
* @
|
|
121
|
+
* @param structure - Optional structure to override the default ordering
|
|
122
|
+
* @returns Array of serialized signal data in the specified order
|
|
123
|
+
*/
|
|
124
|
+
async toDataVector<
|
|
125
|
+
T extends Array<A_Signal> = TSignals,
|
|
126
|
+
>(
|
|
127
|
+
structure?: { [K in keyof T]: T[K] extends A_Signal ? A_TYPES__Entity_Constructor<T[K]> : never }
|
|
128
|
+
): Promise<{ [K in keyof T]: T[K] extends A_Signal<infer D> ? D | undefined : never }> {
|
|
129
|
+
|
|
130
|
+
const usedStructure = structure || this.structure;
|
|
131
|
+
|
|
132
|
+
const results: Array<any> = [];
|
|
133
|
+
|
|
134
|
+
for (const signalConstructor of usedStructure) {
|
|
135
|
+
const signalIndex = this._signals.findIndex(s => s.constructor === signalConstructor);
|
|
136
|
+
let data: any;
|
|
137
|
+
if (signalIndex === -1) {
|
|
138
|
+
|
|
139
|
+
data = await (signalConstructor as typeof A_Signal).default()
|
|
140
|
+
|
|
141
|
+
} else {
|
|
142
|
+
const signal = this._signals[signalIndex];
|
|
143
|
+
data = signal;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
results.push(data?.toJSON().data);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return results as { [K in keyof T]: T[K] extends A_Signal<infer D> ? D | undefined : never };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Converts to Object with signal constructor names as keys and their corresponding data values
|
|
155
|
+
* Uses the structure ordering to ensure consistent key ordering
|
|
156
|
+
*
|
|
157
|
+
* @returns Object with signal constructor names as keys and signal data as values
|
|
59
158
|
*/
|
|
60
|
-
toObject
|
|
61
|
-
|
|
62
|
-
|
|
159
|
+
async toObject<
|
|
160
|
+
T extends Array<A_Signal> = TSignals,
|
|
161
|
+
>(
|
|
162
|
+
structure?: { [K in keyof T]: T[K] extends A_Signal ? A_TYPES__Entity_Constructor<T[K]> : never }
|
|
163
|
+
): Promise<{ [key: string]: T[number] extends A_Signal<infer D> ? D | undefined : never }> {
|
|
164
|
+
|
|
165
|
+
const usedStructure = structure || this.structure;
|
|
166
|
+
|
|
167
|
+
const obj: { [key: string]: T[number] extends A_Signal<infer D> ? D | undefined : never } = {};
|
|
168
|
+
usedStructure.forEach((signalConstructor) => {
|
|
63
169
|
const signalName = signalConstructor.name;
|
|
64
|
-
|
|
170
|
+
const signalIndex = this._signals.findIndex(s => s.constructor === signalConstructor);
|
|
171
|
+
|
|
172
|
+
if (signalIndex !== -1) {
|
|
173
|
+
const signal = this._signals[signalIndex];
|
|
174
|
+
obj[signalName] = signal.toJSON().data as any;
|
|
175
|
+
} else {
|
|
176
|
+
obj[signalName] = undefined as any;
|
|
177
|
+
}
|
|
65
178
|
});
|
|
179
|
+
|
|
66
180
|
return obj;
|
|
67
181
|
}
|
|
68
182
|
|
|
@@ -77,7 +191,8 @@ export class A_SignalVector extends A_Entity<A_SignalVector_Init, A_SignalVector
|
|
|
77
191
|
return {
|
|
78
192
|
...super.toJSON(),
|
|
79
193
|
structure: this.structure.map(s => s.name),
|
|
80
|
-
values: this.
|
|
194
|
+
values: this._signals.map(s => s.toJSON())
|
|
81
195
|
};
|
|
82
196
|
}
|
|
83
|
-
}
|
|
197
|
+
}
|
|
198
|
+
|
package/tests/A-Signal.test.ts
CHANGED
|
@@ -10,9 +10,9 @@ import { A_SignalVector } from "@adaas/a-utils/lib/A-Signal/entities/A-SignalVec
|
|
|
10
10
|
jest.retryTimes(0);
|
|
11
11
|
|
|
12
12
|
describe('A-Signal tests', () => {
|
|
13
|
-
it('Should Allow to
|
|
13
|
+
it('Should Allow to emit basic signal structure', async () => {
|
|
14
14
|
|
|
15
|
-
let result;
|
|
15
|
+
let result: A_SignalVector | undefined = undefined;
|
|
16
16
|
|
|
17
17
|
class UserIntentionListener extends A_Component {
|
|
18
18
|
@A_Concept.Start()
|
|
@@ -27,8 +27,69 @@ describe('A-Signal tests', () => {
|
|
|
27
27
|
buttonId: 'submit-order'
|
|
28
28
|
}
|
|
29
29
|
})
|
|
30
|
+
await signal.emit(scope)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@A_Feature.Extend()
|
|
35
|
+
async [A_SignalBusFeatures.Emit](
|
|
36
|
+
@A_Inject(A_SignalVector) vector: A_SignalVector
|
|
37
|
+
) {
|
|
38
|
+
result = vector;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const concept = new A_Concept({
|
|
43
|
+
name: 'test-concept',
|
|
44
|
+
containers: [new A_Container({
|
|
45
|
+
name: 'test-container',
|
|
46
|
+
components: [A_SignalBus, UserIntentionListener],
|
|
47
|
+
fragments: [
|
|
48
|
+
new A_SignalConfig({
|
|
49
|
+
structure: [A_Signal]
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
})]
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await concept.load();
|
|
56
|
+
await concept.start();
|
|
57
|
+
|
|
58
|
+
expect(result).toBeDefined();
|
|
59
|
+
expect(result).toBeInstanceOf(A_SignalVector);
|
|
60
|
+
expect(result!.length).toBe(1);
|
|
61
|
+
expect((await result!.toDataVector())[0]?.buttonId).toBe('submit-order');
|
|
62
|
+
|
|
63
|
+
});
|
|
64
|
+
it('Should Allow to work with custom Signals', async () => {
|
|
65
|
+
|
|
66
|
+
class UserIntentionSignal extends A_Signal<{ buttonId: string }> { }
|
|
67
|
+
|
|
68
|
+
class UserMousePositionSignal extends A_Signal<{ x: number, y: number }> {
|
|
69
|
+
static async default(): Promise<A_Signal | undefined> {
|
|
70
|
+
return Promise.resolve(new UserMousePositionSignal({
|
|
71
|
+
data: { x: 0, y: 0 }
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
class UserElementHoverSignal extends A_Signal<{ elementId: string }> { }
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
let result: A_SignalVector | undefined = undefined;
|
|
80
|
+
|
|
81
|
+
class UserIntentionListener extends A_Component {
|
|
82
|
+
@A_Concept.Start()
|
|
83
|
+
async start(
|
|
84
|
+
@A_Inject(A_Scope) scope: A_Scope,
|
|
85
|
+
@A_Inject(A_SignalBus) bus: A_SignalBus
|
|
86
|
+
) {
|
|
30
87
|
|
|
31
|
-
|
|
88
|
+
const signal = new UserIntentionSignal({
|
|
89
|
+
data: {
|
|
90
|
+
buttonId: 'submit-order'
|
|
91
|
+
}
|
|
92
|
+
})
|
|
32
93
|
|
|
33
94
|
await signal.emit(scope)
|
|
34
95
|
}
|
|
@@ -49,7 +110,7 @@ describe('A-Signal tests', () => {
|
|
|
49
110
|
components: [A_SignalBus, UserIntentionListener],
|
|
50
111
|
fragments: [
|
|
51
112
|
new A_SignalConfig({
|
|
52
|
-
structure: [
|
|
113
|
+
structure: [UserIntentionSignal, UserMousePositionSignal, UserElementHoverSignal]
|
|
53
114
|
})
|
|
54
115
|
]
|
|
55
116
|
})]
|
|
@@ -58,9 +119,15 @@ describe('A-Signal tests', () => {
|
|
|
58
119
|
await concept.load();
|
|
59
120
|
await concept.start();
|
|
60
121
|
|
|
122
|
+
|
|
61
123
|
expect(result).toBeDefined();
|
|
62
|
-
expect(result
|
|
63
|
-
expect(result
|
|
124
|
+
expect(result).toBeInstanceOf(A_SignalVector);
|
|
125
|
+
expect(result!.length).toBe(3);
|
|
126
|
+
|
|
127
|
+
expect((await result!.toDataVector())[0]?.buttonId).toBe('submit-order');
|
|
128
|
+
expect((await result!.toDataVector())[1]?.x).toBe(0);
|
|
129
|
+
expect((await result!.toDataVector())[1]?.y).toBe(0);
|
|
130
|
+
expect((await result!.toDataVector())[2]).toBeUndefined();
|
|
64
131
|
|
|
65
132
|
});
|
|
66
133
|
})
|