@adaas/a-concept 0.2.5 → 0.2.6
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 +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +15 -11
- package/dist/index.d.ts +15 -11
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/global/A-Component/A-Component.class.ts +3 -3
- package/src/global/A-Feature/A-Feature.class.ts +52 -9
- package/src/global/A-Stage/A-Stage.class.ts +54 -52
- package/src/helpers/A_TypeGuards.helper.ts +5 -0
- package/tests/A-Abstraction.test.ts +0 -2
- package/tests/A-Feature.test.ts +86 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaas/a-concept",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "A-Concept is a framework of the new generation that is tailored to use AI, enabling developers to create AI-powered applications with ease. It provides a structured approach to building, managing, and deploying AI-driven solutions.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -29,7 +29,7 @@ export class A_Component {
|
|
|
29
29
|
* @param scope - the scope in which to call the feature
|
|
30
30
|
* @returns - void
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
call(
|
|
33
33
|
/**
|
|
34
34
|
* Name of the feature to call
|
|
35
35
|
*/
|
|
@@ -38,13 +38,13 @@ export class A_Component {
|
|
|
38
38
|
* Scope in which the feature will be executed
|
|
39
39
|
*/
|
|
40
40
|
scope?: A_Scope
|
|
41
|
-
) {
|
|
41
|
+
): Promise<any> | void {
|
|
42
42
|
const newFeature = new A_Feature({
|
|
43
43
|
name: feature,
|
|
44
44
|
component: this
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
return
|
|
47
|
+
return newFeature.process(scope);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -355,13 +355,13 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
|
|
|
355
355
|
* This method processes the feature by executing all the stages
|
|
356
356
|
*
|
|
357
357
|
*/
|
|
358
|
-
|
|
358
|
+
process(
|
|
359
359
|
/**
|
|
360
360
|
* Optional scope to be used to resolve the steps dependencies
|
|
361
361
|
* If not provided, the scope of the caller component will be used
|
|
362
362
|
*/
|
|
363
363
|
scope?: A_Scope,
|
|
364
|
-
) {
|
|
364
|
+
): Promise<void> | void {
|
|
365
365
|
try {
|
|
366
366
|
// It seems like this is a bad idea to enforce scope inheritance here
|
|
367
367
|
// ---------------------------------------------------------------
|
|
@@ -373,20 +373,63 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
|
|
|
373
373
|
|
|
374
374
|
this._state = A_TYPES__FeatureState.PROCESSING;
|
|
375
375
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
376
|
+
// Convert iterator to array to get all stages
|
|
377
|
+
const stages = Array.from(this);
|
|
378
|
+
|
|
379
|
+
return this.processStagesSequentially(stages, scope, 0);
|
|
379
380
|
|
|
380
|
-
return await this.completed();
|
|
381
381
|
} catch (error) {
|
|
382
|
-
|
|
382
|
+
this.failed(new A_FeatureError({
|
|
383
383
|
title: A_FeatureError.FeatureProcessingError,
|
|
384
384
|
description: `An error occurred while processing the A-Feature: ${this.name}. Failed at stage: ${this.stage?.name || 'N/A'}.`,
|
|
385
385
|
stage: this.stage,
|
|
386
386
|
originalError: error
|
|
387
387
|
}));
|
|
388
388
|
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Process stages one by one, ensuring each stage completes before starting the next
|
|
393
|
+
*/
|
|
394
|
+
private processStagesSequentially(
|
|
395
|
+
stages: A_Stage[],
|
|
396
|
+
scope: A_Scope | undefined,
|
|
397
|
+
index: number
|
|
398
|
+
): Promise<void> | void {
|
|
399
|
+
try {
|
|
400
|
+
// If we've processed all stages, complete the feature
|
|
401
|
+
if (index >= stages.length) {
|
|
402
|
+
this.completed();
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
389
405
|
|
|
406
|
+
const stage = stages[index];
|
|
407
|
+
const result = stage.process(scope);
|
|
408
|
+
|
|
409
|
+
if (A_TypeGuards.isPromiseInstance(result)) {
|
|
410
|
+
// Async stage - return promise that processes remaining stages
|
|
411
|
+
return result.then(() => {
|
|
412
|
+
return this.processStagesSequentially(stages, scope, index + 1);
|
|
413
|
+
}).catch(error => {
|
|
414
|
+
this.failed(new A_FeatureError({
|
|
415
|
+
title: A_FeatureError.FeatureProcessingError,
|
|
416
|
+
description: `An error occurred while processing the A-Feature: ${this.name}. Failed at stage: ${stage.name}.`,
|
|
417
|
+
stage: stage,
|
|
418
|
+
originalError: error
|
|
419
|
+
}));
|
|
420
|
+
});
|
|
421
|
+
} else {
|
|
422
|
+
// Sync stage - continue to next stage immediately
|
|
423
|
+
return this.processStagesSequentially(stages, scope, index + 1);
|
|
424
|
+
}
|
|
425
|
+
} catch (error) {
|
|
426
|
+
this.failed(new A_FeatureError({
|
|
427
|
+
title: A_FeatureError.FeatureProcessingError,
|
|
428
|
+
description: `An error occurred while processing the A-Feature: ${this.name}. Failed at stage: ${this.stage?.name || 'N/A'}.`,
|
|
429
|
+
stage: this.stage,
|
|
430
|
+
originalError: error
|
|
431
|
+
}));
|
|
432
|
+
}
|
|
390
433
|
}
|
|
391
434
|
/**
|
|
392
435
|
* This method moves the feature to the next stage
|
|
@@ -409,7 +452,7 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
|
|
|
409
452
|
* @param result
|
|
410
453
|
* @returns
|
|
411
454
|
*/
|
|
412
|
-
|
|
455
|
+
completed(): void {
|
|
413
456
|
if (this.isProcessed) return;
|
|
414
457
|
|
|
415
458
|
|
|
@@ -423,7 +466,7 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
|
|
|
423
466
|
*
|
|
424
467
|
* @param error
|
|
425
468
|
*/
|
|
426
|
-
|
|
469
|
+
failed(error: A_FeatureError) {
|
|
427
470
|
if (this.isProcessed) return;
|
|
428
471
|
|
|
429
472
|
this._state = A_TYPES__FeatureState.FAILED;
|
|
@@ -35,11 +35,6 @@ export class A_Stage {
|
|
|
35
35
|
*/
|
|
36
36
|
private _status: A_TYPES__A_Stage_Status = A_TYPES__A_Stage_Status.INITIALIZED;
|
|
37
37
|
|
|
38
|
-
/**
|
|
39
|
-
* Promise that will be resolved when the stage is Processed
|
|
40
|
-
*/
|
|
41
|
-
private _processed: Promise<void> | undefined;
|
|
42
|
-
|
|
43
38
|
|
|
44
39
|
/**
|
|
45
40
|
* A_Stage is a callable A_Function within A_Feature that should be run with specific parameters.
|
|
@@ -106,7 +101,7 @@ export class A_Stage {
|
|
|
106
101
|
* @param step
|
|
107
102
|
* @returns
|
|
108
103
|
*/
|
|
109
|
-
protected
|
|
104
|
+
protected getStepArgs(
|
|
110
105
|
scope: A_Scope,
|
|
111
106
|
step: A_TYPES__A_StageStep
|
|
112
107
|
) {
|
|
@@ -114,24 +109,22 @@ export class A_Stage {
|
|
|
114
109
|
(step.dependency.target as A_TYPES__Container_Constructor | A_TYPES__Component_Constructor)
|
|
115
110
|
|| scope.resolveConstructor(step.dependency.name);
|
|
116
111
|
|
|
117
|
-
return
|
|
118
|
-
.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return this._feature.caller.component;
|
|
112
|
+
return A_Context
|
|
113
|
+
.meta(resolverConstructor)
|
|
114
|
+
.injections(step.handler)
|
|
115
|
+
.map(dependency => {
|
|
116
|
+
switch (true) {
|
|
117
|
+
case A_TypeGuards.isCallerConstructor(dependency.target):
|
|
118
|
+
return this._feature.caller.component;
|
|
125
119
|
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
case A_TypeGuards.isFeatureConstructor(dependency.target):
|
|
121
|
+
return this._feature;
|
|
128
122
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
123
|
+
default: {
|
|
124
|
+
return scope.resolve(dependency);
|
|
132
125
|
}
|
|
133
|
-
}
|
|
134
|
-
)
|
|
126
|
+
}
|
|
127
|
+
})
|
|
135
128
|
}
|
|
136
129
|
|
|
137
130
|
|
|
@@ -174,17 +167,23 @@ export class A_Stage {
|
|
|
174
167
|
* @param step
|
|
175
168
|
* @returns
|
|
176
169
|
*/
|
|
177
|
-
protected
|
|
170
|
+
protected callStepHandler(
|
|
178
171
|
step: A_TYPES__A_StageStep,
|
|
179
172
|
scope: A_Scope
|
|
180
|
-
) {
|
|
173
|
+
): {
|
|
174
|
+
handler: Function,
|
|
175
|
+
params: any[]
|
|
176
|
+
} {
|
|
181
177
|
// 1) Resolve component
|
|
182
|
-
const component =
|
|
178
|
+
const component = this.getStepComponent(scope, step);
|
|
183
179
|
// 2) Resolve arguments
|
|
184
|
-
const callArgs =
|
|
180
|
+
const callArgs = this.getStepArgs(scope, step);
|
|
185
181
|
|
|
186
182
|
// 3) Call handler
|
|
187
|
-
return
|
|
183
|
+
return {
|
|
184
|
+
handler: component[step.handler].bind(component),
|
|
185
|
+
params: callArgs
|
|
186
|
+
}
|
|
188
187
|
}
|
|
189
188
|
|
|
190
189
|
|
|
@@ -198,48 +197,51 @@ export class A_Stage {
|
|
|
198
197
|
*
|
|
199
198
|
* @param scope - Scope to be used to resolve the steps dependencies
|
|
200
199
|
*/
|
|
201
|
-
|
|
200
|
+
process(
|
|
202
201
|
/**
|
|
203
202
|
* Scope to be used to resolve the steps dependencies
|
|
204
203
|
*/
|
|
205
204
|
scope?: A_Scope,
|
|
206
|
-
): Promise<void> {
|
|
205
|
+
): Promise<void> | void {
|
|
207
206
|
|
|
208
207
|
const targetScope = A_TypeGuards.isScopeInstance(scope)
|
|
209
208
|
? scope
|
|
210
209
|
: this._feature.scope;
|
|
211
210
|
|
|
212
|
-
if (!this.
|
|
213
|
-
this.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
this._status = A_TYPES__A_Stage_Status.PROCESSING;
|
|
217
|
-
|
|
218
|
-
if (this._definition.behavior === 'sync') {
|
|
219
|
-
// in case we have to wait for the result
|
|
220
|
-
await this.callStepHandler(this._definition, targetScope);
|
|
221
|
-
} else {
|
|
222
|
-
// in case we don't have to wait for the result
|
|
223
|
-
this.callStepHandler(this._definition, targetScope);
|
|
224
|
-
}
|
|
211
|
+
if (!this.isProcessed) {
|
|
212
|
+
this._status = A_TYPES__A_Stage_Status.PROCESSING;
|
|
213
|
+
|
|
214
|
+
const { handler, params } = this.callStepHandler(this._definition, targetScope);
|
|
225
215
|
|
|
226
|
-
|
|
216
|
+
const result = handler(...params);
|
|
227
217
|
|
|
228
|
-
|
|
229
|
-
} catch (error) {
|
|
230
|
-
const wrappedError = new A_Error(error as any);
|
|
218
|
+
if (A_TypeGuards.isPromiseInstance(result)) {
|
|
231
219
|
|
|
232
|
-
|
|
220
|
+
return new Promise<void>(
|
|
221
|
+
async (resolve, reject) => {
|
|
222
|
+
try {
|
|
223
|
+
await result;
|
|
224
|
+
|
|
225
|
+
this.completed();
|
|
233
226
|
|
|
234
|
-
if (this._definition.throwOnError) {
|
|
235
227
|
return resolve();
|
|
236
|
-
}
|
|
237
|
-
|
|
228
|
+
} catch (error) {
|
|
229
|
+
const wrappedError = new A_Error(error as any);
|
|
230
|
+
|
|
231
|
+
this.failed(wrappedError);
|
|
232
|
+
|
|
233
|
+
if (this._definition.throwOnError) {
|
|
234
|
+
return resolve();
|
|
235
|
+
} else {
|
|
236
|
+
return reject(wrappedError);
|
|
237
|
+
}
|
|
238
238
|
}
|
|
239
|
-
}
|
|
240
|
-
|
|
239
|
+
});
|
|
240
|
+
} else {
|
|
241
|
+
this.completed();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
241
244
|
|
|
242
|
-
return this._processed;
|
|
243
245
|
}
|
|
244
246
|
|
|
245
247
|
|
|
@@ -367,4 +367,9 @@ export class A_TypeGuards {
|
|
|
367
367
|
static isErrorSerializedType<T extends A_TYPES__Error_Serialized>(param: any): param is T {
|
|
368
368
|
return !!param && A_TypeGuards.isObject(param) && !(param instanceof Error) && "aseid" in param && ASEID.isASEID(param.aseid);
|
|
369
369
|
}
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
static isPromiseInstance<T>(value: any): value is Promise<T> {
|
|
373
|
+
return value instanceof Promise;
|
|
374
|
+
}
|
|
370
375
|
}
|
package/tests/A-Feature.test.ts
CHANGED
|
@@ -644,7 +644,7 @@ describe('A-Feature tests', () => {
|
|
|
644
644
|
await baseEntity.test();
|
|
645
645
|
|
|
646
646
|
expect(executionResults).toEqual(['testMethod']);
|
|
647
|
-
|
|
647
|
+
|
|
648
648
|
await myEntity.test();
|
|
649
649
|
|
|
650
650
|
expect(executionResults).toEqual(['testMethod', 'testMethod']);
|
|
@@ -783,4 +783,89 @@ describe('A-Feature tests', () => {
|
|
|
783
783
|
]);
|
|
784
784
|
|
|
785
785
|
})
|
|
786
|
+
it('Should execute Sync operations properly', async () => {
|
|
787
|
+
|
|
788
|
+
const resultChain: string[] = [];
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
class ChildComponent_A extends A_Component {
|
|
792
|
+
@A_Feature.Extend({
|
|
793
|
+
name: 'testFeature',
|
|
794
|
+
})
|
|
795
|
+
test1() {
|
|
796
|
+
resultChain.push('ChildComponent_A.test');
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
class ChildComponent_B extends A_Component {
|
|
801
|
+
@A_Feature.Extend({
|
|
802
|
+
name: 'testFeature',
|
|
803
|
+
})
|
|
804
|
+
test2() {
|
|
805
|
+
resultChain.push('ChildComponent_B.test');
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
const testScope = new A_Scope({ name: 'TestScope', components: [ChildComponent_A, ChildComponent_B] });
|
|
811
|
+
|
|
812
|
+
testScope.resolve(ChildComponent_A)!.call('testFeature');
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
expect(resultChain).toEqual([
|
|
816
|
+
'ChildComponent_A.test',
|
|
817
|
+
'ChildComponent_B.test'
|
|
818
|
+
]);
|
|
819
|
+
|
|
820
|
+
})
|
|
821
|
+
|
|
822
|
+
it('Should execute Async operations properly', async () => {
|
|
823
|
+
|
|
824
|
+
const resultChain: string[] = [];
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
class ChildComponent_A extends A_Component {
|
|
828
|
+
@A_Feature.Extend({
|
|
829
|
+
name: 'testFeature',
|
|
830
|
+
})
|
|
831
|
+
async test1() {
|
|
832
|
+
resultChain.push('ChildComponent_A.test');
|
|
833
|
+
|
|
834
|
+
await new Promise<void>(async (resolve) => {
|
|
835
|
+
setTimeout(() => {
|
|
836
|
+
resolve();
|
|
837
|
+
}, 3000);
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
class ChildComponent_B extends A_Component {
|
|
843
|
+
@A_Feature.Extend({
|
|
844
|
+
name: 'testFeature',
|
|
845
|
+
})
|
|
846
|
+
async test2() {
|
|
847
|
+
resultChain.push('ChildComponent_B.test');
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
const testScope = new A_Scope({ name: 'TestScope', components: [ChildComponent_A, ChildComponent_B] });
|
|
852
|
+
|
|
853
|
+
await Promise.all([
|
|
854
|
+
new Promise<void>(async (resolve) => {
|
|
855
|
+
setTimeout(() => {
|
|
856
|
+
resultChain.push('feature3');
|
|
857
|
+
|
|
858
|
+
resolve();
|
|
859
|
+
}, 2000);
|
|
860
|
+
}),
|
|
861
|
+
testScope.resolve(ChildComponent_A)!.call('testFeature')
|
|
862
|
+
]);
|
|
863
|
+
|
|
864
|
+
expect(resultChain).toEqual([
|
|
865
|
+
'ChildComponent_A.test',
|
|
866
|
+
'feature3',
|
|
867
|
+
'ChildComponent_B.test'
|
|
868
|
+
]);
|
|
869
|
+
|
|
870
|
+
})
|
|
786
871
|
});
|