@adaas/a-concept 0.1.18 → 0.1.19
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.d.ts +2 -0
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/src/global/A-Abstraction/A-Abstraction-Extend.decorator.js +11 -4
- package/dist/src/global/A-Abstraction/A-Abstraction-Extend.decorator.js.map +1 -1
- package/dist/src/global/A-Component/A-Component.meta.js +2 -1
- package/dist/src/global/A-Component/A-Component.meta.js.map +1 -1
- package/dist/src/global/A-Component/A-Component.types.d.ts +2 -11
- package/dist/src/global/A-Concept/A-Concept.types.d.ts +4 -21
- package/dist/src/global/A-Container/A-Container.meta.js +4 -2
- package/dist/src/global/A-Container/A-Container.meta.js.map +1 -1
- package/dist/src/global/A-Container/A-Container.types.d.ts +2 -11
- package/dist/src/global/A-Feature/A-Feature-Define.decorator.js +1 -1
- package/dist/src/global/A-Feature/A-Feature-Define.decorator.js.map +1 -1
- package/dist/src/global/A-Feature/A-Feature-Extend.decorator.js +14 -5
- package/dist/src/global/A-Feature/A-Feature-Extend.decorator.js.map +1 -1
- package/dist/src/global/A-Feature/A-Feature.class.d.ts +2 -1
- package/dist/src/global/A-Feature/A-Feature.class.js +7 -3
- package/dist/src/global/A-Feature/A-Feature.class.js.map +1 -1
- package/dist/src/global/A-Feature/A-Feature.types.d.ts +69 -27
- package/dist/src/global/A-Stage/A-Stage.class.d.ts +37 -28
- package/dist/src/global/A-Stage/A-Stage.class.js +62 -98
- package/dist/src/global/A-Stage/A-Stage.class.js.map +1 -1
- package/dist/src/global/A-Stage/A-Stage.types.d.ts +30 -3
- package/dist/src/global/A-Stage/A-Stage.types.js.map +1 -1
- package/dist/src/global/A-StepManager/A-StepManager.class.d.ts +20 -0
- package/dist/src/{helpers/A_StepsManager.class.js → global/A-StepManager/A-StepManager.class.js} +38 -64
- package/dist/src/global/A-StepManager/A-StepManager.class.js.map +1 -0
- package/dist/src/global/A-StepManager/A-StepManager.error.d.ts +4 -0
- package/dist/src/global/A-StepManager/A-StepManager.error.js +9 -0
- package/dist/src/global/A-StepManager/A-StepManager.error.js.map +1 -0
- package/index.ts +2 -1
- package/package.json +3 -3
- package/src/global/A-Abstraction/A-Abstraction-Extend.decorator.ts +18 -6
- package/src/global/A-Component/A-Component.meta.ts +2 -1
- package/src/global/A-Component/A-Component.types.ts +2 -11
- package/src/global/A-Concept/A-Concept.types.ts +4 -21
- package/src/global/A-Container/A-Container.meta.ts +4 -2
- package/src/global/A-Container/A-Container.types.ts +2 -11
- package/src/global/A-Feature/A-Feature-Define.decorator.ts +1 -0
- package/src/global/A-Feature/A-Feature-Extend.decorator.ts +21 -7
- package/src/global/A-Feature/A-Feature.class.ts +8 -1
- package/src/global/A-Feature/A-Feature.types.ts +80 -33
- package/src/global/A-Stage/A-Stage.class.ts +71 -143
- package/src/global/A-Stage/A-Stage.types.ts +34 -3
- package/src/{helpers/A_StepsManager.class.ts → global/A-StepManager/A-StepManager.class.ts} +53 -87
- package/src/global/A-StepManager/A-StepManager.error.ts +10 -0
- package/tests/A-Abstraction.test.ts +273 -255
- package/tests/A-Feature.test.ts +270 -271
- package/tests/A-StepManager.test.ts +346 -0
- package/dist/src/helpers/A_StepsManager.class.d.ts +0 -35
- package/dist/src/helpers/A_StepsManager.class.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
A_TYPES__A_StageStep,
|
|
2
|
+
A_TYPES__A_Stage_Status,
|
|
3
|
+
A_TYPES__A_StageStep,
|
|
4
|
+
A_TYPES__Stage_Serialized
|
|
4
5
|
} from "./A-Stage.types";
|
|
5
6
|
import { A_Context } from "../A-Context/A-Context.class";
|
|
6
7
|
import { A_Feature } from "../A-Feature/A-Feature.class";
|
|
@@ -16,64 +17,60 @@ import { A_TYPES__Component_Constructor } from "../A-Component/A-Component.types
|
|
|
16
17
|
|
|
17
18
|
export class A_Stage {
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* The feature that owns this stage
|
|
22
|
+
*/
|
|
19
23
|
private readonly _feature!: A_Feature;
|
|
20
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Initial Instructions to process the stage
|
|
26
|
+
*/
|
|
27
|
+
private readonly _definition!: A_TYPES__A_StageStep;
|
|
28
|
+
/**
|
|
29
|
+
* Possible errors during stage processing
|
|
30
|
+
*/
|
|
21
31
|
private _error?: Error | A_Error | any;
|
|
32
|
+
/**
|
|
33
|
+
* Indicates the current status of the stage
|
|
34
|
+
*/
|
|
35
|
+
private _status: A_TYPES__A_Stage_Status = A_TYPES__A_Stage_Status.INITIALIZED;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Promise that will be resolved when the stage is Processed
|
|
39
|
+
*/
|
|
40
|
+
private _processed: Promise<void> | undefined;
|
|
22
41
|
|
|
23
42
|
|
|
24
43
|
/**
|
|
25
|
-
* A_Stage is a
|
|
26
|
-
*
|
|
27
|
-
* [!] That always run in parallel (in NodeJS asynchronously), independently of each other.
|
|
44
|
+
* A_Stage is a callable A_Function within A_Feature that should be run with specific parameters.
|
|
45
|
+
* [!] Depending on the Stage Definition type sync/async function can be executed correspondingly.
|
|
28
46
|
*
|
|
29
47
|
* A-Stage is a common object that uses to simplify logic and re-use of A-Feature internals for better composition.
|
|
30
48
|
*/
|
|
31
49
|
constructor(
|
|
50
|
+
/**
|
|
51
|
+
* The feature that owns this stage
|
|
52
|
+
*/
|
|
32
53
|
feature: A_Feature,
|
|
33
|
-
|
|
54
|
+
/**
|
|
55
|
+
* The step definitions of the stage
|
|
56
|
+
*/
|
|
57
|
+
step: A_TYPES__A_StageStep
|
|
34
58
|
) {
|
|
35
59
|
this._feature = feature;
|
|
36
|
-
this.
|
|
60
|
+
this._definition = step;
|
|
37
61
|
}
|
|
38
62
|
|
|
39
|
-
status: A_TYPES__A_Stage_Status = A_TYPES__A_Stage_Status.INITIALIZED;
|
|
40
|
-
|
|
41
63
|
/**
|
|
42
|
-
*
|
|
64
|
+
* Returns the name of the stage
|
|
43
65
|
*/
|
|
44
|
-
processed: Promise<void> | undefined;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
66
|
get name(): string {
|
|
50
67
|
return this.toString();
|
|
51
68
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
]), [] as string[]);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
get after(): string[] {
|
|
61
|
-
return this._steps.reduce((acc, step) => ([
|
|
62
|
-
...acc,
|
|
63
|
-
...step.after
|
|
64
|
-
]), [] as string[]);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
get steps(): A_TYPES__A_StageStep[] {
|
|
68
|
-
return this._steps;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
get asyncSteps(): A_TYPES__A_StageStep[] {
|
|
72
|
-
return this._steps.filter(step => step.behavior === 'async');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
get syncSteps(): A_TYPES__A_StageStep[] {
|
|
76
|
-
return this._steps.filter(step => step.behavior === 'sync');
|
|
69
|
+
/**
|
|
70
|
+
* Returns the current status of the stage
|
|
71
|
+
*/
|
|
72
|
+
get status(): A_TYPES__A_Stage_Status {
|
|
73
|
+
return this._status;
|
|
77
74
|
}
|
|
78
75
|
|
|
79
76
|
|
|
@@ -130,28 +127,13 @@ export class A_Stage {
|
|
|
130
127
|
}
|
|
131
128
|
|
|
132
129
|
|
|
133
|
-
/**
|
|
134
|
-
* Adds a step to the stage
|
|
135
|
-
*
|
|
136
|
-
* @param step
|
|
137
|
-
* @returns
|
|
138
|
-
*/
|
|
139
|
-
add(
|
|
140
|
-
step: A_TYPES__A_StageStep
|
|
141
|
-
): this {
|
|
142
|
-
this._steps.push(step);
|
|
143
|
-
|
|
144
|
-
return this;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
130
|
/**
|
|
149
131
|
* Resolves the component of the step
|
|
150
132
|
*
|
|
151
133
|
* @param step
|
|
152
134
|
* @returns
|
|
153
135
|
*/
|
|
154
|
-
protected
|
|
136
|
+
protected getStepComponent(
|
|
155
137
|
scope: A_Scope,
|
|
156
138
|
step: A_TYPES__A_StageStep
|
|
157
139
|
) {
|
|
@@ -194,15 +176,18 @@ export class A_Stage {
|
|
|
194
176
|
step: A_TYPES__A_StageStep,
|
|
195
177
|
scope: A_Scope
|
|
196
178
|
) {
|
|
197
|
-
|
|
179
|
+
// 1) Resolve component
|
|
180
|
+
const component = await this.getStepComponent(scope, step);
|
|
181
|
+
// 2) Resolve arguments
|
|
198
182
|
const callArgs = await this.getStepArgs(scope, step);
|
|
199
183
|
|
|
200
|
-
|
|
184
|
+
// 3) Call handler
|
|
185
|
+
return await component[step.handler](...callArgs);
|
|
201
186
|
}
|
|
202
187
|
|
|
203
188
|
|
|
204
189
|
skip() {
|
|
205
|
-
this.
|
|
190
|
+
this._status = A_TYPES__A_Stage_Status.SKIPPED;
|
|
206
191
|
}
|
|
207
192
|
|
|
208
193
|
|
|
@@ -216,86 +201,44 @@ export class A_Stage {
|
|
|
216
201
|
* Scope to be used to resolve the steps dependencies
|
|
217
202
|
*/
|
|
218
203
|
scope?: A_Scope,
|
|
219
|
-
): Promise<void>
|
|
220
|
-
async process(
|
|
221
|
-
/**
|
|
222
|
-
* Extra parameters to control the steps processing
|
|
223
|
-
*/
|
|
224
|
-
params?: Partial<A_TYPES__A_StageStepProcessingExtraParams>
|
|
225
|
-
): Promise<void>
|
|
226
|
-
async process(
|
|
227
|
-
/**
|
|
228
|
-
* Scope to be used to resolve the steps dependencies
|
|
229
|
-
*/
|
|
230
|
-
param1?: A_Scope | Partial<A_TYPES__A_StageStepProcessingExtraParams>,
|
|
231
|
-
/**
|
|
232
|
-
* Extra parameters to control the steps processing
|
|
233
|
-
*/
|
|
234
|
-
param2?: Partial<A_TYPES__A_StageStepProcessingExtraParams>
|
|
235
204
|
): Promise<void> {
|
|
236
205
|
|
|
237
|
-
const
|
|
238
|
-
?
|
|
206
|
+
const targetScope = A_TypeGuards.isScopeInstance(scope)
|
|
207
|
+
? scope
|
|
239
208
|
: A_Context.scope(this._feature);
|
|
240
209
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
: param1;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (!this.processed)
|
|
247
|
-
this.processed = new Promise<void>(
|
|
210
|
+
if (!this._processed)
|
|
211
|
+
this._processed = new Promise<void>(
|
|
248
212
|
async (resolve, reject) => {
|
|
249
213
|
try {
|
|
250
|
-
this.
|
|
251
|
-
|
|
252
|
-
if (
|
|
253
|
-
|
|
214
|
+
this._status = A_TYPES__A_Stage_Status.PROCESSING;
|
|
215
|
+
|
|
216
|
+
if (this._definition.behavior === 'sync') {
|
|
217
|
+
// in case we have to wait for the result
|
|
218
|
+
await this.callStepHandler(this._definition, targetScope);
|
|
219
|
+
} else {
|
|
220
|
+
// in case we don't have to wait for the result
|
|
221
|
+
this.callStepHandler(this._definition, targetScope);
|
|
254
222
|
}
|
|
255
223
|
|
|
256
|
-
const syncSteps = this.syncSteps.filter(params?.filter || (() => true));
|
|
257
|
-
const asyncSteps = this.asyncSteps.filter(params?.filter || (() => true));
|
|
258
|
-
|
|
259
|
-
// Run sync _steps
|
|
260
|
-
await Promise
|
|
261
|
-
.all([
|
|
262
|
-
|
|
263
|
-
// Run async _steps that are independent of each other
|
|
264
|
-
...asyncSteps.map(step => this.callStepHandler(step, scope)),
|
|
265
|
-
|
|
266
|
-
// Run sync _steps that are dependent on each other
|
|
267
|
-
new Promise<void>(
|
|
268
|
-
async (r, j) => {
|
|
269
|
-
try {
|
|
270
|
-
for (const step of syncSteps) {
|
|
271
|
-
// console.log(' - -> Processing stage step:', step.handler, ' with Regexp: ', step.name);
|
|
272
|
-
|
|
273
|
-
await this.callStepHandler(step, scope);
|
|
274
|
-
|
|
275
|
-
// console.log(' - -> Finished processing stage step:', step.handler);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return r();
|
|
279
|
-
} catch (error) {
|
|
280
|
-
|
|
281
|
-
return j(error);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
)
|
|
285
|
-
]);
|
|
286
|
-
|
|
287
224
|
this.completed();
|
|
288
225
|
|
|
289
226
|
return resolve();
|
|
290
227
|
} catch (error) {
|
|
291
|
-
|
|
228
|
+
const wrappedError = new A_Error(error as any);
|
|
292
229
|
|
|
293
|
-
|
|
230
|
+
this.failed(wrappedError);
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
if (this._definition.throwOnError) {
|
|
234
|
+
return resolve();
|
|
235
|
+
} else {
|
|
236
|
+
return reject(wrappedError);
|
|
237
|
+
}
|
|
294
238
|
}
|
|
295
239
|
});
|
|
296
240
|
|
|
297
|
-
|
|
298
|
-
return this.processed;
|
|
241
|
+
return this._processed;
|
|
299
242
|
}
|
|
300
243
|
|
|
301
244
|
|
|
@@ -304,7 +247,7 @@ export class A_Stage {
|
|
|
304
247
|
// ==========================================
|
|
305
248
|
|
|
306
249
|
protected completed() {
|
|
307
|
-
this.
|
|
250
|
+
this._status = A_TYPES__A_Stage_Status.COMPLETED;
|
|
308
251
|
}
|
|
309
252
|
|
|
310
253
|
protected failed(
|
|
@@ -312,7 +255,7 @@ export class A_Stage {
|
|
|
312
255
|
) {
|
|
313
256
|
this._error = error;
|
|
314
257
|
|
|
315
|
-
this.
|
|
258
|
+
this._status = A_TYPES__A_Stage_Status.FAILED;
|
|
316
259
|
}
|
|
317
260
|
|
|
318
261
|
|
|
@@ -324,7 +267,7 @@ export class A_Stage {
|
|
|
324
267
|
* Serializes the stage to JSON
|
|
325
268
|
*
|
|
326
269
|
*/
|
|
327
|
-
toJSON():
|
|
270
|
+
toJSON(): A_TYPES__Stage_Serialized {
|
|
328
271
|
return {
|
|
329
272
|
name: this.name,
|
|
330
273
|
status: this.status,
|
|
@@ -337,21 +280,6 @@ export class A_Stage {
|
|
|
337
280
|
* @returns
|
|
338
281
|
*/
|
|
339
282
|
toString() {
|
|
340
|
-
return
|
|
341
|
-
this._feature.name,
|
|
342
|
-
'::a-stage:',
|
|
343
|
-
'[sync:',
|
|
344
|
-
this
|
|
345
|
-
.syncSteps
|
|
346
|
-
.map(s => typeof s.component === 'string' ? s.component : s.component.name + '.' + s.handler)
|
|
347
|
-
.join(' -> '),
|
|
348
|
-
']',
|
|
349
|
-
'[async:',
|
|
350
|
-
this
|
|
351
|
-
.asyncSteps
|
|
352
|
-
.map(s => typeof s.component === 'string' ? s.component : s.component.name + '.' + s.handler)
|
|
353
|
-
.join(' -> '),
|
|
354
|
-
']'
|
|
355
|
-
].join('');
|
|
283
|
+
return `A-Stage(${this._feature.name}::${this._definition.behavior}@${this._definition.handler})`;
|
|
356
284
|
}
|
|
357
285
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { A_Container } from "../A-Container/A-Container.class"
|
|
2
2
|
import { A_TYPES__Component_Constructor } from "../A-Component/A-Component.types"
|
|
3
|
-
import { A_TYPES__FeatureExtendDecoratorBehaviorConfig } from "../A-Feature/A-Feature.types"
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
|
|
@@ -43,6 +42,8 @@ export enum A_TYPES__A_Stage_Status {
|
|
|
43
42
|
ABORTED = 'ABORTED'
|
|
44
43
|
}
|
|
45
44
|
|
|
45
|
+
export type A_TYPES_StageExecutionBehavior = 'async' | 'sync'
|
|
46
|
+
|
|
46
47
|
|
|
47
48
|
export type A_TYPES__A_StageStep = {
|
|
48
49
|
/**
|
|
@@ -61,11 +62,41 @@ export type A_TYPES__A_StageStep = {
|
|
|
61
62
|
*/
|
|
62
63
|
name: string,
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
/**
|
|
66
|
+
* In case its async it will be executed independently from the main thread.
|
|
67
|
+
*
|
|
68
|
+
* [!] However, in case of sync, it will be executed in the main thread.in the order of the declaration.
|
|
69
|
+
*
|
|
70
|
+
*/
|
|
71
|
+
behavior: A_TYPES_StageExecutionBehavior
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Allows to define the order of the execution of the method.
|
|
75
|
+
*
|
|
76
|
+
* [!] In case the method has circular dependencies it will Throw an error.
|
|
77
|
+
*
|
|
78
|
+
*/
|
|
79
|
+
before: string[]
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Allows to define the order of the execution of the method.
|
|
83
|
+
*
|
|
84
|
+
* [!] In case the method has circular dependencies it will Throw an error.
|
|
85
|
+
*
|
|
86
|
+
*/
|
|
87
|
+
after: string[],
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Indicates whether to throw an error if the step fails.
|
|
91
|
+
*
|
|
92
|
+
* [!] By default is true
|
|
93
|
+
*/
|
|
94
|
+
throwOnError: boolean
|
|
95
|
+
}
|
|
65
96
|
|
|
66
97
|
|
|
67
98
|
|
|
68
|
-
export type
|
|
99
|
+
export type A_TYPES__Stage_Serialized = {
|
|
69
100
|
|
|
70
101
|
/**
|
|
71
102
|
* The name of the stage
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { A_Feature } from "../A-Feature/A-Feature.class";
|
|
2
|
+
import { A_TYPES__FeatureDefineDecoratorTemplateItem } from "../A-Feature/A-Feature.types";
|
|
3
|
+
import { A_Stage } from "../A-Stage/A-Stage.class";
|
|
4
|
+
import { A_TYPES__A_StageStep } from "../A-Stage/A-Stage.types";
|
|
5
|
+
import { A_StepManagerError } from "./A-StepManager.error";
|
|
6
6
|
|
|
7
7
|
export class A_StepsManager {
|
|
8
8
|
|
|
@@ -13,6 +13,8 @@ export class A_StepsManager {
|
|
|
13
13
|
public sortedEntities: string[];
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
private _isBuilt: boolean = false;
|
|
17
|
+
|
|
16
18
|
constructor(entities: Array<A_TYPES__FeatureDefineDecoratorTemplateItem>) {
|
|
17
19
|
this.entities = this.prepareSteps(entities);
|
|
18
20
|
|
|
@@ -29,10 +31,11 @@ export class A_StepsManager {
|
|
|
29
31
|
return entities.map(step => {
|
|
30
32
|
return {
|
|
31
33
|
...step,
|
|
32
|
-
|
|
34
|
+
|
|
33
35
|
behavior: step.behavior || 'sync',
|
|
34
36
|
before: step.before || [],
|
|
35
37
|
after: step.after || [],
|
|
38
|
+
throwOnError: false
|
|
36
39
|
};
|
|
37
40
|
});
|
|
38
41
|
}
|
|
@@ -42,6 +45,8 @@ export class A_StepsManager {
|
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
private buildGraph() {
|
|
48
|
+
if (this._isBuilt) return;
|
|
49
|
+
this._isBuilt = true;
|
|
45
50
|
// Initialize graph nodes
|
|
46
51
|
this.entities.forEach(entity => this.graph.set(this.ID(entity), new Set()));
|
|
47
52
|
|
|
@@ -54,7 +59,7 @@ export class A_StepsManager {
|
|
|
54
59
|
// If entity should execute before targets, then targets depend on entity
|
|
55
60
|
// So we add edges: target -> entity (target depends on entity)
|
|
56
61
|
before.forEach(dep => {
|
|
57
|
-
const targets = this.matchEntities(dep);
|
|
62
|
+
const targets = this.matchEntities(entityId, dep);
|
|
58
63
|
targets.forEach(target => {
|
|
59
64
|
if (!this.graph.has(target)) this.graph.set(target, new Set());
|
|
60
65
|
this.graph.get(target)!.add(entityId); // target depends on entity
|
|
@@ -65,7 +70,7 @@ export class A_StepsManager {
|
|
|
65
70
|
// If entity should execute after sources, then entity depends on sources
|
|
66
71
|
// So we add edges: entity -> source (entity depends on source)
|
|
67
72
|
after.forEach(dep => {
|
|
68
|
-
const sources = this.matchEntities(dep);
|
|
73
|
+
const sources = this.matchEntities(entityId, dep);
|
|
69
74
|
|
|
70
75
|
sources.forEach(source => {
|
|
71
76
|
if (!this.graph.has(entityId)) this.graph.set(entityId, new Set());
|
|
@@ -76,28 +81,51 @@ export class A_StepsManager {
|
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
// Match entities by name or regex
|
|
79
|
-
private matchEntities(pattern: string): string[] {
|
|
80
|
-
const regex = new RegExp(
|
|
84
|
+
private matchEntities(entityId: string, pattern: string): string[] {
|
|
85
|
+
const regex = new RegExp(pattern);
|
|
86
|
+
|
|
81
87
|
return this.entities
|
|
82
|
-
.filter(entity => regex.test(this.ID(entity)))
|
|
88
|
+
.filter(entity => regex.test(this.ID(entity)) && this.ID(entity) !== entityId)
|
|
83
89
|
.map(entity => this.ID(entity));
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
// Topological sort with cycle detection
|
|
87
93
|
private visit(node: string): void {
|
|
88
|
-
if (this.tempMark.has(node))
|
|
94
|
+
if (this.tempMark.has(node)) {
|
|
95
|
+
return;
|
|
96
|
+
// TODO: maybe we have to keep this error but only for partial cases
|
|
97
|
+
throw new A_StepManagerError(
|
|
98
|
+
A_StepManagerError.CircularDependencyError,
|
|
99
|
+
`Circular dependency detected involving step: ${node}. Make sure that your 'before' and 'after' dependencies do not create cycles.`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
89
102
|
|
|
90
103
|
if (!this.visited.has(node)) {
|
|
91
104
|
this.tempMark.add(node);
|
|
105
|
+
|
|
106
|
+
|
|
92
107
|
(this.graph.get(node) || []).forEach(neighbor => this.visit(neighbor));
|
|
93
108
|
this.tempMark.delete(node);
|
|
94
109
|
this.visited.add(node);
|
|
95
110
|
this.sortedEntities.push(node);
|
|
111
|
+
|
|
112
|
+
// // Visit neighbors in stable order (preserving original order)
|
|
113
|
+
// const neighbors = Array.from(this.graph.get(node) || []);
|
|
114
|
+
// // neighbors.sort((a, b) => {
|
|
115
|
+
// // const orderA = this.originalOrder.get(a) || 0;
|
|
116
|
+
// // const orderB = this.originalOrder.get(b) || 0;
|
|
117
|
+
// // return orderA - orderB;
|
|
118
|
+
// // });
|
|
119
|
+
|
|
120
|
+
// neighbors.forEach(neighbor => this.visit(neighbor));
|
|
121
|
+
// this.tempMark.delete(node);
|
|
122
|
+
// this.visited.add(node);
|
|
123
|
+
// this.sortedEntities.push(node);
|
|
96
124
|
}
|
|
97
125
|
}
|
|
98
126
|
|
|
99
|
-
|
|
100
|
-
|
|
127
|
+
|
|
128
|
+
toSortedArray(): Array<string> {
|
|
101
129
|
this.buildGraph();
|
|
102
130
|
|
|
103
131
|
// Start topological sort
|
|
@@ -105,87 +133,25 @@ export class A_StepsManager {
|
|
|
105
133
|
if (!this.visited.has(this.ID(entity))) this.visit(this.ID(entity));
|
|
106
134
|
});
|
|
107
135
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// Map sorted names back to entity objects
|
|
111
|
-
this.sortedEntities
|
|
112
|
-
.map(id => {
|
|
113
|
-
const step = this.entities.find(entity => this.ID(entity) === id)!;
|
|
114
|
-
|
|
115
|
-
let stage = stages.find(stage => {
|
|
116
|
-
return stage.after.every(after => step.after.includes(after))
|
|
117
|
-
&& step.before.every(before => stage.after.includes(before));
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (!stage) {
|
|
122
|
-
stage = new A_TmpStage();
|
|
123
|
-
stages.push(stage);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
stage.add(step);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
return stages.map(stage => new A_Stage(feature, stage.steps));
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
export class A_TmpStage {
|
|
138
|
-
|
|
139
|
-
readonly name: string = 'A_TmpStage';
|
|
140
|
-
|
|
141
|
-
private readonly _steps!: A_TYPES__A_StageStep[];
|
|
142
|
-
|
|
143
|
-
constructor(
|
|
144
|
-
_steps: A_TYPES__A_StageStep[] = []
|
|
145
|
-
) {
|
|
146
|
-
this._steps = _steps;
|
|
136
|
+
return this.sortedEntities;
|
|
147
137
|
}
|
|
148
138
|
|
|
139
|
+
// Sort the entities based on dependencies
|
|
140
|
+
toStages(feature: A_Feature): Array<A_Stage> {
|
|
149
141
|
|
|
150
|
-
get before(): string[] {
|
|
151
|
-
return this._steps.reduce((acc, step) => ([
|
|
152
|
-
...acc,
|
|
153
|
-
...step.before
|
|
154
|
-
]), [] as string[]);
|
|
155
|
-
}
|
|
156
142
|
|
|
157
|
-
|
|
158
|
-
return this._steps.reduce((acc, step) => ([
|
|
159
|
-
...acc,
|
|
160
|
-
...step.after
|
|
161
|
-
]), [] as string[]);
|
|
162
|
-
}
|
|
143
|
+
const sortedNames = this.toSortedArray();
|
|
163
144
|
|
|
164
|
-
get steps(): A_TYPES__A_StageStep[] {
|
|
165
|
-
return this._steps;
|
|
166
|
-
}
|
|
167
145
|
|
|
146
|
+
// Map sorted names back to entity objects
|
|
147
|
+
return sortedNames
|
|
148
|
+
.map(id => {
|
|
149
|
+
const step = this.entities.find(entity => this.ID(entity) === id)!;
|
|
168
150
|
|
|
169
|
-
get asyncSteps(): A_TYPES__A_StageStep[] {
|
|
170
|
-
return this._steps.filter(step => step.behavior === 'async');
|
|
171
|
-
}
|
|
172
151
|
|
|
173
|
-
|
|
174
|
-
|
|
152
|
+
return new A_Stage(feature, step);
|
|
153
|
+
});
|
|
175
154
|
}
|
|
155
|
+
}
|
|
176
156
|
|
|
177
157
|
|
|
178
|
-
/**
|
|
179
|
-
* Adds a step to the stage
|
|
180
|
-
*
|
|
181
|
-
* @param step
|
|
182
|
-
* @returns
|
|
183
|
-
*/
|
|
184
|
-
add(
|
|
185
|
-
step: A_TYPES__A_StageStep
|
|
186
|
-
): this {
|
|
187
|
-
this._steps.push(step);
|
|
188
|
-
|
|
189
|
-
return this;
|
|
190
|
-
}
|
|
191
|
-
}
|