@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.
package/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  // src/index.ts
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
+ ILLUMA_ERR_CODES: () => ERR_CODES,
24
25
  INJECTION_SYMBOL: () => INJECTION_SYMBOL,
25
26
  InjectionContext: () => InjectionContext,
26
27
  InjectionError: () => InjectionError,
@@ -34,89 +35,18 @@ __export(index_exports, {
34
35
  extractToken: () => extractToken,
35
36
  getInjectableToken: () => getInjectableToken,
36
37
  injectAsync: () => injectAsync,
38
+ injectDefer: () => injectDefer,
37
39
  injectEntryAsync: () => injectEntryAsync,
38
40
  injectGroupAsync: () => injectGroupAsync,
39
41
  isConstructor: () => isConstructor,
40
42
  isInjectable: () => isInjectable,
41
43
  isNodeBase: () => isNodeBase,
42
44
  makeInjectable: () => makeInjectable,
43
- nodeInject: () => nodeInject
45
+ nodeInject: () => nodeInject,
46
+ registerClassAsInjectable: () => registerClassAsInjectable
44
47
  });
45
48
  module.exports = __toCommonJS(index_exports);
46
49
 
47
- // src/lib/errors.ts
48
- var InjectionError = class _InjectionError extends Error {
49
- static {
50
- __name(this, "InjectionError");
51
- }
52
- code;
53
- constructor(code, message) {
54
- super(`[i${code}] ${message}`), this.code = code;
55
- this.name = "InjectionError";
56
- }
57
- // Provider errors
58
- static duplicate(token) {
59
- return new _InjectionError(100, `Duplicate provider for token "${token.toString()}" detected.`);
60
- }
61
- static duplicateFactory(token) {
62
- return new _InjectionError(101, `Tried to re-provide factory for token "${token.toString()}" detected.`);
63
- }
64
- static invalidCtor(ctor) {
65
- return new _InjectionError(102, `Cannot use constructor for token "${ctor.name}". Please make sure to use @nodeInjectable() decorator`);
66
- }
67
- static invalidProvider(provider) {
68
- return new _InjectionError(103, `Cannot use provider as it is neither a NodeToken nor MultiNodeToken nor a valid constructor.:
69
- ${provider}`);
70
- }
71
- // Alias errors
72
- static invalidAlias(alias) {
73
- const aliasStr = typeof alias === "function" ? alias.name || "Unknown" : String(alias);
74
- return new _InjectionError(200, `Invalid alias target "${aliasStr}". Alias must be a NodeToken, MultiNodeToken, or a class decorated with @NodeInjectable().`);
75
- }
76
- static loopAlias(alias) {
77
- return new _InjectionError(201, `Token "${alias.toString()}" cannot alias itself in a loop.`);
78
- }
79
- // Bootstrap errors
80
- static notBootstrapped() {
81
- return new _InjectionError(300, "Cannot retrieve providers before the container has been bootstrapped.");
82
- }
83
- static bootstrapped() {
84
- return new _InjectionError(301, "Cannot modify providers after the container has been bootstrapped.");
85
- }
86
- static doubleBootstrap() {
87
- return new _InjectionError(302, "Container has already been bootstrapped and cannot be bootstrapped again.");
88
- }
89
- // Retrieval errors
90
- static notFound(token) {
91
- return new _InjectionError(400, `No provider found for "${token.toString()}".`);
92
- }
93
- static circularDependency(provider, path) {
94
- const providerStr = provider instanceof NodeBase ? provider.toString() : provider.name;
95
- const pathStr = path.map((p) => p instanceof NodeBase ? p.toString() : p.name).join(" -> ");
96
- return new _InjectionError(401, `Circular dependency detected while resolving "${providerStr}":
97
- ${pathStr}`);
98
- }
99
- // Instantiation errors
100
- static untracked(token, parent) {
101
- const tokenStr = token instanceof NodeBase ? token.toString() : token.name;
102
- const parentStr = parent instanceof NodeBase ? parent.toString() : parent.name;
103
- return new _InjectionError(500, `Cannot instantiate ${parentStr} because it depends on untracked injection ${tokenStr}. Please make sure all injections are properly tracked.`);
104
- }
105
- static outsideContext(token) {
106
- const tokenStr = token instanceof NodeBase ? token.toString() : token.name;
107
- return new _InjectionError(501, `Cannot inject "${tokenStr}" outside of an injection context.`);
108
- }
109
- static calledUtilsOutsideContext() {
110
- return new _InjectionError(502, "Cannot call injection utilities outside of an injection context.");
111
- }
112
- static instanceAccessFailed(token) {
113
- return new _InjectionError(503, `Failed to access instance for token "${token.toString()}". It was not properly instantiated.`);
114
- }
115
- static accessFailed() {
116
- return new _InjectionError(504, "Failed to access the requested instance due to an unknown error.");
117
- }
118
- };
119
-
120
50
  // src/lib/api/token.ts
121
51
  var NodeBase = class {
122
52
  static {
@@ -195,14 +125,115 @@ function extractToken(provider, isAlias = false) {
195
125
  }
196
126
  __name(extractToken, "extractToken");
197
127
 
128
+ // src/lib/errors.ts
129
+ var ERR_CODES = {
130
+ // Provider errors
131
+ DUPLICATE_PROVIDER: 100,
132
+ DUPLICATE_FACTORY: 101,
133
+ INVALID_CTOR: 102,
134
+ INVALID_PROVIDER: 103,
135
+ // Alias errors
136
+ INVALID_ALIAS: 200,
137
+ LOOP_ALIAS: 201,
138
+ // Bootstrap errors
139
+ NOT_BOOTSTRAPPED: 300,
140
+ BOOTSTRAPPED: 301,
141
+ DOUBLE_BOOTSTRAP: 302,
142
+ // Retrieval errors
143
+ NOT_FOUND: 400,
144
+ CIRCULAR_DEPENDENCY: 401,
145
+ // Instantiation errors
146
+ UNTRACKED: 500,
147
+ OUTSIDE_CONTEXT: 501,
148
+ CALLED_UTILS_OUTSIDE_CONTEXT: 502,
149
+ INSTANCE_ACCESS_FAILED: 503,
150
+ ACCESS_FAILED: 504
151
+ };
152
+ var InjectionError = class _InjectionError extends Error {
153
+ static {
154
+ __name(this, "InjectionError");
155
+ }
156
+ code;
157
+ constructor(code, message) {
158
+ super(`[i${code}] ${message}`), this.code = code;
159
+ this.name = "InjectionError";
160
+ }
161
+ // Provider errors
162
+ static duplicate(token) {
163
+ return new _InjectionError(ERR_CODES.DUPLICATE_PROVIDER, `Duplicate provider for token "${token.toString()}" detected.`);
164
+ }
165
+ static duplicateFactory(token) {
166
+ return new _InjectionError(ERR_CODES.DUPLICATE_FACTORY, `Tried to re-provide factory for token "${token.toString()}" detected.`);
167
+ }
168
+ static invalidCtor(ctor) {
169
+ return new _InjectionError(ERR_CODES.INVALID_CTOR, `Cannot use constructor for token "${ctor.name}". Please make sure to use @nodeInjectable() decorator`);
170
+ }
171
+ static invalidProvider(provider) {
172
+ return new _InjectionError(ERR_CODES.INVALID_PROVIDER, `Cannot use provider as it is neither a NodeToken nor MultiNodeToken nor a valid constructor.:
173
+ ${provider}`);
174
+ }
175
+ // Alias errors
176
+ static invalidAlias(alias) {
177
+ const aliasStr = typeof alias === "function" ? alias.name || "Unknown" : String(alias);
178
+ return new _InjectionError(ERR_CODES.INVALID_ALIAS, `Invalid alias target "${aliasStr}". Alias must be a NodeToken, MultiNodeToken, or a class decorated with @NodeInjectable().`);
179
+ }
180
+ static loopAlias(alias) {
181
+ return new _InjectionError(ERR_CODES.LOOP_ALIAS, `Token "${alias.toString()}" cannot alias itself in a loop.`);
182
+ }
183
+ // Bootstrap errors
184
+ static notBootstrapped() {
185
+ return new _InjectionError(ERR_CODES.NOT_BOOTSTRAPPED, "Cannot retrieve providers before the container has been bootstrapped.");
186
+ }
187
+ static bootstrapped() {
188
+ return new _InjectionError(ERR_CODES.BOOTSTRAPPED, "Cannot modify providers after the container has been bootstrapped.");
189
+ }
190
+ static doubleBootstrap() {
191
+ return new _InjectionError(ERR_CODES.DOUBLE_BOOTSTRAP, "Container has already been bootstrapped and cannot be bootstrapped again.");
192
+ }
193
+ // Retrieval errors
194
+ static notFound(token) {
195
+ return new _InjectionError(ERR_CODES.NOT_FOUND, `No provider found for "${token.toString()}".`);
196
+ }
197
+ static circularDependency(provider, path) {
198
+ const providerStr = provider instanceof NodeBase ? provider.toString() : provider.name;
199
+ const pathStr = path.map((p) => p instanceof NodeBase ? p.toString() : p.name).join(" -> ");
200
+ return new _InjectionError(ERR_CODES.CIRCULAR_DEPENDENCY, `Circular dependency detected while resolving "${providerStr}":
201
+ ${pathStr}`);
202
+ }
203
+ // Instantiation errors
204
+ static untracked(token, parent) {
205
+ const tokenStr = token instanceof NodeBase ? token.toString() : token.name;
206
+ const parentStr = parent instanceof NodeBase ? parent.toString() : parent.name;
207
+ return new _InjectionError(ERR_CODES.UNTRACKED, `Cannot instantiate ${parentStr} because it depends on untracked injection ${tokenStr}. Please make sure all injections are properly tracked.`);
208
+ }
209
+ static outsideContext(token) {
210
+ const tokenStr = token instanceof NodeBase ? token.toString() : token.name;
211
+ return new _InjectionError(ERR_CODES.OUTSIDE_CONTEXT, `Cannot inject "${tokenStr}" outside of an injection context.`);
212
+ }
213
+ static calledUtilsOutsideContext() {
214
+ return new _InjectionError(ERR_CODES.CALLED_UTILS_OUTSIDE_CONTEXT, "Cannot call injection utilities outside of an injection context.");
215
+ }
216
+ static instanceAccessFailed(token) {
217
+ return new _InjectionError(ERR_CODES.INSTANCE_ACCESS_FAILED, `Failed to access instance for token "${token.toString()}". It was not properly instantiated.`);
218
+ }
219
+ static accessFailed() {
220
+ return new _InjectionError(ERR_CODES.ACCESS_FAILED, "Failed to access the requested instance due to an unknown error.");
221
+ }
222
+ };
223
+ function isNotFoundError(error) {
224
+ return error instanceof InjectionError && error.code === ERR_CODES.NOT_FOUND;
225
+ }
226
+ __name(isNotFoundError, "isNotFoundError");
227
+
198
228
  // src/lib/api/decorator.ts
229
+ var tokenRegistry = /* @__PURE__ */ new WeakMap();
199
230
  var INJECTION_SYMBOL = Symbol("Injectable");
200
231
  function NodeInjectable() {
201
232
  return (ctor) => {
202
233
  const nodeToken = new NodeToken(`_${ctor.name}`, {
203
234
  factory: /* @__PURE__ */ __name(() => new ctor(), "factory")
204
235
  });
205
- ctor[INJECTION_SYMBOL] = nodeToken;
236
+ registerClassAsInjectable(ctor, nodeToken);
206
237
  return ctor;
207
238
  };
208
239
  }
@@ -211,22 +242,30 @@ function makeInjectable(ctor) {
211
242
  const nodeToken = new NodeToken(`_${ctor.name}`, {
212
243
  factory: /* @__PURE__ */ __name(() => new ctor(), "factory")
213
244
  });
214
- ctor[INJECTION_SYMBOL] = nodeToken;
245
+ registerClassAsInjectable(ctor, nodeToken);
215
246
  return ctor;
216
247
  }
217
248
  __name(makeInjectable, "makeInjectable");
218
249
  function isInjectable(ctor) {
219
- return typeof ctor === "function" && isConstructor(ctor) && INJECTION_SYMBOL in ctor && ctor[INJECTION_SYMBOL] instanceof NodeToken;
250
+ return typeof ctor === "function" && isConstructor(ctor) && (tokenRegistry.has(ctor) || INJECTION_SYMBOL in ctor);
220
251
  }
221
252
  __name(isInjectable, "isInjectable");
222
253
  function getInjectableToken(ctor) {
223
- return ctor[INJECTION_SYMBOL];
254
+ if (tokenRegistry.has(ctor)) return tokenRegistry.get(ctor);
255
+ if (INJECTION_SYMBOL in ctor) {
256
+ return ctor[INJECTION_SYMBOL];
257
+ }
258
+ throw InjectionError.invalidCtor(ctor);
224
259
  }
225
260
  __name(getInjectableToken, "getInjectableToken");
226
261
  function isConstructor(fn) {
227
262
  return typeof fn === "function" && fn.prototype && fn.prototype.constructor === fn;
228
263
  }
229
264
  __name(isConstructor, "isConstructor");
265
+ function registerClassAsInjectable(ctor, token) {
266
+ tokenRegistry.set(ctor, token);
267
+ }
268
+ __name(registerClassAsInjectable, "registerClassAsInjectable");
230
269
 
231
270
  // src/lib/plugins/core/plugin-container.ts
232
271
  var Illuma = class _Illuma {
@@ -478,23 +517,29 @@ var TreeRootNode = class {
478
517
  static {
479
518
  __name(this, "TreeRootNode");
480
519
  }
520
+ instant;
481
521
  _deps = /* @__PURE__ */ new Set();
482
- _treePool = /* @__PURE__ */ new Map();
522
+ _treePool = /* @__PURE__ */ new WeakMap();
523
+ constructor(instant = true) {
524
+ this.instant = instant;
525
+ }
483
526
  get dependencies() {
484
527
  return this._deps;
485
528
  }
486
529
  addDependency(node) {
487
530
  this._deps.add(node);
488
531
  }
489
- instantiate() {
532
+ build() {
490
533
  for (const dep of this._deps) {
491
- dep.instantiate(this._treePool);
492
534
  if ("token" in dep.proto) this._treePool.set(dep.proto.token, dep);
535
+ if (this.instant) dep.instantiate(this._treePool);
536
+ else dep.collectPool(this._treePool);
493
537
  }
494
538
  }
495
539
  find(token) {
496
540
  const node = this._treePool.get(token);
497
541
  if (!node) return null;
542
+ if (!this.instant) node.instantiate(this._treePool);
498
543
  return node;
499
544
  }
500
545
  toString() {
@@ -525,6 +570,11 @@ var TreeNodeSingle = class {
525
570
  else this._deps.set(node.proto.token, node);
526
571
  node.allocations++;
527
572
  }
573
+ collectPool(pool) {
574
+ for (const node of this._deps.values()) node.collectPool(pool);
575
+ for (const dep of this._transparent) dep.collectPool(pool);
576
+ pool.set(this.proto.token, this);
577
+ }
528
578
  instantiate(pool) {
529
579
  if (this._resolved) return;
530
580
  for (const node of this._deps.values()) node.instantiate(pool);
@@ -562,6 +612,10 @@ var TreeNodeTransparent = class _TreeNodeTransparent {
562
612
  else this._deps.set(node.proto.token, node);
563
613
  node.allocations++;
564
614
  }
615
+ collectPool(pool) {
616
+ for (const node of this._deps.values()) node.collectPool(pool);
617
+ for (const dep of this._transparent) dep.collectPool(pool);
618
+ }
565
619
  instantiate(pool) {
566
620
  if (this._resolved) return;
567
621
  for (const dep of this._transparent) dep.instantiate(pool);
@@ -586,6 +640,10 @@ var TreeNodeMulti = class _TreeNodeMulti {
586
640
  constructor(proto) {
587
641
  this.proto = proto;
588
642
  }
643
+ collectPool(pool) {
644
+ for (const dep of this._deps) dep.collectPool(pool);
645
+ pool.set(this.proto.token, this);
646
+ }
589
647
  instantiate(pool) {
590
648
  if (this._resolved) return;
591
649
  for (const dep of this._deps) {
@@ -762,6 +820,37 @@ var InjectorImpl = class {
762
820
  };
763
821
  var Injector = new NodeToken("Injector");
764
822
 
823
+ // src/lib/utils/defer.ts
824
+ function injectDefer(provider, options) {
825
+ const injector = nodeInject(Injector);
826
+ let token = provider;
827
+ if (isInjectable(provider)) token = getInjectableToken(provider);
828
+ if (!isNodeBase(token)) throw InjectionError.invalidProvider(String(token));
829
+ let resolved = false;
830
+ let instance = SHAPE_SHIFTER;
831
+ return () => {
832
+ if (resolved) return instance;
833
+ if (options?.optional) {
834
+ try {
835
+ instance = injector.get(token);
836
+ resolved = true;
837
+ return instance;
838
+ } catch (e) {
839
+ if (isNotFoundError(e)) {
840
+ resolved = true;
841
+ instance = null;
842
+ return instance;
843
+ }
844
+ throw e;
845
+ }
846
+ }
847
+ instance = injector.get(token);
848
+ resolved = true;
849
+ return instance;
850
+ };
851
+ }
852
+ __name(injectDefer, "injectDefer");
853
+
765
854
  // src/lib/utils/inheritance.ts
766
855
  function injectGroupAsync(fn, opts) {
767
856
  const { container: parent } = nodeInject(Injector);
@@ -956,7 +1045,7 @@ var NodeContainer = class extends Illuma {
956
1045
  return parentNode.findNode(token);
957
1046
  }
958
1047
  _buildInjectionTree() {
959
- const root = new TreeRootNode();
1048
+ const root = new TreeRootNode(this._opts?.instant);
960
1049
  const cache = /* @__PURE__ */ new Map();
961
1050
  const nodes = [
962
1051
  ...this._protoNodes.values(),
@@ -1001,7 +1090,7 @@ var NodeContainer = class extends Illuma {
1001
1090
  value: new InjectorImpl(this)
1002
1091
  });
1003
1092
  this._rootNode = this._buildInjectionTree();
1004
- this._rootNode.instantiate();
1093
+ this._rootNode.build();
1005
1094
  this._bootstrapped = true;
1006
1095
  const end = performance.now();
1007
1096
  const duration = end - start;
@@ -1072,6 +1161,7 @@ var NodeContainer = class extends Illuma {
1072
1161
  };
1073
1162
  // Annotate the CommonJS export names for ESM import in node:
1074
1163
  0 && (module.exports = {
1164
+ ILLUMA_ERR_CODES,
1075
1165
  INJECTION_SYMBOL,
1076
1166
  InjectionContext,
1077
1167
  InjectionError,
@@ -1085,12 +1175,14 @@ var NodeContainer = class extends Illuma {
1085
1175
  extractToken,
1086
1176
  getInjectableToken,
1087
1177
  injectAsync,
1178
+ injectDefer,
1088
1179
  injectEntryAsync,
1089
1180
  injectGroupAsync,
1090
1181
  isConstructor,
1091
1182
  isInjectable,
1092
1183
  isNodeBase,
1093
1184
  makeInjectable,
1094
- nodeInject
1185
+ nodeInject,
1186
+ registerClassAsInjectable
1095
1187
  });
1096
1188
  //# sourceMappingURL=index.cjs.map