@teqfw/di 2.3.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.5.0 - 2026-04-04 - Parser and documentation refinement
4
+
5
+ * Clarified JSDoc typing and module headers to align with TeqFW specifications.
6
+ * Allowed parser recognition of Node.js built-ins that include underscores in their names.
7
+ * Updated package version metadata to `2.5.0`.
8
+
9
+ ## 2.4.0 - 2026-03-31 - Test coverage cleanup
10
+
11
+ * Removed low-value unit tests in favor of broader integration coverage.
12
+ * Moved the useful preprocess/postprocess order scenario into integration tests.
13
+ * Updated package version metadata to `2.4.0`.
14
+
3
15
  ## 2.3.1 - 2026-03-25 - Patch release preparation
4
16
 
5
17
  * Updated package version metadata to `2.3.1`.
package/README.md CHANGED
@@ -157,18 +157,41 @@ export default function App_Child() {
157
157
  }
158
158
  ```
159
159
 
160
+ `src/App/Helper/Cast.mjs`
161
+
162
+ ```javascript
163
+ export default function App_Helper_Cast() {
164
+ return function cast(value) {
165
+ return String(value);
166
+ };
167
+ }
168
+ ```
169
+
160
170
  `src/App/Root.mjs`
161
171
 
162
172
  ```javascript
163
173
  export const __deps__ = {
164
- child: "App_Child$",
174
+ cast: "App_Helper_Cast$",
165
175
  };
166
176
 
167
- export default function App_Root({ child }) {
168
- return {
169
- name: "root",
170
- child,
171
- };
177
+ export default class RuntimeWrapper {
178
+ constructor() {
179
+ return {
180
+ mode: "runtime-wrapper",
181
+ };
182
+ }
183
+ }
184
+
185
+ export class Factory {
186
+ constructor({ cast }) {
187
+ this.configure = function (params = {}) {
188
+ return {
189
+ name: "factory",
190
+ cast,
191
+ params,
192
+ };
193
+ };
194
+ }
172
195
  }
173
196
  ```
174
197
 
@@ -186,10 +209,9 @@ const container = new Container();
186
209
 
187
210
  container.addNamespaceRoot("App_", path.resolve(__dirname, "./src/App"), ".mjs");
188
211
 
189
- const root = await container.get("App_Root$");
212
+ const factory = await container.get("App_Root__Factory$");
190
213
 
191
- console.log(root.name);
192
- console.log(root.child.name);
214
+ console.log(factory.configure().mode);
193
215
  ```
194
216
 
195
217
  The container:
@@ -201,21 +223,96 @@ The container:
201
223
 
202
224
  ## Dependency Contracts (`__deps__`)
203
225
 
204
- Modules declare dependencies using a static export.
226
+ Modules declare dependencies using a static export descriptor.
205
227
 
206
228
  ```javascript
207
229
  export const __deps__ = {
208
- localName: "Dependency_CDC",
230
+ default: {
231
+ localName: "Dependency_CDC",
232
+ },
233
+ Factory: {
234
+ localName: "Dependency_CDC",
235
+ },
209
236
  };
210
237
  ```
211
238
 
212
239
  Rules:
213
240
 
241
+ - the canonical form is hierarchical and keyed by export name
242
+ - each export entry maps constructor argument names to CDC dependency identifiers
214
243
  - if `__deps__` is absent — module has no dependencies
215
- - keys correspond to constructor argument names
216
- - values are CDC dependency identifiers
244
+ - a flat `__deps__` object is a shorthand allowed only for limited single-export cases
217
245
  - dependencies are resolved recursively
218
246
 
247
+ Canonical example:
248
+
249
+ ```javascript
250
+ export const __deps__ = {
251
+ default: {
252
+ cast: "Fl32_Web_Helper_Cast$",
253
+ },
254
+ Factory: {
255
+ cast: "Fl32_Web_Helper_Cast$",
256
+ },
257
+ };
258
+
259
+ export default class RuntimeWrapper {
260
+ constructor() {
261
+ return {
262
+ mode: "runtime-wrapper",
263
+ };
264
+ }
265
+ }
266
+
267
+ export class Factory {
268
+ constructor({ cast }) {
269
+ this.configure = function (params = {}) {
270
+ // DI-managed component
271
+ };
272
+ }
273
+ }
274
+ ```
275
+
276
+ In this pattern:
277
+
278
+ - the default export is the runtime wrapper or module shell
279
+ - the named `Factory` export is the DI-managed component
280
+ - `__deps__` applies to the export selected by the CDC, such as `App_Module__Factory$`
281
+
282
+ Shorthand example for a single-export module:
283
+
284
+ ```javascript
285
+ export const __deps__ = {
286
+ cast: "Fl32_Web_Helper_Cast$",
287
+ };
288
+
289
+ export default class RuntimeWrapper {
290
+ constructor() {
291
+ return {
292
+ mode: "runtime-wrapper",
293
+ };
294
+ }
295
+ }
296
+ ```
297
+
298
+ Empty descriptor example:
299
+
300
+ ```javascript
301
+ export default class App_Empty {
302
+ constructor() {
303
+ this.ready = function () {
304
+ return true;
305
+ };
306
+ }
307
+ }
308
+ ```
309
+
310
+ In this pattern:
311
+
312
+ - the module has no declared dependencies
313
+ - `__deps__` is omitted entirely
314
+ - the empty form is valid and intentionally explicit through omission
315
+
219
316
  ## Canonical Dependency Codes (CDC)
220
317
 
221
318
  CDC identifiers describe **how dependencies should be resolved**.
package/ai/AGENTS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTS.md
2
2
 
3
- Version: 20260307
3
+ Version: 20260331
4
4
 
5
5
  ## Package Purpose
6
6
 
package/ai/concepts.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # concepts.md
2
2
 
3
- Version: 20260307
3
+ Version: 20260331
4
4
 
5
5
  ## Purpose of the Container
6
6
 
@@ -41,6 +41,8 @@ Dependency identifiers define:
41
41
  - which export must be used
42
42
  - whether the dependency represents a singleton or a new instance
43
43
 
44
+ Module dependency descriptors complement CDCs by declaring export-scoped dependency maps. The canonical form is hierarchical and keyed by export name; a flat descriptor is shorthand for limited single-export cases; omission means there are no dependencies.
45
+
44
46
  The identifier syntax and resolution rules are described in **dependency-id.md**.
45
47
 
46
48
  ## Namespaces
package/ai/container.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # container.md
2
2
 
3
- Version: 20260307
3
+ Version: 20260331
4
4
 
5
5
  ## Role of the Container
6
6
 
@@ -47,7 +47,7 @@ The core operations are:
47
47
  - **addPreprocess(handler)** — register a handler that can transform dependency identifiers before resolution.
48
48
  - **addPostprocess(handler)** — register a handler that can modify created objects after instantiation.
49
49
 
50
- The exact semantics of dependency identifiers are defined in **dependency-id.md**.
50
+ The exact semantics of dependency identifiers are defined in **dependency-id.md**. Dependency descriptors are export-scoped: canonical descriptors are hierarchical and keyed by export name, while flat descriptors are shorthand for limited single-export cases.
51
51
 
52
52
  ## Container State Model
53
53
 
@@ -1,6 +1,6 @@
1
1
  # dependency-id.md
2
2
 
3
- Version: 20260307
3
+ Version: 20260331
4
4
 
5
5
  ## Purpose
6
6
 
package/ai/extensions.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # extensions.md
2
2
 
3
- Version: 20260307
3
+ Version: 20260331
4
4
 
5
5
  ## Purpose
6
6
 
@@ -54,6 +54,8 @@ App_Service_User$$_wrapLog_wrapTrace
54
54
 
55
55
  In this example the container creates a new instance of the dependency and applies the wrappers `wrapLog` and `wrapTrace` during the postprocess stage.
56
56
 
57
+ Wrappers do not change the structure of `__deps__`. Dependency descriptors remain either hierarchical export-scoped descriptors, shorthand flat descriptors for limited single-export cases, or omitted entirely for empty-descriptor modules.
58
+
57
59
  ## Execution Order
58
60
 
59
61
  Multiple wrappers may be applied to a single dependency. Wrappers are executed in the order in which they appear in the CDC.
package/ai/package-api.ts CHANGED
@@ -267,14 +267,14 @@ export const PACKAGE_API: PackageApiContract = {
267
267
  kind: 'module-contract',
268
268
  summary: 'Shape expected from application modules resolved by the container.',
269
269
  fields: {
270
- __deps__: 'Optional top-level Record<string, string> mapping constructor keys to CDC strings.',
270
+ __deps__: 'Optional export-scoped dependency descriptor. Canonical form is hierarchical: Record<exportName, Record<dependencyKey, CDC string>>. A flat Record<dependencyKey, CDC string> is shorthand for limited single-export cases.',
271
271
  moduleNamespace: 'Whole ES module namespace object returned for as-is CDC without selected export.',
272
272
  defaultExport: 'Used when the parsed DepId selects exportName="default" for factory composition.',
273
273
  namedExports: 'May be selected via __ExportName for factory composition and may also provide wrapper functions.',
274
274
  wrapperExport: 'Named export whose identifier appears in depId.wrappers; it must be synchronous and unary.',
275
275
  },
276
276
  notes: [
277
- 'The current runtime reads namespace.__deps__ directly; it does not use export-scoped dependency maps.',
277
+ 'The current runtime accepts both export-scoped hierarchical descriptors and the flat shorthand form for limited single-export cases.',
278
278
  'Wrapper functions are exported by the same resolved module namespace, not registered globally in the container.',
279
279
  ],
280
280
  },
@@ -429,7 +429,7 @@ export const PACKAGE_API: PackageApiContract = {
429
429
  operationalNotes: [
430
430
  'Only two runtime entrypoints are supported by package.json exports: @teqfw/di and @teqfw/di/src/Config/NamespaceRegistry.mjs.',
431
431
  'Resolved values are frozen before being returned.',
432
- 'The current runtime reads __deps__ as a flat top-level map exported by the module namespace.',
432
+ 'Dependency descriptors are canonical when hierarchical and export-scoped; flat descriptors are shorthand for limited single-export cases; omission means no dependencies.',
433
433
  'With the default parser, CDC without lifecycle returns the whole module namespace as-is; named export selection implies factory composition.',
434
434
  'Named wrapper exports are executed after addPostprocess() hooks and before freeze.',
435
435
  'In the current implementation, CDC markers $$ and $$$ both end up as transient/no-cache behavior.',
package/ai/usage.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # usage.md
2
2
 
3
- Version: 20260307
3
+ Version: 20260331
4
4
 
5
5
  ## Purpose
6
6
 
@@ -10,7 +10,7 @@ The container performs deterministic runtime linking of ES modules and returns f
10
10
 
11
11
  ## Module Structure
12
12
 
13
- Modules intended for container linking export a default class and may export a static dependency descriptor named `__deps__`.
13
+ Modules intended for container linking may expose a default export, a named export, or both. The static dependency descriptor `__deps__` is canonical when it is hierarchical and keyed by export name. It describes the dependencies of the export selected by the CDC.
14
14
 
15
15
  Dependencies are injected into the constructor as a single structured object. In TeqFW-style modules the public API is defined inside the constructor through assignments to `this`, while internal state may be held in constructor-local variables captured by closures.
16
16
 
@@ -21,26 +21,39 @@ Example module:
21
21
 
22
22
  export const __deps__ = {
23
23
  default: {
24
- child: "App_Child$",
24
+ cast: "Fl32_Web_Helper_Cast$",
25
+ },
26
+ Factory: {
27
+ cast: "Fl32_Web_Helper_Cast$",
25
28
  },
26
29
  };
27
30
 
28
31
  /**
29
- * @typedef {Object} App_Root$Deps
30
- * @property {App_Child} child
32
+ * Runtime wrapper that can hold non-DI behavior.
33
+ */
34
+
35
+ export default class RuntimeWrapper {
36
+ constructor() {
37
+ return proxy;
38
+ }
39
+ }
40
+
41
+ /**
42
+ * @typedef {Object} App_Factory$Deps
43
+ * @property {object} cast
31
44
  */
32
45
 
33
- export default class App_Root {
46
+ export class Factory {
34
47
  /**
35
- * @param {App_Root$Deps} deps
48
+ * @param {App_Factory$Deps} deps
36
49
  */
37
- constructor({ child }) {
38
- this.getName = function () {
39
- return "root";
40
- };
41
-
42
- this.getChild = function () {
43
- return child;
50
+ constructor({ cast }) {
51
+ this.configure = function (params = {}) {
52
+ return {
53
+ mode: "factory",
54
+ cast,
55
+ params,
56
+ };
44
57
  };
45
58
  }
46
59
  }
@@ -62,12 +75,14 @@ export default class App_Child {
62
75
 
63
76
  Rules:
64
77
 
78
+ - the canonical form of `__deps__` is hierarchical and keyed by export name
79
+ - each export entry maps constructor dependency names to CDC identifiers
65
80
  - if `__deps__` is absent the module has no dependencies
66
- - `__deps__.default` describes dependencies of the default export
67
- - keys correspond to constructor dependency names
68
- - values are CDC identifiers
81
+ - a flat `__deps__` object is shorthand for limited single-export cases
69
82
  - dependencies are resolved recursively before instantiation
70
83
 
84
+ When the CDC selects `App_Module$`, the container uses the default export. When the CDC selects `App_Module__Factory$`, the container uses the named `Factory` export. In the first case the default export can act as a runtime wrapper or module shell; in the second case the named export is the DI-managed component that receives `__deps__.Factory`.
85
+
71
86
  ## Container Configuration
72
87
 
73
88
  The container is configured in the composition root of the application. Namespace roots define how CDC prefixes map to module locations.
@@ -178,6 +193,33 @@ Typical usage:
178
193
  - factory entry points
179
194
  - specialized constructors
180
195
 
196
+ For modules with a runtime default export and a DI-managed named export, the canonical descriptor follows the export-scoped hierarchical form, for example:
197
+
198
+ ```js
199
+ export const __deps__ = {
200
+ default: {
201
+ cast: "Fl32_Web_Helper_Cast$",
202
+ },
203
+ Factory: {
204
+ cast: "Fl32_Web_Helper_Cast$",
205
+ },
206
+ };
207
+
208
+ export default class RuntimeWrapper {
209
+ constructor() {
210
+ return proxy;
211
+ }
212
+ }
213
+
214
+ export class Factory {
215
+ constructor({ cast }) {
216
+ this.configure = function (params = {}) {
217
+ return { cast, params };
218
+ };
219
+ }
220
+ }
221
+ ```
222
+
181
223
  ### Wrapper Application
182
224
 
183
225
  Wrappers modify the produced value through postprocess plugins.
@@ -188,6 +230,32 @@ App_Service$$_log_trace
188
230
 
189
231
  The container creates the dependency and applies wrappers in declared order.
190
232
 
233
+ ### Shorthand Form
234
+
235
+ Some single-export modules may use a flat `__deps__` object as shorthand.
236
+
237
+ ```js
238
+ export const __deps__ = {
239
+ cast: "Fl32_Web_Helper_Cast$",
240
+ };
241
+ ```
242
+
243
+ This form is a convenience for limited cases and does not replace the canonical hierarchical model.
244
+
245
+ ### Empty Descriptor
246
+
247
+ Modules with no declared dependencies omit `__deps__` entirely.
248
+
249
+ ```js
250
+ export default class App_Empty {
251
+ constructor() {
252
+ this.ready = function () {
253
+ return true;
254
+ };
255
+ }
256
+ }
257
+ ```
258
+
191
259
  Typical usage:
192
260
 
193
261
  - logging
@@ -221,7 +289,7 @@ Applications typically resolve a single root dependency.
221
289
  const root = await container.get("App_Root$");
222
290
  ```
223
291
 
224
- The container recursively resolves all dependencies declared through `__deps__` and constructs the object graph.
292
+ The container recursively resolves all dependencies declared through `__deps__` and constructs the object graph. Empty descriptor modules omit `__deps__` entirely.
225
293
 
226
294
  ## Wrapper-Based Behavioral Composition
227
295
 
package/dist/esm.js CHANGED
@@ -1 +1 @@
1
- var e=Object.freeze({AS_IS:"A",FACTORY:"F"});var t=Object.freeze({SINGLETON:"S",TRANSIENT:"T"});var o=Object.freeze({TEQ:"teq",NODE:"node",NPM:"npm"});const 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){const t=e&&"object"==typeof e?e:{},o=new l;o.moduleName="string"==typeof t.moduleName?t.moduleName:"";const c="string"==typeof t.platform?t.platform:void 0;o.platform=c&&i.has(c)?c:r;let p=null;null===t.exportName?p=null:"string"==typeof t.exportName&&(p=t.exportName),o.exportName=p;const f="string"==typeof t.composition?t.composition:void 0;o.composition=f&&s.has(f)?f:n;const u="string"==typeof t.life?t.life:void 0;return o.life=u&&a.has(u)?u:null,o.wrappers=Array.isArray(t.wrappers)?t.wrappers.filter(e=>"string"==typeof e):[],o.origin="string"==typeof t.origin?t.origin:"",Object.freeze(o.wrappers),Object.freeze(o)}};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(!/^[\x00-\x7F]+$/.test(i))throw new Error("CDC must be ASCII.");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.");let c=null,p=!1,f=[],u=a;const m=u.match(/(\${1,3})(?:_[a-z][0-9A-Za-z]*)*$/);if(m){const e=m[1],o=m[0].slice(e.length);if(p=!0,"$"===e)c=t.SINGLETON;else if("$$"===e)c=t.TRANSIENT;else{if("$$$"!==e)throw new Error("Lifecycle marker is invalid.");c=null}u=u.slice(0,m.index),o.length>0&&(f=o.slice(1).split("_"))}else{if(a.includes("$"))throw new Error("Invalid lifecycle encoding.");if(/(?:^|[^_])_[a-z][0-9A-Za-z]*$/.test(a))throw new Error("Wrapper without lifecycle is forbidden.")}const d=u.indexOf("__"),g=u.lastIndexOf("__");if(-1!==d&&d!==g)throw new Error("Export delimiter must appear at most once.");if(u.startsWith("__")||u.endsWith("__"))throw new Error("Malformed export segment.");let w=u,h=null;if(-1!==d){if(w=u.slice(0,d),h=u.slice(d+2),!h)throw new Error("Export must be non-empty.");if(h.includes("_"))throw new Error("Export must not contain _.");if(h.includes("$"))throw new Error("Export must not contain $.")}if(!w)throw new Error("moduleName must be non-empty.");if(w.startsWith("_")||w.startsWith("$"))throw new Error("moduleName must not start with _ or $.");if(w.includes("__"))throw new Error("moduleName must not contain __.");if(w.includes("$"))throw new Error("moduleName must not contain $.");if(l!==o.NPM){if(l===o.NODE){if(!/^[A-Za-z_][$0-9A-Za-z_/-]*$/.test(w))throw new Error("node moduleName must satisfy the built-in specifier form.")}else if(!/^[A-Za-z_][$0-9A-Za-z_]*$/.test(w))throw new Error("moduleName must satisfy the canonical identifier form.")}else if(!/^[@A-Za-z_][$0-9A-Za-z_./-]*$/.test(w))throw new Error("npm moduleName must satisfy the package specifier form.");let $=e.AS_IS;null!==h?$=e.FACTORY:p&&($=e.FACTORY,h="default");const y=r.create({moduleName:w,platform:l,exportName:h,composition:$,life:c,wrappers:f,origin:s});return n&&n.log(`Parser.parse: produced='${y.platform}::${y.moduleName}'.`),y},this.setLogger=function(e){n=e}}}let f=class{prefix;target;defaultExt},u=class{create(e){const t=e&&"object"==typeof e?e:{},o=new f;return o.prefix="string"==typeof t.prefix?t.prefix:void 0,o.target="string"==typeof t.target?t.target:void 0,o.defaultExt="string"==typeof t.defaultExt?t.defaultExt:void 0,Object.freeze(o)}};class m{namespaces;nodeModulesRoot}class d{constructor(){const e=new u;this.create=function(t){const o=t&&"object"==typeof t?t:{},r=new m,n=Array.isArray(o.namespaces)?o.namespaces:[];return r.namespaces=n.map(t=>e.create(t)),r.nodeModulesRoot="string"==typeof o.nodeModulesRoot?o.nodeModulesRoot:void 0,Object.freeze(r.namespaces),Object.freeze(r)}}}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=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("::")},i=async function(o,s,a,l){const c=n(o);if(a.has(c)){const e=[...l,c].join(" -> ");throw new Error(`Cyclic dependency detected: ${e}`)}const p=n(o);if(!s.has(p)){a.add(c),l.push(c);try{const n=await t.resolve(o);r&&r.log(`GraphResolver.walk: resolved '${p}'.`),s.set(p,{depId:o,namespace:n});const c=Reflect.get(n,"__deps__");if(void 0===c)return;const f=c;for(const[,t]of Object.entries(f)){const o=t,n=e.parse(o);r&&r.log(`GraphResolver.walk: edge '${p}' -> '${n.platform}::${n.moduleName}'.`),await i(n,s,a,l)}}finally{l.pop(),a.delete(c)}}};this.resolve=async function(e){const t=new Map,o=new Set;return await i(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(t instanceof Promise)throw new Error("Factory composition must return synchronously (non-Promise).");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){return"function"==typeof e};this.execute=function(t,o,r){let n=o;const i=t.wrappers;for(const t of i){if(!(t in r))throw new Error(`Wrapper '${t}' is not found in module namespace.`);const o=r[t];if(!e(o))throw new Error(`Wrapper '${t}' must be callable.`);if(n=o(n),n instanceof Promise)throw new Error(`Wrapper '${t}' must return synchronously (non-Promise).`)}return n}}}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 x=Object.freeze({log(){},error(){}});class E{constructor(){let e="notConfigured";const t=[],o=[],r=[],n=new Map,i=new WeakMap;let s=!1,a=!1,l=new p;const c=new d;let f,u,m,E=x;const C=new h,b=new y,v=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("::")},_=function(e){return v(e)},I=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;if("[object Module]"===Object.prototype.toString.call(e))return e;if(Object.isFrozen(e))return e;try{Object.freeze(e)}catch(e){E.log(`Container.freeze: skipped (${String(e)}).`)}return e},j=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;const o=e;if(i.has(o))return i.get(o);try{return Reflect.get(o,"then"),e}catch{const e=new Proxy(o,{get(e,t,o){if("then"!==t)return Reflect.get(e,t,o)}});return i.set(o,e),e}},A=function(){if("notConfigured"!==e)throw new Error("Container configuration is locked.")},R=function(e){a&&E.log(`Container.builder: ${e}`)};this.addPreprocess=function(e){A(),R("addPreprocess()."),t.push(e)},this.addPostprocess=function(e){A(),R("addPostprocess()."),o.push(e)},this.setParser=function(e){A(),l=e,"function"==typeof l.setLogger&&l.setLogger(a?E:null),R("setParser().")},this.addNamespaceRoot=function(e,t,o){A(),R(`addNamespaceRoot('${e}').`),r.push({prefix:e,target:t,defaultExt:o})},this.enableTestMode=function(){A(),R("enableTestMode()."),s=!0},this.enableLogging=function(){A(),a||(a=!0,E=new N,"function"==typeof l.setLogger&&l.setLogger(E),E.log("Container.builder: enableLogging()."))},this.register=function(e,t){if(A(),R(`register('${e}').`),!0!==s)throw new Error("Container test mode is disabled.");const o=l.parse(e);n.set(_(o),t)},this.get=async function(i){if("failed"===e)throw E.error(`Container.get: rejected in failed state cdc='${i}'.`),new Error("Container is in failed state.");let a="start";try{E.log(`Container.get: cdc='${i}'.`),function(){if("notConfigured"!==e)return;E.log("Container.transition: notConfigured -> operational."),e="operational";const t=c.create({namespaces:r});"function"==typeof l.setLogger&&l.setLogger(E),f=new g({config:t,logger:E}),u=new w({parser:l,resolver:f,logger:E}),m=new $(E)}(),E.log(`Container.state: '${e}'.`),a="parse",E.log("Container.pipeline: parse:entry.");const p=l.parse(i);E.log(`Container.pipeline: parse:exit '${p.platform}::${p.moduleName}'.`),a="preprocess",E.log("Container.pipeline: preprocess:entry.");const d=function(e){let o=e;for(const e of t)o=e(o);return o}(p);if(E.log(`Container.pipeline: preprocess:exit '${d.platform}::${d.moduleName}'.`),!0===s){a="mock",E.log("Container.pipeline: mock-lookup:entry.");const e=_(d);if(n.has(e)){E.log(`Container.pipeline: mock-lookup:hit '${e}'.`),a="freeze",E.log("Container.pipeline: freeze:entry.");const t=I(n.get(e));return E.log("Container.pipeline: freeze:exit."),E.log("Container.pipeline: return:success."),j(t)}E.log(`Container.pipeline: mock-lookup:miss '${e}'.`)}else E.log("Container.pipeline: mock-lookup:disabled.");a="resolve",E.log("Container.pipeline: resolve:entry.");const h=await u.resolve(d);E.log(`Container.pipeline: resolve:exit nodes=${h.size}.`);const y=new Map,N=function(e){if(y.has(e))return y.get(e);if(!h.has(e))throw new Error(`Resolved graph node is missing for '${e}'.`);const t=h.get(e);a="lifecycle",E.log(`Container.pipeline: lifecycle:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const r=m.apply(t.depId,function(){a="instantiate",E.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=l.parse(r);e[t]=N(v(n))}const n=C.instantiate(t.depId,t.namespace,e);E.log(`Container.pipeline: instantiate:exit '${t.depId.platform}::${t.depId.moduleName}'.`),a="postprocess",E.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);E.log(`Container.pipeline: postprocess:exit '${t.depId.platform}::${t.depId.moduleName}'.`);const s=b.execute(t.depId,i,t.namespace);a="freeze",E.log(`Container.pipeline: freeze:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const c=I(s);return E.log(`Container.pipeline: freeze:exit '${t.depId.platform}::${t.depId.moduleName}'.`),c});return E.log(`Container.pipeline: lifecycle:exit '${t.depId.platform}::${t.depId.moduleName}'.`),y.set(e,r),r},x=N(v(d));return E.log("Container.pipeline: return:success."),j(x)}catch(t){throw E.error(`Container.pipeline: failed at stage='${a}'.`,t),E.log("Container.transition: operational -> failed."),e="failed",t}}}}export{E as default};
1
+ var e=Object.freeze({AS_IS:"A",FACTORY:"F"});var t=Object.freeze({SINGLETON:"S",TRANSIENT:"T"});var o=Object.freeze({TEQ:"teq",NODE:"node",NPM:"npm"});const 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){const t=e&&"object"==typeof e?e:{},o=new l;o.moduleName="string"==typeof t.moduleName?t.moduleName:"";const c="string"==typeof t.platform?t.platform:void 0;o.platform=c&&i.has(c)?c:r;let p=null;null===t.exportName?p=null:"string"==typeof t.exportName&&(p=t.exportName),o.exportName=p;const f="string"==typeof t.composition?t.composition:void 0;o.composition=f&&s.has(f)?f:n;const u="string"==typeof t.life?t.life:void 0;return o.life=u&&a.has(u)?u:null,o.wrappers=Array.isArray(t.wrappers)?t.wrappers.filter(e=>"string"==typeof e):[],o.origin="string"==typeof t.origin?t.origin:"",Object.freeze(o.wrappers),Object.freeze(o)}};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(!/^[\x00-\x7F]+$/.test(i))throw new Error("CDC must be ASCII.");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.");let c=null,p=!1,f=[],u=a;const m=u.match(/(\${1,3})(?:_[a-z][0-9A-Za-z]*)*$/);if(m){const e=m[1],o=m[0].slice(e.length);if(p=!0,"$"===e)c=t.SINGLETON;else if("$$"===e)c=t.TRANSIENT;else{if("$$$"!==e)throw new Error("Lifecycle marker is invalid.");c=null}u=u.slice(0,m.index),o.length>0&&(f=o.slice(1).split("_"))}else{if(a.includes("$"))throw new Error("Invalid lifecycle encoding.");if(l!==o.NODE&&/(?:^|[^_])_[a-z][0-9A-Za-z]*$/.test(a))throw new Error("Wrapper without lifecycle is forbidden.")}const d=u.indexOf("__"),g=u.lastIndexOf("__");if(-1!==d&&d!==g)throw new Error("Export delimiter must appear at most once.");if(u.startsWith("__")||u.endsWith("__"))throw new Error("Malformed export segment.");let w=u,h=null;if(-1!==d){if(w=u.slice(0,d),h=u.slice(d+2),!h)throw new Error("Export must be non-empty.");if(h.includes("_"))throw new Error("Export must not contain _.");if(h.includes("$"))throw new Error("Export must not contain $.")}if(!w)throw new Error("moduleName must be non-empty.");if(w.startsWith("_")||w.startsWith("$"))throw new Error("moduleName must not start with _ or $.");if(w.includes("__"))throw new Error("moduleName must not contain __.");if(w.includes("$"))throw new Error("moduleName must not contain $.");if(l!==o.NPM){if(l===o.NODE){if(!/^[A-Za-z_][$0-9A-Za-z_/-]*$/.test(w))throw new Error("node moduleName must satisfy the built-in specifier form.")}else if(!/^[A-Za-z_][$0-9A-Za-z_]*$/.test(w))throw new Error("moduleName must satisfy the canonical identifier form.")}else if(!/^[@A-Za-z_][$0-9A-Za-z_./-]*$/.test(w))throw new Error("npm moduleName must satisfy the package specifier form.");let y=e.AS_IS;null!==h?y=e.FACTORY:p&&(y=e.FACTORY,h="default");const $=r.create({moduleName:w,platform:l,exportName:h,composition:y,life:c,wrappers:f,origin:s});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){const t=e&&"object"==typeof e?e:{},o=new f;return o.prefix="string"==typeof t.prefix?t.prefix:void 0,o.target="string"==typeof t.target?t.target:void 0,o.defaultExt="string"==typeof t.defaultExt?t.defaultExt:void 0,Object.freeze(o)}};class m{namespaces;nodeModulesRoot}class d{constructor(){const e=new u;this.create=function(t){const o=t&&"object"==typeof t?t:{},r=new m,n=Array.isArray(o.namespaces)?o.namespaces:[];return r.namespaces=n.map(t=>e.create(t)),r.nodeModulesRoot="string"==typeof o.nodeModulesRoot?o.nodeModulesRoot:void 0,Object.freeze(r.namespaces),Object.freeze(r)}}}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=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("::")},i=async function(o,s,a,l){const c=n(o);if(a.has(c)){const e=[...l,c].join(" -> ");throw new Error(`Cyclic dependency detected: ${e}`)}const p=n(o);if(!s.has(p)){a.add(c),l.push(c);try{const n=await t.resolve(o);r&&r.log(`GraphResolver.walk: resolved '${p}'.`),s.set(p,{depId:o,namespace:n});const c=Reflect.get(n,"__deps__");if(void 0===c)return;let f=c;if(null!==c&&"object"==typeof c&&!Array.isArray(c)){const e=null===o.exportName?"default":o.exportName,t=Reflect.get(c,e);null==t||"object"!=typeof t||Array.isArray(t)||(f=t)}for(const[,t]of Object.entries(f)){const o=t,n=e.parse(o);r&&r.log(`GraphResolver.walk: edge '${p}' -> '${n.platform}::${n.moduleName}'.`),await i(n,s,a,l)}}finally{l.pop(),a.delete(c)}}};this.resolve=async function(e){const t=new Map,o=new Set;return await i(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(t instanceof Promise)throw new Error("Factory composition must return synchronously (non-Promise).");return t}throw new Error(`Unsupported composition mode: ${String(t.composition)}.`)}}}class y{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 ${constructor(){const e=function(e){return"function"==typeof e};this.execute=function(t,o,r){let n=o;const i=t.wrappers;for(const t of i){if(!(t in r))throw new Error(`Wrapper '${t}' is not found in module namespace.`);const o=r[t];if(!e(o))throw new Error(`Wrapper '${t}' must be callable.`);if(n=o(n),n instanceof Promise)throw new Error(`Wrapper '${t}' must return synchronously (non-Promise).`)}return n}}}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 x=Object.freeze({log(){},error(){}});class E{constructor(){let e="notConfigured";const t=[],o=[],r=[],n=new Map,i=new WeakMap;let s=!1,a=!1,l=new p;const c=new d;let f,u,m,E=x;const C=new h,b=new $,v=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("::")},A=function(e){return v(e)},_=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;if("[object Module]"===Object.prototype.toString.call(e))return e;if(Object.isFrozen(e))return e;try{Object.freeze(e)}catch(e){E.log(`Container.freeze: skipped (${String(e)}).`)}return e},j=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;const o=e;if(i.has(o))return i.get(o);try{return Reflect.get(o,"then"),e}catch{const e=new Proxy(o,{get(e,t,o){if("then"!==t)return Reflect.get(e,t,o)}});return i.set(o,e),e}},I=function(){if("notConfigured"!==e)throw new Error("Container configuration is locked.")},R=function(e){a&&E.log(`Container.builder: ${e}`)};this.addPreprocess=function(e){I(),R("addPreprocess()."),t.push(e)},this.addPostprocess=function(e){I(),R("addPostprocess()."),o.push(e)},this.setParser=function(e){I(),l=e,"function"==typeof l.setLogger&&l.setLogger(a?E:null),R("setParser().")},this.addNamespaceRoot=function(e,t,o){I(),R(`addNamespaceRoot('${e}').`),r.push({prefix:e,target:t,defaultExt:o})},this.enableTestMode=function(){I(),R("enableTestMode()."),s=!0},this.enableLogging=function(){I(),a||(a=!0,E=new N,"function"==typeof l.setLogger&&l.setLogger(E),E.log("Container.builder: enableLogging()."))},this.register=function(e,t){if(I(),R(`register('${e}').`),!0!==s)throw new Error("Container test mode is disabled.");const o=l.parse(e);n.set(A(o),t)},this.get=async function(i){if("failed"===e)throw E.error(`Container.get: rejected in failed state cdc='${i}'.`),new Error("Container is in failed state.");let a="start";try{E.log(`Container.get: cdc='${i}'.`),function(){if("notConfigured"!==e)return;E.log("Container.transition: notConfigured -> operational."),e="operational";const t=c.create({namespaces:r});"function"==typeof l.setLogger&&l.setLogger(E),f=new g({config:t,logger:E}),u=new w({parser:l,resolver:f,logger:E}),m=new y(E)}(),E.log(`Container.state: '${e}'.`),a="parse",E.log("Container.pipeline: parse:entry.");const p=l.parse(i);E.log(`Container.pipeline: parse:exit '${p.platform}::${p.moduleName}'.`),a="preprocess",E.log("Container.pipeline: preprocess:entry.");const d=function(e){let o=e;for(const e of t)o=e(o);return o}(p);if(E.log(`Container.pipeline: preprocess:exit '${d.platform}::${d.moduleName}'.`),!0===s){a="mock",E.log("Container.pipeline: mock-lookup:entry.");const e=A(d);if(n.has(e)){E.log(`Container.pipeline: mock-lookup:hit '${e}'.`),a="freeze",E.log("Container.pipeline: freeze:entry.");const t=_(n.get(e));return E.log("Container.pipeline: freeze:exit."),E.log("Container.pipeline: return:success."),j(t)}E.log(`Container.pipeline: mock-lookup:miss '${e}'.`)}else E.log("Container.pipeline: mock-lookup:disabled.");a="resolve",E.log("Container.pipeline: resolve:entry.");const h=await u.resolve(d);E.log(`Container.pipeline: resolve:exit nodes=${h.size}.`);const $=new Map,N=function(e){if($.has(e))return $.get(e);if(!h.has(e))throw new Error(`Resolved graph node is missing for '${e}'.`);const t=h.get(e);a="lifecycle",E.log(`Container.pipeline: lifecycle:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const r=m.apply(t.depId,function(){a="instantiate",E.log(`Container.pipeline: instantiate:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const e={},r=function(e,t){const o=Reflect.get(e,"__deps__");if(void 0===o)return{};if(null!==o&&"object"==typeof o&&!Array.isArray(o)){const e=null===t.exportName?"default":t.exportName,r=Reflect.get(o,e);if(null!=r&&"object"==typeof r&&!Array.isArray(r))return r}return o}(t.namespace,t.depId);for(const[t,o]of Object.entries(r)){const r=o,n=l.parse(r);e[t]=N(v(n))}const n=C.instantiate(t.depId,t.namespace,e);E.log(`Container.pipeline: instantiate:exit '${t.depId.platform}::${t.depId.moduleName}'.`),a="postprocess",E.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);E.log(`Container.pipeline: postprocess:exit '${t.depId.platform}::${t.depId.moduleName}'.`);const s=b.execute(t.depId,i,t.namespace);a="freeze",E.log(`Container.pipeline: freeze:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const c=_(s);return E.log(`Container.pipeline: freeze:exit '${t.depId.platform}::${t.depId.moduleName}'.`),c});return E.log(`Container.pipeline: lifecycle:exit '${t.depId.platform}::${t.depId.moduleName}'.`),$.set(e,r),r},x=N(v(d));return E.log("Container.pipeline: return:success."),j(x)}catch(t){throw E.error(`Container.pipeline: failed at stage='${a}'.`,t),E.log("Container.transition: operational -> failed."),e="failed",t}}}}export{E 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=Object.freeze({AS_IS:"A",FACTORY:"F"});var t=Object.freeze({SINGLETON:"S",TRANSIENT:"T"});var o=Object.freeze({TEQ:"teq",NODE:"node",NPM:"npm"});const 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){const t=e&&"object"==typeof e?e:{},o=new l;o.moduleName="string"==typeof t.moduleName?t.moduleName:"";const c="string"==typeof t.platform?t.platform:void 0;o.platform=c&&i.has(c)?c:r;let p=null;null===t.exportName?p=null:"string"==typeof t.exportName&&(p=t.exportName),o.exportName=p;const f="string"==typeof t.composition?t.composition:void 0;o.composition=f&&s.has(f)?f:n;const u="string"==typeof t.life?t.life:void 0;return o.life=u&&a.has(u)?u:null,o.wrappers=Array.isArray(t.wrappers)?t.wrappers.filter(e=>"string"==typeof e):[],o.origin="string"==typeof t.origin?t.origin:"",Object.freeze(o.wrappers),Object.freeze(o)}};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(!/^[\x00-\x7F]+$/.test(i))throw new Error("CDC must be ASCII.");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.");let c=null,p=!1,f=[],u=a;const d=u.match(/(\${1,3})(?:_[a-z][0-9A-Za-z]*)*$/);if(d){const e=d[1],o=d[0].slice(e.length);if(p=!0,"$"===e)c=t.SINGLETON;else if("$$"===e)c=t.TRANSIENT;else{if("$$$"!==e)throw new Error("Lifecycle marker is invalid.");c=null}u=u.slice(0,d.index),o.length>0&&(f=o.slice(1).split("_"))}else{if(a.includes("$"))throw new Error("Invalid lifecycle encoding.");if(/(?:^|[^_])_[a-z][0-9A-Za-z]*$/.test(a))throw new Error("Wrapper without lifecycle is forbidden.")}const m=u.indexOf("__"),g=u.lastIndexOf("__");if(-1!==m&&m!==g)throw new Error("Export delimiter must appear at most once.");if(u.startsWith("__")||u.endsWith("__"))throw new Error("Malformed export segment.");let h=u,w=null;if(-1!==m){if(h=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(!h)throw new Error("moduleName must be non-empty.");if(h.startsWith("_")||h.startsWith("$"))throw new Error("moduleName must not start with _ or $.");if(h.includes("__"))throw new Error("moduleName must not contain __.");if(h.includes("$"))throw new Error("moduleName must not contain $.");if(l!==o.NPM){if(l===o.NODE){if(!/^[A-Za-z_][$0-9A-Za-z_/-]*$/.test(h))throw new Error("node moduleName must satisfy the built-in specifier form.")}else if(!/^[A-Za-z_][$0-9A-Za-z_]*$/.test(h))throw new Error("moduleName must satisfy the canonical identifier form.")}else if(!/^[@A-Za-z_][$0-9A-Za-z_./-]*$/.test(h))throw new Error("npm moduleName must satisfy the package specifier form.");let $=e.AS_IS;null!==w?$=e.FACTORY:p&&($=e.FACTORY,w="default");const y=r.create({moduleName:h,platform:l,exportName:w,composition:$,life:c,wrappers:f,origin:s});return n&&n.log(`Parser.parse: produced='${y.platform}::${y.moduleName}'.`),y},this.setLogger=function(e){n=e}}}let f=class{prefix;target;defaultExt},u=class{create(e){const t=e&&"object"==typeof e?e:{},o=new f;return o.prefix="string"==typeof t.prefix?t.prefix:void 0,o.target="string"==typeof t.target?t.target:void 0,o.defaultExt="string"==typeof t.defaultExt?t.defaultExt:void 0,Object.freeze(o)}};class d{namespaces;nodeModulesRoot}class m{constructor(){const e=new u;this.create=function(t){const o=t&&"object"==typeof t?t:{},r=new d,n=Array.isArray(o.namespaces)?o.namespaces:[];return r.namespaces=n.map(t=>e.create(t)),r.nodeModulesRoot="string"==typeof o.nodeModulesRoot?o.nodeModulesRoot:void 0,Object.freeze(r.namespaces),Object.freeze(r)}}}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 h{constructor({parser:e,resolver:t,logger:o=null}){const r=o,n=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("::")},i=async function(o,s,a,l){const c=n(o);if(a.has(c)){const e=[...l,c].join(" -> ");throw new Error(`Cyclic dependency detected: ${e}`)}const p=n(o);if(!s.has(p)){a.add(c),l.push(c);try{const n=await t.resolve(o);r&&r.log(`GraphResolver.walk: resolved '${p}'.`),s.set(p,{depId:o,namespace:n});const c=Reflect.get(n,"__deps__");if(void 0===c)return;const f=c;for(const[,t]of Object.entries(f)){const o=t,n=e.parse(o);r&&r.log(`GraphResolver.walk: edge '${p}' -> '${n.platform}::${n.moduleName}'.`),await i(n,s,a,l)}}finally{l.pop(),a.delete(c)}}};this.resolve=async function(e){const t=new Map,o=new Set;return await i(e,t,o,[]),t}}}class w{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(t instanceof Promise)throw new Error("Factory composition must return synchronously (non-Promise).");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){return"function"==typeof e};this.execute=function(t,o,r){let n=o;const i=t.wrappers;for(const t of i){if(!(t in r))throw new Error(`Wrapper '${t}' is not found in module namespace.`);const o=r[t];if(!e(o))throw new Error(`Wrapper '${t}' must be callable.`);if(n=o(n),n instanceof Promise)throw new Error(`Wrapper '${t}' must return synchronously (non-Promise).`)}return n}}}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 x=Object.freeze({log(){},error(){}});return class{constructor(){let e="notConfigured";const t=[],o=[],r=[],n=new Map,i=new WeakMap;let s=!1,a=!1,l=new p;const c=new m;let f,u,d,E=x;const C=new w,b=new y,v=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("::")},_=function(e){return v(e)},I=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;if("[object Module]"===Object.prototype.toString.call(e))return e;if(Object.isFrozen(e))return e;try{Object.freeze(e)}catch(e){E.log(`Container.freeze: skipped (${String(e)}).`)}return e},j=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;const o=e;if(i.has(o))return i.get(o);try{return Reflect.get(o,"then"),e}catch{const e=new Proxy(o,{get(e,t,o){if("then"!==t)return Reflect.get(e,t,o)}});return i.set(o,e),e}},A=function(){if("notConfigured"!==e)throw new Error("Container configuration is locked.")},R=function(e){a&&E.log(`Container.builder: ${e}`)};this.addPreprocess=function(e){A(),R("addPreprocess()."),t.push(e)},this.addPostprocess=function(e){A(),R("addPostprocess()."),o.push(e)},this.setParser=function(e){A(),l=e,"function"==typeof l.setLogger&&l.setLogger(a?E:null),R("setParser().")},this.addNamespaceRoot=function(e,t,o){A(),R(`addNamespaceRoot('${e}').`),r.push({prefix:e,target:t,defaultExt:o})},this.enableTestMode=function(){A(),R("enableTestMode()."),s=!0},this.enableLogging=function(){A(),a||(a=!0,E=new N,"function"==typeof l.setLogger&&l.setLogger(E),E.log("Container.builder: enableLogging()."))},this.register=function(e,t){if(A(),R(`register('${e}').`),!0!==s)throw new Error("Container test mode is disabled.");const o=l.parse(e);n.set(_(o),t)},this.get=async function(i){if("failed"===e)throw E.error(`Container.get: rejected in failed state cdc='${i}'.`),new Error("Container is in failed state.");let a="start";try{E.log(`Container.get: cdc='${i}'.`),function(){if("notConfigured"!==e)return;E.log("Container.transition: notConfigured -> operational."),e="operational";const t=c.create({namespaces:r});"function"==typeof l.setLogger&&l.setLogger(E),f=new g({config:t,logger:E}),u=new h({parser:l,resolver:f,logger:E}),d=new $(E)}(),E.log(`Container.state: '${e}'.`),a="parse",E.log("Container.pipeline: parse:entry.");const p=l.parse(i);E.log(`Container.pipeline: parse:exit '${p.platform}::${p.moduleName}'.`),a="preprocess",E.log("Container.pipeline: preprocess:entry.");const m=function(e){let o=e;for(const e of t)o=e(o);return o}(p);if(E.log(`Container.pipeline: preprocess:exit '${m.platform}::${m.moduleName}'.`),!0===s){a="mock",E.log("Container.pipeline: mock-lookup:entry.");const e=_(m);if(n.has(e)){E.log(`Container.pipeline: mock-lookup:hit '${e}'.`),a="freeze",E.log("Container.pipeline: freeze:entry.");const t=I(n.get(e));return E.log("Container.pipeline: freeze:exit."),E.log("Container.pipeline: return:success."),j(t)}E.log(`Container.pipeline: mock-lookup:miss '${e}'.`)}else E.log("Container.pipeline: mock-lookup:disabled.");a="resolve",E.log("Container.pipeline: resolve:entry.");const w=await u.resolve(m);E.log(`Container.pipeline: resolve:exit nodes=${w.size}.`);const y=new Map,N=function(e){if(y.has(e))return y.get(e);if(!w.has(e))throw new Error(`Resolved graph node is missing for '${e}'.`);const t=w.get(e);a="lifecycle",E.log(`Container.pipeline: lifecycle:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const r=d.apply(t.depId,function(){a="instantiate",E.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=l.parse(r);e[t]=N(v(n))}const n=C.instantiate(t.depId,t.namespace,e);E.log(`Container.pipeline: instantiate:exit '${t.depId.platform}::${t.depId.moduleName}'.`),a="postprocess",E.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);E.log(`Container.pipeline: postprocess:exit '${t.depId.platform}::${t.depId.moduleName}'.`);const s=b.execute(t.depId,i,t.namespace);a="freeze",E.log(`Container.pipeline: freeze:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const c=I(s);return E.log(`Container.pipeline: freeze:exit '${t.depId.platform}::${t.depId.moduleName}'.`),c});return E.log(`Container.pipeline: lifecycle:exit '${t.depId.platform}::${t.depId.moduleName}'.`),y.set(e,r),r},x=N(v(m));return E.log("Container.pipeline: return:success."),j(x)}catch(t){throw E.error(`Container.pipeline: failed at stage='${a}'.`,t),E.log("Container.transition: operational -> failed."),e="failed",t}}}}});
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=Object.freeze({AS_IS:"A",FACTORY:"F"});var t=Object.freeze({SINGLETON:"S",TRANSIENT:"T"});var o=Object.freeze({TEQ:"teq",NODE:"node",NPM:"npm"});const 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){const t=e&&"object"==typeof e?e:{},o=new l;o.moduleName="string"==typeof t.moduleName?t.moduleName:"";const c="string"==typeof t.platform?t.platform:void 0;o.platform=c&&i.has(c)?c:r;let p=null;null===t.exportName?p=null:"string"==typeof t.exportName&&(p=t.exportName),o.exportName=p;const f="string"==typeof t.composition?t.composition:void 0;o.composition=f&&s.has(f)?f:n;const u="string"==typeof t.life?t.life:void 0;return o.life=u&&a.has(u)?u:null,o.wrappers=Array.isArray(t.wrappers)?t.wrappers.filter(e=>"string"==typeof e):[],o.origin="string"==typeof t.origin?t.origin:"",Object.freeze(o.wrappers),Object.freeze(o)}};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(!/^[\x00-\x7F]+$/.test(i))throw new Error("CDC must be ASCII.");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.");let c=null,p=!1,f=[],u=a;const d=u.match(/(\${1,3})(?:_[a-z][0-9A-Za-z]*)*$/);if(d){const e=d[1],o=d[0].slice(e.length);if(p=!0,"$"===e)c=t.SINGLETON;else if("$$"===e)c=t.TRANSIENT;else{if("$$$"!==e)throw new Error("Lifecycle marker is invalid.");c=null}u=u.slice(0,d.index),o.length>0&&(f=o.slice(1).split("_"))}else{if(a.includes("$"))throw new Error("Invalid lifecycle encoding.");if(l!==o.NODE&&/(?:^|[^_])_[a-z][0-9A-Za-z]*$/.test(a))throw new Error("Wrapper without lifecycle is forbidden.")}const m=u.indexOf("__"),g=u.lastIndexOf("__");if(-1!==m&&m!==g)throw new Error("Export delimiter must appear at most once.");if(u.startsWith("__")||u.endsWith("__"))throw new Error("Malformed export segment.");let h=u,w=null;if(-1!==m){if(h=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(!h)throw new Error("moduleName must be non-empty.");if(h.startsWith("_")||h.startsWith("$"))throw new Error("moduleName must not start with _ or $.");if(h.includes("__"))throw new Error("moduleName must not contain __.");if(h.includes("$"))throw new Error("moduleName must not contain $.");if(l!==o.NPM){if(l===o.NODE){if(!/^[A-Za-z_][$0-9A-Za-z_/-]*$/.test(h))throw new Error("node moduleName must satisfy the built-in specifier form.")}else if(!/^[A-Za-z_][$0-9A-Za-z_]*$/.test(h))throw new Error("moduleName must satisfy the canonical identifier form.")}else if(!/^[@A-Za-z_][$0-9A-Za-z_./-]*$/.test(h))throw new Error("npm moduleName must satisfy the package specifier form.");let y=e.AS_IS;null!==w?y=e.FACTORY:p&&(y=e.FACTORY,w="default");const $=r.create({moduleName:h,platform:l,exportName:w,composition:y,life:c,wrappers:f,origin:s});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){const t=e&&"object"==typeof e?e:{},o=new f;return o.prefix="string"==typeof t.prefix?t.prefix:void 0,o.target="string"==typeof t.target?t.target:void 0,o.defaultExt="string"==typeof t.defaultExt?t.defaultExt:void 0,Object.freeze(o)}};class d{namespaces;nodeModulesRoot}class m{constructor(){const e=new u;this.create=function(t){const o=t&&"object"==typeof t?t:{},r=new d,n=Array.isArray(o.namespaces)?o.namespaces:[];return r.namespaces=n.map(t=>e.create(t)),r.nodeModulesRoot="string"==typeof o.nodeModulesRoot?o.nodeModulesRoot:void 0,Object.freeze(r.namespaces),Object.freeze(r)}}}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 h{constructor({parser:e,resolver:t,logger:o=null}){const r=o,n=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("::")},i=async function(o,s,a,l){const c=n(o);if(a.has(c)){const e=[...l,c].join(" -> ");throw new Error(`Cyclic dependency detected: ${e}`)}const p=n(o);if(!s.has(p)){a.add(c),l.push(c);try{const n=await t.resolve(o);r&&r.log(`GraphResolver.walk: resolved '${p}'.`),s.set(p,{depId:o,namespace:n});const c=Reflect.get(n,"__deps__");if(void 0===c)return;let f=c;if(null!==c&&"object"==typeof c&&!Array.isArray(c)){const e=null===o.exportName?"default":o.exportName,t=Reflect.get(c,e);null==t||"object"!=typeof t||Array.isArray(t)||(f=t)}for(const[,t]of Object.entries(f)){const o=t,n=e.parse(o);r&&r.log(`GraphResolver.walk: edge '${p}' -> '${n.platform}::${n.moduleName}'.`),await i(n,s,a,l)}}finally{l.pop(),a.delete(c)}}};this.resolve=async function(e){const t=new Map,o=new Set;return await i(e,t,o,[]),t}}}class w{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(t instanceof Promise)throw new Error("Factory composition must return synchronously (non-Promise).");return t}throw new Error(`Unsupported composition mode: ${String(t.composition)}.`)}}}class y{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 ${constructor(){const e=function(e){return"function"==typeof e};this.execute=function(t,o,r){let n=o;const i=t.wrappers;for(const t of i){if(!(t in r))throw new Error(`Wrapper '${t}' is not found in module namespace.`);const o=r[t];if(!e(o))throw new Error(`Wrapper '${t}' must be callable.`);if(n=o(n),n instanceof Promise)throw new Error(`Wrapper '${t}' must return synchronously (non-Promise).`)}return n}}}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 x=Object.freeze({log(){},error(){}});return class{constructor(){let e="notConfigured";const t=[],o=[],r=[],n=new Map,i=new WeakMap;let s=!1,a=!1,l=new p;const c=new m;let f,u,d,E=x;const C=new w,b=new $,v=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("::")},_=function(e){return v(e)},A=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;if("[object Module]"===Object.prototype.toString.call(e))return e;if(Object.isFrozen(e))return e;try{Object.freeze(e)}catch(e){E.log(`Container.freeze: skipped (${String(e)}).`)}return e},j=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;const o=e;if(i.has(o))return i.get(o);try{return Reflect.get(o,"then"),e}catch{const e=new Proxy(o,{get(e,t,o){if("then"!==t)return Reflect.get(e,t,o)}});return i.set(o,e),e}},I=function(){if("notConfigured"!==e)throw new Error("Container configuration is locked.")},R=function(e){a&&E.log(`Container.builder: ${e}`)};this.addPreprocess=function(e){I(),R("addPreprocess()."),t.push(e)},this.addPostprocess=function(e){I(),R("addPostprocess()."),o.push(e)},this.setParser=function(e){I(),l=e,"function"==typeof l.setLogger&&l.setLogger(a?E:null),R("setParser().")},this.addNamespaceRoot=function(e,t,o){I(),R(`addNamespaceRoot('${e}').`),r.push({prefix:e,target:t,defaultExt:o})},this.enableTestMode=function(){I(),R("enableTestMode()."),s=!0},this.enableLogging=function(){I(),a||(a=!0,E=new N,"function"==typeof l.setLogger&&l.setLogger(E),E.log("Container.builder: enableLogging()."))},this.register=function(e,t){if(I(),R(`register('${e}').`),!0!==s)throw new Error("Container test mode is disabled.");const o=l.parse(e);n.set(_(o),t)},this.get=async function(i){if("failed"===e)throw E.error(`Container.get: rejected in failed state cdc='${i}'.`),new Error("Container is in failed state.");let a="start";try{E.log(`Container.get: cdc='${i}'.`),function(){if("notConfigured"!==e)return;E.log("Container.transition: notConfigured -> operational."),e="operational";const t=c.create({namespaces:r});"function"==typeof l.setLogger&&l.setLogger(E),f=new g({config:t,logger:E}),u=new h({parser:l,resolver:f,logger:E}),d=new y(E)}(),E.log(`Container.state: '${e}'.`),a="parse",E.log("Container.pipeline: parse:entry.");const p=l.parse(i);E.log(`Container.pipeline: parse:exit '${p.platform}::${p.moduleName}'.`),a="preprocess",E.log("Container.pipeline: preprocess:entry.");const m=function(e){let o=e;for(const e of t)o=e(o);return o}(p);if(E.log(`Container.pipeline: preprocess:exit '${m.platform}::${m.moduleName}'.`),!0===s){a="mock",E.log("Container.pipeline: mock-lookup:entry.");const e=_(m);if(n.has(e)){E.log(`Container.pipeline: mock-lookup:hit '${e}'.`),a="freeze",E.log("Container.pipeline: freeze:entry.");const t=A(n.get(e));return E.log("Container.pipeline: freeze:exit."),E.log("Container.pipeline: return:success."),j(t)}E.log(`Container.pipeline: mock-lookup:miss '${e}'.`)}else E.log("Container.pipeline: mock-lookup:disabled.");a="resolve",E.log("Container.pipeline: resolve:entry.");const w=await u.resolve(m);E.log(`Container.pipeline: resolve:exit nodes=${w.size}.`);const $=new Map,N=function(e){if($.has(e))return $.get(e);if(!w.has(e))throw new Error(`Resolved graph node is missing for '${e}'.`);const t=w.get(e);a="lifecycle",E.log(`Container.pipeline: lifecycle:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const r=d.apply(t.depId,function(){a="instantiate",E.log(`Container.pipeline: instantiate:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const e={},r=function(e,t){const o=Reflect.get(e,"__deps__");if(void 0===o)return{};if(null!==o&&"object"==typeof o&&!Array.isArray(o)){const e=null===t.exportName?"default":t.exportName,r=Reflect.get(o,e);if(null!=r&&"object"==typeof r&&!Array.isArray(r))return r}return o}(t.namespace,t.depId);for(const[t,o]of Object.entries(r)){const r=o,n=l.parse(r);e[t]=N(v(n))}const n=C.instantiate(t.depId,t.namespace,e);E.log(`Container.pipeline: instantiate:exit '${t.depId.platform}::${t.depId.moduleName}'.`),a="postprocess",E.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);E.log(`Container.pipeline: postprocess:exit '${t.depId.platform}::${t.depId.moduleName}'.`);const s=b.execute(t.depId,i,t.namespace);a="freeze",E.log(`Container.pipeline: freeze:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const c=A(s);return E.log(`Container.pipeline: freeze:exit '${t.depId.platform}::${t.depId.moduleName}'.`),c});return E.log(`Container.pipeline: lifecycle:exit '${t.depId.platform}::${t.depId.moduleName}'.`),$.set(e,r),r},x=N(v(m));return E.log("Container.pipeline: return:success."),j(x)}catch(t){throw E.error(`Container.pipeline: failed at stage='${a}'.`,t),E.log("Container.transition: operational -> failed."),e="failed",t}}}}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teqfw/di",
3
- "version": "2.3.1",
3
+ "version": "2.5.0",
4
4
  "description": "Dependency Injection container for ES6 modules that works in both browser and Node.js apps.",
5
5
  "keywords": [
6
6
  "dependency injection",
@@ -45,22 +45,28 @@
45
45
  "./src/Config/NamespaceRegistry.mjs": "./src/Config/NamespaceRegistry.mjs"
46
46
  },
47
47
  "type": "module",
48
+ "teqfw": {
49
+ "namespaces": [
50
+ {
51
+ "prefix": "TeqFw_Di_",
52
+ "path": "./src",
53
+ "ext": ".mjs"
54
+ }
55
+ ]
56
+ },
48
57
  "repository": {
49
58
  "type": "git",
50
59
  "url": "git+https://github.com/teqfw/di.git"
51
60
  },
52
61
  "scripts": {
53
62
  "rollup": "rollup -c",
54
- "eslint": "npx eslint './src/**/*.mjs'",
55
63
  "test": "npm run test:unit && npm run test:integration",
56
64
  "test:unit": "find test/unit -name '*.test.mjs' -print0 | xargs -0 node --test",
57
65
  "test:integration": "find test/integration -name '*.test.mjs' -print0 | xargs -0 node --test"
58
66
  },
59
67
  "devDependencies": {
60
- "@eslint/js": "^10.0.1",
61
68
  "@rollup/plugin-node-resolve": "^16.0.3",
62
69
  "@rollup/plugin-terser": "^1.0.0",
63
- "eslint": "^10.0.2",
64
70
  "rollup": "^4.59.0"
65
71
  },
66
72
  "engines": {
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Config_NamespaceRegistry
5
+ * @description Deterministic loader for package namespace rules.
6
+ */
7
+
3
8
  /**
4
9
  * @typedef {object} TeqFw_Di_Config_NamespaceRegistry_Dependencies
5
10
  * @property {{readFile(path: string, encoding: string): Promise<string>, readdir(path: string): Promise<string[]>, realpath(path: string): Promise<string>, stat(path: string): Promise<{isDirectory(): boolean}>}} fs
@@ -19,7 +24,7 @@
19
24
  */
20
25
  export default class TeqFw_Di_Config_NamespaceRegistry {
21
26
  /**
22
- * @param {TeqFw_Di_Config_NamespaceRegistry_Dependencies} dependencies
27
+ * @param {TeqFw_Di_Config_NamespaceRegistry_Dependencies} deps
23
28
  */
24
29
  constructor({fs, path, appRoot}) {
25
30
  const appRootAbs = path.resolve(appRoot);
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Container_Instantiate_ExportSelector
5
+ * @description Selects target export from loaded module namespace.
6
+ */
7
+
3
8
  /**
4
9
  * Instantiate-stage export selector.
5
10
  *
@@ -15,7 +20,7 @@ export default class TeqFw_Di_Container_Instantiate_ExportSelector {
15
20
  * Selects a raw export value from module namespace.
16
21
  *
17
22
  * @param {object} namespace Loaded ES module namespace object.
18
- * @param {TeqFw_Di_DepId$DTO} depId Dependency identity DTO.
23
+ * @param {TeqFw_Di_DepId__DTO} depId Dependency identity DTO.
19
24
  * @returns {unknown} Raw selected export value.
20
25
  */
21
26
  this.select = function (namespace, depId) {
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Container_Instantiate_Instantiator
5
+ * @description Instantiates selected exports using composition rules.
6
+ */
7
+
3
8
  import TeqFw_Di_Enum_Composition from '../../Enum/Composition.mjs';
4
9
 
5
10
  /**
@@ -30,7 +35,7 @@ export default class TeqFw_Di_Container_Instantiate_Instantiator {
30
35
  /**
31
36
  * Selects the value used by composition.
32
37
  *
33
- * @param {TeqFw_Di_DepId$DTO} depId
38
+ * @param {TeqFw_Di_DepId__DTO} depId
34
39
  * @param {object} moduleNamespace
35
40
  * @returns {Factory}
36
41
  */
@@ -66,7 +71,7 @@ export default class TeqFw_Di_Container_Instantiate_Instantiator {
66
71
  /**
67
72
  * Produces a value from a resolved module namespace and dependency map.
68
73
  *
69
- * @param {TeqFw_Di_DepId$DTO} depId
74
+ * @param {TeqFw_Di_DepId__DTO} depId
70
75
  * @param {object} moduleNamespace
71
76
  * @param {Record<string, unknown>} resolvedDeps
72
77
  * @returns {unknown}
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Container_Lifecycle_Registry
5
+ * @description Lifecycle policy cache for produced values.
6
+ */
7
+
3
8
  import TeqFw_Di_Enum_Composition from '../../Enum/Composition.mjs';
4
9
  import TeqFw_Di_Enum_Life from '../../Enum/Life.mjs';
5
10
 
@@ -25,7 +30,7 @@ export default class TeqFw_Di_Container_Lifecycle_Registry {
25
30
  /**
26
31
  * Builds deterministic cache key from structural DepId fields.
27
32
  *
28
- * @param {TeqFw_Di_DepId$DTO} depId
33
+ * @param {TeqFw_Di_DepId__DTO} depId
29
34
  * @returns {string}
30
35
  */
31
36
  const buildKey = function (depId) {
@@ -44,7 +49,7 @@ export default class TeqFw_Di_Container_Lifecycle_Registry {
44
49
  /**
45
50
  * Returns value according to lifecycle policy.
46
51
  *
47
- * @param {TeqFw_Di_DepId$DTO} depId
52
+ * @param {TeqFw_Di_DepId__DTO} depId
48
53
  * @param {() => unknown} producer
49
54
  * @returns {unknown}
50
55
  */
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Container_Resolve_GraphResolver
5
+ * @description Dependency graph resolver for container preloading.
6
+ */
7
+
3
8
  /**
4
9
  * Resolve-stage graph builder.
5
10
  *
@@ -15,7 +20,7 @@
15
20
  */
16
21
 
17
22
  /**
18
- * @typedef {{depId: TeqFw_Di_DepId$DTO, namespace: object}} TeqFw_Di_Container_Resolve_GraphResolver_Node
23
+ * @typedef {{depId: TeqFw_Di_DepId__DTO, namespace: object}} TeqFw_Di_Container_Resolve_GraphResolver_Node
19
24
  */
20
25
 
21
26
  export default class TeqFw_Di_Container_Resolve_GraphResolver {
@@ -28,7 +33,7 @@ export default class TeqFw_Di_Container_Resolve_GraphResolver {
28
33
  const log = logger;
29
34
 
30
35
  /**
31
- * @param {TeqFw_Di_DepId$DTO} depId
36
+ * @param {TeqFw_Di_DepId__DTO} depId
32
37
  * @returns {string}
33
38
  */
34
39
  const makeNodeKey = function (depId) {
@@ -45,7 +50,7 @@ export default class TeqFw_Di_Container_Resolve_GraphResolver {
45
50
  };
46
51
 
47
52
  /**
48
- * @param {TeqFw_Di_DepId$DTO} depId
53
+ * @param {TeqFw_Di_DepId__DTO} depId
49
54
  * @param {Map<string, TeqFw_Di_Container_Resolve_GraphResolver_Node>} out
50
55
  * @param {Set<string>} stack
51
56
  * @param {string[]} chain
@@ -76,11 +81,18 @@ export default class TeqFw_Di_Container_Resolve_GraphResolver {
76
81
  const depsDecl = Reflect.get(namespace, '__deps__');
77
82
  if (depsDecl === undefined) return;
78
83
  /** @type {Record<string, unknown>} */
79
- const depsMap = /** @type {Record<string, unknown>} */ (depsDecl);
84
+ let depsMap = /** @type {Record<string, unknown>} */ (depsDecl);
85
+ if ((depsDecl !== null) && (typeof depsDecl === 'object') && !Array.isArray(depsDecl)) {
86
+ const exportName = depId.exportName === null ? 'default' : depId.exportName;
87
+ const exportScoped = Reflect.get(/** @type {object} */ (depsDecl), exportName);
88
+ if ((exportScoped !== undefined) && (exportScoped !== null) && (typeof exportScoped === 'object') && !Array.isArray(exportScoped)) {
89
+ depsMap = /** @type {Record<string, unknown>} */ (exportScoped);
90
+ }
91
+ }
80
92
  for (const [, cdc] of Object.entries(depsMap)) {
81
93
  /** @type {string} */
82
94
  const nextCdc = /** @type {string} */ (cdc);
83
- /** @type {TeqFw_Di_DepId$DTO} */
95
+ /** @type {TeqFw_Di_DepId__DTO} */
84
96
  const nextDepId = parser.parse(nextCdc);
85
97
  if (log) log.log(`GraphResolver.walk: edge '${key}' -> '${nextDepId.platform}::${nextDepId.moduleName}'.`);
86
98
  await walk(nextDepId, out, stack, chain);
@@ -94,7 +106,7 @@ export default class TeqFw_Di_Container_Resolve_GraphResolver {
94
106
  /**
95
107
  * Resolves full dependency graph for a root depId.
96
108
  *
97
- * @param {TeqFw_Di_DepId$DTO} depId
109
+ * @param {TeqFw_Di_DepId__DTO} depId
98
110
  * @returns {Promise<Map<string, TeqFw_Di_Container_Resolve_GraphResolver_Node>>}
99
111
  */
100
112
  this.resolve = async function (depId) {
@@ -1,8 +1,13 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Resolver
5
+ * @description Module resolver for namespace-addressed dependencies.
6
+ */
7
+
3
8
  /**
4
9
  * @typedef {object} TeqFw_Di_Resolver_Dependencies
5
- * @property {TeqFw_Di_Dto_Resolver_Config$DTO} config Resolver configuration DTO.
10
+ * @property {TeqFw_Di_Dto_Resolver_Config__DTO} config Resolver configuration DTO.
6
11
  * @property {(specifier: string) => Promise<object>} [importFn] Import function override.
7
12
  * @property {{log(message: string): void, error(message: string, error?: unknown): void}|null} [logger]
8
13
  */
@@ -19,12 +24,12 @@ export default class TeqFw_Di_Resolver {
19
24
  /**
20
25
  * Initializes resolver with runtime dependencies.
21
26
  *
22
- * @param {TeqFw_Di_Resolver_Dependencies} param0 Resolver dependencies descriptor.
27
+ * @param {TeqFw_Di_Resolver_Dependencies} deps Resolver dependencies descriptor.
23
28
  */
24
29
  constructor({config, importFn = (specifier) => import(specifier), logger = null}) {
25
30
  /** @type {Map<string, Promise<object>>} Cache keyed by `(platform,moduleName)`. */
26
31
  const cache = new Map();
27
- /** @type {TeqFw_Di_Dto_Resolver_Config$DTO} Original config reference captured from dependencies. */
32
+ /** @type {TeqFw_Di_Dto_Resolver_Config__DTO} Original config reference captured from dependencies. */
28
33
  const configInput = config;
29
34
  /** @type {{nodeModulesRoot: (string|undefined), namespaces: TeqFw_Di_Resolver_NamespaceRule[]}|undefined} */
30
35
  let configSnapshot;
@@ -36,7 +41,7 @@ export default class TeqFw_Di_Resolver {
36
41
  /**
37
42
  * Creates immutable-in-effect structural snapshot used for all post-start resolutions.
38
43
  *
39
- * @param {TeqFw_Di_Dto_Resolver_Config$DTO} input Resolver config DTO.
44
+ * @param {TeqFw_Di_Dto_Resolver_Config__DTO} input Resolver config DTO.
40
45
  * @returns {{nodeModulesRoot: (string|undefined), namespaces: TeqFw_Di_Resolver_NamespaceRule[]}}
41
46
  */
42
47
  const makeConfigSnapshot = function (input) {
@@ -134,7 +139,7 @@ export default class TeqFw_Di_Resolver {
134
139
  /**
135
140
  * Resolves module namespace object by depId platform and moduleName.
136
141
  *
137
- * @param {TeqFw_Di_DepId$DTO} depId Validated dependency identity DTO.
142
+ * @param {TeqFw_Di_DepId__DTO} depId Validated dependency identity DTO.
138
143
  * @returns {Promise<object>} Promise resolved with ES module namespace object.
139
144
  */
140
145
  this.resolve = async function (depId) {
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Container_Wrapper_Executor
5
+ * @description Applies wrapper pipeline to resolved values.
6
+ */
7
+
3
8
  /**
4
9
  * Wrapper-stage executor.
5
10
  *
@@ -25,7 +30,7 @@ export default class TeqFw_Di_Container_Wrapper_Executor {
25
30
  /**
26
31
  * Applies wrappers in declaration order.
27
32
  *
28
- * @param {TeqFw_Di_DepId$DTO} depId
33
+ * @param {TeqFw_Di_DepId__DTO} depId
29
34
  * @param {unknown} value
30
35
  * @param {object} moduleNamespace
31
36
  * @returns {unknown}
package/src/Container.mjs CHANGED
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Container
5
+ * @description DI container orchestration entry point.
6
+ */
7
+
3
8
  import TeqFw_Di_Def_Parser from './Def/Parser.mjs';
4
9
  import {Factory as TeqFw_Di_Dto_Resolver_Config_Factory} from './Dto/Resolver/Config.mjs';
5
10
  import TeqFw_Di_Resolver from './Container/Resolver.mjs';
@@ -30,11 +35,11 @@ export default class TeqFw_Di_Container {
30
35
  constructor() {
31
36
  /** @type {TeqFw_Di_Container_State} */
32
37
  let state = 'notConfigured';
33
- /** @type {((depId: TeqFw_Di_DepId$DTO) => TeqFw_Di_DepId$DTO)[]} */
38
+ /** @type {((depId: TeqFw_Di_DepId__DTO) => TeqFw_Di_DepId__DTO)[]} */
34
39
  const preprocess = [];
35
40
  /** @type {((value: unknown) => unknown)[]} */
36
41
  const postprocess = [];
37
- /** @type {TeqFw_Di_Dto_Resolver_Config_Namespace$DTO[]} */
42
+ /** @type {TeqFw_Di_Dto_Resolver_Config_Namespace__DTO[]} */
38
43
  const namespaceRoots = [];
39
44
  /** @type {Map<string, unknown>} */
40
45
  const mockRegistry = new Map();
@@ -45,7 +50,7 @@ export default class TeqFw_Di_Container {
45
50
 
46
51
  /** @type {TeqFw_Di_Def_Parser} */
47
52
  let parser = new TeqFw_Di_Def_Parser();
48
- /** @type {TeqFw_Di_Dto_Resolver_Config$Factory} */
53
+ /** @type {TeqFw_Di_Dto_Resolver_Config__Factory} */
49
54
  const configFactory = new TeqFw_Di_Dto_Resolver_Config_Factory();
50
55
  /** @type {TeqFw_Di_Resolver|undefined} */
51
56
  let resolver;
@@ -61,7 +66,7 @@ export default class TeqFw_Di_Container {
61
66
  const wrapperExecutor = new TeqFw_Di_Container_Wrapper_Executor();
62
67
 
63
68
  /**
64
- * @param {TeqFw_Di_DepId$DTO} depId
69
+ * @param {TeqFw_Di_DepId__DTO} depId
65
70
  * @returns {string}
66
71
  */
67
72
  const getKey = function (depId) {
@@ -81,7 +86,7 @@ export default class TeqFw_Di_Container {
81
86
  /**
82
87
  * Canonical structural identity excluding `origin`.
83
88
  *
84
- * @param {TeqFw_Di_DepId$DTO} depId
89
+ * @param {TeqFw_Di_DepId__DTO} depId
85
90
  * @returns {string}
86
91
  */
87
92
  const getMockKey = function (depId) {
@@ -138,11 +143,11 @@ export default class TeqFw_Di_Container {
138
143
  /**
139
144
  * Applies ordered preprocess pipeline.
140
145
  *
141
- * @param {TeqFw_Di_DepId$DTO} depId
142
- * @returns {TeqFw_Di_DepId$DTO}
146
+ * @param {TeqFw_Di_DepId__DTO} depId
147
+ * @returns {TeqFw_Di_DepId__DTO}
143
148
  */
144
149
  const applyPreprocess = function (depId) {
145
- /** @type {TeqFw_Di_DepId$DTO} */
150
+ /** @type {TeqFw_Di_DepId__DTO} */
146
151
  let current = depId;
147
152
  for (const fn of preprocess) {
148
153
  current = fn(current);
@@ -167,12 +172,20 @@ export default class TeqFw_Di_Container {
167
172
 
168
173
  /**
169
174
  * @param {object} namespace
175
+ * @param {TeqFw_Di_DepId__DTO} depId
170
176
  * @returns {Record<string, unknown>}
171
177
  */
172
- const readDepsDecl = function (namespace) {
178
+ const readDepsDecl = function (namespace, depId) {
173
179
  /** @type {unknown} */
174
180
  const deps = Reflect.get(namespace, '__deps__');
175
181
  if (deps === undefined) return {};
182
+ if ((deps !== null) && (typeof deps === 'object') && !Array.isArray(deps)) {
183
+ const exportName = depId.exportName === null ? 'default' : depId.exportName;
184
+ const exportScoped = Reflect.get(/** @type {object} */ (deps), exportName);
185
+ if ((exportScoped !== undefined) && (exportScoped !== null) && (typeof exportScoped === 'object') && !Array.isArray(exportScoped)) {
186
+ return /** @type {Record<string, unknown>} */ (exportScoped);
187
+ }
188
+ }
176
189
  return /** @type {Record<string, unknown>} */ (deps);
177
190
  };
178
191
 
@@ -215,7 +228,7 @@ export default class TeqFw_Di_Container {
215
228
  /**
216
229
  * Registers preprocess extension before first resolution.
217
230
  *
218
- * @param {(depId: TeqFw_Di_DepId$DTO) => TeqFw_Di_DepId$DTO} fn
231
+ * @param {(depId: TeqFw_Di_DepId__DTO) => TeqFw_Di_DepId__DTO} fn
219
232
  * @returns {void}
220
233
  */
221
234
  this.addPreprocess = function (fn) {
@@ -321,12 +334,12 @@ export default class TeqFw_Di_Container {
321
334
  logger.log(`Container.get: cdc='${cdc}'.`);
322
335
  initializeInfrastructure();
323
336
  logger.log(`Container.state: '${state}'.`);
324
- /** @type {TeqFw_Di_DepId$DTO} */
337
+ /** @type {TeqFw_Di_DepId__DTO} */
325
338
  stage = 'parse';
326
339
  logger.log('Container.pipeline: parse:entry.');
327
340
  const parsed = parser.parse(cdc);
328
341
  logger.log(`Container.pipeline: parse:exit '${parsed.platform}::${parsed.moduleName}'.`);
329
- /** @type {TeqFw_Di_DepId$DTO} */
342
+ /** @type {TeqFw_Di_DepId__DTO} */
330
343
  stage = 'preprocess';
331
344
  logger.log('Container.pipeline: preprocess:entry.');
332
345
  const root = applyPreprocess(parsed);
@@ -348,7 +361,7 @@ export default class TeqFw_Di_Container {
348
361
  } else {
349
362
  logger.log('Container.pipeline: mock-lookup:disabled.');
350
363
  }
351
- /** @type {Map<string, {depId: TeqFw_Di_DepId$DTO, namespace: object}>} */
364
+ /** @type {Map<string, {depId: TeqFw_Di_DepId__DTO, namespace: object}>} */
352
365
  stage = 'resolve';
353
366
  logger.log('Container.pipeline: resolve:entry.');
354
367
  const graph = await graphResolver.resolve(root);
@@ -373,11 +386,11 @@ export default class TeqFw_Di_Container {
373
386
  /** @type {Record<string, unknown>} */
374
387
  const deps = {};
375
388
  /** @type {Record<string, unknown>} */
376
- const depsDecl = readDepsDecl(node.namespace);
389
+ const depsDecl = readDepsDecl(node.namespace, node.depId);
377
390
  for (const [name, cdc] of Object.entries(depsDecl)) {
378
391
  /** @type {string} */
379
392
  const childCdc = /** @type {string} */ (cdc);
380
- /** @type {TeqFw_Di_DepId$DTO} */
393
+ /** @type {TeqFw_Di_DepId__DTO} */
381
394
  const childDepId = parser.parse(childCdc);
382
395
  deps[name] = build(getKey(childDepId));
383
396
  }
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Def_Parser
5
+ * @description CDC parser that builds dependency identity DTOs.
6
+ */
7
+
3
8
  import TeqFw_Di_Enum_Composition from '../Enum/Composition.mjs';
4
9
  import TeqFw_Di_Enum_Life from '../Enum/Life.mjs';
5
10
  import TeqFw_Di_Enum_Platform from '../Enum/Platform.mjs';
@@ -13,7 +18,7 @@ export default class TeqFw_Di_Def_Parser {
13
18
  * Creates parser instance.
14
19
  */
15
20
  constructor() {
16
- /** @type {TeqFw_Di_Dto_DepId$Factory} Factory used to construct dependency identity DTO. */
21
+ /** @type {TeqFw_Di_Dto_DepId__Factory} Factory used to construct dependency identity DTO. */
17
22
  const depIdFactory = new TeqFw_Di_Dto_DepId_Factory();
18
23
  /** @type {{log(message: string): void}|null} */
19
24
  let logger = null;
@@ -22,7 +27,7 @@ export default class TeqFw_Di_Def_Parser {
22
27
  * Parses one CDC identifier and returns normalized frozen dependency DTO.
23
28
  *
24
29
  * @param {string} cdc CDC identifier string.
25
- * @returns {TeqFw_Di_DepId$DTO}
30
+ * @returns {TeqFw_Di_DepId__DTO}
26
31
  */
27
32
  this.parse = function (cdc) {
28
33
  if (logger) logger.log(`Parser.parse: input='${cdc}'.`);
@@ -71,7 +76,7 @@ export default class TeqFw_Di_Def_Parser {
71
76
  }
72
77
  } else {
73
78
  if (source.includes('$')) throw new Error('Invalid lifecycle encoding.');
74
- if (/(?:^|[^_])_[a-z][0-9A-Za-z]*$/.test(source)) {
79
+ if ((platform !== TeqFw_Di_Enum_Platform.NODE) && /(?:^|[^_])_[a-z][0-9A-Za-z]*$/.test(source)) {
75
80
  throw new Error('Wrapper without lifecycle is forbidden.');
76
81
  }
77
82
  }
package/src/Dto/DepId.mjs CHANGED
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Dto_DepId
5
+ * @description Dependency identity DTO and factory.
6
+ */
7
+
3
8
  import TeqFw_Di_Enum_Composition from '../Enum/Composition.mjs';
4
9
  import TeqFw_Di_Enum_Life from '../Enum/Life.mjs';
5
10
  import TeqFw_Di_Enum_Platform from '../Enum/Platform.mjs';
@@ -54,7 +59,7 @@ export class Factory {
54
59
  * Creates normalized frozen dependency identity DTO.
55
60
  *
56
61
  * @param {unknown} [input]
57
- * @returns {TeqFw_Di_DepId$DTO}
62
+ * @returns {TeqFw_Di_DepId__DTO}
58
63
  */
59
64
  create(input) {
60
65
  /** @type {Record<string, unknown>} */
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Dto_Resolver_Config_Namespace
5
+ * @description Resolver namespace rule DTO and factory.
6
+ */
7
+
3
8
  /**
4
9
  * DTO for resolver namespace rule records and its factory.
5
10
  */
@@ -25,14 +30,14 @@ export class Factory {
25
30
  /**
26
31
  * Creates normalized frozen resolver namespace DTO.
27
32
  *
28
- * @param {Partial<TeqFw_Di_Dto_Resolver_Config_Namespace$DTO>|Record<string, unknown>} [input] Source values.
29
- * @returns {TeqFw_Di_Dto_Resolver_Config_Namespace$DTO}
33
+ * @param {Partial<TeqFw_Di_Dto_Resolver_Config_Namespace__DTO>|Record<string, unknown>} [input] Source values.
34
+ * @returns {TeqFw_Di_Dto_Resolver_Config_Namespace__DTO}
30
35
  */
31
36
  create(input) {
32
- /** @type {Partial<TeqFw_Di_Dto_Resolver_Config_Namespace$DTO>|Record<string, unknown>} */
37
+ /** @type {Partial<TeqFw_Di_Dto_Resolver_Config_Namespace__DTO>|Record<string, unknown>} */
33
38
  const source = (input && (typeof input === 'object')) ? input : {};
34
39
 
35
- /** @type {TeqFw_Di_Dto_Resolver_Config_Namespace$DTO} */
40
+ /** @type {TeqFw_Di_Dto_Resolver_Config_Namespace__DTO} */
36
41
  const dto = new DTO();
37
42
  dto.prefix = (typeof source.prefix === 'string') ? source.prefix : undefined;
38
43
  dto.target = (typeof source.target === 'string') ? source.target : undefined;
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Dto_Resolver_Config
5
+ * @description Resolver configuration DTO and factory.
6
+ */
7
+
3
8
  import {Factory as TeqFw_Di_Dto_Resolver_Config_Namespace_Factory} from './Config/Namespace.mjs';
4
9
 
5
10
  /**
@@ -10,7 +15,7 @@ import {Factory as TeqFw_Di_Dto_Resolver_Config_Namespace_Factory} from './Confi
10
15
  * Runtime DTO for resolver configuration.
11
16
  */
12
17
  export default class DTO {
13
- /** @type {TeqFw_Di_Dto_Resolver_Config_Namespace$DTO[]} Namespace resolution rules. */
18
+ /** @type {TeqFw_Di_Dto_Resolver_Config_Namespace__DTO[]} Namespace resolution rules. */
14
19
  namespaces;
15
20
 
16
21
  /** @type {string|undefined} Optional node_modules root prefix for npm modules. */
@@ -31,14 +36,14 @@ export class Factory {
31
36
  /**
32
37
  * Creates normalized frozen resolver configuration DTO.
33
38
  *
34
- * @param {Partial<TeqFw_Di_Dto_Resolver_Config$DTO>|Record<string, unknown>} [input] Source values.
35
- * @returns {TeqFw_Di_Dto_Resolver_Config$DTO}
39
+ * @param {Partial<TeqFw_Di_Dto_Resolver_Config__DTO>|Record<string, unknown>} [input] Source values.
40
+ * @returns {TeqFw_Di_Dto_Resolver_Config__DTO}
36
41
  */
37
42
  this.create = function (input) {
38
- /** @type {Partial<TeqFw_Di_Dto_Resolver_Config$DTO>|Record<string, unknown>} */
43
+ /** @type {Partial<TeqFw_Di_Dto_Resolver_Config__DTO>|Record<string, unknown>} */
39
44
  const source = (input && (typeof input === 'object')) ? input : {};
40
45
 
41
- /** @type {TeqFw_Di_Dto_Resolver_Config$DTO} */
46
+ /** @type {TeqFw_Di_Dto_Resolver_Config__DTO} */
42
47
  const dto = new DTO();
43
48
  /** @type {unknown[]} */
44
49
  const items = Array.isArray(source.namespaces) ? source.namespaces : [];
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Enum_Composition
5
+ * @description Composition mode enum constants.
6
+ */
7
+
3
8
  /**
4
9
  * Composition mode enum used in dependency identity DTO.
5
10
  */
package/src/Enum/Life.mjs CHANGED
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Enum_Life
5
+ * @description Lifecycle mode enum constants.
6
+ */
7
+
3
8
  /**
4
9
  * Lifecycle mode enum used in dependency identity DTO.
5
10
  */
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Enum_Platform
5
+ * @description Platform selector enum constants.
6
+ */
7
+
3
8
  /**
4
9
  * Platform enum used to resolve module loading strategy.
5
10
  */
@@ -1,5 +1,10 @@
1
1
  // @ts-check
2
2
 
3
+ /**
4
+ * @namespace TeqFw_Di_Internal_Logger
5
+ * @description Internal console logger for diagnostics.
6
+ */
7
+
3
8
  /**
4
9
  * Internal synchronous console logger.
5
10
  *
package/types.d.ts CHANGED
@@ -8,21 +8,22 @@ declare global {
8
8
  type TeqFw_Di_Container_Wrapper_Executor = import("./src/Container/Wrapper/Executor.mjs").default;
9
9
  type TeqFw_Di_Def_Parser = import("./src/Def/Parser.mjs").default;
10
10
  type TeqFw_Di_DepId = import("./src/Dto/DepId.mjs").default;
11
- type TeqFw_Di_DepId$DTO = import("./src/Dto/DepId.mjs").default;
11
+ type TeqFw_Di_DepId__DTO = import("./src/Dto/DepId.mjs").default;
12
12
  type TeqFw_Di_DepId$Factory = InstanceType<typeof import("./src/Dto/DepId.mjs").Factory>;
13
13
  type TeqFw_Di_Dto_DepId = import("./src/Dto/DepId.mjs").default;
14
14
  type TeqFw_Di_Dto_DepId$DTO = import("./src/Dto/DepId.mjs").default;
15
- type TeqFw_Di_Dto_DepId$Factory = InstanceType<typeof import("./src/Dto/DepId.mjs").Factory>;
15
+ type TeqFw_Di_Dto_DepId__Factory = InstanceType<typeof import("./src/Dto/DepId.mjs").Factory>;
16
16
  type TeqFw_Di_Dto_Resolver_Config = import("./src/Dto/Resolver/Config.mjs").default;
17
- type TeqFw_Di_Dto_Resolver_Config$DTO = import("./src/Dto/Resolver/Config.mjs").default;
18
- type TeqFw_Di_Dto_Resolver_Config$Factory = InstanceType<typeof import("./src/Dto/Resolver/Config.mjs").Factory>;
17
+ type TeqFw_Di_Dto_Resolver_Config__DTO = import("./src/Dto/Resolver/Config.mjs").default;
18
+ type TeqFw_Di_Dto_Resolver_Config__Factory = InstanceType<typeof import("./src/Dto/Resolver/Config.mjs").Factory>;
19
19
  type TeqFw_Di_Dto_Resolver_Config_Namespace = import("./src/Dto/Resolver/Config/Namespace.mjs").default;
20
- type TeqFw_Di_Dto_Resolver_Config_Namespace$DTO = import("./src/Dto/Resolver/Config/Namespace.mjs").default;
21
- type TeqFw_Di_Dto_Resolver_Config_Namespace$Factory = InstanceType<typeof import("./src/Dto/Resolver/Config/Namespace.mjs").Factory>;
20
+ type TeqFw_Di_Dto_Resolver_Config_Namespace__DTO = import("./src/Dto/Resolver/Config/Namespace.mjs").default;
21
+ type TeqFw_Di_Dto_Resolver_Config_Namespace__Factory = InstanceType<typeof import("./src/Dto/Resolver/Config/Namespace.mjs").Factory>;
22
22
  type TeqFw_Di_Enum_Composition = typeof import("./src/Enum/Composition.mjs").default;
23
23
  type TeqFw_Di_Enum_Life = typeof import("./src/Enum/Life.mjs").default;
24
24
  type TeqFw_Di_Enum_Platform = typeof import("./src/Enum/Platform.mjs").default;
25
25
  type TeqFw_Di_Internal_Logger = import("./src/Internal/Logger.mjs").default;
26
+ type TeqFw_Di_Internal_Logger_Noop = typeof import("./src/Internal/Logger.mjs").TeqFw_Di_Internal_Logger_Noop;
26
27
  type TeqFw_Di_Resolver = import("./src/Container/Resolver.mjs").default;
27
28
  }
28
29