@teqfw/di 0.33.0 → 0.34.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/RELEASE.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @teqfw/di releases
2
2
 
3
+ ## 0.34.0 – Strict Mode and Test Support
4
+
5
+ - Removed outdated interface `TeqFw_Di_Api_Container` and associated documentation.
6
+ - Unified the `get()` and `compose()` methods for dependency retrieval.
7
+ - Introduced strict mode by default: manual registration of dependencies is now **disabled** unless explicitly allowed.
8
+ - Added `enableTestMode()` method to the container, enabling safe, test-specific manual registration of singleton
9
+ dependencies.
10
+ - Improved error messages and safeguards against accidental overwrites in `register()`.
11
+ - Updated internal naming and documentation for better clarity and alignment with the platform's principles.
12
+ - Cleaned up ESLint and JSDoc inconsistencies in internal files.
13
+
3
14
  ## 0.33.0 – Cleanup and Enhancements
4
15
 
5
16
  - Removed deprecated documentation.
package/dist/esm.js CHANGED
@@ -1 +1 @@
1
- var e={CA:"A",CF:"F",ID:"container",ID_FQN:"TeqFw_Di_Container$",LI:"I",LS:"S",isClass(e){const t=Object.getOwnPropertyDescriptor(e,"prototype");return t&&!t.writable}};const t=/(function)*\s*\w*\s*\(\s*\{([^}]*)}/s,o=/constructor\s*\(\s*\{([^}]*)}/s;function n(e){const t=[];try{const o=new Function(`{${e}}`,"return");o(new Proxy({},{get:(e,o)=>t.push(o)}))}catch(t){throw new Error(`Cannot analyze the deps specification:${e}\n\nPlease, be sure that spec does not contain extra ')' in a comments.\n\nError: ${t}`)}return t}function s(s){return"function"==typeof s?e.isClass(s)?function(e){const t=[],s=e.toString(),r=o.exec(s);return r&&t.push(...n(r[1])),t}(s):function(e){const o=[],s=e.toString(),r=t.exec(s);return r&&o.push(...n(r[2])),o}(s):[]}class r{constructor(){let t=!1;this.create=async function(o,n,r,i){if(r.includes(o.origin))throw new Error(`Circular dependency for '${o.origin}'. Parents are: ${JSON.stringify(r)}`);if(o.exportName){const a=[...r,o.origin],{[o.exportName]:u}=n;if(o.composition===e.CF){if("function"==typeof u){const n=s(u);n.length&&(c=`Deps for object '${o.origin}' are: ${JSON.stringify(n)}`,t&&console.log(c));const r={};for(const e of n)r[e]=await i.compose(e,a);const l=e.isClass(u)?new u(r):u(r);return l instanceof Promise?await l:l}return Object.assign({},u)}return u}return n;var c},this.setDebug=function(e){t=e}}}class i{exportName;composition;life;moduleName;origin;wrappers=[]}const c=/^(node:)?(@?[A-Za-z0-9_-]+\/?[A-Za-z0-9_-]*)(([.#])?([A-Za-z0-9_]*)((\$)?(\$)?)?)?(\(([A-Za-z0-9_,]*)\))?$/;class a{canParse(){return!0}parse(t){const o=new i;o.origin=t;const n=c.exec(t);if(n&&(o.isNodeModule=Boolean(n[1]),o.moduleName=n[2].replace(/^node:/,""),"."===n[4]||"#"===n[4]?"$"===n[6]||"$$"===n[6]?(o.composition=e.CF,o.exportName=n[5],o.life="$"===n[6]?e.LS:e.LI):(o.composition=e.CA,o.life=e.LS,o.exportName=""!==n[5]?n[5]:"default"):"$"===n[6]||"$$"===n[6]?(o.composition=e.CF,o.exportName="default",o.life="$"===n[6]?e.LS:e.LI):(o.composition=void 0,o.exportName=void 0,o.life=void 0),n[10]&&(o.wrappers=n[10].split(","))),o.composition===e.CA&&o.life===e.LI)throw new Error(`Export is not a function and should be used as a singleton only: '${o.origin}'.`);return o}}class u{constructor(){let e=new a;const t=[];this.addChunk=function(e){t.push(e)},this.parse=function(o){let n;for(const e of t)if(e.canParse(o)){n=e.parse(o);break}return n||(n=e?.parse(o)),n},this.setDefaultChunk=function(t){e=t}}}class l{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=function(t,o){let n=t;for(const s of e)n=s.modify(n,t,o);return n}}}class f{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=async function(t,o,n){let s=t;for(const t of e)s=t.modify(s,o,n),s instanceof Promise&&(s=await s);return s}}}const p="root";class d{constructor(){const e={};let t=!1,o=[],n="/";this.addNamespaceRoot=function(n,s,r){const i=(t?s.replace(/^\\/,""):s).replace(/\\/g,"/"),c=t?`file://${i}`:i;e[n]={ext:r??"js",ns:n,[p]:c},o=Object.keys(e).sort(((e,t)=>t.localeCompare(e)))},this.resolve=function(t){let s,r,i;for(i of o)if(t.startsWith(i)){s=e[i][p],r=e[i].ext;break}if(s&&r){let e=t.replace(i,"");0===e.indexOf("_")&&(e=e.replace("_",""));const o=e.replaceAll("_",n);return`${s}${n}${o}.${r}`}return t},this.setWindowsEnv=function(e=!0){t=e,n=e?"\\":"/"}}}function m(e){return`${e.moduleName}#${e.exportName}`}class h{constructor(){let t=new r,o=!1,n=new u,s=new l,i=new f;const c={},a={};let p=new d;function h(){o&&console.log(...arguments)}this.get=async function(e,t=[]){return this.compose(e,t)},this.compose=async function(o,r=[]){if(h(`Object '${o}' is requested.`),o===e.ID||o===e.ID_FQN)return h("Container itself is returned."),a[e.ID];const u=n.parse(o),l=s.modify(u,r);if(l.life===e.LS){const e=m(l);if(a[e])return h(`Existing singleton '${e}' is returned.`),a[e]}let f;c[l.moduleName]||(h(`ES6 module '${l.moduleName}' is not resolved yet`),c[l.moduleName]=p.resolve(l.moduleName));const d=c[l.moduleName];try{f=await import(d),h(`ES6 module '${l.moduleName}' is loaded from '${d}'.`)}catch(e){throw console.error(e?.message,`Object key: "${o}".`,`Path: "${d}".`,`Stack: ${JSON.stringify(r)}`),e}let $=await t.create(l,f,r,this);var g;if(null===(g=$)||"object"!=typeof g&&"function"!=typeof g||"[object Module]"===Object.prototype.toString.call(g)||Object.isFrozen(g)||Object.freeze($),$=await i.modify($,l,r),h(`Object '${o}' is created.`),l.life===e.LS){const e=m(l);a[e]=$,h(`Object '${o}' is saved as singleton.`)}return $},this.getParser=()=>n,this.getPreProcessor=()=>s,this.getPostProcessor=()=>i,this.getResolver=()=>p,this.register=function(t,o){if(!t||!o)throw new Error("depId and object are required");const s=n.parse(t);if(s.life!==e.LS)throw new Error(`Only singletons can be registered manually. Given: ${t}`);{const e=m(s);a[e]=o,h(`Object '${t}' is registered manually as singleton.`)}},this.setDebug=function(e){o=e,t.setDebug(e)},this.setParser=e=>n=e,this.setPreProcessor=e=>s=e,this.setPostProcessor=e=>i=e,this.setResolver=e=>p=e,a[e.ID]=this}}export{h as default};
1
+ var e={CA:"A",CF:"F",ID:"container",ID_FQN:"TeqFw_Di_Container$",LI:"I",LS:"S",isClass(e){const t=Object.getOwnPropertyDescriptor(e,"prototype");return t&&!t.writable}};const t=/(function)*\s*\w*\s*\(\s*\{([^}]*)}/s,o=/constructor\s*\(\s*\{([^}]*)}/s;function n(e){const t=[];try{const o=new Function(`{${e}}`,"return");o(new Proxy({},{get:(e,o)=>t.push(o)}))}catch(t){throw new Error(`Cannot analyze the deps specification:${e}\n\nPlease, be sure that spec does not contain extra ')' in a comments.\n\nError: ${t}`)}return t}function s(s){return"function"==typeof s?e.isClass(s)?function(e){const t=[],s=e.toString(),r=o.exec(s);return r&&t.push(...n(r[1])),t}(s):function(e){const o=[],s=e.toString(),r=t.exec(s);return r&&o.push(...n(r[2])),o}(s):[]}class r{constructor(){let t=!1;this.create=async function(o,n,r,i){if(r.includes(o.origin))throw new Error(`Circular dependency for '${o.origin}'. Parents are: ${JSON.stringify(r)}`);if(o.exportName){const a=[...r,o.origin],{[o.exportName]:l}=n;if(o.composition===e.CF){if("function"==typeof l){const n=s(l);n.length&&(c=`Deps for object '${o.origin}' are: ${JSON.stringify(n)}`,t&&console.log(c));const r={};for(const e of n)r[e]=await i.get(e,a);const u=e.isClass(l)?new l(r):l(r);return u instanceof Promise?await u:u}return Object.assign({},l)}return l}return n;var c},this.setDebug=function(e){t=e}}}class i{exportName;composition;life;moduleName;origin;wrappers=[]}const c=/^(node:)?(@?[A-Za-z0-9_-]+\/?[A-Za-z0-9_-]*)(([.#])?([A-Za-z0-9_]*)((\$)?(\$)?)?)?(\(([A-Za-z0-9_,]*)\))?$/;class a{canParse(){return!0}parse(t){const o=new i;o.origin=t;const n=c.exec(t);if(n&&(o.isNodeModule=Boolean(n[1]),o.moduleName=n[2].replace(/^node:/,""),"."===n[4]||"#"===n[4]?"$"===n[6]||"$$"===n[6]?(o.composition=e.CF,o.exportName=n[5],o.life="$"===n[6]?e.LS:e.LI):(o.composition=e.CA,o.life=e.LS,o.exportName=""!==n[5]?n[5]:"default"):"$"===n[6]||"$$"===n[6]?(o.composition=e.CF,o.exportName="default",o.life="$"===n[6]?e.LS:e.LI):(o.composition=void 0,o.exportName=void 0,o.life=void 0),n[10]&&(o.wrappers=n[10].split(","))),o.composition===e.CA&&o.life===e.LI)throw new Error(`Export is not a function and should be used as a singleton only: '${o.origin}'.`);return o}}class l{constructor(){let e=new a;const t=[];this.addChunk=function(e){t.push(e)},this.parse=function(o){let n;for(const e of t)if(e.canParse(o)){n=e.parse(o);break}return n||(n=e?.parse(o)),n},this.setDefaultChunk=function(t){e=t}}}class u{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=function(t,o){let n=t;for(const s of e)n=s.modify(n,t,o);return n}}}class f{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=async function(t,o,n){let s=t;for(const t of e)s=t.modify(s,o,n),s instanceof Promise&&(s=await s);return s}}}const d="ext",p="ns",h="root";class m{constructor(){const e={};let t=!1,o=[],n="/";this.addNamespaceRoot=function(n,s,r){const i=(t?s.replace(/^\\/,""):s).replace(/\\/g,"/"),c=t?`file://${i}`:i;e[n]={[d]:r??"js",[p]:n,[h]:c},o=Object.keys(e).sort(((e,t)=>t.localeCompare(e)))},this.resolve=function(t){let s,r,i;for(i of o)if(t.startsWith(i)){s=e[i][h],r=e[i].ext;break}if(s&&r){let e=t.replace(i,"");0===e.indexOf("_")&&(e=e.replace("_",""));const o=e.replaceAll("_",n);return`${s}${n}${o}.${r}`}return t},this.setWindowsEnv=function(e=!0){t=e,n=e?"\\":"/"}}}function $(e){return`${e.moduleName}#${e.exportName}`}class g{constructor(){let t=new r,o=!1,n=new l,s=new f,i=new u,c=!1;const a={},d={};let p=new m;function h(){o&&console.log(...arguments)}this.get=async function(o,r=[]){if(h(`Object '${o}' is requested.`),o===e.ID||o===e.ID_FQN)return h("Container itself is returned."),d[e.ID];const c=n.parse(o),l=i.modify(c,r);if(l.life===e.LS){const e=$(l);if(d[e])return h(`Existing singleton '${e}' is returned.`),d[e]}let u;a[l.moduleName]||(h(`ES6 module '${l.moduleName}' is not resolved yet`),a[l.moduleName]=p.resolve(l.moduleName));const f=a[l.moduleName];try{u=await import(f),h(`ES6 module '${l.moduleName}' is loaded from '${f}'.`)}catch(e){throw console.error(e?.message,`Object key: "${o}".`,`Path: "${f}".`,`Stack: ${JSON.stringify(r)}`),e}let m=await t.create(l,u,r,this);var g;if(null===(g=m)||"object"!=typeof g&&"function"!=typeof g||"[object Module]"===Object.prototype.toString.call(g)||Object.isFrozen(g)||Object.freeze(m),m=await s.modify(m,l,r),h(`Object '${o}' is created.`),l.life===e.LS){const e=$(l);d[e]=m,h(`Object '${o}' is saved as singleton.`)}return m},this.enableTestMode=function(){c=!0,h("Test mode enabled")},this.getParser=()=>n,this.getPreProcessor=()=>i,this.getPostProcessor=()=>s,this.getResolver=()=>p,this.register=function(t,o){if(!c)throw new Error("Use enableTestMode() to allow it");if(!t||!o)throw new Error("Both params are required");const s=n.parse(t);if(s.life!==e.LS)throw new Error(`Only singletons can be registered: '${t}'`);const r=$(s);if(d[r])throw new Error(`'${t}' is already registered`);d[r]=o,h(`'${t}' is registered`)},this.setDebug=function(e){o=e,t.setDebug(e)},this.setParser=e=>n=e,this.setPreProcessor=e=>i=e,this.setPostProcessor=e=>s=e,this.setResolver=e=>p=e,d[e.ID]=this}}export{g as default};
package/dist/umd.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).TeqFw_Di_Container=t()}(this,(function(){"use strict";var e={CA:"A",CF:"F",ID:"container",ID_FQN:"TeqFw_Di_Container$",LI:"I",LS:"S",isClass(e){const t=Object.getOwnPropertyDescriptor(e,"prototype");return t&&!t.writable}};const t=/(function)*\s*\w*\s*\(\s*\{([^}]*)}/s,o=/constructor\s*\(\s*\{([^}]*)}/s;function n(e){const t=[];try{const o=new Function(`{${e}}`,"return");o(new Proxy({},{get:(e,o)=>t.push(o)}))}catch(t){throw new Error(`Cannot analyze the deps specification:${e}\n\nPlease, be sure that spec does not contain extra ')' in a comments.\n\nError: ${t}`)}return t}function s(s){return"function"==typeof s?e.isClass(s)?function(e){const t=[],s=e.toString(),r=o.exec(s);return r&&t.push(...n(r[1])),t}(s):function(e){const o=[],s=e.toString(),r=t.exec(s);return r&&o.push(...n(r[2])),o}(s):[]}class r{constructor(){let t=!1;this.create=async function(o,n,r,i){if(r.includes(o.origin))throw new Error(`Circular dependency for '${o.origin}'. Parents are: ${JSON.stringify(r)}`);if(o.exportName){const a=[...r,o.origin],{[o.exportName]:u}=n;if(o.composition===e.CF){if("function"==typeof u){const n=s(u);n.length&&(c=`Deps for object '${o.origin}' are: ${JSON.stringify(n)}`,t&&console.log(c));const r={};for(const e of n)r[e]=await i.compose(e,a);const l=e.isClass(u)?new u(r):u(r);return l instanceof Promise?await l:l}return Object.assign({},u)}return u}return n;var c},this.setDebug=function(e){t=e}}}class i{exportName;composition;life;moduleName;origin;wrappers=[]}const c=/^(node:)?(@?[A-Za-z0-9_-]+\/?[A-Za-z0-9_-]*)(([.#])?([A-Za-z0-9_]*)((\$)?(\$)?)?)?(\(([A-Za-z0-9_,]*)\))?$/;class a{canParse(){return!0}parse(t){const o=new i;o.origin=t;const n=c.exec(t);if(n&&(o.isNodeModule=Boolean(n[1]),o.moduleName=n[2].replace(/^node:/,""),"."===n[4]||"#"===n[4]?"$"===n[6]||"$$"===n[6]?(o.composition=e.CF,o.exportName=n[5],o.life="$"===n[6]?e.LS:e.LI):(o.composition=e.CA,o.life=e.LS,o.exportName=""!==n[5]?n[5]:"default"):"$"===n[6]||"$$"===n[6]?(o.composition=e.CF,o.exportName="default",o.life="$"===n[6]?e.LS:e.LI):(o.composition=void 0,o.exportName=void 0,o.life=void 0),n[10]&&(o.wrappers=n[10].split(","))),o.composition===e.CA&&o.life===e.LI)throw new Error(`Export is not a function and should be used as a singleton only: '${o.origin}'.`);return o}}class u{constructor(){let e=new a;const t=[];this.addChunk=function(e){t.push(e)},this.parse=function(o){let n;for(const e of t)if(e.canParse(o)){n=e.parse(o);break}return n||(n=e?.parse(o)),n},this.setDefaultChunk=function(t){e=t}}}class l{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=function(t,o){let n=t;for(const s of e)n=s.modify(n,t,o);return n}}}class f{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=async function(t,o,n){let s=t;for(const t of e)s=t.modify(s,o,n),s instanceof Promise&&(s=await s);return s}}}const d="root";class p{constructor(){const e={};let t=!1,o=[],n="/";this.addNamespaceRoot=function(n,s,r){const i=(t?s.replace(/^\\/,""):s).replace(/\\/g,"/"),c=t?`file://${i}`:i;e[n]={ext:r??"js",ns:n,[d]:c},o=Object.keys(e).sort(((e,t)=>t.localeCompare(e)))},this.resolve=function(t){let s,r,i;for(i of o)if(t.startsWith(i)){s=e[i][d],r=e[i].ext;break}if(s&&r){let e=t.replace(i,"");0===e.indexOf("_")&&(e=e.replace("_",""));const o=e.replaceAll("_",n);return`${s}${n}${o}.${r}`}return t},this.setWindowsEnv=function(e=!0){t=e,n=e?"\\":"/"}}}function m(e){return`${e.moduleName}#${e.exportName}`}return class{constructor(){let t=new r,o=!1,n=new u,s=new l,i=new f;const c={},a={};let d=new p;function h(){o&&console.log(...arguments)}this.get=async function(e,t=[]){return this.compose(e,t)},this.compose=async function(o,r=[]){if(h(`Object '${o}' is requested.`),o===e.ID||o===e.ID_FQN)return h("Container itself is returned."),a[e.ID];const u=n.parse(o),l=s.modify(u,r);if(l.life===e.LS){const e=m(l);if(a[e])return h(`Existing singleton '${e}' is returned.`),a[e]}let f;c[l.moduleName]||(h(`ES6 module '${l.moduleName}' is not resolved yet`),c[l.moduleName]=d.resolve(l.moduleName));const p=c[l.moduleName];try{f=await import(p),h(`ES6 module '${l.moduleName}' is loaded from '${p}'.`)}catch(e){throw console.error(e?.message,`Object key: "${o}".`,`Path: "${p}".`,`Stack: ${JSON.stringify(r)}`),e}let g=await t.create(l,f,r,this);var $;if(null===($=g)||"object"!=typeof $&&"function"!=typeof $||"[object Module]"===Object.prototype.toString.call($)||Object.isFrozen($)||Object.freeze(g),g=await i.modify(g,l,r),h(`Object '${o}' is created.`),l.life===e.LS){const e=m(l);a[e]=g,h(`Object '${o}' is saved as singleton.`)}return g},this.getParser=()=>n,this.getPreProcessor=()=>s,this.getPostProcessor=()=>i,this.getResolver=()=>d,this.register=function(t,o){if(!t||!o)throw new Error("depId and object are required");const s=n.parse(t);if(s.life!==e.LS)throw new Error(`Only singletons can be registered manually. Given: ${t}`);{const e=m(s);a[e]=o,h(`Object '${t}' is registered manually as singleton.`)}},this.setDebug=function(e){o=e,t.setDebug(e)},this.setParser=e=>n=e,this.setPreProcessor=e=>s=e,this.setPostProcessor=e=>i=e,this.setResolver=e=>d=e,a[e.ID]=this}}}));
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).TeqFw_Di_Container=t()}(this,(function(){"use strict";var e={CA:"A",CF:"F",ID:"container",ID_FQN:"TeqFw_Di_Container$",LI:"I",LS:"S",isClass(e){const t=Object.getOwnPropertyDescriptor(e,"prototype");return t&&!t.writable}};const t=/(function)*\s*\w*\s*\(\s*\{([^}]*)}/s,o=/constructor\s*\(\s*\{([^}]*)}/s;function n(e){const t=[];try{const o=new Function(`{${e}}`,"return");o(new Proxy({},{get:(e,o)=>t.push(o)}))}catch(t){throw new Error(`Cannot analyze the deps specification:${e}\n\nPlease, be sure that spec does not contain extra ')' in a comments.\n\nError: ${t}`)}return t}function s(s){return"function"==typeof s?e.isClass(s)?function(e){const t=[],s=e.toString(),r=o.exec(s);return r&&t.push(...n(r[1])),t}(s):function(e){const o=[],s=e.toString(),r=t.exec(s);return r&&o.push(...n(r[2])),o}(s):[]}class r{constructor(){let t=!1;this.create=async function(o,n,r,i){if(r.includes(o.origin))throw new Error(`Circular dependency for '${o.origin}'. Parents are: ${JSON.stringify(r)}`);if(o.exportName){const a=[...r,o.origin],{[o.exportName]:u}=n;if(o.composition===e.CF){if("function"==typeof u){const n=s(u);n.length&&(c=`Deps for object '${o.origin}' are: ${JSON.stringify(n)}`,t&&console.log(c));const r={};for(const e of n)r[e]=await i.get(e,a);const l=e.isClass(u)?new u(r):u(r);return l instanceof Promise?await l:l}return Object.assign({},u)}return u}return n;var c},this.setDebug=function(e){t=e}}}class i{exportName;composition;life;moduleName;origin;wrappers=[]}const c=/^(node:)?(@?[A-Za-z0-9_-]+\/?[A-Za-z0-9_-]*)(([.#])?([A-Za-z0-9_]*)((\$)?(\$)?)?)?(\(([A-Za-z0-9_,]*)\))?$/;class a{canParse(){return!0}parse(t){const o=new i;o.origin=t;const n=c.exec(t);if(n&&(o.isNodeModule=Boolean(n[1]),o.moduleName=n[2].replace(/^node:/,""),"."===n[4]||"#"===n[4]?"$"===n[6]||"$$"===n[6]?(o.composition=e.CF,o.exportName=n[5],o.life="$"===n[6]?e.LS:e.LI):(o.composition=e.CA,o.life=e.LS,o.exportName=""!==n[5]?n[5]:"default"):"$"===n[6]||"$$"===n[6]?(o.composition=e.CF,o.exportName="default",o.life="$"===n[6]?e.LS:e.LI):(o.composition=void 0,o.exportName=void 0,o.life=void 0),n[10]&&(o.wrappers=n[10].split(","))),o.composition===e.CA&&o.life===e.LI)throw new Error(`Export is not a function and should be used as a singleton only: '${o.origin}'.`);return o}}class u{constructor(){let e=new a;const t=[];this.addChunk=function(e){t.push(e)},this.parse=function(o){let n;for(const e of t)if(e.canParse(o)){n=e.parse(o);break}return n||(n=e?.parse(o)),n},this.setDefaultChunk=function(t){e=t}}}class l{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=function(t,o){let n=t;for(const s of e)n=s.modify(n,t,o);return n}}}class f{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=async function(t,o,n){let s=t;for(const t of e)s=t.modify(s,o,n),s instanceof Promise&&(s=await s);return s}}}const d="ext",p="ns",h="root";class m{constructor(){const e={};let t=!1,o=[],n="/";this.addNamespaceRoot=function(n,s,r){const i=(t?s.replace(/^\\/,""):s).replace(/\\/g,"/"),c=t?`file://${i}`:i;e[n]={[d]:r??"js",[p]:n,[h]:c},o=Object.keys(e).sort(((e,t)=>t.localeCompare(e)))},this.resolve=function(t){let s,r,i;for(i of o)if(t.startsWith(i)){s=e[i][h],r=e[i].ext;break}if(s&&r){let e=t.replace(i,"");0===e.indexOf("_")&&(e=e.replace("_",""));const o=e.replaceAll("_",n);return`${s}${n}${o}.${r}`}return t},this.setWindowsEnv=function(e=!0){t=e,n=e?"\\":"/"}}}function g(e){return`${e.moduleName}#${e.exportName}`}return class{constructor(){let t=new r,o=!1,n=new u,s=new f,i=new l,c=!1;const a={},d={};let p=new m;function h(){o&&console.log(...arguments)}this.get=async function(o,r=[]){if(h(`Object '${o}' is requested.`),o===e.ID||o===e.ID_FQN)return h("Container itself is returned."),d[e.ID];const c=n.parse(o),u=i.modify(c,r);if(u.life===e.LS){const e=g(u);if(d[e])return h(`Existing singleton '${e}' is returned.`),d[e]}let l;a[u.moduleName]||(h(`ES6 module '${u.moduleName}' is not resolved yet`),a[u.moduleName]=p.resolve(u.moduleName));const f=a[u.moduleName];try{l=await import(f),h(`ES6 module '${u.moduleName}' is loaded from '${f}'.`)}catch(e){throw console.error(e?.message,`Object key: "${o}".`,`Path: "${f}".`,`Stack: ${JSON.stringify(r)}`),e}let m=await t.create(u,l,r,this);var w;if(null===(w=m)||"object"!=typeof w&&"function"!=typeof w||"[object Module]"===Object.prototype.toString.call(w)||Object.isFrozen(w)||Object.freeze(m),m=await s.modify(m,u,r),h(`Object '${o}' is created.`),u.life===e.LS){const e=g(u);d[e]=m,h(`Object '${o}' is saved as singleton.`)}return m},this.enableTestMode=function(){c=!0,h("Test mode enabled")},this.getParser=()=>n,this.getPreProcessor=()=>i,this.getPostProcessor=()=>s,this.getResolver=()=>p,this.register=function(t,o){if(!c)throw new Error("Use enableTestMode() to allow it");if(!t||!o)throw new Error("Both params are required");const s=n.parse(t);if(s.life!==e.LS)throw new Error(`Only singletons can be registered: '${t}'`);const r=g(s);if(d[r])throw new Error(`'${t}' is already registered`);d[r]=o,h(`'${t}' is registered`)},this.setDebug=function(e){o=e,t.setDebug(e)},this.setParser=e=>n=e,this.setPreProcessor=e=>i=e,this.setPostProcessor=e=>s=e,this.setResolver=e=>p=e,d[e.ID]=this}}}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teqfw/di",
3
- "version": "0.33.0",
3
+ "version": "0.34.0",
4
4
  "description": "Dependency Injection container for ES6 modules that works in both browser and Node.js apps.",
5
5
  "keywords": [
6
6
  "dependency injection",
@@ -23,7 +23,7 @@ export default class TeqFw_Di_Container_A_Composer {
23
23
  * Returns or creates and returns the requested object.
24
24
  *
25
25
  * @param {TeqFw_Di_DepId} depId
26
- * @param {Object} module - imported es6 module
26
+ * @param {object} module - imported es6 module
27
27
  * @param {string[]} stack - array of the parent objects IDs to prevent dependency loop
28
28
  * @param {TeqFw_Di_Container} container - to create dependencies for requested object
29
29
  * @returns {Promise<*>}
@@ -42,7 +42,7 @@ export default class TeqFw_Di_Container_A_Composer {
42
42
  if (deps.length) log(`Deps for object '${depId.origin}' are: ${JSON.stringify(deps)}`);
43
43
  const spec = {};
44
44
  for (const dep of deps)
45
- spec[dep] = await container.compose(dep, stackNew);
45
+ spec[dep] = await container.get(dep, stackNew);
46
46
  // create a new object with the factory function
47
47
  const res = (Defs.isClass(exp)) ? new exp(spec) : exp(spec);
48
48
  if (res instanceof Promise)
package/src/Container.js CHANGED
@@ -1,5 +1,7 @@
1
1
  /**
2
2
  * The Object Container (composition root).
3
+ * We can use static imports in the Container.
4
+ *
3
5
  * @namespace TeqFw_Di_Container
4
6
  */
5
7
  import Composer from './Container/A/Composer.js';
@@ -33,11 +35,7 @@ function canBeFrozen(value) {
33
35
  return !Object.isFrozen(value);
34
36
  }
35
37
 
36
-
37
38
  // MAIN
38
- /**
39
- * @implements TeqFw_Di_Api_Container
40
- */
41
39
  export default class TeqFw_Di_Container {
42
40
 
43
41
  constructor() {
@@ -45,8 +43,9 @@ export default class TeqFw_Di_Container {
45
43
  let _composer = new Composer();
46
44
  let _debug = false;
47
45
  let _parser = new Parser();
48
- let _preProcessor = new PreProcessor();
49
46
  let _postProcessor = new PostProcessor();
47
+ let _preProcessor = new PreProcessor();
48
+ let _testMode = false;
50
49
 
51
50
  /**
52
51
  * Registry for paths for loaded es6 modules.
@@ -56,7 +55,7 @@ export default class TeqFw_Di_Container {
56
55
  const _regPaths = {};
57
56
  /**
58
57
  * Registry to store singletons.
59
- * @type {Object<string, *>}
58
+ * @type {Object<string, object>}
60
59
  */
61
60
  const _regSingles = {};
62
61
  let _resolver = new Resolver();
@@ -69,20 +68,9 @@ export default class TeqFw_Di_Container {
69
68
 
70
69
  // INSTANCE METHODS
71
70
 
72
- this.get = async function (runtimeDepId, stack = []) {
73
- return this.compose(runtimeDepId, stack);
74
- };
75
-
76
- /**
77
- * This method is 'private' for the npm package. It is used in the Composer only.
78
- *
79
- * @param {string} depId runtime dependency ID
80
- * @param {string[]} stack set of the depId to detect circular dependencies
81
- * @returns {Promise<*>}
82
- */
83
- this.compose = async function (depId, stack = []) {
71
+ this.get = async function (depId, stack = []) {
84
72
  log(`Object '${depId}' is requested.`);
85
- // return container itself if requested
73
+ // return the container itself if requested
86
74
  if (
87
75
  (depId === Defs.ID) ||
88
76
  (depId === Defs.ID_FQN)
@@ -92,7 +80,7 @@ export default class TeqFw_Di_Container {
92
80
  }
93
81
  // parse the `objectKey` and get the structured DTO
94
82
  const parsed = _parser.parse(depId);
95
- // modify original key according to some rules (replacements, etc.)
83
+ // modify the original key according to some rules (replacements, etc.)
96
84
  const key = _preProcessor.modify(parsed, stack);
97
85
  // return existing singleton
98
86
  if (key.life === Defs.LS) {
@@ -102,10 +90,10 @@ export default class TeqFw_Di_Container {
102
90
  return _regSingles[singleId];
103
91
  }
104
92
  }
105
- // resolve path to es6 module if not resolved before
93
+ // resolve a path to es6 module if not resolved before
106
94
  if (!_regPaths[key.moduleName]) {
107
95
  log(`ES6 module '${key.moduleName}' is not resolved yet`);
108
- // convert module name to the path to es6-module file with a sources
96
+ // convert the module name to the path to an es6-module file with a source
109
97
  _regPaths[key.moduleName] = _resolver.resolve(key.moduleName);
110
98
  }
111
99
 
@@ -124,9 +112,9 @@ export default class TeqFw_Di_Container {
124
112
  );
125
113
  throw e;
126
114
  }
127
- // create object using the composer then modify it in post-processor
115
+ // create an object using the composer, then modify it in post-processor
128
116
  let res = await _composer.create(key, module, stack, this);
129
- // freeze the result to prevent modifications (TODO: should we have configuration for the feature?)
117
+ // freeze the result to prevent modifications
130
118
  if (canBeFrozen(res)) Object.freeze(res);
131
119
  res = await _postProcessor.modify(res, key, stack);
132
120
  log(`Object '${depId}' is created.`);
@@ -140,6 +128,14 @@ export default class TeqFw_Di_Container {
140
128
  return res;
141
129
  };
142
130
 
131
+ /**
132
+ * Enables test mode, allowing manual singleton registration.
133
+ */
134
+ this.enableTestMode = function () {
135
+ _testMode = true;
136
+ log('Test mode enabled');
137
+ };
138
+
143
139
  this.getParser = () => _parser;
144
140
 
145
141
  this.getPreProcessor = () => _preProcessor;
@@ -149,21 +145,28 @@ export default class TeqFw_Di_Container {
149
145
  this.getResolver = () => _resolver;
150
146
 
151
147
  /**
152
- * Register new object in the Container.
153
- * @param {string} depId
154
- * @param {Object} obj
148
+ * Registers a new singleton object in the Container.
149
+ *
150
+ * @param {string} depId - Dependency identifier. Must be a singleton identifier.
151
+ * @param {object} obj - The object to register.
155
152
  */
156
153
  this.register = function (depId, obj) {
157
- if (!depId || !obj) throw new Error('depId and object are required');
154
+ if (!_testMode)
155
+ throw new Error('Use enableTestMode() to allow it');
156
+
157
+ if (!depId || !obj)
158
+ throw new Error('Both params are required');
159
+
158
160
  const key = _parser.parse(depId);
159
- if (key.life === Defs.LS) {
160
- const singleId = getSingletonId(key);
161
- _regSingles[singleId] = obj;
162
- log(`Object '${depId}' is registered manually as singleton.`);
163
- } else {
164
- // TODO: factory function also should be added manually
165
- throw new Error(`Only singletons can be registered manually. Given: ${depId}`);
166
- }
161
+ if (key.life !== Defs.LS)
162
+ throw new Error(`Only singletons can be registered: '${depId}'`);
163
+
164
+ const singleId = getSingletonId(key);
165
+ if (_regSingles[singleId])
166
+ throw new Error(`'${depId}' is already registered`);
167
+
168
+ _regSingles[singleId] = obj;
169
+ log(`'${depId}' is registered`);
167
170
  };
168
171
 
169
172
  this.setDebug = function (data) {
@@ -1,69 +0,0 @@
1
- /**
2
- * Interface for the Object Container.
3
- *
4
- * This is not executable code, it is just for documentation purposes (similar to .h files in the C/C++ language).
5
- * @interface
6
- */
7
- export default class TeqFw_Di_Api_Container {
8
- /**
9
- * Gets or creates a runtime object by ID.
10
- *
11
- * @param {string} runtimeDepId - The ID of the runtime object.
12
- * @param {string[]} [stack]
13
- * @returns {Promise<*>} - A promise that resolves to the runtime object.
14
- */
15
- get(runtimeDepId, stack) {};
16
-
17
- /**
18
- * @returns {TeqFw_Di_Api_Container_Parser}
19
- */
20
- getParser() {};
21
-
22
- /**
23
- * @returns {TeqFw_Di_Api_Container_PreProcessor}
24
- */
25
- getPreProcessor() {};
26
-
27
- /**
28
- * @returns {TeqFw_Di_Api_Container_PostProcessor}
29
- */
30
- getPostProcessor() {};
31
-
32
- /**
33
- * @returns {TeqFw_Di_Container_Resolver} - the default resolver
34
- */
35
- getResolver() {};
36
-
37
- /**
38
- * Registers an object (module, singleton, factory, or prototype) by dependency ID.
39
- * @param {string} depId
40
- * @param {Object} obj
41
- */
42
- register(depId, obj) {};
43
-
44
- /**
45
- * Enable disable debug output for the object composition process.
46
- * @param {boolean} data
47
- */
48
- setDebug(data) {};
49
-
50
- /**
51
- * @param {TeqFw_Di_Api_Container_Parser} data
52
- */
53
- setParser(data) {};
54
-
55
- /**
56
- * @param {TeqFw_Di_Api_Container_PreProcessor} data
57
- */
58
- setPreProcessor(data) {};
59
-
60
- /**
61
- * @param {TeqFw_Di_Api_Container_PostProcessor} data
62
- */
63
- setPostProcessor(data) {};
64
-
65
- /**
66
- * @param {TeqFw_Di_Api_Container_Resolver} data
67
- */
68
- setResolver(data) {};
69
- };