@illuma/core 1.1.0 → 1.3.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.
@@ -1,4 +1,4 @@
1
- import { a as NodeToken, M as MultiNodeToken, N as NodeBase } from './providers-D9YA8L_g.js';
1
+ import { N as NodeToken, M as MultiNodeToken, a as NodeBase } from './types-5mX9F_24.js';
2
2
 
3
3
  /**
4
4
  * Represents a single dependency injection point in the dependency graph.
@@ -12,6 +12,23 @@ interface iInjectionNode<T> {
12
12
  readonly optional: boolean;
13
13
  }
14
14
 
15
+ /**
16
+ * An extension that can scan a factory function for dependency injections.
17
+ * Should return all detected injection nodes within the factory.
18
+ *
19
+ * It's run after default injection scanning and is meant to detect additional
20
+ * injection patterns (e.g., custom decorators or metadata).
21
+ */
22
+ interface iContextScanner {
23
+ /**
24
+ * Scans the provided factory function for dependency injections.
25
+ *
26
+ * @param factory - The factory function to scan
27
+ * @returns A set of detected injection nodes
28
+ */
29
+ scan(factory: any): Set<iInjectionNode<any>>;
30
+ }
31
+
15
32
  declare class ProtoNodeSingle<T = any> {
16
33
  readonly token: NodeToken<T>;
17
34
  readonly injections: Set<iInjectionNode<any>>;
@@ -38,7 +55,7 @@ declare class ProtoNodeMulti<T = any> {
38
55
  toString(): string;
39
56
  }
40
57
 
41
- type DependencyPool = Map<NodeBase<any>, TreeNode<any>>;
58
+ type InjectionPool = Map<NodeBase<any>, TreeNode<any>> | WeakMap<NodeBase<any>, TreeNode<any>>;
42
59
  declare class TreeNodeSingle<T = any> {
43
60
  readonly proto: ProtoNodeSingle<T>;
44
61
  private readonly _transparent;
@@ -49,7 +66,8 @@ declare class TreeNodeSingle<T = any> {
49
66
  get instance(): T;
50
67
  constructor(proto: ProtoNodeSingle<T>);
51
68
  addDependency(node: TreeNode<any>): void;
52
- instantiate(pool?: DependencyPool): void;
69
+ collectPool(pool: InjectionPool): void;
70
+ instantiate(pool?: InjectionPool): void;
53
71
  toString(): string;
54
72
  }
55
73
  declare class TreeNodeTransparent<T = any> {
@@ -62,7 +80,8 @@ declare class TreeNodeTransparent<T = any> {
62
80
  get instance(): T;
63
81
  constructor(proto: ProtoNodeTransparent<T>);
64
82
  addDependency(node: TreeNode<any>): void;
65
- instantiate(pool?: DependencyPool): void;
83
+ collectPool(pool: InjectionPool): void;
84
+ instantiate(pool?: InjectionPool): void;
66
85
  toString(): string;
67
86
  }
68
87
  declare class TreeNodeMulti<T = any> {
@@ -72,29 +91,13 @@ declare class TreeNodeMulti<T = any> {
72
91
  private _resolved;
73
92
  allocations: number;
74
93
  constructor(proto: ProtoNodeMulti<T>);
75
- instantiate(pool?: DependencyPool): void;
94
+ collectPool(pool: InjectionPool): void;
95
+ instantiate(pool?: InjectionPool): void;
76
96
  addDependency(...nodes: TreeNode[]): void;
77
97
  toString(): string;
78
98
  }
79
99
  type TreeNode<T = any> = TreeNodeSingle<T> | TreeNodeMulti<T> | TreeNodeTransparent<T>;
80
100
 
81
- /**
82
- * An extension that can scan a factory function for dependency injections.
83
- * Should return all detected injection nodes within the factory.
84
- *
85
- * It's run after default injection scanning and is meant to detect additional
86
- * injection patterns (e.g., custom decorators or metadata).
87
- */
88
- interface iContextScanner {
89
- /**
90
- * Scans the provided factory function for dependency injections.
91
- *
92
- * @param factory - The factory function to scan
93
- * @returns A set of detected injection nodes
94
- */
95
- scan(factory: any): Set<iInjectionNode<any>>;
96
- }
97
-
98
101
  interface iDiagnosticsReport {
99
102
  readonly totalNodes: number;
100
103
  readonly unusedNodes: TreeNode<unknown>[];
@@ -1,6 +1,6 @@
1
- import { a as iDiagnosticsModule, b as iDiagnosticsReport } from './plugin-container-D8Zwpigq.cjs';
2
- export { I as Illuma, c as iContextScanner } from './plugin-container-D8Zwpigq.cjs';
3
- import './providers-D9YA8L_g.cjs';
1
+ import { a as iDiagnosticsModule, b as iDiagnosticsReport } from './plugin-container-DkECHcvu.cjs';
2
+ export { I as Illuma, c as iContextScanner } from './plugin-container-DkECHcvu.cjs';
3
+ import './types-5mX9F_24.cjs';
4
4
 
5
5
  declare class DiagnosticsDefaultReporter implements iDiagnosticsModule {
6
6
  onReport(report: iDiagnosticsReport): void;
package/dist/plugins.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { a as iDiagnosticsModule, b as iDiagnosticsReport } from './plugin-container-CwkVlVS4.js';
2
- export { I as Illuma, c as iContextScanner } from './plugin-container-CwkVlVS4.js';
3
- import './providers-D9YA8L_g.js';
1
+ import { a as iDiagnosticsModule, b as iDiagnosticsReport } from './plugin-container-GF2OqmiJ.js';
2
+ export { I as Illuma, c as iContextScanner } from './plugin-container-GF2OqmiJ.js';
3
+ import './types-5mX9F_24.js';
4
4
 
5
5
  declare class DiagnosticsDefaultReporter implements iDiagnosticsModule {
6
6
  onReport(report: iDiagnosticsReport): void;
package/dist/testkit.cjs CHANGED
@@ -25,79 +25,6 @@ __export(testkit_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(testkit_exports);
27
27
 
28
- // src/lib/errors.ts
29
- var InjectionError = class _InjectionError extends Error {
30
- static {
31
- __name(this, "InjectionError");
32
- }
33
- code;
34
- constructor(code, message) {
35
- super(`[i${code}] ${message}`), this.code = code;
36
- this.name = "InjectionError";
37
- }
38
- // Provider errors
39
- static duplicate(token) {
40
- return new _InjectionError(100, `Duplicate provider for token "${token.toString()}" detected.`);
41
- }
42
- static duplicateFactory(token) {
43
- return new _InjectionError(101, `Tried to re-provide factory for token "${token.toString()}" detected.`);
44
- }
45
- static invalidCtor(ctor) {
46
- return new _InjectionError(102, `Cannot use constructor for token "${ctor.name}". Please make sure to use @nodeInjectable() decorator`);
47
- }
48
- static invalidProvider(provider) {
49
- return new _InjectionError(103, `Cannot use provider as it is neither a NodeToken nor MultiNodeToken nor a valid constructor.:
50
- ${provider}`);
51
- }
52
- // Alias errors
53
- static invalidAlias(alias) {
54
- const aliasStr = typeof alias === "function" ? alias.name || "Unknown" : String(alias);
55
- return new _InjectionError(200, `Invalid alias target "${aliasStr}". Alias must be a NodeToken, MultiNodeToken, or a class decorated with @NodeInjectable().`);
56
- }
57
- static loopAlias(alias) {
58
- return new _InjectionError(201, `Token "${alias.toString()}" cannot alias itself in a loop.`);
59
- }
60
- // Bootstrap errors
61
- static notBootstrapped() {
62
- return new _InjectionError(300, "Cannot retrieve providers before the container has been bootstrapped.");
63
- }
64
- static bootstrapped() {
65
- return new _InjectionError(301, "Cannot modify providers after the container has been bootstrapped.");
66
- }
67
- static doubleBootstrap() {
68
- return new _InjectionError(302, "Container has already been bootstrapped and cannot be bootstrapped again.");
69
- }
70
- // Retrieval errors
71
- static notFound(token) {
72
- return new _InjectionError(400, `No provider found for "${token.toString()}".`);
73
- }
74
- static circularDependency(provider, path) {
75
- const providerStr = provider instanceof NodeBase ? provider.toString() : provider.name;
76
- const pathStr = path.map((p) => p instanceof NodeBase ? p.toString() : p.name).join(" -> ");
77
- return new _InjectionError(401, `Circular dependency detected while resolving "${providerStr}":
78
- ${pathStr}`);
79
- }
80
- // Instantiation errors
81
- static untracked(token, parent) {
82
- const tokenStr = token instanceof NodeBase ? token.toString() : token.name;
83
- const parentStr = parent instanceof NodeBase ? parent.toString() : parent.name;
84
- return new _InjectionError(500, `Cannot instantiate ${parentStr} because it depends on untracked injection ${tokenStr}. Please make sure all injections are properly tracked.`);
85
- }
86
- static outsideContext(token) {
87
- const tokenStr = token instanceof NodeBase ? token.toString() : token.name;
88
- return new _InjectionError(501, `Cannot inject "${tokenStr}" outside of an injection context.`);
89
- }
90
- static calledUtilsOutsideContext() {
91
- return new _InjectionError(502, "Cannot call injection utilities outside of an injection context.");
92
- }
93
- static instanceAccessFailed(token) {
94
- return new _InjectionError(503, `Failed to access instance for token "${token.toString()}". It was not properly instantiated.`);
95
- }
96
- static accessFailed() {
97
- return new _InjectionError(504, "Failed to access the requested instance due to an unknown error.");
98
- }
99
- };
100
-
101
28
  // src/lib/api/token.ts
102
29
  var NodeBase = class {
103
30
  static {
@@ -176,14 +103,115 @@ function extractToken(provider, isAlias = false) {
176
103
  }
177
104
  __name(extractToken, "extractToken");
178
105
 
106
+ // src/lib/errors.ts
107
+ var ERR_CODES = {
108
+ // Provider errors
109
+ DUPLICATE_PROVIDER: 100,
110
+ DUPLICATE_FACTORY: 101,
111
+ INVALID_CTOR: 102,
112
+ INVALID_PROVIDER: 103,
113
+ // Alias errors
114
+ INVALID_ALIAS: 200,
115
+ LOOP_ALIAS: 201,
116
+ // Bootstrap errors
117
+ NOT_BOOTSTRAPPED: 300,
118
+ BOOTSTRAPPED: 301,
119
+ DOUBLE_BOOTSTRAP: 302,
120
+ // Retrieval errors
121
+ NOT_FOUND: 400,
122
+ CIRCULAR_DEPENDENCY: 401,
123
+ // Instantiation errors
124
+ UNTRACKED: 500,
125
+ OUTSIDE_CONTEXT: 501,
126
+ CALLED_UTILS_OUTSIDE_CONTEXT: 502,
127
+ INSTANCE_ACCESS_FAILED: 503,
128
+ ACCESS_FAILED: 504
129
+ };
130
+ var InjectionError = class _InjectionError extends Error {
131
+ static {
132
+ __name(this, "InjectionError");
133
+ }
134
+ code;
135
+ constructor(code, message) {
136
+ super(`[i${code}] ${message}`), this.code = code;
137
+ this.name = "InjectionError";
138
+ }
139
+ // Provider errors
140
+ static duplicate(token) {
141
+ return new _InjectionError(ERR_CODES.DUPLICATE_PROVIDER, `Duplicate provider for token "${token.toString()}" detected.`);
142
+ }
143
+ static duplicateFactory(token) {
144
+ return new _InjectionError(ERR_CODES.DUPLICATE_FACTORY, `Tried to re-provide factory for token "${token.toString()}" detected.`);
145
+ }
146
+ static invalidCtor(ctor) {
147
+ return new _InjectionError(ERR_CODES.INVALID_CTOR, `Cannot use constructor for token "${ctor.name}". Please make sure to use @nodeInjectable() decorator`);
148
+ }
149
+ static invalidProvider(provider) {
150
+ return new _InjectionError(ERR_CODES.INVALID_PROVIDER, `Cannot use provider as it is neither a NodeToken nor MultiNodeToken nor a valid constructor.:
151
+ ${provider}`);
152
+ }
153
+ // Alias errors
154
+ static invalidAlias(alias) {
155
+ const aliasStr = typeof alias === "function" ? alias.name || "Unknown" : String(alias);
156
+ return new _InjectionError(ERR_CODES.INVALID_ALIAS, `Invalid alias target "${aliasStr}". Alias must be a NodeToken, MultiNodeToken, or a class decorated with @NodeInjectable().`);
157
+ }
158
+ static loopAlias(alias) {
159
+ return new _InjectionError(ERR_CODES.LOOP_ALIAS, `Token "${alias.toString()}" cannot alias itself in a loop.`);
160
+ }
161
+ // Bootstrap errors
162
+ static notBootstrapped() {
163
+ return new _InjectionError(ERR_CODES.NOT_BOOTSTRAPPED, "Cannot retrieve providers before the container has been bootstrapped.");
164
+ }
165
+ static bootstrapped() {
166
+ return new _InjectionError(ERR_CODES.BOOTSTRAPPED, "Cannot modify providers after the container has been bootstrapped.");
167
+ }
168
+ static doubleBootstrap() {
169
+ return new _InjectionError(ERR_CODES.DOUBLE_BOOTSTRAP, "Container has already been bootstrapped and cannot be bootstrapped again.");
170
+ }
171
+ // Retrieval errors
172
+ static notFound(token) {
173
+ return new _InjectionError(ERR_CODES.NOT_FOUND, `No provider found for "${token.toString()}".`);
174
+ }
175
+ static circularDependency(provider, path) {
176
+ const providerStr = provider instanceof NodeBase ? provider.toString() : provider.name;
177
+ const pathStr = path.map((p) => p instanceof NodeBase ? p.toString() : p.name).join(" -> ");
178
+ return new _InjectionError(ERR_CODES.CIRCULAR_DEPENDENCY, `Circular dependency detected while resolving "${providerStr}":
179
+ ${pathStr}`);
180
+ }
181
+ // Instantiation errors
182
+ static untracked(token, parent) {
183
+ const tokenStr = token instanceof NodeBase ? token.toString() : token.name;
184
+ const parentStr = parent instanceof NodeBase ? parent.toString() : parent.name;
185
+ return new _InjectionError(ERR_CODES.UNTRACKED, `Cannot instantiate ${parentStr} because it depends on untracked injection ${tokenStr}. Please make sure all injections are properly tracked.`);
186
+ }
187
+ static outsideContext(token) {
188
+ const tokenStr = token instanceof NodeBase ? token.toString() : token.name;
189
+ return new _InjectionError(ERR_CODES.OUTSIDE_CONTEXT, `Cannot inject "${tokenStr}" outside of an injection context.`);
190
+ }
191
+ static calledUtilsOutsideContext() {
192
+ return new _InjectionError(ERR_CODES.CALLED_UTILS_OUTSIDE_CONTEXT, "Cannot call injection utilities outside of an injection context.");
193
+ }
194
+ static instanceAccessFailed(token) {
195
+ return new _InjectionError(ERR_CODES.INSTANCE_ACCESS_FAILED, `Failed to access instance for token "${token.toString()}". It was not properly instantiated.`);
196
+ }
197
+ static accessFailed() {
198
+ return new _InjectionError(ERR_CODES.ACCESS_FAILED, "Failed to access the requested instance due to an unknown error.");
199
+ }
200
+ };
201
+
179
202
  // src/lib/api/decorator.ts
203
+ var tokenRegistry = /* @__PURE__ */ new WeakMap();
180
204
  var INJECTION_SYMBOL = Symbol("Injectable");
181
205
  function isInjectable(ctor) {
182
- return typeof ctor === "function" && isConstructor(ctor) && INJECTION_SYMBOL in ctor && ctor[INJECTION_SYMBOL] instanceof NodeToken;
206
+ return typeof ctor === "function" && isConstructor(ctor) && (tokenRegistry.has(ctor) || INJECTION_SYMBOL in ctor);
183
207
  }
184
208
  __name(isInjectable, "isInjectable");
185
209
  function getInjectableToken(ctor) {
186
- return ctor[INJECTION_SYMBOL];
210
+ if (tokenRegistry.has(ctor)) return tokenRegistry.get(ctor);
211
+ if (INJECTION_SYMBOL in ctor) {
212
+ return ctor[INJECTION_SYMBOL];
213
+ }
214
+ throw InjectionError.invalidCtor(ctor);
187
215
  }
188
216
  __name(getInjectableToken, "getInjectableToken");
189
217
  function isConstructor(fn) {
@@ -441,23 +469,29 @@ var TreeRootNode = class {
441
469
  static {
442
470
  __name(this, "TreeRootNode");
443
471
  }
472
+ instant;
444
473
  _deps = /* @__PURE__ */ new Set();
445
- _treePool = /* @__PURE__ */ new Map();
474
+ _treePool = /* @__PURE__ */ new WeakMap();
475
+ constructor(instant = true) {
476
+ this.instant = instant;
477
+ }
446
478
  get dependencies() {
447
479
  return this._deps;
448
480
  }
449
481
  addDependency(node) {
450
482
  this._deps.add(node);
451
483
  }
452
- instantiate() {
484
+ build() {
453
485
  for (const dep of this._deps) {
454
- dep.instantiate(this._treePool);
455
486
  if ("token" in dep.proto) this._treePool.set(dep.proto.token, dep);
487
+ if (this.instant) dep.instantiate(this._treePool);
488
+ else dep.collectPool(this._treePool);
456
489
  }
457
490
  }
458
491
  find(token) {
459
492
  const node = this._treePool.get(token);
460
493
  if (!node) return null;
494
+ if (!this.instant) node.instantiate(this._treePool);
461
495
  return node;
462
496
  }
463
497
  toString() {
@@ -488,6 +522,11 @@ var TreeNodeSingle = class {
488
522
  else this._deps.set(node.proto.token, node);
489
523
  node.allocations++;
490
524
  }
525
+ collectPool(pool) {
526
+ for (const node of this._deps.values()) node.collectPool(pool);
527
+ for (const dep of this._transparent) dep.collectPool(pool);
528
+ pool.set(this.proto.token, this);
529
+ }
491
530
  instantiate(pool) {
492
531
  if (this._resolved) return;
493
532
  for (const node of this._deps.values()) node.instantiate(pool);
@@ -525,6 +564,10 @@ var TreeNodeTransparent = class _TreeNodeTransparent {
525
564
  else this._deps.set(node.proto.token, node);
526
565
  node.allocations++;
527
566
  }
567
+ collectPool(pool) {
568
+ for (const node of this._deps.values()) node.collectPool(pool);
569
+ for (const dep of this._transparent) dep.collectPool(pool);
570
+ }
528
571
  instantiate(pool) {
529
572
  if (this._resolved) return;
530
573
  for (const dep of this._transparent) dep.instantiate(pool);
@@ -549,6 +592,10 @@ var TreeNodeMulti = class _TreeNodeMulti {
549
592
  constructor(proto) {
550
593
  this.proto = proto;
551
594
  }
595
+ collectPool(pool) {
596
+ for (const dep of this._deps) dep.collectPool(pool);
597
+ pool.set(this.proto.token, this);
598
+ }
552
599
  instantiate(pool) {
553
600
  if (this._resolved) return;
554
601
  for (const dep of this._deps) {
@@ -854,7 +901,7 @@ var NodeContainer = class extends Illuma {
854
901
  return parentNode.findNode(token);
855
902
  }
856
903
  _buildInjectionTree() {
857
- const root = new TreeRootNode();
904
+ const root = new TreeRootNode(this._opts?.instant);
858
905
  const cache = /* @__PURE__ */ new Map();
859
906
  const nodes = [
860
907
  ...this._protoNodes.values(),
@@ -899,7 +946,7 @@ var NodeContainer = class extends Illuma {
899
946
  value: new InjectorImpl(this)
900
947
  });
901
948
  this._rootNode = this._buildInjectionTree();
902
- this._rootNode.instantiate();
949
+ this._rootNode.build();
903
950
  this._bootstrapped = true;
904
951
  const end = performance.now();
905
952
  const duration = end - start;