@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.cjs CHANGED
@@ -4,6 +4,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
6
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __esm = (fn, res) => function __init() {
8
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
9
+ };
7
10
  var __export = (target, all) => {
8
11
  for (var name in all)
9
12
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -18,6 +21,153 @@ var __copyProps = (to, from, except, desc) => {
18
21
  };
19
22
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
23
 
24
+ // src/lib/plugins/core/plugin-container.ts
25
+ var Illuma;
26
+ var init_plugin_container = __esm({
27
+ "src/lib/plugins/core/plugin-container.ts"() {
28
+ "use strict";
29
+ Illuma = class _Illuma {
30
+ static {
31
+ __name(this, "Illuma");
32
+ }
33
+ static _diagnostics = /* @__PURE__ */ new Set();
34
+ static _scanners = [];
35
+ static _middlewares = [];
36
+ /** @internal */
37
+ static get contextScanners() {
38
+ return _Illuma._scanners;
39
+ }
40
+ /**
41
+ * Extends the diagnostics with a new diagnostics module.
42
+ * These will be run on diagnostics reports after container bootstrap.
43
+ *
44
+ * @param m - The diagnostics module instance to add
45
+ */
46
+ static extendDiagnostics(m) {
47
+ _Illuma._diagnostics.add(m);
48
+ }
49
+ /**
50
+ * Extends the context scanners with a new context scanner.
51
+ * These will be run in injection context scans to detect additional injections (alongside `nodeInject` calls).
52
+ *
53
+ * @param scanner - The context scanner instance to add
54
+ */
55
+ static extendContextScanner(scanner) {
56
+ _Illuma._scanners.push(scanner);
57
+ }
58
+ /**
59
+ * Registers a global middleware to be applied during instance creation.
60
+ * Typically used for cross-cutting concerns like logging, profiling, or custom instantiation logic.
61
+ * Function should accept instantiation parameters and a `next` function to proceed with the next middleware or actual instantiation.
62
+ *
63
+ * @param m - The middleware function to register
64
+ */
65
+ static registerGlobalMiddleware(m) {
66
+ _Illuma._middlewares.push(m);
67
+ }
68
+ middlewares = [];
69
+ registerMiddleware(m) {
70
+ this.middlewares.push(m);
71
+ }
72
+ static onReport(report) {
73
+ for (const diag of _Illuma._diagnostics) diag.onReport(report);
74
+ }
75
+ /**
76
+ * @internal
77
+ * Check if diagnostics modules are registered
78
+ */
79
+ static hasDiagnostics() {
80
+ return _Illuma._diagnostics.size > 0;
81
+ }
82
+ /**
83
+ * @internal
84
+ * Reset all plugin registrations
85
+ */
86
+ static __resetPlugins() {
87
+ _Illuma._diagnostics.clear();
88
+ _Illuma._scanners.length = 0;
89
+ _Illuma._middlewares.length = 0;
90
+ }
91
+ };
92
+ }
93
+ });
94
+
95
+ // src/lib/plugins/core/index.ts
96
+ var init_core = __esm({
97
+ "src/lib/plugins/core/index.ts"() {
98
+ "use strict";
99
+ init_plugin_container();
100
+ }
101
+ });
102
+
103
+ // src/lib/plugins/middlewares/diagnostics.middleware.ts
104
+ var performanceDiagnostics;
105
+ var init_diagnostics_middleware = __esm({
106
+ "src/lib/plugins/middlewares/diagnostics.middleware.ts"() {
107
+ "use strict";
108
+ performanceDiagnostics = /* @__PURE__ */ __name((params, next) => {
109
+ if (!params.deps.size) {
110
+ return next(params);
111
+ }
112
+ const start = performance.now();
113
+ const instance = next(params);
114
+ const end = performance.now();
115
+ const duration = end - start;
116
+ console.log(`Instantiated ${params.token.name} in ${duration.toFixed(2)} ms`);
117
+ return instance;
118
+ }, "performanceDiagnostics");
119
+ }
120
+ });
121
+
122
+ // src/lib/plugins/diagnostics/default-impl.ts
123
+ var DiagnosticsDefaultReporter;
124
+ var init_default_impl = __esm({
125
+ "src/lib/plugins/diagnostics/default-impl.ts"() {
126
+ "use strict";
127
+ DiagnosticsDefaultReporter = class {
128
+ static {
129
+ __name(this, "DiagnosticsDefaultReporter");
130
+ }
131
+ onReport(report) {
132
+ console.log("[Illuma] \u{1F9F9} Diagnostics:");
133
+ console.log(` Total: ${report.totalNodes} node(s)`);
134
+ console.log(` ${report.unusedNodes.length} were not used while bootstrap:`);
135
+ for (const node of report.unusedNodes) console.log(` - ${node.toString()}`);
136
+ }
137
+ };
138
+ }
139
+ });
140
+
141
+ // src/lib/plugins/diagnostics/built-in.ts
142
+ var built_in_exports = {};
143
+ __export(built_in_exports, {
144
+ __resetDiagnosticsState: () => __resetDiagnosticsState,
145
+ enableIllumaDiagnostics: () => enableIllumaDiagnostics
146
+ });
147
+ function enableIllumaDiagnostics() {
148
+ if (state.enabled) return;
149
+ state.enabled = true;
150
+ Illuma.extendDiagnostics(new DiagnosticsDefaultReporter());
151
+ Illuma.registerGlobalMiddleware(performanceDiagnostics);
152
+ }
153
+ function __resetDiagnosticsState() {
154
+ state.enabled = false;
155
+ }
156
+ var state;
157
+ var init_built_in = __esm({
158
+ "src/lib/plugins/diagnostics/built-in.ts"() {
159
+ "use strict";
160
+ init_core();
161
+ init_diagnostics_middleware();
162
+ init_default_impl();
163
+ state = {
164
+ enabled: false
165
+ };
166
+ __name(enableIllumaDiagnostics, "enableIllumaDiagnostics");
167
+ __name(__resetDiagnosticsState, "__resetDiagnosticsState");
168
+ }
169
+ });
170
+
21
171
  // src/testkit.ts
22
172
  var testkit_exports = {};
23
173
  __export(testkit_exports, {
@@ -219,41 +369,8 @@ function isConstructor(fn) {
219
369
  }
220
370
  __name(isConstructor, "isConstructor");
221
371
 
222
- // src/lib/plugins/core/plugin-container.ts
223
- var Illuma = class _Illuma {
224
- static {
225
- __name(this, "Illuma");
226
- }
227
- static _diagnostics = [];
228
- static _scanners = [];
229
- /** @internal */
230
- static get contextScanners() {
231
- return _Illuma._scanners;
232
- }
233
- /**
234
- * Extends the diagnostics with a new diagnostics module.
235
- * These will be run on diagnostics reports after container bootstrap.
236
- *
237
- * @param m - The diagnostics module instance to add
238
- */
239
- static extendDiagnostics(m) {
240
- _Illuma._diagnostics.push(m);
241
- }
242
- /**
243
- * Extends the context scanners with a new context scanner.
244
- * These will be run in injection context scans to detect additional injections (alongside `nodeInject` calls).
245
- *
246
- * @param scanner - The context scanner instance to add
247
- */
248
- static extendContextScanner(scanner) {
249
- _Illuma._scanners.push(scanner);
250
- }
251
- static onReport(report) {
252
- for (const diag of _Illuma._diagnostics) diag.onReport(report);
253
- }
254
- };
255
-
256
372
  // src/lib/context/context.ts
373
+ init_plugin_container();
257
374
  var InjectionContext = class _InjectionContext {
258
375
  static {
259
376
  __name(this, "InjectionContext");
@@ -353,18 +470,8 @@ function nodeInject(provider, options) {
353
470
  }
354
471
  __name(nodeInject, "nodeInject");
355
472
 
356
- // src/lib/plugins/diagnostics/default-impl.ts
357
- var DiagnosticsDefaultReporter = class {
358
- static {
359
- __name(this, "DiagnosticsDefaultReporter");
360
- }
361
- onReport(report) {
362
- console.log("[Illuma] \u{1F9F9} Diagnostics:");
363
- console.log(` Total: ${report.totalNodes} node(s)`);
364
- console.log(` ${report.unusedNodes.length} were not used while bootstrap:`);
365
- for (const node of report.unusedNodes) console.log(` - ${node.toString()}`);
366
- }
367
- };
473
+ // src/lib/container/container.ts
474
+ init_plugin_container();
368
475
 
369
476
  // src/lib/provider/extractor.ts
370
477
  function extractProvider(provider) {
@@ -452,7 +559,34 @@ function isNotTransparentProto(proto) {
452
559
  }
453
560
  __name(isNotTransparentProto, "isNotTransparentProto");
454
561
 
562
+ // src/lib/utils/injector.ts
563
+ var InjectorImpl = class {
564
+ static {
565
+ __name(this, "InjectorImpl");
566
+ }
567
+ container;
568
+ constructor(container) {
569
+ this.container = container;
570
+ }
571
+ get(token) {
572
+ return this.container.get(token);
573
+ }
574
+ produce(fn) {
575
+ return this.container.produce(fn);
576
+ }
577
+ };
578
+ var Injector = new NodeToken("Injector");
579
+
455
580
  // src/lib/provider/tree-node.ts
581
+ function runMiddlewares(middlewares, params) {
582
+ const ms = middlewares;
583
+ const next = /* @__PURE__ */ __name((i, current) => {
584
+ if (i >= ms.length) return current.factory();
585
+ return ms[i](current, (nextParams) => next(i + 1, nextParams));
586
+ }, "next");
587
+ return next(0, params);
588
+ }
589
+ __name(runMiddlewares, "runMiddlewares");
456
590
  function retrieverFactory(node, deps, transparentDeps) {
457
591
  return (token, optional) => {
458
592
  const depNode = deps.get(token);
@@ -470,10 +604,12 @@ var TreeRootNode = class {
470
604
  __name(this, "TreeRootNode");
471
605
  }
472
606
  instant;
607
+ middlewares;
473
608
  _deps = /* @__PURE__ */ new Set();
474
609
  _treePool = /* @__PURE__ */ new WeakMap();
475
- constructor(instant = true) {
610
+ constructor(instant = true, middlewares = []) {
476
611
  this.instant = instant;
612
+ this.middlewares = middlewares;
477
613
  }
478
614
  get dependencies() {
479
615
  return this._deps;
@@ -484,14 +620,14 @@ var TreeRootNode = class {
484
620
  build() {
485
621
  for (const dep of this._deps) {
486
622
  if ("token" in dep.proto) this._treePool.set(dep.proto.token, dep);
487
- if (this.instant) dep.instantiate(this._treePool);
623
+ if (this.instant) dep.instantiate(this._treePool, this.middlewares);
488
624
  else dep.collectPool(this._treePool);
489
625
  }
490
626
  }
491
627
  find(token) {
492
628
  const node = this._treePool.get(token);
493
629
  if (!node) return null;
494
- if (!this.instant) node.instantiate(this._treePool);
630
+ if (!this.instant) node.instantiate(this._treePool, this.middlewares);
495
631
  return node;
496
632
  }
497
633
  toString() {
@@ -516,6 +652,10 @@ var TreeNodeSingle = class {
516
652
  }
517
653
  constructor(proto) {
518
654
  this.proto = proto;
655
+ if (proto.token === Injector) {
656
+ this._instance = proto.factory();
657
+ this._resolved = true;
658
+ }
519
659
  }
520
660
  addDependency(node) {
521
661
  if (node instanceof TreeNodeTransparent) this._transparent.add(node);
@@ -527,14 +667,22 @@ var TreeNodeSingle = class {
527
667
  for (const dep of this._transparent) dep.collectPool(pool);
528
668
  pool.set(this.proto.token, this);
529
669
  }
530
- instantiate(pool) {
670
+ instantiate(pool, middlewares = []) {
531
671
  if (this._resolved) return;
532
- for (const node of this._deps.values()) node.instantiate(pool);
533
- for (const dep of this._transparent) dep.instantiate(pool);
672
+ for (const node of this._deps.values()) node.instantiate(pool, middlewares);
673
+ for (const dep of this._transparent) dep.instantiate(pool, middlewares);
534
674
  const retriever = retrieverFactory(this.proto.token, this._deps, this._transparent);
535
675
  const factory = this.proto.factory ?? this.proto.token.opts?.factory;
536
676
  if (!factory) throw InjectionError.notFound(this.proto.token);
537
- this._instance = InjectionContext.instantiate(factory, retriever);
677
+ const contextFactory = /* @__PURE__ */ __name(() => InjectionContext.instantiate(factory, retriever), "contextFactory");
678
+ this._instance = runMiddlewares(middlewares, {
679
+ token: this.proto.token,
680
+ factory: contextFactory,
681
+ deps: /* @__PURE__ */ new Set([
682
+ ...this._deps.keys(),
683
+ ...Array.from(this._transparent).map((n) => n.proto.parent.token)
684
+ ])
685
+ });
538
686
  this._resolved = true;
539
687
  if (pool) pool.set(this.proto.token, this);
540
688
  }
@@ -568,12 +716,20 @@ var TreeNodeTransparent = class _TreeNodeTransparent {
568
716
  for (const node of this._deps.values()) node.collectPool(pool);
569
717
  for (const dep of this._transparent) dep.collectPool(pool);
570
718
  }
571
- instantiate(pool) {
719
+ instantiate(pool, middlewares = []) {
572
720
  if (this._resolved) return;
573
- for (const dep of this._transparent) dep.instantiate(pool);
574
- for (const node of this._deps.values()) node.instantiate(pool);
721
+ for (const dep of this._transparent) dep.instantiate(pool, middlewares);
722
+ for (const node of this._deps.values()) node.instantiate(pool, middlewares);
575
723
  const retriever = retrieverFactory(this.proto.parent.token, this._deps, this._transparent);
576
- this._instance = InjectionContext.instantiate(this.proto.factory, retriever);
724
+ const refFactory = /* @__PURE__ */ __name(() => InjectionContext.instantiate(this.proto.factory, retriever), "refFactory");
725
+ this._instance = runMiddlewares(middlewares, {
726
+ token: this.proto.parent.token,
727
+ factory: refFactory,
728
+ deps: /* @__PURE__ */ new Set([
729
+ ...this._deps.keys(),
730
+ ...Array.from(this._transparent).map((n) => n.proto.parent.token)
731
+ ])
732
+ });
577
733
  this._resolved = true;
578
734
  }
579
735
  toString() {
@@ -596,10 +752,10 @@ var TreeNodeMulti = class _TreeNodeMulti {
596
752
  for (const dep of this._deps) dep.collectPool(pool);
597
753
  pool.set(this.proto.token, this);
598
754
  }
599
- instantiate(pool) {
755
+ instantiate(pool, middlewares = []) {
600
756
  if (this._resolved) return;
601
757
  for (const dep of this._deps) {
602
- dep.instantiate(pool);
758
+ dep.instantiate(pool, middlewares);
603
759
  if (dep instanceof TreeNodeSingle) {
604
760
  this.instance.push(dep.instance);
605
761
  } else if (dep instanceof _TreeNodeMulti) {
@@ -754,24 +910,6 @@ function resolveTreeNode(rootProto, cache, singleNodes, multiNodes, upstreamGett
754
910
  }
755
911
  __name(resolveTreeNode, "resolveTreeNode");
756
912
 
757
- // src/lib/utils/injector.ts
758
- var InjectorImpl = class {
759
- static {
760
- __name(this, "InjectorImpl");
761
- }
762
- container;
763
- constructor(container) {
764
- this.container = container;
765
- }
766
- get(token) {
767
- return this.container.get(token);
768
- }
769
- produce(fn) {
770
- return this.container.produce(fn);
771
- }
772
- };
773
- var Injector = new NodeToken("Injector");
774
-
775
913
  // src/lib/container/container.ts
776
914
  var NodeContainer = class extends Illuma {
777
915
  static {
@@ -785,10 +923,13 @@ var NodeContainer = class extends Illuma {
785
923
  _multiProtoNodes = /* @__PURE__ */ new Map();
786
924
  constructor(_opts) {
787
925
  super(), this._opts = _opts;
788
- this._parent = _opts?.parent;
789
926
  if (_opts?.diagnostics) {
790
- Illuma.extendDiagnostics(new DiagnosticsDefaultReporter());
927
+ 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.");
928
+ const m = (init_built_in(), __toCommonJS(built_in_exports));
929
+ if (m.enabled) return;
930
+ m.enableIllumaDiagnostics();
791
931
  }
932
+ this._parent = _opts?.parent;
792
933
  }
793
934
  /**
794
935
  * Registers a provider in the container.
@@ -901,7 +1042,11 @@ var NodeContainer = class extends Illuma {
901
1042
  return parentNode.findNode(token);
902
1043
  }
903
1044
  _buildInjectionTree() {
904
- const root = new TreeRootNode(this._opts?.instant);
1045
+ const middlewares = [
1046
+ ...Illuma._middlewares,
1047
+ ...this.collectMiddlewares()
1048
+ ];
1049
+ const root = new TreeRootNode(this._opts?.instant, middlewares);
905
1050
  const cache = /* @__PURE__ */ new Map();
906
1051
  const nodes = [
907
1052
  ...this._protoNodes.values(),
@@ -918,6 +1063,12 @@ var NodeContainer = class extends Illuma {
918
1063
  this._multiProtoNodes.clear();
919
1064
  return root;
920
1065
  }
1066
+ collectMiddlewares() {
1067
+ return [
1068
+ ...this._parent && "collectMiddlewares" in this._parent && typeof this._parent.collectMiddlewares === "function" ? this._parent.collectMiddlewares() : [],
1069
+ ...this.middlewares
1070
+ ];
1071
+ }
921
1072
  /**
922
1073
  * Bootstraps the container by resolving the dependency trees and instantiating all providers.
923
1074
  * This must be called after all providers are registered and before calling {@link get}.
@@ -953,7 +1104,7 @@ var NodeContainer = class extends Illuma {
953
1104
  if (this._opts?.measurePerformance) {
954
1105
  console.log(`[Illuma] \u{1F680} Bootstrapped in ${duration.toFixed(2)} ms`);
955
1106
  }
956
- if (this._opts?.diagnostics) {
1107
+ if (this._opts?.diagnostics || Illuma.hasDiagnostics()) {
957
1108
  const allNodes = this._rootNode.dependencies.size;
958
1109
  const unusedNodes = Array.from(this._rootNode.dependencies).filter((node) => node.allocations === 0).filter((node) => {
959
1110
  if (!(node.proto instanceof ProtoNodeSingle)) return true;