@adaas/a-concept 0.3.7 → 0.3.8
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/benchmarks/feature-chaining.bench.ts +465 -0
- package/benchmarks/feature-optimize.bench.ts +205 -0
- package/dist/browser/index.d.mts +2 -1
- package/dist/browser/index.mjs +2 -2
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/index.cjs +35 -34
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.mts +2 -1
- package/dist/node/index.d.ts +2 -1
- package/dist/node/index.mjs +35 -34
- package/dist/node/index.mjs.map +1 -1
- package/package.json +3 -1
- package/src/lib/A-Entity/A-Entity.class.ts +3 -3
- package/src/lib/A-Feature/A-Feature.class.ts +46 -41
- package/tests/A-Feature.test.ts +101 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaas/a-concept",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
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
|
"author": {
|
|
@@ -58,6 +58,8 @@
|
|
|
58
58
|
"bench": "ts-node -r tsconfig-paths/register benchmarks/run-all.ts",
|
|
59
59
|
"bench:step-manager": "ts-node -r tsconfig-paths/register benchmarks/step-manager.bench.ts",
|
|
60
60
|
"bench:feature-template": "ts-node -r tsconfig-paths/register benchmarks/feature-template.bench.ts",
|
|
61
|
+
"bench:feature-optimize": "ts-node -r tsconfig-paths/register benchmarks/feature-optimize.bench.ts",
|
|
62
|
+
"bench:feature-chaining": "ts-node -r tsconfig-paths/register benchmarks/feature-chaining.bench.ts",
|
|
61
63
|
"bench:scope-resolve": "ts-node -r tsconfig-paths/register benchmarks/scope-resolve.bench.ts",
|
|
62
64
|
"bench:feature-lifecycle": "ts-node -r tsconfig-paths/register benchmarks/feature-lifecycle.bench.ts",
|
|
63
65
|
"start": "nodemon ./tests/example-usage.ts",
|
|
@@ -269,17 +269,17 @@ export class A_Entity<
|
|
|
269
269
|
* @param lifecycleMethod
|
|
270
270
|
* @param args
|
|
271
271
|
*/
|
|
272
|
-
|
|
272
|
+
call(
|
|
273
273
|
feature: string,
|
|
274
274
|
scope?: A_Scope
|
|
275
|
-
) {
|
|
275
|
+
): Promise<any> | void {
|
|
276
276
|
const newFeature = new A_Feature({
|
|
277
277
|
name: feature,
|
|
278
278
|
component: this,
|
|
279
279
|
scope
|
|
280
280
|
});
|
|
281
281
|
|
|
282
|
-
return
|
|
282
|
+
return newFeature.process(scope);
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
A_StageError
|
|
13
13
|
} from "@adaas/a-concept/a-stage";
|
|
14
14
|
import { A_StepsManager } from "@adaas/a-concept/a-step-manager";
|
|
15
|
-
import { A_TypeGuards} from "@adaas/a-concept/helpers/A_TypeGuards.helper";
|
|
15
|
+
import { A_TypeGuards } from "@adaas/a-concept/helpers/A_TypeGuards.helper";
|
|
16
16
|
import { A_FeatureError } from "./A-Feature.error";
|
|
17
17
|
import { A_Context } from "@adaas/a-concept/a-context";
|
|
18
18
|
import { A_Caller } from "@adaas/a-concept/a-caller";
|
|
@@ -203,7 +203,7 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
|
|
|
203
203
|
if (!params || typeof params !== 'object') {
|
|
204
204
|
throw new A_FeatureError(
|
|
205
205
|
A_FeatureError.FeatureInitializationError,
|
|
206
|
-
`Invalid A-Feature initialization parameters of type: ${typeof params} with value: ${JSON.stringify(params)
|
|
206
|
+
`Invalid A-Feature initialization parameters of type: ${typeof params} with value: ${JSON.stringify(params)?.slice(0, 100)}...`
|
|
207
207
|
);
|
|
208
208
|
}
|
|
209
209
|
}
|
|
@@ -226,7 +226,7 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
|
|
|
226
226
|
default:
|
|
227
227
|
throw new A_FeatureError(
|
|
228
228
|
A_FeatureError.FeatureInitializationError,
|
|
229
|
-
`Invalid A-Feature initialization parameters of type: ${typeof params} with value: ${JSON.stringify(params)
|
|
229
|
+
`Invalid A-Feature initialization parameters of type: ${typeof params} with value: ${JSON.stringify(params)?.slice(0, 100)}...`
|
|
230
230
|
);
|
|
231
231
|
}
|
|
232
232
|
}
|
|
@@ -241,14 +241,14 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
|
|
|
241
241
|
if (!params.template || !Array.isArray(params.template)) {
|
|
242
242
|
throw new A_FeatureError(
|
|
243
243
|
A_FeatureError.FeatureInitializationError,
|
|
244
|
-
`Invalid A-Feature template provided of type: ${typeof params.template} with value: ${JSON.stringify(params.template)
|
|
244
|
+
`Invalid A-Feature template provided of type: ${typeof params.template} with value: ${JSON.stringify(params.template)?.slice(0, 100)}...`
|
|
245
245
|
);
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
if (!params.component && (!params.scope || !(params.scope instanceof A_Scope))) {
|
|
249
249
|
throw new A_FeatureError(
|
|
250
250
|
A_FeatureError.FeatureInitializationError,
|
|
251
|
-
`Invalid A-Feature scope provided of type: ${typeof params.scope} with value: ${JSON.stringify(params.scope)
|
|
251
|
+
`Invalid A-Feature scope provided of type: ${typeof params.scope} with value: ${JSON.stringify(params.scope)?.slice(0, 100)}...`
|
|
252
252
|
);
|
|
253
253
|
}
|
|
254
254
|
|
|
@@ -304,7 +304,7 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
|
|
|
304
304
|
if (!params.component || !A_TypeGuards.isAllowedForFeatureDefinition(params.component)) {
|
|
305
305
|
throw new A_FeatureError(
|
|
306
306
|
A_FeatureError.FeatureInitializationError,
|
|
307
|
-
`Invalid A-Feature component provided of type: ${typeof params.component} with value: ${JSON.stringify(params.component)
|
|
307
|
+
`Invalid A-Feature component provided of type: ${typeof params.component} with value: ${JSON.stringify(params.component)?.slice(0, 100)}...`
|
|
308
308
|
);
|
|
309
309
|
}
|
|
310
310
|
|
|
@@ -398,52 +398,57 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
|
|
|
398
398
|
scope: A_Scope | undefined,
|
|
399
399
|
index: number
|
|
400
400
|
): Promise<void> | void {
|
|
401
|
-
try {
|
|
402
|
-
// Check if feature has been interrupted before processing next stage
|
|
403
|
-
if (this.state === A_TYPES__FeatureState.INTERRUPTED) {
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
401
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
}
|
|
402
|
+
// ── Sync loop — avoids stack overflow for all-sync chains ────────────────
|
|
403
|
+
while (index < stages.length) {
|
|
404
|
+
|
|
405
|
+
if (this.state === A_TYPES__FeatureState.INTERRUPTED) return
|
|
412
406
|
|
|
413
|
-
const stage = stages[index]
|
|
414
|
-
|
|
407
|
+
const stage = stages[index]
|
|
408
|
+
let result: Promise<void> | void
|
|
415
409
|
|
|
410
|
+
try {
|
|
411
|
+
result = stage.process(scope)
|
|
412
|
+
} catch (error) {
|
|
413
|
+
throw this.createStageError(error, stage)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// ── Async stage — hand off to promise chain ───────────────────────────
|
|
416
417
|
if (A_TypeGuards.isPromiseInstance(result)) {
|
|
417
|
-
// Async stage - return promise that processes remaining stages
|
|
418
418
|
return result
|
|
419
419
|
.then(() => {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
return this.processStagesSequentially(stages, scope, index + 1);
|
|
420
|
+
if (this.state === A_TYPES__FeatureState.INTERRUPTED) return
|
|
421
|
+
return this.processStagesSequentially(stages, scope, index + 1)
|
|
425
422
|
})
|
|
426
423
|
.catch(error => {
|
|
427
|
-
throw this.
|
|
428
|
-
|
|
429
|
-
description: `An error occurred while processing the A-Feature: ${this.name}. Failed at stage: ${stage.name}.`,
|
|
430
|
-
stage: stage,
|
|
431
|
-
originalError: error
|
|
432
|
-
}));
|
|
433
|
-
});
|
|
434
|
-
} else {
|
|
435
|
-
// Sync stage - continue to next stage immediately
|
|
436
|
-
return this.processStagesSequentially(stages, scope, index + 1);
|
|
424
|
+
throw this.createStageError(error, stage)
|
|
425
|
+
})
|
|
437
426
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
427
|
+
|
|
428
|
+
index++
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ── All stages complete ───────────────────────────────────────────────────
|
|
432
|
+
if (this.state !== A_TYPES__FeatureState.INTERRUPTED) {
|
|
433
|
+
this.completed()
|
|
445
434
|
}
|
|
446
435
|
}
|
|
436
|
+
|
|
437
|
+
private createStageError(error: unknown, stage: A_Stage): A_FeatureError {
|
|
438
|
+
this.failed(new A_FeatureError({
|
|
439
|
+
title: A_FeatureError.FeatureProcessingError,
|
|
440
|
+
description: `An error occurred while processing the A-Feature: ${this.name}. Failed at stage: ${stage.name}.`,
|
|
441
|
+
stage,
|
|
442
|
+
originalError: error,
|
|
443
|
+
}))
|
|
444
|
+
|
|
445
|
+
return new A_FeatureError({
|
|
446
|
+
title: A_FeatureError.FeatureProcessingError,
|
|
447
|
+
description: `An error occurred while processing the A-Feature: ${this.name}. Failed at stage: ${stage.name}.`,
|
|
448
|
+
stage,
|
|
449
|
+
originalError: error,
|
|
450
|
+
})
|
|
451
|
+
}
|
|
447
452
|
/**
|
|
448
453
|
* This method moves the feature to the next stage
|
|
449
454
|
*
|
package/tests/A-Feature.test.ts
CHANGED
|
@@ -1103,6 +1103,107 @@ describe('A-Feature tests', () => {
|
|
|
1103
1103
|
'ComponentA.feature1'
|
|
1104
1104
|
]);
|
|
1105
1105
|
})
|
|
1106
|
+
it('Should return promise if at least one step is async', async () => {
|
|
1107
|
+
|
|
1108
|
+
const resultChain: string[] = [];
|
|
1109
|
+
|
|
1110
|
+
class ComponentA extends A_Component {
|
|
1111
|
+
@A_Feature.Extend({
|
|
1112
|
+
name: 'testFeature',
|
|
1113
|
+
})
|
|
1114
|
+
async step1() {
|
|
1115
|
+
resultChain.push('ComponentA.step1');
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
@A_Feature.Extend({
|
|
1119
|
+
name: 'testFeature',
|
|
1120
|
+
})
|
|
1121
|
+
step2() {
|
|
1122
|
+
resultChain.push('ComponentA.step2');
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
class MyEntity extends A_Entity {
|
|
1128
|
+
async test() {
|
|
1129
|
+
return await this.call('testFeature');
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
const testScope = new A_Scope({ name: 'TestScope', components: [ComponentA] });
|
|
1135
|
+
|
|
1136
|
+
const component = testScope.resolve(ComponentA)!;
|
|
1137
|
+
|
|
1138
|
+
const myEntity = new MyEntity();
|
|
1139
|
+
|
|
1140
|
+
testScope.register(myEntity);
|
|
1141
|
+
|
|
1142
|
+
const res = component.call('testFeature');
|
|
1143
|
+
const res2 = myEntity.test();
|
|
1144
|
+
|
|
1145
|
+
expect(res).toBeInstanceOf(Promise);
|
|
1146
|
+
expect(res2).toBeInstanceOf(Promise);
|
|
1147
|
+
|
|
1148
|
+
await res;
|
|
1149
|
+
await res2;
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
expect(resultChain).toEqual([
|
|
1153
|
+
'ComponentA.step1',
|
|
1154
|
+
'ComponentA.step1',
|
|
1155
|
+
'ComponentA.step2',
|
|
1156
|
+
'ComponentA.step2'
|
|
1157
|
+
]);
|
|
1158
|
+
})
|
|
1159
|
+
it('Should execute sync if all steps are synchronous', async () => {
|
|
1160
|
+
|
|
1161
|
+
const resultChain: string[] = [];
|
|
1162
|
+
|
|
1163
|
+
class ComponentA extends A_Component {
|
|
1164
|
+
@A_Feature.Extend({
|
|
1165
|
+
name: 'testFeature',
|
|
1166
|
+
})
|
|
1167
|
+
step1() {
|
|
1168
|
+
resultChain.push('ComponentA.step1');
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
@A_Feature.Extend({
|
|
1172
|
+
name: 'testFeature',
|
|
1173
|
+
})
|
|
1174
|
+
step2() {
|
|
1175
|
+
resultChain.push('ComponentA.step2');
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
class MyEntity extends A_Entity {
|
|
1181
|
+
test() {
|
|
1182
|
+
return this.call('testFeature');
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
const testScope = new A_Scope({ name: 'TestScope', components: [ComponentA] });
|
|
1187
|
+
|
|
1188
|
+
const component = testScope.resolve(ComponentA)!;
|
|
1189
|
+
|
|
1190
|
+
const myEntity = new MyEntity();
|
|
1191
|
+
|
|
1192
|
+
testScope.register(myEntity);
|
|
1193
|
+
|
|
1194
|
+
const res = component.call('testFeature');
|
|
1195
|
+
const res2 = myEntity.test();
|
|
1196
|
+
|
|
1197
|
+
expect(res).not.toBeInstanceOf(Promise);
|
|
1198
|
+
expect(res2).not.toBeInstanceOf(Promise);
|
|
1199
|
+
|
|
1200
|
+
expect(resultChain).toEqual([
|
|
1201
|
+
'ComponentA.step1',
|
|
1202
|
+
'ComponentA.step2',
|
|
1203
|
+
'ComponentA.step1',
|
|
1204
|
+
'ComponentA.step2'
|
|
1205
|
+
]);
|
|
1206
|
+
})
|
|
1106
1207
|
|
|
1107
1208
|
|
|
1108
1209
|
});
|