@adaas/a-concept 0.1.44 → 0.1.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaas/a-concept",
3
- "version": "0.1.44",
3
+ "version": "0.1.45",
4
4
  "description": "A-Concept is a framework to build new Applications within or outside the ADAAS ecosystem. This framework is designed to be modular structure regardless environment and program goal.",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.cjs",
@@ -35,7 +35,6 @@ import { A_TYPES__Component_Constructor } from "../A-Component/A-Component.types
35
35
  import { A_FormatterHelper } from "@adaas/a-concept/helpers/A_Formatter.helper";
36
36
  import { A_Fragment } from "../A-Fragment/A-Fragment.class";
37
37
  import { A_TYPES__InjectableTargets } from "../A-Inject/A-Inject.types";
38
- import { A_TYPES__ConceptAbstraction } from "../A-Concept/A-Concept.types";
39
38
  import { A_TYPES__ConceptAbstractions } from "../A-Concept/A-Concept.constants";
40
39
  import { A_CommonHelper } from "@adaas/a-concept/helpers/A_Common.helper";
41
40
 
@@ -5,6 +5,9 @@ import { A_TypeGuards } from "@adaas/a-concept/helpers/A_TypeGuards.helper";
5
5
  import { A_TYPES__ComponentMetaKey } from "../A-Component/A-Component.constants";
6
6
  import { A_FeatureError } from "./A-Feature.error";
7
7
  import { A_CommonHelper } from "@adaas/a-concept/helpers/A_Common.helper";
8
+ import { A_TYPES__EntityMetaKey } from "../A-Entity/A-Entity.constants";
9
+ import { A_TYPES__ContainerMetaKey } from "../A-Container/A-Container.constants";
10
+ import { A_Container } from "../A-Container/A-Container.class";
8
11
 
9
12
 
10
13
 
@@ -81,8 +84,21 @@ export function A_Feature_Extend(
81
84
  let include: Array<A_TYPES__FeatureExtendDecoratorScopeItem> = [];
82
85
  let exclude: Array<A_TYPES__FeatureExtendDecoratorScopeItem> = [];
83
86
  let throwOnError: boolean = true;
87
+ let metaKey;
84
88
 
85
89
 
90
+ switch (true) {
91
+ case A_TypeGuards.isEntityInstance(target):
92
+ metaKey = A_TYPES__EntityMetaKey.EXTENSIONS;
93
+ break;
94
+ case A_TypeGuards.isContainerInstance(target):
95
+ metaKey = A_TYPES__ContainerMetaKey.EXTENSIONS
96
+ break;
97
+ case A_TypeGuards.isComponentInstance(target):
98
+ metaKey = A_TYPES__ComponentMetaKey.EXTENSIONS
99
+ break;
100
+ }
101
+
86
102
 
87
103
  switch (true) {
88
104
  case A_TypeGuards.isRegExp(param1):
@@ -130,17 +146,20 @@ export function A_Feature_Extend(
130
146
  }
131
147
 
132
148
 
149
+
150
+
151
+
133
152
  const existedDefinitions = A_Context
134
153
  .meta(target)
135
- .get(A_TYPES__ComponentMetaKey.FEATURES);
154
+ .get(metaKey);
136
155
 
137
156
 
138
157
  // Get the existed metadata or create a new one
139
158
  const meta = A_Context
140
159
  .meta(target)
141
160
 
142
- const existedMeta = meta.get(A_TYPES__ComponentMetaKey.EXTENSIONS)
143
- ? new A_Meta().from(meta.get(A_TYPES__ComponentMetaKey.EXTENSIONS)!)
161
+ const existedMeta = meta.get(metaKey)
162
+ ? new A_Meta().from(meta.get(metaKey)!)
144
163
  : new A_Meta();
145
164
 
146
165
  if (existedDefinitions
@@ -187,7 +206,7 @@ export function A_Feature_Extend(
187
206
  // Update the metadata of the container with the new Feature definition
188
207
  A_Context
189
208
  .meta(target)
190
- .set(A_TYPES__ComponentMetaKey.EXTENSIONS, existedMeta);
209
+ .set(metaKey, existedMeta);
191
210
  };
192
211
  }
193
212
 
@@ -24,7 +24,7 @@ import { A_TYPES__Fragment_Init, A_TYPES__Fragment_Serialized } from "./A-Fragme
24
24
  * constructor() {
25
25
  * super({ name: 'UserFragment' });
26
26
  * }
27
- * }
27
+ * }
28
28
  *
29
29
  * // Custom serialization
30
30
  * class SessionFragment extends A_Fragment<
@@ -41,8 +41,7 @@ import { A_TYPES__Fragment_Init, A_TYPES__Fragment_Serialized } from "./A-Fragme
41
41
  * ```
42
42
  */
43
43
  export class A_Fragment<
44
- _MetaItems extends Record<string, any> = any,
45
- _SerializedType extends A_TYPES__Fragment_Serialized = A_TYPES__Fragment_Serialized & _MetaItems
44
+ _SerializedType extends A_TYPES__Fragment_Serialized = A_TYPES__Fragment_Serialized
46
45
  > {
47
46
  /**
48
47
  * The unique identifier/name for this fragment instance.
@@ -50,14 +49,6 @@ export class A_Fragment<
50
49
  */
51
50
  protected _name: string;
52
51
 
53
- /**
54
- * Internal meta storage using A_Meta for type-safe key-value operations.
55
- * This stores all the fragment's runtime data that can be accessed and modified
56
- * throughout the execution pipeline.
57
- */
58
- protected _meta: A_Meta<_MetaItems> = new A_Meta<_MetaItems>();
59
-
60
-
61
52
  /**
62
53
  * Creates a new A_Fragment instance.
63
54
  *
@@ -69,7 +60,7 @@ export class A_Fragment<
69
60
  * Key Benefits:
70
61
  * - Centralized state management for related operations
71
62
  * - Type-safe meta operations with full IntelliSense support
72
- * - Serialization support for data persistence
63
+ * - Serialization support for data persistence
73
64
  * - Singleton pattern ensures consistent state within scope
74
65
  *
75
66
  * @param params - Initialization parameters
@@ -96,191 +87,6 @@ export class A_Fragment<
96
87
  return this._name;
97
88
  }
98
89
 
99
- /**
100
- * Gets direct access to the underlying Meta object for advanced meta operations.
101
- *
102
- * Use this when you need to perform bulk operations or access Meta-specific methods.
103
- * For simple get/set operations, prefer using the direct methods on the fragment.
104
- *
105
- * @returns The Meta instance containing the fragment's meta
106
- *
107
- * @example
108
- * ```typescript
109
- * const fragment = new A_Fragment<{ users: string[], count: number }>();
110
- *
111
- * // Advanced operations using meta
112
- * fragment.meta.setMultiple({
113
- * users: ['alice', 'bob'],
114
- * count: 2
115
- * });
116
- *
117
- * // Get all keys
118
- * const keys = fragment.meta.keys();
119
- * ```
120
- */
121
- get meta(): A_Meta<_MetaItems> {
122
- return this._meta;
123
- }
124
-
125
- /**
126
- * Checks if a specific meta key exists in the fragment.
127
- *
128
- * @param param - The key to check for existence
129
- * @returns True if the key exists, false otherwise
130
- *
131
- * @example
132
- * ```typescript
133
- * if (fragment.has('userId')) {
134
- * console.log('User ID is set');
135
- * }
136
- * ```
137
- */
138
- has(param: keyof _MetaItems): boolean {
139
- return this._meta.has(param);
140
- }
141
-
142
- /**
143
- * Retrieves a value from the fragment's meta.
144
- *
145
- * @param param - The key to retrieve
146
- * @returns The value associated with the key, or undefined if not found
147
- *
148
- * @example
149
- * ```typescript
150
- * const userId = fragment.get('userId');
151
- * if (userId) {
152
- * console.log(`Current user: ${userId}`);
153
- * }
154
- * ```
155
- */
156
- get(param: keyof _MetaItems): _MetaItems[typeof param] | undefined {
157
- return this._meta.get(param);
158
- }
159
-
160
- /**
161
- * Stores a value in the fragment's meta.
162
- *
163
- * @param param - The key to store the value under
164
- * @param value - The value to store
165
- *
166
- * @example
167
- * ```typescript
168
- * fragment.set('userId', '12345');
169
- * fragment.set('role', 'admin');
170
- * ```
171
- */
172
- set(param: keyof _MetaItems, value: _MetaItems[typeof param]): void {
173
- this._meta.set(param, value);
174
- }
175
-
176
- /**
177
- * Removes a specific key from the fragment's meta.
178
- *
179
- * @param param - The key to remove
180
- *
181
- * @example
182
- * ```typescript
183
- * fragment.drop('temporaryData');
184
- * ```
185
- */
186
- drop(param: keyof _MetaItems): void {
187
- this._meta.delete(param);
188
- }
189
-
190
- /**
191
- * Clears all data from the fragment's meta.
192
- *
193
- * Use with caution as this will remove all stored data in the fragment.
194
- *
195
- * @example
196
- * ```typescript
197
- * fragment.clear(); // All meta data is now gone
198
- * ```
199
- */
200
- clear(): void {
201
- this._meta.clear();
202
- }
203
-
204
- /**
205
- * Gets the number of items stored in the fragment's meta.
206
- *
207
- * @returns The count of stored meta items
208
- *
209
- * @example
210
- * ```typescript
211
- * console.log(`Fragment contains ${fragment.size()} items`);
212
- * ```
213
- */
214
- size(): number {
215
- return this._meta.size();
216
- }
217
-
218
- /**
219
- * Gets all keys currently stored in the fragment's meta.
220
- *
221
- * @returns Array of all meta keys
222
- *
223
- * @example
224
- * ```typescript
225
- * const keys = fragment.keys();
226
- * console.log('Stored keys:', keys);
227
- * ```
228
- */
229
- keys(): (keyof _MetaItems)[] {
230
- return this._meta.toArray().map(([key]) => key);
231
- }
232
-
233
- /**
234
- * Sets multiple values at once in the fragment's meta.
235
- *
236
- * @param data - Object containing key-value pairs to set
237
- *
238
- * @example
239
- * ```typescript
240
- * fragment.setMultiple({
241
- * userId: '12345',
242
- * role: 'admin',
243
- * lastLogin: new Date()
244
- * });
245
- * ```
246
- */
247
- setMultiple(data: A_TYPES__DeepPartial<_MetaItems>): void {
248
- Object.entries(data).forEach(([key, value]) => {
249
- if (value !== undefined) {
250
- this._meta.set(key as keyof _MetaItems, value);
251
- }
252
- });
253
- }
254
-
255
- /**
256
- * Creates a shallow copy of the fragment with the same meta data.
257
- *
258
- * @param newName - Optional new name for the cloned fragment
259
- * @returns A new fragment instance with copied meta
260
- *
261
- * @example
262
- * ```typescript
263
- * const original = new A_Fragment<{ data: string }>({ name: 'original' });
264
- * original.set('data', 'test');
265
- *
266
- * const clone = original.clone('cloned');
267
- * console.log(clone.get('data')); // 'test'
268
- * ```
269
- */
270
- clone(newName?: string): A_Fragment<_MetaItems, _SerializedType> {
271
- const cloned = new (this.constructor as any)({
272
- name: newName || `${this._name}_copy`
273
- });
274
-
275
- // Copy all meta data
276
- this._meta.toArray().forEach(([key, value]) => {
277
- cloned.set(key, value);
278
- });
279
-
280
- return cloned;
281
- }
282
-
283
-
284
90
  /**
285
91
  * Serializes the fragment to a JSON-compatible object.
286
92
  *
@@ -305,13 +111,8 @@ export class A_Fragment<
305
111
  toJSON(): _SerializedType {
306
112
  const result = {
307
113
  name: this.name,
308
-
309
- ...this.meta.toArray().reduce((acc, [key, value]) => {
310
- acc[key] = value;
311
- return acc;
312
- }, {} as _MetaItems)
313
114
  };
314
115
 
315
- return result as unknown as _SerializedType;
116
+ return result as _SerializedType;
316
117
  }
317
118
  }
@@ -4,8 +4,8 @@
4
4
  * [!] Meta can be different depending on the type of input data
5
5
  */
6
6
  export class A_Meta<
7
- _StorageItems extends Record<string, any> = any
8
- // _StorageItems extends Record<string, Map<string | Symbol, any> | Array<any> | A_TYPES__Dictionary<any>>
7
+ _StorageItems extends Record<string, any> = any,
8
+ _SerializedType extends Record<string, any> = Record<string, any>
9
9
  > implements Iterable<[keyof _StorageItems, _StorageItems[keyof _StorageItems]]> {
10
10
 
11
11
  protected meta: Map<keyof _StorageItems, _StorageItems[keyof _StorageItems]> = new Map();
@@ -192,4 +192,47 @@ export class A_Meta<
192
192
  toArray(): Array<[keyof _StorageItems, _StorageItems[keyof _StorageItems]]> {
193
193
  return Array.from(this.meta.entries());
194
194
  }
195
+
196
+
197
+ protected recursiveToJSON(value: any): any {
198
+ switch (true) {
199
+ case value instanceof A_Meta:
200
+ return value.toJSON();
201
+
202
+ case value instanceof Map:
203
+ const obj: Record<string, any> = {};
204
+ for (const [k, v] of value.entries()) {
205
+ obj[String(k)] = this.recursiveToJSON(v);
206
+ }
207
+ return obj;
208
+
209
+ case Array.isArray(value):
210
+ return value.map((item) => this.recursiveToJSON(item));
211
+
212
+ case !!value && typeof value === 'object':
213
+ const res: Record<string, any> = {};
214
+ for (const [k, v] of Object.entries(value)) {
215
+ res[k] = this.recursiveToJSON(v);
216
+ }
217
+ return res;
218
+
219
+ default:
220
+ return value;
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Serializes the meta to a JSON object
226
+ * Uses internal storage to convert to JSON
227
+ *
228
+ * @returns
229
+ */
230
+ toJSON(): _SerializedType {
231
+ const json: Record<string, any> = {};
232
+
233
+ for (const [key, value] of this.meta.entries()) {
234
+ json[String(key)] = this.recursiveToJSON(value);
235
+ }
236
+ return json as _SerializedType;
237
+ }
195
238
  }
@@ -10,7 +10,6 @@ import {
10
10
  A_TYPES__A_InjectDecorator_EntityInjectionInstructions,
11
11
  A_TYPES__A_InjectDecorator_EntityInjectionQuery,
12
12
  A_TYPES__InjectableConstructors,
13
- A_TYPES__InjectableTargets,
14
13
  } from "@adaas/a-concept/global/A-Inject/A-Inject.types";
15
14
  import { A_Fragment } from "../A-Fragment/A-Fragment.class";
16
15
  import { A_Context } from "../A-Context/A-Context.class";
@@ -27,11 +26,13 @@ import { A_TYPES__Component_Constructor } from '../A-Component/A-Component.types
27
26
  import { A_TYPES__Fragment_Constructor } from '../A-Fragment/A-Fragment.types';
28
27
  import { A_TYPES__Error_Constructor } from '../A-Error/A_Error.types';
29
28
  import { A_TYPES__ComponentMetaKey } from '../A-Component/A-Component.constants';
29
+ import { A_Meta } from '../A-Meta/A-Meta.class';
30
30
 
31
31
 
32
32
 
33
33
 
34
34
  export class A_Scope<
35
+ _MetaItems extends Record<string, any> = any,
35
36
  _ComponentType extends A_TYPES__Component_Constructor[] = A_TYPES__Component_Constructor[],
36
37
  _ErrorType extends A_TYPES__Error_Constructor[] = A_TYPES__Error_Constructor[],
37
38
  _EntityType extends A_TYPES__Entity_Constructor[] = A_TYPES__Entity_Constructor[],
@@ -46,6 +47,12 @@ export class A_Scope<
46
47
  * Parent scope reference, used for inheritance of components, fragments, entities and commands
47
48
  */
48
49
  protected _parent?: A_Scope;
50
+ /**
51
+ * Internal meta storage using A_Meta for type-safe key-value operations.
52
+ * This stores all the scope's runtime data that can be accessed and modified
53
+ * throughout the execution pipeline or within running containers.
54
+ */
55
+ protected _meta: A_Meta<_MetaItems> = new A_Meta<_MetaItems>();
49
56
 
50
57
  // ===========================================================================
51
58
  // --------------------ALLowed Constructors--------------------------------
@@ -100,7 +107,10 @@ export class A_Scope<
100
107
  * Returns the name of the scope
101
108
  */
102
109
  get name() { return this._name }
103
-
110
+ /**
111
+ * Returns the meta object of the scope
112
+ */
113
+ get meta() { return this._meta }
104
114
  /**
105
115
  * Returns a list of Constructors for A-Components that are available in the scope
106
116
  */
@@ -300,6 +310,41 @@ export class A_Scope<
300
310
  }
301
311
 
302
312
 
313
+ /**
314
+ * Retrieves a value from the scope's meta.
315
+ *
316
+ * @param param - The key to retrieve
317
+ * @returns The value associated with the key, or undefined if not found
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * const userId = scope.get('userId');
322
+ * if (userId) {
323
+ * console.log(`Current user: ${userId}`);
324
+ * }
325
+ * ```
326
+ */
327
+ get(param: keyof _MetaItems): _MetaItems[typeof param] | undefined {
328
+ return this._meta.get(param);
329
+ }
330
+
331
+ /**
332
+ * Stores a value in the scope's meta.
333
+ *
334
+ * @param param - The key to store the value under
335
+ * @param value - The value to store
336
+ *
337
+ * @example
338
+ * ```typescript
339
+ * scope.set('userId', '12345');
340
+ * scope.set('role', 'admin');
341
+ * ```
342
+ */
343
+ set(param: keyof _MetaItems, value: _MetaItems[typeof param]): void {
344
+ this._meta.set(param, value);
345
+ }
346
+
347
+
303
348
  /**
304
349
  * Returns the issuer of the scope, useful for debugging and tracking purposes
305
350
  *
@@ -312,7 +357,7 @@ export class A_Scope<
312
357
  * @returns
313
358
  */
314
359
  issuer<T extends A_TYPES__ScopeLinkedComponents>(): T | undefined {
315
- return A_Context.issuer(this) as T;
360
+ return A_Context.issuer(this) as T;
316
361
  }
317
362
 
318
363
 
@@ -1,15 +1,48 @@
1
1
  import { A_Container } from '@adaas/a-concept/global/A-Container/A-Container.class';
2
2
  import { A_Scope } from '@adaas/a-concept/global/A-Scope/A-Scope.class';
3
+ import { A_Concept, A_Feature } from '../src';
3
4
 
4
5
 
5
6
  describe('A-Container tests', () => {
6
7
 
7
- it('Should Allow to create a concept', async () => {
8
+ it('Should allow to create a concept', async () => {
8
9
  const container = new A_Container();
9
10
  expect(container).toBeInstanceOf(A_Container);
10
11
  expect(container.scope).toBeDefined();
11
12
  expect(container.scope).toBeInstanceOf(A_Scope);
12
13
  });
14
+ it('Should allow to define and extend features on container level', async () => {
15
+ const results: string[] = [];
16
+
17
+
18
+ class customContainer extends A_Container {
19
+
20
+
21
+ @A_Concept.Start()
22
+ async start() {
23
+ results.push('started');
24
+
25
+ await this.call('testFeature');
26
+ }
27
+
28
+ @A_Feature.Extend({
29
+ name: 'testFeature',
30
+ })
31
+ async extendFeature() {
32
+ results.push('extended');
33
+ }
34
+ }
35
+
36
+
37
+ const myContainer = new customContainer();
38
+ const concept = new A_Concept({
39
+ containers: [myContainer]
40
+ });
41
+
42
+ await concept.start();
43
+
44
+ expect(results).toEqual(['started', 'extended']);
45
+ });
13
46
 
14
47
 
15
48
  });