@adaas/a-concept 0.1.29 → 0.1.31

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.29",
3
+ "version": "0.1.31",
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",
@@ -330,16 +330,30 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
330
330
  */
331
331
  scope?: A_Scope,
332
332
  ) {
333
- if (this.isDone)
334
- return;
333
+ try {
334
+ if (scope && !scope.isInheritedFrom(A_Context.scope(this)))
335
+ scope.inherit(A_Context.scope(this));
335
336
 
336
- this._state = A_TYPES__FeatureState.PROCESSING;
337
337
 
338
- for (const stage of this) {
339
- await stage.process(scope);
338
+ if (this.isDone)
339
+ return;
340
+
341
+ this._state = A_TYPES__FeatureState.PROCESSING;
342
+
343
+ for (const stage of this) {
344
+ await stage.process(scope);
345
+ }
346
+
347
+ return await this.completed();
348
+ } catch (error) {
349
+ return await this.failed(new A_FeatureError({
350
+ title: A_FeatureError.FeatureProcessingError,
351
+ description: `An error occurred while processing the A-Feature: ${this.name}. Failed at stage: ${this.stage?.name || 'N/A'}.`,
352
+ stage: this.stage,
353
+ originalError: error
354
+ }));
340
355
  }
341
356
 
342
- return await this.completed();
343
357
  }
344
358
  /**
345
359
  * This method moves the feature to the next stage
@@ -368,6 +382,22 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
368
382
 
369
383
  this.scope.destroy();
370
384
  }
385
+ /**
386
+ * This method marks the feature as failed and throws an error
387
+ * Uses to mark the feature as failed
388
+ *
389
+ * @param error
390
+ */
391
+ async failed(error: A_FeatureError) {
392
+
393
+ this._state = A_TYPES__FeatureState.FAILED;
394
+
395
+ this._error = error;
396
+
397
+ this.scope.destroy();
398
+
399
+ throw this._error;
400
+ }
371
401
  /**
372
402
  * This method marks the feature as failed and throws an error
373
403
  * Uses to interrupt or end the feature processing
@@ -390,6 +420,7 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
390
420
  code: A_FeatureError.Interruption,
391
421
  title: reason.title,
392
422
  description: reason.description,
423
+ stage: this.stage,
393
424
  originalError: reason
394
425
  });
395
426
  break;
@@ -1,8 +1,10 @@
1
1
  import { A_Error } from "../A-Error/A_Error.class";
2
+ import { A_Stage } from "../A-Stage/A-Stage.class";
3
+ import { A_TYPES__FeatureError_Init } from "./A-Feature.types";
2
4
 
3
5
 
4
6
 
5
- export class A_FeatureError extends A_Error {
7
+ export class A_FeatureError extends A_Error<A_TYPES__FeatureError_Init> {
6
8
 
7
9
  /**
8
10
  * Indicates that the Feature has been interrupted
@@ -14,6 +16,12 @@ export class A_FeatureError extends A_Error {
14
16
  * Failed during the A-Feature initialization process
15
17
  */
16
18
  static readonly FeatureInitializationError = 'Unable to initialize A-Feature';
19
+ /**
20
+ * Indicates that there was an error processing the Feature
21
+ *
22
+ * Failed during the A-Feature processing
23
+ */
24
+ static readonly FeatureProcessingError = 'Error occurred during A-Feature processing';
17
25
 
18
26
  // =======================================================================
19
27
  // ---------------------- Decorator Errors -----------------------------
@@ -30,4 +38,17 @@ export class A_FeatureError extends A_Error {
30
38
  * Failed during the @A_Feature.Extend() decorator execution
31
39
  */
32
40
  static readonly FeatureExtensionError = 'Unable to extend A-Feature';
41
+
42
+
43
+ /**
44
+ * Stage where the error occurred
45
+ */
46
+ stage?: A_Stage
47
+
48
+
49
+ protected fromConstructor(params: A_TYPES__FeatureError_Init): void {
50
+ super.fromConstructor(params);
51
+
52
+ this.stage = params.stage;
53
+ }
33
54
  }
@@ -9,6 +9,8 @@ import { A_TYPES__Entity_Constructor } from "../A-Entity/A-Entity.types"
9
9
  import { A_Feature } from "./A-Feature.class"
10
10
  import { A_TYPES__Required } from "@adaas/a-concept/types/A_Common.types"
11
11
  import { A_Scope } from "../A-Scope/A-Scope.class"
12
+ import { A_Stage } from "../A-Stage/A-Stage.class"
13
+ import { A_TYPES__Error_Init } from "../A-Error/A_Error.types"
12
14
 
13
15
 
14
16
  // ============================================================================
@@ -99,8 +101,26 @@ export enum A_TYPES__FeatureState {
99
101
  * The feature has been interrupted
100
102
  */
101
103
  INTERRUPTED = "INTERRUPTED",
104
+ /**
105
+ * The feature has failed
106
+ */
107
+ FAILED = "FAILED"
102
108
  }
103
109
 
110
+ // ===========================================================================
111
+ // --------------------------- Error Types ------------------------------------
112
+ // ===========================================================================
113
+
114
+ export type A_TYPES__FeatureError_Init = {
115
+ /**
116
+ * Stage where the error occurred
117
+ */
118
+ stage?: A_Stage
119
+
120
+ } & A_TYPES__Error_Init
121
+
122
+
123
+
104
124
  // ===========================================================================-
105
125
  // --------------------------- Available Types -------------------------------
106
126
  // ===========================================================================
@@ -1,62 +1,317 @@
1
+ import { A_TYPES__DeepPartial } from "@adaas/a-concept/types/A_Common.types";
1
2
  import { A_Meta } from "../A-Meta/A-Meta.class";
2
- import { A_TYPES__Fragment_Init } from "./A-Fragment.types";
3
-
3
+ import { A_TYPES__Fragment_Init, A_TYPES__Fragment_Serialized } from "./A-Fragment.types";
4
4
 
5
5
 
6
+ /**
7
+ * A_Fragment is a core architectural component that represents a singleton execution context
8
+ * within the A-Concept framework. It serves as a shared memory container that can be passed
9
+ * between Components, Entities, and Commands throughout the application pipeline.
10
+ *
11
+ * Key Features:
12
+ * - Singleton pattern: Only one instance per fragment type per scope
13
+ * - Meta storage: Built-in key-value storage for pipeline data
14
+ * - Type-safe: Full TypeScript generics support for meta items and serialization
15
+ * - Serializable: Can be converted to JSON for persistence or transmission
16
+ *
17
+ * @template _MetaItems - Type definition for the meta storage structure
18
+ * @template _SerializedType - Type definition for the serialized output format
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Basic usage with typed meta
23
+ * class UserFragment extends A_Fragment<{ userId: string; role: string }> {
24
+ * constructor() {
25
+ * super({ name: 'UserFragment' });
26
+ * }
27
+ * }
28
+ *
29
+ * // Custom serialization
30
+ * class SessionFragment extends A_Fragment<
31
+ * { sessionId: string; timestamp: number },
32
+ * { name: string; sessionData: string }
33
+ * > {
34
+ * toJSON() {
35
+ * return {
36
+ * name: this.name,
37
+ * sessionData: `${this.get('sessionId')}-${this.get('timestamp')}`
38
+ * };
39
+ * }
40
+ * }
41
+ * ```
42
+ */
6
43
  export class A_Fragment<
7
- _MemoryItems extends Record<string, any> = any
44
+ _MetaItems extends Record<string, any> = any,
45
+ _SerializedType extends A_TYPES__Fragment_Serialized = A_TYPES__Fragment_Serialized & _MetaItems
8
46
  > {
9
47
  /**
10
- * Fragment Name
48
+ * The unique identifier/name for this fragment instance.
49
+ * Used for identification and debugging purposes.
11
50
  */
12
- name: string;
51
+ protected _name: string;
52
+
13
53
  /**
14
- * Memory storage for the Fragment instance
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.
15
57
  */
16
- protected _meta: A_Meta<_MemoryItems> = new A_Meta<_MemoryItems>();
58
+ protected _meta: A_Meta<_MetaItems> = new A_Meta<_MetaItems>();
17
59
 
18
60
 
19
61
  /**
20
- * A-Fragment is a singleton, a piece of execution Context that can be shared between the Components/Entities/Commands
21
- * For every A_Scope can be defined only One A_Fragment of the same type.
22
- * This class is useful for the design purpose and maintainance of the application
62
+ * Creates a new A_Fragment instance.
63
+ *
64
+ * A_Fragment implements the singleton pattern for execution contexts, allowing
65
+ * shared state management across different parts of the application pipeline.
66
+ * Each fragment serves as a memory container that can store typed data and be
67
+ * serialized for persistence or transmission.
23
68
  *
69
+ * Key Benefits:
70
+ * - Centralized state management for related operations
71
+ * - Type-safe meta operations with full IntelliSense support
72
+ * - Serialization support for data persistence
73
+ * - Singleton pattern ensures consistent state within scope
24
74
  *
25
- * [!] Every A_Fragment is a Memory Class that can store data in memory between the steps of the pipeline.
26
- * [!] So if it necessary to store some information in the Execution Context - use memory of the Fragment
75
+ * @param params - Initialization parameters
76
+ * @param params.name - Optional custom name for the fragment (defaults to class name)
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const fragment = new A_Fragment<{ userId: string }>({
81
+ * name: 'UserSessionFragment'
82
+ * });
83
+ * fragment.set('userId', '12345');
84
+ * ```
27
85
  */
28
86
  constructor(params: Partial<A_TYPES__Fragment_Init> = {}) {
29
- /**
30
- * Register the Namespace in the global Namespace provider
31
- */
32
- this.name = params.name || this.constructor.name;
87
+ this._name = params.name || this.constructor.name;
88
+ }
89
+
90
+ /**
91
+ * Gets the fragment's unique name/identifier.
92
+ *
93
+ * @returns The fragment name
94
+ */
95
+ get name(): string {
96
+ return this._name;
33
97
  }
34
98
 
35
99
  /**
36
- * Returns the Meta object that allows to store data in the Fragment memory
100
+ * Gets direct access to the underlying Meta object for advanced meta operations.
37
101
  *
38
- * @returns
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
+ * ```
39
120
  */
40
- get memory(): A_Meta<_MemoryItems> {
121
+ get meta(): A_Meta<_MetaItems> {
41
122
  return this._meta;
42
123
  }
43
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<K extends keyof _MetaItems>(param: K): _MetaItems[K] | 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<K extends keyof _MetaItems>(param: K, value: _MetaItems[K]): 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
+ }
44
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
+ }
45
282
 
46
283
 
47
284
  /**
48
- * Returns the JSON representation of the Fragment
285
+ * Serializes the fragment to a JSON-compatible object.
286
+ *
287
+ * This method combines the fragment's name with all meta data to create
288
+ * a serializable representation. The return type is determined by the
289
+ * _SerializedType generic parameter, allowing for custom serialization formats.
290
+ *
291
+ * @returns A serialized representation of the fragment
49
292
  *
50
- * @returns
293
+ * @example
294
+ * ```typescript
295
+ * const fragment = new A_Fragment<{ userId: string, role: string }>({
296
+ * name: 'UserFragment'
297
+ * });
298
+ * fragment.set('userId', '12345');
299
+ * fragment.set('role', 'admin');
300
+ *
301
+ * const json = fragment.toJSON();
302
+ * // Result: { name: 'UserFragment', userId: '12345', role: 'admin' }
303
+ * ```
51
304
  */
52
- toJSON(): _MemoryItems & { name: string } {
53
- return {
305
+ toJSON(): _SerializedType {
306
+ const result = {
54
307
  name: this.name,
55
- ...this.memory.toArray().reduce((acc, [key, value]) => {
308
+
309
+ ...this.meta.toArray().reduce((acc, [key, value]) => {
56
310
  acc[key] = value;
57
311
  return acc;
58
- }, {} as _MemoryItems)
312
+ }, {} as _MetaItems)
59
313
  };
60
- }
61
314
 
315
+ return result as unknown as _SerializedType;
316
+ }
62
317
  }
@@ -20,9 +20,9 @@ export type A_TYPES__Fragment_Init = {
20
20
  */
21
21
  export type A_TYPES__Fragment_Serialized = {
22
22
  /**
23
- * The ASEID of the fragment
23
+ * The Name of the fragment
24
24
  */
25
- aseid: string
25
+ name: string
26
26
  };
27
27
 
28
28