@adaas/a-concept 0.0.63 → 0.0.64
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/src/global/A-Concept/A_Concept.class.d.ts +1 -1
- package/dist/src/global/A-Scope/A-Scope.class.d.ts +417 -56
- package/dist/src/global/A-Scope/A-Scope.class.js +542 -250
- package/dist/src/global/A-Scope/A-Scope.class.js.map +1 -1
- package/dist/src/global/A-Scope/A-Scope.constants.d.ts +2 -0
- package/dist/src/global/A-Scope/A-Scope.constants.js +11 -0
- package/dist/src/global/A-Scope/A-Scope.constants.js.map +1 -0
- package/dist/src/global/A-Scope/A-Scope.types.d.ts +11 -9
- package/dist/src/global/A-Stage/A-Stage.class.d.ts +2 -2
- package/package.json +1 -1
- package/src/global/A-Scope/A-Scope.class.ts +834 -425
- package/src/global/A-Scope/A-Scope.constants.ts +9 -0
- package/src/global/A-Scope/A-Scope.types.ts +23 -18
|
@@ -1,112 +1,218 @@
|
|
|
1
|
-
import { A_CommonHelper, ASEID } from "@adaas/a-utils";
|
|
2
|
-
import { A_TYPES__ScopeConfig, A_TYPES__ScopeConstructor } from "./A-Scope.types";
|
|
3
|
-
import { A_Fragment } from "../A-Fragment/A-Fragment.class";
|
|
4
|
-
import { A_Context } from "../A-Context/A-Context.class";
|
|
5
1
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
A_CommonHelper,
|
|
3
|
+
A_Error,
|
|
4
|
+
ASEID
|
|
5
|
+
} from "@adaas/a-utils";
|
|
6
|
+
import {
|
|
7
|
+
A_TYPES__AllowedCommandsConstructor,
|
|
8
|
+
A_TYPES__AllowedComponentsConstructor,
|
|
9
|
+
A_TYPES__AllowedEntitiesConstructor,
|
|
10
|
+
A_TYPES__AllowedFragmentsConstructor,
|
|
11
|
+
A_TYPES__AllowedScopesConstructor,
|
|
12
|
+
A_TYPES__ScopeConfig,
|
|
13
|
+
A_TYPES__ScopeConstructor
|
|
14
|
+
} from './A-Scope.types'
|
|
10
15
|
import {
|
|
11
16
|
A_TYPES__A_InjectDecorator_EntityInjectionInstructions,
|
|
12
17
|
A_TYPES__A_InjectDecorator_EntityInjectionQuery,
|
|
13
|
-
A_TYPES__A_InjectDecorator_Injectable
|
|
14
18
|
} from "@adaas/a-concept/decorators/A-Inject/A-Inject.decorator.types";
|
|
19
|
+
import { A_TYPES__ComponentMetaKey } from "../A-Component/A-Component.types";
|
|
20
|
+
import { A_Fragment } from "../A-Fragment/A-Fragment.class";
|
|
21
|
+
import { A_Context } from "../A-Context/A-Context.class";
|
|
22
|
+
import { A_Component } from "../A-Component/A-Component.class";
|
|
23
|
+
import { A_Entity } from "../A-Entity/A-Entity.class";
|
|
15
24
|
import { A_Command } from "../A-Command/A-Command.class";
|
|
16
25
|
|
|
17
26
|
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* A_Scope refers to the visibility and accessibility of :
|
|
22
|
-
* - variables,
|
|
23
|
-
* - Components,
|
|
24
|
-
* - Context Fragments
|
|
25
|
-
* - and objects in different parts of your code.
|
|
26
|
-
* Scope determines where a particular piece of data (like a variable or function)
|
|
27
|
-
* can be accessed, modified, or referenced, and it plays a crucial role in avoiding naming collisions and ensuring data integrity.
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*/
|
|
31
|
-
export class A_Scope {
|
|
32
27
|
|
|
28
|
+
|
|
29
|
+
export class A_Scope<
|
|
30
|
+
_ComponentType extends A_TYPES__AllowedComponentsConstructor[] = A_TYPES__AllowedComponentsConstructor[],
|
|
31
|
+
_CommandType extends A_TYPES__AllowedCommandsConstructor[] = A_TYPES__AllowedCommandsConstructor[],
|
|
32
|
+
_EntityType extends A_Entity[] = A_Entity[],
|
|
33
|
+
_FragmentType extends A_Fragment[] = A_Fragment[],
|
|
34
|
+
> {
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Scope Name uses for identification and logging purposes
|
|
38
|
+
*/
|
|
33
39
|
readonly name: string = '';
|
|
40
|
+
/**
|
|
41
|
+
* Parent scope reference, used for inheritance of components, fragments, entities and commands
|
|
42
|
+
*/
|
|
43
|
+
protected _parent?: A_Scope;
|
|
34
44
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
// ===========================================================================
|
|
46
|
+
// --------------------ALLowed Constructors--------------------------------
|
|
47
|
+
// ===========================================================================
|
|
48
|
+
/**
|
|
49
|
+
* A set of allowed components, A set of constructors that are allowed in the scope
|
|
50
|
+
*
|
|
51
|
+
*/
|
|
52
|
+
protected _allowedComponents = new Set<_ComponentType[number]>();
|
|
53
|
+
/**
|
|
54
|
+
* A set of allowed entities, A set of constructors that are allowed in the scope
|
|
55
|
+
*/
|
|
56
|
+
protected _allowedEntities = new Set<A_TYPES__AllowedEntitiesConstructor<_EntityType[number]>>();
|
|
57
|
+
/**
|
|
58
|
+
* A set of allowed fragments, A set of constructors that are allowed in the scope
|
|
59
|
+
*/
|
|
60
|
+
protected _allowedFragments = new Set<A_TYPES__AllowedFragmentsConstructor<_FragmentType[number]>>();
|
|
61
|
+
/**
|
|
62
|
+
* A set of allowed commands, A set of constructors that are allowed in the scope
|
|
63
|
+
*/
|
|
64
|
+
protected _allowedCommands = new Set<_CommandType[number]>();
|
|
39
65
|
|
|
40
|
-
private _parent?: A_Scope;
|
|
41
66
|
|
|
42
|
-
|
|
67
|
+
// ===========================================================================
|
|
68
|
+
// --------------------Internal Storage--------------------------------
|
|
69
|
+
// ===========================================================================
|
|
70
|
+
/**
|
|
71
|
+
* Internal storage for the components, fragments, entities and commands
|
|
72
|
+
*/
|
|
73
|
+
protected _components: Map<_ComponentType[number], InstanceType<_ComponentType[number]>> = new Map();
|
|
74
|
+
/**
|
|
75
|
+
* Storage for the fragments, should be weak as fragments are singletons per scope
|
|
76
|
+
*/
|
|
77
|
+
protected _fragments: Map<A_TYPES__AllowedFragmentsConstructor<_FragmentType[number]>, _FragmentType[number]> = new Map();
|
|
78
|
+
/**
|
|
79
|
+
* Storage for the entities, should be strong as entities are unique per aseid
|
|
80
|
+
*/
|
|
81
|
+
protected _entities: Map<string, _EntityType[number]> = new Map();
|
|
82
|
+
/**
|
|
83
|
+
* Storage for the commands, should be strong as commands are unique per code
|
|
84
|
+
*/
|
|
85
|
+
protected _commands: Map<string, InstanceType<_CommandType[number]>> = new Map();
|
|
43
86
|
|
|
44
87
|
|
|
45
|
-
constructor(
|
|
46
|
-
params: Partial<A_TYPES__ScopeConstructor>,
|
|
47
|
-
config: Partial<A_TYPES__ScopeConfig> = {}
|
|
48
|
-
) {
|
|
49
|
-
this.name = params.name || this.constructor.name;
|
|
50
88
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
89
|
+
// ===========================================================================
|
|
90
|
+
// --------------------Readonly Allowed Properties----------------------------
|
|
91
|
+
// ===========================================================================
|
|
92
|
+
/**
|
|
93
|
+
* Returns a list of Constructors for A-Components that are available in the scope
|
|
94
|
+
*/
|
|
95
|
+
get allowedComponents() { return this._allowedComponents }
|
|
96
|
+
/**
|
|
97
|
+
* Returns a list of Constructors for A-Commands that are available in the scope
|
|
98
|
+
*/
|
|
99
|
+
get allowedCommands() { return this._allowedCommands }
|
|
100
|
+
/**
|
|
101
|
+
* Returns a list of Constructors for A-Fragments that are available in the scope
|
|
102
|
+
*/
|
|
103
|
+
get allowedFragments() { return this._allowedFragments }
|
|
104
|
+
/**
|
|
105
|
+
* Returns a list of Constructors for A-Entities that are available in the scope
|
|
106
|
+
*/
|
|
107
|
+
get allowedEntities() { return this._allowedEntities }
|
|
59
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Returns an Array of entities registered in the scope
|
|
111
|
+
*
|
|
112
|
+
* [!] One entity per aseid
|
|
113
|
+
*/
|
|
114
|
+
get entities(): Array<_EntityType[number]> { return Array.from(this._entities.values()) }
|
|
115
|
+
/**
|
|
116
|
+
* Returns an Array of fragments registered in the scope
|
|
117
|
+
*
|
|
118
|
+
* [!] One fragment per scope
|
|
119
|
+
*/
|
|
120
|
+
get fragments(): Array<_FragmentType[number]> { return Array.from(this._fragments.values()) }
|
|
121
|
+
/**
|
|
122
|
+
* Returns an Array of components registered in the scope
|
|
123
|
+
*
|
|
124
|
+
* [!] One component instance per scope
|
|
125
|
+
*/
|
|
126
|
+
get components(): Array<InstanceType<_ComponentType[number]>> { return Array.from(this._components.values()) }
|
|
127
|
+
/**
|
|
128
|
+
* Returns an Array of commands registered in the scope
|
|
129
|
+
*
|
|
130
|
+
* [!] One command per command aseid
|
|
131
|
+
* [!!] There may be any number of instances of the same command code, but with different aseids.
|
|
132
|
+
*/
|
|
133
|
+
get commands(): Array<InstanceType<_CommandType[number]>> { return Array.from(this._commands.values()) }
|
|
60
134
|
|
|
61
|
-
this.params = {
|
|
62
|
-
...defaultParams,
|
|
63
|
-
...params
|
|
64
|
-
}
|
|
65
135
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
136
|
+
/**
|
|
137
|
+
* A_Scope refers to the visibility and accessibility of :
|
|
138
|
+
* - variables,
|
|
139
|
+
* - Components,
|
|
140
|
+
* - Context Fragments
|
|
141
|
+
* - Commands
|
|
142
|
+
* - Entities
|
|
143
|
+
* - and objects in different parts of your code.
|
|
144
|
+
* Scope determines where a particular piece of data (like a variable or function)
|
|
145
|
+
* can be accessed, modified, or referenced, and it plays a crucial role in avoiding naming collisions and ensuring data integrity.
|
|
146
|
+
*
|
|
147
|
+
* [!] The scope behavior is similar to tree structure where each scope can have a parent scope and inherit its components, fragments, entities and commands
|
|
148
|
+
*
|
|
149
|
+
* @param params
|
|
150
|
+
* @param config
|
|
151
|
+
*/
|
|
152
|
+
constructor(
|
|
153
|
+
params: Partial<A_TYPES__ScopeConstructor<_ComponentType, _CommandType, _EntityType, _FragmentType>>,
|
|
154
|
+
config: Partial<A_TYPES__ScopeConfig> = {}
|
|
155
|
+
) {
|
|
156
|
+
this.name = params.name || this.constructor.name
|
|
157
|
+
|
|
158
|
+
this.initComponents(params.components);
|
|
159
|
+
this.initCommands(params.commands);
|
|
160
|
+
this.initFragments(params.fragments);
|
|
161
|
+
this.initEntities(params.entities);
|
|
69
162
|
|
|
70
163
|
if (config.parent) {
|
|
71
164
|
this._parent = config.parent;
|
|
72
165
|
}
|
|
73
166
|
}
|
|
74
167
|
|
|
168
|
+
//==========================================================================
|
|
169
|
+
// --------------------Scope Initialization Methods---------------------------
|
|
170
|
+
//==========================================================================
|
|
75
171
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
172
|
+
/**
|
|
173
|
+
* This method is used to initialize the components in the scope
|
|
174
|
+
* To save memory components are initialized only when they are requested
|
|
175
|
+
*
|
|
176
|
+
* This method only registers the component in the scope in case they are not registered yet
|
|
177
|
+
*
|
|
178
|
+
* @param _components
|
|
179
|
+
*/
|
|
180
|
+
protected initComponents(_components?: _ComponentType) { _components?.forEach(this.register.bind(this)); }
|
|
181
|
+
/**
|
|
182
|
+
* This method is used to initialize the entities in the scope
|
|
183
|
+
*
|
|
184
|
+
* This method only registers the entities in the scope in case they are not registered yet
|
|
185
|
+
*
|
|
186
|
+
* @param _entities
|
|
187
|
+
*/
|
|
188
|
+
protected initEntities(_entities?: _EntityType) { _entities?.forEach(this.register.bind(this)); }
|
|
189
|
+
/**
|
|
190
|
+
* This method is used to initialize the fragments in the scope
|
|
191
|
+
*
|
|
192
|
+
* This method only registers the fragments in the scope in case they are not registered yet
|
|
193
|
+
*
|
|
194
|
+
* @param _fragments
|
|
195
|
+
*/
|
|
196
|
+
protected initFragments(_fragments?: _FragmentType) { _fragments?.forEach(this.register.bind(this)); }
|
|
197
|
+
/**
|
|
198
|
+
* This method is used to initialize the commands in the scope
|
|
199
|
+
*
|
|
200
|
+
* This method only registers the commands in the scope in case they are not registered yet
|
|
201
|
+
*
|
|
202
|
+
* @param _commands
|
|
203
|
+
*/
|
|
204
|
+
protected initCommands(_commands?: _CommandType) { _commands?.forEach(this.register.bind(this)); }
|
|
103
205
|
|
|
104
206
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
207
|
+
/**
|
|
208
|
+
* This method is used to get or set the parent scope
|
|
209
|
+
*
|
|
210
|
+
* [!] Note that setting the parent scope will override the existing parent scope
|
|
211
|
+
*
|
|
212
|
+
* @param setValue
|
|
213
|
+
* @returns
|
|
214
|
+
*/
|
|
215
|
+
parent(setValue?: A_Scope): A_Scope | undefined {
|
|
110
216
|
if (setValue) {
|
|
111
217
|
return this.inherit(setValue);
|
|
112
218
|
}
|
|
@@ -114,162 +220,131 @@ export class A_Scope {
|
|
|
114
220
|
return this._parent;
|
|
115
221
|
}
|
|
116
222
|
|
|
117
|
-
isInheritedFrom(scope: A_Scope): boolean {
|
|
118
|
-
let current: A_Scope | undefined = this;
|
|
119
|
-
|
|
120
|
-
while (current) {
|
|
121
|
-
if (current === scope) {
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
current = current._parent;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
inherit(parent: A_Scope): A_Scope {
|
|
132
|
-
// Prevent circular inheritance
|
|
133
|
-
const circularCheck = this.checkCircularInheritance(parent);
|
|
134
|
-
|
|
135
|
-
if (circularCheck) {
|
|
136
|
-
throw new Error(`Circular inheritance detected: ${[...circularCheck, parent.name].join(' -> ')}`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
this._parent = parent;
|
|
140
|
-
return this;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
223
|
|
|
144
224
|
|
|
145
225
|
/**
|
|
146
|
-
*
|
|
147
|
-
* Should return a full sequence of inheritance for logging purposes
|
|
226
|
+
* This method is used to inherit from a parent scope
|
|
148
227
|
*
|
|
149
|
-
*
|
|
228
|
+
* [!] This method checks for circular inheritance and throws an error if detected
|
|
229
|
+
*
|
|
230
|
+
* @param parent
|
|
150
231
|
* @returns
|
|
151
232
|
*/
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
while (current) {
|
|
157
|
-
inheritanceChain.push(current.name);
|
|
158
|
-
if (current === scope) {
|
|
159
|
-
return inheritanceChain;
|
|
160
|
-
}
|
|
161
|
-
current = current._parent;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
|
|
233
|
+
inherit(parent: A_Scope): A_Scope {
|
|
234
|
+
// Prevent circular inheritance
|
|
235
|
+
const circularCheck = this.checkCircularInheritance(parent);
|
|
167
236
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
let current: A_Scope | undefined = this;
|
|
237
|
+
if (circularCheck)
|
|
238
|
+
throw new A_Error(`Circular inheritance detected: ${[...circularCheck, parent.name].join(' -> ')}`);
|
|
171
239
|
|
|
172
|
-
while (current) {
|
|
173
|
-
chain.push(current.name);
|
|
174
|
-
current = current._parent;
|
|
175
|
-
}
|
|
176
240
|
|
|
177
|
-
|
|
241
|
+
this._parent = parent;
|
|
242
|
+
return this;
|
|
178
243
|
}
|
|
179
244
|
|
|
180
245
|
|
|
181
246
|
/**
|
|
182
247
|
* This method is used to check if the component is available in the scope
|
|
183
248
|
*
|
|
249
|
+
* [!] Note that this method checks for the component in the current scope and all parent scopes
|
|
250
|
+
*
|
|
184
251
|
* @param component
|
|
185
252
|
* @returns
|
|
186
253
|
*/
|
|
187
254
|
has<T extends A_Component>(
|
|
188
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Provide a component constructor to check if it's available in the scope
|
|
257
|
+
*/
|
|
258
|
+
component: A_TYPES__AllowedComponentsConstructor<T>
|
|
189
259
|
): boolean
|
|
190
260
|
has<T extends A_Entity>(
|
|
191
|
-
|
|
261
|
+
/**
|
|
262
|
+
* Provide an entity constructor to check if it's available in the scope
|
|
263
|
+
*
|
|
264
|
+
* [!] Note that entities are unique per aseid, so this method checks if there's at least one entity of the provided type in the scope
|
|
265
|
+
*/
|
|
266
|
+
entity: A_TYPES__AllowedEntitiesConstructor<T>
|
|
192
267
|
): boolean
|
|
193
268
|
has<T extends A_Fragment>(
|
|
194
|
-
|
|
269
|
+
/**
|
|
270
|
+
* Provide a fragment constructor to check if it's available in the scope
|
|
271
|
+
*/
|
|
272
|
+
fragment: A_TYPES__AllowedFragmentsConstructor<T>
|
|
273
|
+
): boolean
|
|
274
|
+
has<T extends A_Fragment>(
|
|
275
|
+
/**
|
|
276
|
+
* Provide a command constructor to check if it's available in the scope
|
|
277
|
+
*/
|
|
278
|
+
command: A_TYPES__AllowedCommandsConstructor<T>
|
|
195
279
|
): boolean
|
|
196
280
|
has(
|
|
281
|
+
/**
|
|
282
|
+
* Provide a string to check if a component, entity or fragment with the provided name is available in the scope
|
|
283
|
+
*/
|
|
197
284
|
constructor: string
|
|
198
285
|
): boolean
|
|
199
|
-
has
|
|
200
|
-
|
|
286
|
+
has(
|
|
287
|
+
ctor: unknown
|
|
201
288
|
): boolean {
|
|
202
289
|
|
|
290
|
+
let found = false;
|
|
203
291
|
|
|
204
292
|
switch (true) {
|
|
293
|
+
// 1) Check by string name.
|
|
294
|
+
case typeof ctor === 'string': {
|
|
295
|
+
// 1.1 Check if it's a component name
|
|
296
|
+
const possibleComponent = Array.from(this.allowedComponents).find(c => c.name === ctor);
|
|
297
|
+
if (possibleComponent) found = true;
|
|
205
298
|
|
|
206
|
-
|
|
207
|
-
const
|
|
299
|
+
// 1.2 Check if it's a fragment name
|
|
300
|
+
const possibleFragment = Array.from(this.allowedFragments).find(f => f.name === ctor);
|
|
301
|
+
if (possibleFragment) found = true;
|
|
208
302
|
|
|
209
|
-
if
|
|
210
|
-
|
|
211
|
-
|
|
303
|
+
// 1.3 Check if it's a command code or name
|
|
304
|
+
const possibleCommand = Array.from(this.allowedCommands).find(c => c.name === ctor);
|
|
305
|
+
if (possibleCommand) found = true;
|
|
212
306
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (
|
|
216
|
-
return true;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (this.params.entities.some(e => e.constructor.name === entity)) {
|
|
220
|
-
return true;
|
|
221
|
-
}
|
|
307
|
+
// 1.4 Check if it's an entity name or entity static entity property
|
|
308
|
+
const possibleEntity = Array.from(this.allowedEntities).find(e => e.name === ctor);
|
|
309
|
+
if (possibleEntity) found = true;
|
|
222
310
|
|
|
311
|
+
// 1.5 If not found in current scope, check parent scope
|
|
223
312
|
if (!!this._parent)
|
|
224
|
-
return this._parent.has(
|
|
313
|
+
return this._parent.has(ctor);
|
|
225
314
|
|
|
226
315
|
return false;
|
|
227
316
|
}
|
|
317
|
+
// 2) Check if it's a Component
|
|
318
|
+
case this.isComponentConstructor(ctor): {
|
|
319
|
+
found = this.isAllowedComponent(ctor);
|
|
228
320
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return this._parent.has(entity as any);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return found;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
case typeof entity === 'function'
|
|
241
|
-
&& A_CommonHelper.isInheritedFrom(entity, A_Entity): {
|
|
242
|
-
const entities = Array.from(this._entities.values());
|
|
243
|
-
|
|
244
|
-
const found = entities.find(e => e instanceof entity);
|
|
245
|
-
|
|
246
|
-
return !!found;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
case typeof entity === 'function'
|
|
250
|
-
&& A_CommonHelper.isInheritedFrom(entity, A_Fragment): {
|
|
251
|
-
const found = this._fragments.has(entity);
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
// 3) Check if it's an Entity
|
|
324
|
+
case this.isEntityConstructor(ctor): {
|
|
325
|
+
found = this.isAllowedEntity(ctor);
|
|
252
326
|
|
|
253
|
-
|
|
254
|
-
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
// 4) Check if it's a Fragment
|
|
330
|
+
case this.isFragmentConstructor(ctor): {
|
|
331
|
+
found = this.isAllowedFragment(ctor);
|
|
255
332
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
// 5) Check if it's a Command
|
|
336
|
+
case this.isCommandConstructor(ctor): {
|
|
337
|
+
found = this.isAllowedCommand(ctor);
|
|
261
338
|
|
|
262
|
-
|
|
263
|
-
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
264
342
|
|
|
265
|
-
|
|
266
|
-
|
|
343
|
+
if (!found && !!this._parent)
|
|
344
|
+
return this._parent.has(ctor as any);
|
|
267
345
|
|
|
268
346
|
|
|
269
|
-
|
|
270
|
-
return false;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
347
|
+
return found;
|
|
273
348
|
}
|
|
274
349
|
|
|
275
350
|
|
|
@@ -286,19 +361,13 @@ export class A_Scope {
|
|
|
286
361
|
merge(anotherScope: A_Scope): A_Scope {
|
|
287
362
|
const merged = new A_Scope(
|
|
288
363
|
{
|
|
289
|
-
name: `${this.name}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
fragments:
|
|
295
|
-
|
|
296
|
-
...anotherScope.params.fragments
|
|
297
|
-
])),
|
|
298
|
-
entities: Array.from(new Set([
|
|
299
|
-
...this.params.entities,
|
|
300
|
-
...anotherScope.params.entities
|
|
301
|
-
])),
|
|
364
|
+
name: `${this.name} + ${anotherScope.name}`,
|
|
365
|
+
|
|
366
|
+
components: [...this.allowedComponents, ...anotherScope.allowedComponents],
|
|
367
|
+
commands: [...this.allowedCommands, ...anotherScope.allowedCommands],
|
|
368
|
+
|
|
369
|
+
fragments: [...this.fragments, ...anotherScope.fragments],
|
|
370
|
+
entities: [...this.entities, ...anotherScope.entities],
|
|
302
371
|
},
|
|
303
372
|
{
|
|
304
373
|
parent: this._parent || anotherScope._parent
|
|
@@ -320,28 +389,63 @@ export class A_Scope {
|
|
|
320
389
|
* @param name
|
|
321
390
|
* @returns
|
|
322
391
|
*/
|
|
323
|
-
resolveConstructor<T extends
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
392
|
+
resolveConstructor<T extends A_Command>(
|
|
393
|
+
/**
|
|
394
|
+
* Provide the command name or code to retrieve its constructor
|
|
395
|
+
*/
|
|
396
|
+
name: string
|
|
397
|
+
): A_TYPES__AllowedCommandsConstructor<T>
|
|
398
|
+
resolveConstructor<T extends A_Entity>(
|
|
399
|
+
/**
|
|
400
|
+
* Provide the entity name or static entity property to retrieve its constructor
|
|
401
|
+
*/
|
|
402
|
+
name: string
|
|
403
|
+
): A_TYPES__AllowedEntitiesConstructor<T>
|
|
404
|
+
resolveConstructor<T extends A_Component>(
|
|
405
|
+
/**
|
|
406
|
+
* Provide the component name in PascalCase to retrieve its constructor
|
|
407
|
+
*/
|
|
408
|
+
name: string
|
|
409
|
+
): A_TYPES__AllowedComponentsConstructor<T>
|
|
410
|
+
resolveConstructor<T extends A_Fragment>(
|
|
411
|
+
/**
|
|
412
|
+
* Provide the fragment name in PascalCase to retrieve its constructor
|
|
413
|
+
*/
|
|
414
|
+
name: string
|
|
415
|
+
): A_TYPES__AllowedFragmentsConstructor<T>
|
|
416
|
+
resolveConstructor<T extends A_Command | A_Entity | A_Component | A_Fragment>(name: string): A_TYPES__AllowedCommandsConstructor<T> | A_TYPES__AllowedEntitiesConstructor<T> | A_TYPES__AllowedComponentsConstructor<T> | A_TYPES__AllowedFragmentsConstructor<T> {
|
|
417
|
+
// 1) Check components
|
|
418
|
+
const component = Array.from(this.allowedComponents).find(
|
|
419
|
+
c => c.name === name
|
|
420
|
+
|| c.name === A_CommonHelper.toPascalCase(name)
|
|
421
|
+
);
|
|
422
|
+
if (component) return component as A_TYPES__AllowedComponentsConstructor<T>;
|
|
423
|
+
|
|
424
|
+
// 2) Check entities
|
|
425
|
+
const entity = Array.from(this.allowedEntities).find(
|
|
426
|
+
e => e.name === name
|
|
427
|
+
|| e.name === A_CommonHelper.toPascalCase(name)
|
|
428
|
+
|| (e as any).entity === name
|
|
429
|
+
|| (e as any).entity === A_CommonHelper.toKebabCase(name)
|
|
332
430
|
);
|
|
333
|
-
if (entity) return entity
|
|
431
|
+
if (entity) return entity as A_TYPES__AllowedEntitiesConstructor<T>;
|
|
334
432
|
|
|
335
|
-
// Check commands
|
|
336
|
-
const command = this.
|
|
433
|
+
// 3) Check commands
|
|
434
|
+
const command = Array.from(this.allowedCommands).find(c => (c as any).code === name
|
|
337
435
|
|| (c as any).name === A_CommonHelper.toPascalCase(name)
|
|
338
436
|
|| (c as any).code === A_CommonHelper.toKebabCase(name)
|
|
339
437
|
);
|
|
340
|
-
if (command) return command as
|
|
438
|
+
if (command) return command as A_TYPES__AllowedCommandsConstructor<T>;
|
|
439
|
+
|
|
440
|
+
// 4) Check fragments
|
|
441
|
+
const fragment = Array.from(this.allowedFragments).find(f => f.name === name
|
|
442
|
+
|| f.name === A_CommonHelper.toPascalCase(name)
|
|
443
|
+
);
|
|
444
|
+
if (fragment) return fragment as A_TYPES__AllowedFragmentsConstructor<T>;
|
|
341
445
|
|
|
342
446
|
// If not found in current scope, check parent scope
|
|
343
447
|
if (!!this._parent) {
|
|
344
|
-
return this._parent.resolveConstructor(name);
|
|
448
|
+
return this._parent.resolveConstructor(name) as any;
|
|
345
449
|
}
|
|
346
450
|
|
|
347
451
|
throw new Error(`Component or Entity with name ${name} not found in the scope ${this.name}`);
|
|
@@ -349,135 +453,219 @@ export class A_Scope {
|
|
|
349
453
|
|
|
350
454
|
|
|
351
455
|
|
|
352
|
-
|
|
353
|
-
|
|
354
456
|
/**
|
|
355
|
-
* This method
|
|
457
|
+
* This method allows to resolve/inject a component, fragment or entity from the scope
|
|
458
|
+
* Depending on the provided parameters it can resolve:
|
|
459
|
+
* - A single component/fragment/entity by its constructor or name
|
|
460
|
+
* - An array of components/fragments/entities by providing an array of constructors
|
|
461
|
+
* - An entity or an array of entities by providing the entity constructor and query instructions
|
|
356
462
|
*
|
|
357
463
|
* @param component
|
|
358
464
|
* @returns
|
|
359
465
|
*/
|
|
360
|
-
resolve<T extends
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
component: T
|
|
365
|
-
):
|
|
466
|
+
resolve<T extends A_Component>(
|
|
467
|
+
/**
|
|
468
|
+
* Provide a component constructor to resolve its instance from the scope
|
|
469
|
+
*/
|
|
470
|
+
component: A_TYPES__AllowedComponentsConstructor<T>
|
|
471
|
+
): T
|
|
472
|
+
resolve<T extends A_TYPES__AllowedComponentsConstructor[]>(
|
|
473
|
+
/**
|
|
474
|
+
* Provide an array of component constructors to resolve their instances from the scope
|
|
475
|
+
*/
|
|
476
|
+
components: [...T]
|
|
477
|
+
): Array<InstanceType<T[number]>>
|
|
478
|
+
resolve<T extends A_Fragment>(
|
|
479
|
+
/**
|
|
480
|
+
* Provide a fragment constructor to resolve its instance from the scope
|
|
481
|
+
*/
|
|
482
|
+
fragment: A_TYPES__AllowedFragmentsConstructor<T>
|
|
483
|
+
): T
|
|
484
|
+
resolve<T extends A_TYPES__AllowedFragmentsConstructor[]>(
|
|
485
|
+
/**
|
|
486
|
+
* Provide an array of fragment constructors to resolve their instances from the scope
|
|
487
|
+
*/
|
|
488
|
+
fragments: [...T]
|
|
489
|
+
): Array<InstanceType<T[number]>>
|
|
490
|
+
resolve<T extends A_Command>(
|
|
491
|
+
/**
|
|
492
|
+
* Provide a command constructor to resolve its instance from the scope
|
|
493
|
+
*/
|
|
494
|
+
command: A_TYPES__AllowedCommandsConstructor<T>
|
|
495
|
+
): T
|
|
496
|
+
resolve<T extends A_TYPES__AllowedCommandsConstructor[]>(
|
|
497
|
+
/**
|
|
498
|
+
* Provide an array of command constructors to resolve their instances from the scope
|
|
499
|
+
*/
|
|
500
|
+
commands: [...T]
|
|
501
|
+
): Array<InstanceType<T[number]>>
|
|
502
|
+
resolve<T extends A_Entity>(
|
|
503
|
+
/**
|
|
504
|
+
* Provide an entity constructor to resolve its instance or an array of instances from the scope
|
|
505
|
+
*/
|
|
506
|
+
entity: A_TYPES__AllowedEntitiesConstructor<T>
|
|
507
|
+
): T | undefined
|
|
508
|
+
resolve<T extends A_Scope>(
|
|
509
|
+
/**
|
|
510
|
+
* Uses only in case of resolving a single entity
|
|
511
|
+
*
|
|
512
|
+
* Provide an entity constructor to resolve its instance from the scope
|
|
513
|
+
*/
|
|
514
|
+
scope: new (...args: any[]) => T
|
|
515
|
+
): T
|
|
366
516
|
resolve<T extends A_Entity>(
|
|
367
|
-
|
|
517
|
+
/**
|
|
518
|
+
* Provide an entity constructor to resolve its instance or an array of instances from the scope
|
|
519
|
+
*/
|
|
520
|
+
entity: A_TYPES__AllowedEntitiesConstructor<T>,
|
|
521
|
+
/**
|
|
522
|
+
* Provide optional instructions to find a specific entity or a set of entities
|
|
523
|
+
*/
|
|
368
524
|
instructions: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions<T>>
|
|
369
|
-
):
|
|
370
|
-
resolve<T extends A_TYPES__A_InjectDecorator_Injectable>(
|
|
371
|
-
component: Array<T>
|
|
372
|
-
): Array<InstanceType<T>>
|
|
525
|
+
): Array<T>
|
|
373
526
|
// base definition
|
|
374
|
-
resolve<T extends
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
527
|
+
resolve<T extends A_Component | A_Fragment | A_Entity | A_Command>(
|
|
528
|
+
/**
|
|
529
|
+
* Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
|
|
530
|
+
*/
|
|
531
|
+
param1: unknown,
|
|
532
|
+
param2?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
|
|
533
|
+
): T | Array<T> {
|
|
380
534
|
switch (true) {
|
|
381
535
|
case Array.isArray(param1): {
|
|
382
|
-
return param1.map(c => this.resolveOnce(
|
|
536
|
+
return param1.map(c => this.resolveOnce(c, param2)).filter(Boolean) as Array<T>;
|
|
383
537
|
}
|
|
384
538
|
|
|
385
539
|
case typeof param1 === 'function': {
|
|
386
|
-
return this.resolveOnce(param1
|
|
540
|
+
return this.resolveOnce(param1, param2);
|
|
387
541
|
}
|
|
388
542
|
|
|
543
|
+
|
|
389
544
|
case typeof param1 === 'string': {
|
|
390
|
-
return this.resolveByName(param1
|
|
545
|
+
return this.resolveByName(param1) as T;
|
|
391
546
|
}
|
|
392
547
|
|
|
393
548
|
default: {
|
|
394
|
-
throw new
|
|
549
|
+
throw new A_Error(`Invalid parameter provided to resolve method: ${param1} in scope ${this.name}`);
|
|
395
550
|
}
|
|
396
551
|
}
|
|
397
552
|
}
|
|
398
553
|
|
|
399
554
|
|
|
400
|
-
private resolveByName(name: string): A_Entity | A_Fragment | A_Component {
|
|
401
|
-
// Check components
|
|
402
|
-
const component = this.params.components.find(c => c.name === name);
|
|
403
|
-
if (component) return this.resolveComponent(component);
|
|
404
555
|
|
|
405
|
-
// Check commands
|
|
406
|
-
const command = this.params.commands.find(c => c.name === name);
|
|
407
|
-
if (command) return this.resolveComponent(command);
|
|
408
556
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
557
|
+
// ==================================================================================================
|
|
558
|
+
// --------------------------------------------------------------------------------------------------
|
|
559
|
+
// -------------------------------------INTERNAL RESOLVERS-------------------------------------------
|
|
560
|
+
// --------------------------------------------------------------------------------------------------
|
|
561
|
+
// ==================================================================================================
|
|
562
|
+
private resolveByName(name: string): _EntityType[number] | InstanceType<_ComponentType[number]> | _FragmentType[number] | InstanceType<_CommandType[number]> {
|
|
563
|
+
// 1) Check components
|
|
564
|
+
const component = Array.from(this.allowedComponents).find(
|
|
565
|
+
c => c.name === name
|
|
566
|
+
|| c.name === A_CommonHelper.toPascalCase(name)
|
|
567
|
+
);
|
|
568
|
+
if (component) return this.resolveOnce(component) as InstanceType<_ComponentType[number]>;
|
|
569
|
+
|
|
570
|
+
// 2) Check entities
|
|
571
|
+
const entity = Array.from(this.allowedEntities).find(
|
|
572
|
+
e => e.name === name
|
|
573
|
+
|| e.name === A_CommonHelper.toPascalCase(name)
|
|
574
|
+
|| (e as any).entity === name
|
|
575
|
+
|| (e as any).entity === A_CommonHelper.toKebabCase(name)
|
|
576
|
+
);
|
|
577
|
+
if (entity) return this.resolveOnce(entity) as _EntityType[number];
|
|
578
|
+
|
|
579
|
+
// 3) Check commands
|
|
580
|
+
const command = Array.from(this.allowedCommands).find(c => (c as any).code === name
|
|
581
|
+
|| (c as any).name === A_CommonHelper.toPascalCase(name)
|
|
582
|
+
|| (c as any).code === A_CommonHelper.toKebabCase(name)
|
|
583
|
+
);
|
|
584
|
+
if (command) return this.resolveOnce(command) as InstanceType<_CommandType[number]>;
|
|
412
585
|
|
|
413
|
-
// Check
|
|
414
|
-
const
|
|
415
|
-
|
|
586
|
+
// 4) Check fragments
|
|
587
|
+
const fragment = Array.from(this.allowedFragments).find(f => f.name === name
|
|
588
|
+
|| f.name === A_CommonHelper.toPascalCase(name)
|
|
589
|
+
);
|
|
590
|
+
if (fragment) return this.resolveOnce(fragment) as _FragmentType[number];
|
|
416
591
|
|
|
417
592
|
// If not found in current scope, check parent scope
|
|
418
|
-
if (this._parent) {
|
|
419
|
-
return this._parent.resolveByName(name);
|
|
593
|
+
if (!!this._parent) {
|
|
594
|
+
return this._parent.resolveByName(name) as any;
|
|
420
595
|
}
|
|
421
596
|
|
|
422
|
-
throw new Error(`Component
|
|
597
|
+
throw new Error(`Component or Entity with name ${name} not found in the scope ${this.name}`);
|
|
423
598
|
}
|
|
424
599
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
private resolveOnce<T extends
|
|
433
|
-
component:
|
|
434
|
-
): InstanceType<T>
|
|
435
|
-
private resolveOnce<T extends { new(...args: any[]): A_Entity } | A_TYPES__A_InjectDecorator_Injectable>(
|
|
436
|
-
component: T,
|
|
600
|
+
/**
|
|
601
|
+
* This method is used internally to resolve a single component, fragment or entity from the scope
|
|
602
|
+
*
|
|
603
|
+
* @param component
|
|
604
|
+
* @param instructions
|
|
605
|
+
* @returns
|
|
606
|
+
*/
|
|
607
|
+
private resolveOnce<T extends A_Component | A_Fragment | A_Entity | A_Command | A_Scope>(
|
|
608
|
+
component: unknown,
|
|
437
609
|
instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
|
|
438
|
-
):
|
|
610
|
+
): T | Array<T> {
|
|
439
611
|
|
|
612
|
+
if (this.isScopeConstructor(component))
|
|
613
|
+
component
|
|
614
|
+
|
|
615
|
+
if (typeof component == 'function' && (component as any).name === 'A_Scope')
|
|
616
|
+
component
|
|
440
617
|
|
|
441
618
|
switch (true) {
|
|
442
|
-
case
|
|
443
|
-
return this.resolveEntity(component
|
|
619
|
+
case this.isEntityConstructor(component): {
|
|
620
|
+
return this.resolveEntity(component, instructions) as T | Array<T>;
|
|
444
621
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
return this.resolveFragment(component as typeof A_Fragment) as InstanceType<T>;
|
|
622
|
+
case this.isFragmentConstructor(component): {
|
|
623
|
+
return this.resolveFragment(component) as T;
|
|
448
624
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
return this.resolveScope(component as typeof A_Scope) as InstanceType<T>;
|
|
625
|
+
case this.isCommandConstructor(component): {
|
|
626
|
+
return this.resolveCommand(component) as T;
|
|
452
627
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
628
|
+
case this.isScopeConstructor(component): {
|
|
629
|
+
return this.resolveScope(component) as T;
|
|
630
|
+
}
|
|
631
|
+
case this.isComponentConstructor(component): {
|
|
632
|
+
return this.resolveComponent(component) as T;
|
|
456
633
|
}
|
|
457
|
-
|
|
458
634
|
default:
|
|
459
635
|
throw new Error(`Injected Component ${component} not found in the scope`);
|
|
460
636
|
}
|
|
461
637
|
}
|
|
462
638
|
|
|
639
|
+
/**
|
|
640
|
+
* This method is used internally to resolve a single entity from the scope based on the provided instructions
|
|
641
|
+
*
|
|
642
|
+
* [!] Note that this method can return either a single entity or an array of entities depending on the instructions provided
|
|
643
|
+
*
|
|
644
|
+
* @param entity
|
|
645
|
+
* @param instructions
|
|
646
|
+
* @returns
|
|
647
|
+
*/
|
|
648
|
+
private resolveEntity<T extends A_Entity>(
|
|
649
|
+
entity: A_TYPES__AllowedEntitiesConstructor<T>,
|
|
650
|
+
instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions<T>>
|
|
651
|
+
): T | Array<T> | undefined {
|
|
463
652
|
|
|
464
|
-
|
|
465
|
-
entity: T,
|
|
466
|
-
instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions<InstanceType<T>>>
|
|
467
|
-
): InstanceType<T> | undefined | InstanceType<T>[] {
|
|
468
|
-
|
|
469
|
-
const query = instructions?.query || {} as Partial<A_TYPES__A_InjectDecorator_EntityInjectionQuery<InstanceType<T>>>;
|
|
653
|
+
const query = instructions?.query || {} as Partial<A_TYPES__A_InjectDecorator_EntityInjectionQuery<T>>;
|
|
470
654
|
const count = instructions?.pagination?.count || 1;
|
|
471
655
|
|
|
472
656
|
switch (true) {
|
|
657
|
+
/**
|
|
658
|
+
* 1) In case when no instructions provided, return the first found entity of the provided type
|
|
659
|
+
*
|
|
660
|
+
* [!] Note that it returns ONLY ONE entity
|
|
661
|
+
* [!!] In case when no entity found in the current scope, it tries to resolve it from the parent scope (if exists)
|
|
662
|
+
*/
|
|
473
663
|
case !instructions: {
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
const found = entities.find(e => e instanceof entity);
|
|
664
|
+
const found = this.entities.find(e => e instanceof entity);
|
|
477
665
|
|
|
478
666
|
switch (true) {
|
|
479
667
|
case !!found:
|
|
480
|
-
return found as
|
|
668
|
+
return found as T;
|
|
481
669
|
|
|
482
670
|
case !found && !!this._parent:
|
|
483
671
|
return this._parent.resolveEntity(entity, instructions);
|
|
@@ -486,74 +674,84 @@ export class A_Scope {
|
|
|
486
674
|
throw new Error(`Entity ${entity.name} not found in the scope ${this.name}`);
|
|
487
675
|
}
|
|
488
676
|
}
|
|
489
|
-
|
|
677
|
+
/**
|
|
678
|
+
* 2) In case when aseid is provided in the query, we can directly get the entity from the map
|
|
679
|
+
*
|
|
680
|
+
* [!] Note that it returns ONLY ONE entity
|
|
681
|
+
*/
|
|
490
682
|
case !!query.aseid
|
|
491
683
|
&& typeof query.aseid === 'string'
|
|
492
684
|
&& this._entities.has(query.aseid): {
|
|
493
|
-
return this._entities.get(query.aseid) as
|
|
685
|
+
return this._entities.get(query.aseid) as T;
|
|
494
686
|
}
|
|
495
|
-
|
|
687
|
+
/**
|
|
688
|
+
* 3) In case when aseid is provided as ASEID instance, we can directly get the entity from the map
|
|
689
|
+
*
|
|
690
|
+
* [!] Note that it returns ONLY ONE entity
|
|
691
|
+
*/
|
|
496
692
|
case !!query.aseid
|
|
497
693
|
&& typeof query.aseid === 'object'
|
|
498
694
|
&& query.aseid instanceof ASEID
|
|
499
695
|
&& this._entities.has(query.aseid.toString()): {
|
|
500
|
-
return this._entities.get(query.aseid.toString()) as
|
|
696
|
+
return this._entities.get(query.aseid.toString()) as T;
|
|
501
697
|
}
|
|
502
|
-
|
|
698
|
+
/**
|
|
699
|
+
* 4) In case when id is provided in the query, we have to find the entity by the id
|
|
700
|
+
*
|
|
701
|
+
* [!] Note that it returns ONLY ONE entity
|
|
702
|
+
*/
|
|
503
703
|
case !!query.id: {
|
|
504
704
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
const found = entities.filter(
|
|
509
|
-
e => e instanceof entity
|
|
510
|
-
).find(e => {
|
|
511
|
-
return String(e.id) === String(query.id)
|
|
512
|
-
});
|
|
705
|
+
const found = this.entities
|
|
706
|
+
.filter(e => e instanceof entity)
|
|
707
|
+
.find(e => String(e.id) === String(query.id));
|
|
513
708
|
|
|
514
|
-
return found as
|
|
709
|
+
return found as T;
|
|
515
710
|
}
|
|
516
|
-
|
|
711
|
+
/**
|
|
712
|
+
* 5) In case when there's a query object, we have to filter the entities by the query
|
|
713
|
+
*
|
|
714
|
+
* [!] Note that it can return either a single entity or an array of entities depending on the count instruction
|
|
715
|
+
* [!!] In case when no entity found in the current scope, it tries to resolve it from the parent scope (if exists)
|
|
716
|
+
*/
|
|
517
717
|
default: {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
e =>
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
718
|
+
|
|
719
|
+
const found = this.entities
|
|
720
|
+
.filter(e => e instanceof entity)
|
|
721
|
+
.filter(e => {
|
|
722
|
+
return Object
|
|
723
|
+
.entries(query)
|
|
724
|
+
.every(([key, value]) => {
|
|
725
|
+
if (key in e) {
|
|
726
|
+
return (e as any)[key] === value;
|
|
727
|
+
}
|
|
728
|
+
return false;
|
|
729
|
+
});
|
|
528
730
|
});
|
|
529
|
-
});
|
|
530
731
|
|
|
531
732
|
if (found.length === 0 && !!this._parent)
|
|
532
733
|
return this._parent.resolveEntity(entity, instructions);
|
|
533
734
|
|
|
534
735
|
if (count === 1)
|
|
535
|
-
return found[0] as
|
|
736
|
+
return found[0] as T;
|
|
536
737
|
|
|
537
|
-
return found as
|
|
738
|
+
return found as T[];
|
|
538
739
|
}
|
|
539
|
-
|
|
540
740
|
}
|
|
541
741
|
}
|
|
542
742
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
743
|
+
/**
|
|
744
|
+
* This method is used internally to resolve a single fragment from the scope
|
|
745
|
+
*
|
|
746
|
+
* @param fragment
|
|
747
|
+
* @returns
|
|
748
|
+
*/
|
|
749
|
+
private resolveFragment<T extends A_Fragment>(fragment: A_TYPES__AllowedFragmentsConstructor<T>): _FragmentType[number] {
|
|
750
|
+
const fragmentInstancePresented = this._fragments.get(fragment);
|
|
549
751
|
|
|
550
752
|
switch (true) {
|
|
551
|
-
|
|
552
753
|
case fragmentInstancePresented && this._fragments.has(fragment):
|
|
553
|
-
return
|
|
554
|
-
|
|
555
|
-
case fragmentInstancePresented && !this._fragments.has(fragment):
|
|
556
|
-
return this.fragments.find(fr => fr instanceof fragment) as InstanceType<T>;
|
|
754
|
+
return fragmentInstancePresented;
|
|
557
755
|
|
|
558
756
|
case !fragmentInstancePresented && !!this._parent:
|
|
559
757
|
return this._parent.resolveFragment(fragment);
|
|
@@ -562,28 +760,34 @@ export class A_Scope {
|
|
|
562
760
|
throw new Error(`Fragment ${fragment.name} not found in the scope ${this.name}`);
|
|
563
761
|
}
|
|
564
762
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
763
|
+
/**
|
|
764
|
+
* This method is used internally to resolve a single scope from the current scope
|
|
765
|
+
*
|
|
766
|
+
* @param scope
|
|
767
|
+
* @returns
|
|
768
|
+
*/
|
|
769
|
+
private resolveScope(scope: A_TYPES__AllowedScopesConstructor): A_Scope {
|
|
568
770
|
return this;
|
|
569
771
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
772
|
+
/**
|
|
773
|
+
* This method is used internally to resolve a single component from the scope
|
|
774
|
+
*
|
|
775
|
+
* @param component
|
|
776
|
+
* @returns
|
|
777
|
+
*/
|
|
778
|
+
private resolveComponent<T extends A_Component>(component: A_TYPES__AllowedComponentsConstructor<T>): InstanceType<_ComponentType[number]> {
|
|
575
779
|
|
|
576
780
|
// The idea here that in case when Scope has no exact component we have to resolve it from the _parent
|
|
577
781
|
// BUT: if it's not presented in _parent we have to check for inheritance
|
|
578
782
|
// That means that we should ensure that there's no components that are children of the required component
|
|
579
783
|
switch (true) {
|
|
580
|
-
// In case when the component is available and exists in the scope
|
|
581
|
-
case this.
|
|
582
|
-
return this._components.get(component)
|
|
784
|
+
// 1) In case when the component is available and exists in the scope
|
|
785
|
+
case this.allowedComponents.has(component) && this._components.has(component): {
|
|
786
|
+
return this._components.get(component)!;
|
|
583
787
|
}
|
|
584
788
|
|
|
585
|
-
// In case the component available but does NOT exist in the scope
|
|
586
|
-
case this.
|
|
789
|
+
// 2) In case the component available but does NOT exist in the scope
|
|
790
|
+
case this.allowedComponents.has(component) && !this._components.has(component): {
|
|
587
791
|
const componentMeta = A_Context.meta(component)
|
|
588
792
|
|
|
589
793
|
const argsMeta = componentMeta.get(A_TYPES__ComponentMetaKey.INJECTIONS);
|
|
@@ -597,53 +801,48 @@ export class A_Scope {
|
|
|
597
801
|
instructions
|
|
598
802
|
);
|
|
599
803
|
}
|
|
600
|
-
|
|
804
|
+
// TODO: Fix types mismatch here
|
|
805
|
+
return this.resolve<T>(arg.target as any);
|
|
601
806
|
});
|
|
602
807
|
|
|
603
808
|
const newComponent = new component(...resolvedArgs)
|
|
604
809
|
|
|
605
810
|
this.register(newComponent);
|
|
606
811
|
|
|
607
|
-
return this._components.get(component)
|
|
812
|
+
return this._components.get(component)!;
|
|
608
813
|
}
|
|
609
814
|
|
|
610
|
-
// In case when there's a component that is inherited from the required component
|
|
611
|
-
case !this.
|
|
612
|
-
|
|
613
|
-
const found = this.components.find(el => A_CommonHelper.isInheritedFrom(el, component));
|
|
815
|
+
// 3) In case when there's a component that is inherited from the required component
|
|
816
|
+
case !this.allowedComponents.has(component) && Array.from(this.allowedComponents).some(el => A_CommonHelper.isInheritedFrom(el, component)): {
|
|
817
|
+
const found = Array.from(this.allowedComponents).find(el => A_CommonHelper.isInheritedFrom(el, component))!;
|
|
614
818
|
|
|
615
|
-
return this.resolveComponent
|
|
819
|
+
return this.resolveComponent(found);
|
|
616
820
|
}
|
|
617
821
|
|
|
618
|
-
// In case when the component is not available in the scope but the _parent is available
|
|
619
|
-
case
|
|
620
|
-
return this._parent.resolveComponent(component)
|
|
822
|
+
// 4) In case when the component is not available in the scope but the _parent is available
|
|
823
|
+
case !!this._parent: {
|
|
824
|
+
return this._parent.resolveComponent(component) as InstanceType<_ComponentType[number]>;
|
|
621
825
|
}
|
|
622
826
|
|
|
623
827
|
default:
|
|
624
828
|
throw new Error(`Component ${component.name} not found in the scope ${this.name}`);
|
|
625
829
|
}
|
|
626
830
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
831
|
/**
|
|
630
832
|
* Should be similar to resolveEntity but for commands
|
|
631
833
|
*
|
|
632
834
|
* @param command
|
|
633
835
|
*/
|
|
634
|
-
private resolveCommand
|
|
635
|
-
new(...args: any[]): T
|
|
636
|
-
}): T {
|
|
637
|
-
const commands = Array.from(this._commands.values());
|
|
836
|
+
private resolveCommand(command: _CommandType[number]): InstanceType<_CommandType[number]> {
|
|
638
837
|
|
|
639
|
-
const found = commands.find(e => e instanceof command);
|
|
838
|
+
const found = this.commands.find(e => e instanceof command);
|
|
640
839
|
|
|
641
840
|
switch (true) {
|
|
642
841
|
case !!found:
|
|
643
|
-
return found
|
|
842
|
+
return found
|
|
644
843
|
|
|
645
844
|
case !found && !!this._parent:
|
|
646
|
-
return this._parent.resolveCommand(command)
|
|
845
|
+
return this._parent.resolveCommand(command) as InstanceType<_CommandType[number]>;
|
|
647
846
|
|
|
648
847
|
default:
|
|
649
848
|
throw new Error(`Command ${command.name} not found in the scope ${this.name}`);
|
|
@@ -657,86 +856,137 @@ export class A_Scope {
|
|
|
657
856
|
*
|
|
658
857
|
* @param fragment
|
|
659
858
|
*/
|
|
660
|
-
register<T extends A_Component>(
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
859
|
+
register<T extends A_Component>(
|
|
860
|
+
/**
|
|
861
|
+
* Provide a component constructor to register it in the scope
|
|
862
|
+
*/
|
|
863
|
+
component: A_TYPES__AllowedComponentsConstructor<T>
|
|
864
|
+
): void
|
|
865
|
+
register<T extends A_Entity>(
|
|
866
|
+
/**
|
|
867
|
+
* Provide an entity constructor to register it in the scope
|
|
868
|
+
*/
|
|
869
|
+
entity: A_TYPES__AllowedEntitiesConstructor<T>
|
|
870
|
+
): void
|
|
871
|
+
register<T extends A_Command>(
|
|
872
|
+
/**
|
|
873
|
+
* Provide a command constructor to register it in the scope
|
|
874
|
+
*/
|
|
875
|
+
command: A_TYPES__AllowedCommandsConstructor<T>
|
|
876
|
+
): void
|
|
877
|
+
register<T extends A_Fragment>(
|
|
878
|
+
/**
|
|
879
|
+
* Provide a command instance to register it in the scope
|
|
880
|
+
*/
|
|
881
|
+
fragment: A_TYPES__AllowedFragmentsConstructor<T>
|
|
882
|
+
): void
|
|
666
883
|
register(
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
884
|
+
/**
|
|
885
|
+
* Provide an entity instance to register it in the scope
|
|
886
|
+
*/
|
|
887
|
+
entity: A_Entity
|
|
888
|
+
): void
|
|
889
|
+
register(
|
|
890
|
+
/**
|
|
891
|
+
* Provide a command instance to register it in the scope
|
|
892
|
+
*/
|
|
893
|
+
component: A_Component
|
|
894
|
+
): void
|
|
895
|
+
register(
|
|
896
|
+
/**
|
|
897
|
+
* Provide a command instance to register it in the scope
|
|
898
|
+
*/
|
|
899
|
+
command: A_Command
|
|
900
|
+
): void
|
|
901
|
+
register(
|
|
902
|
+
/**
|
|
903
|
+
* Provide a fragment instance to register it in the scope
|
|
904
|
+
*/
|
|
905
|
+
fragment: A_Fragment
|
|
906
|
+
): void
|
|
907
|
+
register(
|
|
908
|
+
param1: unknown
|
|
673
909
|
): void {
|
|
674
910
|
switch (true) {
|
|
675
|
-
|
|
676
|
-
|
|
911
|
+
// ------------------------------------------
|
|
912
|
+
// ------------ Instances ----------------
|
|
913
|
+
// ------------------------------------------
|
|
914
|
+
// 1) In case when it's a A-Component instance
|
|
915
|
+
case param1 instanceof A_Component: {
|
|
677
916
|
|
|
678
|
-
|
|
917
|
+
if (!this.allowedComponents.has(param1.constructor as _ComponentType[number]))
|
|
918
|
+
this.allowedComponents.add(param1.constructor as _ComponentType[number]);
|
|
679
919
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
920
|
+
this._components.set(
|
|
921
|
+
param1.constructor as _ComponentType[number],
|
|
922
|
+
param1 as InstanceType<_ComponentType[number]>
|
|
923
|
+
);
|
|
683
924
|
|
|
684
925
|
A_Context.register(this, param1);
|
|
926
|
+
|
|
685
927
|
break;
|
|
686
928
|
}
|
|
929
|
+
// 2) In case when it's a A-Command instance
|
|
930
|
+
case param1 instanceof A_Command: {
|
|
931
|
+
|
|
932
|
+
if (!this.allowedCommands.has(param1.constructor as _CommandType[number]))
|
|
933
|
+
this.allowedCommands.add(param1.constructor as _CommandType[number]);
|
|
934
|
+
|
|
935
|
+
this._commands.set((param1 as any).constructor.code, param1 as InstanceType<_CommandType[number]>);
|
|
687
936
|
|
|
688
|
-
case param1 instanceof A_Entity && !this._entities.has(param1.aseid.toString()): {
|
|
689
|
-
this._entities.set(param1.aseid.toString(), param1);
|
|
690
937
|
A_Context.register(this, param1);
|
|
691
938
|
break;
|
|
692
939
|
}
|
|
940
|
+
// 3) In case when it's a A-Entity instance
|
|
941
|
+
case param1 instanceof A_Entity && !this._entities.has(param1.aseid.toString()): {
|
|
693
942
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
if (!allowedFragment) {
|
|
698
|
-
this.fragments.push(param1);
|
|
699
|
-
}
|
|
943
|
+
if (!this.allowedEntities.has(param1.constructor as A_TYPES__AllowedEntitiesConstructor<_EntityType[number]>))
|
|
944
|
+
this.allowedEntities.add(param1.constructor as A_TYPES__AllowedEntitiesConstructor<_EntityType[number]>);
|
|
700
945
|
|
|
701
|
-
this.
|
|
946
|
+
this._entities.set(param1.aseid.toString(), param1);
|
|
702
947
|
A_Context.register(this, param1);
|
|
703
948
|
break;
|
|
704
949
|
}
|
|
950
|
+
// 4) In case when it's a A-Fragment instance
|
|
951
|
+
case param1 instanceof A_Fragment: {
|
|
705
952
|
|
|
706
|
-
|
|
707
|
-
|
|
953
|
+
if (!this.allowedFragments.has(param1.constructor as A_TYPES__AllowedFragmentsConstructor<_FragmentType[number]>))
|
|
954
|
+
this.allowedFragments.add(param1.constructor as A_TYPES__AllowedFragmentsConstructor<_FragmentType[number]>);
|
|
708
955
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
956
|
+
this._fragments.set(
|
|
957
|
+
param1.constructor as A_TYPES__AllowedFragmentsConstructor<_FragmentType[number]>,
|
|
958
|
+
param1 as _FragmentType[number]
|
|
959
|
+
);
|
|
714
960
|
|
|
715
961
|
A_Context.register(this, param1);
|
|
962
|
+
|
|
716
963
|
break;
|
|
717
964
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
965
|
+
// ------------------------------------------
|
|
966
|
+
// ------------ Constructors ----------------
|
|
967
|
+
// ------------------------------------------
|
|
968
|
+
// 5) In case when it's a A-Component constructor
|
|
969
|
+
case this.isComponentConstructor(param1): {
|
|
970
|
+
if (!this.allowedComponents.has(param1))
|
|
971
|
+
this.allowedComponents.add(param1 as _ComponentType[number]);
|
|
724
972
|
break;
|
|
725
973
|
}
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
this.params.entities.push(new (param1 as any)());
|
|
731
|
-
}
|
|
974
|
+
// 6) In case when it's a A-Command constructor
|
|
975
|
+
case this.isCommandConstructor(param1): {
|
|
976
|
+
if (!this.allowedCommands.has(param1))
|
|
977
|
+
this.allowedCommands.add(param1 as _CommandType[number]);
|
|
732
978
|
break;
|
|
733
979
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
980
|
+
// 7) In case when it's a A-Fragment constructor
|
|
981
|
+
case this.isFragmentConstructor(param1): {
|
|
982
|
+
if (!this.allowedFragments.has(param1))
|
|
983
|
+
this.allowedFragments.add(param1 as A_TYPES__AllowedFragmentsConstructor<_FragmentType[number]>);
|
|
984
|
+
break;
|
|
985
|
+
}
|
|
986
|
+
// 8) In case when it's a A-Entity constructor
|
|
987
|
+
case this.isEntityConstructor(param1): {
|
|
988
|
+
if (!this.allowedEntities.has(param1))
|
|
989
|
+
this.allowedEntities.add(param1 as A_TYPES__AllowedEntitiesConstructor<_EntityType[number]>);
|
|
740
990
|
break;
|
|
741
991
|
}
|
|
742
992
|
|
|
@@ -748,23 +998,182 @@ export class A_Scope {
|
|
|
748
998
|
else
|
|
749
999
|
throw new Error(`Cannot register ${param1} in the scope ${this.name}`);
|
|
750
1000
|
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
|
|
751
1005
|
|
|
1006
|
+
/**
|
|
1007
|
+
* This method is useful when you want to serialize the scope to JSON
|
|
1008
|
+
*
|
|
1009
|
+
* [!] Note this is not a deep serialization, only the fragments are serialized
|
|
1010
|
+
* [!] Fragments are a storage for information which is relevant to the scope
|
|
1011
|
+
*
|
|
1012
|
+
* @returns
|
|
1013
|
+
*/
|
|
1014
|
+
toJSON(): Record<string, any> {
|
|
1015
|
+
return this.fragments
|
|
1016
|
+
.reduce((acc, fragment) => {
|
|
752
1017
|
|
|
1018
|
+
const serialized = fragment.toJSON()
|
|
753
1019
|
|
|
1020
|
+
return {
|
|
1021
|
+
...acc,
|
|
1022
|
+
[serialized.name]: serialized
|
|
1023
|
+
}
|
|
1024
|
+
}, {});
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
//==========================================================================
|
|
1030
|
+
// --------------------Scope Type Check Helpers---------------------------
|
|
1031
|
+
//==========================================================================
|
|
1032
|
+
/**
|
|
1033
|
+
* Type guard to check if the constructor is of type A_Component
|
|
1034
|
+
*
|
|
1035
|
+
* @param ctor
|
|
1036
|
+
* @returns
|
|
1037
|
+
*/
|
|
1038
|
+
protected isComponentConstructor(ctor: unknown): ctor is A_TYPES__AllowedComponentsConstructor {
|
|
1039
|
+
return typeof ctor === 'function' && A_CommonHelper.isInheritedFrom(ctor, A_Component);
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Type guard to check if the constructor is of type A_Command
|
|
1043
|
+
*
|
|
1044
|
+
* @param ctor
|
|
1045
|
+
* @returns
|
|
1046
|
+
*/
|
|
1047
|
+
protected isCommandConstructor(ctor: unknown): ctor is A_TYPES__AllowedCommandsConstructor {
|
|
1048
|
+
return typeof ctor === 'function' && A_CommonHelper.isInheritedFrom(ctor, A_Command);
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Type guard to check if the constructor is of type A_Fragment
|
|
1052
|
+
*
|
|
1053
|
+
* @param ctor
|
|
1054
|
+
* @returns
|
|
1055
|
+
*/
|
|
1056
|
+
protected isFragmentConstructor(ctor: any): ctor is A_TYPES__AllowedFragmentsConstructor {
|
|
1057
|
+
return typeof ctor === 'function' && A_CommonHelper.isInheritedFrom(ctor, A_Fragment);
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Type guard to check if the constructor is of type A_Entity
|
|
1061
|
+
*
|
|
1062
|
+
* @param ctor
|
|
1063
|
+
* @returns
|
|
1064
|
+
*/
|
|
1065
|
+
protected isEntityConstructor(ctor: unknown): ctor is A_TYPES__AllowedEntitiesConstructor {
|
|
1066
|
+
return typeof ctor === 'function' && A_CommonHelper.isInheritedFrom(ctor, A_Entity);
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Type guard to check if the constructor is of type A_Scope
|
|
1070
|
+
*
|
|
1071
|
+
* @param ctor
|
|
1072
|
+
* @returns
|
|
1073
|
+
*/
|
|
1074
|
+
protected isScopeConstructor(ctor: unknown): ctor is A_TYPES__AllowedScopesConstructor {
|
|
1075
|
+
return typeof ctor === 'function' && A_CommonHelper.isInheritedFrom(ctor, A_Scope);
|
|
1076
|
+
}
|
|
1077
|
+
// -------------------------------------------------------------------------------
|
|
1078
|
+
// --------------------Scope Allowed Type Check Helpers---------------------------
|
|
1079
|
+
// -------------------------------------------------------------------------------
|
|
1080
|
+
/**
|
|
1081
|
+
* Type guard to check if the constructor is of type A_Component and is allowed in the scope
|
|
1082
|
+
*
|
|
1083
|
+
* @param ctor
|
|
1084
|
+
* @returns
|
|
1085
|
+
*/
|
|
1086
|
+
protected isAllowedComponent(ctor: unknown): ctor is _ComponentType[number] {
|
|
1087
|
+
return this.isComponentConstructor(ctor) && this.allowedComponents.has(ctor);
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Type guard to check if the constructor is of type A_Command and is allowed in the scope
|
|
1091
|
+
*
|
|
1092
|
+
* @param ctor
|
|
1093
|
+
* @returns
|
|
1094
|
+
*/
|
|
1095
|
+
protected isAllowedCommand(ctor: unknown): ctor is _CommandType[number] {
|
|
1096
|
+
return this.isCommandConstructor(ctor) && this.allowedCommands.has(ctor);
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Type guard to check if the constructor is of type A_Entity and is allowed in the scope
|
|
1100
|
+
*
|
|
1101
|
+
* @param ctor
|
|
1102
|
+
* @returns
|
|
1103
|
+
*/
|
|
1104
|
+
protected isAllowedEntity(ctor: unknown): ctor is A_TYPES__AllowedEntitiesConstructor<_EntityType[number]> {
|
|
1105
|
+
return this.isEntityConstructor(ctor) && this.allowedEntities.has(ctor);
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Type guard to check if the constructor is of type A_Fragment and is allowed in the scope
|
|
1109
|
+
*
|
|
1110
|
+
* @param ctor
|
|
1111
|
+
* @returns
|
|
1112
|
+
*/
|
|
1113
|
+
protected isAllowedFragment(ctor: unknown): ctor is A_TYPES__AllowedFragmentsConstructor<_FragmentType[number]> {
|
|
1114
|
+
return this.isFragmentConstructor(ctor) && this.allowedFragments.has(ctor);
|
|
754
1115
|
}
|
|
755
1116
|
|
|
756
1117
|
|
|
757
1118
|
|
|
758
1119
|
|
|
759
|
-
|
|
760
|
-
|
|
1120
|
+
// ==========================================================================
|
|
1121
|
+
// --------------------DEBUG & Helpers Methods--------------------------------
|
|
1122
|
+
// ===========================================================================
|
|
1123
|
+
/**
|
|
1124
|
+
* This method is used to check if the scope is inherited from another scope
|
|
1125
|
+
*
|
|
1126
|
+
* @param scope
|
|
1127
|
+
* @returns
|
|
1128
|
+
*/
|
|
1129
|
+
isInheritedFrom(scope: A_Scope): boolean {
|
|
1130
|
+
let current: A_Scope | undefined = this;
|
|
761
1131
|
|
|
762
|
-
|
|
1132
|
+
while (current) {
|
|
1133
|
+
if (current === scope) {
|
|
1134
|
+
return true;
|
|
1135
|
+
}
|
|
1136
|
+
current = current._parent;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
return false;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* Helper method to check circular inheritance
|
|
1144
|
+
* Should return a full sequence of inheritance for logging purposes
|
|
1145
|
+
*
|
|
1146
|
+
* @param scope
|
|
1147
|
+
* @returns
|
|
1148
|
+
*/
|
|
1149
|
+
checkCircularInheritance(scope: A_Scope): Array<string> | false {
|
|
1150
|
+
const inheritanceChain: Array<string> = [];
|
|
1151
|
+
let current: A_Scope | undefined = this._parent;
|
|
763
1152
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
1153
|
+
while (current) {
|
|
1154
|
+
inheritanceChain.push(current.name);
|
|
1155
|
+
if (current === scope) {
|
|
1156
|
+
return inheritanceChain;
|
|
767
1157
|
}
|
|
768
|
-
|
|
1158
|
+
current = current._parent;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
return false;
|
|
769
1162
|
}
|
|
770
|
-
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Helper method to print the inheritance chain of the scope
|
|
1166
|
+
*/
|
|
1167
|
+
printInheritanceChain(): void {
|
|
1168
|
+
const chain: Array<string> = [];
|
|
1169
|
+
let current: A_Scope | undefined = this;
|
|
1170
|
+
|
|
1171
|
+
while (current) {
|
|
1172
|
+
chain.push(current.name);
|
|
1173
|
+
current = current._parent;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
console.log(chain.join(' -> '));
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|