@teqfw/di 1.2.0 → 2.0.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +5 -42
  2. package/README.md +173 -271
  3. package/dist/esm.js +1 -1
  4. package/dist/umd.js +1 -1
  5. package/package.json +12 -8
  6. package/src/AGENTS.md +177 -0
  7. package/src/Config/NamespaceRegistry.mjs +210 -0
  8. package/src/Container/Instantiate/ExportSelector.mjs +39 -0
  9. package/src/Container/Instantiate/Instantiator.mjs +143 -0
  10. package/src/Container/Lifecycle/Registry.mjs +81 -0
  11. package/src/Container/Resolve/GraphResolver.mjs +119 -0
  12. package/src/Container/Resolver.mjs +175 -0
  13. package/src/Container/Wrapper/Executor.mjs +71 -0
  14. package/src/Container.mjs +380 -0
  15. package/src/Def/Parser.mjs +146 -0
  16. package/src/Dto/DepId.mjs +131 -0
  17. package/src/Dto/Resolver/Config/Namespace.mjs +48 -0
  18. package/src/Dto/Resolver/Config.mjs +58 -0
  19. package/src/Enum/Composition.mjs +11 -0
  20. package/src/Enum/Life.mjs +11 -0
  21. package/src/Enum/Platform.mjs +12 -0
  22. package/src/Internal/Logger.mjs +54 -0
  23. package/types.d.ts +58 -21
  24. package/src/Api/Container/Parser/Chunk.js +0 -23
  25. package/src/Api/Container/Parser.js +0 -28
  26. package/src/Api/Container/PostProcessor/Chunk.js +0 -17
  27. package/src/Api/Container/PostProcessor.js +0 -25
  28. package/src/Api/Container/PreProcessor/Chunk.js +0 -17
  29. package/src/Api/Container/PreProcessor.js +0 -23
  30. package/src/Api/Container/Resolver.js +0 -16
  31. package/src/Container/A/Composer/A/SpecParser.js +0 -86
  32. package/src/Container/A/Composer.js +0 -69
  33. package/src/Container/A/Parser/Chunk/Def.js +0 -69
  34. package/src/Container/A/Parser/Chunk/V02X.js +0 -66
  35. package/src/Container/Parser.js +0 -48
  36. package/src/Container/PostProcessor.js +0 -32
  37. package/src/Container/PreProcessor.js +0 -34
  38. package/src/Container/Resolver.js +0 -80
  39. package/src/Container.js +0 -187
  40. package/src/Defs.js +0 -22
  41. package/src/DepId.js +0 -52
  42. package/src/Pre/Replace.js +0 -80
  43. package/teqfw.json +0 -8
package/CHANGELOG.md CHANGED
@@ -1,45 +1,8 @@
1
1
  # Changelog
2
2
 
3
- ## 1.2.0
3
+ ## 2.0.0 - 2026-02-27
4
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
-
9
- ## 1.1.3
10
-
11
- - Added global type declarations to `types.d.ts` to match the type map architecture rules.
12
-
13
- ## 1.1.2
14
-
15
- - Moved architecture diagrams into `ctx/img/` and updated the context map accordingly.
16
- - Clarified type map rules to require global namespace declarations for IDE type resolution.
17
-
18
- ## 1.1.1
19
-
20
- - Added missing published files (`CHANGELOG.md`, `teqfw.json`, `types.d.ts`) and declared `types.d.ts` in `package.json`.
21
-
22
- ## 1.1.0
23
-
24
- - Added ADSM cognitive context documentation and reporting structure under `ctx/`.
25
- - Added type map documentation and a `types.d.ts` namespace-to-source mapping for IDE support.
26
- - Updated `.npmignore` to ignore `output.md` artifacts.
27
-
28
- ## 1.0.2
29
-
30
- - Added ability to import the Replace preprocessor chunk via package subpath (`./pre/replace`).
31
- - Updated `.npmignore` to exclude development artifacts (`ctx/`, logs, test files) and ensure clean npm package contents.
32
- - Improved ignore patterns to prevent accidental publication of internal files.
33
-
34
- ## 1.0.1
35
-
36
- - Prepare npm package for publication.
37
- - Add distribution build outputs to package files and specify entry points.
38
-
39
- ## 1.0.0
40
-
41
- - Started changelog for version 1.0.0.
42
- - Added AGENTS.md with English-only guidelines and link to PHILOSOPHY.md.
43
- - Switched tests from Mocha to Node's built-in runner.
44
- - Updated package scripts and removed Mocha dependency.
45
- - 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.
5
+ - Started a new changelog lineage for generation 2 of `@teqfw/di`.
6
+ - Replaced legacy v1 implementation with the new architecture.
7
+ - Promoted `src2/` to `src/` and `test2/` to `test/` as the primary code and test layout.
8
+ - Updated project configuration and type paths to the new directory structure.
package/README.md CHANGED
@@ -3,360 +3,262 @@
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] > **Breaking Changes in v1.0.0**
7
- >
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`.
6
+ Deterministic runtime DI container for native ES modules.
9
7
 
10
- `@teqfw/di` is a lightweight dependency injection container for standard JavaScript, enabling late binding of code
11
- objects with minimal manual configuration. It integrates smoothly in both browser and Node.js environments, supporting
12
- flexibility, modularity, and easier testing for your applications.
8
+ `@teqfw/di` uses explicit dependency contracts (CDC strings) and module-level dependency descriptors (`__deps__`).
9
+ It does not infer dependencies from constructor signatures.
13
10
 
14
- Unlike typical object containers, `@teqfw/di` requires no manual registration of objects, instead mapping dependency IDs
15
- directly to their source paths for greater simplicity. However, for advanced use cases—such as unit testing—it is
16
- possible to explicitly register singleton objects using the `register(depId, obj)` method (available only in test mode).
17
- This allows controlled substitution of dependencies without altering the main codebase.
11
+ ## Version Line
18
12
 
19
- **This library is specifically optimized for ES6 modules, ensuring top performance and compatibility. It does not
20
- support CommonJS, AMD, UMD, or other module formats.**
13
+ This branch is the v2 line.
21
14
 
22
- To increase robustness, all instances created by the container are automatically **frozen** using `Object.freeze()`.
23
- This guarantees immutability of the returned objects, helping prevent accidental modifications and ensuring predictable
24
- behavior at runtime.
15
+ - package version: `2.0.0`
16
+ - changelog starts from `2.0.0`
25
17
 
26
- While this library is primarily designed for JavaScript, it is also fully compatible with TypeScript. Developers can use
27
- TypeScript to compose dependency identifiers in the same way as in JavaScript. It is important to ensure that TypeScript
28
- transpiles the source code to ES6 modules for proper functionality. With this setup, TypeScript users can effectively
29
- leverage the benefits of this library without any additional configuration.
30
-
31
- ---
32
-
33
- ## Design Philosophy
34
-
35
- This library is a component of the **TeqFW platform**, an experimental framework grounded in the principles of modular
36
- monolith design, long-term maintainability, late binding, and immutability-first logic composition.
37
-
38
- To explore the conceptual background, see: **[TeqFW Philosophy](./PHILOSOPHY.md)**.
39
-
40
- ---
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
-
53
- ## Samples
54
-
55
- Explore `@teqfw/di` in action through the following demo applications:
56
-
57
- - [demo-di-app](https://flancer64.github.io/demo-di-app/): A simple demonstration of dependency injection with
58
- `@teqfw/di`.
59
- - [demo-wa-esm-openai](https://github.com/flancer64/demo-wa-esm-openai): Integrates OpenAI with ES6 modules.
60
- - [pwa-wallet](https://github.com/flancer64/pwa-wallet): A progressive web application wallet showcasing the library's
61
- modularity.
62
- - [spa-remote-console](https://github.com/flancer64/spa-remote-console): Demonstrates remote console functionality in a
63
- single-page application.
64
- - [demo-webauthn-pubkey](https://github.com/flancer64/demo-webauthn-pubkey): Uses Web Authentication (WebAuthn) with
65
- public key credentials.
66
- - [tg-bot-habr-demo-grammy](https://github.com/flancer64/tg-bot-habr-demo-grammy): A Telegram bot demo built with the
67
- grammY library.
68
-
69
- These projects offer practical examples and insights into using `@teqfw/di` effectively!
70
-
71
- ---
18
+ ## Installation
72
19
 
73
- ## Example of Typical Usage
20
+ ```bash
21
+ npm install @teqfw/di
22
+ ```
74
23
 
75
- Using `@teqfw/di` typically involves a few simple steps: organizing the file structure, declaring dependencies,
76
- configuring the container, and finally retrieving the main object with injected dependencies.
24
+ ## Quick Start
77
25
 
78
- ### Step 1: Organize File Structure
26
+ ### 1. Define modules with `__deps__`
79
27
 
80
- Here’s an example of how files might be organized in a project. This structure can vary depending on your project needs,
81
- as the container can be configured to work with any layout (e.g., within `/home/user/project/`):
28
+ `src/App/Child.mjs`
82
29
 
83
- ```text
84
- ./src/
85
- ./Service/
86
- ./Customer.js
87
- ./Sale.js
88
- ./Config.js
89
- ./Logger.js
90
- ./Main.js
30
+ ```js
31
+ export default function App_Child() {
32
+ return { name: "child" };
33
+ }
91
34
  ```
92
35
 
93
- ### Step 2: Declare Dependencies
94
-
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.
36
+ `src/App/Root.mjs`
99
37
 
100
38
  ```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
- }
39
+ export const __deps__ = {
40
+ child: "App_Child$",
41
+ };
42
+
43
+ export default function App_Root({ child }) {
44
+ return {
45
+ name: "root",
46
+ child,
47
+ };
110
48
  }
111
49
  ```
112
50
 
113
- ### Step 3: Configure the Container
114
-
115
- Next, set up the container and configure it to use the correct namespace and path for your dependencies:
51
+ ### 2. Configure container in composition root
116
52
 
117
53
  ```js
54
+ import path from "node:path";
55
+ import { fileURLToPath } from "node:url";
118
56
  import Container from "@teqfw/di";
119
57
 
120
- // Create a new instance of the container
121
- const container = new Container();
58
+ const __filename = fileURLToPath(import.meta.url);
59
+ const __dirname = path.dirname(__filename);
122
60
 
123
- // Get the resolver from the container
124
- const resolver = container.getResolver();
61
+ const container = new Container();
62
+ container.addNamespaceRoot("App_", path.resolve(__dirname, "./src/App"), ".mjs");
125
63
 
126
- // Define the namespace root for dependencies, allowing the container to resolve identifiers like 'App_*'
127
- resolver.addNamespaceRoot("App_", "/home/user/project/src");
64
+ const root = await container.get("App_Root$");
65
+ console.log(root.name); // root
66
+ console.log(root.child.name); // child
67
+ console.log(Object.isFrozen(root)); // true
128
68
  ```
129
69
 
130
- ### Step 4: Retrieve the Main Object with Dependencies
70
+ ## Dependency Descriptor (`__deps__`)
131
71
 
132
- Finally, retrieve your main application instance. The container automatically injects all declared dependencies:
72
+ `__deps__` is a static module export:
133
73
 
134
74
  ```js
135
- // Retrieve the main application instance as a singleton asynchronously
136
- const app = await container.get("App_Main$");
75
+ export const __deps__ = {
76
+ localName: "Some_CDC",
77
+ };
137
78
  ```
138
79
 
139
- ---
80
+ Rules used by container runtime:
140
81
 
141
- ## Test Mode Support
82
+ - if `__deps__` is missing: module has zero dependencies
83
+ - keys are local argument names passed into factory/class constructor
84
+ - values are CDC strings
85
+ - dependencies are resolved recursively before instantiation
142
86
 
143
- `@teqfw/di` supports a dedicated **test mode** to facilitate unit testing and dependency mocking.
87
+ ## CDC Grammar (Default Profile)
144
88
 
145
- When test mode is enabled via `container.enableTestMode()`, you can manually register singleton dependencies using the
146
- `register(depId, obj)` method:
89
+ Surface form:
147
90
 
148
- ```js
149
- container.enableTestMode();
150
- container.register("App_Service_Customer$", mockCustomerService);
91
+ ```text
92
+ [PlatformPrefix]ModuleName[__ExportName][LifecycleAndWrappers]
151
93
  ```
152
94
 
153
- This makes it easy to substitute real implementations with mocks or stubs during tests, without altering production
154
- logic. Overrides are allowed only in test mode, ensuring clean separation of concerns.
95
+ Where:
155
96
 
156
- ### Mocking Node.js Built-in Modules
97
+ - `PlatformPrefix`: `node_` | `npm_` | omitted (`teq` by default)
98
+ - `Export segment`: `__ExportName`
99
+ - `Lifecycle marker`: `$` | `$$` | `$$$`
100
+ - `Wrappers`: `_<wrapperId>` suffixes after lifecycle marker
157
101
 
158
- A powerful feature of `@teqfw/di` is the ability to mock **Node.js built-in libraries** such as `fs`, `path`, or
159
- `process`. This is useful for isolating side effects and simulating system behavior:
102
+ Examples:
160
103
 
161
- ```js
162
- container.register("node:fs", {
163
- existsSync: (path) => path.endsWith(".html"),
164
- });
165
- ```
104
+ - `App_Service` - whole module (`as-is`)
105
+ - `App_Service$` - default export as factory with lifecycle marker
106
+ - `App_Service__build$$` - named export `build` with lifecycle marker
107
+ - `App_Service$$_wrapLog_wrapTrace` - wrapper chain in declared order
108
+ - `node_fs` - Node builtin
109
+ - `npm_lodash` - npm package
110
+
111
+ Notes:
166
112
 
167
- You can also register mocks for custom logic or environment-specific behavior:
113
+ - explicit `teq_` prefix is forbidden
114
+ - wrappers without lifecycle marker are invalid
115
+ - parser is deterministic and fail-fast
116
+
117
+ ## Public API
168
118
 
169
119
  ```js
170
- container.register("node:path", {
171
- join: (...args) => args.join("/"),
172
- resolve: (p) => `/abs/${p}`,
173
- });
120
+ const container = new Container();
174
121
  ```
175
122
 
176
- These mocks are injected transparently wherever such modules are used as dependencies, making it possible to write pure,
177
- isolated, and deterministic unit tests — even for logic that relies on the filesystem or path resolution.
123
+ Builder stage methods (only before first `get`):
178
124
 
179
- ---
180
-
181
- ## Key Benefits
125
+ - `setParser(parser)`
126
+ - `addNamespaceRoot(prefix, target, defaultExt)`
127
+ - `addPreprocess(fn)`
128
+ - `addPostprocess(fn)`
129
+ - `enableLogging()`
130
+ - `enableTestMode()`
131
+ - `register(cdc, mock)` (only in test mode)
182
132
 
183
- `@teqfw/di` offers the core functionality of any object container — creating objects and injecting dependencies — with
184
- extensive flexibility and configurability. This allows the library to adapt seamlessly to a wide range of project needs.
185
- Here’s what makes it stand out:
133
+ Resolution:
186
134
 
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.
135
+ - `await container.get(cdc)`
189
136
 
190
- - **Flexible Dependency ID Configuration**: With customizable parsers and chunks, you can define unique ID schemes for
191
- dependencies, making it easy to adapt the library to specific naming conventions or custom mapping rules.
137
+ Behavioral guarantees:
192
138
 
193
- - **Mapping IDs to Source Modules via Resolvers**: Thanks to resolvers, `@teqfw/di` lets you map dependency IDs to their
194
- source locations effortlessly. This makes the library adaptable to any project structure or file layout.
139
+ - configuration is locked after first `get`
140
+ - fail-fast pipeline
141
+ - deterministic linking under identical contracts and config
142
+ - produced values are frozen
143
+ - container enters failed state after fatal linking error
195
144
 
196
- - **Immutable Objects for Safer Runtime**: All objects created by the container are frozen by default. This ensures that
197
- dependencies cannot be modified once instantiated, eliminating unintended mutations and reinforcing modular,
198
- predictable application behavior.
145
+ ## Wrappers
199
146
 
200
- - **Preprocessing for Enhanced Control**: Built-in preprocessing allows modifying dependencies at the time of creation,
201
- enabling local overrides or adjustments in functionality. This is especially useful for larger projects, where
202
- different teams may tailor dependencies to their specific requirements. The default preprocessing can also be replaced
203
- to suit more precise needs.
147
+ Wrappers are postprocess plugins registered during container configuration.
148
+ They are activated by wrapper markers in the CDC string and applied to the produced value after instantiation.
204
149
 
205
- - **Interfaces and Dependencies Without TypeScript**: `@teqfw/di` allows you to define interfaces using standard
206
- JavaScript files with JSDoc annotations. The container supports configuring dependencies to replace interfaces with
207
- project-specific implementations, offering flexibility without requiring TypeScript.
150
+ Wrappers:
208
151
 
209
- - **Postprocessing for Object Customization**: Use postprocessing to add wrappers or extend created objects. This can be
210
- valuable for adding factories, logging, or other behavior, tailored to each project’s requirements.
152
+ - are **container-level plugins**
153
+ - are **not module exports**
154
+ - are applied in declared order
155
+ - must return synchronously
156
+ - run before lifecycle enforcement and freeze
211
157
 
212
- These features make `@teqfw/di` a powerful, adaptable DI container that not only provides ready-to-use solutions but can
213
- be easily customized to meet unique project demands.
158
+ Surface form:
214
159
 
215
- ---
160
+ ```text
161
+ ModuleName$$_wrapperA_wrapperB
162
+ ```
216
163
 
217
- ## Installation
164
+ Wrappers are part of the dependency contract (CDC).
165
+ They declaratively modify how a resolved value behaves.
218
166
 
219
- ### For Node.js
167
+ ---
220
168
 
221
- To install `@teqfw/di` in a Node.js environment, use the following command:
169
+ ### Example: Logging Wrapper
222
170
 
223
- ```shell
224
- npm install @teqfw/di
225
- ```
171
+ Suppose we want to log all method calls of a service without modifying the service itself.
226
172
 
227
- Then, import and initialize the container:
173
+ #### Service module
228
174
 
229
175
  ```js
230
- import Container from "@teqfw/di";
231
-
232
- /** @type {TeqFw_Di_Container} */
233
- const container = new Container();
176
+ export default function App_Service() {
177
+ return {
178
+ sum(a, b) {
179
+ return a + b;
180
+ },
181
+ multiply(a, b) {
182
+ return a * b;
183
+ },
184
+ };
185
+ }
234
186
  ```
235
187
 
236
- ### For the Browser (ESM Module)
237
-
238
- To use `@teqfw/di` in a browser environment with ES modules, include it as follows (~5KB):
239
-
240
- ```html
241
- <script type="module">
242
- import Container from "https://cdn.jsdelivr.net/npm/@teqfw/di@latest/+esm";
188
+ #### Container configuration
243
189
 
244
- /** @type {TeqFw_Di_Container} */
245
- const container = new Container();
246
- </script>
190
+ ```js
191
+ container.addPostprocessWrapper("logIO", (value) => {
192
+ return new Proxy(value, {
193
+ get(target, prop, receiver) {
194
+ const original = Reflect.get(target, prop, receiver);
195
+
196
+ if (typeof original !== "function") {
197
+ return original;
198
+ }
199
+
200
+ return function (...args) {
201
+ console.log(`[CALL] ${String(prop)} ->`, args);
202
+ const result = original.apply(this, args);
203
+ console.log(`[RETURN] ${String(prop)} ->`, result);
204
+ return result;
205
+ };
206
+ },
207
+ });
208
+ });
247
209
  ```
248
210
 
249
- ### For the Browser (UMD Module)
211
+ #### Request
250
212
 
251
- Alternatively, you can use the UMD version in the browser (~5KB):
213
+ ```js
214
+ const service = await container.get("App_Service$$_logIO");
252
215
 
253
- ```html
254
- <script src="https://cdn.jsdelivr.net/npm/@teqfw/di@latest/dist/umd.js"></script>
255
- <script>
256
- /** @type {TeqFw_Di_Container} */
257
- const container = new window.TeqFw_Di_Container();
258
- </script>
216
+ service.sum(2, 3);
217
+ // [CALL] sum -> [2, 3]
218
+ // [RETURN] sum -> 5
259
219
  ```
260
220
 
261
- ---
262
-
263
- ## Using the Container
264
-
265
- ### In Node.js
221
+ The module remains unaware of logging.
222
+ The wrapper applies cross-cutting behavior declaratively through CDC.
266
223
 
267
- 1. **Configure Dependency Mapping**: Configure the resolver to detect the platform environment. Then, set up namespace
268
- roots to map dependency IDs to their source paths.
224
+ This allows:
269
225
 
270
- ```js
271
- import { platform } from "node:process";
226
+ - tracing
227
+ - metrics collection
228
+ - access control
229
+ - behavioral instrumentation
272
230
 
273
- const resolver = container.getResolver();
274
- resolver.setWindowsEnv(platform === "win32"); // Adjusts for Windows environment if needed
275
- resolver.addNamespaceRoot("App_", "/path/to/src");
276
- ```
231
+ without modifying business logic or module structure.
277
232
 
278
- 2. **Retrieve Singleton Instances**: Retrieve the main application instance as a singleton asynchronously:
233
+ Wrappers therefore act as a declarative DI-level AOP mechanism.
279
234
 
280
- ```js
281
- const app = await container.get("App_Main$");
282
- ```
283
-
284
- ### In the Browser
285
-
286
- 1. **Configure Dependency Mapping**: Set up namespace roots to map dependency IDs to their source paths, using URLs as
287
- needed.
288
-
289
- ```js
290
- const resolver = container.getResolver();
291
- resolver.addNamespaceRoot("App_", "https://cdn.jsdelivr.net/npm/@flancer64/demo-di-app@0.2/src");
292
- ```
293
-
294
- 2. **Retrieve Singleton Instances**: Retrieve the main application instance as a singleton asynchronously:
295
-
296
- ```js
297
- const app = await container.get("App_Main$");
298
- ```
299
-
300
- With these steps, the container is configured to automatically resolve and inject dependencies based on your setup,
301
- whether in Node.js or in a browser environment.
302
-
303
- ---
304
-
305
- ## Dependency ID Types
306
-
307
- `@teqfw/di` supports various dependency ID formats to match different import styles and object requirements. Here’s a
308
- quick reference:
309
-
310
- | Dependency ID | Import Style | Description |
311
- | --------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
312
- | `App_Service` | `import * as Service from './App/Service.js';` | Imports the entire module as an ES module. |
313
- | `App_Service.default` | `import {default} from './App/Service.js';` | Imports the default export as-is. |
314
- | `App_Service.name` | `import {name} from './App/Service.js';` | Imports a named export as-is. |
315
- | `App_Service$` | `import {default as Factory} from './App/Service.js';` | Uses default export as a singleton for the container. |
316
- | `App_Service$$` | `import {default as Factory} from './App/Service.js';` | Creates a new instance from the default export for each dependency. |
317
- | `App_Service.name$` | `import {name} from './App/Service.js';` | Uses a named export as a singleton. |
318
- | `App_Service.name$$` | `import {name} from './App/Service.js';` | Creates a new instance from a named export for each dependency. |
319
- | `App_Service.name$$(proxy)` | `import {name} from './App/Service.js';` | Applies a custom wrapper to the created object in postprocessing, using a handler function `proxy()`. |
320
-
321
- ### Example Usage
322
-
323
- Here’s an example showing a class with multiple dependencies, each using different dependency IDs:
235
+ ## Test Mode and Mocks
324
236
 
325
237
  ```js
326
- export default class App_Main {
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
- }
339
- }
238
+ container.enableTestMode();
239
+ container.register("App_Service$", { name: "mock-service" });
340
240
  ```
341
241
 
342
- ---
343
-
344
- ## Summary
242
+ Mock lookup uses canonical parsed dependency identity and is applied before resolver/instantiation.
345
243
 
346
- `@teqfw/di` is a versatile and lightweight dependency injection container tailored for modern JavaScript applications.
347
- With its flexible dependency mapping, customizable ID configurations, and support for dynamic object creation,
348
- `@teqfw/di` empowers developers to build modular, testable, and scalable codebases.
244
+ ## Browser Usage
349
245
 
350
- Whether you’re working in Node.js or a browser environment, `@teqfw/di` provides a solid foundation with built-in
351
- functionality that you can further adapt to fit your project’s unique requirements. Feel free to explore and extend the
352
- library as needed to create your ideal development environment.
246
+ ESM via jsDelivr:
353
247
 
354
- For any questions, feedback, or collaboration opportunities, please feel free to reach out through the following
355
- channels:
248
+ ```html
249
+ <script type="module">
250
+ import Container from "https://cdn.jsdelivr.net/npm/@teqfw/di@2/+esm";
251
+ const container = new Container();
252
+ </script>
253
+ ```
356
254
 
357
- - **Website**: [wiredgeese.com](https://wiredgeese.com)
358
- - **LinkedIn**: [LinkedIn Profile](https://www.linkedin.com/in/aleksandrs-gusevs-011ba928/)
255
+ ## Documentation Source
359
256
 
360
- You can also leave suggestions, feedback, and feature requests directly on GitHub by opening an issue in the repository.
257
+ Normative docs live in `ctx/`:
361
258
 
362
- Happy coding!
259
+ - product overview: `ctx/docs/product/overview.md`
260
+ - default CDC profile: `ctx/docs/product/default-cdc-profile.md`
261
+ - grammar: `ctx/docs/architecture/cdc-profile/default/grammar.md`
262
+ - transformation: `ctx/docs/architecture/cdc-profile/default/transformation.md`
263
+ - validation: `ctx/docs/architecture/cdc-profile/default/validation.md`
264
+ - container contract: `ctx/docs/code/components/container.md`
package/dist/esm.js CHANGED
@@ -1 +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};
1
+ const e={AS_IS:"A",FACTORY:"F"},t={SINGLETON:"S",TRANSIENT:"T"},o={TEQ:"teq",NODE:"node",NPM:"npm"},r=o.TEQ,n=e.AS_IS,i=new Set(Object.values(o)),s=new Set(Object.values(e)),a=new Set(Object.values(t));let l=class{moduleName;platform;exportName;composition;life;wrappers;origin},c=class{create(e,t){const o=e&&"object"==typeof e?e:{},c=new l;c.moduleName="string"==typeof o.moduleName?o.moduleName:"";const p="string"==typeof o.platform?o.platform:void 0;c.platform=p&&i.has(p)?p:r;let f=null;null===o.exportName?f=null:"string"==typeof o.exportName&&(f=o.exportName),c.exportName=f;const u="string"==typeof o.composition?o.composition:void 0;c.composition=u&&s.has(u)?u:n;const m="string"==typeof o.life?o.life:void 0;return c.life=m&&a.has(m)?m:null,c.wrappers=Array.isArray(o.wrappers)?o.wrappers.filter(e=>"string"==typeof e):[],c.origin="string"==typeof o.origin?o.origin:"",!0===t?.immutable&&(Object.freeze(c.wrappers),Object.freeze(c)),c}};class p{constructor(){const r=new c;let n=null;this.parse=function(i){if(n&&n.log(`Parser.parse: input='${i}'.`),"string"!=typeof i)throw new Error("CDC must be a string.");if(0===i.length)throw new Error("CDC must be non-empty.");if(!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(i))throw new Error("CDC must satisfy AsciiCdcIdentifier.");const s=i;let a=i,l=o.TEQ;if(a.startsWith("node_"))l=o.NODE,a=a.slice(5);else if(a.startsWith("npm_"))l=o.NPM,a=a.slice(4);else if(a.startsWith("teq_"))throw new Error("Explicit teq_ prefix is forbidden.");if(0===a.length)throw new Error("moduleName must be non-empty.");const c=a.match(/(\${1,3})(?:_([A-Za-z0-9]+(?:_[A-Za-z0-9]+)*))?$/);let p=null,f=[],u=a;if(c){const e=c[1],o=c[2];if("$"===e)p=t.SINGLETON;else{if("$$"!==e&&"$$$"!==e)throw new Error("Lifecycle marker overflow.");p=t.TRANSIENT}if(u=a.slice(0,c.index),o){f=o.split("_");for(const e of f){if(!e)throw new Error("Wrapper must be non-empty.");if(e.includes("$"))throw new Error("Wrapper must not contain $.");if(e.includes("_"))throw new Error("Wrapper must not contain _.")}}}else{if(a.includes("$"))throw new Error("Invalid lifecycle marker.");if(a.match(/(?:^|[^_])_([a-z][A-Za-z0-9]*)$/))throw new Error("Wrapper without lifecycle is forbidden.")}if(u.includes("$$$$"))throw new Error("Lifecycle marker overflow.");const m=u.indexOf("__"),d=u.lastIndexOf("__");if(-1!==m&&m!==d)throw new Error("Export delimiter must appear at most once.");if(u.startsWith("__")||u.endsWith("__"))throw new Error("Malformed export segment.");let g=u,w=null;if(-1!==m){if(g=u.slice(0,m),w=u.slice(m+2),!w)throw new Error("Export must be non-empty.");if(w.includes("_"))throw new Error("Export must not contain _.");if(w.includes("$"))throw new Error("Export must not contain $.")}if(!g)throw new Error("moduleName must be non-empty.");if(g.startsWith("_")||g.startsWith("$"))throw new Error("moduleName must not start with _ or $.");if(g.includes("__"))throw new Error("moduleName must not contain __.");if(g.includes("$"))throw new Error("moduleName must not contain $.");let h=e.AS_IS;null!==w?h=e.FACTORY:p===t.SINGLETON?(w="default",h=e.FACTORY):p===t.TRANSIENT&&(h=e.FACTORY,null===w&&(w="default"));const $=r.create({moduleName:g,platform:l,exportName:w,composition:h,life:p,wrappers:f,origin:s},{immutable:!0});return n&&n.log(`Parser.parse: produced='${$.platform}::${$.moduleName}'.`),$},this.setLogger=function(e){n=e}}}let f=class{prefix;target;defaultExt},u=class{create(e,t){const o=e&&"object"==typeof e?e:{},r=t&&"object"==typeof t?t:{},n=new f;return n.prefix="string"==typeof o.prefix?o.prefix:void 0,n.target="string"==typeof o.target?o.target:void 0,n.defaultExt="string"==typeof o.defaultExt?o.defaultExt:void 0,!0===r.immutable&&Object.freeze(n),n}};class m{namespaces;nodeModulesRoot}class d{constructor(){const e=new u;this.create=function(t,o){const r=t&&"object"==typeof t?t:{},n=o&&"object"==typeof o?o:{},i=new m,s=Array.isArray(r.namespaces)?r.namespaces:[];return i.namespaces=s.map(t=>e.create(t,n)),i.nodeModulesRoot="string"==typeof r.nodeModulesRoot?r.nodeModulesRoot:void 0,!0===n.immutable&&(Object.freeze(i.namespaces),Object.freeze(i)),i}}}class g{constructor({config:e,importFn:t=e=>import(e),logger:o=null}){const r=new Map,n=e;let i;const s=t,a=o,l=function(e,t){if("node"===e){const e=`node:${t}`;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("npm"===e){const e=t;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("teq"!==e)throw new Error(`Unsupported platform: ${e}`);const o=function(e){let t=null,o=-1;const r=i.namespaces;for(const n of r){const r=e.startsWith(n.prefix);a&&a.log(`Resolver.namespace: prefix='${n.prefix}' match=${String(r)} module='${e}'.`),r&&n.prefix.length>o&&(t=n,o=n.prefix.length)}if(!t)throw new Error(`Namespace rule is not found for '${e}'.`);return t}(t),r=t.slice(o.prefix.length).split("_").join("/"),n=(s=r,(l=o.defaultExt)?s.endsWith(l)?s:`${s}${l}`:s);var s,l;const c=function(e,t){return e?e.endsWith("/")?`${e}${t}`:`${e}/${t}`:t}(o.target,n);return a&&a.log(`Resolver.specifier: module='${t}' -> '${c}'.`),c};this.resolve=async function(e){var t;await Promise.resolve(),i||(i={nodeModulesRoot:(t=n).nodeModulesRoot,namespaces:t.namespaces.map(e=>({prefix:e.prefix,target:e.target,defaultExt:e.defaultExt}))});const o=e.platform,c=e.moduleName,p=`${o}::${c}`;if(r.has(p))return a&&a.log(`Resolver.cache: hit key='${p}'.`),r.get(p);a&&a.log(`Resolver.cache: miss key='${p}'.`);const f=(async()=>{const e=l(o,c);return a&&a.log(`Resolver.import: '${e}'.`),s(e)})();r.set(p,f);try{return await f}catch(e){throw r.delete(p),a&&a.error(`Resolver.cache: evict key='${p}' after failure.`,e),e}}}}class w{constructor({parser:e,resolver:t,logger:o=null}){const r=o,n=async function(o,i,s,a){const l=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")}(o);if(s.has(l)){const e=[...a,l].join(" -> ");throw new Error(`Cyclic dependency detected: ${e}`)}const c=function(e){return`${e.platform}::${e.moduleName}`}(o);if(!i.has(c)){s.add(l),a.push(l);try{const l=await t.resolve(o);r&&r.log(`GraphResolver.walk: resolved '${c}'.`),i.set(c,{depId:o,namespace:l});const p=Reflect.get(l,"__deps__");if(void 0===p)return;const f=p;for(const[,t]of Object.entries(f)){const o=t,l=e.parse(o);r&&r.log(`GraphResolver.walk: edge '${c}' -> '${l.platform}::${l.moduleName}'.`),await n(l,i,s,a)}}finally{a.pop(),s.delete(l)}}};this.resolve=async function(e){const t=new Map,o=new Set;return await n(e,t,o,[]),t}}}class h{constructor(){this.instantiate=function(t,o,r){const n=function(e,t){if(null===e.exportName)return t;if(!(e.exportName in t))throw new Error(`Export '${e.exportName}' is not found in module namespace.`);return t[e.exportName]}(t,o);if(t.composition===e.AS_IS)return n;if(t.composition===e.FACTORY){if("function"!=typeof n)throw new Error("Factory composition requires a callable export.");const e=n;let t;if(function(e){try{return Reflect.construct(String,[],e),!0}catch{return!1}}(e)){t=new e(r)}else{t=e(r)}if(function(e){if(null==e)return!1;const t=typeof e;return("object"===t||"function"===t)&&"function"==typeof e.then}(t))throw new Error("Factory composition must return synchronously (non-thenable).");return t}throw new Error(`Unsupported composition mode: ${String(t.composition)}.`)}}}class ${constructor(o=null){const r=new Map,n=o;this.apply=function(o,i){if(o.composition!==e.FACTORY)return n&&n.log(`Lifecycle.apply: composition='${o.composition}' cache=skip.`),i();if(o.life===t.TRANSIENT)return n&&n.log("Lifecycle.apply: transient cache=skip."),i();if(o.life===t.SINGLETON){const e=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")}(o);if(r.has(e))return n&&n.log(`Lifecycle.cache: hit key='${e}'.`),r.get(e);n&&n.log(`Lifecycle.cache: miss key='${e}', create.`);const t=i();return r.set(e,t),n&&n.log(`Lifecycle.cache: stored key='${e}'.`),t}return n&&n.log("Lifecycle.apply: no lifecycle marker cache=skip."),i()}}}class y{constructor(){const e=function(e){if(null==e)return!1;const t=typeof e;if("object"!==t&&"function"!==t)return!1;return"function"==typeof e.then},t=function(e){return"function"==typeof e};this.execute=function(o,r,n){let i=r;const s=o.wrappers;for(const o of s){if(!(o in n))throw new Error(`Wrapper '${o}' is not found in module namespace.`);const r=n[o];if(!t(r))throw new Error(`Wrapper '${o}' must be callable.`);if(i=r(i),e(i))throw new Error(`Wrapper '${o}' must return synchronously (non-thenable).`)}return i}}}class N{constructor(e="teqfw/di"){const t=`[${e}]`;this.log=function(e){console.debug(`${t} ${e}`)},this.error=function(e,o){console.error(`${t} ${e}`),o instanceof Error?console.error(o.stack??o.message):void 0!==o&&console.error(o)}}}const E=Object.freeze({log(){},error(){}});class x{constructor(){let e="notConfigured";const t=[],o=[],r=[],n=new Map;let i=!1,s=!1,a=new p;const l=new d;let c,f,u,m=E;const x=new h,C=new y,b=function(e){return`${e.platform}::${e.moduleName}`},_=function(e){const t=null===e.exportName?"":e.exportName,o=null===e.life?"":e.life,r=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,t,e.composition,o,r].join("::")},v=function(e){if(null==e)return e;const t=typeof e;return"object"!==t&&"function"!==t||"[object Module]"===Object.prototype.toString.call(e)||Object.isFrozen(e)||Object.freeze(e),e},I=function(){if("notConfigured"!==e)throw new Error("Container configuration is locked.")},j=function(e){s&&m.log(`Container.builder: ${e}`)};this.addPreprocess=function(e){I(),j("addPreprocess()."),t.push(e)},this.addPostprocess=function(e){I(),j("addPostprocess()."),o.push(e)},this.setParser=function(e){I(),a=e,"function"==typeof a.setLogger&&a.setLogger(s?m:null),j("setParser().")},this.addNamespaceRoot=function(e,t,o){I(),j(`addNamespaceRoot('${e}').`),r.push({prefix:e,target:t,defaultExt:o})},this.enableTestMode=function(){I(),j("enableTestMode()."),i=!0},this.enableLogging=function(){I(),s||(s=!0,m=new N,"function"==typeof a.setLogger&&a.setLogger(m),m.log("Container.builder: enableLogging()."))},this.register=function(e,t){if(I(),j(`register('${e}').`),!0!==i)throw new Error("Container test mode is disabled.");const o=a.parse(e);n.set(_(o),t)},this.get=async function(s){if("failed"===e)throw m.error(`Container.get: rejected in failed state cdc='${s}'.`),new Error("Container is in failed state.");let p="start";try{m.log(`Container.get: cdc='${s}'.`),function(){if("notConfigured"!==e)return;m.log("Container.transition: notConfigured -> operational."),e="operational";const t=l.create({namespaces:r},{immutable:!0});"function"==typeof a.setLogger&&a.setLogger(m),c=new g({config:t,logger:m}),f=new w({parser:a,resolver:c,logger:m}),u=new $(m)}(),m.log(`Container.state: '${e}'.`),p="parse",m.log("Container.pipeline: parse:entry.");const d=a.parse(s);m.log(`Container.pipeline: parse:exit '${d.platform}::${d.moduleName}'.`),p="preprocess",m.log("Container.pipeline: preprocess:entry.");const h=function(e){let o=e;for(const e of t)o=e(o);return o}(d);if(m.log(`Container.pipeline: preprocess:exit '${h.platform}::${h.moduleName}'.`),!0===i){p="mock",m.log("Container.pipeline: mock-lookup:entry.");const e=_(h);if(n.has(e)){m.log(`Container.pipeline: mock-lookup:hit '${e}'.`),p="freeze",m.log("Container.pipeline: freeze:entry.");const t=v(n.get(e));return m.log("Container.pipeline: freeze:exit."),m.log("Container.pipeline: return:success."),t}m.log(`Container.pipeline: mock-lookup:miss '${e}'.`)}else m.log("Container.pipeline: mock-lookup:disabled.");p="resolve",m.log("Container.pipeline: resolve:entry.");const y=await f.resolve(h);m.log(`Container.pipeline: resolve:exit nodes=${y.size}.`);const N=new Map,E=function(e){if(N.has(e))return N.get(e);if(!y.has(e))throw new Error(`Resolved graph node is missing for '${e}'.`);const t=y.get(e);p="lifecycle",m.log(`Container.pipeline: lifecycle:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const r=u.apply(t.depId,function(){p="instantiate",m.log(`Container.pipeline: instantiate:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const e={},r=function(e){const t=Reflect.get(e,"__deps__");return void 0===t?{}:t}(t.namespace);for(const[t,o]of Object.entries(r)){const r=o,n=a.parse(r);e[t]=E(b(n))}const n=x.instantiate(t.depId,t.namespace,e);m.log(`Container.pipeline: instantiate:exit '${t.depId.platform}::${t.depId.moduleName}'.`),p="postprocess",m.log(`Container.pipeline: postprocess:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const i=function(e){let t=e;for(const e of o)t=e(t);return t}(n);m.log(`Container.pipeline: postprocess:exit '${t.depId.platform}::${t.depId.moduleName}'.`);const s=C.execute(t.depId,i,t.namespace);p="freeze",m.log(`Container.pipeline: freeze:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const l=v(s);return m.log(`Container.pipeline: freeze:exit '${t.depId.platform}::${t.depId.moduleName}'.`),l});return m.log(`Container.pipeline: lifecycle:exit '${t.depId.platform}::${t.depId.moduleName}'.`),N.set(e,r),r},I=E(b(h));return m.log("Container.pipeline: return:success."),I}catch(t){throw m.error(`Container.pipeline: failed at stage='${p}'.`,t),m.log("Container.transition: operational -> failed."),e="failed",t}}}}export{x as default};