chore: npm run format

This commit is contained in:
Stevan Freeborn
2025-05-12 22:23:31 -05:00
parent 586ee228ac
commit 92f00e3aa0
10 changed files with 144 additions and 129 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
- name: Build - name: Build
run: npm run build run: npm run build
- name: Publish - name: Publish
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.ACTIONS_PAT }} GITHUB_TOKEN: ${{ secrets.ACTIONS_PAT }}
run: npx semantic-release run: npx semantic-release
+2 -3
View File
@@ -11,7 +11,7 @@ jobs:
steps: steps:
- name: Check out repository - name: Check out repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup node - name: Setup node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: lts/* node-version: lts/*
@@ -25,7 +25,7 @@ jobs:
steps: steps:
- name: Check out repository - name: Check out repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup node - name: Setup node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: lts/* node-version: lts/*
@@ -76,4 +76,3 @@ jobs:
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v4
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
+10 -12
View File
@@ -52,11 +52,11 @@ Add the following to your `tsconfig.json`:
Here's a simple example of how to use netdi: Here's a simple example of how to use netdi:
```typescript ```typescript
import { import {
ServiceCollection, ServiceCollection,
createServiceIdentifier, createServiceIdentifier,
injectable, injectable,
inject inject,
} from '@stevanfreeborn/netdi'; } from '@stevanfreeborn/netdi';
// Define interfaces // Define interfaces
@@ -82,9 +82,7 @@ class GreetingService implements IGreetingService {
@injectable() @injectable()
class Greeter implements IGreeter { class Greeter implements IGreeter {
constructor( constructor(@inject(greetingServiceIdentifier) private greetingService: IGreetingService) {}
@inject(greetingServiceIdentifier) private greetingService: IGreetingService
) {}
greet(name: string): string { greet(name: string): string {
return this.greetingService.createGreeting(name); return this.greetingService.createGreeting(name);
@@ -146,14 +144,14 @@ services.addTransient(serviceIdentifier, Implementation);
For complex service instantiation, you can use factory methods: For complex service instantiation, you can use factory methods:
```typescript ```typescript
services.addSingleton(serviceIdentifier, (provider) => { services.addSingleton(serviceIdentifier, provider => {
// Use the provider to get dependencies // Use the provider to get dependencies
const dependency = provider.getService(dependencyIdentifier); const dependency = provider.getService(dependencyIdentifier);
// Create and configure your service instance // Create and configure your service instance
const instance = new MyService(dependency); const instance = new MyService(dependency);
instance.configure(); instance.configure();
return instance; return instance;
}); });
``` ```
@@ -192,7 +190,7 @@ Specifies a dependency for a parameter:
class MyService { class MyService {
constructor( constructor(
@inject(loggerIdentifier) private logger: ILogger, @inject(loggerIdentifier) private logger: ILogger,
@inject(configIdentifier) private config: IConfig @inject(configIdentifier) private config: IConfig,
) {} ) {}
} }
``` ```
+4 -4
View File
@@ -14,11 +14,11 @@ export const DI_INJECTABLE = 'di:injectable';
/** /**
* Decorator for constructor parameters that specifies which service identifier to use for injection * Decorator for constructor parameters that specifies which service identifier to use for injection
* *
* @template T - The type of the service to be injected * @template T - The type of the service to be injected
* @param serviceType - The service identifier for the dependency to inject * @param serviceType - The service identifier for the dependency to inject
* @returns A parameter decorator function that associates the parameter with the service identifier * @returns A parameter decorator function that associates the parameter with the service identifier
* *
* @example * @example
* ```typescript * ```typescript
* class MyService { * class MyService {
@@ -37,9 +37,9 @@ export function inject<T>(serviceType: ServiceIdentifier<T>): ParameterDecorator
/** /**
* Decorator that marks a class as injectable, allowing the container to create instances with dependencies * Decorator that marks a class as injectable, allowing the container to create instances with dependencies
* *
* @returns A class decorator function that marks the class as injectable * @returns A class decorator function that marks the class as injectable
* *
* @example * @example
* ```typescript * ```typescript
* @injectable() * @injectable()
+1 -1
View File
@@ -1,4 +1,4 @@
import "reflect-metadata"; import 'reflect-metadata';
export * from './serviceProvider.js'; export * from './serviceProvider.js';
export * from './types.js'; export * from './types.js';
+19 -18
View File
@@ -11,10 +11,10 @@ import type {
/** /**
* A collection of service descriptors that can be used to build a service provider. * A collection of service descriptors that can be used to build a service provider.
* *
* This class is used to register services with different lifetimes and build a service provider * This class is used to register services with different lifetimes and build a service provider
* that can resolve those services at runtime. * that can resolve those services at runtime.
* *
* @implements {IServiceCollection} * @implements {IServiceCollection}
*/ */
export class ServiceCollection implements IServiceCollection { export class ServiceCollection implements IServiceCollection {
@@ -26,14 +26,14 @@ export class ServiceCollection implements IServiceCollection {
/** /**
* Registers a singleton service with the collection. * Registers a singleton service with the collection.
* *
* Singleton services are created once and shared by all consumers. * Singleton services are created once and shared by all consumers.
* *
* @template T - The type of the service to register * @template T - The type of the service to register
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param implementationOrFactory - The implementation class or factory function * @param implementationOrFactory - The implementation class or factory function
* @returns The service collection instance for method chaining * @returns The service collection instance for method chaining
* *
* @example * @example
* ```typescript * ```typescript
* services.addSingleton(userServiceIdentifier, UserService); * services.addSingleton(userServiceIdentifier, UserService);
@@ -50,15 +50,15 @@ export class ServiceCollection implements IServiceCollection {
/** /**
* Registers a scoped service with the collection. * Registers a scoped service with the collection.
* *
* Scoped services are created once per scope. This is useful for services that should be * Scoped services are created once per scope. This is useful for services that should be
* shared within a request but not across requests. * shared within a request but not across requests.
* *
* @template T - The type of the service to register * @template T - The type of the service to register
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param implementationOrFactory - The implementation class or factory function * @param implementationOrFactory - The implementation class or factory function
* @returns The service collection instance for method chaining * @returns The service collection instance for method chaining
* *
* @example * @example
* ```typescript * ```typescript
* services.addScoped(userServiceIdentifier, UserService); * services.addScoped(userServiceIdentifier, UserService);
@@ -75,14 +75,14 @@ export class ServiceCollection implements IServiceCollection {
/** /**
* Registers a transient service with the collection. * Registers a transient service with the collection.
* *
* Transient services are created each time they are requested. * Transient services are created each time they are requested.
* *
* @template T - The type of the service to register * @template T - The type of the service to register
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param implementationOrFactory - The implementation class or factory function * @param implementationOrFactory - The implementation class or factory function
* @returns The service collection instance for method chaining * @returns The service collection instance for method chaining
* *
* @example * @example
* ```typescript * ```typescript
* services.addTransient(userServiceIdentifier, UserService); * services.addTransient(userServiceIdentifier, UserService);
@@ -99,7 +99,7 @@ export class ServiceCollection implements IServiceCollection {
/** /**
* Builds a service provider from the registered services. * Builds a service provider from the registered services.
* *
* @returns A new service provider that can resolve the registered services * @returns A new service provider that can resolve the registered services
*/ */
public build(): IServiceProvider { public build(): IServiceProvider {
@@ -108,7 +108,7 @@ export class ServiceCollection implements IServiceCollection {
/** /**
* Internal method to add a service descriptor to the collection. * Internal method to add a service descriptor to the collection.
* *
* @template T - The type of the service to register * @template T - The type of the service to register
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param implementationOrFactory - The implementation class or factory function * @param implementationOrFactory - The implementation class or factory function
@@ -120,7 +120,10 @@ export class ServiceCollection implements IServiceCollection {
implementationOrFactory: ServiceFactory<T> | Constructor<T>, implementationOrFactory: ServiceFactory<T> | Constructor<T>,
lifetime: ServiceLifetime, lifetime: ServiceLifetime,
): IServiceCollection { ): IServiceCollection {
if (typeof implementationOrFactory === 'function' && this.isConstructor(implementationOrFactory) === false) { if (
typeof implementationOrFactory === 'function' &&
this.isConstructor(implementationOrFactory) === false
) {
const descriptor: ServiceDescriptor<T> = { const descriptor: ServiceDescriptor<T> = {
serviceType, serviceType,
implementationType: Object as unknown as Constructor<T>, implementationType: Object as unknown as Constructor<T>,
@@ -144,13 +147,11 @@ export class ServiceCollection implements IServiceCollection {
/** /**
* Checks if a function is a constructor * Checks if a function is a constructor
* *
* @param func - The function to check * @param func - The function to check
* @returns True if the function is a constructor, false otherwise * @returns True if the function is a constructor, false otherwise
*/ */
private isConstructor(func: unknown): func is Constructor<unknown> { private isConstructor(func: unknown): func is Constructor<unknown> {
return typeof func === 'function' && return typeof func === 'function' && !!func.prototype && func.prototype.constructor === func;
!!func.prototype &&
func.prototype.constructor === func;
} }
} }
+15 -15
View File
@@ -9,9 +9,9 @@ import type {
/** /**
* Represents a scope for scoped services. * Represents a scope for scoped services.
* *
* A service scope provides access to scoped services that are created once per scope. * A service scope provides access to scoped services that are created once per scope.
* *
* @implements {IServiceScope} * @implements {IServiceScope}
*/ */
export class ServiceScope implements IServiceScope { export class ServiceScope implements IServiceScope {
@@ -22,7 +22,7 @@ export class ServiceScope implements IServiceScope {
/** /**
* Creates a new service scope * Creates a new service scope
* *
* @param serviceProvider - The service provider for this scope * @param serviceProvider - The service provider for this scope
*/ */
constructor(serviceProvider: IServiceProvider) { constructor(serviceProvider: IServiceProvider) {
@@ -39,10 +39,10 @@ export class ServiceScope implements IServiceScope {
/** /**
* A provider that can resolve registered services by their service identifier. * A provider that can resolve registered services by their service identifier.
* *
* The service provider is responsible for creating and managing service instances * The service provider is responsible for creating and managing service instances
* according to their registered lifetime. * according to their registered lifetime.
* *
* @implements {IServiceProvider} * @implements {IServiceProvider}
*/ */
export class ServiceProvider implements IServiceProvider { export class ServiceProvider implements IServiceProvider {
@@ -50,12 +50,12 @@ export class ServiceProvider implements IServiceProvider {
* Map of service descriptors by service identifier * Map of service descriptors by service identifier
*/ */
private readonly _descriptors: Map<ServiceIdentifier<unknown>, ServiceDescriptor<unknown>>; private readonly _descriptors: Map<ServiceIdentifier<unknown>, ServiceDescriptor<unknown>>;
/** /**
* Map of singleton service instances by service identifier * Map of singleton service instances by service identifier
*/ */
private readonly _singletonInstances: Map<ServiceIdentifier<unknown>, unknown> = new Map(); private readonly _singletonInstances: Map<ServiceIdentifier<unknown>, unknown> = new Map();
/** /**
* Map of scoped service instances by service identifier * Map of scoped service instances by service identifier
*/ */
@@ -63,7 +63,7 @@ export class ServiceProvider implements IServiceProvider {
/** /**
* Creates a new service provider * Creates a new service provider
* *
* @param descriptors - Map of service descriptors * @param descriptors - Map of service descriptors
* @param parent - Optional parent service provider to inherit singleton instances from * @param parent - Optional parent service provider to inherit singleton instances from
*/ */
@@ -89,12 +89,12 @@ export class ServiceProvider implements IServiceProvider {
/** /**
* Gets a service instance by its service identifier * Gets a service instance by its service identifier
* *
* @template T - The type of the service to resolve * @template T - The type of the service to resolve
* @param serviceType - The service identifier of the service to resolve * @param serviceType - The service identifier of the service to resolve
* @returns The resolved service instance * @returns The resolved service instance
* @throws Error if the service is not registered * @throws Error if the service is not registered
* *
* @example * @example
* ```typescript * ```typescript
* const userService = serviceProvider.getService(userServiceIdentifier); * const userService = serviceProvider.getService(userServiceIdentifier);
@@ -102,7 +102,7 @@ export class ServiceProvider implements IServiceProvider {
*/ */
getService<T>(serviceType: ServiceIdentifier<T>): T { getService<T>(serviceType: ServiceIdentifier<T>): T {
const descriptor = this._descriptors.get(serviceType); const descriptor = this._descriptors.get(serviceType);
if (!descriptor) { if (!descriptor) {
throw new Error(`Service of type ${serviceType.toString()} is not registered.`); throw new Error(`Service of type ${serviceType.toString()} is not registered.`);
} }
@@ -112,9 +112,9 @@ export class ServiceProvider implements IServiceProvider {
/** /**
* Creates a new scope for scoped services * Creates a new scope for scoped services
* *
* @returns A new service scope * @returns A new service scope
* *
* @example * @example
* ```typescript * ```typescript
* const scope = serviceProvider.createScope(); * const scope = serviceProvider.createScope();
@@ -137,7 +137,7 @@ export class ServiceProvider implements IServiceProvider {
/** /**
* Resolves a service instance from its descriptor * Resolves a service instance from its descriptor
* *
* @template T - The type of the service to resolve * @template T - The type of the service to resolve
* @param descriptor - The service descriptor * @param descriptor - The service descriptor
* @returns The resolved service instance * @returns The resolved service instance
@@ -172,7 +172,7 @@ export class ServiceProvider implements IServiceProvider {
/** /**
* Creates an instance of a service class and resolves its dependencies * Creates an instance of a service class and resolves its dependencies
* *
* @template T - The type of the service to create * @template T - The type of the service to create
* @param ctor - The constructor of the service class * @param ctor - The constructor of the service class
* @returns A new instance of the service class with its dependencies resolved * @returns A new instance of the service class with its dependencies resolved
+49 -34
View File
@@ -1,6 +1,6 @@
/** /**
* Represents the possible lifetimes for registered services * Represents the possible lifetimes for registered services
* *
* - singleton: Created once and shared by all consumers * - singleton: Created once and shared by all consumers
* - scoped: Created once per scope * - scoped: Created once per scope
* - transient: Created each time they are requested * - transient: Created each time they are requested
@@ -9,7 +9,7 @@ export type ServiceLifetime = 'singleton' | 'scoped' | 'transient';
/** /**
* Represents a constructor function for a class * Represents a constructor function for a class
* *
* @template T - The type of object the constructor creates * @template T - The type of object the constructor creates
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -17,21 +17,21 @@ export type Constructor<T> = new (...args: any[]) => T;
/** /**
* A unique identifier for a service type * A unique identifier for a service type
* *
* @template T - The type of the service * @template T - The type of the service
*/ */
export type ServiceIdentifier<T = unknown> = symbol & { __brand: T }; export type ServiceIdentifier<T = unknown> = symbol & { __brand: T };
/** /**
* A factory function that creates a service instance * A factory function that creates a service instance
* *
* @template T - The type of the service to create * @template T - The type of the service to create
*/ */
export type ServiceFactory<T> = (provider: IServiceProvider) => T; export type ServiceFactory<T> = (provider: IServiceProvider) => T;
/** /**
* Descriptor for a registered service * Descriptor for a registered service
* *
* @template T - The type of the service * @template T - The type of the service
*/ */
export type ServiceDescriptor<T = unknown> = { export type ServiceDescriptor<T = unknown> = {
@@ -39,17 +39,17 @@ export type ServiceDescriptor<T = unknown> = {
* The service identifier * The service identifier
*/ */
serviceType: ServiceIdentifier<T>; serviceType: ServiceIdentifier<T>;
/** /**
* The implementation class constructor * The implementation class constructor
*/ */
implementationType: Constructor<T>; implementationType: Constructor<T>;
/** /**
* The service lifetime * The service lifetime
*/ */
lifetime: ServiceLifetime; lifetime: ServiceLifetime;
/** /**
* Optional factory function to create the service instance * Optional factory function to create the service instance
*/ */
@@ -58,16 +58,16 @@ export type ServiceDescriptor<T = unknown> = {
/** /**
* Creates a typed service identifier * Creates a typed service identifier
* *
* @template T - The type of the service * @template T - The type of the service
* @returns A unique identifier for the service type * @returns A unique identifier for the service type
* *
* @example * @example
* ```typescript * ```typescript
* interface IUserService { * interface IUserService {
* getUserById(id: string): Promise<User>; * getUserById(id: string): Promise<User>;
* } * }
* *
* const userServiceIdentifier = createServiceIdentifier<IUserService>(); * const userServiceIdentifier = createServiceIdentifier<IUserService>();
* ``` * ```
*/ */
@@ -81,67 +81,82 @@ export function createServiceIdentifier<T>(): ServiceIdentifier<T> {
export interface IServiceCollection { export interface IServiceCollection {
/** /**
* Registers a singleton service with the collection * Registers a singleton service with the collection
* *
* @template T - The type of the service * @template T - The type of the service
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param implementationType - The implementation class * @param implementationType - The implementation class
* @returns The service collection for method chaining * @returns The service collection for method chaining
*/ */
addSingleton<T>(serviceType: ServiceIdentifier<T>, implementationType: Constructor<T>): IServiceCollection; addSingleton<T>(
serviceType: ServiceIdentifier<T>,
implementationType: Constructor<T>,
): IServiceCollection;
/** /**
* Registers a singleton service with a factory function * Registers a singleton service with a factory function
* *
* @template T - The type of the service * @template T - The type of the service
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param factory - A factory function that creates the service instance * @param factory - A factory function that creates the service instance
* @returns The service collection for method chaining * @returns The service collection for method chaining
*/ */
addSingleton<T>(serviceType: ServiceIdentifier<T>, factory: ServiceFactory<T>): IServiceCollection; addSingleton<T>(
serviceType: ServiceIdentifier<T>,
factory: ServiceFactory<T>,
): IServiceCollection;
/** /**
* Registers a scoped service with the collection * Registers a scoped service with the collection
* *
* @template T - The type of the service * @template T - The type of the service
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param implementationType - The implementation class * @param implementationType - The implementation class
* @returns The service collection for method chaining * @returns The service collection for method chaining
*/ */
addScoped<T>(serviceType: ServiceIdentifier<T>, implementationType: Constructor<T>): IServiceCollection; addScoped<T>(
serviceType: ServiceIdentifier<T>,
implementationType: Constructor<T>,
): IServiceCollection;
/** /**
* Registers a scoped service with a factory function * Registers a scoped service with a factory function
* *
* @template T - The type of the service * @template T - The type of the service
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param factory - A factory function that creates the service instance * @param factory - A factory function that creates the service instance
* @returns The service collection for method chaining * @returns The service collection for method chaining
*/ */
addScoped<T>(serviceType: ServiceIdentifier<T>, factory: ServiceFactory<T>): IServiceCollection; addScoped<T>(serviceType: ServiceIdentifier<T>, factory: ServiceFactory<T>): IServiceCollection;
/** /**
* Registers a transient service with the collection * Registers a transient service with the collection
* *
* @template T - The type of the service * @template T - The type of the service
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param implementationType - The implementation class * @param implementationType - The implementation class
* @returns The service collection for method chaining * @returns The service collection for method chaining
*/ */
addTransient<T>(serviceType: ServiceIdentifier<T>, implementationType: Constructor<T>): IServiceCollection; addTransient<T>(
serviceType: ServiceIdentifier<T>,
implementationType: Constructor<T>,
): IServiceCollection;
/** /**
* Registers a transient service with a factory function * Registers a transient service with a factory function
* *
* @template T - The type of the service * @template T - The type of the service
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @param factory - A factory function that creates the service instance * @param factory - A factory function that creates the service instance
* @returns The service collection for method chaining * @returns The service collection for method chaining
*/ */
addTransient<T>(serviceType: ServiceIdentifier<T>, factory: ServiceFactory<T>): IServiceCollection; addTransient<T>(
serviceType: ServiceIdentifier<T>,
factory: ServiceFactory<T>,
): IServiceCollection;
/** /**
* Builds a service provider from the registered services * Builds a service provider from the registered services
* *
* @returns A new service provider instance * @returns A new service provider instance
*/ */
build(): IServiceProvider; build(): IServiceProvider;
@@ -153,20 +168,20 @@ export interface IServiceCollection {
export interface IServiceProvider { export interface IServiceProvider {
/** /**
* Gets a service instance by its service identifier * Gets a service instance by its service identifier
* *
* @template T - The type of the service to resolve * @template T - The type of the service to resolve
* @param serviceType - The service identifier * @param serviceType - The service identifier
* @returns The resolved service instance * @returns The resolved service instance
*/ */
getService<T>(serviceType: ServiceIdentifier<T>): T; getService<T>(serviceType: ServiceIdentifier<T>): T;
/** /**
* Creates a new scope for scoped services * Creates a new scope for scoped services
* *
* @returns A new service scope * @returns A new service scope
*/ */
createScope(): IServiceScope; createScope(): IServiceScope;
/** /**
* Disposes the service provider and clears any scoped service instances * Disposes the service provider and clears any scoped service instances
*/ */
@@ -181,7 +196,7 @@ export interface IServiceScope {
* The service provider for this scope * The service provider for this scope
*/ */
serviceProvider: IServiceProvider; serviceProvider: IServiceProvider;
/** /**
* Disposes the scope and clears any scoped service instances * Disposes the scope and clears any scoped service instances
*/ */
+30 -28
View File
@@ -5,103 +5,102 @@ describe('ServiceCollection', () => {
it('should add a singleton service', () => { it('should add a singleton service', () => {
class TestService {} class TestService {}
const serviceIdentifier = createServiceIdentifier(); const serviceIdentifier = createServiceIdentifier();
const collection = new ServiceCollection(); const collection = new ServiceCollection();
collection.addSingleton(serviceIdentifier, TestService); collection.addSingleton(serviceIdentifier, TestService);
const provider = collection.build(); const provider = collection.build();
const serviceInstance1 = provider.getService(serviceIdentifier); const serviceInstance1 = provider.getService(serviceIdentifier);
const serviceInstance2 = provider.getService(serviceIdentifier); const serviceInstance2 = provider.getService(serviceIdentifier);
expect(serviceInstance1).toBe(serviceInstance2); expect(serviceInstance1).toBe(serviceInstance2);
}); });
it('should add a scoped service', () => { it('should add a scoped service', () => {
class TestService {} class TestService {}
const serviceIdentifier = createServiceIdentifier(); const serviceIdentifier = createServiceIdentifier();
const collection = new ServiceCollection(); const collection = new ServiceCollection();
collection.addScoped(serviceIdentifier, TestService); collection.addScoped(serviceIdentifier, TestService);
const provider = collection.build(); const provider = collection.build();
const scope1 = provider.createScope(); const scope1 = provider.createScope();
const scope2 = provider.createScope(); const scope2 = provider.createScope();
const serviceInstance1 = scope1.serviceProvider.getService(serviceIdentifier); const serviceInstance1 = scope1.serviceProvider.getService(serviceIdentifier);
const serviceInstance2 = scope2.serviceProvider.getService(serviceIdentifier); const serviceInstance2 = scope2.serviceProvider.getService(serviceIdentifier);
expect(serviceInstance1).not.toBe(serviceInstance2); expect(serviceInstance1).not.toBe(serviceInstance2);
}); });
it('should add a transient service', () => { it('should add a transient service', () => {
class TestService {} class TestService {}
const serviceIdentifier = createServiceIdentifier(); const serviceIdentifier = createServiceIdentifier();
const collection = new ServiceCollection(); const collection = new ServiceCollection();
collection.addTransient(serviceIdentifier, TestService); collection.addTransient(serviceIdentifier, TestService);
const provider = collection.build(); const provider = collection.build();
const serviceInstance1 = provider.getService(serviceIdentifier); const serviceInstance1 = provider.getService(serviceIdentifier);
const serviceInstance2 = provider.getService(serviceIdentifier); const serviceInstance2 = provider.getService(serviceIdentifier);
expect(serviceInstance1).not.toBe(serviceInstance2); expect(serviceInstance1).not.toBe(serviceInstance2);
}); });
it('should add a single service with a factory', () => { it('should add a single service with a factory', () => {
class TestService {} class TestService {}
const serviceIdentifier = createServiceIdentifier(); const serviceIdentifier = createServiceIdentifier();
const collection = new ServiceCollection(); const collection = new ServiceCollection();
collection.addSingleton(serviceIdentifier, () => new TestService()); collection.addSingleton(serviceIdentifier, () => new TestService());
const provider = collection.build(); const provider = collection.build();
const serviceInstance1 = provider.getService(serviceIdentifier); const serviceInstance1 = provider.getService(serviceIdentifier);
const serviceInstance2 = provider.getService(serviceIdentifier); const serviceInstance2 = provider.getService(serviceIdentifier);
expect(serviceInstance1).toBe(serviceInstance2); expect(serviceInstance1).toBe(serviceInstance2);
}); });
it('should add a scoped service with a factory', () => { it('should add a scoped service with a factory', () => {
class TestService {} class TestService {}
const serviceIdentifier = createServiceIdentifier(); const serviceIdentifier = createServiceIdentifier();
const collection = new ServiceCollection(); const collection = new ServiceCollection();
collection.addScoped(serviceIdentifier, () => new TestService()); collection.addScoped(serviceIdentifier, () => new TestService());
const provider = collection.build(); const provider = collection.build();
const scope1 = provider.createScope(); const scope1 = provider.createScope();
const scope2 = provider.createScope(); const scope2 = provider.createScope();
const serviceInstance1 = scope1.serviceProvider.getService(serviceIdentifier); const serviceInstance1 = scope1.serviceProvider.getService(serviceIdentifier);
const serviceInstance2 = scope2.serviceProvider.getService(serviceIdentifier); const serviceInstance2 = scope2.serviceProvider.getService(serviceIdentifier);
expect(serviceInstance1).not.toBe(serviceInstance2); expect(serviceInstance1).not.toBe(serviceInstance2);
}); });
it('should add a transient service with a factory', () => { it('should add a transient service with a factory', () => {
class TestService {} class TestService {}
const serviceIdentifier = createServiceIdentifier(); const serviceIdentifier = createServiceIdentifier();
const collection = new ServiceCollection(); const collection = new ServiceCollection();
collection.addTransient(serviceIdentifier, () => new TestService()); collection.addTransient(serviceIdentifier, () => new TestService());
const provider = collection.build(); const provider = collection.build();
const serviceInstance1 = provider.getService(serviceIdentifier); const serviceInstance1 = provider.getService(serviceIdentifier);
const serviceInstance2 = provider.getService(serviceIdentifier); const serviceInstance2 = provider.getService(serviceIdentifier);
expect(serviceInstance1).not.toBe(serviceInstance2); expect(serviceInstance1).not.toBe(serviceInstance2);
}); });
it('should add a service with a factory and dependencies', () => { it('should add a service with a factory and dependencies', () => {
type IDependencyService = object type IDependencyService = object;
class DependencyService implements IDependencyService {} class DependencyService implements IDependencyService {}
type ITestService = { type ITestService = {
dependency: IDependencyService; dependency: IDependencyService;
} };
class TestService implements ITestService { class TestService implements ITestService {
constructor(public dependency: DependencyService) {} constructor(public dependency: DependencyService) {}
} }
@@ -111,12 +110,15 @@ describe('ServiceCollection', () => {
const collection = new ServiceCollection(); const collection = new ServiceCollection();
collection.addSingleton(dependencyServiceIdentifier, DependencyService); collection.addSingleton(dependencyServiceIdentifier, DependencyService);
collection.addSingleton(testServiceIdentifier, (provider) => new TestService(provider.getService(dependencyServiceIdentifier))); collection.addSingleton(
testServiceIdentifier,
provider => new TestService(provider.getService(dependencyServiceIdentifier)),
);
const provider = collection.build(); const provider = collection.build();
const serviceInstance1 = provider.getService(testServiceIdentifier); const serviceInstance1 = provider.getService(testServiceIdentifier);
const serviceInstance2 = provider.getService(testServiceIdentifier); const serviceInstance2 = provider.getService(testServiceIdentifier);
expect(serviceInstance1).toBe(serviceInstance2); expect(serviceInstance1).toBe(serviceInstance2);
expect(serviceInstance1.dependency).toBe(serviceInstance2.dependency); expect(serviceInstance1.dependency).toBe(serviceInstance2.dependency);
}); });
+13 -13
View File
@@ -247,7 +247,7 @@ describe('ServiceProvider', () => {
); );
const userService = serviceProvider.getService(userServiceIdentifier); const userService = serviceProvider.getService(userServiceIdentifier);
const user = userService.getUser(); const user = userService.getUser();
expect(user).toBe('John Doe'); expect(user).toBe('John Doe');
@@ -255,9 +255,9 @@ describe('ServiceProvider', () => {
it('should throw an error when service has invalid lifetime', () => { it('should throw an error when service has invalid lifetime', () => {
type IService = object; type IService = object;
const serviceIdentifier = createServiceIdentifier<IService>(); const serviceIdentifier = createServiceIdentifier<IService>();
const serviceProvider = new ServiceProvider( const serviceProvider = new ServiceProvider(
new Map([ new Map([
[ [
@@ -341,9 +341,9 @@ describe('ServiceProvider', () => {
); );
const initialService = serviceProvider.getService(serviceIdentifier); const initialService = serviceProvider.getService(serviceIdentifier);
serviceProvider.dispose(); serviceProvider.dispose();
const newService = serviceProvider.getService(serviceIdentifier); const newService = serviceProvider.getService(serviceIdentifier);
expect(initialService).not.toBe(newService); expect(initialService).not.toBe(newService);
@@ -380,9 +380,9 @@ describe('ServiceProvider', () => {
const scope = serviceProvider.createScope(); const scope = serviceProvider.createScope();
const initialService = scope.serviceProvider.getService(serviceIdentifier); const initialService = scope.serviceProvider.getService(serviceIdentifier);
scope.dispose(); scope.dispose();
const newService = scope.serviceProvider.getService(serviceIdentifier); const newService = scope.serviceProvider.getService(serviceIdentifier);
expect(initialService).not.toBe(newService); expect(initialService).not.toBe(newService);
@@ -419,15 +419,15 @@ describe('ServiceProvider', () => {
const scope = serviceProvider.createScope(); const scope = serviceProvider.createScope();
const initialService = scope.serviceProvider.getService(serviceIdentifier); const initialService = scope.serviceProvider.getService(serviceIdentifier);
serviceProvider.dispose(); serviceProvider.dispose();
const newService = scope.serviceProvider.getService(serviceIdentifier); const newService = scope.serviceProvider.getService(serviceIdentifier);
expect(initialService).toBe(newService); expect(initialService).toBe(newService);
}); });
it("should not clear the scoped instances on dispose from another scope when one scope is disposed", () => { it('should not clear the scoped instances on dispose from another scope when one scope is disposed', () => {
type IService = { type IService = {
id: string; id: string;
}; };
@@ -460,9 +460,9 @@ describe('ServiceProvider', () => {
const initialService1 = scope1.serviceProvider.getService(serviceIdentifier); const initialService1 = scope1.serviceProvider.getService(serviceIdentifier);
const initialService2 = scope2.serviceProvider.getService(serviceIdentifier); const initialService2 = scope2.serviceProvider.getService(serviceIdentifier);
scope1.dispose(); scope1.dispose();
const newService1 = scope1.serviceProvider.getService(serviceIdentifier); const newService1 = scope1.serviceProvider.getService(serviceIdentifier);
const newService2 = scope2.serviceProvider.getService(serviceIdentifier); const newService2 = scope2.serviceProvider.getService(serviceIdentifier);
@@ -501,7 +501,7 @@ describe('ServiceProvider', () => {
], ],
]), ]),
); );
expect(() => { expect(() => {
serviceProvider.getService(userServiceIdentifier); serviceProvider.getService(userServiceIdentifier);
}).toThrowError(); }).toThrowError();