@teqfw/di 2.3.1 → 2.4.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 +6 -0
- package/README.md +110 -13
- package/ai/AGENTS.md +1 -1
- package/ai/concepts.md +3 -1
- package/ai/container.md +2 -2
- package/ai/dependency-id.md +1 -1
- package/ai/extensions.md +3 -1
- package/ai/package-api.ts +3 -3
- package/ai/usage.md +86 -18
- package/dist/esm.js +1 -1
- package/dist/umd.js +1 -1
- package/package.json +10 -4
- package/src/Container/Resolve/GraphResolver.mjs +8 -1
- package/src/Container.mjs +10 -2
- package/types.d.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.4.0 - 2026-03-31 - Test coverage cleanup
|
|
4
|
+
|
|
5
|
+
* Removed low-value unit tests in favor of broader integration coverage.
|
|
6
|
+
* Moved the useful preprocess/postprocess order scenario into integration tests.
|
|
7
|
+
* Updated package version metadata to `2.4.0`.
|
|
8
|
+
|
|
3
9
|
## 2.3.1 - 2026-03-25 - Patch release preparation
|
|
4
10
|
|
|
5
11
|
* 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
|
-
|
|
174
|
+
cast: "App_Helper_Cast$",
|
|
165
175
|
};
|
|
166
176
|
|
|
167
|
-
export default
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
|
212
|
+
const factory = await container.get("App_Root__Factory$");
|
|
190
213
|
|
|
191
|
-
console.log(
|
|
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
|
-
|
|
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
|
-
-
|
|
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
package/ai/concepts.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# concepts.md
|
|
2
2
|
|
|
3
|
-
Version:
|
|
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:
|
|
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
|
|
package/ai/dependency-id.md
CHANGED
package/ai/extensions.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# extensions.md
|
|
2
2
|
|
|
3
|
-
Version:
|
|
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
|
|
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
|
|
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
|
-
'
|
|
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:
|
|
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
|
|
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
|
-
|
|
24
|
+
cast: "Fl32_Web_Helper_Cast$",
|
|
25
|
+
},
|
|
26
|
+
Factory: {
|
|
27
|
+
cast: "Fl32_Web_Helper_Cast$",
|
|
25
28
|
},
|
|
26
29
|
};
|
|
27
30
|
|
|
28
31
|
/**
|
|
29
|
-
*
|
|
30
|
-
|
|
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
|
|
46
|
+
export class Factory {
|
|
34
47
|
/**
|
|
35
|
-
* @param {
|
|
48
|
+
* @param {App_Factory$Deps} deps
|
|
36
49
|
*/
|
|
37
|
-
constructor({
|
|
38
|
-
this.
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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__
|
|
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(/(?:^|[^_])_[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(/(?:^|[^_])_[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
|
+
"version": "2.4.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": {
|
|
@@ -76,7 +76,14 @@ export default class TeqFw_Di_Container_Resolve_GraphResolver {
|
|
|
76
76
|
const depsDecl = Reflect.get(namespace, '__deps__');
|
|
77
77
|
if (depsDecl === undefined) return;
|
|
78
78
|
/** @type {Record<string, unknown>} */
|
|
79
|
-
|
|
79
|
+
let depsMap = /** @type {Record<string, unknown>} */ (depsDecl);
|
|
80
|
+
if ((depsDecl !== null) && (typeof depsDecl === 'object') && !Array.isArray(depsDecl)) {
|
|
81
|
+
const exportName = depId.exportName === null ? 'default' : depId.exportName;
|
|
82
|
+
const exportScoped = Reflect.get(/** @type {object} */ (depsDecl), exportName);
|
|
83
|
+
if ((exportScoped !== undefined) && (exportScoped !== null) && (typeof exportScoped === 'object') && !Array.isArray(exportScoped)) {
|
|
84
|
+
depsMap = /** @type {Record<string, unknown>} */ (exportScoped);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
80
87
|
for (const [, cdc] of Object.entries(depsMap)) {
|
|
81
88
|
/** @type {string} */
|
|
82
89
|
const nextCdc = /** @type {string} */ (cdc);
|
package/src/Container.mjs
CHANGED
|
@@ -167,12 +167,20 @@ export default class TeqFw_Di_Container {
|
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
169
|
* @param {object} namespace
|
|
170
|
+
* @param {TeqFw_Di_DepId$DTO} depId
|
|
170
171
|
* @returns {Record<string, unknown>}
|
|
171
172
|
*/
|
|
172
|
-
const readDepsDecl = function (namespace) {
|
|
173
|
+
const readDepsDecl = function (namespace, depId) {
|
|
173
174
|
/** @type {unknown} */
|
|
174
175
|
const deps = Reflect.get(namespace, '__deps__');
|
|
175
176
|
if (deps === undefined) return {};
|
|
177
|
+
if ((deps !== null) && (typeof deps === 'object') && !Array.isArray(deps)) {
|
|
178
|
+
const exportName = depId.exportName === null ? 'default' : depId.exportName;
|
|
179
|
+
const exportScoped = Reflect.get(/** @type {object} */ (deps), exportName);
|
|
180
|
+
if ((exportScoped !== undefined) && (exportScoped !== null) && (typeof exportScoped === 'object') && !Array.isArray(exportScoped)) {
|
|
181
|
+
return /** @type {Record<string, unknown>} */ (exportScoped);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
176
184
|
return /** @type {Record<string, unknown>} */ (deps);
|
|
177
185
|
};
|
|
178
186
|
|
|
@@ -373,7 +381,7 @@ export default class TeqFw_Di_Container {
|
|
|
373
381
|
/** @type {Record<string, unknown>} */
|
|
374
382
|
const deps = {};
|
|
375
383
|
/** @type {Record<string, unknown>} */
|
|
376
|
-
const depsDecl = readDepsDecl(node.namespace);
|
|
384
|
+
const depsDecl = readDepsDecl(node.namespace, node.depId);
|
|
377
385
|
for (const [name, cdc] of Object.entries(depsDecl)) {
|
|
378
386
|
/** @type {string} */
|
|
379
387
|
const childCdc = /** @type {string} */ (cdc);
|
package/types.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ declare global {
|
|
|
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
|
|