@teqfw/di 0.7.0 → 0.11.0
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/README.md +7 -4
- package/RELEASE.md +24 -0
- package/bin/release/clean.sh +11 -0
- package/package.json +3 -3
- package/src/Back/Api/Dto/Plugin/Desc.mjs +29 -14
- package/src/Shared/Api/IProxy.mjs +11 -0
- package/src/Shared/Container.mjs +26 -11
- package/src/Shared/IdParser/Dto.mjs +5 -0
- package/src/Shared/IdParser.mjs +70 -26
- package/src/Shared/SpecProxy.mjs +4 -4
- package/src/Shared/Api/Dto/Plugin/Desc/Replace.mjs +0 -63
package/README.md
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
"_DI_" means both "_Dynamic Import_" and "_Dependency Injection_" here. This package allows defining logical namespaces
|
|
4
4
|
in your projects, dynamically importing ES6-modules from these namespaces, creating new objects from imported
|
|
5
5
|
functions/classes and resolving dependencies in constructors. It uses pure ECMAScript 2015+ (ES6+) and works both for
|
|
6
|
-
modern browsers & nodejs apps. You can share the same code between your frontend (browser) and your backend (nodejs)
|
|
6
|
+
modern browsers & nodejs apps. You can share the same code between your frontend (browser) and your backend (nodejs)
|
|
7
|
+
without TypeScript and preprocessors. Code in the browser's debugger will be the same as in your editor. Finally, you
|
|
8
|
+
even can use interfaces in you projects and replace it with implementations.
|
|
7
9
|
|
|
8
|
-
The '_proxy object_' for `constructor` specification is inspired by [awilix](https://github.com/jeffijoe/awilix).
|
|
9
|
-
|
|
10
|
+
The '_proxy object_' for `constructor` specification is inspired by [awilix](https://github.com/jeffijoe/awilix). Thanks
|
|
11
|
+
guys.
|
|
10
12
|
|
|
11
13
|
## Installation
|
|
12
14
|
|
|
@@ -36,7 +38,8 @@ import ScanData from '../Api/Dto/Scanned.mjs';
|
|
|
36
38
|
import {existsSync, readdirSync, readFileSync, statSync} from 'fs';
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
but DI container cannot process these imports. Function or class should have this interface to be compatible with DI
|
|
41
|
+
but DI container cannot process these imports. Function or class should have this interface to be compatible with DI
|
|
42
|
+
container:
|
|
40
43
|
|
|
41
44
|
```ecmascript 6
|
|
42
45
|
export default function ObjectFactory(spec) {/* ... */}
|
package/RELEASE.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @teqfw/di releases
|
|
2
|
+
|
|
3
|
+
## 0.11.0
|
|
4
|
+
|
|
5
|
+
* Restructure `/@teqfw/di/replace` node in `teqfw.json`.
|
|
6
|
+
* Remove `TeqFw_Di_Shared_Api_Enum_Area` enumeration.
|
|
7
|
+
* Fix example code (`npm run example`).
|
|
8
|
+
|
|
9
|
+
## 0.10.0
|
|
10
|
+
|
|
11
|
+
* Improve error messaging.
|
|
12
|
+
* Use '.' instead of '#' in depIDs (Vnd_Plugin#export => Vnd_Plugin.export). Both variants are available for now.
|
|
13
|
+
* Experimental proxy for deps are added (Vnd_Plugin.export@@).
|
|
14
|
+
|
|
15
|
+
## 0.9.0
|
|
16
|
+
|
|
17
|
+
* `TeqFw_Di_Shared_Api_Enum_Area` enumeration is added;
|
|
18
|
+
|
|
19
|
+
## 0.8.0
|
|
20
|
+
|
|
21
|
+
* docs for plugin's teq-descriptor (see in `main` branch);
|
|
22
|
+
* use object notation instead of array notation in namespace replacement statements of
|
|
23
|
+
teq-descriptor (`@teqfw/di.replace` node format is changed in `./teqfw.json`);
|
|
24
|
+
* array is used as a container for upline dependencies in [SpecProxy](./src/Shared/SpecProxy.mjs) (object was);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
##
|
|
3
|
+
# Clean development files from release branch
|
|
4
|
+
##
|
|
5
|
+
DIR_ROOT=${DIR_ROOT:-$(cd "$(dirname "$0")/../../" && pwd)}
|
|
6
|
+
|
|
7
|
+
rm -fr "${DIR_ROOT}/doc/"
|
|
8
|
+
rm -fr "${DIR_ROOT}/node_modules/"
|
|
9
|
+
rm -fr "${DIR_ROOT}/package-lock.json"
|
|
10
|
+
rm -fr "${DIR_ROOT}/test/"
|
|
11
|
+
rm -fr "${DIR_ROOT}/tmp/"
|
package/package.json
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teqfw/di",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Dependency Injection container based on logical namespaces for ES6 modules.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "src/Shared/Container.mjs",
|
|
7
5
|
"keywords": [
|
|
8
6
|
"dependency injection",
|
|
9
7
|
"di",
|
|
@@ -23,6 +21,8 @@
|
|
|
23
21
|
"email": "alex@flancer64.com",
|
|
24
22
|
"url": "https://github.com/flancer64"
|
|
25
23
|
},
|
|
24
|
+
"main": "src/Shared/Container.mjs",
|
|
25
|
+
"type": "module",
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
|
28
28
|
"url": "git+https://github.com/teqfw/di.git"
|
|
@@ -9,7 +9,12 @@ const NS = 'TeqFw_Di_Back_Api_Dto_Plugin_Desc';
|
|
|
9
9
|
export default class TeqFw_Di_Back_Api_Dto_Plugin_Desc {
|
|
10
10
|
/** @type {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload} */
|
|
11
11
|
autoload;
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Replacements for IDs:
|
|
14
|
+
* - {'Interface_Name': 'Impl_Name'}: replace es6-module 'Interface_Name' with 'Impl_Name' on injection;
|
|
15
|
+
* - {'front': {'Interface_Name': 'Impl_Name'}}: do the same for 'front' area only (should be implemented outside this plugin)
|
|
16
|
+
* @type {Object<string, string>|Object<string, Object<string, string>>}
|
|
17
|
+
*/
|
|
13
18
|
replace;
|
|
14
19
|
}
|
|
15
20
|
|
|
@@ -23,27 +28,37 @@ TeqFw_Di_Back_Api_Dto_Plugin_Desc.REPLACE = 'replace';
|
|
|
23
28
|
*/
|
|
24
29
|
export class Factory {
|
|
25
30
|
constructor(spec) {
|
|
26
|
-
// EXTRACT DEPS
|
|
27
|
-
/** @type {typeof TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload} */
|
|
28
|
-
const TAutoload = spec['TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload#'];
|
|
29
31
|
/** @type {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload.Factory} */
|
|
30
32
|
const fAutoload = spec['TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload#Factory$'];
|
|
31
|
-
/** @type {typeof TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace} */
|
|
32
|
-
const TReplace = spec['TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace#'];
|
|
33
|
-
/** @type {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace.Factory} */
|
|
34
|
-
const fReplace = spec['TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace#Factory$'];
|
|
35
33
|
|
|
36
34
|
/**
|
|
37
|
-
* @param {
|
|
35
|
+
* @param {*} data
|
|
38
36
|
* @return {TeqFw_Di_Back_Api_Dto_Plugin_Desc}
|
|
39
37
|
*/
|
|
40
38
|
this.create = function (data = null) {
|
|
39
|
+
|
|
40
|
+
// DEFINE INNER FUNCTIONS
|
|
41
|
+
function parseReplace(data) {
|
|
42
|
+
const res = {};
|
|
43
|
+
if (typeof data === 'object')
|
|
44
|
+
for (const ns of Object.keys(data)) {
|
|
45
|
+
const node = data[ns];
|
|
46
|
+
if (typeof node === 'string') {
|
|
47
|
+
res[ns] = data[ns]; // {"interface": "impl"}
|
|
48
|
+
} else if (typeof node === 'object') {
|
|
49
|
+
res[ns] = {}; // {"interface": {"area": "impl"}}
|
|
50
|
+
for (const area of Object.keys(node))
|
|
51
|
+
if (typeof node[area] === 'string')
|
|
52
|
+
res[ns][area] = node[area];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return res;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// MAIN FUNCTIONALITY
|
|
41
59
|
const res = new TeqFw_Di_Back_Api_Dto_Plugin_Desc();
|
|
42
|
-
res.autoload = (data?.autoload
|
|
43
|
-
|
|
44
|
-
res.replace = Array.isArray(data?.replace)
|
|
45
|
-
? data.replace.map((one) => (one instanceof TReplace) ? one : fReplace.create(one))
|
|
46
|
-
: [];
|
|
60
|
+
res.autoload = fAutoload.create(data?.autoload);
|
|
61
|
+
res.replace = parseReplace(data?.replace);
|
|
47
62
|
return res;
|
|
48
63
|
}
|
|
49
64
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for proxy factory to create objects using 'Vnd_Plugin_Single@' & 'Vnd_Plugin_Obj@@' dependency ID.
|
|
3
|
+
* @interface
|
|
4
|
+
*/
|
|
5
|
+
export default class TeqFw_Di_Shared_Api_IProxy {
|
|
6
|
+
/**
|
|
7
|
+
* Get target object asynchronously.
|
|
8
|
+
* @return {Promise<*>}
|
|
9
|
+
*/
|
|
10
|
+
get create() { }
|
|
11
|
+
}
|
package/src/Shared/Container.mjs
CHANGED
|
@@ -50,11 +50,14 @@ export default class TeqFw_Di_Shared_Container {
|
|
|
50
50
|
singletons.set('container', this); // as singleton
|
|
51
51
|
singletons.set('TeqFw_Di_Shared_Container', this); // as singleton of the class
|
|
52
52
|
|
|
53
|
+
// pin itself for nested functions
|
|
54
|
+
const me = this;
|
|
55
|
+
|
|
53
56
|
/**
|
|
54
57
|
* Internal function to get/create object|function|class|module by given `id`.
|
|
55
58
|
*
|
|
56
59
|
* @param {string} mainId main object ID (singleton, module, new object, default export singleton)
|
|
57
|
-
* @param {
|
|
60
|
+
* @param {string[]} uplineDeps dependencies registry to prevent circular loop.
|
|
58
61
|
* @returns {Promise<*>}
|
|
59
62
|
*/
|
|
60
63
|
async function getObject(mainId, uplineDeps) {
|
|
@@ -122,7 +125,7 @@ export default class TeqFw_Di_Shared_Container {
|
|
|
122
125
|
// try to create object and start chain of deps resolving in SpecProxy
|
|
123
126
|
fnCreate();
|
|
124
127
|
} else {
|
|
125
|
-
throw new Error(
|
|
128
|
+
throw new Error(`Unexpected type of factory function for '${mainId}'.`);
|
|
126
129
|
}
|
|
127
130
|
// `resolve` for this promise is called from fnCreate
|
|
128
131
|
// (fnCreate is recalled from spec proxy on every dep failure)
|
|
@@ -165,7 +168,7 @@ export default class TeqFw_Di_Shared_Container {
|
|
|
165
168
|
const parsed = $parser.parse(mainId);
|
|
166
169
|
parsed.nameModule = checkReplacements(parsed.nameModule);
|
|
167
170
|
// try to find requested dependency in local storages
|
|
168
|
-
result = await getFromStorages(parsed);
|
|
171
|
+
if (!parsed.isProxy) result = await getFromStorages(parsed);
|
|
169
172
|
// if not found then try to load sources and create new one
|
|
170
173
|
if (result === undefined) {
|
|
171
174
|
// Sources for requested dependency are not imported or not set manually before.
|
|
@@ -181,13 +184,25 @@ export default class TeqFw_Di_Shared_Container {
|
|
|
181
184
|
// result as ES6 module export
|
|
182
185
|
result = module[parsed.nameExport];
|
|
183
186
|
} else {
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
// create new object (singleton or instance) using factory
|
|
188
|
+
if (parsed.isProxy) {
|
|
189
|
+
// we need to create proxy to resolve deps for the object later
|
|
190
|
+
const depId = parsed.orig.replace(/@/gi, '$');
|
|
191
|
+
result = new Proxy({dep: undefined, depId}, {
|
|
192
|
+
get: async function (base, name) {
|
|
193
|
+
if (name === 'create') base.dep = await me.get(base.depId);
|
|
194
|
+
return base.dep;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
} else {
|
|
198
|
+
// we need use module export as factory for new object or singleton for the first time
|
|
199
|
+
const factory = module[parsed.nameExport];
|
|
200
|
+
factories.set(parsed.mapKey, factory);
|
|
201
|
+
const object = await _useFactory(factory);
|
|
202
|
+
// save singleton object in container storage
|
|
203
|
+
if (parsed.typeTarget === ParsedId.TYPE_TARGET_SINGLETON) singletons.set(parsed.mapKey, object);
|
|
204
|
+
result = object;
|
|
205
|
+
}
|
|
191
206
|
}
|
|
192
207
|
}
|
|
193
208
|
return result;
|
|
@@ -252,7 +267,7 @@ export default class TeqFw_Di_Shared_Container {
|
|
|
252
267
|
* TODO: /bootstrap path, for example/).
|
|
253
268
|
*/
|
|
254
269
|
this.get = async function (depId, context = null) {
|
|
255
|
-
return await getObject(depId,
|
|
270
|
+
return await getObject(depId, []);
|
|
256
271
|
};
|
|
257
272
|
|
|
258
273
|
/**
|
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
* Structure to store parsing results of identifiers for imports and injects.
|
|
31
31
|
*/
|
|
32
32
|
export default class TeqFw_Di_Shared_IdParser_Dto {
|
|
33
|
+
/**
|
|
34
|
+
* 'true' if dependency should be a proxy.
|
|
35
|
+
* @type {boolean}
|
|
36
|
+
*/
|
|
37
|
+
isProxy;
|
|
33
38
|
/**
|
|
34
39
|
* Key to map object in container's store (singletons, constructors, modules) - original id w/o '$' chars.
|
|
35
40
|
* @type {string}
|
package/src/Shared/IdParser.mjs
CHANGED
|
@@ -2,12 +2,28 @@
|
|
|
2
2
|
import ParsedId from './IdParser/Dto.mjs';
|
|
3
3
|
|
|
4
4
|
// MODULE'S VARS
|
|
5
|
+
/** @type {string} default export keyword */
|
|
6
|
+
const DEF_EXP = 'default';
|
|
7
|
+
/** @type {string} logical namespace export mark (Ns_Mod.export) */
|
|
8
|
+
const EXP = '.';
|
|
9
|
+
/** @type {string} filesystem export mark (@vendor/package!module#export$$) and old logical export mark */
|
|
10
|
+
const EXP_OLD = '#';
|
|
5
11
|
/** @type {RegExp} expression for filepath based IDs (@vendor/package!module#export$$) */
|
|
6
12
|
const FILEPATH_ID = /^((([a-z@])([A-Za-z0-9_\-/@]*))(!([A-Za-z0-9_\-/@]*)?((#)?([A-Za-z0-9_]*)(\${1,2})?)?)?)$/;
|
|
13
|
+
/** @type {string} filesystem module mark (@vendor/package!module#export$$) */
|
|
14
|
+
const FSM = '!';
|
|
15
|
+
/** @type {string} new instance mark (Ns_Mod.export$$) */
|
|
16
|
+
const INST = '$$';
|
|
7
17
|
/** @type {RegExp} expression for logical namespace IDs (Ns_Module#export$$) */
|
|
8
|
-
const LOGICAL_NS_ID = /^((([A-Z])[A-Za-z0-9_]*)(
|
|
18
|
+
const LOGICAL_NS_ID = /^((([A-Z])[A-Za-z0-9_]*)((#|.)?([A-Za-z0-9_]*)(\${1,2}|@{1,2})?)?)$/;
|
|
9
19
|
/** @type {RegExp} expression for objects that manually added to DI container (singleton, namedFactory$$) */
|
|
10
20
|
const MANUAL_DI_ID = /^((([a-z])[A-Za-z0-9_]*)(\$\$)?)$/;
|
|
21
|
+
/** @type {string} new instance proxy mark (Ns_Mod.export@@) */
|
|
22
|
+
const P_INST = '@@';
|
|
23
|
+
/** @type {string} singleton proxy mark (Ns_Mod.export@) */
|
|
24
|
+
const P_SNGLT = '@';
|
|
25
|
+
/** @type {string} singleton mark (Ns_Mod.export$) */
|
|
26
|
+
const SNGLT = '$';
|
|
11
27
|
|
|
12
28
|
// MODULE'S CLASSES
|
|
13
29
|
/**
|
|
@@ -49,8 +65,8 @@ export default class TeqFw_Di_Shared_IdParser {
|
|
|
49
65
|
result.nameModule = parts[6];
|
|
50
66
|
result.mapKey = parts[1];
|
|
51
67
|
result.typeTarget = ParsedId.TYPE_TARGET_MODULE;
|
|
52
|
-
if (parts[8] ===
|
|
53
|
-
result.nameExport =
|
|
68
|
+
if (parts[8] === EXP_OLD) {
|
|
69
|
+
result.nameExport = DEF_EXP;
|
|
54
70
|
result.typeTarget = ParsedId.TYPE_TARGET_EXPORT;
|
|
55
71
|
result.mapKey = undefined;
|
|
56
72
|
}
|
|
@@ -60,16 +76,16 @@ export default class TeqFw_Di_Shared_IdParser {
|
|
|
60
76
|
result.mapKey = undefined;
|
|
61
77
|
}
|
|
62
78
|
if (parts[10]) {
|
|
63
|
-
if (parts[10] ===
|
|
79
|
+
if (parts[10] === INST) {
|
|
64
80
|
result.typeTarget = ParsedId.TYPE_TARGET_FACTORY;
|
|
65
|
-
} else if (parts[10] ===
|
|
81
|
+
} else if (parts[10] === SNGLT) {
|
|
66
82
|
result.typeTarget = ParsedId.TYPE_TARGET_SINGLETON;
|
|
67
83
|
}
|
|
68
84
|
if (result.nameExport === undefined) {
|
|
69
|
-
result.nameExport =
|
|
70
|
-
result.mapKey = result.namePackage +
|
|
85
|
+
result.nameExport = DEF_EXP;
|
|
86
|
+
result.mapKey = result.namePackage + FSM + result.nameModule;
|
|
71
87
|
} else {
|
|
72
|
-
result.mapKey = result.namePackage +
|
|
88
|
+
result.mapKey = result.namePackage + FSM + result.nameModule + EXP_OLD + result.nameExport;
|
|
73
89
|
}
|
|
74
90
|
}
|
|
75
91
|
}
|
|
@@ -90,31 +106,59 @@ export default class TeqFw_Di_Shared_IdParser {
|
|
|
90
106
|
result.orig = id;
|
|
91
107
|
result.typeId = ParsedId.TYPE_ID_LOGICAL;
|
|
92
108
|
result.nameModule = parts[2];
|
|
93
|
-
result.
|
|
109
|
+
result.isProxy = false;
|
|
110
|
+
result.mapKey = result.nameModule; // init mapKey with module's name
|
|
94
111
|
result.typeTarget = ParsedId.TYPE_TARGET_MODULE;
|
|
95
|
-
|
|
96
|
-
|
|
112
|
+
// Ns_Module.name$$[@@] - named instance [proxy]
|
|
113
|
+
if (
|
|
114
|
+
((parts[5] === EXP) || (parts[5] === EXP_OLD))
|
|
115
|
+
&& ((parts[7] === INST) || (parts[7] === P_INST))
|
|
116
|
+
) {
|
|
117
|
+
result.isProxy = (parts[7] === P_INST);
|
|
118
|
+
result.nameExport = parts[6];
|
|
119
|
+
result.typeTarget = ParsedId.TYPE_TARGET_FACTORY;
|
|
120
|
+
result.mapKey = result.nameModule + EXP + result.nameExport;
|
|
121
|
+
}
|
|
122
|
+
// Ns_Module.name$[@] - named singleton [proxy]
|
|
123
|
+
else if (
|
|
124
|
+
((parts[5] === EXP) || (parts[5] === EXP_OLD))
|
|
125
|
+
&& ((parts[7] === SNGLT) || (parts[7] === P_SNGLT))
|
|
126
|
+
) {
|
|
127
|
+
result.isProxy = (parts[7] === P_SNGLT);
|
|
128
|
+
result.nameExport = parts[6];
|
|
129
|
+
result.typeTarget = ParsedId.TYPE_TARGET_SINGLETON;
|
|
130
|
+
result.mapKey = result.nameModule + EXP + result.nameExport;
|
|
131
|
+
}
|
|
132
|
+
// Ns_Module.name - named export
|
|
133
|
+
else if (
|
|
134
|
+
((parts[5] === EXP) || (parts[5] === EXP_OLD))
|
|
135
|
+
&& ((parts[6] !== undefined) && (parts[6] !== ''))
|
|
136
|
+
) {
|
|
137
|
+
result.nameExport = parts[6];
|
|
97
138
|
result.typeTarget = ParsedId.TYPE_TARGET_EXPORT;
|
|
98
139
|
result.mapKey = undefined;
|
|
99
140
|
}
|
|
100
|
-
|
|
101
|
-
|
|
141
|
+
// Ns_Module$$[@@]- default instance [proxy]
|
|
142
|
+
else if ((parts[4] === INST) || (parts[4] === P_INST)) {
|
|
143
|
+
result.isProxy = (parts[4] === P_INST);
|
|
144
|
+
result.nameExport = DEF_EXP;
|
|
145
|
+
result.typeTarget = ParsedId.TYPE_TARGET_FACTORY;
|
|
146
|
+
}
|
|
147
|
+
// Ns_Module$[@] - default singleton [proxy]
|
|
148
|
+
else if ((parts[4] === SNGLT) || (parts[4] === P_SNGLT)) {
|
|
149
|
+
result.isProxy = (parts[4] === P_SNGLT);
|
|
150
|
+
result.nameExport = DEF_EXP;
|
|
151
|
+
result.typeTarget = ParsedId.TYPE_TARGET_SINGLETON;
|
|
152
|
+
}
|
|
153
|
+
// Ns_Module#[.] - default export
|
|
154
|
+
else if (
|
|
155
|
+
((parts[5] === EXP) || (parts[5] === EXP_OLD))
|
|
156
|
+
&& (parts[7] === undefined)
|
|
157
|
+
) {
|
|
158
|
+
result.nameExport = DEF_EXP;
|
|
102
159
|
result.typeTarget = ParsedId.TYPE_TARGET_EXPORT;
|
|
103
160
|
result.mapKey = undefined;
|
|
104
161
|
}
|
|
105
|
-
if (parts[6]) {
|
|
106
|
-
if (parts[6] === '$$') {
|
|
107
|
-
result.typeTarget = ParsedId.TYPE_TARGET_FACTORY;
|
|
108
|
-
} else if (parts[6] === '$') {
|
|
109
|
-
result.typeTarget = ParsedId.TYPE_TARGET_SINGLETON;
|
|
110
|
-
}
|
|
111
|
-
if (result.nameExport === undefined) {
|
|
112
|
-
result.nameExport = 'default';
|
|
113
|
-
result.mapKey = result.nameModule;
|
|
114
|
-
} else {
|
|
115
|
-
result.mapKey = result.nameModule + '#' + result.nameExport;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
162
|
}
|
|
119
163
|
return result;
|
|
120
164
|
}
|
package/src/Shared/SpecProxy.mjs
CHANGED
|
@@ -18,7 +18,7 @@ const $parser = new IdParser();
|
|
|
18
18
|
export default class TeqFw_Di_Shared_SpecProxy {
|
|
19
19
|
/**
|
|
20
20
|
* @param {string} mainId ID of the constructing object ('Vendor_Module$', 'Vendor_Module$$', 'dbCfg').
|
|
21
|
-
* @param {
|
|
21
|
+
* @param {string[]} uplineDeps All incomplete dependencies in current construction process
|
|
22
22
|
* (to prevent circular dependencies).
|
|
23
23
|
* @param {Map} containerSingletons Container level registry with created singletons (ids: 'dbCfg', 'Module$$').
|
|
24
24
|
* @param {Function} fnCreate constructing process level registry to save functions that
|
|
@@ -73,14 +73,14 @@ export default class TeqFw_Di_Shared_SpecProxy {
|
|
|
73
73
|
} else {
|
|
74
74
|
// check stack of incomplete dependencies
|
|
75
75
|
if (parsed.nameModule) { // don't process manually inserted singletons
|
|
76
|
-
if (uplineDeps
|
|
76
|
+
if (uplineDeps.includes(parsed.nameModule)) {
|
|
77
77
|
// `dep_id` is already requested to be created, so we report it as 'main'
|
|
78
78
|
const err = new Error(`Circular dependencies (main: ${depId}; dep: ${mainId})`);
|
|
79
79
|
fnRejectUseFactory(err); // reject async _useFactory
|
|
80
80
|
throw err; // break sync object's constructor
|
|
81
81
|
}
|
|
82
82
|
// ... and register new one
|
|
83
|
-
uplineDeps
|
|
83
|
+
uplineDeps.push(parsed.nameModule);
|
|
84
84
|
}
|
|
85
85
|
// create new required dependency for this object
|
|
86
86
|
fnGetObject(depId, uplineDeps).then((obj) => {
|
|
@@ -88,7 +88,7 @@ export default class TeqFw_Di_Shared_SpecProxy {
|
|
|
88
88
|
// save created `dep_id` instance to local dependencies registry
|
|
89
89
|
deps[depId] = obj;
|
|
90
90
|
// remove created dependency from circular registry
|
|
91
|
-
uplineDeps
|
|
91
|
+
uplineDeps.splice(uplineDeps.indexOf(parsed.nameModule), 1);
|
|
92
92
|
// re-call main object construction function
|
|
93
93
|
fnCreate();
|
|
94
94
|
}).catch(err => {
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DTO to represent plugin descriptor (teqfw.json) structure
|
|
3
|
-
* that is related to 'di/replace' node:
|
|
4
|
-
*/
|
|
5
|
-
// MODULE'S VARS
|
|
6
|
-
const NS = 'TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace';
|
|
7
|
-
|
|
8
|
-
// MODULE'S CLASSES
|
|
9
|
-
export default class TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace {
|
|
10
|
-
/**
|
|
11
|
-
* Logical name for ES6 module with replacement code (Vnd_Plug_Implementation).
|
|
12
|
-
* @type {string}
|
|
13
|
-
*/
|
|
14
|
-
alter;
|
|
15
|
-
/**
|
|
16
|
-
* App area to use replacement ('back', 'front', 'shared').
|
|
17
|
-
* @type {string}
|
|
18
|
-
*/
|
|
19
|
-
area;
|
|
20
|
-
/**
|
|
21
|
-
* Logical name for original ES6 module (Vnd_Plug_Interface).
|
|
22
|
-
* @type {string}
|
|
23
|
-
*/
|
|
24
|
-
orig;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// attributes names to use as aliases in queries to object props
|
|
28
|
-
TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace.ALTER = 'alter';
|
|
29
|
-
TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace.AREA = 'area';
|
|
30
|
-
TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace.ORIG = 'orig';
|
|
31
|
-
|
|
32
|
-
TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace.DATA_AREA_BACK = 'back';
|
|
33
|
-
TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace.DATA_AREA_FRONT = 'front';
|
|
34
|
-
TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace.DATA_AREA_SHARED = 'shared';
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Factory to create new DTO instances.
|
|
38
|
-
* @memberOf TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace
|
|
39
|
-
*/
|
|
40
|
-
export class Factory {
|
|
41
|
-
constructor() {
|
|
42
|
-
/**
|
|
43
|
-
* @param {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace|null} data
|
|
44
|
-
* @return {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace}
|
|
45
|
-
*/
|
|
46
|
-
this.create = function (data = null) {
|
|
47
|
-
const res = new TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace();
|
|
48
|
-
const clazz = TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace;
|
|
49
|
-
res.alter = data?.alter;
|
|
50
|
-
res.area = (
|
|
51
|
-
(data?.area === clazz.DATA_AREA_BACK) ||
|
|
52
|
-
(data?.area === clazz.DATA_AREA_FRONT)
|
|
53
|
-
)
|
|
54
|
-
? data.area : clazz.DATA_AREA_SHARED;
|
|
55
|
-
res.orig = data?.orig;
|
|
56
|
-
return res;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// freeze DTO class to deny attributes changes and pin namespace
|
|
62
|
-
Object.freeze(TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Replace);
|
|
63
|
-
Object.defineProperty(Factory, 'name', {value: `${NS}.${Factory.constructor.name}`});
|