@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
@@ -1,51 +0,0 @@
1
- // MODULE'S IMPORT
2
- import IdParser from '../IdParser.mjs';
3
-
4
- // MODULE'S VARS
5
- const $parser = new IdParser();
6
-
7
- /**
8
- * Map codebase file path namespaces to files/URLs.
9
- */
10
- export default class TeqFw_Di_Shared_Resolver_FilepathNs {
11
- /** @type {Object.<string, TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload>} */
12
- packages = {}
13
-
14
- /**
15
- * Register 'package to sources root' mapping.
16
- *
17
- * @param {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload} details namespace resolving details
18
- */
19
- addNamespaceRoot(details) {
20
- this.packages[details.ns] = details;
21
- }
22
-
23
- /**
24
- * List all registered packages with resolving details.
25
- *
26
- * @returns {Object.<string, TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload>}
27
- */
28
- list() {
29
- return this.packages;
30
- }
31
-
32
- /**
33
- * Resolve module id to module source path.
34
- * @param {string} moduleId '@vendor/package!path/to/module'
35
- * @returns {string} './@vendor/package/dist/path/to/module.mjs'
36
- */
37
- resolveModuleId(moduleId) {
38
- let result;
39
- /** @type {TeqFw_Di_Shared_IdParser_Dto} */
40
- const parsed = $parser.parse(moduleId);
41
- const pkg = parsed.namePackage;
42
- if (this.packages[pkg]) {
43
- /** @type {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload} */
44
- const details = this.packages[pkg];
45
- result = `${details.path}/${parsed.nameModule}.${details.ext}`;
46
- } else {
47
- throw new Error(`Cannot resolve path for id '${moduleId}'.`);
48
- }
49
- return result;
50
- }
51
- }
@@ -1,136 +0,0 @@
1
- /**
2
- * Tree-like structure of namespaces registry entry.
3
- *
4
- * @typedef {Object<string, NamespaceDetails|TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload>} NamespaceDetails
5
- */
6
-
7
- // MODULE'S VARS
8
- /**
9
- * Namespace parts separator.
10
- *
11
- * @type {string}
12
- */
13
- const NSS = '_';
14
- /**
15
- * Key to save sources data in namespaces registry.
16
- *
17
- * @type {string}
18
- */
19
- const KEY_DATA = '.data';
20
-
21
- // MODULE'S CLASSES
22
- /**
23
- * Map codebase logical namespaces to files/URLs.
24
- */
25
- export default class TeqFw_Di_Shared_Resolver_LogicalNs {
26
- /**
27
- * Registry for logical namespaces. Tree-like structure to save root paths (relative or absolute) to sources
28
- * by namespaces.
29
- *
30
- * TeqFw_Prj_App => ./path/to/app/files
31
- * TeqFw_Prj_App_Mod => ./another/path/to/mod/files
32
- * TeqFw_Prj_App_Mod_Rewrite => ./rewrite/path/to/part/of/mod/files
33
- *
34
- * @type {Object<string, NamespaceDetails>}
35
- * @private
36
- */
37
- namespaces = {};
38
-
39
- /**
40
- * Register sources path mapping details for namespace.
41
- *
42
- * @param {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload} details namespace resolving details
43
- */
44
- addNamespaceRoot(details) {
45
- const spaces = details.ns.split(NSS);
46
- let pointer = this.namespaces;
47
- for (const one of spaces) {
48
- if (!pointer[one]) {
49
- pointer[one] = {};
50
- pointer = pointer[one];
51
- } else {
52
- pointer = pointer[one];
53
- }
54
- }
55
- // add source folder to the namespaces map
56
- pointer[KEY_DATA] = details;
57
- }
58
-
59
- /**
60
- * List all namespaces with resolving details.
61
- *
62
- * @returns {Object.<string, TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload>}
63
- */
64
- list() {
65
- const result = {};
66
-
67
- /**
68
- * Scan one level of mapping tree and save mapping data into results (if found) and/or dive deeper.
69
-
70
- * @param {string} curPath
71
- * @param level
72
- */
73
- function scanLevel(curPath, level) {
74
- for (const key of Object.keys(level)) {
75
- if (key === KEY_DATA) {
76
- result[curPath] = level[KEY_DATA];
77
- } else {
78
- const subPath = (curPath) ? curPath + NSS + key : key;
79
- const sub = level[key];
80
- scanLevel(subPath, sub);
81
- }
82
- }
83
- }
84
-
85
- scanLevel('', this.namespaces);
86
- return result;
87
- }
88
-
89
- /**
90
- * Resolve path to module's source using `moduleId`:
91
- * - Vendor_Project_Module => './relative/path/to/vendor/Project/Module.mjs'
92
- * - Vendor_Project_Module => '/absolute/path/to/project/Module.js'
93
- * - Vendor_Project_Module => 'https://vendor.com/lib/Project/Module.js'
94
- *
95
- * @param {string} moduleId
96
- * @returns {*}
97
- */
98
- resolveModuleId(moduleId) {
99
- let result;
100
- const parts = moduleId.split(NSS);
101
- let nsExplored = ''; // explored part of the object's full name
102
- let pointer = this.namespaces;
103
- for (const part of parts) {
104
- if (pointer[part]) {
105
- pointer = pointer[part];
106
- if (pointer[KEY_DATA]) {
107
- // compose path to root module of the current namespace (`index.[js|mjs]`)
108
- /** @type {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload} */
109
- const entry = pointer[KEY_DATA];
110
- // compose path to NS default root
111
- result = `${entry.path}/../index.${entry.ext}`;
112
- if (!entry.isAbsolute) result = `./${result}`;
113
- }
114
- } else {
115
- // compose path to requested module starting from namespace root
116
- if (pointer[KEY_DATA]) {
117
- /** @type {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload} */
118
- const entry = pointer[KEY_DATA];
119
- const nsModule = nsExplored.substring(1);
120
- const nsObject = moduleId.substring(nsModule.length + 1);
121
- const pathObject = nsObject.replace(new RegExp(NSS, 'g'), '/') + '.' + entry.ext;
122
- result = `${entry.path}/${pathObject}`;
123
- if (!entry.isAbsolute) result = `./${result}`;
124
- break;
125
- }
126
- }
127
- nsExplored += NSS + part;
128
- }
129
- if (result === undefined) throw new Error(`Cannot resolve path for id '${moduleId}'.`);
130
- // strip '././' from result
131
- result = result.replace('././', './');
132
- return result;
133
- }
134
-
135
- }
136
-
@@ -1,74 +0,0 @@
1
- // MODULE'S IMPORT
2
- import FilepathNs from './Resolver/FilepathNs.mjs';
3
- import LogicalNs from './Resolver/LogicalNs.mjs';
4
-
5
- // MODULE'S VARS
6
- /** @type {RegExp} expression for logical namespace IDs w/o dep. injection fraction (Ns_Module) */
7
- const LOGICAL_NS = /^((([A-Z])[A-Za-z0-9_]*)?)$/;
8
-
9
- // MODULE'S CLASSES
10
- /**
11
- * Map codebase namespaces to files/URLs.
12
- */
13
- export default class TeqFw_Di_Shared_Resolver {
14
- /** @type {TeqFw_Di_Shared_Resolver_LogicalNs} */
15
- logicalNs = new LogicalNs();
16
- /** @type {TeqFw_Di_Shared_Resolver_FilepathNs} */
17
- filepathNs = new FilepathNs();
18
- // TODO: this is a hotfix
19
- /** @type {boolean} */
20
- isWindows = false;
21
-
22
- /**
23
- * Registry sources path mapping details for namespace.
24
- *
25
- * @param {TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload} details namespace resolving details
26
- */
27
- addNamespaceRoot(details) {
28
- const parsed = LOGICAL_NS.exec(details.ns);
29
- if (parsed) {
30
- // this is logical namespace
31
- this.logicalNs.addNamespaceRoot(details);
32
- } else {
33
- // this is file path based namespace
34
- this.filepathNs.addNamespaceRoot(details);
35
- }
36
- }
37
-
38
- /**
39
- * Resolve path to module's source using `moduleId`:
40
- * - '@vendor/package!path/to/module' => './@vendor/package/dist/path/to/module.mjs'
41
- * - 'Vendor_Project_Module' => 'https://vendor.com/lib/Project/Module.js'
42
- *
43
- * @param {string} moduleId
44
- * @returns {string}
45
- */
46
- resolveModuleId(moduleId) {
47
- let result;
48
- const parsed = LOGICAL_NS.exec(moduleId);
49
- if (parsed) {
50
- // this is logical namespace
51
- result = this.logicalNs.resolveModuleId(moduleId);
52
- } else {
53
- // this is file path based namespace
54
- result = this.filepathNs.resolveModuleId(moduleId);
55
- }
56
- // TODO: tmp fix for windows
57
- if (this.isWindows) {
58
- result = 'file://' + result.replace(/\//g, '\\');
59
- }
60
- return result;
61
- }
62
-
63
- /**
64
- * List all namespaces with resolving details.
65
- *
66
- * @returns {{filepathNs: Object<string, TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload>, logicalNs: Object<string, TeqFw_Di_Shared_Api_Dto_Plugin_Desc_Autoload>}}
67
- */
68
- list() {
69
- const filepathNs = this.filepathNs.list();
70
- const logicalNs = this.logicalNs.list();
71
- return {filepathNs, logicalNs};
72
- }
73
-
74
- }
@@ -1,110 +0,0 @@
1
- // MODULE'S IMPORT
2
- import IdParser from './IdParser.mjs';
3
- import ParsedId from './IdParser/Dto.mjs';
4
-
5
- // MODULE'S VARS
6
- const $parser = new IdParser();
7
-
8
- // MODULE'S CLASSES
9
- /**
10
- * Proxy object for constructors specification ('spec' argument in constructor) to analyze dependencies and to collect
11
- * required dependencies. This proxy adds constructed instances into container's `_instances` object.
12
- *
13
- * This code is too much coupled to `TeqFw_Di_Shared_Container` and extracted to separate class just for decreasing
14
- * of nesting levels.
15
- *
16
- * @class
17
- */
18
- export default class TeqFw_Di_Shared_SpecProxy {
19
- /**
20
- * @param {string} mainId ID of the constructing object ('Vendor_Module$', 'Vendor_Module$$', 'dbCfg').
21
- * @param {string[]} uplineDeps All incomplete dependencies in current construction process
22
- * (to prevent circular dependencies).
23
- * @param {Map} containerSingletons Container level registry with created singletons (ids: 'dbCfg', 'Module$$').
24
- * @param {Function} fnCreate constructing process level registry to save functions that
25
- * construct main object & nested dependencies.
26
- * @param {Function} fnGetObject `TeqFw_Di_Shared_Container.getObject` function to get/create required dependencies.
27
- * construction process on some error (import error or circular dependency, for example).
28
- * @param {Function} fnRejectUseFactory 'reject' function from 'TeqFw_Di_Shared_Container.getObject._useFactory' result.
29
- * @returns {{}} Proxy object to resolve dependencies as `constructor(spec)`.
30
- */
31
- constructor(
32
- mainId,
33
- uplineDeps,
34
- containerSingletons,
35
- fnCreate,
36
- fnGetObject,
37
- fnRejectUseFactory
38
- ) {
39
-
40
- /**
41
- * Resolved dependencies for currently constructing object (with `mainId`).
42
- *
43
- * @type {Object<string, Object>}
44
- */
45
- const deps = {};
46
-
47
- return new Proxy({}, {
48
- get(target, prop) {
49
- // convert property name of the `spec` object in `constructor(spec)` to dependency id string.
50
- const depId = String(prop);
51
- if (deps[depId]) {
52
- // use dependency from local registry (it is possible on second, third, ... usage
53
- // of the `constructor` after exception on un-existing dependency)
54
- return deps[depId];
55
- } else {
56
- // we have no dependency in the local cache yet
57
- // look up dependency in container's registry
58
- const parsed = $parser.parse(depId);
59
- if (
60
- (parsed.typeTarget === ParsedId.TYPE_TARGET_SINGLETON) &&
61
- containerSingletons.has(parsed.mapKey)
62
- ) {
63
- // requested dependency is an instance and is created before
64
- // save dependency to local registry & return
65
- deps[depId] = containerSingletons.get(parsed.mapKey);
66
- return deps[depId];
67
- } else if (
68
- (parsed.typeId === ParsedId.TYPE_ID_MANUAL) &&
69
- (parsed.typeTarget === ParsedId.TYPE_TARGET_SINGLETON) &&
70
- !containerSingletons.has(parsed.mapKey)
71
- ) {
72
- throw new Error(`There is no '${parsed.mapKey}' singleton in the container.`);
73
- } else {
74
- // check stack of incomplete dependencies
75
- if (parsed.nameModule) { // don't process manually inserted singletons
76
- if (uplineDeps.includes(parsed.nameModule)) {
77
- // `dep_id` is already requested to be created, so we report it as 'main'
78
- const err = new Error(`Circular dependencies (main: ${depId}; dep: ${mainId})`);
79
- fnRejectUseFactory(err); // reject async _useFactory
80
- throw err; // break sync object's constructor
81
- }
82
- // ... and register new one
83
- uplineDeps.push(parsed.nameModule);
84
- }
85
- // create new required dependency for this object
86
- fnGetObject(depId, uplineDeps).then((obj) => {
87
- if (obj === undefined) throw new Error(`Cannot resolve dependency '${depId}'.`);
88
- // save created `dep_id` instance to local dependencies registry
89
- deps[depId] = obj;
90
- // remove created dependency from circular registry
91
- uplineDeps.splice(uplineDeps.indexOf(parsed.nameModule), 1);
92
- // re-call main object construction function
93
- fnCreate();
94
- }).catch(err => {
95
- // re-throw error from promise
96
- fnRejectUseFactory(err); // reject async _useFactory
97
- });
98
- }
99
- // interrupt construction process until new dependency will be created
100
- // and new construction process will be started (see try-catch block in `fnCreate`)
101
- throw TeqFw_Di_Shared_SpecProxy.EXCEPTION_TO_STEALTH;
102
- }
103
- }
104
- });
105
- }
106
- }
107
-
108
- // static properties (compatible with Safari "< 14.1", "iOS < 14.5" form)
109
- /** Marker for construction exceptions that should be stolen. */
110
- TeqFw_Di_Shared_SpecProxy.EXCEPTION_TO_STEALTH = Symbol('exception_to_stealth')