@teqfw/di 1.1.3 → 1.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.0
4
+
5
+ - Documented the dependency declaration model in the README and product overview.
6
+ - Refined the type map rules to clarify tsserver scope and public vs internal type visibility.
7
+ - Updated `types.d.ts` mappings to use `InstanceType` for class defaults and split internal aliases from globals.
8
+
3
9
  ## 1.1.3
4
10
 
5
11
  - Added global type declarations to `types.d.ts` to match the type map architecture rules.
package/README.md CHANGED
@@ -3,8 +3,7 @@
3
3
  ![npms.io](https://img.shields.io/npm/dm/@teqfw/di)
4
4
  ![jsdelivr](https://img.shields.io/jsdelivr/npm/hm/@teqfw/di)
5
5
 
6
- > [!IMPORTANT]
7
- > **Breaking Changes in v1.0.0**
6
+ > [!IMPORTANT] > **Breaking Changes in v1.0.0**
8
7
  >
9
8
  > The library has been stable for a long time and is now promoted to its first major version. To improve security, the Object Container can no longer access itself, so all configuration must occur in the Composition Root. This restriction ensures that third-party plugins cannot override or modify the container's internal functionality. Legacy versions are maintained in the `forerunner` branch, and packages like `@teqfw/core` should depend on `@teqfw/di` versions below `1.0.0`.
10
9
 
@@ -40,6 +39,17 @@ To explore the conceptual background, see: **[TeqFW Philosophy](./PHILOSOPHY.md)
40
39
 
41
40
  ---
42
41
 
42
+ ## Dependency Declaration Model
43
+
44
+ In `@teqfw/di`, dependencies are declared **exclusively in the constructor (or factory) signature**.
45
+ A component defines its dependencies using a **single object parameter**, where each property name
46
+ is a dependency identifier interpreted by the container.
47
+
48
+ The container analyzes the constructor signature, resolves all declared identifiers **before object
49
+ creation**, and invokes the constructor with a fully populated argument object. Created objects are isolated from the container.
50
+
51
+ ---
52
+
43
53
  ## Samples
44
54
 
45
55
  Explore `@teqfw/di` in action through the following demo applications:
@@ -70,41 +80,42 @@ configuring the container, and finally retrieving the main object with injected
70
80
  Here’s an example of how files might be organized in a project. This structure can vary depending on your project needs,
71
81
  as the container can be configured to work with any layout (e.g., within `/home/user/project/`):
72
82
 
73
- ```
74
- ./src/
75
- ./Service/
76
- ./Customer.js
77
- ./Sale.js
78
- ./Config.js
79
- ./Logger.js
80
- ./Main.js
81
- ```
83
+ ```text
84
+ ./src/
85
+ ./Service/
86
+ ./Customer.js
87
+ ./Sale.js
88
+ ./Config.js
89
+ ./Logger.js
90
+ ./Main.js
91
+ ```
82
92
 
83
93
  ### Step 2: Declare Dependencies
84
94
 
85
- In your code, declare dependencies by specifying them as keys in the constructor. Dependency identifiers here follow a
86
- namespace style similar to PHP Zend 1, which is used by default in this library. You can also implement a custom parser
87
- if you prefer a different naming convention or mapping strategy.
88
-
89
- ```js
90
- export default class App_Main {
91
- constructor(
92
- {
93
- App_Config$: config,
94
- App_Logger$: logger,
95
- App_Service_Customer$: servCustomer,
96
- App_Service_Sale$: servSale,
97
- }
98
- ) { /* ... */ }
95
+ In your code, declare dependencies by specifying them as keys in the constructor. This is the only supported
96
+ way to declare dependencies in `@teqfw/di`. Dependency identifiers here follow a namespace style similar to PHP
97
+ Zend 1, which is used by default in this library. You can also implement a custom parser if you prefer a
98
+ different naming convention or mapping strategy.
99
+
100
+ ```js
101
+ export default class App_Main {
102
+ constructor({
103
+ App_Config$: config,
104
+ App_Logger$: logger,
105
+ App_Service_Customer$: servCustomer,
106
+ App_Service_Sale$: servSale,
107
+ }) {
108
+ /* ... */
109
+ }
99
110
  }
100
- ```
111
+ ```
101
112
 
102
113
  ### Step 3: Configure the Container
103
114
 
104
115
  Next, set up the container and configure it to use the correct namespace and path for your dependencies:
105
116
 
106
- ```js
107
- import Container from '@teqfw/di';
117
+ ```js
118
+ import Container from "@teqfw/di";
108
119
 
109
120
  // Create a new instance of the container
110
121
  const container = new Container();
@@ -113,17 +124,17 @@ const container = new Container();
113
124
  const resolver = container.getResolver();
114
125
 
115
126
  // Define the namespace root for dependencies, allowing the container to resolve identifiers like 'App_*'
116
- resolver.addNamespaceRoot('App_', '/home/user/project/src');
117
- ```
127
+ resolver.addNamespaceRoot("App_", "/home/user/project/src");
128
+ ```
118
129
 
119
130
  ### Step 4: Retrieve the Main Object with Dependencies
120
131
 
121
132
  Finally, retrieve your main application instance. The container automatically injects all declared dependencies:
122
133
 
123
- ```js
124
- // Retrieve the main application instance as a singleton asynchronously
125
- const app = await container.get('App_Main$');
126
- ```
134
+ ```js
135
+ // Retrieve the main application instance as a singleton asynchronously
136
+ const app = await container.get("App_Main$");
137
+ ```
127
138
 
128
139
  ---
129
140
 
@@ -136,7 +147,7 @@ When test mode is enabled via `container.enableTestMode()`, you can manually reg
136
147
 
137
148
  ```js
138
149
  container.enableTestMode();
139
- container.register('App_Service_Customer$', mockCustomerService);
150
+ container.register("App_Service_Customer$", mockCustomerService);
140
151
  ```
141
152
 
142
153
  This makes it easy to substitute real implementations with mocks or stubs during tests, without altering production
@@ -148,17 +159,17 @@ A powerful feature of `@teqfw/di` is the ability to mock **Node.js built-in libr
148
159
  `process`. This is useful for isolating side effects and simulating system behavior:
149
160
 
150
161
  ```js
151
- container.register('node:fs', {
152
- existsSync: (path) => path.endsWith('.html'),
162
+ container.register("node:fs", {
163
+ existsSync: (path) => path.endsWith(".html"),
153
164
  });
154
165
  ```
155
166
 
156
167
  You can also register mocks for custom logic or environment-specific behavior:
157
168
 
158
169
  ```js
159
- container.register('node:path', {
160
- join: (...args) => args.join('/'),
161
- resolve: (p) => `/abs/${p}`,
170
+ container.register("node:path", {
171
+ join: (...args) => args.join("/"),
172
+ resolve: (p) => `/abs/${p}`,
162
173
  });
163
174
  ```
164
175
 
@@ -173,9 +184,8 @@ isolated, and deterministic unit tests — even for logic that relies on the fil
173
184
  extensive flexibility and configurability. This allows the library to adapt seamlessly to a wide range of project needs.
174
185
  Here’s what makes it stand out:
175
186
 
176
- - **Automatic Dependency Resolution**: The library simplifies managing complex objects and their dependencies by
177
- automatically resolving and injecting them based on container configuration. This basic functionality works out of the
178
- box but can be fully customized if needed.
187
+ - **Automatic Dependency Resolution**: The library resolves and injects dependencies by interpreting constructor
188
+ signatures. This basic functionality works out of the box but can be fully customized if needed.
179
189
 
180
190
  - **Flexible Dependency ID Configuration**: With customizable parsers and chunks, you can define unique ID schemes for
181
191
  dependencies, making it easy to adapt the library to specific naming conventions or custom mapping rules.
@@ -210,45 +220,43 @@ be easily customized to meet unique project demands.
210
220
 
211
221
  To install `@teqfw/di` in a Node.js environment, use the following command:
212
222
 
213
- ```shell
214
- $ npm install @teqfw/di
215
- ```
223
+ ```shell
224
+ npm install @teqfw/di
225
+ ```
216
226
 
217
227
  Then, import and initialize the container:
218
228
 
219
- ```js
220
- import Container from '@teqfw/di';
229
+ ```js
230
+ import Container from "@teqfw/di";
221
231
 
222
232
  /** @type {TeqFw_Di_Container} */
223
233
  const container = new Container();
224
- ```
234
+ ```
225
235
 
226
236
  ### For the Browser (ESM Module)
227
237
 
228
238
  To use `@teqfw/di` in a browser environment with ES modules, include it as follows (~5KB):
229
239
 
230
- ```html
231
-
240
+ ```html
232
241
  <script type="module">
233
- import Container from 'https://cdn.jsdelivr.net/npm/@teqfw/di@latest/+esm';
242
+ import Container from "https://cdn.jsdelivr.net/npm/@teqfw/di@latest/+esm";
234
243
 
235
- /** @type {TeqFw_Di_Container} */
236
- const container = new Container();
244
+ /** @type {TeqFw_Di_Container} */
245
+ const container = new Container();
237
246
  </script>
238
- ```
247
+ ```
239
248
 
240
249
  ### For the Browser (UMD Module)
241
250
 
242
251
  Alternatively, you can use the UMD version in the browser (~5KB):
243
252
 
244
- ```html
245
-
253
+ ```html
246
254
  <script src="https://cdn.jsdelivr.net/npm/@teqfw/di@latest/dist/umd.js"></script>
247
255
  <script>
248
- /** @type {TeqFw_Di_Container} */
249
- const container = new window.TeqFw_Di_Container();
256
+ /** @type {TeqFw_Di_Container} */
257
+ const container = new window.TeqFw_Di_Container();
250
258
  </script>
251
- ```
259
+ ```
252
260
 
253
261
  ---
254
262
 
@@ -259,35 +267,35 @@ Alternatively, you can use the UMD version in the browser (~5KB):
259
267
  1. **Configure Dependency Mapping**: Configure the resolver to detect the platform environment. Then, set up namespace
260
268
  roots to map dependency IDs to their source paths.
261
269
 
262
- ```js
263
- import { platform } from 'node:process';
270
+ ```js
271
+ import { platform } from "node:process";
264
272
 
265
- const resolver = container.getResolver();
266
- resolver.setWindowsEnv(platform === 'win32'); // Adjusts for Windows environment if needed
267
- resolver.addNamespaceRoot('App_', '/path/to/src');
268
- ```
273
+ const resolver = container.getResolver();
274
+ resolver.setWindowsEnv(platform === "win32"); // Adjusts for Windows environment if needed
275
+ resolver.addNamespaceRoot("App_", "/path/to/src");
276
+ ```
269
277
 
270
278
  2. **Retrieve Singleton Instances**: Retrieve the main application instance as a singleton asynchronously:
271
279
 
272
- ```js
273
- const app = await container.get('App_Main$');
274
- ```
280
+ ```js
281
+ const app = await container.get("App_Main$");
282
+ ```
275
283
 
276
284
  ### In the Browser
277
285
 
278
286
  1. **Configure Dependency Mapping**: Set up namespace roots to map dependency IDs to their source paths, using URLs as
279
287
  needed.
280
288
 
281
- ```js
282
- const resolver = container.getResolver();
283
- resolver.addNamespaceRoot('App_', 'https://cdn.jsdelivr.net/npm/@flancer64/demo-di-app@0.2/src');
284
- ```
289
+ ```js
290
+ const resolver = container.getResolver();
291
+ resolver.addNamespaceRoot("App_", "https://cdn.jsdelivr.net/npm/@flancer64/demo-di-app@0.2/src");
292
+ ```
285
293
 
286
294
  2. **Retrieve Singleton Instances**: Retrieve the main application instance as a singleton asynchronously:
287
295
 
288
- ```js
289
- const app = await container.get('App_Main$');
290
- ```
296
+ ```js
297
+ const app = await container.get("App_Main$");
298
+ ```
291
299
 
292
300
  With these steps, the container is configured to automatically resolve and inject dependencies based on your setup,
293
301
  whether in Node.js or in a browser environment.
@@ -300,7 +308,7 @@ whether in Node.js or in a browser environment.
300
308
  quick reference:
301
309
 
302
310
  | Dependency ID | Import Style | Description |
303
- |-----------------------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------|
311
+ | --------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
304
312
  | `App_Service` | `import * as Service from './App/Service.js';` | Imports the entire module as an ES module. |
305
313
  | `App_Service.default` | `import {default} from './App/Service.js';` | Imports the default export as-is. |
306
314
  | `App_Service.name` | `import {name} from './App/Service.js';` | Imports a named export as-is. |
@@ -316,20 +324,18 @@ Here’s an example showing a class with multiple dependencies, each using diffe
316
324
 
317
325
  ```js
318
326
  export default class App_Main {
319
- constructor(
320
- {
321
- App_Service: EsModule,
322
- 'App_Service.default': defaultExportAsIs,
323
- 'App_Service.name': namedExportAsIs,
324
- App_Service$: defaultExportAsSingleton,
325
- App_Service$$: defaultExportAsInstance,
326
- 'App_Service.name$': namedExportAsSingleton,
327
- 'App_Service.name$$': namedExportAsInstance,
328
- 'App_Service.name(factory)': factoryToCreateInstancesFromNamedExport,
329
- }
330
- ) {
331
- const {default: SrvDef, name: SrvName} = EsModule; // Deconstruct the module and access the exports
332
- }
327
+ constructor({
328
+ App_Service: EsModule,
329
+ "App_Service.default": defaultExportAsIs,
330
+ "App_Service.name": namedExportAsIs,
331
+ App_Service$: defaultExportAsSingleton,
332
+ App_Service$$: defaultExportAsInstance,
333
+ "App_Service.name$": namedExportAsSingleton,
334
+ "App_Service.name$$": namedExportAsInstance,
335
+ "App_Service.name(factory)": factoryToCreateInstancesFromNamedExport,
336
+ }) {
337
+ const { default: SrvDef, name: SrvName } = EsModule; // Deconstruct the module and access the exports
338
+ }
333
339
  }
334
340
  ```
335
341
 
@@ -353,4 +359,4 @@ channels:
353
359
 
354
360
  You can also leave suggestions, feedback, and feature requests directly on GitHub by opening an issue in the repository.
355
361
 
356
- Happy coding!
362
+ Happy coding!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teqfw/di",
3
- "version": "1.1.3",
3
+ "version": "1.2.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",
package/types.d.ts CHANGED
@@ -1,23 +1,24 @@
1
+ type TeqFw_Di_Container_A_Composer = InstanceType<typeof import("./src/Container/A/Composer.js").default>;
2
+ type TeqFw_Di_Container_A_Composer_A_SpecParser = import("./src/Container/A/Composer/A/SpecParser.js").default;
3
+ type TeqFw_Di_Container_A_Parser_Chunk_Def = InstanceType<typeof import("./src/Container/A/Parser/Chunk/Def.js").default>;
4
+ type TeqFw_Di_Container_A_Parser_Chunk_V02X = InstanceType<typeof import("./src/Container/A/Parser/Chunk/V02X.js").default>;
5
+ type TeqFw_Di_Container_Parser = InstanceType<typeof import("./src/Container/Parser.js").default>;
6
+ type TeqFw_Di_Container_PostProcessor = InstanceType<typeof import("./src/Container/PostProcessor.js").default>;
7
+ type TeqFw_Di_Container_PreProcessor = InstanceType<typeof import("./src/Container/PreProcessor.js").default>;
8
+ type TeqFw_Di_Container_Resolver = InstanceType<typeof import("./src/Container/Resolver.js").default>;
9
+
1
10
  declare global {
2
- type TeqFw_Di_Api_Container_Parser = import("./src/Api/Container/Parser.js").default;
3
- type TeqFw_Di_Api_Container_Parser_Chunk = import("./src/Api/Container/Parser/Chunk.js").default;
4
- type TeqFw_Di_Api_Container_PostProcessor = import("./src/Api/Container/PostProcessor.js").default;
5
- type TeqFw_Di_Api_Container_PostProcessor_Chunk = import("./src/Api/Container/PostProcessor/Chunk.js").default;
6
- type TeqFw_Di_Api_Container_PreProcessor = import("./src/Api/Container/PreProcessor.js").default;
7
- type TeqFw_Di_Api_Container_PreProcessor_Chunk = import("./src/Api/Container/PreProcessor/Chunk.js").default;
8
- type TeqFw_Di_Api_Container_Resolver = import("./src/Api/Container/Resolver.js").default;
9
- type TeqFw_Di_Container = import("./src/Container.js").default;
10
- type TeqFw_Di_Container_A_Composer = import("./src/Container/A/Composer.js").default;
11
- type TeqFw_Di_Container_A_Composer_A_SpecParser = import("./src/Container/A/Composer/A/SpecParser.js").default;
12
- type TeqFw_Di_Container_A_Parser_Chunk_Def = import("./src/Container/A/Parser/Chunk/Def.js").default;
13
- type TeqFw_Di_Container_A_Parser_Chunk_V02X = import("./src/Container/A/Parser/Chunk/V02X.js").default;
14
- type TeqFw_Di_Container_Parser = import("./src/Container/Parser.js").default;
15
- type TeqFw_Di_Container_PostProcessor = import("./src/Container/PostProcessor.js").default;
16
- type TeqFw_Di_Container_PreProcessor = import("./src/Container/PreProcessor.js").default;
17
- type TeqFw_Di_Container_Resolver = import("./src/Container/Resolver.js").default;
11
+ type TeqFw_Di_Api_Container_Parser = InstanceType<typeof import("./src/Api/Container/Parser.js").default>;
12
+ type TeqFw_Di_Api_Container_Parser_Chunk = InstanceType<typeof import("./src/Api/Container/Parser/Chunk.js").default>;
13
+ type TeqFw_Di_Api_Container_PostProcessor = InstanceType<typeof import("./src/Api/Container/PostProcessor.js").default>;
14
+ type TeqFw_Di_Api_Container_PostProcessor_Chunk = InstanceType<typeof import("./src/Api/Container/PostProcessor/Chunk.js").default>;
15
+ type TeqFw_Di_Api_Container_PreProcessor = InstanceType<typeof import("./src/Api/Container/PreProcessor.js").default>;
16
+ type TeqFw_Di_Api_Container_PreProcessor_Chunk = InstanceType<typeof import("./src/Api/Container/PreProcessor/Chunk.js").default>;
17
+ type TeqFw_Di_Api_Container_Resolver = InstanceType<typeof import("./src/Api/Container/Resolver.js").default>;
18
+ type TeqFw_Di_Container = InstanceType<typeof import("./src/Container.js").default>;
18
19
  type TeqFw_Di_Defs = import("./src/Defs.js").default;
19
- type TeqFw_Di_DepId = import("./src/DepId.js").default;
20
- type TeqFw_Di_Pre_Replace = import("./src/Pre/Replace.js").default;
20
+ type TeqFw_Di_DepId = InstanceType<typeof import("./src/DepId.js").default>;
21
+ type TeqFw_Di_Pre_Replace = InstanceType<typeof import("./src/Pre/Replace.js").default>;
21
22
  }
22
23
 
23
24
  export {};