@khapu2906/treasure-chest 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -11
- package/dist/cjs/Container.js +194 -23
- package/dist/cjs/Container.js.map +1 -1
- package/dist/cjs/Graph.js +207 -0
- package/dist/cjs/Graph.js.map +1 -0
- package/dist/cjs/Scope.js.map +1 -1
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/Container.js +194 -23
- package/dist/esm/Container.js.map +1 -1
- package/dist/esm/Graph.js +203 -0
- package/dist/esm/Graph.js.map +1 -0
- package/dist/esm/Scope.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/types/Container.d.ts +60 -11
- package/dist/types/Container.d.ts.map +1 -1
- package/dist/types/Graph.d.ts +159 -0
- package/dist/types/Graph.d.ts.map +1 -0
- package/dist/types/Scope.d.ts +4 -4
- package/dist/types/Scope.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +4 -2
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency graph for inspecting and filtering container bindings
|
|
3
|
+
*
|
|
4
|
+
* @module Graph
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Read-only, filterable view over a container's bindings and the
|
|
8
|
+
* dependency edges discovered while resolving them.
|
|
9
|
+
*
|
|
10
|
+
* Edges are recorded as `resolve()` runs, so they only reflect
|
|
11
|
+
* dependencies that have actually been resolved at least once - this is
|
|
12
|
+
* a runtime graph, not a static analysis of factory source code.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const graph = container.graph();
|
|
17
|
+
*
|
|
18
|
+
* const singletons = graph.getNodes({ lifecycle: 'singleton' });
|
|
19
|
+
* const unresolved = graph.getNodes({ resolved: false });
|
|
20
|
+
* const deps = graph.dependenciesOf('userService');
|
|
21
|
+
*
|
|
22
|
+
* console.log(graph.toDot()); // paste into a Graphviz viewer
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export class Graph {
|
|
26
|
+
constructor(snapshot) {
|
|
27
|
+
this.nodes = snapshot.nodes;
|
|
28
|
+
this.edges = snapshot.edges;
|
|
29
|
+
this.byPlainKey = new Map();
|
|
30
|
+
for (const node of this.nodes) {
|
|
31
|
+
if (!this.byPlainKey.has(node.key)) {
|
|
32
|
+
this.byPlainKey.set(node.key, node);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get all nodes, optionally filtered
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* graph.getNodes({ lifecycle: ['singleton', 'scoped'], resolved: true });
|
|
42
|
+
* graph.getNodes({ key: /Repository$/ });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
getNodes(filter) {
|
|
46
|
+
let result = this.nodes;
|
|
47
|
+
if (!filter) {
|
|
48
|
+
return [...result];
|
|
49
|
+
}
|
|
50
|
+
if (filter.lifecycle) {
|
|
51
|
+
const lifecycles = Array.isArray(filter.lifecycle)
|
|
52
|
+
? filter.lifecycle
|
|
53
|
+
: [filter.lifecycle];
|
|
54
|
+
result = result.filter((n) => lifecycles.includes(n.lifecycle));
|
|
55
|
+
}
|
|
56
|
+
if (filter.resolved !== undefined) {
|
|
57
|
+
result = result.filter((n) => n.resolved === filter.resolved);
|
|
58
|
+
}
|
|
59
|
+
if (filter.lazy !== undefined) {
|
|
60
|
+
result = result.filter((n) => n.lazy === filter.lazy);
|
|
61
|
+
}
|
|
62
|
+
if (filter.inherited !== undefined) {
|
|
63
|
+
result = result.filter((n) => n.inherited === filter.inherited);
|
|
64
|
+
}
|
|
65
|
+
if (filter.key !== undefined) {
|
|
66
|
+
const matcher = filter.key;
|
|
67
|
+
result = result.filter((n) => matcher instanceof RegExp
|
|
68
|
+
? matcher.test(n.key)
|
|
69
|
+
: n.key.includes(matcher));
|
|
70
|
+
}
|
|
71
|
+
return [...result];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get a single (non-contextual) node by key
|
|
75
|
+
*/
|
|
76
|
+
getNode(key) {
|
|
77
|
+
return this.byPlainKey.get(key.toString());
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get all edges, optionally filtered by source and/or target key
|
|
81
|
+
*/
|
|
82
|
+
getEdges(filter) {
|
|
83
|
+
if (!filter) {
|
|
84
|
+
return [...this.edges];
|
|
85
|
+
}
|
|
86
|
+
return this.edges.filter((e) => {
|
|
87
|
+
if (filter.from !== undefined && e.from !== filter.from.toString()) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (filter.to !== undefined && e.to !== filter.to.toString()) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Direct dependencies of a key - the services it needs
|
|
98
|
+
*/
|
|
99
|
+
dependenciesOf(key) {
|
|
100
|
+
const keyStr = key.toString();
|
|
101
|
+
return this.edges
|
|
102
|
+
.filter((e) => e.from === keyStr)
|
|
103
|
+
.map((e) => this.byPlainKey.get(e.to))
|
|
104
|
+
.filter((n) => n !== undefined);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Direct dependents of a key - the services that need it
|
|
108
|
+
*/
|
|
109
|
+
dependentsOf(key) {
|
|
110
|
+
const keyStr = key.toString();
|
|
111
|
+
return this.edges
|
|
112
|
+
.filter((e) => e.to === keyStr)
|
|
113
|
+
.map((e) => this.byPlainKey.get(e.from))
|
|
114
|
+
.filter((n) => n !== undefined);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Nodes that nothing else depends on (candidate entry points)
|
|
118
|
+
*/
|
|
119
|
+
roots() {
|
|
120
|
+
const dependedOn = new Set(this.edges.map((e) => e.to));
|
|
121
|
+
return this.nodes.filter((n) => !dependedOn.has(n.key));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Nodes with no recorded dependencies (leaves of the graph)
|
|
125
|
+
*/
|
|
126
|
+
leaves() {
|
|
127
|
+
const withDeps = new Set(this.edges.map((e) => e.from));
|
|
128
|
+
return this.nodes.filter((n) => !withDeps.has(n.key));
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Build a nested tree starting at `key`, recursively expanding
|
|
132
|
+
* dependencies into `children`. Handy for rendering a dependency tree in
|
|
133
|
+
* a UI (e.g. a collapsible tree view).
|
|
134
|
+
*
|
|
135
|
+
* A node that reappears along the same branch (A depends on B, B depends
|
|
136
|
+
* on A, recorded from two separate resolve() calls) is marked
|
|
137
|
+
* `cyclic: true` instead of recursing forever - `children` stays empty
|
|
138
|
+
* there. Nodes that appear in multiple, unrelated branches (e.g. two
|
|
139
|
+
* services sharing the same `db` dependency) are duplicated as separate
|
|
140
|
+
* tree nodes, which is expected for a tree view.
|
|
141
|
+
*
|
|
142
|
+
* @param key The root key to build the tree from
|
|
143
|
+
* @returns The tree, or undefined if `key` isn't a known node
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const tree = container.graph().toTree('service');
|
|
148
|
+
* // { key: 'service', children: [{ key: 'repo', children: [{ key: 'db', children: [] }] }] }
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
toTree(key, _visited = new Set()) {
|
|
152
|
+
const keyStr = key.toString();
|
|
153
|
+
const node = this.byPlainKey.get(keyStr);
|
|
154
|
+
if (!node)
|
|
155
|
+
return undefined;
|
|
156
|
+
if (_visited.has(keyStr)) {
|
|
157
|
+
return { ...node, children: [], cyclic: true };
|
|
158
|
+
}
|
|
159
|
+
const visited = new Set(_visited);
|
|
160
|
+
visited.add(keyStr);
|
|
161
|
+
const children = this.dependenciesOf(keyStr)
|
|
162
|
+
.map((dep) => this.toTree(dep.key, visited))
|
|
163
|
+
.filter((n) => n !== undefined);
|
|
164
|
+
return { ...node, children };
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Build a tree for every root (nodes nothing else depends on), covering
|
|
168
|
+
* the whole graph at once - ready to hand to a UI as-is.
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* const forest = container.graph().forest();
|
|
173
|
+
* // [{ key: 'service', children: [...] }, { key: 'unusedSingleton', children: [] }]
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
forest() {
|
|
177
|
+
return this.roots()
|
|
178
|
+
.map((root) => this.toTree(root.key))
|
|
179
|
+
.filter((n) => n !== undefined);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Plain JSON-serializable snapshot of the graph
|
|
183
|
+
*/
|
|
184
|
+
toJSON() {
|
|
185
|
+
return { nodes: [...this.nodes], edges: [...this.edges] };
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Export as Graphviz DOT source, for visualizing the graph
|
|
189
|
+
*/
|
|
190
|
+
toDot() {
|
|
191
|
+
const lines = ['digraph Container {'];
|
|
192
|
+
for (const node of this.nodes) {
|
|
193
|
+
const label = `${node.key}\\n(${node.lifecycle}${node.lazy ? ', lazy' : ''})`;
|
|
194
|
+
lines.push(` "${node.key}" [label="${label}"];`);
|
|
195
|
+
}
|
|
196
|
+
for (const edge of this.edges) {
|
|
197
|
+
lines.push(` "${edge.from}" -> "${edge.to}";`);
|
|
198
|
+
}
|
|
199
|
+
lines.push('}');
|
|
200
|
+
return lines.join('\n');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=Graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Graph.js","sourceRoot":"","sources":["../../src/Graph.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0DH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,KAAK;IAKhB,YAAY,QAAuB;QACjC,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QAE5B,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,EAAE,CAAC;QAC5B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAwB;QAC/B,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC;QAExB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;QACrB,CAAC;QAED,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;gBAChD,CAAC,CAAC,MAAM,CAAC,SAAS;gBAClB,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACvB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC;QACxD,CAAC;QAED,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;YAC3B,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3B,OAAO,YAAY,MAAM;gBACvB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;gBACrB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAC5B,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,GAAe;QACrB,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,MAA+C;QACtD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YAC7B,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;gBACnE,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IAAI,MAAM,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC7D,OAAO,KAAK,CAAC;YACf,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,GAAe;QAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,KAAK;aACd,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;aAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aACrC,MAAM,CAAC,CAAC,CAAC,EAAkB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,GAAe;QAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,KAAK;aACd,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC;aAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aACvC,MAAM,CAAC,CAAC,CAAC,EAAkB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,KAAK;QACH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CACJ,GAAe,EACf,WAAwB,IAAI,GAAG,EAAE;QAEjC,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QAE5B,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACjD,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC;aACzC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;aAC3C,MAAM,CAAC,CAAC,CAAC,EAAsB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QAEtD,OAAO,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC/B,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,KAAK,EAAE;aAChB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;aACpC,MAAM,CAAC,CAAC,CAAC,EAAsB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,KAAK;QACH,MAAM,KAAK,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAEtC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,GAAG,IAAI,CAAC,GAAG,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;YAC9E,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,aAAa,KAAK,KAAK,CAAC,CAAC;QACpD,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;QAClD,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF"}
|
package/dist/esm/Scope.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Scope.js","sourceRoot":"","sources":["../../src/Scope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;;;;;;;GAUG;AACH,MAAM,OAAO,KAAK;IAAlB;QACE,8DAA8D;QACtD,cAAS,
|
|
1
|
+
{"version":3,"file":"Scope.js","sourceRoot":"","sources":["../../src/Scope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;;;;;;;GAUG;AACH,MAAM,OAAO,KAAK;IAAlB;QACE,8DAA8D;QACtD,cAAS,GAAkC,IAAI,GAAG,EAAE,CAAC;QACrD,gBAAW,GAAgB,EAAE,CAAC;IA2ExC,CAAC;IAzEC;;;;OAIG;IACH,8DAA8D;IAC9D,GAAG,CAAC,GAAe;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;OAOG;IACH,8DAA8D;IAC9D,GAAG,CAAC,GAAe,EAAE,KAAU,EAAE,OAAmB;QAClD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE/B,0BAA0B;QAC1B,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QAClC,CAAC;QAED,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAe;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED;;;;;OAKG;IACH,8DAA8D;IACtD,YAAY,CAAC,KAAU;QAC7B,OAAO,CACL,KAAK,KAAK,IAAI;YACd,KAAK,KAAK,SAAS;YACnB,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU,CACpC,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO;QACX,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACzC,MAAM,SAAS,EAAE,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;IACxB,CAAC;CACF"}
|
package/dist/esm/index.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* - High-performance Map-based storage (v1.2.0)
|
|
18
18
|
* - Auto-dispose for IDisposable instances (v1.2.0)
|
|
19
19
|
* - Modular architecture (v1.2.0)
|
|
20
|
+
* - Dependency graph inspection with filtering, tree, and DOT export (v1.5.0)
|
|
20
21
|
*
|
|
21
22
|
* @example
|
|
22
23
|
* ```typescript
|
|
@@ -31,4 +32,5 @@
|
|
|
31
32
|
export { Container } from './Container';
|
|
32
33
|
export { Lazy } from './Lazy';
|
|
33
34
|
export { Scope } from './Scope';
|
|
35
|
+
export { Graph } from './Graph';
|
|
34
36
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,sBAAsB;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module Container
|
|
5
5
|
*/
|
|
6
|
-
import type { ConditionFn, DisposeFn, FactoryFn, Lifecycle } from './types';
|
|
6
|
+
import type { ConditionFn, DisposeFn, FactoryFn, Lifecycle, ServiceKey } from './types';
|
|
7
7
|
import { Scope } from './Scope';
|
|
8
|
+
import { Graph } from './Graph';
|
|
8
9
|
/**
|
|
9
10
|
* Container class for dependency injection
|
|
10
11
|
* Manages service bindings, instances, and resolution logic
|
|
@@ -35,11 +36,24 @@ export declare class Container {
|
|
|
35
36
|
private currentScope?;
|
|
36
37
|
/** Resolution stack for circular dependency detection */
|
|
37
38
|
private resolutionStack;
|
|
39
|
+
/** Dependency edges observed while resolving: consumerKey -> Set of dependency keys */
|
|
40
|
+
private dependencyEdges;
|
|
38
41
|
/**
|
|
39
42
|
* Create a new container
|
|
40
43
|
* @param parent Optional parent container for hierarchy
|
|
41
44
|
*/
|
|
42
45
|
constructor(parent?: Container);
|
|
46
|
+
/**
|
|
47
|
+
* Generates a consistent string key for caching, handling both strings and symbols.
|
|
48
|
+
* This is a simple implementation; it assumes no string keys will collide with `Symbol().toString()`.
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
private _toCacheKey;
|
|
52
|
+
/**
|
|
53
|
+
* Record that `from` depends on `to`, for later inspection via graph()
|
|
54
|
+
* @private
|
|
55
|
+
*/
|
|
56
|
+
private _recordEdge;
|
|
43
57
|
/**
|
|
44
58
|
* Register a transient binding (new instance on each resolve)
|
|
45
59
|
*
|
|
@@ -54,7 +68,7 @@ export declare class Container {
|
|
|
54
68
|
* container.bind('cache', (c) => new Cache(), (c) => process.env.CACHE_ENABLED === 'true');
|
|
55
69
|
* ```
|
|
56
70
|
*/
|
|
57
|
-
bind<T>(key:
|
|
71
|
+
bind<T>(key: ServiceKey, factory: FactoryFn<T>, condition?: ConditionFn): void;
|
|
58
72
|
/**
|
|
59
73
|
* Register a singleton binding (single instance shared across all resolves)
|
|
60
74
|
*
|
|
@@ -68,7 +82,7 @@ export declare class Container {
|
|
|
68
82
|
* container.singleton('config', (c) => new Config());
|
|
69
83
|
* ```
|
|
70
84
|
*/
|
|
71
|
-
singleton<T>(key:
|
|
85
|
+
singleton<T>(key: ServiceKey, factory: FactoryFn<T>, condition?: ConditionFn): void;
|
|
72
86
|
/**
|
|
73
87
|
* Register a scoped binding (single instance per scope)
|
|
74
88
|
*
|
|
@@ -84,7 +98,7 @@ export declare class Container {
|
|
|
84
98
|
* });
|
|
85
99
|
* ```
|
|
86
100
|
*/
|
|
87
|
-
scoped<T>(key:
|
|
101
|
+
scoped<T>(key: ServiceKey, factory: FactoryFn<T>, dispose?: DisposeFn): void;
|
|
88
102
|
/**
|
|
89
103
|
* Register a lazy binding (deferred initialization)
|
|
90
104
|
*
|
|
@@ -101,7 +115,7 @@ export declare class Container {
|
|
|
101
115
|
* const service = lazy.value; // Initialized now
|
|
102
116
|
* ```
|
|
103
117
|
*/
|
|
104
|
-
lazy<T>(key:
|
|
118
|
+
lazy<T>(key: ServiceKey, factory: FactoryFn<T>, lifecycle?: Lifecycle): void;
|
|
105
119
|
/**
|
|
106
120
|
* Create an alias for an existing service key
|
|
107
121
|
*
|
|
@@ -115,7 +129,7 @@ export declare class Container {
|
|
|
115
129
|
* // Both keys now resolve to the same binding
|
|
116
130
|
* ```
|
|
117
131
|
*/
|
|
118
|
-
alias(aliasKey:
|
|
132
|
+
alias(aliasKey: ServiceKey, originalKey: ServiceKey): void;
|
|
119
133
|
/**
|
|
120
134
|
* Create a child container that inherits from this container
|
|
121
135
|
*
|
|
@@ -180,6 +194,18 @@ export declare class Container {
|
|
|
180
194
|
* @returns The matching binding or undefined
|
|
181
195
|
*/
|
|
182
196
|
private findBinding;
|
|
197
|
+
/**
|
|
198
|
+
* Find the appropriate binding for a given key and context, along with
|
|
199
|
+
* the container that actually declared it (the "owner"). Searches in
|
|
200
|
+
* current container and parent containers. Uses cached result when
|
|
201
|
+
* possible for performance.
|
|
202
|
+
*
|
|
203
|
+
* @private
|
|
204
|
+
* @param key The service key to find
|
|
205
|
+
* @param context Optional context for contextual binding
|
|
206
|
+
* @returns The matching binding paired with its owning container, or undefined
|
|
207
|
+
*/
|
|
208
|
+
private findBindingEntry;
|
|
183
209
|
/**
|
|
184
210
|
* Resolve a service instance from the container
|
|
185
211
|
* Handles transient, singleton, scoped, and lazy bindings
|
|
@@ -197,7 +223,7 @@ export declare class Container {
|
|
|
197
223
|
* const userRepo = container.resolve('UserRepo', 'UserService');
|
|
198
224
|
* ```
|
|
199
225
|
*/
|
|
200
|
-
resolve<T>(key:
|
|
226
|
+
resolve<T>(key: ServiceKey, context?: ServiceKey): T;
|
|
201
227
|
/**
|
|
202
228
|
* Resolve a transient instance
|
|
203
229
|
* @private
|
|
@@ -234,8 +260,8 @@ export declare class Container {
|
|
|
234
260
|
* container.when('OrderService').needs('UserRepo').give(() => new RealUserRepo());
|
|
235
261
|
* ```
|
|
236
262
|
*/
|
|
237
|
-
when(context:
|
|
238
|
-
needs: (depKey:
|
|
263
|
+
when(context: ServiceKey): {
|
|
264
|
+
needs: (depKey: ServiceKey) => {
|
|
239
265
|
give: (factory: FactoryFn<any>) => void;
|
|
240
266
|
};
|
|
241
267
|
};
|
|
@@ -252,7 +278,7 @@ export declare class Container {
|
|
|
252
278
|
* }
|
|
253
279
|
* ```
|
|
254
280
|
*/
|
|
255
|
-
has(key:
|
|
281
|
+
has(key: ServiceKey): boolean;
|
|
256
282
|
/**
|
|
257
283
|
* Get all registered service keys
|
|
258
284
|
*
|
|
@@ -264,7 +290,30 @@ export declare class Container {
|
|
|
264
290
|
* console.log('Registered services:', keys);
|
|
265
291
|
* ```
|
|
266
292
|
*/
|
|
267
|
-
keys():
|
|
293
|
+
keys(): ServiceKey[];
|
|
294
|
+
/**
|
|
295
|
+
* Build a snapshot of this container's bindings (own, inherited from a
|
|
296
|
+
* parent, and inherited from composed containers), plus the dependency
|
|
297
|
+
* edges observed so far. Used to build a Graph via graph().
|
|
298
|
+
*
|
|
299
|
+
* @private
|
|
300
|
+
* @param seen Keys already captured by a more specific (closer) container
|
|
301
|
+
*/
|
|
302
|
+
private inspect;
|
|
303
|
+
/**
|
|
304
|
+
* Build a filterable dependency graph of this container's bindings and
|
|
305
|
+
* the dependency edges observed while resolving them.
|
|
306
|
+
*
|
|
307
|
+
* @returns A Graph snapshot you can filter/inspect
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```typescript
|
|
311
|
+
* const graph = container.graph();
|
|
312
|
+
* const singletons = graph.getNodes({ lifecycle: 'singleton' });
|
|
313
|
+
* const deps = graph.dependenciesOf('userService');
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
graph(): Graph;
|
|
268
317
|
/**
|
|
269
318
|
* Reset the container to its initial state
|
|
270
319
|
* Clears all bindings, instances, aliases, and context
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../src/Container.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAEV,WAAW,EACX,SAAS,EACT,SAAS,EACT,SAAS,
|
|
1
|
+
{"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../src/Container.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAEV,WAAW,EACX,SAAS,EACT,SAAS,EACT,SAAS,EACT,UAAU,EACX,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EACL,KAAK,EAIN,MAAM,SAAS,CAAC;AAYjB;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;IACpB,mDAAmD;IACnD,OAAO,CAAC,QAAQ,CAAoC;IAEpD,oCAAoC;IAEpC,OAAO,CAAC,SAAS,CAA0B;IAE3C,0CAA0C;IAC1C,OAAO,CAAC,OAAO,CAAqC;IAEpD,6DAA6D;IAC7D,OAAO,CAAC,YAAY,CAAmC;IAEvD,wDAAwD;IACxD,OAAO,CAAC,cAAc,CAAC,CAAa;IAEpC,qCAAqC;IACrC,OAAO,CAAC,MAAM,CAAC,CAAY;IAE3B,kDAAkD;IAClD,OAAO,CAAC,kBAAkB,CAAmB;IAE7C,2BAA2B;IAC3B,OAAO,CAAC,YAAY,CAAC,CAAQ;IAE7B,yDAAyD;IACzD,OAAO,CAAC,eAAe,CAAoB;IAE3C,uFAAuF;IACvF,OAAO,CAAC,eAAe,CAAkC;IAEzD;;;OAGG;gBACS,MAAM,CAAC,EAAE,SAAS;IAI9B;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAQnB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAUnB;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,WAAW;IAOvE;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,CAAC,EACT,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EACrB,SAAS,CAAC,EAAE,WAAW;IAQzB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,SAAS;IAOrE;;;;;;;;;;;;;;;OAeG;IACH,IAAI,CAAC,CAAC,EACJ,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EACrB,SAAS,GAAE,SAAuB;IAQpC;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU;IAInD;;;;;;;;;;;;;;;;;OAiBG;IACH,WAAW,IAAI,SAAS;IAIxB;;;;;;;;;;;;;;;OAeG;IACH,WAAW,IAAI,KAAK;IAMpB;;;;;;;;;;;;;;;OAeG;IACG,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAS1E;;;;;;;;;OASG;IACH,OAAO,CAAC,WAAW;IAOnB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,gBAAgB;IAiDxB;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,CAAC;IAyDpD;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAgBrB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAgBnB;;;;;;;;;;;;;;;OAeG;IACH,IAAI,CAAC,OAAO,EAAE,UAAU;wBAEJ,UAAU;4BAER,SAAS,CAAC,GAAG,CAAC;;;IAepC;;;;;;;;;;;;OAYG;IACH,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO;IAkB7B;;;;;;;;;;OAUG;IACH,IAAI,IAAI,UAAU,EAAE;IAMpB;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO;IAgEf;;;;;;;;;;;;OAYG;IACH,KAAK,IAAI,KAAK;IAId;;;;;;;;;;;OAWG;IACH,KAAK;IAWL;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS;IA6BlD;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAkC9B;;OAEG;IACG,OAAO;CAMd"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency graph for inspecting and filtering container bindings
|
|
3
|
+
*
|
|
4
|
+
* @module Graph
|
|
5
|
+
*/
|
|
6
|
+
import type { Lifecycle, ServiceKey } from './types';
|
|
7
|
+
/** A single node in the dependency graph, representing one registered binding */
|
|
8
|
+
export interface GraphNode {
|
|
9
|
+
/** Stable string form of the service key */
|
|
10
|
+
key: string;
|
|
11
|
+
/** Lifecycle of the binding (transient, singleton, scoped) */
|
|
12
|
+
lifecycle: Lifecycle;
|
|
13
|
+
/** Whether this binding is registered as lazy */
|
|
14
|
+
lazy: boolean;
|
|
15
|
+
/** Context this binding is scoped to, if it's a contextual binding */
|
|
16
|
+
context?: string;
|
|
17
|
+
/** Original key this node is an alias for, if any */
|
|
18
|
+
aliasOf?: string;
|
|
19
|
+
/** Whether this binding comes from a parent or composed container */
|
|
20
|
+
inherited: boolean;
|
|
21
|
+
/** Whether an instance has already been created and cached */
|
|
22
|
+
resolved: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** A directed edge meaning `from` depends on `to` */
|
|
25
|
+
export interface GraphEdge {
|
|
26
|
+
from: string;
|
|
27
|
+
to: string;
|
|
28
|
+
}
|
|
29
|
+
/** Raw data used to build a Graph; produced by Container#graph() */
|
|
30
|
+
export interface GraphSnapshot {
|
|
31
|
+
nodes: GraphNode[];
|
|
32
|
+
edges: GraphEdge[];
|
|
33
|
+
}
|
|
34
|
+
/** A GraphNode nested with its dependencies, for tree-shaped UI rendering */
|
|
35
|
+
export interface GraphTreeNode extends GraphNode {
|
|
36
|
+
children: GraphTreeNode[];
|
|
37
|
+
/**
|
|
38
|
+
* True if this key already appears higher up in the current branch.
|
|
39
|
+
* Recursion stops here instead of looping forever - `children` will be empty.
|
|
40
|
+
*/
|
|
41
|
+
cyclic?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Criteria for filtering graph nodes */
|
|
44
|
+
export interface GraphNodeFilter {
|
|
45
|
+
/** Only include nodes matching this lifecycle (or one of these) */
|
|
46
|
+
lifecycle?: Lifecycle | Lifecycle[];
|
|
47
|
+
/** Only include nodes whose instance has (or hasn't) been resolved */
|
|
48
|
+
resolved?: boolean;
|
|
49
|
+
/** Only include lazy (or non-lazy) bindings */
|
|
50
|
+
lazy?: boolean;
|
|
51
|
+
/** Only include inherited (or own) bindings */
|
|
52
|
+
inherited?: boolean;
|
|
53
|
+
/** Only include keys matching this substring or RegExp */
|
|
54
|
+
key?: string | RegExp;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Read-only, filterable view over a container's bindings and the
|
|
58
|
+
* dependency edges discovered while resolving them.
|
|
59
|
+
*
|
|
60
|
+
* Edges are recorded as `resolve()` runs, so they only reflect
|
|
61
|
+
* dependencies that have actually been resolved at least once - this is
|
|
62
|
+
* a runtime graph, not a static analysis of factory source code.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const graph = container.graph();
|
|
67
|
+
*
|
|
68
|
+
* const singletons = graph.getNodes({ lifecycle: 'singleton' });
|
|
69
|
+
* const unresolved = graph.getNodes({ resolved: false });
|
|
70
|
+
* const deps = graph.dependenciesOf('userService');
|
|
71
|
+
*
|
|
72
|
+
* console.log(graph.toDot()); // paste into a Graphviz viewer
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare class Graph {
|
|
76
|
+
private readonly nodes;
|
|
77
|
+
private readonly edges;
|
|
78
|
+
private readonly byPlainKey;
|
|
79
|
+
constructor(snapshot: GraphSnapshot);
|
|
80
|
+
/**
|
|
81
|
+
* Get all nodes, optionally filtered
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* graph.getNodes({ lifecycle: ['singleton', 'scoped'], resolved: true });
|
|
86
|
+
* graph.getNodes({ key: /Repository$/ });
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
getNodes(filter?: GraphNodeFilter): GraphNode[];
|
|
90
|
+
/**
|
|
91
|
+
* Get a single (non-contextual) node by key
|
|
92
|
+
*/
|
|
93
|
+
getNode(key: ServiceKey): GraphNode | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Get all edges, optionally filtered by source and/or target key
|
|
96
|
+
*/
|
|
97
|
+
getEdges(filter?: {
|
|
98
|
+
from?: ServiceKey;
|
|
99
|
+
to?: ServiceKey;
|
|
100
|
+
}): GraphEdge[];
|
|
101
|
+
/**
|
|
102
|
+
* Direct dependencies of a key - the services it needs
|
|
103
|
+
*/
|
|
104
|
+
dependenciesOf(key: ServiceKey): GraphNode[];
|
|
105
|
+
/**
|
|
106
|
+
* Direct dependents of a key - the services that need it
|
|
107
|
+
*/
|
|
108
|
+
dependentsOf(key: ServiceKey): GraphNode[];
|
|
109
|
+
/**
|
|
110
|
+
* Nodes that nothing else depends on (candidate entry points)
|
|
111
|
+
*/
|
|
112
|
+
roots(): GraphNode[];
|
|
113
|
+
/**
|
|
114
|
+
* Nodes with no recorded dependencies (leaves of the graph)
|
|
115
|
+
*/
|
|
116
|
+
leaves(): GraphNode[];
|
|
117
|
+
/**
|
|
118
|
+
* Build a nested tree starting at `key`, recursively expanding
|
|
119
|
+
* dependencies into `children`. Handy for rendering a dependency tree in
|
|
120
|
+
* a UI (e.g. a collapsible tree view).
|
|
121
|
+
*
|
|
122
|
+
* A node that reappears along the same branch (A depends on B, B depends
|
|
123
|
+
* on A, recorded from two separate resolve() calls) is marked
|
|
124
|
+
* `cyclic: true` instead of recursing forever - `children` stays empty
|
|
125
|
+
* there. Nodes that appear in multiple, unrelated branches (e.g. two
|
|
126
|
+
* services sharing the same `db` dependency) are duplicated as separate
|
|
127
|
+
* tree nodes, which is expected for a tree view.
|
|
128
|
+
*
|
|
129
|
+
* @param key The root key to build the tree from
|
|
130
|
+
* @returns The tree, or undefined if `key` isn't a known node
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* const tree = container.graph().toTree('service');
|
|
135
|
+
* // { key: 'service', children: [{ key: 'repo', children: [{ key: 'db', children: [] }] }] }
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
toTree(key: ServiceKey, _visited?: Set<string>): GraphTreeNode | undefined;
|
|
139
|
+
/**
|
|
140
|
+
* Build a tree for every root (nodes nothing else depends on), covering
|
|
141
|
+
* the whole graph at once - ready to hand to a UI as-is.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* const forest = container.graph().forest();
|
|
146
|
+
* // [{ key: 'service', children: [...] }, { key: 'unusedSingleton', children: [] }]
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
forest(): GraphTreeNode[];
|
|
150
|
+
/**
|
|
151
|
+
* Plain JSON-serializable snapshot of the graph
|
|
152
|
+
*/
|
|
153
|
+
toJSON(): GraphSnapshot;
|
|
154
|
+
/**
|
|
155
|
+
* Export as Graphviz DOT source, for visualizing the graph
|
|
156
|
+
*/
|
|
157
|
+
toDot(): string;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=Graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Graph.d.ts","sourceRoot":"","sources":["../../src/Graph.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErD,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,SAAS,EAAE,SAAS,CAAC;IACrB,iDAAiD;IACjD,IAAI,EAAE,OAAO,CAAC;IACd,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,SAAS,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED,6EAA6E;AAC7E,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC9C,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,yCAAyC;AACzC,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IACpC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,+CAA+C;IAC/C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;gBAExC,QAAQ,EAAE,aAAa;IAYnC;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,EAAE;IAsC/C;;OAEG;IACH,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS;IAI/C;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,UAAU,CAAC;QAAC,EAAE,CAAC,EAAE,UAAU,CAAA;KAAE,GAAG,SAAS,EAAE;IAgBtE;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,EAAE;IAQ5C;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,EAAE;IAQ1C;;OAEG;IACH,KAAK,IAAI,SAAS,EAAE;IAKpB;;OAEG;IACH,MAAM,IAAI,SAAS,EAAE;IAKrB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CACJ,GAAG,EAAE,UAAU,EACf,QAAQ,GAAE,GAAG,CAAC,MAAM,CAAa,GAChC,aAAa,GAAG,SAAS;IAmB5B;;;;;;;;;OASG;IACH,MAAM,IAAI,aAAa,EAAE;IAMzB;;OAEG;IACH,MAAM,IAAI,aAAa;IAIvB;;OAEG;IACH,KAAK,IAAI,MAAM;CAehB"}
|
package/dist/types/Scope.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module Scope
|
|
5
5
|
*/
|
|
6
|
-
import type { DisposeFn } from './types';
|
|
6
|
+
import type { DisposeFn, ServiceKey } from './types';
|
|
7
7
|
/**
|
|
8
8
|
* Scope class for managing scoped instances
|
|
9
9
|
* A scope contains instances that live for a specific duration (e.g., per HTTP request)
|
|
@@ -23,7 +23,7 @@ export declare class Scope {
|
|
|
23
23
|
* @param key The service key
|
|
24
24
|
* @returns The instance or undefined
|
|
25
25
|
*/
|
|
26
|
-
get(key:
|
|
26
|
+
get(key: ServiceKey): any;
|
|
27
27
|
/**
|
|
28
28
|
* Set an instance in this scope with optional cleanup
|
|
29
29
|
* Auto-detects IDisposable instances
|
|
@@ -32,13 +32,13 @@ export declare class Scope {
|
|
|
32
32
|
* @param value The instance to store
|
|
33
33
|
* @param dispose Optional disposal function
|
|
34
34
|
*/
|
|
35
|
-
set(key:
|
|
35
|
+
set(key: ServiceKey, value: any, dispose?: DisposeFn): void;
|
|
36
36
|
/**
|
|
37
37
|
* Check if instance exists in scope
|
|
38
38
|
* @param key The service key
|
|
39
39
|
* @returns True if the instance exists
|
|
40
40
|
*/
|
|
41
|
-
has(key:
|
|
41
|
+
has(key: ServiceKey): boolean;
|
|
42
42
|
/**
|
|
43
43
|
* Check if value implements IDisposable interface
|
|
44
44
|
* @private
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Scope.d.ts","sourceRoot":"","sources":["../../src/Scope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Scope.d.ts","sourceRoot":"","sources":["../../src/Scope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAe,UAAU,EAAE,MAAM,SAAS,CAAC;AAElE;;;;;;;;;;GAUG;AACH,qBAAa,KAAK;IAEhB,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,WAAW,CAAmB;IAEtC;;;;OAIG;IAEH,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,GAAG;IAIzB;;;;;;;OAOG;IAEH,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;IAapD;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO;IAI7B;;;;;OAKG;IAEH,OAAO,CAAC,YAAY;IASpB;;;;;;;;OAQG;IACG,OAAO;CAOd"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* - High-performance Map-based storage (v1.2.0)
|
|
18
18
|
* - Auto-dispose for IDisposable instances (v1.2.0)
|
|
19
19
|
* - Modular architecture (v1.2.0)
|
|
20
|
+
* - Dependency graph inspection with filtering, tree, and DOT export (v1.5.0)
|
|
20
21
|
*
|
|
21
22
|
* @example
|
|
22
23
|
* ```typescript
|
|
@@ -30,5 +31,7 @@
|
|
|
30
31
|
export { Container } from './Container';
|
|
31
32
|
export { Lazy } from './Lazy';
|
|
32
33
|
export { Scope } from './Scope';
|
|
33
|
-
export
|
|
34
|
+
export { Graph } from './Graph';
|
|
35
|
+
export type { Lifecycle, IDisposable, DisposeFn, ServiceKey } from './types';
|
|
36
|
+
export type { GraphNode, GraphEdge, GraphSnapshot, GraphNodeFilter, GraphTreeNode, } from './Graph';
|
|
34
37
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC7E,YAAY,EACV,SAAS,EACT,SAAS,EACT,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,SAAS,CAAC"}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export interface ComposeOptions {
|
|
|
60
60
|
*/
|
|
61
61
|
export interface Binding<T = any> {
|
|
62
62
|
/** The service key identifier */
|
|
63
|
-
key:
|
|
63
|
+
key: ServiceKey;
|
|
64
64
|
/** Factory function to create the service instance */
|
|
65
65
|
factory: FactoryFn<T>;
|
|
66
66
|
/** Lifecycle type: transient, singleton, or scoped */
|
|
@@ -68,10 +68,12 @@ export interface Binding<T = any> {
|
|
|
68
68
|
/** Optional condition for conditional binding */
|
|
69
69
|
condition?: ConditionFn;
|
|
70
70
|
/** Optional context for contextual binding */
|
|
71
|
-
context?:
|
|
71
|
+
context?: ServiceKey;
|
|
72
72
|
/** Whether this is a lazy binding */
|
|
73
73
|
lazy?: boolean;
|
|
74
74
|
/** Optional disposal function */
|
|
75
75
|
dispose?: DisposeFn;
|
|
76
76
|
}
|
|
77
|
+
export type Constructor<T = any> = new (...args: any[]) => T;
|
|
78
|
+
export type ServiceKey = string | Symbol | Constructor;
|
|
77
79
|
//# sourceMappingURL=types.d.ts.map
|