@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.
@@ -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":"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"}
@@ -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,GAAqB,IAAI,GAAG,EAAE,CAAC;QACxC,gBAAW,GAAgB,EAAE,CAAC;IA2ExC,CAAC;IAzEC;;;;OAIG;IACH,8DAA8D;IAC9D,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;OAOG;IACH,8DAA8D;IAC9D,GAAG,CAAC,GAAW,EAAE,KAAU,EAAE,OAAmB;QAC9C,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,GAAW;QACb,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"}
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;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"}
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: string, factory: FactoryFn<T>, condition?: ConditionFn): void;
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: string, factory: FactoryFn<T>, condition?: ConditionFn): void;
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: string, factory: FactoryFn<T>, dispose?: DisposeFn): void;
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: string, factory: FactoryFn<T>, lifecycle?: Lifecycle): void;
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: string, originalKey: string): void;
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: string, context?: string): T;
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: string): {
238
- needs: (depKey: string) => {
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: string): boolean;
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(): string[];
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,EACV,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;IACpB,mDAAmD;IACnD,OAAO,CAAC,QAAQ,CAAgC;IAEhD,oCAAoC;IAEpC,OAAO,CAAC,SAAS,CAA0B;IAE3C,0CAA0C;IAC1C,OAAO,CAAC,OAAO,CAA6B;IAE5C,6DAA6D;IAC7D,OAAO,CAAC,YAAY,CAA8B;IAElD,wDAAwD;IACxD,OAAO,CAAC,cAAc,CAAC,CAAS;IAEhC,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,CAAgB;IAEvC;;;OAGG;gBACS,MAAM,CAAC,EAAE,SAAS;IAI9B;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,WAAW;IAOnE;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,WAAW;IAOxE;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,SAAS;IAOjE;;;;;;;;;;;;;;;OAeG;IACH,IAAI,CAAC,CAAC,EACJ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EACrB,SAAS,GAAE,SAAuB;IAQpC;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAI3C;;;;;;;;;;;;;;;;;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;IA0CnB;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC;IA6C5C;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAgBrB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAgBnB;;;;;;;;;;;;;;;OAeG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM;wBAEA,MAAM;4BAEJ,SAAS,CAAC,GAAG,CAAC;;;IAepC;;;;;;;;;;;;OAYG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;;;;;;;;;OAUG;IACH,IAAI,IAAI,MAAM,EAAE;IAMhB;;;;;;;;;;;OAWG;IACH,KAAK;IAUL;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS;IA2BlD;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;OAEG;IACG,OAAO;CAMd"}
1
+ {"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../src/Container.ts"],"names":[],"mappings":"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"}
@@ -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"}
@@ -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: string): any;
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: string, value: any, dispose?: DisposeFn): void;
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: string): boolean;
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;AAEtD;;;;;;;;;;GAUG;AACH,qBAAa,KAAK;IAEhB,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,WAAW,CAAmB;IAEtC;;;;OAIG;IAEH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG;IAIrB;;;;;;;OAOG;IAEH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;IAahD;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;;;;OAKG;IAEH,OAAO,CAAC,YAAY;IASpB;;;;;;;;OAQG;IACG,OAAO;CAOd"}
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"}
@@ -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 type { Lifecycle, IDisposable, DisposeFn } from './types';
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
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"}
@@ -60,7 +60,7 @@ export interface ComposeOptions {
60
60
  */
61
61
  export interface Binding<T = any> {
62
62
  /** The service key identifier */
63
- key: string;
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?: string;
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