@teqfw/di 1.3.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +173 -259
  3. package/dist/esm.js +1 -1
  4. package/dist/umd.js +1 -1
  5. package/package.json +19 -13
  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 +24 -32
  24. package/src/Api/Container/Config.js +0 -73
  25. package/src/Api/Container/Parser/Chunk.js +0 -27
  26. package/src/Api/Container/Parser.js +0 -34
  27. package/src/Api/Container/PostProcessor/Chunk.js +0 -17
  28. package/src/Api/Container/PostProcessor.js +0 -29
  29. package/src/Api/Container/PreProcessor/Chunk.js +0 -19
  30. package/src/Api/Container/PreProcessor.js +0 -27
  31. package/src/Api/Container/Resolver.js +0 -18
  32. package/src/Api/Container.js +0 -19
  33. package/src/Container/A/Composer/A/SpecParser.js +0 -86
  34. package/src/Container/A/Composer.js +0 -69
  35. package/src/Container/A/Parser/Chunk/Def.js +0 -69
  36. package/src/Container/A/Parser/Chunk/V02X.js +0 -66
  37. package/src/Container/Config.js +0 -93
  38. package/src/Container/Parser.js +0 -48
  39. package/src/Container/PostProcessor.js +0 -32
  40. package/src/Container/PreProcessor.js +0 -34
  41. package/src/Container/Resolver.js +0 -80
  42. package/src/Container.js +0 -187
  43. package/src/Defs.js +0 -22
  44. package/src/DepId.js +0 -52
  45. package/src/Pre/Replace.js +0 -80
  46. package/teqfw.json +0 -8
package/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## 2.0.1 - 2026-03-04
4
+
5
+ - Regenerated `types.d.ts` according to updated type-map conventions.
6
+ - Unified package type aliases under a deterministic global declaration registry.
7
+ - Updated package version metadata to `2.0.1`.
8
+
9
+ ## 2.0.0 - 2026-02-27
10
+
11
+ - Started a new changelog lineage for generation 2 of `@teqfw/di`.
12
+ - Replaced legacy v1 implementation with the new architecture.
13
+ - Promoted `src2/` to `src/` and `test2/` to `test/` as the primary code and test layout.
14
+ - Updated project configuration and type paths to the new directory structure.
package/README.md CHANGED
@@ -3,348 +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
- > [!WARNING]
7
- > This branch contains the **legacy v1 line** of `@teqfw/di`.
8
- > The code here is **manually authored** and is kept for compatibility with existing integrations and previously delivered solutions.
9
- >
10
- > Active development has moved to the main branch:
11
- > **https://github.com/teqfw/di/tree/main**
12
- >
13
- > The new container generation is built through an AI-agent workflow and follows a different architecture and dependency model.
14
- > **Backward compatibility with this v1 line is not guaranteed.**
15
-
16
- `@teqfw/di` v1 is a lightweight dependency injection container for standard JavaScript, enabling late binding of code
17
- objects with minimal manual configuration. It integrates in both browser and Node.js environments for modularity and testing.
6
+ Deterministic runtime DI container for native ES modules.
18
7
 
19
- ---
20
-
21
- ## Design Philosophy
22
-
23
- This library is a component of the **TeqFW platform**, an experimental framework grounded in the principles of modular
24
- monolith design, long-term maintainability, late binding, and immutability-first logic composition.
25
-
26
- To explore the conceptual background, see: **[TeqFW Philosophy](./PHILOSOPHY.md)**.
27
-
28
- ---
29
-
30
- ## Dependency Declaration Model
31
-
32
- In `@teqfw/di`, dependencies are declared **exclusively in the constructor (or factory) signature**.
33
- A component defines its dependencies using a **single object parameter**, where each property name
34
- is a dependency identifier interpreted by the container.
35
-
36
- The container analyzes the constructor signature, resolves all declared identifiers **before object
37
- creation**, and invokes the constructor with a fully populated argument object. Created objects are isolated from the container.
38
-
39
- ---
8
+ `@teqfw/di` uses explicit dependency contracts (CDC strings) and module-level dependency descriptors (`__deps__`).
9
+ It does not infer dependencies from constructor signatures.
40
10
 
41
- ## Samples
11
+ ## Version Line
42
12
 
43
- Explore `@teqfw/di` in action through the following demo applications:
13
+ This branch is the v2 line.
44
14
 
45
- - [demo-di-app](https://flancer64.github.io/demo-di-app/): A simple demonstration of dependency injection with
46
- `@teqfw/di`.
47
- - [demo-wa-esm-openai](https://github.com/flancer64/demo-wa-esm-openai): Integrates OpenAI with ES6 modules.
48
- - [pwa-wallet](https://github.com/flancer64/pwa-wallet): A progressive web application wallet showcasing the library's
49
- modularity.
50
- - [spa-remote-console](https://github.com/flancer64/spa-remote-console): Demonstrates remote console functionality in a
51
- single-page application.
52
- - [demo-webauthn-pubkey](https://github.com/flancer64/demo-webauthn-pubkey): Uses Web Authentication (WebAuthn) with
53
- public key credentials.
54
- - [tg-bot-habr-demo-grammy](https://github.com/flancer64/tg-bot-habr-demo-grammy): A Telegram bot demo built with the
55
- grammY library.
15
+ - package version: `2.0.0`
16
+ - changelog starts from `2.0.0`
56
17
 
57
- These projects offer practical examples and insights into using `@teqfw/di` effectively!
58
-
59
- ---
18
+ ## Installation
60
19
 
61
- ## Example of Typical Usage
20
+ ```bash
21
+ npm install @teqfw/di
22
+ ```
62
23
 
63
- Using `@teqfw/di` typically involves a few simple steps: organizing the file structure, declaring dependencies,
64
- configuring the container, and finally retrieving the main object with injected dependencies.
24
+ ## Quick Start
65
25
 
66
- ### Step 1: Organize File Structure
26
+ ### 1. Define modules with `__deps__`
67
27
 
68
- Here’s an example of how files might be organized in a project. This structure can vary depending on your project needs,
69
- as the container can be configured to work with any layout (e.g., within `/home/user/project/`):
28
+ `src/App/Child.mjs`
70
29
 
71
- ```text
72
- ./src/
73
- ./Service/
74
- ./Customer.js
75
- ./Sale.js
76
- ./Config.js
77
- ./Logger.js
78
- ./Main.js
30
+ ```js
31
+ export default function App_Child() {
32
+ return { name: "child" };
33
+ }
79
34
  ```
80
35
 
81
- ### Step 2: Declare Dependencies
82
-
83
- In your code, declare dependencies by specifying them as keys in the constructor. This is the only supported
84
- way to declare dependencies in `@teqfw/di`. Dependency identifiers here follow a namespace style similar to PHP
85
- Zend 1, which is used by default in this library. You can also implement a custom parser if you prefer a
86
- different naming convention or mapping strategy.
36
+ `src/App/Root.mjs`
87
37
 
88
38
  ```js
89
- export default class App_Main {
90
- constructor({
91
- App_Config$: config,
92
- App_Logger$: logger,
93
- App_Service_Customer$: servCustomer,
94
- App_Service_Sale$: servSale,
95
- }) {
96
- /* ... */
97
- }
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
+ };
98
48
  }
99
49
  ```
100
50
 
101
- ### Step 3: Configure the Container
102
-
103
- 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
104
52
 
105
53
  ```js
54
+ import path from "node:path";
55
+ import { fileURLToPath } from "node:url";
106
56
  import Container from "@teqfw/di";
107
57
 
108
- // Create a new instance of the container
109
- const container = new Container();
58
+ const __filename = fileURLToPath(import.meta.url);
59
+ const __dirname = path.dirname(__filename);
110
60
 
111
- // Get the resolver from the container
112
- const resolver = container.getResolver();
61
+ const container = new Container();
62
+ container.addNamespaceRoot("App_", path.resolve(__dirname, "./src/App"), ".mjs");
113
63
 
114
- // Define the namespace root for dependencies, allowing the container to resolve identifiers like 'App_*'
115
- 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
116
68
  ```
117
69
 
118
- ### Step 4: Retrieve the Main Object with Dependencies
70
+ ## Dependency Descriptor (`__deps__`)
119
71
 
120
- Finally, retrieve your main application instance. The container automatically injects all declared dependencies:
72
+ `__deps__` is a static module export:
121
73
 
122
74
  ```js
123
- // Retrieve the main application instance as a singleton asynchronously
124
- const app = await container.get("App_Main$");
75
+ export const __deps__ = {
76
+ localName: "Some_CDC",
77
+ };
125
78
  ```
126
79
 
127
- ---
80
+ Rules used by container runtime:
128
81
 
129
- ## 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
130
86
 
131
- `@teqfw/di` supports a dedicated **test mode** to facilitate unit testing and dependency mocking.
87
+ ## CDC Grammar (Default Profile)
132
88
 
133
- When test mode is enabled via `container.enableTestMode()`, you can manually register singleton dependencies using the
134
- `register(depId, obj)` method:
89
+ Surface form:
135
90
 
136
- ```js
137
- container.enableTestMode();
138
- container.register("App_Service_Customer$", mockCustomerService);
91
+ ```text
92
+ [PlatformPrefix]ModuleName[__ExportName][LifecycleAndWrappers]
139
93
  ```
140
94
 
141
- This makes it easy to substitute real implementations with mocks or stubs during tests, without altering production
142
- logic. Overrides are allowed only in test mode, ensuring clean separation of concerns.
95
+ Where:
143
96
 
144
- ### 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
145
101
 
146
- A powerful feature of `@teqfw/di` is the ability to mock **Node.js built-in libraries** such as `fs`, `path`, or
147
- `process`. This is useful for isolating side effects and simulating system behavior:
102
+ Examples:
148
103
 
149
- ```js
150
- container.register("node:fs", {
151
- existsSync: (path) => path.endsWith(".html"),
152
- });
153
- ```
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:
112
+
113
+ - explicit `teq_` prefix is forbidden
114
+ - wrappers without lifecycle marker are invalid
115
+ - parser is deterministic and fail-fast
154
116
 
155
- You can also register mocks for custom logic or environment-specific behavior:
117
+ ## Public API
156
118
 
157
119
  ```js
158
- container.register("node:path", {
159
- join: (...args) => args.join("/"),
160
- resolve: (p) => `/abs/${p}`,
161
- });
120
+ const container = new Container();
162
121
  ```
163
122
 
164
- These mocks are injected transparently wherever such modules are used as dependencies, making it possible to write pure,
165
- isolated, and deterministic unit tests — even for logic that relies on the filesystem or path resolution.
123
+ Builder stage methods (only before first `get`):
166
124
 
167
- ---
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)
168
132
 
169
- ## Key Benefits
133
+ Resolution:
170
134
 
171
- `@teqfw/di` offers the core functionality of any object container — creating objects and injecting dependencies — with
172
- extensive flexibility and configurability. This allows the library to adapt seamlessly to a wide range of project needs.
173
- Here’s what makes it stand out:
135
+ - `await container.get(cdc)`
174
136
 
175
- - **Automatic Dependency Resolution**: The library resolves and injects dependencies by interpreting constructor
176
- signatures. This basic functionality works out of the box but can be fully customized if needed.
137
+ Behavioral guarantees:
177
138
 
178
- - **Flexible Dependency ID Configuration**: With customizable parsers and chunks, you can define unique ID schemes for
179
- dependencies, making it easy to adapt the library to specific naming conventions or custom mapping rules.
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
180
144
 
181
- - **Mapping IDs to Source Modules via Resolvers**: Thanks to resolvers, `@teqfw/di` lets you map dependency IDs to their
182
- source locations effortlessly. This makes the library adaptable to any project structure or file layout.
145
+ ## Wrappers
183
146
 
184
- - **Immutable Objects for Safer Runtime**: All objects created by the container are frozen by default. This ensures that
185
- dependencies cannot be modified once instantiated, eliminating unintended mutations and reinforcing modular,
186
- predictable application behavior.
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.
187
149
 
188
- - **Preprocessing for Enhanced Control**: Built-in preprocessing allows modifying dependencies at the time of creation,
189
- enabling local overrides or adjustments in functionality. This is especially useful for larger projects, where
190
- different teams may tailor dependencies to their specific requirements. The default preprocessing can also be replaced
191
- to suit more precise needs.
150
+ Wrappers:
192
151
 
193
- - **Interfaces and Dependencies Without TypeScript**: `@teqfw/di` allows you to define interfaces using standard
194
- JavaScript files with JSDoc annotations. The container supports configuring dependencies to replace interfaces with
195
- project-specific implementations, offering flexibility without requiring TypeScript.
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
196
157
 
197
- - **Postprocessing for Object Customization**: Use postprocessing to add wrappers or extend created objects. This can be
198
- valuable for adding factories, logging, or other behavior, tailored to each project’s requirements.
158
+ Surface form:
159
+
160
+ ```text
161
+ ModuleName$$_wrapperA_wrapperB
162
+ ```
199
163
 
200
- These features make `@teqfw/di` a powerful, adaptable DI container that not only provides ready-to-use solutions but can
201
- be easily customized to meet unique project demands.
164
+ Wrappers are part of the dependency contract (CDC).
165
+ They declaratively modify how a resolved value behaves.
202
166
 
203
167
  ---
204
168
 
205
- ## Installation
206
-
207
- ### For Node.js
169
+ ### Example: Logging Wrapper
208
170
 
209
- To install `@teqfw/di` in a Node.js environment, use the following command:
171
+ Suppose we want to log all method calls of a service without modifying the service itself.
210
172
 
211
- ```shell
212
- npm install @teqfw/di
213
- ```
214
-
215
- Then, import and initialize the container:
173
+ #### Service module
216
174
 
217
175
  ```js
218
- import Container from "@teqfw/di";
219
-
220
- /** @type {TeqFw_Di_Container} */
221
- 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
+ }
222
186
  ```
223
187
 
224
- ### For the Browser (ESM Module)
225
-
226
- To use `@teqfw/di` in a browser environment with ES modules, include it as follows (~5KB):
188
+ #### Container configuration
227
189
 
228
- ```html
229
- <script type="module">
230
- import Container from "https://cdn.jsdelivr.net/npm/@teqfw/di@latest/+esm";
231
-
232
- /** @type {TeqFw_Di_Container} */
233
- const container = new Container();
234
- </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
+ });
235
209
  ```
236
210
 
237
- ### For the Browser (UMD Module)
211
+ #### Request
238
212
 
239
- Alternatively, you can use the UMD version in the browser (~5KB):
213
+ ```js
214
+ const service = await container.get("App_Service$$_logIO");
240
215
 
241
- ```html
242
- <script src="https://cdn.jsdelivr.net/npm/@teqfw/di@latest/dist/umd.js"></script>
243
- <script>
244
- /** @type {TeqFw_Di_Container} */
245
- const container = new window.TeqFw_Di_Container();
246
- </script>
216
+ service.sum(2, 3);
217
+ // [CALL] sum -> [2, 3]
218
+ // [RETURN] sum -> 5
247
219
  ```
248
220
 
249
- ---
250
-
251
- ## Using the Container
252
-
253
- ### In Node.js
254
-
255
- 1. **Configure Dependency Mapping**: Configure the resolver to detect the platform environment. Then, set up namespace
256
- roots to map dependency IDs to their source paths.
257
-
258
- ```js
259
- import { platform } from "node:process";
221
+ The module remains unaware of logging.
222
+ The wrapper applies cross-cutting behavior declaratively through CDC.
260
223
 
261
- const resolver = container.getResolver();
262
- resolver.setWindowsEnv(platform === "win32"); // Adjusts for Windows environment if needed
263
- resolver.addNamespaceRoot("App_", "/path/to/src");
264
- ```
224
+ This allows:
265
225
 
266
- 2. **Retrieve Singleton Instances**: Retrieve the main application instance as a singleton asynchronously:
226
+ - tracing
227
+ - metrics collection
228
+ - access control
229
+ - behavioral instrumentation
267
230
 
268
- ```js
269
- const app = await container.get("App_Main$");
270
- ```
231
+ without modifying business logic or module structure.
271
232
 
272
- ### In the Browser
233
+ Wrappers therefore act as a declarative DI-level AOP mechanism.
273
234
 
274
- 1. **Configure Dependency Mapping**: Set up namespace roots to map dependency IDs to their source paths, using URLs as
275
- needed.
276
-
277
- ```js
278
- const resolver = container.getResolver();
279
- resolver.addNamespaceRoot("App_", "https://cdn.jsdelivr.net/npm/@flancer64/demo-di-app@0.2/src");
280
- ```
281
-
282
- 2. **Retrieve Singleton Instances**: Retrieve the main application instance as a singleton asynchronously:
283
-
284
- ```js
285
- const app = await container.get("App_Main$");
286
- ```
287
-
288
- With these steps, the container is configured to automatically resolve and inject dependencies based on your setup,
289
- whether in Node.js or in a browser environment.
290
-
291
- ---
292
-
293
- ## Dependency ID Types
294
-
295
- `@teqfw/di` supports various dependency ID formats to match different import styles and object requirements. Here’s a
296
- quick reference:
297
-
298
- | Dependency ID | Import Style | Description |
299
- | --------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
300
- | `App_Service` | `import * as Service from './App/Service.js';` | Imports the entire module as an ES module. |
301
- | `App_Service.default` | `import {default} from './App/Service.js';` | Imports the default export as-is. |
302
- | `App_Service.name` | `import {name} from './App/Service.js';` | Imports a named export as-is. |
303
- | `App_Service$` | `import {default as Factory} from './App/Service.js';` | Uses default export as a singleton for the container. |
304
- | `App_Service$$` | `import {default as Factory} from './App/Service.js';` | Creates a new instance from the default export for each dependency. |
305
- | `App_Service.name$` | `import {name} from './App/Service.js';` | Uses a named export as a singleton. |
306
- | `App_Service.name$$` | `import {name} from './App/Service.js';` | Creates a new instance from a named export for each dependency. |
307
- | `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()`. |
308
-
309
- ### Example Usage
310
-
311
- Here’s an example showing a class with multiple dependencies, each using different dependency IDs:
235
+ ## Test Mode and Mocks
312
236
 
313
237
  ```js
314
- export default class App_Main {
315
- constructor({
316
- App_Service: EsModule,
317
- "App_Service.default": defaultExportAsIs,
318
- "App_Service.name": namedExportAsIs,
319
- App_Service$: defaultExportAsSingleton,
320
- App_Service$$: defaultExportAsInstance,
321
- "App_Service.name$": namedExportAsSingleton,
322
- "App_Service.name$$": namedExportAsInstance,
323
- "App_Service.name(factory)": factoryToCreateInstancesFromNamedExport,
324
- }) {
325
- const { default: SrvDef, name: SrvName } = EsModule; // Deconstruct the module and access the exports
326
- }
327
- }
238
+ container.enableTestMode();
239
+ container.register("App_Service$", { name: "mock-service" });
328
240
  ```
329
241
 
330
- ---
331
-
332
- ## Summary
242
+ Mock lookup uses canonical parsed dependency identity and is applied before resolver/instantiation.
333
243
 
334
- `@teqfw/di` is a versatile and lightweight dependency injection container tailored for modern JavaScript applications.
335
- With its flexible dependency mapping, customizable ID configurations, and support for dynamic object creation,
336
- `@teqfw/di` empowers developers to build modular, testable, and scalable codebases.
244
+ ## Browser Usage
337
245
 
338
- Whether you’re working in Node.js or a browser environment, `@teqfw/di` provides a solid foundation with built-in
339
- functionality that you can further adapt to fit your project’s unique requirements. Feel free to explore and extend the
340
- library as needed to create your ideal development environment.
246
+ ESM via jsDelivr:
341
247
 
342
- For any questions, feedback, or collaboration opportunities, please feel free to reach out through the following
343
- 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
+ ```
344
254
 
345
- - **Website**: [wiredgeese.com](https://wiredgeese.com)
346
- - **LinkedIn**: [LinkedIn Profile](https://www.linkedin.com/in/aleksandrs-gusevs-011ba928/)
255
+ ## Documentation Source
347
256
 
348
- 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/`:
349
258
 
350
- 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};
package/dist/umd.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).TeqFw_Di_Container=t()}(this,function(){"use strict";var e={CA:"A",CF:"F",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}}});
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";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(){}});return class{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,b=new y,C=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(C(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=b.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(C(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}}}}});