@needle-di/core 0.7.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Dirk Luijk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # Needle DI 💉
2
+
3
+ > A lightweight, type-safe Dependency Injection (DI) library for JavaScript and TypeScript projects.
4
+
5
+ [![NPM version](http://img.shields.io/npm/v/needle-di.svg?style=flat-square)](https://www.npmjs.com/package/needle-di)
6
+ [![NPM downloads](http://img.shields.io/npm/dm/needle-di.svg?style=flat-square)](https://www.npmjs.com/package/needle-di)
7
+ [![Build status](https://github.com/dirkluijk/needle-di/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/dirkluijk/needle-di/actions/workflows/main.yml)
8
+
9
+ Needle DI is a lightweight, TypeScript-first library for dependency injection (DI). It is designed to be both easy to use and highly efficient.
10
+
11
+ ### Key Features
12
+
13
+ - Stand-alone: No additional dependencies required
14
+ - Intended for both JavaScript-only and TypeScript projects
15
+ - Supports [tree-shakeable injection tokens](https://needle-di.io/advanced/tree-shaking.html): optimize your builds for production.
16
+ - Inspired by [Angular](https://angular.dev/) and [InversifyJS](https://github.com/inversify/InversifyJS), familiar to developers coming from these frameworks.
17
+ - Uses native [ECMAScript TC39 decorators](https://github.com/tc39/proposal-decorators) (currently stage 3)
18
+ - No need for `experimentalDecorators` and `emitDecoratorMetadata`
19
+ - No reflection libraries needed, like `reflect-metadata` or other reflection mechanisms.
20
+
21
+ ## Basic example
22
+
23
+ Here’s a simple example using constructor injection to inject one service into another.
24
+
25
+ ```typescript
26
+ import { injectable, inject } from "needle-di";
27
+
28
+ @injectable()
29
+ class FooService {}
30
+
31
+ @injectable()
32
+ class BarService {
33
+ constructor(private fooService = inject(FooService)) {}
34
+ // ^? Type will be inferred as `FooService`
35
+ }
36
+ ```
37
+
38
+ The `@injectable` decorator eliminates the need to manually register services. To construct the `BarService`, create a
39
+ dependency injection container, and use the `container.get()` method:
40
+
41
+ ```typescript
42
+ import { Container } from "needle-di";
43
+
44
+ const container = new Container();
45
+ const barService = container.get(BarService);
46
+ // ^? Type will be inferred as `BarService`
47
+ ```
48
+
49
+ Check out the [docs](https://needle-di.io/concepts/binding.html) to learn more!
50
+
51
+ ## Installation
52
+
53
+ ```
54
+ npm install --save needle-di
55
+ ```
56
+
57
+ ## Docs
58
+
59
+ Check out our docs on [https://needle-di.io](https://needle-di.io/concepts/binding.html).
60
+
61
+ ## License
62
+
63
+ License under the MIT License (MIT)
64
+
65
+ Copyright (c) 2024 Dirk Luijk
66
+
67
+ Permission is hereby granted, free of charge, to any person obtaining a copy
68
+ of this software and associated documentation files (the "Software"), to deal
69
+ in the Software without restriction, including without limitation the rights
70
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71
+ copies of the Software, and to permit persons to whom the Software is
72
+ furnished to do so, subject to the following conditions:
73
+
74
+ The above copyright notice and this permission notice shall be included in all
75
+ copies or substantial portions of the Software.
76
+
77
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
78
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
79
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
80
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
81
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
82
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
83
+ SOFTWARE.
@@ -0,0 +1,92 @@
1
+ import { type Token } from "./tokens.js";
2
+ import { type Provider } from "./providers.js";
3
+ export declare class Container {
4
+ private readonly providers;
5
+ private readonly singletons;
6
+ bindAll<A>(p1: Provider<A>): this;
7
+ bindAll<A, B>(p1: Provider<A>, p2: Provider<B>): this;
8
+ bindAll<A, B, C>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>): this;
9
+ bindAll<A, B, C, D>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>, p4: Provider<D>): this;
10
+ bindAll<A, B, C, D, E>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>, p4: Provider<D>, p5: Provider<E>): this;
11
+ bindAll<A, B, C, D, E, F>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>, p4: Provider<D>, p5: Provider<E>, p6: Provider<F>): this;
12
+ bindAll<A, B, C, D, E, F, G>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>, p4: Provider<D>, p5: Provider<E>, p6: Provider<F>, p7: Provider<G>): this;
13
+ bindAll<A, B, C, D, E, F, G, H>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>, p4: Provider<D>, p5: Provider<E>, p6: Provider<F>, p7: Provider<G>, p8: Provider<H>): this;
14
+ bindAll<A, B, C, D, E, F, G, H, I>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>, p4: Provider<D>, p5: Provider<E>, p6: Provider<F>, p7: Provider<G>, p8: Provider<H>, p9: Provider<I>): this;
15
+ bindAll<A, B, C, D, E, F, G, H, I>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>, p4: Provider<D>, p5: Provider<E>, p6: Provider<F>, p7: Provider<G>, p8: Provider<H>, p9: Provider<I>, ...providers: Provider<any>[]): this;
16
+ bind<T>(provider: Provider<T>): this;
17
+ get<T>(token: Token<T>, options: {
18
+ multi: true;
19
+ }): T[];
20
+ get<T>(token: Token<T>, options: {
21
+ optional: true;
22
+ }): T | undefined;
23
+ get<T>(token: Token<T>, options: {
24
+ multi: true;
25
+ optional: true;
26
+ }): T[] | undefined;
27
+ get<T>(token: Token<T>, options?: {
28
+ optional?: boolean;
29
+ multi?: boolean;
30
+ }): T;
31
+ getAsync<T>(token: Token<T>, options: {
32
+ multi: true;
33
+ }): Promise<T[]>;
34
+ getAsync<T>(token: Token<T>, options: {
35
+ optional: true;
36
+ }): Promise<T | undefined>;
37
+ getAsync<T>(token: Token<T>, options: {
38
+ multi: true;
39
+ optional: true;
40
+ }): Promise<T[] | undefined>;
41
+ getAsync<T>(token: Token<T>, options?: {
42
+ optional?: boolean;
43
+ multi?: boolean;
44
+ }): Promise<T>;
45
+ private construct;
46
+ private constructAsync;
47
+ private doConstructAsync;
48
+ private autoBindIfNeeded;
49
+ private existingProviderAlreadyProvided;
50
+ }
51
+ /**
52
+ * Injects a service within the current injection context, using the token provided.
53
+ */
54
+ export declare function inject<T>(token: Token<T>, options: {
55
+ multi: true;
56
+ }): T[];
57
+ export declare function inject<T>(token: Token<T>, options: {
58
+ optional: true;
59
+ }): T | undefined;
60
+ export declare function inject<T>(token: Token<T>, options: {
61
+ multi: true;
62
+ optional: true;
63
+ }): T[] | undefined;
64
+ export declare function inject<T>(token: Token<T>, options?: {
65
+ optional?: boolean;
66
+ multi?: boolean;
67
+ }): T;
68
+ /**
69
+ * Injects a service asynchronously within the current injection context, using the token provided.
70
+ */
71
+ export declare function injectAsync<T>(token: Token<T>, options: {
72
+ multi: true;
73
+ }): Promise<T[]>;
74
+ export declare function injectAsync<T>(token: Token<T>, options: {
75
+ optional: true;
76
+ }): Promise<T | undefined>;
77
+ export declare function injectAsync<T>(token: Token<T>, options: {
78
+ multi: true;
79
+ optional: true;
80
+ }): Promise<T[] | undefined>;
81
+ export declare function injectAsync<T>(token: Token<T>, options?: {
82
+ optional?: boolean;
83
+ multi?: boolean;
84
+ }): Promise<T>;
85
+ /**
86
+ * Bootstraps a new container and obtains a service using the provided token.
87
+ */
88
+ export declare function bootstrap<T>(token: Token<T>): T;
89
+ /**
90
+ * Bootstraps a new container and obtains a service asynchronously using the provided token.
91
+ */
92
+ export declare function bootstrapAsync<T>(token: Token<T>): Promise<T>;
@@ -0,0 +1,262 @@
1
+ import { isClassToken, toString, isInjectionToken } from "./tokens.js";
2
+ import { isClassProvider, isFactoryProvider, isConstructorProvider, isValueProvider, isAsyncFactoryProvider, isMultiProvider, isExistingProvider, } from "./providers.js";
3
+ import { getInjectableTargets, isInjectable } from "./decorators.js";
4
+ import { assertPresent, getParentClasses, windowedSlice } from "./utils.js";
5
+ export class Container {
6
+ providers = new Map();
7
+ singletons = new Map();
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ bindAll(...providers) {
10
+ providers.forEach((it) => this.bind(it));
11
+ return this;
12
+ }
13
+ bind(provider) {
14
+ const token = isConstructorProvider(provider) ? provider : provider.provide;
15
+ const multi = isMultiProvider(provider);
16
+ if (isExistingProvider(provider) && provider.provide === provider.useExisting) {
17
+ throw Error(`The provider for token ${toString(token)} with "useExisting" cannot refer to itself.`);
18
+ }
19
+ if (!isExistingProvider(provider) && this.singletons.has(token)) {
20
+ throw Error(`Cannot bind a new provider for ${toString(token)}, since the existing provider was already constructed.`);
21
+ }
22
+ const existingProviders = this.providers.get(token) ?? [];
23
+ // ignore this provider if it was already provided as existingProvider
24
+ if (isExistingProvider(provider) &&
25
+ isMultiProvider(provider) &&
26
+ this.existingProviderAlreadyProvided(token, provider.useExisting)) {
27
+ return this;
28
+ }
29
+ if (multi && existingProviders.some((it) => !isMultiProvider(it))) {
30
+ throw Error(`Cannot bind ${toString(token)} as multi-provider, since there is already a provider which is not a multi-provider.`);
31
+ }
32
+ else if (!multi && existingProviders.some((it) => isMultiProvider(it))) {
33
+ if (!existingProviders.every(isExistingProvider)) {
34
+ throw Error(`Cannot bind ${toString(token)} as provider, since there are already provider(s) that are multi-providers.`);
35
+ }
36
+ }
37
+ this.providers.set(token, multi ? [...existingProviders, provider] : [provider]);
38
+ // inheritance support: also bind parent classes to their immediate child classes
39
+ if (isClassToken(token) && (isClassProvider(provider) || isConstructorProvider(provider))) {
40
+ windowedSlice([token, ...getParentClasses(token)]).forEach(([childClass, parentClass]) => {
41
+ const parentProvider = {
42
+ provide: parentClass,
43
+ useExisting: childClass,
44
+ multi: true,
45
+ };
46
+ const existingParentProviders = this.providers.get(parentClass) ?? [];
47
+ if (!this.existingProviderAlreadyProvided(parentClass, childClass)) {
48
+ this.providers.set(parentClass, [...existingParentProviders, parentProvider]);
49
+ }
50
+ });
51
+ }
52
+ return this;
53
+ }
54
+ get(token, options) {
55
+ this.autoBindIfNeeded(token);
56
+ const optional = options?.optional ?? false;
57
+ const multi = options?.multi ?? false;
58
+ if (!this.providers.has(token)) {
59
+ if (optional) {
60
+ return undefined;
61
+ }
62
+ throw Error(`No provider(s) found for ${toString(token)}`);
63
+ }
64
+ const providers = assertPresent(this.providers.get(token));
65
+ if (!this.singletons.has(token)) {
66
+ if (providers.some(isAsyncFactoryProvider)) {
67
+ throw new AsyncProvidersInSyncInjectionContextError(token);
68
+ }
69
+ this.singletons.set(token, providers.flatMap((it) => this.construct(it, this)));
70
+ }
71
+ const singletons = assertPresent(this.singletons.get(token));
72
+ if (multi) {
73
+ return singletons;
74
+ }
75
+ else if (singletons.length > 1) {
76
+ throw Error(`Requesting a single value for ${toString(token)}, but multiple values were provided. ` +
77
+ `Consider passing "{ multi: true }" to inject all values, or adjust your bindings accordingly.`);
78
+ }
79
+ else {
80
+ return assertPresent(singletons.at(0));
81
+ }
82
+ }
83
+ async getAsync(token, options) {
84
+ this.autoBindIfNeeded(token);
85
+ const optional = options?.optional ?? false;
86
+ const multi = options?.multi ?? false;
87
+ if (!this.providers.has(token)) {
88
+ if (optional) {
89
+ return undefined;
90
+ }
91
+ throw Error(`No provider(s) found for ${toString(token)}`);
92
+ }
93
+ const existingProviders = this.providers.get(token) ?? [];
94
+ if (!this.singletons.has(token)) {
95
+ const values = await Promise.all(existingProviders.map((it) => this.constructAsync(it, this)));
96
+ this.singletons.set(token, values.flat());
97
+ }
98
+ const singletons = assertPresent(this.singletons.get(token));
99
+ if (multi) {
100
+ return Promise.all(singletons.map(promisify));
101
+ }
102
+ else if (singletons.length > 1) {
103
+ throw Error(`Requesting a single value for ${toString(token)}, but multiple values were provided. ` +
104
+ `Consider passing "{ multi: true }" to inject all values, or adjust your bindings accordingly.`);
105
+ }
106
+ else {
107
+ return promisify(singletons.at(0));
108
+ }
109
+ }
110
+ construct(provider, scope) {
111
+ const originalScope = currentScope;
112
+ try {
113
+ currentScope = scope;
114
+ return doConstruct(provider, scope);
115
+ }
116
+ finally {
117
+ currentScope = originalScope;
118
+ }
119
+ }
120
+ async constructAsync(provider, scope) {
121
+ const originalScope = currentScope;
122
+ try {
123
+ currentScope = scope;
124
+ return await this.doConstructAsync(provider, scope);
125
+ }
126
+ finally {
127
+ currentScope = originalScope;
128
+ }
129
+ }
130
+ async doConstructAsync(provider, scope) {
131
+ if (isAsyncFactoryProvider(provider)) {
132
+ return [await provider.useFactory()];
133
+ }
134
+ else if (isExistingProvider(provider)) {
135
+ return scope.getAsync(provider.useExisting, { multi: true });
136
+ }
137
+ else if (isClassProvider(provider) || isConstructorProvider(provider)) {
138
+ while (true) {
139
+ try {
140
+ return doConstruct(provider, scope);
141
+ }
142
+ catch (error) {
143
+ if (error instanceof AsyncProvidersInSyncInjectionContextError) {
144
+ const values = await injectAsync(error.token, { multi: true, optional: true });
145
+ if (values) {
146
+ this.singletons.set(error.token, values);
147
+ }
148
+ }
149
+ else {
150
+ throw error;
151
+ }
152
+ }
153
+ }
154
+ }
155
+ else {
156
+ return doConstruct(provider, scope);
157
+ }
158
+ }
159
+ autoBindIfNeeded(token) {
160
+ if (this.singletons.has(token)) {
161
+ return;
162
+ }
163
+ if (isClassToken(token) && isInjectable(token)) {
164
+ const targetClasses = getInjectableTargets(token);
165
+ targetClasses
166
+ .filter((targetClass) => !this.providers.has(targetClass))
167
+ .forEach((targetClass) => {
168
+ this.bind({
169
+ provide: targetClass,
170
+ useClass: targetClass,
171
+ multi: true,
172
+ });
173
+ });
174
+ }
175
+ else if (!this.providers.has(token) && isInjectionToken(token) && token.options?.factory) {
176
+ const async = token.options.async;
177
+ if (!async) {
178
+ this.bind({
179
+ provide: token,
180
+ async: false,
181
+ useFactory: token.options.factory,
182
+ });
183
+ }
184
+ else if (async) {
185
+ this.bind({
186
+ provide: token,
187
+ async: true,
188
+ useFactory: token.options.factory,
189
+ });
190
+ }
191
+ }
192
+ }
193
+ existingProviderAlreadyProvided(token, existingToken) {
194
+ return (this.providers.get(token) ?? []).some((it) => isExistingProvider(it) && it.provide === token && it.useExisting === existingToken);
195
+ }
196
+ }
197
+ let currentScope = undefined;
198
+ export function inject(token, options) {
199
+ if (currentScope === undefined) {
200
+ if (options?.optional)
201
+ return undefined;
202
+ throw new Error("You can only invoke inject() from the injection context");
203
+ }
204
+ return currentScope.get(token, options);
205
+ }
206
+ export async function injectAsync(token, options) {
207
+ if (currentScope === undefined) {
208
+ if (options?.optional)
209
+ return undefined;
210
+ throw new Error("You can only invoke injectAsync() from the injection context");
211
+ }
212
+ return currentScope.getAsync(token, options);
213
+ }
214
+ // see: https://github.com/tc39/proposal-promise-try
215
+ async function promisify(value) {
216
+ return new Promise((resolve) => resolve(value));
217
+ }
218
+ function doConstruct(provider, scope) {
219
+ if (isConstructorProvider(provider)) {
220
+ return [new provider()];
221
+ }
222
+ else if (isClassProvider(provider)) {
223
+ return [new provider.useClass()];
224
+ }
225
+ else if (isValueProvider(provider)) {
226
+ return [provider.useValue];
227
+ }
228
+ else if (isFactoryProvider(provider)) {
229
+ return [provider.useFactory()];
230
+ }
231
+ else if (isAsyncFactoryProvider(provider)) {
232
+ throw Error("Invalid state");
233
+ }
234
+ else {
235
+ return scope.get(provider.useExisting, { multi: true });
236
+ }
237
+ }
238
+ /**
239
+ * Bootstraps a new container and obtains a service using the provided token.
240
+ */
241
+ export function bootstrap(token) {
242
+ return new Container().get(token);
243
+ }
244
+ /**
245
+ * Bootstraps a new container and obtains a service asynchronously using the provided token.
246
+ */
247
+ export function bootstrapAsync(token) {
248
+ return new Container().getAsync(token);
249
+ }
250
+ /**
251
+ * An error that occurs when an async provider is requested in a synchronous context.
252
+ *
253
+ * @internal
254
+ */
255
+ class AsyncProvidersInSyncInjectionContextError extends Error {
256
+ token;
257
+ constructor(token) {
258
+ super(`Some providers for token ${toString(token)} are async, please use injectAsync() or container.getAsync() instead`);
259
+ this.token = token;
260
+ }
261
+ }
262
+ //# sourceMappingURL=container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EAEf,sBAAsB,EACtB,eAAe,EACf,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,MAAM,OAAO,SAAS;IACH,SAAS,GAAgB,IAAI,GAAG,EAAE,CAAC;IACnC,UAAU,GAAiB,IAAI,GAAG,EAAE,CAAC;IAgEtD,8DAA8D;IACvD,OAAO,CAAC,GAAG,SAA0B;QAC1C,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,IAAI,CAAI,QAAqB;QAClC,MAAM,KAAK,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC5E,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QAExC,IAAI,kBAAkB,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;YAC9E,MAAM,KAAK,CAAC,0BAA0B,QAAQ,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACtG,CAAC;QAED,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,MAAM,KAAK,CACT,kCAAkC,QAAQ,CAAC,KAAK,CAAC,wDAAwD,CAC1G,CAAC;QACJ,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAE1D,sEAAsE;QACtE,IACE,kBAAkB,CAAC,QAAQ,CAAC;YAC5B,eAAe,CAAC,QAAQ,CAAC;YACzB,IAAI,CAAC,+BAA+B,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,EACjE,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,KAAK,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAClE,MAAM,KAAK,CACT,eAAe,QAAQ,CAAC,KAAK,CAAC,sFAAsF,CACrH,CAAC;QACJ,CAAC;aAAM,IAAI,CAAC,KAAK,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACzE,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACjD,MAAM,KAAK,CACT,eAAe,QAAQ,CAAC,KAAK,CAAC,6EAA6E,CAC5G,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEjF,iFAAiF;QACjF,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,IAAI,qBAAqB,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC1F,aAAa,CAAC,CAAC,KAAK,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,EAAE;gBACvF,MAAM,cAAc,GAAgC;oBAClD,OAAO,EAAE,WAAW;oBACpB,WAAW,EAAE,UAAU;oBACvB,KAAK,EAAE,IAAI;iBACZ,CAAC;gBACF,MAAM,uBAAuB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;gBACtE,IAAI,CAAC,IAAI,CAAC,+BAA+B,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC;oBACnE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,uBAAuB,EAAE,cAAc,CAAC,CAAC,CAAC;gBAChF,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAMM,GAAG,CAAI,KAAe,EAAE,OAAiD;QAC9E,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAE7B,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,KAAK,CAAC;QAC5C,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,KAAK,CAAC;QAEtC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,MAAM,KAAK,CAAC,4BAA4B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAE3D,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAChC,IAAI,SAAS,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC;gBAC3C,MAAM,IAAI,yCAAyC,CAAC,KAAK,CAAC,CAAC;YAC7D,CAAC;YAED,IAAI,CAAC,UAAU,CAAC,GAAG,CACjB,KAAK,EACL,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CACpD,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAE7D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,UAAU,CAAC;QACpB,CAAC;aAAM,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,MAAM,KAAK,CACT,iCAAiC,QAAQ,CAAC,KAAK,CAAC,uCAAuC;gBACrF,+FAA+F,CAClG,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAMM,KAAK,CAAC,QAAQ,CACnB,KAAe,EACf,OAGC;QAED,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAE7B,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,KAAK,CAAC;QAC5C,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,KAAK,CAAC;QAEtC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,MAAM,KAAK,CAAC,4BAA4B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAE1D,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/F,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;QAChD,CAAC;aAAM,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,MAAM,KAAK,CACT,iCAAiC,QAAQ,CAAC,KAAK,CAAC,uCAAuC;gBACrF,+FAA+F,CAClG,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAEO,SAAS,CAAI,QAAqB,EAAE,KAAgB;QAC1D,MAAM,aAAa,GAAG,YAAY,CAAC;QACnC,IAAI,CAAC;YACH,YAAY,GAAG,KAAK,CAAC;YACrB,OAAO,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACtC,CAAC;gBAAS,CAAC;YACT,YAAY,GAAG,aAAa,CAAC;QAC/B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,cAAc,CAAI,QAAqB,EAAE,KAAgB;QACrE,MAAM,aAAa,GAAG,YAAY,CAAC;QACnC,IAAI,CAAC;YACH,YAAY,GAAG,KAAK,CAAC;YACrB,OAAO,MAAM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACtD,CAAC;gBAAS,CAAC;YACT,YAAY,GAAG,aAAa,CAAC;QAC/B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAI,QAAqB,EAAE,KAAgB;QACvE,IAAI,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrC,OAAO,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxC,OAAO,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;aAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,IAAI,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxE,OAAO,IAAI,EAAE,CAAC;gBACZ,IAAI,CAAC;oBACH,OAAO,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBACtC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,KAAK,YAAY,yCAAyC,EAAE,CAAC;wBAC/D,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;wBAC/E,IAAI,MAAM,EAAE,CAAC;4BACX,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;wBAC3C,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,MAAM,KAAK,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAEO,gBAAgB,CAAI,KAAe;QACzC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO;QACT,CAAC;QAED,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/C,MAAM,aAAa,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;YAElD,aAAa;iBACV,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;iBACzD,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;gBACvB,IAAI,CAAC,IAAI,CAAC;oBACR,OAAO,EAAE,WAAW;oBACpB,QAAQ,EAAE,WAAW;oBACrB,KAAK,EAAE,IAAI;iBACZ,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACP,CAAC;aAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;YAC3F,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAClC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,IAAI,CAAC,IAAI,CAAC;oBACR,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,KAAK;oBACZ,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;iBAClC,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,KAAK,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC;oBACR,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,IAAI;oBACX,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;iBAClC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAEO,+BAA+B,CAAC,KAAqB,EAAE,aAA6B;QAC1F,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAC3C,CAAC,EAAE,EAAE,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,KAAK,KAAK,IAAI,EAAE,CAAC,WAAW,KAAK,aAAa,CAC3F,CAAC;IACJ,CAAC;CACF;AAED,IAAI,YAAY,GAA0B,SAAS,CAAC;AASpD,MAAM,UAAU,MAAM,CAAI,KAAe,EAAE,OAAiD;IAC1F,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,OAAO,EAAE,QAAQ;YAAE,OAAO,SAAS,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC;AAYD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAe,EACf,OAGC;IAED,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,OAAO,EAAE,QAAQ;YAAE,OAAO,SAAS,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,YAAY,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,oDAAoD;AACpD,KAAK,UAAU,SAAS,CAAI,KAAqB;IAC/C,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,WAAW,CAAI,QAAqB,EAAE,KAAgB;IAC7D,IAAI,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;IAC1B,CAAC;SAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,OAAO,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnC,CAAC;SAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;SAAM,IAAI,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACjC,CAAC;SAAM,IAAI,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5C,MAAM,KAAK,CAAC,eAAe,CAAC,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAcD;;GAEG;AACH,MAAM,UAAU,SAAS,CAAI,KAAe;IAC1C,OAAO,IAAI,SAAS,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAI,KAAe;IAC/C,OAAO,IAAI,SAAS,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,yCAA6C,SAAQ,KAAK;IAC3C;IAAnB,YAAmB,KAAe;QAChC,KAAK,CACH,4BAA4B,QAAQ,CAAC,KAAK,CAAC,sEAAsE,CAClH,CAAC;QAHe,UAAK,GAAL,KAAK,CAAU;IAIlC,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import { type AbstractClass, type Class } from "./utils.js";
2
+ type ClassDecorator<C extends Class<unknown>> = (target: C) => C | void;
3
+ export declare const injectableSymbol: unique symbol;
4
+ export type InjectableClass<T = unknown> = (Class<T> | AbstractClass<T>) & {
5
+ [injectableSymbol]: Class<unknown>[];
6
+ };
7
+ export declare function injectable<C extends Class<unknown>>(): ClassDecorator<C>;
8
+ export declare function isInjectable<T>(target: AbstractClass<T>): target is InjectableClass<T>;
9
+ export declare function getInjectableTargets<T>(target: InjectableClass<T>): Class<unknown>[];
10
+ export {};
@@ -0,0 +1,31 @@
1
+ import { getParentClasses } from "./utils.js";
2
+ export const injectableSymbol = Symbol("injectable");
3
+ export function injectable() {
4
+ return (target) => {
5
+ getParentClasses(target).forEach((parentClass) => {
6
+ if (!Object.getOwnPropertyDescriptor(parentClass, injectableSymbol)) {
7
+ Object.defineProperty(parentClass, injectableSymbol, {
8
+ value: [target],
9
+ writable: true,
10
+ enumerable: false,
11
+ });
12
+ }
13
+ else {
14
+ const injectableParentClass = parentClass;
15
+ injectableParentClass[injectableSymbol] = [...injectableParentClass[injectableSymbol], target];
16
+ }
17
+ });
18
+ Object.defineProperty(target, injectableSymbol, {
19
+ value: [target],
20
+ writable: true,
21
+ });
22
+ };
23
+ }
24
+ export function isInjectable(target) {
25
+ // eslint-disable-next-line no-prototype-builtins
26
+ return target.hasOwnProperty(injectableSymbol);
27
+ }
28
+ export function getInjectableTargets(target) {
29
+ return target[injectableSymbol];
30
+ }
31
+ //# sourceMappingURL=decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAK9E,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAIrD,MAAM,UAAU,UAAU;IACxB,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,gBAAgB,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;YAC/C,IAAI,CAAC,MAAM,CAAC,wBAAwB,CAAC,WAAW,EAAE,gBAAgB,CAAC,EAAE,CAAC;gBACpE,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,gBAAgB,EAAE;oBACnD,KAAK,EAAE,CAAC,MAAM,CAAC;oBACf,QAAQ,EAAE,IAAI;oBACd,UAAU,EAAE,KAAK;iBAClB,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,MAAM,qBAAqB,GAAG,WAA8B,CAAC;gBAC7D,qBAAqB,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,qBAAqB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,CAAC;YACjG,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,gBAAgB,EAAE;YAC9C,KAAK,EAAE,CAAC,MAAM,CAAC;YACf,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAI,MAAwB;IACtD,iDAAiD;IACjD,OAAO,MAAM,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAI,MAA0B;IAChE,OAAO,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { inject, Container, bootstrap, bootstrapAsync, injectAsync } from "./container.js";
2
+ export { injectable } from "./decorators.js";
3
+ export type { FactoryProvider, ExistingProvider, Provider, ConstructorProvider, ClassProvider, ValueProvider, AsyncFactoryProvider, } from "./providers.js";
4
+ export { InjectionToken } from "./tokens.js";
5
+ export type { Token } from "./tokens.js";
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { inject, Container, bootstrap, bootstrapAsync, injectAsync } from "./container.js";
2
+ export { injectable } from "./decorators.js";
3
+ export { InjectionToken } from "./tokens.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3F,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAU7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,63 @@
1
+ import type { Token } from "./tokens.js";
2
+ import { type Class } from "./utils.js";
3
+ /**
4
+ * A provider states how, for a given token, a service should be constructed.
5
+ */
6
+ export type Provider<T> = ConstructorProvider<T> | ClassProvider<T> | ValueProvider<T> | FactoryProvider<T> | AsyncFactoryProvider<T> | ExistingProvider<T>;
7
+ /**
8
+ * A constructor provider refers to a class constructor,
9
+ * which is the same class as the token itself.
10
+ */
11
+ export type ConstructorProvider<T> = Class<T>;
12
+ /**
13
+ * A class provider refers to a class constructor,
14
+ * which may be the same class as the token, or a subclass.
15
+ */
16
+ export interface ClassProvider<T> {
17
+ provide: Token<T>;
18
+ useClass: Class<NoInfer<T>>;
19
+ multi?: true;
20
+ }
21
+ /**
22
+ * A value provider refers to a static value.
23
+ */
24
+ export interface ValueProvider<T> {
25
+ provide: Token<T>;
26
+ useValue: T;
27
+ multi?: true;
28
+ }
29
+ /**
30
+ * A factory provider refers to a value which is lazily returned
31
+ * by a synchronous factory function.
32
+ */
33
+ export interface FactoryProvider<T> {
34
+ provide: Token<T>;
35
+ async?: false;
36
+ multi?: true;
37
+ useFactory: () => NoInfer<T>;
38
+ }
39
+ /**
40
+ * An async factory provider refers to a value which is lazily returned
41
+ * by an asynchronous factory function.
42
+ */
43
+ export interface AsyncFactoryProvider<T> {
44
+ provide: Token<T>;
45
+ async: true;
46
+ multi?: true;
47
+ useFactory: () => Promise<NoInfer<T>>;
48
+ }
49
+ /**
50
+ * An existing provider refers to a value provided by another provider.
51
+ */
52
+ export interface ExistingProvider<T> {
53
+ provide: Token<T>;
54
+ useExisting: Token<T>;
55
+ multi?: boolean;
56
+ }
57
+ export declare function isConstructorProvider<T>(provider: Provider<T>): provider is ConstructorProvider<T>;
58
+ export declare function isClassProvider<T>(provider: Provider<T>): provider is ClassProvider<T>;
59
+ export declare function isValueProvider<T>(provider: Provider<T>): provider is ValueProvider<T>;
60
+ export declare function isFactoryProvider<T>(provider: Provider<T>): provider is FactoryProvider<T>;
61
+ export declare function isAsyncFactoryProvider<T>(provider: Provider<T>): provider is AsyncFactoryProvider<T>;
62
+ export declare function isExistingProvider<T>(provider: Provider<T>): provider is ExistingProvider<T>;
63
+ export declare function isMultiProvider<T>(provider: Provider<T>): boolean;
@@ -0,0 +1,23 @@
1
+ import { isClassLike } from "./utils.js";
2
+ export function isConstructorProvider(provider) {
3
+ return isClassLike(provider);
4
+ }
5
+ export function isClassProvider(provider) {
6
+ return "provide" in provider && "useClass" in provider;
7
+ }
8
+ export function isValueProvider(provider) {
9
+ return "provide" in provider && "useValue" in provider;
10
+ }
11
+ export function isFactoryProvider(provider) {
12
+ return "provide" in provider && "useFactory" in provider && !provider.async;
13
+ }
14
+ export function isAsyncFactoryProvider(provider) {
15
+ return "provide" in provider && "useFactory" in provider && provider.async === true;
16
+ }
17
+ export function isExistingProvider(provider) {
18
+ return "provide" in provider && "useExisting" in provider;
19
+ }
20
+ export function isMultiProvider(provider) {
21
+ return "provide" in provider && "multi" in provider && provider.multi === true;
22
+ }
23
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../src/providers.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,WAAW,EAAE,MAAM,YAAY,CAAC;AAqErD,MAAM,UAAU,qBAAqB,CAAI,QAAqB;IAC5D,OAAO,WAAW,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,eAAe,CAAI,QAAqB;IACtD,OAAO,SAAS,IAAI,QAAQ,IAAI,UAAU,IAAI,QAAQ,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,eAAe,CAAI,QAAqB;IACtD,OAAO,SAAS,IAAI,QAAQ,IAAI,UAAU,IAAI,QAAQ,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAI,QAAqB;IACxD,OAAO,SAAS,IAAI,QAAQ,IAAI,YAAY,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAI,QAAqB;IAC7D,OAAO,SAAS,IAAI,QAAQ,IAAI,YAAY,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAI,QAAqB;IACzD,OAAO,SAAS,IAAI,QAAQ,IAAI,aAAa,IAAI,QAAQ,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,eAAe,CAAI,QAAqB;IACtD,OAAO,SAAS,IAAI,QAAQ,IAAI,OAAO,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC;AACjF,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { type AbstractClass, type Class } from "./utils.js";
2
+ /**
3
+ * A token is a reference to a service in the dependency injection (DI) container.
4
+ * When obtaining a service from the container, you should use this token.
5
+ */
6
+ export type Token<T> = Class<T> | AbstractClass<T> | string | symbol | InjectionToken<T>;
7
+ /**
8
+ * A unique injection token object, that is used by reference. Can hold a generic type.
9
+ * Can optionally hold an (async) factory.
10
+ */
11
+ export declare class InjectionToken<T> {
12
+ private description;
13
+ options?: InjectionTokenOptions<T> | undefined;
14
+ constructor(description: string | symbol, options?: InjectionTokenOptions<T> | undefined);
15
+ toString(): string;
16
+ }
17
+ type InjectionTokenOptions<T> = {
18
+ async?: false;
19
+ factory: () => T;
20
+ } | {
21
+ async: true;
22
+ factory: () => Promise<T>;
23
+ };
24
+ /**
25
+ * Type-guard to check if a token is a class reference.
26
+ * @internal
27
+ */
28
+ export declare function isClassToken<T>(token: Token<T>): token is Class<T>;
29
+ /**
30
+ * Type-guard to check if a token is an InjectionToken
31
+ * @internal
32
+ */
33
+ export declare function isInjectionToken<T>(token: Token<T>): token is InjectionToken<T>;
34
+ /**
35
+ * Describes a token, useful for error messages.
36
+ * @internal
37
+ */
38
+ export declare function toString<T>(token: Token<T>): string;
39
+ export {};
package/dist/tokens.js ADDED
@@ -0,0 +1,49 @@
1
+ import { isClassLike } from "./utils.js";
2
+ /**
3
+ * A unique injection token object, that is used by reference. Can hold a generic type.
4
+ * Can optionally hold an (async) factory.
5
+ */
6
+ export class InjectionToken {
7
+ description;
8
+ options;
9
+ constructor(description, options) {
10
+ this.description = description;
11
+ this.options = options;
12
+ }
13
+ toString() {
14
+ return `InjectionToken "${String(this.description)}"`;
15
+ }
16
+ }
17
+ /**
18
+ * Type-guard to check if a token is a class reference.
19
+ * @internal
20
+ */
21
+ export function isClassToken(token) {
22
+ return isClassLike(token);
23
+ }
24
+ /**
25
+ * Type-guard to check if a token is an InjectionToken
26
+ * @internal
27
+ */
28
+ export function isInjectionToken(token) {
29
+ return token instanceof InjectionToken;
30
+ }
31
+ /**
32
+ * Describes a token, useful for error messages.
33
+ * @internal
34
+ */
35
+ export function toString(token) {
36
+ if (isClassLike(token)) {
37
+ return token.name;
38
+ }
39
+ else if (typeof token === "symbol") {
40
+ return token.description ?? String(token);
41
+ }
42
+ else if (token instanceof InjectionToken) {
43
+ return token.toString();
44
+ }
45
+ else {
46
+ return token;
47
+ }
48
+ }
49
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,WAAW,EAAE,MAAM,YAAY,CAAC;AAQzE;;;GAGG;AACH,MAAM,OAAO,cAAc;IAEf;IACD;IAFT,YACU,WAA4B,EAC7B,OAAkC;QADjC,gBAAW,GAAX,WAAW,CAAiB;QAC7B,YAAO,GAAP,OAAO,CAA2B;IACxC,CAAC;IAEG,QAAQ;QACb,OAAO,mBAAmB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;IACxD,CAAC;CACF;AAYD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAI,KAAe;IAC7C,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAI,KAAe;IACjD,OAAO,KAAK,YAAY,cAAc,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAI,KAAe;IACzC,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACrC,OAAO,KAAK,CAAC,WAAW,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;SAAM,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ export type Class<T> = new (...args: any[]) => T;
2
+ export interface AbstractClass<T> {
3
+ prototype: T;
4
+ name: string;
5
+ }
6
+ /**
7
+ * Type-guard to assert if the given object is an (abstract) class.
8
+ * @internal
9
+ */
10
+ export declare function isClassLike(target: unknown): target is Class<unknown> | AbstractClass<unknown>;
11
+ /**
12
+ * Returns all parent classes of a given class.
13
+ * @internal
14
+ */
15
+ export declare function getParentClasses(target: Class<unknown>): Class<unknown>[];
16
+ /**
17
+ * Ensures a given value is not null or undefined.
18
+ * @internal
19
+ */
20
+ export declare function assertPresent<T>(value: T | null | undefined): T;
21
+ /**
22
+ * @internal
23
+ */
24
+ export declare function windowedSlice<T>(array: T[], step?: 2): [T, T][];
25
+ export declare function windowedSlice<T>(array: T[], step: number): T[][];
package/dist/utils.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Type-guard to assert if the given object is an (abstract) class.
3
+ * @internal
4
+ */
5
+ export function isClassLike(target) {
6
+ return typeof target === "function";
7
+ }
8
+ /**
9
+ * Returns all parent classes of a given class.
10
+ * @internal
11
+ */
12
+ export function getParentClasses(target) {
13
+ const parentClasses = [];
14
+ let currentClass = target;
15
+ while (Object.getPrototypeOf(currentClass).name) {
16
+ const parentClass = Object.getPrototypeOf(currentClass);
17
+ parentClasses.push(parentClass);
18
+ currentClass = parentClass;
19
+ }
20
+ return parentClasses;
21
+ }
22
+ /**
23
+ * Ensures a given value is not null or undefined.
24
+ * @internal
25
+ */
26
+ export function assertPresent(value) {
27
+ if (value === null || value === undefined) {
28
+ throw Error(`Expected value to be not null or undefined`);
29
+ }
30
+ return value;
31
+ }
32
+ export function windowedSlice(array, step = 2) {
33
+ const result = [];
34
+ array.some((_, i) => {
35
+ if (i + step > array.length)
36
+ return true;
37
+ result.push(array.slice(i, i + step));
38
+ });
39
+ return result;
40
+ }
41
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAe;IACzC,OAAO,OAAO,MAAM,KAAK,UAAU,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAsB;IACrD,MAAM,aAAa,GAAqB,EAAE,CAAC;IAC3C,IAAI,YAAY,GAAG,MAAM,CAAC;IAC1B,OAAO,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC;QAChD,MAAM,WAAW,GAAmB,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QACxE,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAChC,YAAY,GAAG,WAAW,CAAC;IAC7B,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAI,KAA2B;IAC1D,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,MAAM,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAOD,MAAM,UAAU,aAAa,CAAI,KAAU,EAAE,IAAI,GAAG,CAAC;IACnD,MAAM,MAAM,GAAU,EAAE,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAClB,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@needle-di/core",
3
+ "version": "0.7.0",
4
+ "description": "A simple TypeScript library for dependency injection",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "dependency injection",
8
+ "di",
9
+ "dependency",
10
+ "injection",
11
+ "typescript",
12
+ "type-safe"
13
+ ],
14
+ "homepage": "https://needle-di.io",
15
+ "author": {
16
+ "name": "Dirk Luijk",
17
+ "email": "mail@dirkluijk.nl"
18
+ },
19
+ "private": false,
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/dirkluijk/needle-di.git"
26
+ },
27
+ "type": "module",
28
+ "module": "dist/index.js",
29
+ "exports": "./dist/index.js",
30
+ "types": "dist/index.d.ts",
31
+ "sideEffects": false,
32
+ "files": [
33
+ "dist/**/**"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "build:watch": "tsc -w",
38
+ "test": "vitest run && tsc -p tsconfig.test.json",
39
+ "test:watch": "vitest",
40
+ "test:ci": "vitest run --silent --coverage",
41
+ "lint": "eslint src",
42
+ "lint:fix": "eslint src --fix",
43
+ "reformat": "prettier src/**/*.ts README.md --write",
44
+ "docs:dev": "vitepress dev docs",
45
+ "docs:build": "vitepress build docs",
46
+ "docs:preview": "vitepress preview docs"
47
+ },
48
+ "devDependencies": {
49
+ "@eslint/js": "^9.10.0",
50
+ "@total-typescript/tsconfig": "github:total-typescript/tsconfig",
51
+ "@vitest/coverage-v8": "^2.1.1",
52
+ "eslint": "^9.10.0",
53
+ "prettier": "^3.3.3",
54
+ "typescript": "~5.5.0",
55
+ "typescript-eslint": "^8.6.0",
56
+ "vitepress": "^1.3.4",
57
+ "vitest": "^2.1.1"
58
+ }
59
+ }