@illuma/core 1.5.0 → 1.5.2
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/README.md +43 -31
- package/dist/index.cjs +51 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +51 -20
- package/dist/index.js.map +1 -1
- package/dist/{injection-uBc6Sjj_.d.cts → injection-DbD-KHxh.d.cts} +1 -1
- package/dist/{injection-CsNE009y.d.ts → injection-NAMHFl1Y.d.ts} +1 -1
- package/dist/{plugin-container-OWBUHjSf.d.cts → plugin-container-C3xE3HLf.d.cts} +1 -1
- package/dist/{plugin-container-DZj4vSLu.d.ts → plugin-container-XmDO_bdM.d.ts} +1 -1
- package/dist/plugins.d.cts +3 -3
- package/dist/plugins.d.ts +3 -3
- package/dist/testkit.cjs +51 -20
- package/dist/testkit.cjs.map +1 -1
- package/dist/testkit.d.cts +2 -2
- package/dist/testkit.d.ts +2 -2
- package/dist/testkit.js +51 -20
- package/dist/testkit.js.map +1 -1
- package/dist/{types-zryyqrii.d.cts → types-HBicpdg6.d.cts} +1 -1
- package/dist/{types-zryyqrii.d.ts → types-HBicpdg6.d.ts} +1 -1
- package/package.json +7 -8
- package/CHANGELOG.md +0 -22
package/README.md
CHANGED
|
@@ -1,35 +1,37 @@
|
|
|
1
|
-
#
|
|
1
|
+
# **Illuma** – Dependency Injection for TypeScript
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|

|
|
6
6
|

|
|
7
7
|
|
|
8
|
-
A
|
|
8
|
+
A universal, lightweight and type-safe dependency injection container for TypeScript.
|
|
9
|
+
Heavily inspired by Angular's DI system, but designed to work in any environment (Node.js, Bun, Deno, browsers, and more).
|
|
9
10
|
|
|
10
|
-
##
|
|
11
|
+
## Features
|
|
11
12
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
13
|
+
- **Type-Safe** – Excellent type inference
|
|
14
|
+
- **Lightweight** – Zero dependencies, minimal bundle size
|
|
15
|
+
- **Flexible** – Classes, factories, values, and aliases
|
|
16
|
+
- **Optional decorators** – Injectable classes with `@NodeInjectable()` decorator
|
|
17
|
+
- **Multi-Tokens** – Built-in multi-provider support
|
|
18
|
+
- **Plugin System** – Extensible architecture with custom middlewares, scanners, and diagnostics
|
|
19
|
+
- **TestKit** – Unit testing and mocking utilities for any testing framework
|
|
20
|
+
- **Universal** – Node.js, Bun, Deno, browser, and Electron
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
21
23
|
|
|
22
24
|
```bash
|
|
23
25
|
npm install @illuma/core
|
|
24
26
|
```
|
|
25
27
|
|
|
26
|
-
##
|
|
28
|
+
## Compatibility
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
Practically the library is compatible with Node.js (v14+) and all modern browsers.
|
|
30
|
-
For older environments, consider using a transpiler
|
|
30
|
+
Compatible with virtually anything supporting ES2015+ (ES6+).
|
|
31
|
+
Practically the library is compatible with Node.js (v14+), Bun, Deno and all modern browsers.
|
|
32
|
+
For older environments, consider using a transpiler or provide polyfills as needed.
|
|
31
33
|
|
|
32
|
-
##
|
|
34
|
+
## Quick start
|
|
33
35
|
|
|
34
36
|
```typescript
|
|
35
37
|
import { NodeContainer, NodeInjectable, nodeInject } from '@illuma/core';
|
|
@@ -58,9 +60,11 @@ container.bootstrap();
|
|
|
58
60
|
const userService = container.get(UserService);
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
> **Note:**
|
|
63
|
+
> **Note:**
|
|
64
|
+
> Example above requires `experimentalDecorators` and `emitDecoratorMetadata` in tsconfig.
|
|
65
|
+
> See [Getting Started](./docs/GETTING_STARTED.md) for decorator-free alternatives.
|
|
62
66
|
|
|
63
|
-
##
|
|
67
|
+
## Using Tokens
|
|
64
68
|
|
|
65
69
|
```typescript
|
|
66
70
|
import { NodeToken, MultiNodeToken, NodeContainer } from '@illuma/core';
|
|
@@ -95,7 +99,7 @@ const plugins = container.get(PLUGINS); // Plugin[]: [AnalyticsPlugin, LoggingP
|
|
|
95
99
|
|
|
96
100
|
See [Tokens Guide](./docs/TOKENS.md) for more details.
|
|
97
101
|
|
|
98
|
-
##
|
|
102
|
+
## Provider types
|
|
99
103
|
|
|
100
104
|
```typescript
|
|
101
105
|
// Class provider
|
|
@@ -106,6 +110,7 @@ container.provide({ provide: CONFIG, value: { apiUrl: '...' } });
|
|
|
106
110
|
|
|
107
111
|
// Factory provider
|
|
108
112
|
container.provide({ provide: DATABASE, factory: () => {
|
|
113
|
+
// You can use nodeInject inside factories!
|
|
109
114
|
const env = nodeInject(ENV);
|
|
110
115
|
return createDatabase(env.connectionString);
|
|
111
116
|
} });
|
|
@@ -119,7 +124,7 @@ container.provide({ provide: Database, alias: ExistingDatabase });
|
|
|
119
124
|
|
|
120
125
|
See [Providers Guide](./docs/PROVIDERS.md) for details.
|
|
121
126
|
|
|
122
|
-
##
|
|
127
|
+
## Testing
|
|
123
128
|
|
|
124
129
|
```typescript
|
|
125
130
|
import { createTestFactory } from '@illuma/core/testkit';
|
|
@@ -135,36 +140,43 @@ it('should fetch user', () => {
|
|
|
135
140
|
});
|
|
136
141
|
```
|
|
137
142
|
|
|
138
|
-
See [Testing Guide](./docs/TESTKIT.md) for
|
|
143
|
+
See [Testing Guide](./docs/TESTKIT.md) for examples.
|
|
139
144
|
|
|
140
|
-
##
|
|
145
|
+
## Documentation
|
|
141
146
|
|
|
142
147
|
| Guide | Description |
|
|
143
|
-
|
|
|
148
|
+
| :-- | :-- |
|
|
144
149
|
| [Getting Started](./docs/GETTING_STARTED.md) | Installation, setup, and basic usage |
|
|
145
150
|
| [Providers](./docs/PROVIDERS.md) | Value, factory, class, and alias providers |
|
|
146
151
|
| [Tokens](./docs/TOKENS.md) | NodeToken and MultiNodeToken |
|
|
147
152
|
| [Async Injection](./docs/ASYNC_INJECTION.md) | Lazy loading and sub-containers |
|
|
148
|
-
| [Testing](./docs/TESTKIT.md) |
|
|
153
|
+
| [Testing](./docs/TESTKIT.md) | TestKit and mocking |
|
|
149
154
|
| [Plugins](./docs/PLUGINS.md) | Extending Illuma with custom scanners and diagnostics |
|
|
150
155
|
| [Technical Overview](./docs/TECHNICAL_OVERVIEW.md) | Deep dive into how Illuma works |
|
|
151
156
|
| [API Reference](./docs/API.md) | Complete API documentation |
|
|
152
157
|
| [Troubleshooting](./docs/TROUBLESHOOTING.md) | Error codes and solutions |
|
|
153
158
|
|
|
154
|
-
##
|
|
159
|
+
## Plugins
|
|
155
160
|
|
|
156
|
-
Illuma supports
|
|
161
|
+
Illuma supports plugins! Check these out:
|
|
157
162
|
|
|
158
163
|
- **[@illuma/reflect](https://github.com/git-illuma/reflect)** – Constructor metadata and property decorator injection support
|
|
159
164
|
|
|
160
165
|
See [Plugins Guide](./docs/PLUGINS.md) for creating your own plugins.
|
|
161
166
|
|
|
162
|
-
##
|
|
167
|
+
## Contributing
|
|
168
|
+
|
|
169
|
+
Thank you for considering contributing to Illuma! I deeply appreciate your interest in making this project better.
|
|
170
|
+
|
|
171
|
+
Anyways, to get you started, please take a look at the [Contributing Guide](./CONTRIBUTING.md) for guidelines on how to setup development environment, run tests, and submit pull requests.
|
|
172
|
+
|
|
173
|
+
## License
|
|
163
174
|
|
|
164
|
-
MIT
|
|
175
|
+
MIT
|
|
165
176
|
|
|
166
|
-
|
|
177
|
+
Created by [bebrasmell](https://github.com/bebrasmell)
|
|
167
178
|
|
|
179
|
+
## Links
|
|
180
|
+
- [NPM](https://npmjs.com/package/@illuma/core)
|
|
168
181
|
- [GitHub](https://github.com/git-illuma/core)
|
|
169
|
-
- [NPM](https://www.npmjs.com/package/@illuma/core)
|
|
170
182
|
- [Issues](https://github.com/git-illuma/core/issues)
|
package/dist/index.cjs
CHANGED
|
@@ -377,7 +377,7 @@ __name(isNotFoundError, "isNotFoundError");
|
|
|
377
377
|
|
|
378
378
|
// src/lib/api/decorator.ts
|
|
379
379
|
var tokenRegistry = /* @__PURE__ */ new WeakMap();
|
|
380
|
-
var INJECTION_SYMBOL = Symbol("Injectable");
|
|
380
|
+
var INJECTION_SYMBOL = /* @__PURE__ */ Symbol("Injectable");
|
|
381
381
|
function NodeInjectable() {
|
|
382
382
|
return (ctor) => {
|
|
383
383
|
const nodeToken = new NodeToken(`_${ctor.name}`, {
|
|
@@ -521,6 +521,17 @@ __name(nodeInject, "nodeInject");
|
|
|
521
521
|
// src/lib/container/container.ts
|
|
522
522
|
init_plugin_container();
|
|
523
523
|
|
|
524
|
+
// src/lib/plugins/middlewares/runner.ts
|
|
525
|
+
function runMiddlewares(middlewares, params) {
|
|
526
|
+
const ms = middlewares;
|
|
527
|
+
const next = /* @__PURE__ */ __name((i, current) => {
|
|
528
|
+
if (i >= ms.length) return current.factory();
|
|
529
|
+
return ms[i](current, (nextParams) => next(i + 1, nextParams));
|
|
530
|
+
}, "next");
|
|
531
|
+
return next(0, params);
|
|
532
|
+
}
|
|
533
|
+
__name(runMiddlewares, "runMiddlewares");
|
|
534
|
+
|
|
524
535
|
// src/lib/provider/extractor.ts
|
|
525
536
|
function extractProvider(provider) {
|
|
526
537
|
if ("value" in provider) return () => provider.value;
|
|
@@ -626,24 +637,15 @@ var InjectorImpl = class {
|
|
|
626
637
|
var Injector = new NodeToken("Injector");
|
|
627
638
|
|
|
628
639
|
// src/lib/provider/tree-node.ts
|
|
629
|
-
function runMiddlewares(middlewares, params) {
|
|
630
|
-
const ms = middlewares;
|
|
631
|
-
const next = /* @__PURE__ */ __name((i, current) => {
|
|
632
|
-
if (i >= ms.length) return current.factory();
|
|
633
|
-
return ms[i](current, (nextParams) => next(i + 1, nextParams));
|
|
634
|
-
}, "next");
|
|
635
|
-
return next(0, params);
|
|
636
|
-
}
|
|
637
|
-
__name(runMiddlewares, "runMiddlewares");
|
|
638
640
|
function retrieverFactory(node, deps, transparentDeps) {
|
|
639
641
|
return (token, optional) => {
|
|
640
642
|
const depNode = deps.get(token);
|
|
641
643
|
if (!depNode && !optional) {
|
|
642
|
-
const transparent =
|
|
644
|
+
const transparent = transparentDeps.get(token);
|
|
643
645
|
if (transparent) return transparent.instance;
|
|
644
646
|
throw InjectionError.untracked(token, node);
|
|
645
647
|
}
|
|
646
|
-
return depNode
|
|
648
|
+
return depNode ? depNode.instance : null;
|
|
647
649
|
};
|
|
648
650
|
}
|
|
649
651
|
__name(retrieverFactory, "retrieverFactory");
|
|
@@ -654,7 +656,7 @@ var TreeRootNode = class {
|
|
|
654
656
|
instant;
|
|
655
657
|
middlewares;
|
|
656
658
|
_deps = /* @__PURE__ */ new Set();
|
|
657
|
-
_treePool = /* @__PURE__ */ new
|
|
659
|
+
_treePool = /* @__PURE__ */ new Map();
|
|
658
660
|
constructor(instant = true, middlewares = []) {
|
|
659
661
|
this.instant = instant;
|
|
660
662
|
this.middlewares = middlewares;
|
|
@@ -719,7 +721,11 @@ var TreeNodeSingle = class {
|
|
|
719
721
|
if (this._resolved) return;
|
|
720
722
|
for (const node of this._deps.values()) node.instantiate(pool, middlewares);
|
|
721
723
|
for (const dep of this._transparent) dep.instantiate(pool, middlewares);
|
|
722
|
-
const
|
|
724
|
+
const transparentMap = /* @__PURE__ */ new Map();
|
|
725
|
+
for (const tNode of this._transparent) {
|
|
726
|
+
transparentMap.set(tNode.proto.parent.token, tNode);
|
|
727
|
+
}
|
|
728
|
+
const retriever = retrieverFactory(this.proto.token, this._deps, transparentMap);
|
|
723
729
|
const factory = this.proto.factory ?? this.proto.token.opts?.factory;
|
|
724
730
|
if (!factory) throw InjectionError.notFound(this.proto.token);
|
|
725
731
|
const contextFactory = /* @__PURE__ */ __name(() => InjectionContext.instantiate(factory, retriever), "contextFactory");
|
|
@@ -768,7 +774,11 @@ var TreeNodeTransparent = class _TreeNodeTransparent {
|
|
|
768
774
|
if (this._resolved) return;
|
|
769
775
|
for (const dep of this._transparent) dep.instantiate(pool, middlewares);
|
|
770
776
|
for (const node of this._deps.values()) node.instantiate(pool, middlewares);
|
|
771
|
-
const
|
|
777
|
+
const transparentMap = /* @__PURE__ */ new Map();
|
|
778
|
+
for (const tNode of this._transparent) {
|
|
779
|
+
transparentMap.set(tNode.proto.parent.token, tNode);
|
|
780
|
+
}
|
|
781
|
+
const retriever = retrieverFactory(this.proto.parent.token, this._deps, transparentMap);
|
|
772
782
|
const refFactory = /* @__PURE__ */ __name(() => InjectionContext.instantiate(this.proto.factory, retriever), "refFactory");
|
|
773
783
|
this._instance = runMiddlewares(middlewares, {
|
|
774
784
|
token: this.proto.parent.token,
|
|
@@ -1301,12 +1311,33 @@ var NodeContainer = class extends Illuma {
|
|
|
1301
1311
|
if (isConstructor(fn) && !isInjectable(fn)) {
|
|
1302
1312
|
throw InjectionError.invalidCtor(fn);
|
|
1303
1313
|
}
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1314
|
+
let factory;
|
|
1315
|
+
if (isInjectable(fn)) {
|
|
1316
|
+
const f = getInjectableToken(fn).opts?.factory;
|
|
1317
|
+
if (!f) factory = /* @__PURE__ */ __name(() => new fn(), "factory");
|
|
1318
|
+
else factory = /* @__PURE__ */ __name(() => getInjectableToken(fn).opts?.factory?.(), "factory");
|
|
1319
|
+
} else {
|
|
1320
|
+
factory = fn;
|
|
1321
|
+
}
|
|
1322
|
+
const rootNode = this._rootNode;
|
|
1323
|
+
if (!rootNode) throw InjectionError.notBootstrapped();
|
|
1324
|
+
const retriever = /* @__PURE__ */ __name((token, optional) => {
|
|
1325
|
+
const node = rootNode.find(token);
|
|
1326
|
+
if (!node && !optional) throw InjectionError.notFound(token);
|
|
1309
1327
|
return node ? node.instance : null;
|
|
1328
|
+
}, "retriever");
|
|
1329
|
+
const deps = InjectionContext.scan(factory);
|
|
1330
|
+
const middlewares = [
|
|
1331
|
+
...Illuma._middlewares,
|
|
1332
|
+
...this.collectMiddlewares()
|
|
1333
|
+
];
|
|
1334
|
+
const contextFactory = /* @__PURE__ */ __name(() => InjectionContext.instantiate(factory, retriever), "contextFactory");
|
|
1335
|
+
return runMiddlewares(middlewares, {
|
|
1336
|
+
token: new NodeToken("ProducedNode"),
|
|
1337
|
+
deps: new Set([
|
|
1338
|
+
...deps.values()
|
|
1339
|
+
].map((d) => d.token)),
|
|
1340
|
+
factory: contextFactory
|
|
1310
1341
|
});
|
|
1311
1342
|
}
|
|
1312
1343
|
};
|