Skip to content

Commit e405ed3

Browse files
authored
feat(injector): add support for receive type in isProvided (#511)
* feat(injector): resolve receive type in isProvided * chore: remove unnecessary code * refactor(injector): improve isProvided function --------- Signed-off-by: Marcus S. Abildskov <[email protected]>
1 parent 2a8bf2c commit e405ed3

File tree

5 files changed

+45
-13
lines changed

5 files changed

+45
-13
lines changed

packages/app/src/service-container.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,21 @@
1111
import { ClassType, getClassName, isClass, isFunction } from '@deepkit/core';
1212
import { EventDispatcher, EventListenerRegistered, isEventListenerContainerEntryCallback } from '@deepkit/event';
1313
import { AddedListener, AppModule, ConfigurationInvalidError, MiddlewareConfig, ModuleDefinition } from './module.js';
14-
import { injectedFunction, Injector, InjectorContext, InjectorModule, isProvided, ProviderWithScope, resolveToken, Token } from '@deepkit/injector';
14+
import {
15+
injectedFunction,
16+
Injector,
17+
InjectorContext,
18+
InjectorModule,
19+
isProvided,
20+
provide,
21+
ProviderWithScope,
22+
resolveToken,
23+
Token
24+
} from '@deepkit/injector';
1525
import { cli } from './command.js';
1626
import { WorkflowDefinition } from '@deepkit/workflow';
1727
import { deserialize, ReflectionClass, ReflectionFunction, validate } from '@deepkit/type';
18-
import { ConsoleTransport, Logger, ScopedLogger } from '@deepkit/logger';
28+
import { ConsoleTransport, Logger, LoggerInterface, ScopedLogger } from '@deepkit/logger';
1929

2030
export interface ControllerConfig {
2131
controller?: ClassType,

packages/injector/src/injector.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,15 @@ export function resolveToken(provider: ProviderWithScope): Token {
184184
return provider.provide;
185185
}
186186

187+
export type ContainerToken = Exclude<Token, Type | TagProvider<any>>;
188+
187189
/**
188190
* Returns a value that can be compared with `===` to check if two tokens are actually equal even though
189191
* they are the result of different type expressions.
190192
*
191193
* This is used in the big switch-case statement in the generated code to match DI tokens.
192194
*/
193-
export function getContainerToken(type: Token): string | number | symbol | bigint | boolean | RegExp | ClassType | Function {
195+
export function getContainerToken(type: Token): ContainerToken {
194196
if (isClass(type)) return type;
195197
if (type instanceof TagProvider) return getContainerToken(type.provider);
196198

packages/injector/src/module.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { NormalizedProvider, ProviderWithScope, TagProvider, Token } from './provider.js';
22
import { arrayRemoveItem, ClassType, getClassName, isClass, isPlainObject, isPrototypeOfBase } from '@deepkit/core';
3-
import { BuildContext, Injector, SetupProviderRegistry } from './injector.js';
3+
import { BuildContext, getContainerToken, Injector, resolveToken, SetupProviderRegistry } from './injector.js';
44
import {
55
hasTypeInformation,
66
isType,
77
ReceiveType,
88
reflect,
99
ReflectionKind,
1010
reflectOrUndefined,
11-
resolveReceiveType, stringifyType,
11+
resolveReceiveType,
1212
Type,
1313
TypeClass,
1414
typeInfer,
@@ -226,8 +226,9 @@ export function findModuleForConfig(config: ClassType, modules: InjectorModule[]
226226

227227
export type ExportType = Token | InjectorModule;
228228

229-
export function isProvided(providers: ProviderWithScope[], token: any): boolean {
230-
return providers.find(v => !(v instanceof TagProvider) ? token === (isClass(v) ? v : v.provide) : false) !== undefined;
229+
230+
export function isProvided<T>(providers: ProviderWithScope[], token: Token<T>): boolean {
231+
return providers.some(v => getContainerToken(resolveToken(v)) === getContainerToken(token));
231232
}
232233

233234
export function getScope(provider: ProviderWithScope): string {
@@ -342,8 +343,11 @@ export class InjectorModule<C extends { [name: string]: any } = any, IMPORT = In
342343
return this.exports.includes(token);
343344
}
344345

345-
isProvided(classType: ClassType): boolean {
346-
return isProvided(this.getProviders(), classType);
346+
isProvided<T>(token?: Token<T>, type?: ReceiveType<T>): boolean {
347+
if (!token) {
348+
token = resolveReceiveType(type);
349+
}
350+
return isProvided<T>(this.getProviders(), token);
347351
}
348352

349353
addProvider(...provider: (ProviderWithScope | ProviderWithScope[])[]): this {

packages/injector/src/provider.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export interface ProviderScope {
2525
}
2626

2727
/** @reflection never */
28-
export type Token<T = any> = symbol | number | bigint | RegExp | boolean | string | AbstractClassType<T> | Type | T;
28+
export type Token<T = any> = symbol | number | bigint | RegExp | boolean | string | AbstractClassType<T> | Type | TagProvider<T> | Function | T;
2929

3030
export function provide<T>(
3131
provider:
@@ -95,7 +95,7 @@ export interface FactoryProvider<T> extends ProviderBase {
9595
}
9696

9797
/** @reflection never */
98-
export type Provider<T = any> = ClassType | ValueProvider<T> | ClassProvider<T> | ExistingProvider<T> | FactoryProvider<T> | TagProvider<T>;
98+
export type Provider<T = any> = AbstractClassType | ValueProvider<T> | ClassProvider<T> | ExistingProvider<T> | FactoryProvider<T> | TagProvider<T>;
9999

100100
/** @reflection never */
101101
export type ProviderProvide<T = any> = ValueProvider<T> | ClassProvider<T> | ExistingProvider<T> | FactoryProvider<T>;
@@ -163,7 +163,7 @@ export class Tag<T, TP extends TagProvider<T> = TagProvider<T>> {
163163
export type NormalizedProvider<T = any> = ProviderProvide<T> & ProviderScope;
164164

165165
/** @reflection never */
166-
export type ProviderWithScope<T = any> = ClassType | (ProviderProvide<T> & ProviderScope) | TagProvider<any>;
166+
export type ProviderWithScope<T = any> = AbstractClassType | (ProviderProvide<T> & ProviderScope) | TagProvider<any>;
167167

168168
export function isScopedProvider(obj: any): obj is ProviderProvide & ProviderScope {
169169
return obj.provide && obj.hasOwnProperty('scope');

packages/injector/tests/injector.spec.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
PartialFactory,
1010
} from '../src/injector.js';
1111
import { InjectorModule } from '../src/module.js';
12-
import { ReflectionClass, ReflectionKind, ReflectionParameter, ReflectionProperty } from '@deepkit/type';
12+
import { ReflectionClass, ReflectionKind } from '@deepkit/type';
1313
import { Inject } from '../src/types.js';
1414
import { provide } from '../src/provider.js';
1515

@@ -1025,3 +1025,19 @@ test('PartialFactory', () => {
10251025
expect(a.num).toBe(5);
10261026
}
10271027
});
1028+
1029+
test('isProvided supports receive type', () => {
1030+
interface A {
1031+
b: string;
1032+
}
1033+
const providers = [provide<A>({ useValue: { b: 'a' } })];
1034+
const module = new InjectorModule(providers)
1035+
expect(module.isProvided<A>()).toBe(true);
1036+
});
1037+
1038+
test('isProvided supports token', () => {
1039+
class A {}
1040+
const providers = [A];
1041+
const module = new InjectorModule(providers)
1042+
expect(module.isProvided(A)).toBe(true);
1043+
});

0 commit comments

Comments
 (0)