@adaas/a-utils 0.3.5 → 0.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.
Files changed (63) hide show
  1. package/.conf/tsconfig.browser.json +4 -1
  2. package/.conf/tsconfig.node.json +5 -2
  3. package/dist/browser/a-service.mjs +12 -12
  4. package/dist/browser/a-service.mjs.map +1 -1
  5. package/dist/browser/a-signal.d.mts +51 -30
  6. package/dist/browser/a-signal.mjs +100 -65
  7. package/dist/browser/a-signal.mjs.map +1 -1
  8. package/dist/browser/chunk-S2RSPZXR.mjs +143 -0
  9. package/dist/browser/chunk-S2RSPZXR.mjs.map +1 -0
  10. package/dist/browser/helpers.d.mts +56 -0
  11. package/dist/browser/helpers.mjs +5 -0
  12. package/dist/browser/helpers.mjs.map +1 -0
  13. package/dist/node/{A-Signal.types-P5VKMKMs.d.mts → A-Signal.types-DxQHmPm6.d.mts} +23 -27
  14. package/dist/node/{A-Signal.types-P5VKMKMs.d.ts → A-Signal.types-DxQHmPm6.d.ts} +23 -27
  15. package/dist/node/helpers/A-Utils.helper.d.mts +56 -0
  16. package/dist/node/helpers/A-Utils.helper.d.ts +56 -0
  17. package/dist/node/helpers/A-Utils.helper.js +153 -0
  18. package/dist/node/helpers/A-Utils.helper.js.map +1 -0
  19. package/dist/node/helpers/A-Utils.helper.mjs +143 -0
  20. package/dist/node/helpers/A-Utils.helper.mjs.map +1 -0
  21. package/dist/node/helpers/index.d.mts +3 -0
  22. package/dist/node/helpers/index.d.ts +3 -0
  23. package/dist/node/helpers/index.js +12 -0
  24. package/dist/node/helpers/index.js.map +1 -0
  25. package/dist/node/helpers/index.mjs +4 -0
  26. package/dist/node/helpers/index.mjs.map +1 -0
  27. package/dist/node/lib/A-Service/A-Service.container.js +12 -12
  28. package/dist/node/lib/A-Service/A-Service.container.js.map +1 -1
  29. package/dist/node/lib/A-Service/A-Service.container.mjs +12 -12
  30. package/dist/node/lib/A-Service/A-Service.container.mjs.map +1 -1
  31. package/dist/node/lib/A-Signal/A-Signal.types.d.mts +1 -1
  32. package/dist/node/lib/A-Signal/A-Signal.types.d.ts +1 -1
  33. package/dist/node/lib/A-Signal/components/A-SignalBus.component.d.mts +1 -1
  34. package/dist/node/lib/A-Signal/components/A-SignalBus.component.d.ts +1 -1
  35. package/dist/node/lib/A-Signal/context/A-SignalConfig.context.d.mts +1 -1
  36. package/dist/node/lib/A-Signal/context/A-SignalConfig.context.d.ts +1 -1
  37. package/dist/node/lib/A-Signal/context/A-SignalState.context.d.mts +1 -1
  38. package/dist/node/lib/A-Signal/context/A-SignalState.context.d.ts +1 -1
  39. package/dist/node/lib/A-Signal/entities/A-Signal.entity.d.mts +1 -1
  40. package/dist/node/lib/A-Signal/entities/A-Signal.entity.d.ts +1 -1
  41. package/dist/node/lib/A-Signal/entities/A-Signal.entity.js +35 -59
  42. package/dist/node/lib/A-Signal/entities/A-Signal.entity.js.map +1 -1
  43. package/dist/node/lib/A-Signal/entities/A-Signal.entity.mjs +35 -59
  44. package/dist/node/lib/A-Signal/entities/A-Signal.entity.mjs.map +1 -1
  45. package/dist/node/lib/A-Signal/entities/A-SignalVector.entity.d.mts +29 -4
  46. package/dist/node/lib/A-Signal/entities/A-SignalVector.entity.d.ts +29 -4
  47. package/dist/node/lib/A-Signal/entities/A-SignalVector.entity.js +64 -5
  48. package/dist/node/lib/A-Signal/entities/A-SignalVector.entity.js.map +1 -1
  49. package/dist/node/lib/A-Signal/entities/A-SignalVector.entity.mjs +65 -6
  50. package/dist/node/lib/A-Signal/entities/A-SignalVector.entity.mjs.map +1 -1
  51. package/dist/node/lib/A-Signal/index.d.mts +1 -1
  52. package/dist/node/lib/A-Signal/index.d.ts +1 -1
  53. package/jest.config.ts +3 -1
  54. package/package.json +19 -3
  55. package/src/helpers/A-Utils.helper.ts +186 -0
  56. package/src/helpers/index.ts +1 -0
  57. package/src/lib/A-Service/A-Service.container.ts +12 -12
  58. package/src/lib/A-Signal/A-Signal.types.ts +2 -2
  59. package/src/lib/A-Signal/entities/A-Signal.entity.ts +44 -84
  60. package/src/lib/A-Signal/entities/A-SignalVector.entity.ts +80 -11
  61. package/tests/A-Signal.test.ts +16 -12
  62. package/tsconfig.json +4 -1
  63. package/tsup.config.ts +2 -0
@@ -0,0 +1,186 @@
1
+ import { A_Caller, A_Component, A_Feature, A_Inject } from "@adaas/a-concept";
2
+ import { A_Frame } from "@adaas/a-frame";
3
+ import { A_ExecutionContext } from "@adaas/a-utils/a-execution";
4
+
5
+
6
+
7
+ @A_Frame.Component({
8
+ namespace: 'A-Utils',
9
+ name: 'A-UtilsHelper',
10
+ description: 'Utility helper class providing common functions for A-Utils library, such as hashing and serialization.'
11
+ })
12
+ export class A_UtilsHelper extends A_Component {
13
+
14
+ // ─────────────────────────────────────────────────────────────────────────────
15
+ // ── Hashing ──────────────────────────────────────────────────────────────────
16
+ // ─────────────────────────────────────────────────────────────────────────────
17
+
18
+ /**
19
+ * Produces a deterministic, collision-resistant hash string for any JS value.
20
+ *
21
+ * Improvements over the legacy `createHash`:
22
+ * - **Null-safe** — handles `null` without throwing
23
+ * - **Function-aware serialization** — functions inside objects / arrays are
24
+ * serialized via `.toString()` so `{ fn: () => 1 }` ≠ `{}`
25
+ * - **FNV-1a 52-bit** — better avalanche / distribution than DJB2-32,
26
+ * and uses the safe JS integer range so the result is always positive
27
+ * - **Hex output** — compact, URL-safe, fixed-width (13 chars)
28
+ *
29
+ * @param value Any value: string, number, boolean, null, undefined,
30
+ * object, array, Map, Set, function, or a mix of these.
31
+ * @returns A 13-character lower-hex string (52-bit FNV-1a).
32
+ */
33
+ static hash(value?: any): string {
34
+ const source = A_UtilsHelper.serialize(value);
35
+ return A_UtilsHelper.fnv1a52(source);
36
+ }
37
+
38
+
39
+ // ─────────────────────────────────────────────────────────────────────────────
40
+ // ── Serialization ────────────────────────────────────────────────────────────
41
+ // ─────────────────────────────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * Converts any JS value into a deterministic string representation
45
+ * suitable for hashing.
46
+ *
47
+ * Key properties:
48
+ * - **Deterministic**: same logical value → same string every time
49
+ * - **Injective-ish**: structurally different values produce different
50
+ * strings (type tags prevent `"3"` vs `3` collisions)
51
+ * - **Recursive**: handles nested objects, arrays, Maps, Sets
52
+ * - **Function-aware**: serializes functions via `.toString()`
53
+ *
54
+ * @param value Anything.
55
+ * @returns A deterministic string.
56
+ */
57
+ static serialize(value: any): string {
58
+ // Primitives & null/undefined
59
+ if (value === null) return '<null>';
60
+ if (value === undefined) return '<undefined>';
61
+
62
+ switch (typeof value) {
63
+ case 'string':
64
+ return `s:${value}`;
65
+ case 'number':
66
+ return `n:${value}`;
67
+ case 'boolean':
68
+ return `b:${value}`;
69
+ case 'bigint':
70
+ return `bi:${value}`;
71
+ case 'symbol':
72
+ return `sym:${value.toString()}`;
73
+ case 'function':
74
+ return `fn:${value.toString()}`;
75
+ }
76
+
77
+ // Map
78
+ if (value instanceof Map) {
79
+ const entries = Array.from(value.entries())
80
+ .map(([k, v]) => `${A_UtilsHelper.serialize(k)}=>${A_UtilsHelper.serialize(v)}`)
81
+ .sort()
82
+ .join(',');
83
+ return `Map{${entries}}`;
84
+ }
85
+
86
+ // Set
87
+ if (value instanceof Set) {
88
+ const items = Array.from(value.values())
89
+ .map(v => A_UtilsHelper.serialize(v))
90
+ .sort()
91
+ .join(',');
92
+ return `Set{${items}}`;
93
+ }
94
+
95
+ // Date
96
+ if (value instanceof Date) {
97
+ return `Date:${value.toISOString()}`;
98
+ }
99
+
100
+ // RegExp
101
+ if (value instanceof RegExp) {
102
+ return `RegExp:${value.toString()}`;
103
+ }
104
+
105
+ // Array
106
+ if (Array.isArray(value)) {
107
+ const items = value.map(v => A_UtilsHelper.serialize(v)).join(',');
108
+ return `[${items}]`;
109
+ }
110
+
111
+ // toJSON support (e.g. custom entities, ASEID, etc.)
112
+ if (typeof value.toJSON === 'function') {
113
+ return `json:${A_UtilsHelper.serialize(value.toJSON())}`;
114
+ }
115
+
116
+ // Plain object — sort keys for determinism, serialize functions too
117
+ const keys = Object.keys(value).sort();
118
+ const pairs = keys.map(k => `${k}:${A_UtilsHelper.serialize(value[k])}`).join(',');
119
+ return `{${pairs}}`;
120
+ }
121
+
122
+
123
+ // ─────────────────────────────────────────────────────────────────────────────
124
+ // ── FNV-1a (pure Number, no BigInt) ──────────────────────────────────────────
125
+ // ─────────────────────────────────────────────────────────────────────────────
126
+
127
+ /**
128
+ * FNV-1a hash using two 32-bit halves to simulate a 52-bit space,
129
+ * without requiring BigInt.
130
+ *
131
+ * Works identically in:
132
+ * - All browsers (including Safari 13, IE11 polyfill targets, React Native)
133
+ * - Node.js (any version)
134
+ * - Web Workers, Service Workers, Deno, Bun
135
+ *
136
+ * - Better avalanche than DJB2 (each input bit affects many output bits)
137
+ * - ~52-bit effective space — vastly fewer collisions than 32-bit
138
+ * - Always produces a **positive** hex string of 13 characters
139
+ *
140
+ * @param input Pre-serialized string.
141
+ * @returns 13-character lower-hex string.
142
+ */
143
+ private static fnv1a52(input: string): string {
144
+ // FNV-1a offset basis split into two 32-bit halves
145
+ let h1 = 0x811c9dc5; // low 32 bits
146
+ let h2 = 0x00000842; // high 20 bits (keeps us in 52-bit range)
147
+
148
+ // FNV prime = 0x01000193
149
+ const PRIME = 0x01000193;
150
+
151
+ for (let i = 0; i < input.length; i++) {
152
+ h1 ^= input.charCodeAt(i);
153
+
154
+ // Multiply h1 by prime (32-bit, unsigned)
155
+ const product = Math.imul(h1, PRIME);
156
+ h1 = product >>> 0;
157
+
158
+ // Carry overflow into h2, keep h2 within 20 bits
159
+ h2 = ((Math.imul(h2, PRIME) + (product / 0x100000000 >>> 0)) & 0xFFFFF) >>> 0;
160
+ }
161
+
162
+ // Combine: h2 (20 bits) << 32 | h1 (32 bits) → 52-bit number
163
+ // Since 2^52 fits in Number.MAX_SAFE_INTEGER, this is exact.
164
+ const combined = h2 * 0x100000000 + h1;
165
+
166
+ return combined.toString(16).padStart(13, '0');
167
+ }
168
+
169
+
170
+
171
+ // ==============================================================================
172
+ // =============== Instance methods for used for Injection ======================
173
+ // ==============================================================================
174
+ @A_Frame.Method({
175
+ description: 'Instance method wrapper for the static hash function, allowing it to be injected as a dependency.'
176
+ })
177
+ hash(
178
+ @A_Inject(A_Caller) caller: any,
179
+ @A_Inject(A_ExecutionContext) context: A_ExecutionContext,
180
+ @A_Inject(A_Feature) feature: A_Feature
181
+ ) {
182
+ const hash = A_UtilsHelper.hash(caller);
183
+
184
+ context.set(feature.name, hash);
185
+ }
186
+ }
@@ -0,0 +1 @@
1
+ export { A_UtilsHelper } from './A-Utils.helper';
@@ -26,11 +26,11 @@ export class A_Service extends A_Container {
26
26
  */
27
27
  async load() {
28
28
  try {
29
- await this.call(A_ServiceFeatures.onBeforeLoad);
29
+ await this.call(A_ServiceFeatures.onBeforeLoad, this.scope);
30
30
 
31
- await this.call(A_ServiceFeatures.onLoad);
31
+ await this.call(A_ServiceFeatures.onLoad, this.scope);
32
32
 
33
- await this.call(A_ServiceFeatures.onAfterLoad);
33
+ await this.call(A_ServiceFeatures.onAfterLoad, this.scope);
34
34
 
35
35
  } catch (error) {
36
36
 
@@ -56,7 +56,7 @@ export class A_Service extends A_Container {
56
56
 
57
57
  this.scope.register(wrappedError);
58
58
 
59
- await this.call(A_ServiceFeatures.onError);
59
+ await this.call(A_ServiceFeatures.onError, this.scope);
60
60
  }
61
61
 
62
62
  }
@@ -68,11 +68,11 @@ export class A_Service extends A_Container {
68
68
  */
69
69
  async start() {
70
70
  try {
71
- await this.call(A_ServiceFeatures.onBeforeStart);
71
+ await this.call(A_ServiceFeatures.onBeforeStart, this.scope);
72
72
 
73
- await this.call(A_ServiceFeatures.onStart);
73
+ await this.call(A_ServiceFeatures.onStart, this.scope);
74
74
 
75
- await this.call(A_ServiceFeatures.onAfterStart);
75
+ await this.call(A_ServiceFeatures.onAfterStart, this.scope);
76
76
 
77
77
  } catch (error) {
78
78
 
@@ -98,7 +98,7 @@ export class A_Service extends A_Container {
98
98
 
99
99
  this.scope.register(wrappedError);
100
100
 
101
- await this.call(A_ServiceFeatures.onError);
101
+ await this.call(A_ServiceFeatures.onError, this.scope);
102
102
  }
103
103
 
104
104
  }
@@ -109,11 +109,11 @@ export class A_Service extends A_Container {
109
109
  */
110
110
  async stop() {
111
111
  try {
112
- await this.call(A_ServiceFeatures.onBeforeStop);
112
+ await this.call(A_ServiceFeatures.onBeforeStop, this.scope);
113
113
 
114
- await this.call(A_ServiceFeatures.onStop);
114
+ await this.call(A_ServiceFeatures.onStop, this.scope);
115
115
 
116
- await this.call(A_ServiceFeatures.onAfterStop);
116
+ await this.call(A_ServiceFeatures.onAfterStop, this.scope);
117
117
 
118
118
  } catch (error) {
119
119
 
@@ -139,7 +139,7 @@ export class A_Service extends A_Container {
139
139
 
140
140
  this.scope.register(wrappedError);
141
141
 
142
- await this.call(A_ServiceFeatures.onError);
142
+ await this.call(A_ServiceFeatures.onError, this.scope);
143
143
  }
144
144
  }
145
145
 
@@ -51,7 +51,7 @@ export type A_SignalVector_Serialized = A_TYPES__Entity_Serialized & {
51
51
 
52
52
 
53
53
 
54
- export type A_Signal_Init<T extends Record<string, any> = Record<string, any>> = {
54
+ export type A_Signal_Init<T extends any = any> = {
55
55
  /**
56
56
  * Possible signal id
57
57
  *
@@ -68,7 +68,7 @@ export type A_Signal_Init<T extends Record<string, any> = Record<string, any>> =
68
68
  data: T
69
69
  }
70
70
 
71
- export type A_Signal_Serialized<T extends Record<string, any> = Record<string, any>> = {
71
+ export type A_Signal_Serialized<T extends any = any> = {
72
72
  /**
73
73
  * The signal data
74
74
  */
@@ -1,6 +1,7 @@
1
- import { A_Entity, A_Scope } from "@adaas/a-concept";
1
+ import { A_Entity } from "@adaas/a-concept";
2
2
  import { A_Signal_Init, A_Signal_Serialized } from "../A-Signal.types";
3
3
  import { A_Frame } from "@adaas/a-frame";
4
+ import { A_UtilsHelper } from "@adaas/a-utils/helpers";
4
5
 
5
6
  /**
6
7
  * A Signal Entity is an individual signal instance that carries data.
@@ -21,23 +22,14 @@ import { A_Frame } from "@adaas/a-frame";
21
22
  description: 'A Signal Entity represents an individual signal instance that carries data, used for managing state within an application context. Signals are designed to reflect the current state rather than individual events, making them suitable for scenarios where state monitoring and real-time updates are essential.'
22
23
  })
23
24
  export class A_Signal<
24
- _TSignalDataType extends Record<string, any> = Record<string, any>
25
- > extends A_Entity<A_Signal_Init<_TSignalDataType>, A_Signal_Serialized<_TSignalDataType>> {
25
+ _TSignalDataType extends any = any,
26
+ _TSignalSerializedDataType extends any = _TSignalDataType,
27
+ > extends A_Entity<A_Signal_Init<_TSignalDataType>, A_Signal_Serialized<_TSignalSerializedDataType>> {
26
28
 
27
29
 
28
30
  // ========================================================================
29
31
  // ========================== Static Methods ==============================
30
32
  // ========================================================================
31
- /**
32
- * Allows to define default data for the signal.
33
- *
34
- * If no data is provided during initialization, the default data will be used.
35
- *
36
- * @returns
37
- */
38
- static async default(): Promise<A_Signal | undefined> {
39
- return undefined;
40
- }
41
33
 
42
34
  // ========================================================================
43
35
  // ========================== Instance Properties ========================
@@ -48,69 +40,6 @@ export class A_Signal<
48
40
  */
49
41
  data!: _TSignalDataType;
50
42
 
51
- /**
52
- * Generates signal hash uses for comparison
53
- *
54
- * @param str
55
- */
56
- protected createHash(str?: string): string
57
- protected createHash(str?: undefined): string
58
- protected createHash(str?: Record<string, any>): string
59
- protected createHash(str?: Array<any>): string
60
- protected createHash(str?: number): string
61
- protected createHash(str?: boolean): string
62
- protected createHash(str?: null): string
63
- protected createHash(map?: Map<any, any>): string
64
- protected createHash(set?: Set<any>): string
65
- protected createHash(str?: any): string {
66
- let hashSource: string;
67
-
68
- if (str instanceof Map) {
69
- hashSource = JSON.stringify(Array.from(str.entries()));
70
- } else if (str instanceof Set) {
71
- hashSource = JSON.stringify(Array.from(str.values()));
72
- } else {
73
- switch (typeof str) {
74
- case 'string':
75
- hashSource = str;
76
- break;
77
- case 'undefined':
78
- hashSource = 'undefined';
79
- break;
80
-
81
- case 'object':
82
- if ('toJSON' in str)
83
- hashSource = JSON.stringify(str.toJSON());
84
-
85
- else
86
- hashSource = JSON.stringify(str);
87
- break;
88
- case 'number':
89
- hashSource = str.toString();
90
- break;
91
- case 'boolean':
92
- hashSource = str ? 'true' : 'false';
93
- break;
94
- case 'function':
95
- hashSource = str.toString();
96
- break;
97
- default:
98
- hashSource = String(str);
99
- }
100
- }
101
-
102
- let hash = 0, i, chr;
103
- for (i = 0; i < hashSource.length; i++) {
104
- chr = hashSource.charCodeAt(i);
105
- hash = ((hash << 5) - hash) + chr;
106
- hash |= 0; // Convert to 32bit integer
107
- }
108
-
109
- const hashString = hash.toString();
110
-
111
- return hashString;
112
- }
113
-
114
43
  /**
115
44
  * This method compares the current signal with another signal instance by deduplication ID
116
45
  * this id can be configured during initialization with the "id" property.
@@ -131,15 +60,37 @@ export class A_Signal<
131
60
 
132
61
  return true;
133
62
  }
134
-
135
63
 
64
+ /**
65
+ * Allows to define default data for the signal.
66
+ *
67
+ * If no data is provided during initialization, the default data will be used.
68
+ *
69
+ * @returns
70
+ */
71
+ fromUndefined(): void {
72
+ const name = (this.constructor as typeof A_Entity).entity;
73
+
74
+ this.data = undefined as unknown as _TSignalDataType;
136
75
 
137
- fromJSON(serializedEntity: A_Signal_Serialized<_TSignalDataType>): void {
138
- super.fromJSON(serializedEntity);
139
- this.data = serializedEntity.data;
140
- }
76
+ const identity = {
77
+ name: name,
78
+ data: this.data
79
+ };
141
80
 
81
+ const id = A_UtilsHelper.hash(identity);
142
82
 
83
+ this.aseid = this.generateASEID({
84
+ entity: name,
85
+ id: id,
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Allows to initialize the signal from a new signal entity. This is useful for example when we want to create a new instance of the signal entity with the same data as another instance, but with a different ASEID.
91
+ *
92
+ * @param newEntity
93
+ */
143
94
  fromNew(newEntity: A_Signal_Init<_TSignalDataType>): void {
144
95
  this.data = newEntity.data;
145
96
 
@@ -148,7 +99,7 @@ export class A_Signal<
148
99
  data: this.data
149
100
  };
150
101
 
151
- const id = this.createHash(identity);
102
+ const id = A_UtilsHelper.hash(identity);
152
103
 
153
104
  this.aseid = this.generateASEID({
154
105
  entity: newEntity.name,
@@ -156,11 +107,20 @@ export class A_Signal<
156
107
  });
157
108
  }
158
109
 
110
+ /**
111
+ * Allows to initialize the signal from a serialized version of the signal. This is useful for example when we receive a signal from the server and we want to create an instance of the signal entity from the received data.
112
+ *
113
+ * @param serializedEntity
114
+ */
115
+ fromJSON(serializedEntity: A_Signal_Serialized<_TSignalSerializedDataType>): void {
116
+ super.fromJSON(serializedEntity);
117
+ this.data = serializedEntity.data as unknown as _TSignalDataType;
118
+ }
159
119
 
160
- toJSON(): A_Signal_Serialized<_TSignalDataType> {
120
+ toJSON(): A_Signal_Serialized<_TSignalSerializedDataType> {
161
121
  return {
162
122
  ...super.toJSON(),
163
- data: this.data
123
+ data: this.data as unknown as _TSignalSerializedDataType
164
124
  };
165
125
  }
166
126
 
@@ -1,4 +1,4 @@
1
- import { A_Entity, A_Scope, A_TYPES__Component_Constructor, A_TYPES__Entity_Constructor } from "@adaas/a-concept";
1
+ import { A_Entity, A_Scope, A_TypeGuards, A_TYPES__Component_Constructor, A_TYPES__Entity_Constructor } from "@adaas/a-concept";
2
2
  import { A_SignalVector_Serialized, A_SignalVector_Init, A_Signal_TSignalsConstructors, A_SignalTValue, A_SignalTValueArray } from "../A-Signal.types";
3
3
  import { A_Signal } from "./A-Signal.entity";
4
4
  import { A_Frame } from "@adaas/a-frame";
@@ -107,10 +107,60 @@ export class A_SignalVector<
107
107
  };
108
108
  }
109
109
 
110
+ /**
111
+ * Checks that 2 vectors are identical by types and data
112
+ *
113
+ * e.g. [UserSignInSignal, UserStatusSignal] is equal to [UserSignInSignal, UserStatusSignal] with the same data,
114
+ * but not equal to [UserStatusSignal, UserSignInSignal] or [UserSignInSignal, UserStatusSignal] with different data.
115
+ *
116
+ * @param other
117
+ * @returns
118
+ */
119
+ equals(other: A_SignalVector<TSignals>): boolean {
120
+ if (this.structure.length !== other.structure.length) {
121
+ return false;
122
+ }
123
+
124
+ for (let i = 0; i < this.structure.length; i++) {
125
+ const thisSignalConstructor = this.structure[i];
126
+ const otherSignalConstructor = other.structure[i];
127
+
128
+ if (thisSignalConstructor !== otherSignalConstructor) {
129
+ return false;
130
+ }
131
+
132
+ const thisSignalIndex = this._signals.findIndex(s => s.constructor === thisSignalConstructor);
133
+ const otherSignalIndex = other._signals.findIndex(s => s.constructor === otherSignalConstructor);
134
+
135
+ if (thisSignalIndex !== otherSignalIndex) {
136
+ return false;
137
+ }
138
+
139
+ const thisSignal = thisSignalIndex !== -1 ? this._signals[thisSignalIndex] : undefined;
140
+ const otherSignal = otherSignalIndex !== -1 ? other._signals[otherSignalIndex] : undefined;
141
+
142
+ if (thisSignal && otherSignal) {
143
+ if (!thisSignal.compare(otherSignal)) {
144
+ return false;
145
+ }
146
+ } else if (thisSignal || otherSignal) {
147
+ return false;
148
+ }
149
+ }
150
+
151
+ return true;
152
+ }
153
+
110
154
 
111
155
  /**
112
156
  * Allows to match the current Signal Vector with another Signal Vector by comparing each signal in the structure.
113
- * This method returns true if all signals in the vector match the corresponding signals in the other vector.
157
+ * This method returns true if all signals in the vector A match the corresponding signals in vector B, and false otherwise.
158
+ *
159
+ *
160
+ * e.g. [UserSignInSignal, UserStatusSignal] matches [UserStatusSignal, UserSignInSignal] with the same data,
161
+ *
162
+ * but not matches [UserSignInSignal, UserStatusSignal] with different data or [UserSignInSignal] or [UserSignInSignal, UserStatusSignal, UserActivitySignal].
163
+ *
114
164
  *
115
165
  * @param other
116
166
  * @returns
@@ -146,13 +196,32 @@ export class A_SignalVector<
146
196
  return true;
147
197
  }
148
198
 
149
-
199
+
200
+ /**
201
+ * Checks if the current Signal Vector includes all signals from another Signal Vector, regardless of order.
202
+ *
203
+ * e.g. [UserSignInSignal, UserStatusSignal] includes [UserStatusSignal] with the same data,
204
+ * but not includes [UserStatusSignal] with different data or [UserActivitySignal].
205
+ *
206
+ * @param other
207
+ */
208
+ includes(other: A_SignalVector<TSignals>): boolean {
209
+ for (const signalConstructor of other.structure) {
210
+ const signalIndex = this._signals.findIndex(s => s.constructor === signalConstructor);
211
+ if (signalIndex === -1) {
212
+ return false;
213
+ }
214
+ }
215
+ return true;
216
+ }
217
+
218
+
150
219
  /**
151
220
  * This method should ensure that the current Signal Vector contains all signals from the provided Signal Vector.
152
221
  *
153
222
  * @param signal
154
223
  */
155
- contains(signal: A_SignalVector): boolean{
224
+ contains(signal: A_SignalVector): boolean {
156
225
  for (const signalConstructor of signal.structure) {
157
226
  const signalIndex = this._signals.findIndex(s => s.constructor === signalConstructor);
158
227
  if (signalIndex === -1) {
@@ -171,12 +240,12 @@ export class A_SignalVector<
171
240
  has(signalConstructor: A_TYPES__Entity_Constructor<A_Signal>): boolean
172
241
  has(param1: A_Signal | A_TYPES__Entity_Constructor<A_Signal>): boolean {
173
242
  let signalConstructor: A_TYPES__Entity_Constructor<A_Signal>;
174
- if (param1 instanceof A_Entity) {
243
+ if (A_TypeGuards.isEntityInstance(param1)) {
175
244
  signalConstructor = param1.constructor as A_TYPES__Entity_Constructor<A_Signal>;
176
245
  } else {
177
246
  signalConstructor = param1;
178
247
  }
179
- return this.structure.includes(signalConstructor as any);
248
+ return this.structure.includes(signalConstructor);
180
249
  }
181
250
 
182
251
  /**
@@ -210,11 +279,11 @@ export class A_SignalVector<
210
279
  * @param structure - Optional structure to override the default ordering
211
280
  * @returns Array of signal instances in the specified order
212
281
  */
213
- async toVector<
282
+ toVector<
214
283
  T extends Array<A_Signal> = TSignals,
215
284
  >(
216
285
  structure?: A_Signal_TSignalsConstructors<T>
217
- ): Promise<T> {
286
+ ): T {
218
287
  const usedStructure = structure || this.structure;
219
288
 
220
289
  return usedStructure.map((signalConstructor) => {
@@ -231,11 +300,11 @@ export class A_SignalVector<
231
300
  * @param structure - Optional structure to override the default ordering
232
301
  * @returns Array of serialized signal data in the specified order
233
302
  */
234
- async toDataVector<
303
+ toDataVector<
235
304
  T extends A_Signal[] = TSignals,
236
305
  >(
237
306
  structure?: A_Signal_TSignalsConstructors<T>
238
- ): Promise<A_SignalTValueArray<T>> {
307
+ ): A_SignalTValueArray<T> {
239
308
 
240
309
  const usedStructure = structure || this.structure;
241
310
 
@@ -246,7 +315,7 @@ export class A_SignalVector<
246
315
  let data: any;
247
316
  if (signalIndex === -1) {
248
317
 
249
- data = await (signalConstructor as typeof A_Signal).default()
318
+ data = new (signalConstructor as typeof A_Signal)()
250
319
 
251
320
  } else {
252
321
  const signal = this._signals[signalIndex];
@@ -29,8 +29,8 @@ describe('A-Signal tests', () => {
29
29
  expect(vector).toBeDefined();
30
30
  expect(vector).toBeInstanceOf(A_SignalVector);
31
31
  expect(vector.length).toBe(2);
32
- expect((await vector.toDataVector())[0]?.buttonId).toBe('submit-order');
33
- expect((await vector.toDataVector())[1]?.pageId).toBe('home-page');
32
+ expect((vector.toDataVector())[0]?.buttonId).toBe('submit-order');
33
+ expect((vector.toDataVector())[1]?.pageId).toBe('home-page');
34
34
  });
35
35
  it('Should Allow to match Signal Vector', async () => {
36
36
  class MySignalA extends A_Signal<{ buttonId: string }> { }
@@ -57,7 +57,7 @@ describe('A-Signal tests', () => {
57
57
  class MySignalA extends A_Signal<{ buttonId: string }> { }
58
58
  class MySignalB extends A_Signal<{ pageId: string }> { }
59
59
  class MySignalC extends A_Signal<{ userId: string }> { }
60
-
60
+
61
61
  const vector = new A_SignalVector<[MySignalA, MySignalB, MySignalC]>([
62
62
  new MySignalA({ data: { buttonId: 'submit-order' } }),
63
63
  new MySignalB({ data: { pageId: 'home-page' } }),
@@ -142,7 +142,7 @@ describe('A-Signal tests', () => {
142
142
  expect(result).toBeDefined();
143
143
  expect(result).toBeInstanceOf(A_SignalVector);
144
144
  expect(result!.length).toBe(1);
145
- expect((await result!.toDataVector())[0]?.buttonId).toBe('submit-order');
145
+ expect((result!.toDataVector())[0]?.buttonId).toBe('submit-order');
146
146
 
147
147
  });
148
148
  it('Should Allow to work with custom Signals', async () => {
@@ -150,10 +150,14 @@ describe('A-Signal tests', () => {
150
150
  class UserIntentionSignal extends A_Signal<{ buttonId: string }> { }
151
151
 
152
152
  class UserMousePositionSignal extends A_Signal<{ x: number, y: number }> {
153
- static async default(): Promise<A_Signal | undefined> {
154
- return Promise.resolve(new UserMousePositionSignal({
155
- data: { x: 0, y: 0 }
156
- }));
153
+ fromUndefined(): void {
154
+ super.fromNew({
155
+ name: 'UserMousePositionSignal',
156
+ data: {
157
+ x: 0,
158
+ y: 0
159
+ }
160
+ })
157
161
  }
158
162
  }
159
163
  class UserElementHoverSignal extends A_Signal<{ elementId: string }> { }
@@ -208,10 +212,10 @@ describe('A-Signal tests', () => {
208
212
  expect(result).toBeInstanceOf(A_SignalVector);
209
213
  expect(result!.length).toBe(3);
210
214
 
211
- expect((await result!.toDataVector())[0]?.buttonId).toBe('submit-order');
212
- expect((await result!.toDataVector())[1]?.x).toBe(0);
213
- expect((await result!.toDataVector())[1]?.y).toBe(0);
214
- expect((await result!.toDataVector())[2]).toBeUndefined();
215
+ expect((result!.toDataVector())[0]?.buttonId).toBe('submit-order');
216
+ expect((result!.toDataVector())[1]?.x).toBe(0);
217
+ expect((result!.toDataVector())[1]?.y).toBe(0);
218
+ expect((result!.toDataVector())[2]).toBeUndefined();
215
219
 
216
220
  });
217
221