@teqfw/di 1.0.0 → 1.0.2

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/esm.js ADDED
@@ -0,0 +1 @@
1
+ var e={CA:"A",CF:"F",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 s(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 n(n){return"function"==typeof n?e.isClass(n)?function(e){const t=[],n=e.toString(),r=o.exec(n);return r&&t.push(...s(r[1])),t}(n):function(e){const o=[],n=e.toString(),r=t.exec(n);return r&&o.push(...s(r[2])),o}(n):[]}class r{constructor(){let t=!1;this.create=async function(o,s,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}=s;if(o.composition===e.CF){if("function"==typeof l){const s=n(l);s.length&&(c=`Deps for object '${o.origin}' are: ${JSON.stringify(s)}`,t&&console.log(c));const r={};for(const e of s)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 s;var c},this.setDebug=function(e){t=e}}}class i{exportName;composition;isNodeModule;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 s=c.exec(t);if(s&&(o.isNodeModule=Boolean(s[1]),o.moduleName=s[2].replace(/^node:/,""),"."===s[4]||"#"===s[4]?"$"===s[6]||"$$"===s[6]?(o.composition=e.CF,o.exportName=s[5],o.life="$"===s[6]?e.LS:e.LI):(o.composition=e.CA,o.life=e.LS,o.exportName=""!==s[5]?s[5]:"default"):"$"===s[6]||"$$"===s[6]?(o.composition=e.CF,o.exportName="default",o.life="$"===s[6]?e.LS:e.LI):(o.composition=void 0,o.exportName=void 0,o.life=void 0),s[10]&&(o.wrappers=s[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 s;for(const e of t)if(e.canParse(o)){s=e.parse(o);break}return s||(s=e?.parse(o)),s},this.setDefaultChunk=function(t){e=t}}}class u{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=function(t,o){let s=t;for(const n of e)s=n.modify(s,t,o);return s}}}class f{constructor(){const e=[];this.addChunk=function(t){e.push(t)},this.modify=async function(t,o,s){let n=t;for(const t of e)n=t.modify(n,o,s),n instanceof Promise&&(n=await n);return n}}}const d="ext",p="ns",h="root";class m{constructor(){const e={};let t=!1,o=[],s="/";this.addNamespaceRoot=function(s,n,r){const i=(t?n.replace(/^\\/,""):n).replace(/\\/g,"/"),c=t?`file://${i}`:i;e[s]={[d]:r??"js",[p]:s,[h]:c},o=Object.keys(e).sort((e,t)=>t.localeCompare(e))},this.resolve=function(t){let n,r,i;for(i of o)if(t.startsWith(i)){n=e[i][h],r=e[i].ext;break}if(n&&r){let e=t.replace(i,"");0===e.indexOf("_")&&(e=e.replace("_",""));const o=e.replaceAll("_",s);return`${n}${s}${o}.${r}`}return t},this.setWindowsEnv=function(e=!0){t=e,s=e?"\\":"/"}}}function g(e){return`${e.moduleName}#${e.exportName}`}class ${constructor(){let t=new r,o=!1,s=new l,n=new f,i=new u,c=!1;const a={},d={},p={};let h=new m;function $(){o&&console.log(...arguments)}this.get=async function(o,r=[]){$(`Object '${o}' is requested.`);const l=s.parse(o),u=i.modify(l,r);if(u.life===e.LS){const e=g(u);if(d[e])return $(`Existing singleton '${e}' is returned.`),d[e]}if(u.isNodeModule&&c){const e=u.origin;if(p[e])return $(`Existing nodejs lib '${e}' is returned.`),p[e]}let f;a[u.moduleName]||($(`ES6 module '${u.moduleName}' is not resolved yet`),a[u.moduleName]=h.resolve(u.moduleName));const m=a[u.moduleName];try{f=await import(m),$(`ES6 module '${u.moduleName}' is loaded from '${m}'.`)}catch(e){throw console.error(e?.message,`Object key: "${o}".`,`Path: "${m}".`,`Stack: ${JSON.stringify(r)}`),e}let w=await t.create(u,f,r,this);var y;if(null===(y=w)||"object"!=typeof y&&"function"!=typeof y||"[object Module]"===Object.prototype.toString.call(y)||Object.isFrozen(y)||Object.freeze(w),w=await n.modify(w,u,r),$(`Object '${o}' is created.`),u.life===e.LS){const e=g(u);d[e]=w,$(`Object '${o}' is saved as singleton.`)}return w},this.enableTestMode=function(){c=!0,$("Test mode enabled")},this.getParser=()=>s,this.getPreProcessor=()=>i,this.getPostProcessor=()=>n,this.getResolver=()=>h,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 n=s.parse(t);if(n.life!==e.LS&&!n.isNodeModule)throw new Error(`Only node modules & singletons can be registered: '${t}'`);if(n.life===e.LS){const e=g(n);if(d[e])throw new Error(`'${t}' is already registered`);d[e]=o}else if(n.isNodeModule){const e=n.origin;if(p[e])throw new Error(`'${t}' is already registered`);p[e]=o}$(`'${t}' is registered`)},this.setDebug=function(e){o=e,t.setDebug(e)},this.setParser=e=>s=e,this.setPreProcessor=e=>i=e,this.setPostProcessor=e=>n=e,this.setResolver=e=>h=e}}export{$ as default};
package/dist/umd.js ADDED
@@ -0,0 +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",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;isNodeModule;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 g(e){return`${e.moduleName}#${e.exportName}`}return class{constructor(){let t=new r,o=!1,n=new l,s=new f,i=new u,c=!1;const a={},d={},p={};let h=new m;function w(){o&&console.log(...arguments)}this.get=async function(o,r=[]){w(`Object '${o}' is requested.`);const l=n.parse(o),u=i.modify(l,r);if(u.life===e.LS){const e=g(u);if(d[e])return w(`Existing singleton '${e}' is returned.`),d[e]}if(u.isNodeModule&&c){const e=u.origin;if(p[e])return w(`Existing nodejs lib '${e}' is returned.`),p[e]}let f;a[u.moduleName]||(w(`ES6 module '${u.moduleName}' is not resolved yet`),a[u.moduleName]=h.resolve(u.moduleName));const m=a[u.moduleName];try{f=await import(m),w(`ES6 module '${u.moduleName}' is loaded from '${m}'.`)}catch(e){throw console.error(e?.message,`Object key: "${o}".`,`Path: "${m}".`,`Stack: ${JSON.stringify(r)}`),e}let $=await t.create(u,f,r,this);var y;if(null===(y=$)||"object"!=typeof y&&"function"!=typeof y||"[object Module]"===Object.prototype.toString.call(y)||Object.isFrozen(y)||Object.freeze($),$=await s.modify($,u,r),w(`Object '${o}' is created.`),u.life===e.LS){const e=g(u);d[e]=$,w(`Object '${o}' is saved as singleton.`)}return $},this.enableTestMode=function(){c=!0,w("Test mode enabled")},this.getParser=()=>n,this.getPreProcessor=()=>i,this.getPostProcessor=()=>s,this.getResolver=()=>h,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&&!s.isNodeModule)throw new Error(`Only node modules & singletons can be registered: '${t}'`);if(s.life===e.LS){const e=g(s);if(d[e])throw new Error(`'${t}' is already registered`);d[e]=o}else if(s.isNodeModule){const e=s.origin;if(p[e])throw new Error(`'${t}' is already registered`);p[e]=o}w(`'${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=>h=e}}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teqfw/di",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
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",
@@ -20,7 +20,23 @@
20
20
  "email": "alex@flancer64.com",
21
21
  "url": "https://github.com/flancer64"
22
22
  },
23
- "main": "src/Container.js",
23
+ "files": [
24
+ "dist/",
25
+ "src/",
26
+ "LICENSE",
27
+ "README.md"
28
+ ],
29
+ "main": "dist/umd.js",
30
+ "module": "dist/esm.js",
31
+ "exports": {
32
+ ".": {
33
+ "import": "./dist/esm.js",
34
+ "require": "./dist/umd.js"
35
+ },
36
+ "./pre/replace": {
37
+ "import": "./src/Pre/Replace.js"
38
+ }
39
+ },
24
40
  "type": "module",
25
41
  "repository": {
26
42
  "type": "git",
@@ -1,48 +0,0 @@
1
- name: npm publication
2
-
3
- on:
4
- workflow_dispatch:
5
- release:
6
- types: [ created ]
7
-
8
- jobs:
9
- build:
10
- runs-on: ubuntu-latest
11
- steps:
12
- # Checkout repository code
13
- - uses: actions/checkout@v4
14
-
15
- # Setup Node.js environment
16
- - uses: actions/setup-node@v4
17
- with:
18
- node-version: 20
19
-
20
- # Install dependencies using package-lock.json
21
- - run: npm ci
22
-
23
- # Run unit tests
24
- - run: npm run test
25
-
26
- publish-npm:
27
- needs: build
28
- runs-on: ubuntu-latest
29
- steps:
30
- # Checkout repository code again for a separate job
31
- - uses: actions/checkout@v4
32
-
33
- # Setup Node.js and configure npm registry
34
- - uses: actions/setup-node@v4
35
- with:
36
- node-version: 20
37
- registry-url: https://registry.npmjs.org/
38
-
39
- # Install dependencies again
40
- - run: npm ci
41
-
42
- # Build a code for browsers
43
- - run: npm run rollup
44
-
45
- # Publish package to npm registry with authentication token
46
- - run: npm publish --access public
47
- env:
48
- NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
package/AGENTS.md DELETED
@@ -1,6 +0,0 @@
1
- # AGENTS
2
-
3
- - Write all code comments, documentation, commit messages, and changelog entries in English.
4
- - Record every project change in `CHANGELOG.md` under a new version `X.Y.Z` (the exact number is assigned at release).
5
- - For the platform philosophy behind this library, see [PHILOSOPHY.md](./PHILOSOPHY.md).
6
-
package/CHANGELOG.md DELETED
@@ -1,9 +0,0 @@
1
- # Changelog
2
-
3
- ## 1.0.0
4
- - Started changelog for version 1.0.0.
5
- - Added AGENTS.md with English-only guidelines and link to PHILOSOPHY.md.
6
- - Switched tests from Mocha to Node's built-in runner.
7
- - Updated package scripts and removed Mocha dependency.
8
- - Documented breaking changes for v1.0.0: the container can no longer access itself, configuration must occur in the Composition Root, and legacy versions live in the `forerunner` branch.
9
-
package/PHILOSOPHY.md DELETED
@@ -1,175 +0,0 @@
1
- # Philosophy of the TeqFW Platform
2
-
3
- **The philosophy of Tequila Framework (TeqFW)** is my personal approach to organizing web application development. I,
4
- Alex Gusev, have shaped this approach based on my own experience, which focuses on **modular monoliths** with a single
5
- database. This document reflects that specific context and does not aim to be universal.
6
-
7
- Some of the principles presented may be applicable more broadly, while others may be irrelevant (or even
8
- counterproductive) outside monolithic architectures. It is important to keep this limitation in mind when interpreting
9
- the material.
10
-
11
- The document is intended to provide cognitive context for both human and artificial intelligences. It addresses both
12
- specific aspects of web development and more general software architecture issues, emphasizing the reduction of
13
- excessive complexity, improved structuring, and adaptability to changes.
14
-
15
- **Tequila Framework (TeqFW)** is not a finished product but an evolving experimental platform. It serves as a testbed
16
- for the principles outlined here and is actively used in development.
17
-
18
- ## Core Principles of TeqFW
19
-
20
- 1. **Use a Unified Development Language:** JavaScript (ES6+) is used on both the client and server sides, ensuring code
21
- integrity, reducing duplication, and lowering cognitive load.
22
-
23
- 2. **Enable Late Binding for Flexibility:** Dynamic dependency management through an object container and ES6 module
24
- namespaces. This reduces tight coupling between modules, simplifies system expansion, and makes the code more
25
- adaptable.
26
-
27
- 3. **Design for Evolutionary Code Resilience:** Code is designed with inevitable changes in mind to minimize adaptation
28
- costs and facilitate expansion without modifying existing components.
29
-
30
- 4. **Separate Data and Logic Functionally:** Isolation of data structures (DTO) and logic handlers. This approach makes
31
- code easier to test, maintain, and reuse.
32
-
33
- 5. **Use Namespaces for Structure and Isolation:** Each type of entity—npm packages, ES6 modules, database tables, CLI
34
- commands, or configurations—has its own namespace. This ensures clear project structure, reduces conflicts, and
35
- simplifies code navigation.
36
-
37
- 6. **Favor Pure JavaScript Without Compilation:** Using modern JavaScript (ES6+) without TypeScript or version
38
- downgrading. The code remains transparent and accessible, simplifying maintenance, library integration, and speeding
39
- up development.
40
-
41
- 7. **Optimize Code and Docs for LLMs:** Code and documentation are organized to be easily analyzed and supplemented by
42
- language models. Clear structure, standardized templates, and predictable conventions simplify automation and code
43
- generation.
44
-
45
- ## Principles in Detail
46
-
47
- ### Use a Unified Development Language
48
-
49
- Using modern JavaScript (ES6+) at all application levels eliminates the need to switch between different languages and
50
- simplifies knowledge sharing among developers. This is especially important in small teams and projects with limited
51
- resources, where minimizing cognitive load accelerates work.
52
-
53
- Browsers support only JavaScript (among high-level languages), and thanks to Node.js, it has become widespread in server
54
- development. This enables writing **isomorphic code** that can be reused on both client and server sides, reducing logic
55
- duplication.
56
-
57
- A unified language simplifies code maintenance and accelerates the onboarding of new developers into the project.
58
-
59
- ### Enable Late Binding for Flexibility
60
-
61
- Late binding ensures architectural flexibility by allowing dynamic dependency management without tight coupling between
62
- modules. Instead of direct imports, ES6 module namespaces and an object container are used to handle instantiation and
63
- component replacement at runtime.
64
-
65
- This approach reduces the risk of application "breakage" due to changes, simplifies system expansion, and makes the code
66
- more adaptable. Components can be replaced without deep refactoring, and the dependency mechanism remains transparent
67
- and predictable.
68
-
69
- Late binding also improves testability: modules can be replaced with stubs or alternative implementations, making it
70
- easier to isolate tests. In team development, this simplifies understanding of complex dependencies and makes system
71
- maintenance more manageable.
72
-
73
- ### Design for Evolutionary Code Resilience
74
-
75
- Code is designed to adapt to inevitable changes in requirements, APIs, and data with minimal overhead. This is achieved
76
- through approaches that allow **expanding functionality without significant modifications to existing code**.
77
-
78
- Key techniques:
79
-
80
- - **Flexible input data processing.** Using function argument destructuring and the "ignore unknown attributes"
81
- principle in data structures allows adding new parameters and properties without modifying existing handlers.
82
- - **Clear interaction contracts.** Separating interfaces from implementations reduces the impact of changes while
83
- maintaining system predictability.
84
- - **Late binding.** Components depend on abstractions rather than specific implementations, enabling code adaptation
85
- without directly modifying dependencies (see **Enable Late Binding for Flexibility** principle).
86
-
87
- These methods make the code less fragile and allow the system to evolve while reducing complexity and refactoring
88
- volume.
89
-
90
- ### Separate Data and Logic Functionally
91
-
92
- Code is divided into **data structures (DTO) and logic handlers**, eliminating state within handlers and making them
93
- independent of data. DTOs contain all necessary information and are passed between handlers that perform operations on
94
- them.
95
-
96
- This approach offers several key advantages:
97
-
98
- - **Handlers can be singletons.** Since they do not store state, they are execution-context-independent and can be
99
- shared across the entire application.
100
- - **The program consists of data processing nodes.** The code is structured as a set of functions that receive data,
101
- process it, and pass it on.
102
- - **Changeability through pure logic.** Logic remains separate from data structures, allowing modifications without
103
- affecting handlers and vice versa.
104
- - **Minimized side effects.** Handlers do not depend on global state, making the system more predictable.
105
-
106
- ### Use Namespaces for Structure and Isolation
107
-
108
- Namespaces ensure a clear project structure and prevent conflicts by allowing each entity to reserve its name and build
109
- its own hierarchy. This principle applies at all levels:
110
-
111
- - **Packages and modules.** npm packages and ES6 modules are organized into predictable namespaces, avoiding dependency
112
- conflicts.
113
- - **Files and classes.** File and class names reflect their purpose and relationships with other components, simplifying
114
- project navigation and structure.
115
- - **Database tables.** Table names are structured to avoid collisions and logically group data.
116
- - **Endpoints and APIs.** Namespaces are used in routing and APIs, ensuring consistent addressing.
117
- - **Configurations and CLI commands.** Settings and commands are organized hierarchically to prevent duplication.
118
-
119
- Code is designed to operate in an environment with other code. Each unit within its namespace reserves a name and builds
120
- a downward hierarchy, creating a predictable interaction structure.
121
-
122
- ### Favor Pure JavaScript Without Compilation
123
-
124
- Tequila Framework uses modern JavaScript (ES6+) without version downgrading or strict TypeScript typing. The code
125
- remains in its original form, making it transparent, accessible, and easy to maintain.
126
-
127
- Key characteristics:
128
-
129
- - **No compilation.** Developers work with pure JavaScript without intermediate transformations, speeding up debugging
130
- and simplifying maintenance.
131
- - **JSDoc instead of TypeScript.** JSDoc annotations allow IDEs to understand data structures and provide
132
- autocompletion, maintaining flexibility without strict typing.
133
- - **Maximum compatibility.** The code easily integrates with any libraries and tools, as it does not require adaptation
134
- to strict type contracts.
135
- - **Fast development.** Changes are immediately reflected in the code without requiring a rebuild, increasing
136
- development speed.
137
-
138
- ### Optimize Code and Docs for LLMs
139
-
140
- Architecture, code, and documentation are designed for easy analysis and use by language models (LLM). This improves the
141
- efficiency of **automatic code completion, generation of template solutions, and integration with AI tools**.
142
-
143
- For this, the following practices are applied:
144
-
145
- - **Predictable project structure.** Clear file organization, logical naming, and standardized conventions.
146
- - **Unified code templates.** Repetitive structures and a predictable format help models understand and supplement the
147
- code.
148
- - **Optimized abstraction depth.** Code is organized to maintain modularity while avoiding excessive nesting.
149
- - **Automated annotations.** JSDoc and standardized comments ensure precise code generation and documentation.
150
-
151
- This approach allows LLM agents to:
152
-
153
- - Quickly analyze code and suggest corrections.
154
- - Automatically supplement documentation and comment code.
155
- - Generate new modules according to the project's architectural standards.
156
- - Simplify CI/CD integration by checking code compliance with style and conventions.
157
-
158
- LLMs become part of the development process, helping not only with writing code but also keeping it up to date, reducing
159
- developers' routine workload.
160
-
161
- ## Conclusion
162
-
163
- The principles outlined in this document form an approach to **modular monolith** development, focused on
164
- predictability, structure, and adaptability. They enable building architectures where code remains flexible,
165
- transparent, and easily extensible.
166
-
167
- These ideas do not require complex theoretical justifications or significant time investments for validation. They aim
168
- to simplify integration, reduce unnecessary complexity, and enhance the potential for automation. **Standardized
169
- structures, predictable namespaces, and development without transpilation** create an environment where the code is
170
- understandable both for developers and language models (LLM).
171
-
172
- The **Tequila Framework (TeqFW)** platform demonstrates these principles in action. While still evolving, it already
173
- supports real-world development. This approach may serve not only as a foundation for proprietary tools, but also as
174
- inspiration for rethinking conventional software architecture, prioritizing clarity, modularity, and adaptability over
175
- unnecessary complexity.
package/eslint.config.js DELETED
@@ -1,37 +0,0 @@
1
- // eslint.config.js
2
- import js from '@eslint/js';
3
-
4
- /** @type {import('eslint').Linter.FlatConfig[]} */
5
- export default [
6
- js.configs.recommended,
7
- {
8
- languageOptions: {
9
- ecmaVersion: 2022, // required for public class fields
10
- sourceType: 'module',
11
- globals: {
12
- console: 'readonly',
13
- },
14
- },
15
- rules: {
16
- 'camelcase': [
17
- 'warn',
18
- {
19
- properties: 'never',
20
- ignoreDestructuring: true,
21
- allow: ['^([A-Z][a-zA-Z0-9]*_)+[A-Z][a-zA-Z0-9]*$'],
22
- },
23
- ],
24
- 'indent': ['error', 4],
25
- 'linebreak-style': ['error', 'unix'],
26
- 'quotes': ['error', 'single'],
27
- 'semi': ['error', 'always'],
28
- },
29
- },
30
- // Special rule override for interface declarations
31
- {
32
- files: ['./src/Api/**/*.js'],
33
- rules: {
34
- 'no-unused-vars': 'off',
35
- },
36
- },
37
- ];
package/rollup.config.js DELETED
@@ -1,21 +0,0 @@
1
- import resolve from '@rollup/plugin-node-resolve';
2
- import terser from '@rollup/plugin-terser';
3
-
4
- export default {
5
- input: 'src/Container.js',
6
- output: [
7
- {
8
- file: 'dist/esm.js',
9
- format: 'es'
10
- },
11
- {
12
- file: 'dist/umd.js',
13
- format: 'umd',
14
- name: 'TeqFw_Di_Container',
15
- }
16
- ],
17
- plugins: [
18
- resolve(),
19
- terser()
20
- ]
21
- };
package/teqfw.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "@teqfw/di": {
3
- "autoload": {
4
- "ns": "TeqFw_Di_",
5
- "path": "./src"
6
- }
7
- }
8
- }
@@ -1,98 +0,0 @@
1
- import parse from '../../../../../src/Container/A/Composer/A/SpecParser.js';
2
- import {describe, it} from 'node:test';
3
- import assert from 'node:assert';
4
-
5
-
6
- describe('TeqFw_Di_Container_A_Composer_A_SpecParser', () => {
7
-
8
- it('parses not a function', async () => {
9
- const deps = parse('namedSingleton');
10
- assert(deps, []);
11
- });
12
-
13
- describe('parses an arrow function', () => {
14
- it('w/o arguments', async () => {
15
- const fn = () => {};
16
- const deps = parse(fn);
17
- assert(deps, []);
18
- });
19
- it('with simple arguments', async () => {
20
- const fn = ({container, logger, config}) => {};
21
- const deps = parse(fn);
22
- assert(deps, []);
23
- });
24
- it('with complex arguments', async () => {
25
- const fn = (
26
- {
27
- Vnd_Pkg_Mod1,
28
- Vnd_Pkg_Mod2$,
29
- Vnd_Pkg_Mod3$$,
30
- 'Vnd_Pkg_Mod4.exp': exp,
31
- }
32
- ) => {};
33
- const deps = parse(fn);
34
- assert(deps.length, 4);
35
- });
36
- });
37
-
38
- describe('parses a regular function', () => {
39
- it('w/o arguments', async () => {
40
- const fn = function () {};
41
- const deps = parse(fn);
42
- assert(deps, []);
43
- });
44
- it('with simple arguments', async () => {
45
- const fn = function ({container, logger, config}) {};
46
- const deps = parse(fn);
47
- assert(deps, []);
48
- });
49
- it('with complex arguments', async () => {
50
- const fn = function (
51
- {
52
- Vnd_Pkg_Mod1,
53
- Vnd_Pkg_Mod2$,
54
- Vnd_Pkg_Mod3$$,
55
- 'Vnd_Pkg_Mod4.exp': exp,
56
- }
57
- ) {};
58
- const deps = parse(fn);
59
- assert(deps.length, 4);
60
- });
61
- });
62
-
63
- describe('parses a class', () => {
64
- it('w/o arguments', async () => {
65
- const Clazz = class {
66
- constructor() { }
67
-
68
- };
69
- const deps = parse(Clazz);
70
- assert(deps, []);
71
- });
72
- it('with simple arguments', async () => {
73
- const Clazz = class {
74
- constructor({container, logger, config}) { }
75
-
76
- };
77
- const deps = parse(Clazz);
78
- assert(deps, []);
79
- });
80
- it('with complex arguments', async () => {
81
- const Clazz = class {
82
- constructor(
83
- {
84
- Vnd_Pkg_Mod1,
85
- Vnd_Pkg_Mod2$,
86
- Vnd_Pkg_Mod3$$,
87
- 'Vnd_Pkg_Mod4.exp': exp,
88
- }
89
- ) { }
90
-
91
- };
92
- const deps = parse(Clazz);
93
- assert(deps.length, 4);
94
- });
95
- });
96
-
97
-
98
- });
@@ -1,237 +0,0 @@
1
- /**
2
- * Default format for the objects:
3
- * - Ns_Module: es6 module
4
- * - Ns_Module$: default export, factory, singleton (the most frequently used case)
5
- * - Ns_Module$$: default export, factory, instance
6
- * - Ns_Module.default: default export, as-is, singleton
7
- * - Ns_Module.name: named export, as-is, singleton
8
- * - Ns_Module.name$: named export, factory, singleton (the most frequently used case)
9
- * - Ns_Module.name$$: named export, factory, instance
10
- * - Ns_Module$(proxy): default export, factory, singleton with one post wrapper
11
- * - Ns_Module$(proxy,factory): default export, factory, singleton with two post wrappers
12
- */
13
- import DefChunk from '../../../../../src/Container/A/Parser/Chunk/Def.js';
14
- import {describe, it} from 'node:test';
15
- import assert from 'node:assert';
16
- import Defs from '../../../../../src/Defs.js';
17
-
18
- describe('TeqFw_Di_Container_A_Parser_Chunk_Def', () => {
19
-
20
- const chunk = new DefChunk();
21
-
22
- describe('should parse:', () => {
23
-
24
- describe('default export:', () => {
25
- it('es6 module (Ns_Module)', () => {
26
- /** @type {TeqFw_Di_DepId} */
27
- const dto = chunk.parse('Ns_Module');
28
- assert.strictEqual(dto.composition, undefined);
29
- assert.strictEqual(dto.exportName, undefined);
30
- assert.strictEqual(dto.life, undefined);
31
- assert.strictEqual(dto.moduleName, 'Ns_Module');
32
- assert.strictEqual(dto.origin, 'Ns_Module');
33
- assert.strictEqual(dto.wrappers.length, 0);
34
- });
35
- it('factory, singleton (Ns_Module$)', () => {
36
- /** @type {TeqFw_Di_DepId} */
37
- const dto = chunk.parse('Ns_Module$');
38
- assert.strictEqual(dto.composition, Defs.CF);
39
- assert.strictEqual(dto.exportName, 'default');
40
- assert.strictEqual(dto.life, Defs.LS);
41
- assert.strictEqual(dto.moduleName, 'Ns_Module');
42
- assert.strictEqual(dto.origin, 'Ns_Module$');
43
- assert.strictEqual(dto.wrappers.length, 0);
44
- });
45
- it('factory, instance (Ns_Module$$)', () => {
46
- /** @type {TeqFw_Di_DepId} */
47
- const dto = chunk.parse('Ns_Module$$');
48
- assert.strictEqual(dto.composition, Defs.CF);
49
- assert.strictEqual(dto.exportName, 'default');
50
- assert.strictEqual(dto.life, Defs.LI);
51
- assert.strictEqual(dto.moduleName, 'Ns_Module');
52
- assert.strictEqual(dto.origin, 'Ns_Module$$');
53
- assert.strictEqual(dto.wrappers.length, 0);
54
- });
55
- it('default export, as-is, singleton (Ns_Module.)', () => {
56
- /** @type {TeqFw_Di_DepId} */
57
- const dto = chunk.parse('Ns_Module.');
58
- assert.strictEqual(dto.composition, Defs.CA);
59
- assert.strictEqual(dto.exportName, 'default');
60
- assert.strictEqual(dto.life, Defs.LS);
61
- assert.strictEqual(dto.moduleName, 'Ns_Module');
62
- assert.strictEqual(dto.origin, 'Ns_Module.');
63
- assert.strictEqual(dto.wrappers.length, 0);
64
- });
65
- it('factory, singleton, wrapper (Ns_Module$(proxy))', () => {
66
- /** @type {TeqFw_Di_DepId} */
67
- const dto = chunk.parse('Ns_Module$(proxy)');
68
- assert.strictEqual(dto.composition, Defs.CF);
69
- assert.strictEqual(dto.exportName, 'default');
70
- assert.strictEqual(dto.life, Defs.LS);
71
- assert.strictEqual(dto.moduleName, 'Ns_Module');
72
- assert.strictEqual(dto.origin, 'Ns_Module$(proxy)');
73
- assert.strictEqual(dto.wrappers.length, 1);
74
- });
75
- it('factory, singleton, wrappers (Ns_Module$(proxy,factory))', () => {
76
- /** @type {TeqFw_Di_DepId} */
77
- const dto = chunk.parse('Ns_Module$(proxy,factory)');
78
- assert.strictEqual(dto.composition, Defs.CF);
79
- assert.strictEqual(dto.exportName, 'default');
80
- assert.strictEqual(dto.life, Defs.LS);
81
- assert.strictEqual(dto.moduleName, 'Ns_Module');
82
- assert.strictEqual(dto.origin, 'Ns_Module$(proxy,factory)');
83
- assert.strictEqual(dto.wrappers.length, 2);
84
- });
85
- });
86
-
87
- describe('named export:', () => {
88
- it('as-is, singleton (Ns_Module.name)', () => {
89
- /** @type {TeqFw_Di_DepId} */
90
- const dto = chunk.parse('Ns_Module.name');
91
- assert.strictEqual(dto.composition, Defs.CA);
92
- assert.strictEqual(dto.exportName, 'name');
93
- assert.strictEqual(dto.life, Defs.LS);
94
- assert.strictEqual(dto.moduleName, 'Ns_Module');
95
- assert.strictEqual(dto.origin, 'Ns_Module.name');
96
- assert.strictEqual(dto.wrappers.length, 0);
97
- });
98
- it('factory, singleton (Ns_Module.name$)', () => {
99
- /** @type {TeqFw_Di_DepId} */
100
- const dto = chunk.parse('Ns_Module.name$');
101
- assert.strictEqual(dto.composition, Defs.CF);
102
- assert.strictEqual(dto.exportName, 'name');
103
- assert.strictEqual(dto.life, Defs.LS);
104
- assert.strictEqual(dto.moduleName, 'Ns_Module');
105
- assert.strictEqual(dto.origin, 'Ns_Module.name$');
106
- assert.strictEqual(dto.wrappers.length, 0);
107
- });
108
- it('factory, instance (Ns_Module.name$$)', () => {
109
- /** @type {TeqFw_Di_DepId} */
110
- const dto = chunk.parse('Ns_Module.name$$');
111
- assert.strictEqual(dto.composition, Defs.CF);
112
- assert.strictEqual(dto.exportName, 'name');
113
- assert.strictEqual(dto.life, Defs.LI);
114
- assert.strictEqual(dto.moduleName, 'Ns_Module');
115
- assert.strictEqual(dto.origin, 'Ns_Module.name$$');
116
- assert.strictEqual(dto.wrappers.length, 0);
117
- });
118
- it('factory, singleton.wrapper (Ns_Module.name$(proxy))', () => {
119
- /** @type {TeqFw_Di_DepId} */
120
- const dto = chunk.parse('Ns_Module.name$(proxy)');
121
- assert.strictEqual(dto.composition, Defs.CF);
122
- assert.strictEqual(dto.exportName, 'name');
123
- assert.strictEqual(dto.life, Defs.LS);
124
- assert.strictEqual(dto.moduleName, 'Ns_Module');
125
- assert.strictEqual(dto.origin, 'Ns_Module.name$(proxy)');
126
- assert.strictEqual(dto.wrappers.length, 1);
127
- });
128
- it('factory, singleton.wrappers (Ns_Module.name$(proxy,factory))', () => {
129
- /** @type {TeqFw_Di_DepId} */
130
- const dto = chunk.parse('Ns_Module.name$(proxy,factory)');
131
- assert.strictEqual(dto.composition, Defs.CF);
132
- assert.strictEqual(dto.exportName, 'name');
133
- assert.strictEqual(dto.life, Defs.LS);
134
- assert.strictEqual(dto.moduleName, 'Ns_Module');
135
- assert.strictEqual(dto.origin, 'Ns_Module.name$(proxy,factory)');
136
- assert.strictEqual(dto.wrappers.length, 2);
137
- });
138
- });
139
-
140
- describe('named export with "#" separator:', () => {
141
- it('as-is, singleton (Ns_Module#name)', () => {
142
- const dto = chunk.parse('Ns_Module#name');
143
- assert.strictEqual(dto.composition, Defs.CA);
144
- assert.strictEqual(dto.exportName, 'name');
145
- assert.strictEqual(dto.life, Defs.LS);
146
- assert.strictEqual(dto.moduleName, 'Ns_Module');
147
- assert.strictEqual(dto.origin, 'Ns_Module#name');
148
- assert.strictEqual(dto.wrappers.length, 0);
149
- });
150
- it('factory, singleton (Ns_Module#name$)', () => {
151
- const dto = chunk.parse('Ns_Module#name$');
152
- assert.strictEqual(dto.composition, Defs.CF);
153
- assert.strictEqual(dto.exportName, 'name');
154
- assert.strictEqual(dto.life, Defs.LS);
155
- assert.strictEqual(dto.moduleName, 'Ns_Module');
156
- assert.strictEqual(dto.origin, 'Ns_Module#name$');
157
- assert.strictEqual(dto.wrappers.length, 0);
158
- });
159
- it('factory, instance (Ns_Module#name$$)', () => {
160
- const dto = chunk.parse('Ns_Module#name$$');
161
- assert.strictEqual(dto.composition, Defs.CF);
162
- assert.strictEqual(dto.exportName, 'name');
163
- assert.strictEqual(dto.life, Defs.LI);
164
- assert.strictEqual(dto.moduleName, 'Ns_Module');
165
- assert.strictEqual(dto.origin, 'Ns_Module#name$$');
166
- assert.strictEqual(dto.wrappers.length, 0);
167
- });
168
- it('factory, singleton with wrappers (Ns_Module#name$(proxy,factory))', () => {
169
- const dto = chunk.parse('Ns_Module#name$(proxy,factory)');
170
- assert.strictEqual(dto.composition, Defs.CF);
171
- assert.strictEqual(dto.exportName, 'name');
172
- assert.strictEqual(dto.life, Defs.LS);
173
- assert.strictEqual(dto.moduleName, 'Ns_Module');
174
- assert.strictEqual(dto.origin, 'Ns_Module#name$(proxy,factory)');
175
- assert.strictEqual(dto.wrappers.length, 2);
176
- });
177
- });
178
-
179
- describe('nodejs package:', () => {
180
- it('es6 module (node:pkg)', () => {
181
- const dto = chunk.parse('node:pkg');
182
- assert.strictEqual(dto.isNodeModule, true);
183
- assert.strictEqual(dto.moduleName, 'pkg');
184
- assert.strictEqual(dto.composition, undefined);
185
- assert.strictEqual(dto.exportName, undefined);
186
- assert.strictEqual(dto.life, undefined);
187
- assert.strictEqual(dto.origin, 'node:pkg');
188
- });
189
- it('default export, singleton (node:pkg$$)', () => {
190
- const dto = chunk.parse('node:pkg$$');
191
- assert.strictEqual(dto.isNodeModule, true);
192
- assert.strictEqual(dto.moduleName, 'pkg');
193
- assert.strictEqual(dto.composition, Defs.CF);
194
- assert.strictEqual(dto.exportName, 'default');
195
- assert.strictEqual(dto.life, Defs.LI);
196
- assert.strictEqual(dto.origin, 'node:pkg$$');
197
- });
198
- it('named export (node:pkg.export)', () => {
199
- const dto = chunk.parse('node:pkg.export');
200
- assert.strictEqual(dto.isNodeModule, true);
201
- assert.strictEqual(dto.moduleName, 'pkg');
202
- assert.strictEqual(dto.composition, Defs.CA);
203
- assert.strictEqual(dto.exportName, 'export');
204
- assert.strictEqual(dto.life, Defs.LS);
205
- assert.strictEqual(dto.origin, 'node:pkg.export');
206
- });
207
- it('named export, factory (node:pkg.export$$)', () => {
208
- const dto = chunk.parse('node:pkg.export$$');
209
- assert.strictEqual(dto.isNodeModule, true);
210
- assert.strictEqual(dto.moduleName, 'pkg');
211
- assert.strictEqual(dto.composition, Defs.CF);
212
- assert.strictEqual(dto.exportName, 'export');
213
- assert.strictEqual(dto.life, Defs.LI);
214
- assert.strictEqual(dto.origin, 'node:pkg.export$$');
215
- });
216
- it('scoped package (node:@teqfw/db)', () => {
217
- const dto = chunk.parse('node:@teqfw/db');
218
- assert.strictEqual(dto.isNodeModule, true);
219
- assert.strictEqual(dto.moduleName, '@teqfw/db');
220
- assert.strictEqual(dto.composition, undefined);
221
- assert.strictEqual(dto.exportName, undefined);
222
- assert.strictEqual(dto.life, undefined);
223
- assert.strictEqual(dto.origin, 'node:@teqfw/db');
224
- });
225
- it('scoped package export (node:@teqfw/db.export$$)', () => {
226
- const dto = chunk.parse('node:@teqfw/db.export$$');
227
- assert.strictEqual(dto.isNodeModule, true);
228
- assert.strictEqual(dto.moduleName, '@teqfw/db');
229
- assert.strictEqual(dto.composition, Defs.CF);
230
- assert.strictEqual(dto.exportName, 'export');
231
- assert.strictEqual(dto.life, Defs.LI);
232
- assert.strictEqual(dto.origin, 'node:@teqfw/db.export$$');
233
- });
234
- });
235
- });
236
-
237
- });
@@ -1,138 +0,0 @@
1
- /**
2
- * Default format for the objects:
3
- * - Ns_Module: es6 module
4
- * - Ns_Module$: default export, factory, singleton (the most frequently used case)
5
- * - Ns_Module$I: default export, factory, instance
6
- * - Ns_Module$AS: default export, as-is, singleton
7
- * - Ns_Module.name: named export, as-is, singleton
8
- * - Ns_Module.name$: named export, factory, singleton (the most frequently used case)
9
- * - Ns_Module.name$I: named export, factory, instance
10
- */
11
- import DefChunk from '../../../../../src/Container/A/Parser/Chunk/V02X.js';
12
- import {describe, it} from 'node:test';
13
- import assert from 'node:assert';
14
- import Defs from '../../../../../src/Defs.js';
15
-
16
- describe('TeqFw_Di_Container_A_Parser_Chunk_V02X', () => {
17
-
18
- const chunk = new DefChunk();
19
-
20
- describe('should parse:', () => {
21
-
22
- describe('default export:', () => {
23
- it('es6 module (Ns_Module)', () => {
24
- /** @type {TeqFw_Di_DepId} */
25
- const dto = chunk.parse('Ns_Module');
26
- assert.strictEqual(dto.composition, undefined);
27
- assert.strictEqual(dto.exportName, undefined);
28
- assert.strictEqual(dto.life, undefined);
29
- assert.strictEqual(dto.moduleName, 'Ns_Module');
30
- assert.strictEqual(dto.origin, 'Ns_Module');
31
- assert.strictEqual(dto.wrappers.length, 0);
32
- });
33
- it('factory, singleton (Ns_Module$)', () => {
34
- /** @type {TeqFw_Di_DepId} */
35
- const dto = chunk.parse('Ns_Module$');
36
- assert.strictEqual(dto.composition, Defs.CF);
37
- assert.strictEqual(dto.exportName, 'default');
38
- assert.strictEqual(dto.life, Defs.LS);
39
- assert.strictEqual(dto.moduleName, 'Ns_Module');
40
- assert.strictEqual(dto.origin, 'Ns_Module$');
41
- assert.strictEqual(dto.wrappers.length, 0);
42
- });
43
- it('factory, instance (Ns_Module$I)', () => {
44
- /** @type {TeqFw_Di_DepId} */
45
- const dto = chunk.parse('Ns_Module$I');
46
- assert.strictEqual(dto.composition, Defs.CF);
47
- assert.strictEqual(dto.exportName, 'default');
48
- assert.strictEqual(dto.life, Defs.LI);
49
- assert.strictEqual(dto.moduleName, 'Ns_Module');
50
- assert.strictEqual(dto.origin, 'Ns_Module$I');
51
- assert.strictEqual(dto.wrappers.length, 0);
52
- });
53
- it('default export, as-is, singleton (Ns_Module$AS)', () => {
54
- /** @type {TeqFw_Di_DepId} */
55
- const dto = chunk.parse('Ns_Module$AS');
56
- assert.strictEqual(dto.composition, Defs.CA);
57
- assert.strictEqual(dto.exportName, 'default');
58
- assert.strictEqual(dto.life, Defs.LS);
59
- assert.strictEqual(dto.moduleName, 'Ns_Module');
60
- assert.strictEqual(dto.origin, 'Ns_Module$AS');
61
- assert.strictEqual(dto.wrappers.length, 0);
62
- });
63
- });
64
-
65
- describe('named export:', () => {
66
- it('as-is, singleton (Ns_Module.name)', () => {
67
- /** @type {TeqFw_Di_DepId} */
68
- const dto = chunk.parse('Ns_Module.name');
69
- assert.strictEqual(dto.composition, Defs.CA);
70
- assert.strictEqual(dto.exportName, 'name');
71
- assert.strictEqual(dto.life, Defs.LS);
72
- assert.strictEqual(dto.moduleName, 'Ns_Module');
73
- assert.strictEqual(dto.origin, 'Ns_Module.name');
74
- assert.strictEqual(dto.wrappers.length, 0);
75
- });
76
- it('factory, singleton (Ns_Module.name$)', () => {
77
- /** @type {TeqFw_Di_DepId} */
78
- const dto = chunk.parse('Ns_Module.name$');
79
- assert.strictEqual(dto.composition, Defs.CF);
80
- assert.strictEqual(dto.exportName, 'name');
81
- assert.strictEqual(dto.life, Defs.LS);
82
- assert.strictEqual(dto.moduleName, 'Ns_Module');
83
- assert.strictEqual(dto.origin, 'Ns_Module.name$');
84
- assert.strictEqual(dto.wrappers.length, 0);
85
- });
86
- it('factory, instance (Ns_Module.name$I)', () => {
87
- /** @type {TeqFw_Di_DepId} */
88
- const dto = chunk.parse('Ns_Module.name$I');
89
- assert.strictEqual(dto.composition, Defs.CF);
90
- assert.strictEqual(dto.exportName, 'name');
91
- assert.strictEqual(dto.life, Defs.LI);
92
- assert.strictEqual(dto.moduleName, 'Ns_Module');
93
- assert.strictEqual(dto.origin, 'Ns_Module.name$I');
94
- assert.strictEqual(dto.wrappers.length, 0);
95
- });
96
- });
97
-
98
- describe('nodejs package:', () => {
99
- it('es6 module (node:pkg)', () => {
100
- const dto = chunk.parse('node:pkg');
101
- assert.strictEqual(dto.isNodeModule, true);
102
- assert.strictEqual(dto.moduleName, 'pkg');
103
- assert.strictEqual(dto.composition, undefined);
104
- assert.strictEqual(dto.exportName, undefined);
105
- assert.strictEqual(dto.life, undefined);
106
- assert.strictEqual(dto.origin, 'node:pkg');
107
- });
108
- it('default export, singleton (node:pkg$)', () => {
109
- const dto = chunk.parse('node:pkg$');
110
- assert.strictEqual(dto.isNodeModule, true);
111
- assert.strictEqual(dto.moduleName, 'pkg');
112
- assert.strictEqual(dto.composition, Defs.CF);
113
- assert.strictEqual(dto.exportName, 'default');
114
- assert.strictEqual(dto.life, Defs.LS);
115
- assert.strictEqual(dto.origin, 'node:pkg$');
116
- });
117
- it('named export (node:pkg.export)', () => {
118
- const dto = chunk.parse('node:pkg.export');
119
- assert.strictEqual(dto.isNodeModule, true);
120
- assert.strictEqual(dto.moduleName, 'pkg');
121
- assert.strictEqual(dto.composition, Defs.CA);
122
- assert.strictEqual(dto.exportName, 'export');
123
- assert.strictEqual(dto.life, Defs.LS);
124
- assert.strictEqual(dto.origin, 'node:pkg.export');
125
- });
126
- it('named export, factory (node:pkg.export$)', () => {
127
- const dto = chunk.parse('node:pkg.export$');
128
- assert.strictEqual(dto.isNodeModule, true);
129
- assert.strictEqual(dto.moduleName, 'pkg');
130
- assert.strictEqual(dto.composition, Defs.CF);
131
- assert.strictEqual(dto.exportName, 'export');
132
- assert.strictEqual(dto.life, Defs.LS);
133
- assert.strictEqual(dto.origin, 'node:pkg.export$');
134
- });
135
- });
136
- });
137
-
138
- });
@@ -1,141 +0,0 @@
1
- import {dirname, join} from 'node:path';
2
- import assert from 'node:assert';
3
- import {describe, it} from 'node:test';
4
- import Container from '../src/Container.js';
5
- import Defs from '../src/Defs.js';
6
-
7
- const __dirname = dirname(import.meta.url);
8
- const ROOT = join(__dirname, '_data', 'Container');
9
-
10
- describe('TeqFw_Di_Container', () => {
11
-
12
- describe('basic tests', () => {
13
- it('has right classname', async () => {
14
- const container = new Container();
15
- assert.strictEqual(container.constructor.name, 'TeqFw_Di_Container');
16
- });
17
-
18
- it('has all expected public methods', async () => {
19
- const container = new Container();
20
- const methods = Object.getOwnPropertyNames(container)
21
- .filter(p => (typeof container[p] === 'function'));
22
- assert.deepStrictEqual(methods.sort(), [
23
- 'enableTestMode',
24
- 'get',
25
- 'getParser',
26
- 'getPostProcessor',
27
- 'getPreProcessor',
28
- 'getResolver',
29
- 'register',
30
- 'setDebug',
31
- 'setParser',
32
- 'setPostProcessor',
33
- 'setPreProcessor',
34
- 'setResolver',
35
- ]);
36
- });
37
-
38
- it('does not contain itself inside', async () => {
39
- const container = new Container();
40
- await assert.rejects(
41
- async () => {
42
- await container.get('container');
43
- },
44
- {
45
- code: 'ERR_MODULE_NOT_FOUND',
46
- message: /^Cannot find package 'container'/
47
- }
48
- );
49
- });
50
- });
51
-
52
- describe('creates objects', () => {
53
-
54
- it('default export singleton (App_Service$)', async () => {
55
- const container = new Container();
56
- container.setDebug(true);
57
- const resolver = container.getResolver();
58
- const src = join(ROOT, 'classes');
59
- resolver.addNamespaceRoot('App_', src, 'js');
60
- const dep = await container.get('App_Service$');
61
- assert(dep);
62
- assert(Object.isFrozen(dep));
63
- dep({boobs: 'big'});
64
- });
65
-
66
- });
67
-
68
- describe('prevents loops', () => {
69
-
70
- it('simple loop', async () => {
71
- const container = new Container();
72
- container.setDebug(true);
73
- const resolver = container.getResolver();
74
- const src = join(ROOT, 'loop');
75
- resolver.addNamespaceRoot('App_', src, 'js');
76
- try {
77
- await container.get('App_Service$');
78
- } catch (e) {
79
- assert(e);
80
- }
81
- });
82
-
83
- });
84
-
85
- describe('register()', () => {
86
-
87
- it('registers a new singleton successfully when test mode is enabled', async () => {
88
- const container = new Container();
89
- container.enableTestMode();
90
- const obj = {hello: 'world'};
91
- container.register('My_Test_Module$', obj);
92
- const instance = await container.get('My_Test_Module$');
93
- assert.strictEqual(instance, obj);
94
- });
95
-
96
- it('throws if already registered, even in test mode', async () => {
97
- const container = new Container();
98
- container.enableTestMode();
99
- const obj = {hello: 'again'};
100
- container.register('My_Test_Module$', obj);
101
- assert.throws(() => {
102
- container.register('My_Test_Module$', {oops: true});
103
- }, /already registered/);
104
- });
105
-
106
- it('throws if test mode is not enabled', () => {
107
- const container = new Container();
108
- const obj = {unauthorized: true};
109
- assert.throws(() => {
110
- container.register('My_Test_Module$', obj);
111
- }, /Use enableTestMode\(\) to allow it/);
112
- });
113
-
114
- it('throws if depId is missing (in test mode)', () => {
115
- const container = new Container();
116
- container.enableTestMode();
117
- assert.throws(() => {
118
- container.register(undefined, {});
119
- }, /required/);
120
- });
121
-
122
- it('throws if object is missing (in test mode)', () => {
123
- const container = new Container();
124
- container.enableTestMode();
125
- assert.throws(() => {
126
- container.register('My_Missing_Obj$', null);
127
- }, /required/);
128
- });
129
-
130
- it('throws if trying to register a non-singleton (in test mode)', () => {
131
- const container = new Container();
132
- container.enableTestMode();
133
- assert.throws(() => {
134
- container.register('My_Test_Module$$', {notAllowed: true});
135
- }, /Only node modules & singletons can be registered/);
136
- });
137
-
138
- });
139
-
140
-
141
- });
@@ -1,3 +0,0 @@
1
- export default {
2
- appName: 'Test App',
3
- };
@@ -1,7 +0,0 @@
1
- export default async function ({App_Config: config}) {
2
- console.info(`Logger is created with config: '${JSON.stringify(config)}'`);
3
- return {
4
- error: (msg) => console.error(msg),
5
- info: (msg) => console.info(msg),
6
- };
7
- };
@@ -1,10 +0,0 @@
1
- export default async function (
2
- {
3
- App_Logger$: logger,
4
- App_Config: config,
5
- }
6
- ) {
7
- return function (opts) {
8
- logger.info(`Service '${config.appName}' is running with: ${JSON.stringify(opts)}`);
9
- };
10
- }
@@ -1,3 +0,0 @@
1
- export default {
2
- appName: 'Test App',
3
- };
@@ -1,7 +0,0 @@
1
- export default async function ({App_Config: config}) {
2
- console.info(`Logger is created with config: '${JSON.stringify(config)}'`);
3
- return {
4
- error: (msg) => console.error(msg),
5
- info: (msg) => console.info(msg),
6
- };
7
- };
@@ -1,15 +0,0 @@
1
- export default class App_Service {
2
- constructor(
3
- {
4
- App_Logger$: logger,
5
- App_Config: config,
6
- 'node:http2': http2,
7
- }
8
- ) {
9
- const {constants: {HTTP2_HEADER_CONTENT_TYPE}} = http2;
10
- return function (opts) {
11
- logger.info(`Service '${config.appName}' is running with: ${JSON.stringify(opts)}`);
12
- logger.info(`Header: ${HTTP2_HEADER_CONTENT_TYPE}`);
13
- };
14
- }
15
- }
@@ -1,7 +0,0 @@
1
- export default class {
2
- constructor({App_Service$}) {
3
- return {
4
- appName: 'Test App',
5
- };
6
- }
7
- };
@@ -1,7 +0,0 @@
1
- export default async function ({App_Config$I: config}) {
2
- console.info(`Logger is created with config: '${JSON.stringify(config)}'`);
3
- return {
4
- error: (msg) => console.error(msg),
5
- info: (msg) => console.info(msg),
6
- };
7
- };
@@ -1,12 +0,0 @@
1
- export default class App_Service {
2
- constructor(
3
- {
4
- App_Logger$: logger,
5
- App_Config: config,
6
- }
7
- ) {
8
- return function (opts) {
9
- logger.info(`Service '${config.appName}' is running with: ${JSON.stringify(opts)}`);
10
- };
11
- }
12
- }
@@ -1,3 +0,0 @@
1
- export default {
2
- appName: 'Test App',
3
- };
@@ -1,7 +0,0 @@
1
- export default async function ({App_Config: config}) {
2
- console.info(`Logger is created with config: '${JSON.stringify(config)}'`);
3
- return {
4
- error: (msg) => console.error(msg),
5
- info: (msg) => console.info(msg),
6
- };
7
- };
@@ -1,12 +0,0 @@
1
- export default class App_Service {
2
- constructor(
3
- {
4
- App_Logger$: logger,
5
- App_Config: config,
6
- }
7
- ) {
8
- return function (opts) {
9
- logger.info(`Service '${config.appName}' is running with: ${JSON.stringify(opts)}`);
10
- };
11
- }
12
- }