@teqfw/di 2.4.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +159 -284
- package/ai/AGENTS.md +20 -1
- package/ai/concepts.md +2 -2
- package/ai/container.md +3 -0
- package/ai/dependency-id.md +4 -2
- package/ai/package-api.ts +2 -2
- package/ai/usage.md +58 -43
- package/dist/esm.js +1 -1
- package/dist/umd.js +1 -1
- package/package.json +1 -1
- package/src/Config/NamespaceRegistry.mjs +6 -1
- package/src/Container/Instantiate/ExportSelector.mjs +6 -1
- package/src/Container/Instantiate/Instantiator.mjs +7 -2
- package/src/Container/Lifecycle/Registry.mjs +7 -2
- package/src/Container/Resolve/GraphResolver.mjs +28 -11
- package/src/Container/Resolver.mjs +10 -5
- package/src/Container/Wrapper/Executor.mjs +6 -1
- package/src/Container.mjs +40 -20
- package/src/Def/Parser.mjs +8 -3
- package/src/Dto/DepId.mjs +6 -1
- package/src/Dto/Resolver/Config/Namespace.mjs +9 -4
- package/src/Dto/Resolver/Config.mjs +10 -5
- package/src/Enum/Composition.mjs +5 -0
- package/src/Enum/Life.mjs +5 -0
- package/src/Enum/Platform.mjs +5 -0
- package/src/Internal/Logger.mjs +5 -0
- package/types.d.ts +6 -6
|
@@ -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 {
|
|
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:
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
142
|
-
* @returns {
|
|
146
|
+
* @param {TeqFw_Di_DepId__DTO} depId
|
|
147
|
+
* @returns {TeqFw_Di_DepId__DTO}
|
|
143
148
|
*/
|
|
144
149
|
const applyPreprocess = function (depId) {
|
|
145
|
-
/** @type {
|
|
150
|
+
/** @type {TeqFw_Di_DepId__DTO} */
|
|
146
151
|
let current = depId;
|
|
147
152
|
for (const fn of preprocess) {
|
|
148
153
|
current = fn(current);
|
|
@@ -167,21 +172,36 @@ export default class TeqFw_Di_Container {
|
|
|
167
172
|
|
|
168
173
|
/**
|
|
169
174
|
* @param {object} namespace
|
|
170
|
-
* @param {
|
|
175
|
+
* @param {TeqFw_Di_DepId__DTO} depId
|
|
171
176
|
* @returns {Record<string, unknown>}
|
|
172
177
|
*/
|
|
173
178
|
const readDepsDecl = function (namespace, depId) {
|
|
174
179
|
/** @type {unknown} */
|
|
175
180
|
const deps = Reflect.get(namespace, '__deps__');
|
|
176
181
|
if (deps === undefined) return {};
|
|
177
|
-
if ((deps
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
+
if ((deps === null) || (typeof deps !== 'object') || Array.isArray(deps)) {
|
|
183
|
+
throw new Error('__deps__ must be a plain object.');
|
|
184
|
+
}
|
|
185
|
+
const exportName = depId.exportName === null ? 'default' : depId.exportName;
|
|
186
|
+
const exportScoped = Reflect.get(/** @type {object} */ (deps), exportName);
|
|
187
|
+
if ((exportScoped !== undefined) && (exportScoped !== null) && (typeof exportScoped === 'object') && !Array.isArray(exportScoped)) {
|
|
188
|
+
const values = Object.values(/** @type {Record<string, unknown>} */ (exportScoped));
|
|
189
|
+
if (!values.every((value) => typeof value === 'string')) {
|
|
190
|
+
throw new Error('__deps__ export entries must map dependency names to CDC strings.');
|
|
191
|
+
}
|
|
192
|
+
return /** @type {Record<string, unknown>} */ (exportScoped);
|
|
193
|
+
}
|
|
194
|
+
if (exportName === 'default') {
|
|
195
|
+
const values = Object.values(/** @type {Record<string, unknown>} */ (deps));
|
|
196
|
+
if (values.every((value) => typeof value === 'string')) {
|
|
197
|
+
return /** @type {Record<string, unknown>} */ (deps);
|
|
198
|
+
}
|
|
199
|
+
if (values.every((value) => (value !== null) && (typeof value === 'object') && !Array.isArray(value))) {
|
|
200
|
+
return {};
|
|
182
201
|
}
|
|
202
|
+
throw new Error('__deps__ must be either flat or export-scoped.');
|
|
183
203
|
}
|
|
184
|
-
return
|
|
204
|
+
return {};
|
|
185
205
|
};
|
|
186
206
|
|
|
187
207
|
/**
|
|
@@ -223,7 +243,7 @@ export default class TeqFw_Di_Container {
|
|
|
223
243
|
/**
|
|
224
244
|
* Registers preprocess extension before first resolution.
|
|
225
245
|
*
|
|
226
|
-
* @param {(depId:
|
|
246
|
+
* @param {(depId: TeqFw_Di_DepId__DTO) => TeqFw_Di_DepId__DTO} fn
|
|
227
247
|
* @returns {void}
|
|
228
248
|
*/
|
|
229
249
|
this.addPreprocess = function (fn) {
|
|
@@ -329,12 +349,12 @@ export default class TeqFw_Di_Container {
|
|
|
329
349
|
logger.log(`Container.get: cdc='${cdc}'.`);
|
|
330
350
|
initializeInfrastructure();
|
|
331
351
|
logger.log(`Container.state: '${state}'.`);
|
|
332
|
-
/** @type {
|
|
352
|
+
/** @type {TeqFw_Di_DepId__DTO} */
|
|
333
353
|
stage = 'parse';
|
|
334
354
|
logger.log('Container.pipeline: parse:entry.');
|
|
335
355
|
const parsed = parser.parse(cdc);
|
|
336
356
|
logger.log(`Container.pipeline: parse:exit '${parsed.platform}::${parsed.moduleName}'.`);
|
|
337
|
-
/** @type {
|
|
357
|
+
/** @type {TeqFw_Di_DepId__DTO} */
|
|
338
358
|
stage = 'preprocess';
|
|
339
359
|
logger.log('Container.pipeline: preprocess:entry.');
|
|
340
360
|
const root = applyPreprocess(parsed);
|
|
@@ -356,7 +376,7 @@ export default class TeqFw_Di_Container {
|
|
|
356
376
|
} else {
|
|
357
377
|
logger.log('Container.pipeline: mock-lookup:disabled.');
|
|
358
378
|
}
|
|
359
|
-
/** @type {Map<string, {depId:
|
|
379
|
+
/** @type {Map<string, {depId: TeqFw_Di_DepId__DTO, namespace: object}>} */
|
|
360
380
|
stage = 'resolve';
|
|
361
381
|
logger.log('Container.pipeline: resolve:entry.');
|
|
362
382
|
const graph = await graphResolver.resolve(root);
|
|
@@ -385,7 +405,7 @@ export default class TeqFw_Di_Container {
|
|
|
385
405
|
for (const [name, cdc] of Object.entries(depsDecl)) {
|
|
386
406
|
/** @type {string} */
|
|
387
407
|
const childCdc = /** @type {string} */ (cdc);
|
|
388
|
-
/** @type {
|
|
408
|
+
/** @type {TeqFw_Di_DepId__DTO} */
|
|
389
409
|
const childDepId = parser.parse(childCdc);
|
|
390
410
|
deps[name] = build(getKey(childDepId));
|
|
391
411
|
}
|
package/src/Def/Parser.mjs
CHANGED
|
@@ -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 {
|
|
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 {
|
|
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 {
|
|
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<
|
|
29
|
-
* @returns {
|
|
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<
|
|
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 {
|
|
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 {
|
|
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<
|
|
35
|
-
* @returns {
|
|
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<
|
|
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 {
|
|
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 : [];
|
package/src/Enum/Composition.mjs
CHANGED
package/src/Enum/Life.mjs
CHANGED
package/src/Enum/Platform.mjs
CHANGED
package/src/Internal/Logger.mjs
CHANGED
package/types.d.ts
CHANGED
|
@@ -8,17 +8,17 @@ 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
|
|
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
|
|
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
|
|
18
|
-
type
|
|
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
|
|
21
|
-
type
|
|
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;
|