Skip to content

Commit

Permalink
feat(ServiceManager): fix typings and add support for shareable services
Browse files Browse the repository at this point in the history
  • Loading branch information
RWOverdijk committed Sep 22, 2018
1 parent 069edd5 commit 6b12b66
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/Library/ServiceManager/FactoryInterface.ts
@@ -1,2 +1,2 @@
export interface FactoryInterface {
export interface FactoryInterface extends Function {
}
28 changes: 21 additions & 7 deletions src/Library/ServiceManager/ServiceManager.ts
@@ -1,6 +1,7 @@
import { ServiceManagerInterface } from './ServiceManagerInterface';
import { ServicesMapType, FactoriesMapType, AliasesType, ServiceKeyType, ServiceFactoryType, SharedMapType, ServiceManagerConfigType, ServiceType } from './ServiceManagerConfigInterface';
import { ServicesMapType, FactoriesMapType, AliasesType, ServiceKeyType, ServiceFactoryType, SharedMapType, ServiceManagerConfigType } from './ServiceManagerConfigInterface';
import { NotFoundError } from '../Error';
import { Instantiable } from '../Core/Types';

/**
* @export
Expand Down Expand Up @@ -29,17 +30,18 @@ export class ServiceManager implements ServiceManagerInterface {
}

public get<T>(Service: ServiceKeyType<T>, forceTransient: boolean = false): T {
const resolvedName = this.resolveName(Service) as ServiceType<T>;
const resolvedName = this.resolveName(Service) as ServiceKeyType<T>;

if (!this.has(resolvedName)) {
throw new NotFoundError(`Unable to locate service "${typeof Service === 'string' ? Service : Service.name}".`);
}

if (forceTransient || !this.services.has(resolvedName)) {
const service = this.factories.get(resolvedName)(this.creationContext) as T;
const shared = this.shared.has(resolvedName) ? this.shared.get(resolvedName) : this.sharedByDefault;

// We just needed a new instance or we don't want our instances to be shared.. Return service.
if (forceTransient || (!this.sharedByDefault && !this.shared.has(resolvedName))) {
if (forceTransient || !shared) {
return service;
}

Expand All @@ -50,7 +52,7 @@ export class ServiceManager implements ServiceManagerInterface {
}

has<T>(Service: ServiceKeyType<T>): boolean {
const resolvedName = this.resolveName(Service) as ServiceType<T>;
const resolvedName = this.resolveName(Service) as ServiceKeyType<T>;

return this.services.has(resolvedName) || this.factories.has(resolvedName);
}
Expand Down Expand Up @@ -81,15 +83,15 @@ export class ServiceManager implements ServiceManagerInterface {
}

if (config.shared instanceof Map) {
config.shared.forEach((value, key: Function | string) => this.shared.set(key, value));
config.shared.forEach((value, key: ServiceKeyType<Object>) => this.shared.set(key, value));
}

if (config.services instanceof Map) {
config.services.forEach((value, key: Function | string) => this.services.set(key, value));
config.services.forEach((value, key: ServiceKeyType<Object>) => this.services.set(key, value));
}

if (config.invokables instanceof Map) {
config.invokables.forEach((value, key: Function | string) => {
config.invokables.forEach((value: Instantiable<Object>, key: ServiceKeyType<Object>) => {
this.factories.set(key, () => new value);
});
}
Expand All @@ -105,6 +107,18 @@ export class ServiceManager implements ServiceManagerInterface {
return this;
}

public registerAliases(aliases: AliasesType): this {
Object.assign(this.aliases, aliases);

return this;
}

public registerAlias(alias: string, to: string | Function): this {
this.aliases[alias] = to;

return this;
}

private resolveName<T>(name: ServiceKeyType<T>): ServiceKeyType<T> {
if (typeof name !== 'string') {
return name;
Expand Down
10 changes: 5 additions & 5 deletions src/Library/ServiceManager/ServiceManagerConfigInterface.ts
@@ -1,20 +1,20 @@
import { ServiceManagerInterface } from './ServiceManagerInterface';

export interface ServiceType<T> extends Function { new (...args: any[]): T; }
import { Instantiable } from '../Core/Types';
import { FactoryInterface } from './FactoryInterface';

export interface ServiceFactoryType<T> extends Function { (sm?: ServiceManagerInterface): T; }

export type FactoriesMapType = Map<Function | string, ServiceFactoryType<Object>>;
export type FactoriesMapType = Map<Function | string, FactoryInterface>;

export type ServicesMapType = Map<Function | string, Object>;

export type InvokablesMapType<T> = Map<Function | string, { new (...args: any[]): T; }>;
export type InvokablesMapType<T> = Map<Instantiable<Object> | string, Instantiable<T>>;

export type AliasesType = { [alias: string]: string | Function };

export type SharedMapType = Map<Function | string, Object>;

export type ServiceKeyType<T> = ServiceType<T> | string;
export type ServiceKeyType<T> = Instantiable<T> | string;

export type ServiceManagerConfigType = Partial<{
sharedByDefault: boolean;
Expand Down

0 comments on commit 6b12b66

Please sign in to comment.