@teqfw/di 0.12.1 → 0.20.1

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.
Files changed (41) hide show
  1. package/.eslintrc.mjs +0 -0
  2. package/README.md +27 -0
  3. package/RELEASE.md +11 -1
  4. package/bin/release/clean.sh +2 -1
  5. package/dist/di.cjs.js +205 -0
  6. package/dist/di.esm.js +206 -0
  7. package/index.cjs +5 -0
  8. package/index.mjs +6 -0
  9. package/package.json +14 -4
  10. package/src/Api/ObjectKey.js +35 -0
  11. package/src/Composer.js +68 -0
  12. package/src/Container.js +142 -0
  13. package/src/Defs.js +25 -0
  14. package/src/DepId/Parser.mjs +68 -0
  15. package/src/Parser/Def.js +63 -0
  16. package/src/Parser/Old.js +108 -0
  17. package/src/Parser.js +65 -0
  18. package/src/PreProcessor/Replace.js +48 -0
  19. package/src/PreProcessor.js +45 -0
  20. package/src/Resolver.js +65 -0
  21. package/src/Spec/Parser.mjs +101 -0
  22. package/src/SpecAnalyser.js +82 -0
  23. package/teqfw.json +2 -1
  24. package/webpack.config.mjs +15 -0
  25. package/src/Back/Api/Dto/Plugin/Desc.mjs +0 -70
  26. package/src/Back/Api/Dto/Scanned.mjs +0 -12
  27. package/src/Back/Api/README.md +0 -1
  28. package/src/Back/Defaults.mjs +0 -11
  29. package/src/Back/Plugin/Scanner.mjs +0 -154
  30. package/src/Back/README.md +0 -1
  31. package/src/Shared/Api/Dto/Plugin/Desc/Autoload.mjs +0 -50
  32. package/src/Shared/Api/IProxy.mjs +0 -11
  33. package/src/Shared/Container.mjs +0 -333
  34. package/src/Shared/IdParser/Dto.mjs +0 -96
  35. package/src/Shared/IdParser.mjs +0 -187
  36. package/src/Shared/ModuleLoader.mjs +0 -38
  37. package/src/Shared/README.md +0 -1
  38. package/src/Shared/Resolver/FilepathNs.mjs +0 -51
  39. package/src/Shared/Resolver/LogicalNs.mjs +0 -136
  40. package/src/Shared/Resolver.mjs +0 -74
  41. package/src/Shared/SpecProxy.mjs +0 -110
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "@teqfw/di",
3
- "version": "0.12.1",
3
+ "version": "0.20.1",
4
4
  "description": "Dependency Injection container based on logical namespaces for ES6 modules.",
5
5
  "keywords": [
6
6
  "dependency injection",
7
7
  "di",
8
8
  "dynamic import",
9
- "ecmascript 2015",
10
- "es6+",
9
+ "es6 modules",
11
10
  "teqfw",
12
11
  "tequila framework"
13
12
  ],
@@ -21,10 +20,21 @@
21
20
  "email": "alex@flancer64.com",
22
21
  "url": "https://github.com/flancer64"
23
22
  },
24
- "main": "src/Shared/Container.mjs",
23
+ "main": "src/Container.js",
25
24
  "type": "module",
26
25
  "repository": {
27
26
  "type": "git",
28
27
  "url": "git+https://github.com/teqfw/di.git"
28
+ },
29
+ "scripts": {
30
+ "build": "rm -fr ./dist/ && webpack build"
31
+ },
32
+ "devDependencies": {
33
+ "babel-eslint": "*",
34
+ "eslint": "*",
35
+ "esm": "*",
36
+ "mocha": "*",
37
+ "webpack": "^5.88.1",
38
+ "webpack-cli": "^5.1.4"
29
39
  }
30
40
  }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * This is a DTO that represents the structure of an ID for a runtime dependency.
3
+ */
4
+ export default class TeqFw_Di_Api_ObjectKey {
5
+ /**
6
+ * The name of an export of the module.
7
+ * @type {string}
8
+ */
9
+ exportName;
10
+ /**
11
+ * Composition type (see Defs.COMPOSE_): use the export as Factory (F) or return as-is (A).
12
+ * @type {string}
13
+ */
14
+ composition;
15
+ /**
16
+ * Lifestyle type (see Defs.LIFE_): singleton (S) or instance (I).
17
+ * @type {string}
18
+ */
19
+ life;
20
+ /**
21
+ * The code for ES6 module that can be converted to the path to this es6 module.
22
+ * @type {string}
23
+ */
24
+ moduleName;
25
+ /**
26
+ * Object key value.
27
+ * @type {string}
28
+ */
29
+ value;
30
+ /**
31
+ * List of wrappers to decorate the result.
32
+ * @type {string[]}
33
+ */
34
+ wrappers = [];
35
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ *
3
+ */
4
+ import Defs from './Defs.js';
5
+ import specAnalyser from './SpecAnalyser.js';
6
+
7
+ // FUNCS
8
+
9
+ // MAIN
10
+ export default class TeqFw_Di_Composer {
11
+
12
+ constructor() {
13
+ // VARS
14
+ let _debug = false;
15
+
16
+ // FUNCS
17
+ function log(msg) {
18
+ if (_debug) console.log(msg);
19
+ }
20
+
21
+ // INSTANCE METHODS
22
+
23
+ /**
24
+ *
25
+ * @param {TeqFw_Di_Api_ObjectKey} key
26
+ * @param {Object} module
27
+ * @param {string[]} stack array of the parent objects to prevent dependency loop
28
+ * @param {TeqFw_Di_Container} container
29
+ * @return {Promise<*>}
30
+ */
31
+ this.create = async function (key, module, stack, container) {
32
+ if (stack.includes(key.value))
33
+ throw new Error(`Circular dependency for '${key.value}'. Parents are: ${JSON.stringify(stack)}`);
34
+ if (key.exportName) {
35
+ // use export from the es6-module
36
+ const stackNew = [...stack, key.value];
37
+ const {[key.exportName]: exp} = module;
38
+ if (key.composition === Defs.COMPOSE_FACTORY) {
39
+ if (typeof exp === 'function') {
40
+ // create deps for factory function
41
+ const deps = specAnalyser(exp);
42
+ if (deps.length) log(`Deps for object '${key.value}' are: ${JSON.stringify(deps)}`);
43
+ const spec = {};
44
+ for (const dep of deps)
45
+ spec[dep] = await container.get(dep, stackNew);
46
+ // create a new object with the factory function
47
+ const res = (Defs.isClass(exp)) ? new exp(spec) : exp(spec);
48
+ if (res instanceof Promise)
49
+ return await res;
50
+ else
51
+ return res;
52
+ } else
53
+ // just clone the export
54
+ return Object.assign({}, exp);
55
+ } else
56
+ return exp;
57
+ } else {
58
+ return module;
59
+ }
60
+ };
61
+
62
+ this.setDebug = function (data) {
63
+ _debug = data;
64
+ };
65
+
66
+ // MAIN
67
+ }
68
+ };
@@ -0,0 +1,142 @@
1
+ /**
2
+ * The Object Container (composition root).
3
+ */
4
+ import Composer from './Composer.js';
5
+ import Defs from './Defs.js';
6
+ import Parser from './Parser.js';
7
+ import PreProcessor from './PreProcessor.js';
8
+ import NewReplace from './PreProcessor/Replace.js';
9
+ import Resolver from './Resolver.js';
10
+
11
+ // VARS
12
+
13
+ // FUNCS
14
+ /**
15
+ * ID to store singletons in the internal registry.
16
+ * @param {TeqFw_Di_Api_ObjectKey} key
17
+ * @return {string}
18
+ */
19
+ function getSingletonId(key) {
20
+ return `${key.moduleName}#${key.exportName}`;
21
+ }
22
+
23
+ // MAIN
24
+ export default class TeqFw_Di_Container {
25
+
26
+ constructor() {
27
+ // VARS
28
+ let _composer = new Composer();
29
+ let _debug = false;
30
+ let _parser = new Parser();
31
+ let _preProcessor = new PreProcessor();
32
+ _preProcessor.addHandler(NewReplace()); // create new instance of the replacement handler
33
+
34
+ /**
35
+ * Registry for loaded es6 modules.
36
+ * @type {Object<string, Module>}
37
+ */
38
+ const _regModules = {};
39
+ /**
40
+ * Registry to store singletons.
41
+ * @type {Object<string, *>}
42
+ */
43
+ const _regSingles = {};
44
+ let _resolver = new Resolver();
45
+
46
+ // FUNCS
47
+ function error() {
48
+ console.error(...arguments);
49
+ }
50
+
51
+ function log() {
52
+ if (_debug) console.log(...arguments);
53
+ }
54
+
55
+
56
+ // INSTANCE METHODS
57
+
58
+ this.get = async function (objectKey, stack = []) {
59
+ log(`Object '${objectKey}' is requested.`);
60
+ // return container itself if requested
61
+ if (
62
+ (objectKey === Defs.KEY_CONTAINER) ||
63
+ (objectKey === Defs.KEY_CONTAINER_NS)
64
+ ) {
65
+ log(`Container itself is returned.`);
66
+ return _regSingles[Defs.KEY_CONTAINER];
67
+ }
68
+ // parse the `objectKey` and get the structured DTO
69
+ const parsed = _parser.parse(objectKey);
70
+ // modify original key according to some rules (replacements, etc.)
71
+ const key = _preProcessor.process(parsed);
72
+ // return existing singleton
73
+ if (key.life === Defs.LIFE_SINGLETON) {
74
+ const singleId = getSingletonId(key);
75
+ if (_regSingles[singleId]) {
76
+ log(`Existing singleton '${singleId}' is returned.`);
77
+ return _regSingles[singleId];
78
+ }
79
+ }
80
+ // load es6 module if not loaded before
81
+ if (!_regModules[key.moduleName]) {
82
+ log(`ES6 module '${key.moduleName}' is not loaded yet`);
83
+ // convert module name to the path to es6-module file with a sources
84
+ const path = _resolver.resolve(key.moduleName);
85
+ try {
86
+ _regModules[key.moduleName] = await import(path);
87
+ log(`ES6 module '${key.moduleName}' is loaded from '${path}'.`);
88
+ } catch (e) {
89
+ console.error(
90
+ e?.message,
91
+ `Object key: "${objectKey}".`,
92
+ `Path: "${path}".`,
93
+ `Stack: ${JSON.stringify(stack)}`
94
+ );
95
+ throw e;
96
+ }
97
+
98
+ }
99
+ // create object using the composer
100
+ let res = await _composer.create(key, _regModules[key.moduleName], stack, this);
101
+ log(`Object '${objectKey}' is created.`);
102
+
103
+ // TODO: refactor this code to use wrappers w/o hardcode
104
+ if (key.wrappers.includes(Defs.WRAP_PROXY)) {
105
+ const me = this;
106
+ res = new Proxy({dep: undefined, objectKey}, {
107
+ get: async function (base, name) {
108
+ if (name === 'create') base.dep = await me.get(base.objectKey);
109
+ return base.dep;
110
+ }
111
+ });
112
+ }
113
+
114
+ if (key.life === Defs.LIFE_SINGLETON) {
115
+ const singleId = getSingletonId(key);
116
+ _regSingles[singleId] = res;
117
+ log(`Object '${objectKey}' is saved as singleton.`);
118
+ }
119
+ return res;
120
+ };
121
+
122
+ this.getParser = () => _parser;
123
+
124
+ this.getPreProcessor = () => _preProcessor
125
+ ;
126
+ this.getResolver = () => _resolver;
127
+
128
+ this.setDebug = function (data) {
129
+ _debug = data;
130
+ _composer.setDebug(data);
131
+ };
132
+
133
+ this.setParser = (data) => _parser = data;
134
+
135
+ this.setPreProcessor = (data) => _preProcessor = data;
136
+
137
+ this.setResolver = (data) => _resolver = data;
138
+
139
+ // MAIN
140
+ _regSingles[Defs.KEY_CONTAINER] = this;
141
+ }
142
+ };
package/src/Defs.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Hardcoded constants for the package.
3
+ */
4
+ export default {
5
+ COMPOSE_AS_IS: 'A',
6
+ COMPOSE_FACTORY: 'F',
7
+ EXT: 'js',
8
+ KEY_CONTAINER: 'container',
9
+ KEY_CONTAINER_NS: 'TeqFw_Di_Container$',
10
+ LIFE_INSTANCE: 'I',
11
+ LIFE_SINGLETON: 'S',
12
+ WRAP_PROXY: 'proxy',
13
+
14
+ /**
15
+ * Return 'true' if function is a class definition.
16
+ * See: https://stackoverflow.com/a/29094018/4073821
17
+ *
18
+ * @param {function} fn
19
+ * @return {boolean}
20
+ */
21
+ isClass(fn) {
22
+ const proto = Object.getOwnPropertyDescriptor(fn, 'prototype');
23
+ return proto && !proto.writable;
24
+ },
25
+ };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * This is default parser that converts dependency ID to the `depId` DTO.
3
+ * @namespace ObjectKey.Parser
4
+ */
5
+ // IMPORTS
6
+ import {ObjectKey} from '../Api/ObjectKey.mjs';
7
+
8
+ // VARS
9
+ /** @type {RegExp} expression for depId (Ns_Module.export$$#adapter) */
10
+ const TMPL = /^(([A-Z])[A-Za-z0-9_]*)((.)([A-Za-z0-9_]*)?((\$|\$\$)?((#)([A-Za-z0-9_]*)?)?)?)?$/;
11
+
12
+ // FUNCS
13
+ /**
14
+ * @param {string} depId
15
+ * @return {Api.ObjectKey}
16
+ */
17
+ export default function (depId) {
18
+ let res;
19
+ const parts = TMPL.exec(depId);
20
+ if (parts) {
21
+ const nameMod = parts[1];
22
+ const sepMod = parts[4]; // after-module separator
23
+ const sepExp = parts[6]; // after-export separator
24
+ const sepLife = parts[9]; // after-life separator
25
+
26
+ res = new ObjectKey();
27
+ // always presents
28
+ res.nameModule = nameMod;
29
+ if (sepLife === '#') {
30
+ // the longest form of the ID (Mod.exp$#adp)
31
+ res.adapter = parts[10] ?? 'default';
32
+ res.isExport = true;
33
+ res.isFactory = parts[7] !== undefined;
34
+ if (parts[7] === '$') res.isSingleton = true;
35
+ else if (parts[7] === '$$') res.isSingleton = false;
36
+ res.nameExport = parts[5];
37
+ } else if (sepMod === '#') {
38
+ // Mod#adp
39
+ res.adapter = parts[5] ?? 'default';
40
+ res.isExport = true;
41
+ res.isFactory = false;
42
+ res.nameExport = 'default';
43
+ } else if ((sepExp === '$') || (sepExp === '$$')) {
44
+ if (sepMod === '.') {
45
+ // Mod.exp$$
46
+ res.isExport = true;
47
+ res.isFactory = true;
48
+ if (parts[7] === '$') res.isSingleton = true;
49
+ else if (parts[7] === '$$') res.isSingleton = false;
50
+ res.nameExport = parts[5];
51
+ } else if (sepMod === '$') {
52
+ // Mod$$
53
+ res.isExport = true;
54
+ res.isFactory = true;
55
+ if (parts[3] === '$') res.isSingleton = true;
56
+ else if (parts[3] === '$$') res.isSingleton = false;
57
+ res.nameExport = 'default';
58
+ }
59
+ } else {
60
+ // Mod.exp
61
+ res.isFactory = false;
62
+ res.isExport = (sepMod === '.');
63
+ // define the name of the export
64
+ if (res.isExport) res.nameExport = parts[5] ?? 'default';
65
+ }
66
+ }
67
+ return res;
68
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Default parser for object keys in format:
3
+ * - Vnd_Pkg_Prj_Mod$FA
4
+ */
5
+ import Dto from '../Api/ObjectKey.js';
6
+ import Defs from '../Defs.js';
7
+
8
+ // VARS
9
+ /** @type {RegExp} expression for default object key (Ns_Module[.|#]export$[F|A][S|I]) */
10
+ const REGEXP = /^((([A-Z])[A-Za-z0-9_]*)((#|\.)?([A-Za-z0-9]*)((\$)([F|A])?([S|I])?)?)?)$/;
11
+
12
+
13
+ // MAIN
14
+ /**
15
+ * @param {string} objectKey
16
+ * @return {TeqFw_Di_Api_ObjectKey}
17
+ */
18
+ export default function TeqFw_Di_Parser_Def(objectKey) {
19
+ const res = new Dto();
20
+ res.value = objectKey;
21
+ const parts = REGEXP.exec(objectKey);
22
+ if (parts) {
23
+ res.moduleName = parts[2];
24
+ if (parts[5] === '.') {
25
+ // App_Service.export...
26
+ if (parts[8] === '$') {
27
+ // App_Service.export$...
28
+ res.composition = Defs.COMPOSE_FACTORY;
29
+ res.exportName = parts[6];
30
+ res.life = (parts[10] === Defs.LIFE_INSTANCE)
31
+ ? Defs.LIFE_INSTANCE : Defs.LIFE_SINGLETON;
32
+ } else {
33
+ res.composition = ((parts[8] === undefined) || (parts[8] === Defs.COMPOSE_AS_IS))
34
+ ? Defs.COMPOSE_AS_IS : Defs.COMPOSE_FACTORY;
35
+ res.exportName = parts[6];
36
+ res.life = ((parts[8] === undefined) || (parts[10] === Defs.LIFE_SINGLETON))
37
+ ? Defs.LIFE_SINGLETON : Defs.LIFE_INSTANCE;
38
+ }
39
+
40
+
41
+ } else if (parts[8] === '$') {
42
+ // App_Logger$FS
43
+ res.composition = ((parts[9] === undefined) || (parts[9] === Defs.COMPOSE_FACTORY))
44
+ ? Defs.COMPOSE_FACTORY : Defs.COMPOSE_AS_IS;
45
+ res.exportName = 'default';
46
+ if (parts[10]) {
47
+ res.life = (parts[10] === Defs.LIFE_SINGLETON) ? Defs.LIFE_SINGLETON : Defs.LIFE_INSTANCE;
48
+ } else {
49
+ res.life = (res.composition === Defs.COMPOSE_FACTORY) ? Defs.LIFE_SINGLETON : Defs.LIFE_INSTANCE;
50
+ }
51
+ } else {
52
+ // App_Service
53
+ res.composition = Defs.COMPOSE_AS_IS;
54
+ res.exportName = 'default';
55
+ res.life = Defs.LIFE_SINGLETON;
56
+ }
57
+ }
58
+
59
+ // we should always use singletons for as-is exports
60
+ if ((res.composition === Defs.COMPOSE_AS_IS) && (res.life === Defs.LIFE_INSTANCE))
61
+ throw new Error(`Export is not a function and should be used as a singleton only: '${res.value}'.`);
62
+ return res;
63
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Parser for object keys in old format:
3
+ * - Vnd_Pkg_Prj_Mod[.|#]export$$
4
+ */
5
+ import Dto from '../Api/ObjectKey.js';
6
+ import Defs from '../Defs.js';
7
+
8
+ // VARS
9
+ /** @type {string} default export keyword */
10
+ const DEF_EXP = 'default';
11
+ /** @type {string} logical namespace export mark (Ns_Mod.export) */
12
+ const EXP = '.';
13
+ /** @type {string} filesystem export mark (@vendor/package!module#export$$) and old logical export mark */
14
+ const EXP_OLD = '#';
15
+ /** @type {string} new instance mark (Ns_Mod.export$$) */
16
+ const INST = '$$';
17
+ /** @type {RegExp} expression for logical namespace IDs (Ns_Module[.|#]export$$@@) */
18
+ const REGEXP = /^((([A-Z])[A-Za-z0-9_]*)((#|.)?([A-Za-z0-9_]*)(\${1,2}|@{1,2})?)?)$/;
19
+ /** @type {RegExp} expression for objects that manually added to DI container (singleton, namedFactory$$) */
20
+ const MANUAL = /^((([a-z])[A-Za-z0-9_]*)(\$\$)?)$/s;
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 = '$';
27
+
28
+ // MAIN
29
+ export default function TeqFw_Di_Parser_Old(objectKey) {
30
+ const res = new Dto();
31
+ res.value = objectKey;
32
+ const parts = REGEXP.exec(objectKey);
33
+ if (parts) {
34
+ res.moduleName = parts[2];
35
+ // Ns_Module.name$$[@@] - named instance [proxy]
36
+ if (
37
+ ((parts[5] === EXP) || (parts[5] === EXP_OLD))
38
+ && ((parts[7] === INST) || (parts[7] === P_INST))
39
+ ) {
40
+ if (parts[7] === P_INST)
41
+ res.wrappers.push(Defs.WRAP_PROXY);
42
+ res.composition = Defs.COMPOSE_FACTORY;
43
+ res.life = Defs.LIFE_INSTANCE;
44
+ res.exportName = parts[6];
45
+ }
46
+ // Ns_Module.name$[@] - named singleton [proxy]
47
+ else if (
48
+ ((parts[5] === EXP) || (parts[5] === EXP_OLD))
49
+ && ((parts[7] === SNGLT) || (parts[7] === P_SNGLT))
50
+ ) {
51
+ if (parts[7] === P_SNGLT)
52
+ res.wrappers.push(Defs.WRAP_PROXY);
53
+ res.composition = Defs.COMPOSE_FACTORY;
54
+ res.life = Defs.LIFE_SINGLETON;
55
+ res.exportName = parts[6];
56
+ }
57
+ // Ns_Module.name - named export
58
+ else if (
59
+ ((parts[5] === EXP) || (parts[5] === EXP_OLD))
60
+ && ((parts[6] !== undefined) && (parts[6] !== ''))
61
+ ) {
62
+ res.composition = Defs.COMPOSE_AS_IS;
63
+ res.exportName = parts[6];
64
+ res.life = Defs.LIFE_SINGLETON;
65
+ }
66
+ // Ns_Module$$[@@]- default instance [proxy]
67
+ else if ((parts[4] === INST) || (parts[4] === P_INST)) {
68
+ if (parts[4] === P_INST)
69
+ res.wrappers.push(Defs.WRAP_PROXY);
70
+ res.composition = Defs.COMPOSE_FACTORY;
71
+ res.life = Defs.LIFE_INSTANCE;
72
+ res.exportName = DEF_EXP;
73
+ }
74
+ // Ns_Module$[@] - default singleton [proxy]
75
+ else if ((parts[4] === SNGLT) || (parts[4] === P_SNGLT)) {
76
+ if (parts[4] === P_SNGLT)
77
+ res.wrappers.push(Defs.WRAP_PROXY);
78
+ res.composition = Defs.COMPOSE_FACTORY;
79
+ res.life = Defs.LIFE_SINGLETON;
80
+ res.exportName = DEF_EXP;
81
+ }
82
+ // Ns_Module#[.] - default export
83
+ else if (
84
+ ((parts[5] === EXP) || (parts[5] === EXP_OLD))
85
+ && (parts[7] === undefined)
86
+ ) {
87
+ res.composition = Defs.COMPOSE_AS_IS;
88
+ res.life = Defs.LIFE_SINGLETON;
89
+ res.exportName = DEF_EXP;
90
+ } else {
91
+ // just a es6-module (deprecated)
92
+
93
+ }
94
+ } else {
95
+ const manual = MANUAL.exec(objectKey);
96
+ if (manual) {
97
+ if (manual[4] === '$$') {
98
+ res.composition = Defs.COMPOSE_FACTORY;
99
+ res.life = Defs.LIFE_INSTANCE;
100
+ } else {
101
+ res.life = Defs.LIFE_SINGLETON;
102
+ }
103
+ } else {
104
+ // TODO: add exception
105
+ }
106
+ }
107
+ return res;
108
+ }
package/src/Parser.js ADDED
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The root parser for `objectKeys` contains all other parsers.
3
+ * It calls the other parser one by one to parse the object key as a structure.
4
+ * Every npm package can have its own format for an `objectKey`.
5
+ */
6
+ import defaultParser from './Parser/Def.js';
7
+
8
+ // VARS
9
+ const KEY_PARSER = 'parser';
10
+ const KEY_VALIDATOR = 'validator';
11
+
12
+ // MAIN
13
+ export default class TeqFw_Di_Parser {
14
+
15
+ constructor() {
16
+ // VARS
17
+ /**
18
+ * Default parsing function.
19
+ * @type {(function(string): TeqFw_Di_Api_ObjectKey)}
20
+ */
21
+ let _defaultParser = defaultParser;
22
+ /**
23
+ * The array of the pairs {validator, parser} to parse objectKeys.
24
+ * @type {Object<validator:function, parser:function>[]}
25
+ */
26
+ const _parsers = [];
27
+
28
+ // INSTANCE METHODS
29
+
30
+ /**
31
+ *
32
+ * @param {function(string):boolean} validator
33
+ * @param {function(string):TeqFw_Di_Api_ObjectKey} parser
34
+ */
35
+ this.addParser = function (validator, parser) {
36
+ _parsers.push({[KEY_VALIDATOR]: validator, [KEY_PARSER]: parser});
37
+ };
38
+
39
+ /**
40
+ * @param {string} objectKey
41
+ * @return {TeqFw_Di_Api_ObjectKey}
42
+ */
43
+ this.parse = function (objectKey) {
44
+ let res;
45
+ for (const one of _parsers) {
46
+ if (one[KEY_VALIDATOR](objectKey)) {
47
+ res = one[KEY_PARSER](objectKey);
48
+ break;
49
+ }
50
+ }
51
+ if (!res)
52
+ res = _defaultParser(objectKey);
53
+ return res;
54
+ };
55
+
56
+ /**
57
+ * @param {function(string):TeqFw_Di_Api_ObjectKey} parser
58
+ */
59
+ this.setDefaultParser = function (parser) {
60
+ _defaultParser = parser;
61
+ };
62
+
63
+ // MAIN
64
+ }
65
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Pre-processor handler to replace one object key with another.
3
+ * @namespace TeqFw_Di_PreProcessor_Replace
4
+ */
5
+
6
+ /**
7
+ * Factory function to create pre-processor handler.
8
+ * @return {function(*): *}
9
+ */
10
+ export default function () {
11
+ // VARS
12
+ /**
13
+ * Storage for ES modules replacements (interface => implementation).
14
+ * Sample: {['Vnd_Plug_Interface']:'Vnd_Plug_Impl', ...}
15
+ * @type {Object<string, string>}
16
+ */
17
+ const replacements = {};
18
+
19
+ // FUNCS
20
+ /**
21
+ * @param {TeqFw_Di_Api_ObjectKey} objectKey
22
+ * @param {TeqFw_Di_Api_ObjectKey} originalKey
23
+ * @return {TeqFw_Di_Api_ObjectKey}
24
+ */
25
+ function TeqFw_Di_PreProcessor_Replace(objectKey, originalKey) {
26
+ let module = objectKey.moduleName;
27
+ while (replacements[module]) module = replacements[module];
28
+ if (module !== objectKey.moduleName) {
29
+ const res = Object.assign({}, objectKey);
30
+ res.moduleName = module;
31
+ return res;
32
+ } else
33
+ return objectKey;
34
+ }
35
+
36
+ /**
37
+ * Add replacement for ES6 modules.
38
+ *
39
+ * @param {string} orig ('Vnd_Plug_Interface')
40
+ * @param {string} alter ('Vnd_Plug_Impl')
41
+ */
42
+ TeqFw_Di_PreProcessor_Replace.add = function (orig, alter) {
43
+ replacements[orig] = alter;
44
+ };
45
+
46
+ // MAIN
47
+ return TeqFw_Di_PreProcessor_Replace;
48
+ }