@illuma/core 1.3.1 → 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/dist/testkit.js CHANGED
@@ -1,5 +1,171 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
2
5
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ var __esm = (fn, res) => function __init() {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ };
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+
23
+ // src/lib/plugins/core/plugin-container.ts
24
+ var Illuma;
25
+ var init_plugin_container = __esm({
26
+ "src/lib/plugins/core/plugin-container.ts"() {
27
+ "use strict";
28
+ Illuma = class _Illuma {
29
+ static {
30
+ __name(this, "Illuma");
31
+ }
32
+ static _diagnostics = /* @__PURE__ */ new Set();
33
+ static _scanners = [];
34
+ static _middlewares = [];
35
+ /** @internal */
36
+ static get contextScanners() {
37
+ return _Illuma._scanners;
38
+ }
39
+ /**
40
+ * Extends the diagnostics with a new diagnostics module.
41
+ * These will be run on diagnostics reports after container bootstrap.
42
+ *
43
+ * @param m - The diagnostics module instance to add
44
+ */
45
+ static extendDiagnostics(m) {
46
+ _Illuma._diagnostics.add(m);
47
+ }
48
+ /**
49
+ * Extends the context scanners with a new context scanner.
50
+ * These will be run in injection context scans to detect additional injections (alongside `nodeInject` calls).
51
+ *
52
+ * @param scanner - The context scanner instance to add
53
+ */
54
+ static extendContextScanner(scanner) {
55
+ _Illuma._scanners.push(scanner);
56
+ }
57
+ /**
58
+ * Registers a global middleware to be applied during instance creation.
59
+ * Typically used for cross-cutting concerns like logging, profiling, or custom instantiation logic.
60
+ * Function should accept instantiation parameters and a `next` function to proceed with the next middleware or actual instantiation.
61
+ *
62
+ * @param m - The middleware function to register
63
+ */
64
+ static registerGlobalMiddleware(m) {
65
+ _Illuma._middlewares.push(m);
66
+ }
67
+ middlewares = [];
68
+ registerMiddleware(m) {
69
+ this.middlewares.push(m);
70
+ }
71
+ static onReport(report) {
72
+ for (const diag of _Illuma._diagnostics) diag.onReport(report);
73
+ }
74
+ /**
75
+ * @internal
76
+ * Check if diagnostics modules are registered
77
+ */
78
+ static hasDiagnostics() {
79
+ return _Illuma._diagnostics.size > 0;
80
+ }
81
+ /**
82
+ * @internal
83
+ * Reset all plugin registrations
84
+ */
85
+ static __resetPlugins() {
86
+ _Illuma._diagnostics.clear();
87
+ _Illuma._scanners.length = 0;
88
+ _Illuma._middlewares.length = 0;
89
+ }
90
+ };
91
+ }
92
+ });
93
+
94
+ // src/lib/plugins/core/index.ts
95
+ var init_core = __esm({
96
+ "src/lib/plugins/core/index.ts"() {
97
+ "use strict";
98
+ init_plugin_container();
99
+ }
100
+ });
101
+
102
+ // src/lib/plugins/middlewares/diagnostics.middleware.ts
103
+ var performanceDiagnostics;
104
+ var init_diagnostics_middleware = __esm({
105
+ "src/lib/plugins/middlewares/diagnostics.middleware.ts"() {
106
+ "use strict";
107
+ performanceDiagnostics = /* @__PURE__ */ __name((params, next) => {
108
+ if (!params.deps.size) {
109
+ return next(params);
110
+ }
111
+ const start = performance.now();
112
+ const instance = next(params);
113
+ const end = performance.now();
114
+ const duration = end - start;
115
+ console.log(`Instantiated ${params.token.name} in ${duration.toFixed(2)} ms`);
116
+ return instance;
117
+ }, "performanceDiagnostics");
118
+ }
119
+ });
120
+
121
+ // src/lib/plugins/diagnostics/default-impl.ts
122
+ var DiagnosticsDefaultReporter;
123
+ var init_default_impl = __esm({
124
+ "src/lib/plugins/diagnostics/default-impl.ts"() {
125
+ "use strict";
126
+ DiagnosticsDefaultReporter = class {
127
+ static {
128
+ __name(this, "DiagnosticsDefaultReporter");
129
+ }
130
+ onReport(report) {
131
+ console.log("[Illuma] \u{1F9F9} Diagnostics:");
132
+ console.log(` Total: ${report.totalNodes} node(s)`);
133
+ console.log(` ${report.unusedNodes.length} were not used while bootstrap:`);
134
+ for (const node of report.unusedNodes) console.log(` - ${node.toString()}`);
135
+ }
136
+ };
137
+ }
138
+ });
139
+
140
+ // src/lib/plugins/diagnostics/built-in.ts
141
+ var built_in_exports = {};
142
+ __export(built_in_exports, {
143
+ __resetDiagnosticsState: () => __resetDiagnosticsState,
144
+ enableIllumaDiagnostics: () => enableIllumaDiagnostics
145
+ });
146
+ function enableIllumaDiagnostics() {
147
+ if (state.enabled) return;
148
+ state.enabled = true;
149
+ Illuma.extendDiagnostics(new DiagnosticsDefaultReporter());
150
+ Illuma.registerGlobalMiddleware(performanceDiagnostics);
151
+ }
152
+ function __resetDiagnosticsState() {
153
+ state.enabled = false;
154
+ }
155
+ var state;
156
+ var init_built_in = __esm({
157
+ "src/lib/plugins/diagnostics/built-in.ts"() {
158
+ "use strict";
159
+ init_core();
160
+ init_diagnostics_middleware();
161
+ init_default_impl();
162
+ state = {
163
+ enabled: false
164
+ };
165
+ __name(enableIllumaDiagnostics, "enableIllumaDiagnostics");
166
+ __name(__resetDiagnosticsState, "__resetDiagnosticsState");
167
+ }
168
+ });
3
169
 
4
170
  // src/lib/api/token.ts
5
171
  var NodeBase = class {
@@ -195,41 +361,8 @@ function isConstructor(fn) {
195
361
  }
196
362
  __name(isConstructor, "isConstructor");
197
363
 
198
- // src/lib/plugins/core/plugin-container.ts
199
- var Illuma = class _Illuma {
200
- static {
201
- __name(this, "Illuma");
202
- }
203
- static _diagnostics = [];
204
- static _scanners = [];
205
- /** @internal */
206
- static get contextScanners() {
207
- return _Illuma._scanners;
208
- }
209
- /**
210
- * Extends the diagnostics with a new diagnostics module.
211
- * These will be run on diagnostics reports after container bootstrap.
212
- *
213
- * @param m - The diagnostics module instance to add
214
- */
215
- static extendDiagnostics(m) {
216
- _Illuma._diagnostics.push(m);
217
- }
218
- /**
219
- * Extends the context scanners with a new context scanner.
220
- * These will be run in injection context scans to detect additional injections (alongside `nodeInject` calls).
221
- *
222
- * @param scanner - The context scanner instance to add
223
- */
224
- static extendContextScanner(scanner) {
225
- _Illuma._scanners.push(scanner);
226
- }
227
- static onReport(report) {
228
- for (const diag of _Illuma._diagnostics) diag.onReport(report);
229
- }
230
- };
231
-
232
364
  // src/lib/context/context.ts
365
+ init_plugin_container();
233
366
  var InjectionContext = class _InjectionContext {
234
367
  static {
235
368
  __name(this, "InjectionContext");
@@ -329,18 +462,8 @@ function nodeInject(provider, options) {
329
462
  }
330
463
  __name(nodeInject, "nodeInject");
331
464
 
332
- // src/lib/plugins/diagnostics/default-impl.ts
333
- var DiagnosticsDefaultReporter = class {
334
- static {
335
- __name(this, "DiagnosticsDefaultReporter");
336
- }
337
- onReport(report) {
338
- console.log("[Illuma] \u{1F9F9} Diagnostics:");
339
- console.log(` Total: ${report.totalNodes} node(s)`);
340
- console.log(` ${report.unusedNodes.length} were not used while bootstrap:`);
341
- for (const node of report.unusedNodes) console.log(` - ${node.toString()}`);
342
- }
343
- };
465
+ // src/lib/container/container.ts
466
+ init_plugin_container();
344
467
 
345
468
  // src/lib/provider/extractor.ts
346
469
  function extractProvider(provider) {
@@ -428,7 +551,34 @@ function isNotTransparentProto(proto) {
428
551
  }
429
552
  __name(isNotTransparentProto, "isNotTransparentProto");
430
553
 
554
+ // src/lib/utils/injector.ts
555
+ var InjectorImpl = class {
556
+ static {
557
+ __name(this, "InjectorImpl");
558
+ }
559
+ container;
560
+ constructor(container) {
561
+ this.container = container;
562
+ }
563
+ get(token) {
564
+ return this.container.get(token);
565
+ }
566
+ produce(fn) {
567
+ return this.container.produce(fn);
568
+ }
569
+ };
570
+ var Injector = new NodeToken("Injector");
571
+
431
572
  // src/lib/provider/tree-node.ts
573
+ function runMiddlewares(middlewares, params) {
574
+ const ms = middlewares;
575
+ const next = /* @__PURE__ */ __name((i, current) => {
576
+ if (i >= ms.length) return current.factory();
577
+ return ms[i](current, (nextParams) => next(i + 1, nextParams));
578
+ }, "next");
579
+ return next(0, params);
580
+ }
581
+ __name(runMiddlewares, "runMiddlewares");
432
582
  function retrieverFactory(node, deps, transparentDeps) {
433
583
  return (token, optional) => {
434
584
  const depNode = deps.get(token);
@@ -446,10 +596,12 @@ var TreeRootNode = class {
446
596
  __name(this, "TreeRootNode");
447
597
  }
448
598
  instant;
599
+ middlewares;
449
600
  _deps = /* @__PURE__ */ new Set();
450
601
  _treePool = /* @__PURE__ */ new WeakMap();
451
- constructor(instant = true) {
602
+ constructor(instant = true, middlewares = []) {
452
603
  this.instant = instant;
604
+ this.middlewares = middlewares;
453
605
  }
454
606
  get dependencies() {
455
607
  return this._deps;
@@ -460,14 +612,14 @@ var TreeRootNode = class {
460
612
  build() {
461
613
  for (const dep of this._deps) {
462
614
  if ("token" in dep.proto) this._treePool.set(dep.proto.token, dep);
463
- if (this.instant) dep.instantiate(this._treePool);
615
+ if (this.instant) dep.instantiate(this._treePool, this.middlewares);
464
616
  else dep.collectPool(this._treePool);
465
617
  }
466
618
  }
467
619
  find(token) {
468
620
  const node = this._treePool.get(token);
469
621
  if (!node) return null;
470
- if (!this.instant) node.instantiate(this._treePool);
622
+ if (!this.instant) node.instantiate(this._treePool, this.middlewares);
471
623
  return node;
472
624
  }
473
625
  toString() {
@@ -492,6 +644,10 @@ var TreeNodeSingle = class {
492
644
  }
493
645
  constructor(proto) {
494
646
  this.proto = proto;
647
+ if (proto.token === Injector) {
648
+ this._instance = proto.factory();
649
+ this._resolved = true;
650
+ }
495
651
  }
496
652
  addDependency(node) {
497
653
  if (node instanceof TreeNodeTransparent) this._transparent.add(node);
@@ -503,14 +659,22 @@ var TreeNodeSingle = class {
503
659
  for (const dep of this._transparent) dep.collectPool(pool);
504
660
  pool.set(this.proto.token, this);
505
661
  }
506
- instantiate(pool) {
662
+ instantiate(pool, middlewares = []) {
507
663
  if (this._resolved) return;
508
- for (const node of this._deps.values()) node.instantiate(pool);
509
- for (const dep of this._transparent) dep.instantiate(pool);
664
+ for (const node of this._deps.values()) node.instantiate(pool, middlewares);
665
+ for (const dep of this._transparent) dep.instantiate(pool, middlewares);
510
666
  const retriever = retrieverFactory(this.proto.token, this._deps, this._transparent);
511
667
  const factory = this.proto.factory ?? this.proto.token.opts?.factory;
512
668
  if (!factory) throw InjectionError.notFound(this.proto.token);
513
- this._instance = InjectionContext.instantiate(factory, retriever);
669
+ const contextFactory = /* @__PURE__ */ __name(() => InjectionContext.instantiate(factory, retriever), "contextFactory");
670
+ this._instance = runMiddlewares(middlewares, {
671
+ token: this.proto.token,
672
+ factory: contextFactory,
673
+ deps: /* @__PURE__ */ new Set([
674
+ ...this._deps.keys(),
675
+ ...Array.from(this._transparent).map((n) => n.proto.parent.token)
676
+ ])
677
+ });
514
678
  this._resolved = true;
515
679
  if (pool) pool.set(this.proto.token, this);
516
680
  }
@@ -544,12 +708,20 @@ var TreeNodeTransparent = class _TreeNodeTransparent {
544
708
  for (const node of this._deps.values()) node.collectPool(pool);
545
709
  for (const dep of this._transparent) dep.collectPool(pool);
546
710
  }
547
- instantiate(pool) {
711
+ instantiate(pool, middlewares = []) {
548
712
  if (this._resolved) return;
549
- for (const dep of this._transparent) dep.instantiate(pool);
550
- for (const node of this._deps.values()) node.instantiate(pool);
713
+ for (const dep of this._transparent) dep.instantiate(pool, middlewares);
714
+ for (const node of this._deps.values()) node.instantiate(pool, middlewares);
551
715
  const retriever = retrieverFactory(this.proto.parent.token, this._deps, this._transparent);
552
- this._instance = InjectionContext.instantiate(this.proto.factory, retriever);
716
+ const refFactory = /* @__PURE__ */ __name(() => InjectionContext.instantiate(this.proto.factory, retriever), "refFactory");
717
+ this._instance = runMiddlewares(middlewares, {
718
+ token: this.proto.parent.token,
719
+ factory: refFactory,
720
+ deps: /* @__PURE__ */ new Set([
721
+ ...this._deps.keys(),
722
+ ...Array.from(this._transparent).map((n) => n.proto.parent.token)
723
+ ])
724
+ });
553
725
  this._resolved = true;
554
726
  }
555
727
  toString() {
@@ -572,10 +744,10 @@ var TreeNodeMulti = class _TreeNodeMulti {
572
744
  for (const dep of this._deps) dep.collectPool(pool);
573
745
  pool.set(this.proto.token, this);
574
746
  }
575
- instantiate(pool) {
747
+ instantiate(pool, middlewares = []) {
576
748
  if (this._resolved) return;
577
749
  for (const dep of this._deps) {
578
- dep.instantiate(pool);
750
+ dep.instantiate(pool, middlewares);
579
751
  if (dep instanceof TreeNodeSingle) {
580
752
  this.instance.push(dep.instance);
581
753
  } else if (dep instanceof _TreeNodeMulti) {
@@ -730,24 +902,6 @@ function resolveTreeNode(rootProto, cache, singleNodes, multiNodes, upstreamGett
730
902
  }
731
903
  __name(resolveTreeNode, "resolveTreeNode");
732
904
 
733
- // src/lib/utils/injector.ts
734
- var InjectorImpl = class {
735
- static {
736
- __name(this, "InjectorImpl");
737
- }
738
- container;
739
- constructor(container) {
740
- this.container = container;
741
- }
742
- get(token) {
743
- return this.container.get(token);
744
- }
745
- produce(fn) {
746
- return this.container.produce(fn);
747
- }
748
- };
749
- var Injector = new NodeToken("Injector");
750
-
751
905
  // src/lib/container/container.ts
752
906
  var NodeContainer = class extends Illuma {
753
907
  static {
@@ -761,10 +915,13 @@ var NodeContainer = class extends Illuma {
761
915
  _multiProtoNodes = /* @__PURE__ */ new Map();
762
916
  constructor(_opts) {
763
917
  super(), this._opts = _opts;
764
- this._parent = _opts?.parent;
765
918
  if (_opts?.diagnostics) {
766
- Illuma.extendDiagnostics(new DiagnosticsDefaultReporter());
919
+ console.warn("[Illuma] Deprecation Warning: The 'diagnostics' option in iContainerOptions is deprecated and will be removed in future versions. Please use the `enableIllumaDiagnostics` from '@illuma/core/plugins` instead.");
920
+ const m = (init_built_in(), __toCommonJS(built_in_exports));
921
+ if (m.enabled) return;
922
+ m.enableIllumaDiagnostics();
767
923
  }
924
+ this._parent = _opts?.parent;
768
925
  }
769
926
  /**
770
927
  * Registers a provider in the container.
@@ -877,7 +1034,11 @@ var NodeContainer = class extends Illuma {
877
1034
  return parentNode.findNode(token);
878
1035
  }
879
1036
  _buildInjectionTree() {
880
- const root = new TreeRootNode(this._opts?.instant);
1037
+ const middlewares = [
1038
+ ...Illuma._middlewares,
1039
+ ...this.collectMiddlewares()
1040
+ ];
1041
+ const root = new TreeRootNode(this._opts?.instant, middlewares);
881
1042
  const cache = /* @__PURE__ */ new Map();
882
1043
  const nodes = [
883
1044
  ...this._protoNodes.values(),
@@ -894,6 +1055,12 @@ var NodeContainer = class extends Illuma {
894
1055
  this._multiProtoNodes.clear();
895
1056
  return root;
896
1057
  }
1058
+ collectMiddlewares() {
1059
+ return [
1060
+ ...this._parent && "collectMiddlewares" in this._parent && typeof this._parent.collectMiddlewares === "function" ? this._parent.collectMiddlewares() : [],
1061
+ ...this.middlewares
1062
+ ];
1063
+ }
897
1064
  /**
898
1065
  * Bootstraps the container by resolving the dependency trees and instantiating all providers.
899
1066
  * This must be called after all providers are registered and before calling {@link get}.
@@ -929,7 +1096,7 @@ var NodeContainer = class extends Illuma {
929
1096
  if (this._opts?.measurePerformance) {
930
1097
  console.log(`[Illuma] \u{1F680} Bootstrapped in ${duration.toFixed(2)} ms`);
931
1098
  }
932
- if (this._opts?.diagnostics) {
1099
+ if (this._opts?.diagnostics || Illuma.hasDiagnostics()) {
933
1100
  const allNodes = this._rootNode.dependencies.size;
934
1101
  const unusedNodes = Array.from(this._rootNode.dependencies).filter((node) => node.allocations === 0).filter((node) => {
935
1102
  if (!(node.proto instanceof ProtoNodeSingle)) return true;