@teqfw/di 2.6.2 → 2.8.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 +24 -0
- package/README.md +63 -561
- package/ai/AGENTS.md +10 -54
- package/dist/esm.js +1 -1
- package/dist/umd.js +1 -1
- package/package.json +23 -16
- package/skills/teqfw-di/SKILL.md +36 -0
- package/skills/teqfw-di/agents/openai.yaml +4 -0
- package/skills/teqfw-di/references/compatibility.md +35 -0
- package/skills/teqfw-di/references/concepts.md +43 -0
- package/{ai → skills/teqfw-di/references}/container.md +12 -6
- package/{ai → skills/teqfw-di/references}/dependency-id.md +28 -11
- package/skills/teqfw-di/references/distribution.md +24 -0
- package/{ai → skills/teqfw-di/references}/extensions.md +18 -7
- package/{ai → skills/teqfw-di/references}/package-api.ts +58 -35
- package/skills/teqfw-di/references/usage.md +283 -0
- package/src/AGENTS.md +20 -16
- package/src/Config/NamespaceRegistry.mjs +3 -213
- package/src/Container/Executor.mjs +2 -2
- package/src/Container/GraphResolver.mjs +24 -13
- package/src/Container/Instantiate.mjs +2 -2
- package/src/Container/Lifecycle.mjs +2 -2
- package/src/Container/Pipeline.mjs +20 -22
- package/src/Container.mjs +67 -35
- package/src/Dto/DepId.mjs +1 -1
- package/src/Internal/DepsDecl.mjs +2 -2
- package/src/Node/Registry/Namespace.mjs +208 -0
- package/src/Node/Registry/Package.mjs +215 -0
- package/src/Parser.mjs +18 -18
- package/types.d.ts +9 -4
- package/ai/concepts.md +0 -25
- package/ai/usage.md +0 -194
package/src/Parser.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @namespace TeqFw_Di_Parser
|
|
5
|
-
* @description
|
|
5
|
+
* @description Dependency Specifier parser that builds dependency identity DTOs.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import TeqFw_Di_Enum_Composition from './Enum/Composition.mjs';
|
|
@@ -11,7 +11,7 @@ import TeqFw_Di_Enum_Platform from './Enum/Platform.mjs';
|
|
|
11
11
|
import {Factory as TeqFw_Di_Dto_DepId_Factory} from './Dto/DepId.mjs';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Parser for
|
|
14
|
+
* Parser for Dependency Specifiers into frozen dependency identity DTOs.
|
|
15
15
|
*/
|
|
16
16
|
export default class TeqFw_Di_Parser {
|
|
17
17
|
/**
|
|
@@ -26,7 +26,7 @@ export default class TeqFw_Di_Parser {
|
|
|
26
26
|
/**
|
|
27
27
|
* Detects platform prefix and strips it from the source string.
|
|
28
28
|
*
|
|
29
|
-
* @param {string} source
|
|
29
|
+
* @param {string} source Dependency Specifier source without validation.
|
|
30
30
|
* @returns {{platform: typeof TeqFw_Di_Enum_Platform[keyof typeof TeqFw_Di_Enum_Platform], source: string}}
|
|
31
31
|
*/
|
|
32
32
|
const detectPlatform = function (source) {
|
|
@@ -49,7 +49,7 @@ export default class TeqFw_Di_Parser {
|
|
|
49
49
|
/**
|
|
50
50
|
* Parses lifecycle and wrapper suffix from the source string.
|
|
51
51
|
*
|
|
52
|
-
* @param {string} source
|
|
52
|
+
* @param {string} source Dependency Specifier source without platform prefix.
|
|
53
53
|
* @param {typeof TeqFw_Di_Enum_Platform[keyof typeof TeqFw_Di_Enum_Platform]} platform
|
|
54
54
|
* @returns {{core: string, life: typeof TeqFw_Di_Enum_Life[keyof typeof TeqFw_Di_Enum_Life] | null, lifecycleDeclared: boolean, wrappers: string[]}}
|
|
55
55
|
*/
|
|
@@ -89,7 +89,7 @@ export default class TeqFw_Di_Parser {
|
|
|
89
89
|
/**
|
|
90
90
|
* Splits module and export names from canonical core string.
|
|
91
91
|
*
|
|
92
|
-
* @param {string} core
|
|
92
|
+
* @param {string} core Dependency Specifier core without lifecycle suffix.
|
|
93
93
|
* @returns {{moduleName: string, exportName: string|null}}
|
|
94
94
|
*/
|
|
95
95
|
const parseModuleExport = function (core) {
|
|
@@ -139,20 +139,20 @@ export default class TeqFw_Di_Parser {
|
|
|
139
139
|
};
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
|
-
* Parses one
|
|
142
|
+
* Parses one Dependency Specifier and returns a normalized frozen dependency DTO.
|
|
143
143
|
*
|
|
144
|
-
* @param {string}
|
|
144
|
+
* @param {string} specifier Dependency Specifier string.
|
|
145
145
|
* @returns {TeqFw_Di_DepId__DTO}
|
|
146
146
|
*/
|
|
147
|
-
this.parse = function (
|
|
148
|
-
if (logger) logger.log(`Parser.parse: input='${
|
|
149
|
-
if (typeof
|
|
150
|
-
if (
|
|
151
|
-
if (!/^[\x00-\x7F]+$/.test(
|
|
147
|
+
this.parse = function (specifier) {
|
|
148
|
+
if (logger) logger.log(`Parser.parse: input='${specifier}'.`);
|
|
149
|
+
if (typeof specifier !== 'string') throw new Error('Dependency Specifier must be a string.');
|
|
150
|
+
if (specifier.length === 0) throw new Error('Dependency Specifier must be non-empty.');
|
|
151
|
+
if (!/^[\x00-\x7F]+$/.test(specifier)) throw new Error('Dependency Specifier must be ASCII.');
|
|
152
152
|
|
|
153
153
|
/** @type {string} */
|
|
154
|
-
const origin =
|
|
155
|
-
const detected = detectPlatform(
|
|
154
|
+
const origin = specifier;
|
|
155
|
+
const detected = detectPlatform(specifier);
|
|
156
156
|
const platform = detected.platform;
|
|
157
157
|
const source = detected.source;
|
|
158
158
|
if (source.length === 0) throw new Error('moduleName must be non-empty.');
|
|
@@ -163,10 +163,10 @@ export default class TeqFw_Di_Parser {
|
|
|
163
163
|
/** @type {typeof TeqFw_Di_Enum_Composition[keyof typeof TeqFw_Di_Enum_Composition]} */
|
|
164
164
|
let composition = TeqFw_Di_Enum_Composition.AS_IS;
|
|
165
165
|
let exportName = split.exportName;
|
|
166
|
-
if (
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
if (lifecycle.lifecycleDeclared) {
|
|
167
|
+
if (exportName === null) {
|
|
168
|
+
exportName = 'default';
|
|
169
|
+
}
|
|
170
170
|
composition = TeqFw_Di_Enum_Composition.FACTORY;
|
|
171
171
|
}
|
|
172
172
|
|
package/types.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
declare global {
|
|
2
|
+
type TeqFw_Di_Node_Registry_Namespace = import("./src/Node/Registry/Namespace.mjs").default;
|
|
2
3
|
type TeqFw_Di_Config_NamespaceRegistry = import("./src/Config/NamespaceRegistry.mjs").default;
|
|
4
|
+
type TeqFw_Di_Node_Registry_Namespace_Entry = Readonly<{prefix: string, dirAbs: string, ext: string}>;
|
|
5
|
+
type TeqFw_Di_Node_Registry_Package = import("./src/Node/Registry/Package.mjs").default;
|
|
6
|
+
type TeqFw_Di_Node_Registry_Package_Record = Readonly<{name: string, rootAbs: string, rootReal: string, packageJson: Readonly<Record<string, unknown>>, dependencies: ReadonlyArray<string>}>;
|
|
3
7
|
type TeqFw_Di_Container = import("./src/Container.mjs").default;
|
|
4
|
-
type
|
|
5
|
-
type
|
|
6
|
-
type
|
|
7
|
-
type
|
|
8
|
+
type TeqFw_Di_Container_Instantiate = import("./src/Container/Instantiate.mjs").default;
|
|
9
|
+
type TeqFw_Di_Container_Lifecycle = import("./src/Container/Lifecycle.mjs").default;
|
|
10
|
+
type TeqFw_Di_Container_Postprocess_Context = Readonly<{depId: TeqFw_Di_DepId__DTO}>;
|
|
11
|
+
type TeqFw_Di_Container_GraphResolver = import("./src/Container/GraphResolver.mjs").default;
|
|
12
|
+
type TeqFw_Di_Container_Executor = import("./src/Container/Executor.mjs").default;
|
|
8
13
|
type TeqFw_Di_Parser = import("./src/Parser.mjs").default;
|
|
9
14
|
type TeqFw_Di_DepId = import("./src/Dto/DepId.mjs").default;
|
|
10
15
|
type TeqFw_Di_DepId__DTO = import("./src/Dto/DepId.mjs").default;
|
package/ai/concepts.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# concepts.md
|
|
2
|
-
|
|
3
|
-
Version: 20260606
|
|
4
|
-
|
|
5
|
-
## Late Binding
|
|
6
|
-
|
|
7
|
-
Dependencies are resolved at runtime rather than through direct static imports between application modules. This keeps modules independent of concrete implementations and moves dependency binding into the container.
|
|
8
|
-
|
|
9
|
-
## Runtime Linker
|
|
10
|
-
|
|
11
|
-
The container acts as a runtime linker for ES modules. It interprets CDC identifiers, resolves modules, selects exports, and produces linked values for callers.
|
|
12
|
-
|
|
13
|
-
## Dependency Contracts
|
|
14
|
-
|
|
15
|
-
Dependencies are declared through CDC strings and module-level `__deps__` descriptors. Together they form the contract between module code and runtime composition.
|
|
16
|
-
|
|
17
|
-
The canonical `__deps__` form is hierarchical and keyed by export name.
|
|
18
|
-
|
|
19
|
-
## Namespace Mapping
|
|
20
|
-
|
|
21
|
-
Logical module identifiers are translated into module-specifier bases through namespace roots. This keeps dependency addressing independent from concrete filesystem paths or URL locations.
|
|
22
|
-
|
|
23
|
-
## Immutable Linked Values
|
|
24
|
-
|
|
25
|
-
Values returned by the container are frozen after linking. Consumers should treat them as stable resolved values rather than mutable construction targets.
|
package/ai/usage.md
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
# usage.md
|
|
2
|
-
|
|
3
|
-
Version: 20260606
|
|
4
|
-
|
|
5
|
-
## Purpose
|
|
6
|
-
|
|
7
|
-
This document shows canonical usage patterns for the container. Examples are intentionally short and prioritize supported, recommended forms over convenience shorthand.
|
|
8
|
-
|
|
9
|
-
## Canonical Module Descriptor
|
|
10
|
-
|
|
11
|
-
The canonical form of `__deps__` is hierarchical and keyed by export name.
|
|
12
|
-
|
|
13
|
-
```js
|
|
14
|
-
// @ts-check
|
|
15
|
-
|
|
16
|
-
export const __deps__ = {
|
|
17
|
-
default: {
|
|
18
|
-
cast: "App_Helper_Cast$",
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export default class App_Root {
|
|
23
|
-
/**
|
|
24
|
-
* @param {{cast: (value: unknown) => string}} deps
|
|
25
|
-
*/
|
|
26
|
-
constructor({ cast }) {
|
|
27
|
-
return {
|
|
28
|
-
configure(params = {}) {
|
|
29
|
-
return {
|
|
30
|
-
name: cast(params.name ?? "app"),
|
|
31
|
-
};
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Dependency module:
|
|
39
|
-
|
|
40
|
-
```js
|
|
41
|
-
// @ts-check
|
|
42
|
-
|
|
43
|
-
export default function App_Helper_Cast() {
|
|
44
|
-
return function cast(value) {
|
|
45
|
-
return String(value);
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Rules:
|
|
51
|
-
|
|
52
|
-
- the hierarchical export-scoped form is canonical;
|
|
53
|
-
- each export entry maps constructor dependency names to CDC identifiers;
|
|
54
|
-
- if `__deps__` is omitted, the module has no declared dependencies;
|
|
55
|
-
- dependencies are resolved recursively before instantiation.
|
|
56
|
-
|
|
57
|
-
## Canonical Container Setup
|
|
58
|
-
|
|
59
|
-
The container is configured in the composition root before the first resolution.
|
|
60
|
-
|
|
61
|
-
```js
|
|
62
|
-
import path from "node:path";
|
|
63
|
-
import { fileURLToPath } from "node:url";
|
|
64
|
-
import Container from "@teqfw/di";
|
|
65
|
-
|
|
66
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
67
|
-
const __dirname = path.dirname(__filename);
|
|
68
|
-
|
|
69
|
-
const container = new Container();
|
|
70
|
-
container.addNamespaceRoot("App_", path.resolve(__dirname, "./src/App"), ".mjs");
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Namespace roots may also use URL-backed module-specifier bases:
|
|
74
|
-
|
|
75
|
-
```js
|
|
76
|
-
container.addNamespaceRoot("App_", "https://cdn.example.com/app", ".mjs");
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Resolve Root Dependency
|
|
80
|
-
|
|
81
|
-
Applications typically resolve one root dependency and let the container build the full object graph.
|
|
82
|
-
|
|
83
|
-
```js
|
|
84
|
-
const root = await container.get("App_Root$");
|
|
85
|
-
console.log(root.configure({name: 123}).name);
|
|
86
|
-
console.log(Object.isFrozen(root));
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Named Export
|
|
90
|
-
|
|
91
|
-
Named exports use the `__ExportName` segment in the CDC and the same hierarchical `__deps__` structure.
|
|
92
|
-
|
|
93
|
-
```js
|
|
94
|
-
export const __deps__ = {
|
|
95
|
-
default: {
|
|
96
|
-
cast: "App_Helper_Cast$",
|
|
97
|
-
},
|
|
98
|
-
Factory: {
|
|
99
|
-
cast: "App_Helper_Cast$",
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
export default class RuntimeWrapper {
|
|
104
|
-
constructor() {
|
|
105
|
-
return {mode: "runtime"};
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export class Factory {
|
|
110
|
-
constructor({ cast }) {
|
|
111
|
-
this.configure = function (params = {}) {
|
|
112
|
-
return {
|
|
113
|
-
mode: "factory",
|
|
114
|
-
name: cast(params.name ?? "app"),
|
|
115
|
-
};
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Resolution examples:
|
|
122
|
-
|
|
123
|
-
```js
|
|
124
|
-
const runtime = await container.get("App_Module$");
|
|
125
|
-
const factory = await container.get("App_Module__Factory$");
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Singleton And Transient
|
|
129
|
-
|
|
130
|
-
Common lifecycle-based compositions:
|
|
131
|
-
|
|
132
|
-
```txt
|
|
133
|
-
App_Service$
|
|
134
|
-
App_Task$$
|
|
135
|
-
App_Task$$$
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
- `$` creates and reuses a singleton instance;
|
|
139
|
-
- `$$` creates a new instance for each request;
|
|
140
|
-
- `$$$` is a transient alias in the current implementation.
|
|
141
|
-
|
|
142
|
-
## Wrappers
|
|
143
|
-
|
|
144
|
-
Wrapper exports are selected by CDC suffixes and are applied after postprocess hooks.
|
|
145
|
-
|
|
146
|
-
```txt
|
|
147
|
-
App_Service$$_wrapLog_wrapTrace
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
This pattern is useful when runtime behavior should be decorated without changing the service module contract.
|
|
151
|
-
|
|
152
|
-
## Platform Modules
|
|
153
|
-
|
|
154
|
-
CDC may refer to platform modules directly.
|
|
155
|
-
|
|
156
|
-
```txt
|
|
157
|
-
node:fs
|
|
158
|
-
npm:@humanfs/core
|
|
159
|
-
node:worker_threads
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
These forms resolve the selected platform module export as-is unless a lifecycle marker is explicitly added.
|
|
163
|
-
|
|
164
|
-
## Non-Canonical Shorthand
|
|
165
|
-
|
|
166
|
-
A flat `__deps__` object is a supported shorthand for default-export-only modules, but it is not the canonical model.
|
|
167
|
-
|
|
168
|
-
```js
|
|
169
|
-
export const __deps__ = {
|
|
170
|
-
cast: "App_Helper_Cast$",
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
export default class App_Short {
|
|
174
|
-
constructor({ cast }) {
|
|
175
|
-
this.cast = cast;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
Prefer the hierarchical form for new integrations and for any module that exposes named exports.
|
|
181
|
-
|
|
182
|
-
## Empty Descriptor
|
|
183
|
-
|
|
184
|
-
Modules with no declared dependencies omit `__deps__` entirely.
|
|
185
|
-
|
|
186
|
-
```js
|
|
187
|
-
export default class App_Empty {
|
|
188
|
-
constructor() {
|
|
189
|
-
this.ready = function () {
|
|
190
|
-
return true;
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
```
|