projects/wms-framework/src/lib/regionsframework/SimpleDIContainer.ts
Metadata decoration to identify property that will be injected
Properties |
Methods |
|
constructor(p1?: any, p2?: any)
|
Public name |
Type : string
|
The name of the dependency |
Public typeInfo |
Type : RuntimeTypeInfo | ReifiedInterfaceInfo | Function
|
The type information of the dependency |
Public OnAppliedTo | ||||||
OnAppliedTo(target: any)
|
||||||
Inherited from
MetadataAttribute
|
||||||
Defined in
MetadataAttribute:33
|
||||||
On applied to a soruce element
Parameters :
Returns :
void
|
import {
RuntimeTypeInfo,
ReifiedInterfaceInfo,
MetadataAttribute,
ReflectionHelper,
getAsExplicitContractForType,
ClassType,
} from '../baseframework';
import {
DependencyContainer,
container as tsyringeContainer,
RegistrationOptions,
InjectionToken,
Lifecycle,
} from 'tsyringe';
import { containerInjectionToken } from './injectionTokens';
import { Debugger } from '../diagnostics/Debugger';
/**
* Calls `Dispose()` on all instances within this container.
*
* NOTE: this function should be called in the context of a `DependencyContainer`.
*/
function disposeDIContainer(container: any): void {
const disposedSet = new Set<any>();
for (const registrations of container._registry._registryMap.values()) {
registrations
.filter((x) => !!x.instance)
.forEach((x) => {
/* istanbul ignore else */
if (!disposedSet.has(x.instance)) {
disposedSet.add(x.instance);
genericDispose(x.instance);
}
});
}
}
export function createDIContainer(): DependencyContainer {
return initializeDIContainer(tsyringeContainer.createChildContainer());
}
export function initializeDIContainer(
container: DependencyContainer
): DependencyContainer {
container.registerInstance(containerInjectionToken, container);
(container as any).Dispose = () => disposeDIContainer(container);
return container;
}
/**
* Tries to resolve the given element in the specified container
*
* If the class for the given injection token could not be created this funtion return null
* @export
* @template T
* @param {DependencyContainer} container
* @param {InjectionToken<T>} token
* @return {*} A new instance of the object or `null` if the instance could not be created
*/
export function tryResolveInContainer<T>(
token: InjectionToken<T> | RuntimeTypeInfo | ReifiedInterfaceInfo,
container: DependencyContainer
): T {
let result: T = null;
try {
if (token instanceof RuntimeTypeInfo && token.JSType) {
result = container.resolve<T>(token.JSType);
} else if (token instanceof ReifiedInterfaceInfo) {
result = container.resolve<T>(token.interfaceName);
} else {
result = container.resolve<T>(token as InjectionToken);
}
} catch (_) {
result = null;
}
return result;
}
export function genericDispose(obj: any) {
if (typeof obj.Dispose === 'function') {
obj.Dispose();
}
}
/**
* Helper function to register resolution for a type based on a interface, when the interface is registered
* it also is registered the type with the same RegistrationOptions
*
* @export
* @template T
* @param {DependencyContainer} container
* @param {string} token
* @param {*} typeMapInfo
* @param {RegistrationOptions} options
*/
export function registerTypeWithInterface<T>(
container: DependencyContainer,
token: string,
typeMapInfo: any,
options: RegistrationOptions = { lifecycle: Lifecycle.Transient }
) {
var explicitContractForType = getAsExplicitContractForType(
token,
typeMapInfo
);
if (explicitContractForType !== null) {
container.register(typeMapInfo, typeMapInfo, options);
container.register(token, {
useFactory: (c) => {
return c.resolve(typeMapInfo)[explicitContractForType]();
},
});
} else {
container.register(typeMapInfo, typeMapInfo, options);
container.register(token, { useToken: typeMapInfo }, options);
}
}
export function registerTypeExtended(
container: DependencyContainer,
type1: any,
type2: any,
lifetimeManager: unknown,
injectionToken?: string
): DependencyContainer {
container.registerInstance(type1 + (injectionToken ?? ''), type2);
return container;
}
export function registerWithRuntimeTypeInfo<T>(
container: DependencyContainer,
typeInfo: RuntimeTypeInfo | Function,
options: RegistrationOptions
);
export function registerWithRuntimeTypeInfo<T>(
container: DependencyContainer,
typeInfo: RuntimeTypeInfo | Function,
name?: string,
options?: RegistrationOptions
);
export function registerWithRuntimeTypeInfo<T>(
container: DependencyContainer,
typeInfo: RuntimeTypeInfo | Function,
nameOrOptionsArg?: unknown,
optionsArg?: unknown
) {
if (typeInfo instanceof RuntimeTypeInfo) {
if (typeof nameOrOptionsArg === 'string') {
container.register(
nameOrOptionsArg,
typeInfo.JSType,
optionsArg as RegistrationOptions
);
} else if (typeof nameOrOptionsArg === 'object') {
container.register(
typeInfo.JSType,
typeInfo.JSType,
optionsArg as RegistrationOptions
);
} else {
container.registerType(typeInfo.JSType, typeInfo.JSType);
}
} else {
Debugger.Throw('Not implemented');
}
}
/**
* Registers a type inside a container using runtime type information
*
* @export
* @template T Inner type
* @param {DependencyContainer} container injectino container
* @param {(RuntimeTypeInfo | Function)} typeInfo runtime type information
* @param {*} obj object to register
* @param {*} [ltmanager] registration options
*/
export function registerInstanceWithRuntimeTypeInfo<T>(
container: DependencyContainer,
typeInfo: RuntimeTypeInfo | Function,
obj: any,
ltmanager?: any
);
export function registerInstanceWithRuntimeTypeInfo<T>(
container: DependencyContainer,
name: string,
obj: any,
ltmanager?: any
);
export function registerInstanceWithRuntimeTypeInfo<T>(
container: DependencyContainer,
name: string,
typeInfo: RuntimeTypeInfo | Function,
obj: any,
ltmanager?: any
);
export function registerInstanceWithRuntimeTypeInfo<T>(
container: DependencyContainer,
p0: unknown,
p1?: unknown,
p2?: unknown,
p3?: unknown
) {
if (
p0 instanceof RuntimeTypeInfo &&
p0.JSType instanceof ReifiedInterfaceInfo &&
typeof p1 !== 'undefined'
) {
container.registerInstance(p0.JSType.interfaceName, p1);
} else if (
typeof p0 === 'string' &&
p1 instanceof RuntimeTypeInfo &&
p1.JSType instanceof ReifiedInterfaceInfo &&
typeof p2 !== 'undefined'
) {
container.registerInstance(p1.JSType.interfaceName + '/' + p0, p2);
} else if (p0 instanceof RuntimeTypeInfo) {
container.registerInstance(p0.JSType, p1);
} else {
Debugger.Throw('Not implemented');
}
}
export function resolveWithRuntimeTypeInfo<T>(
container: DependencyContainer,
typeInfo: RuntimeTypeInfo | ClassType
): T {
if (typeInfo instanceof RuntimeTypeInfo) {
return container.resolve(typeInfo.JSType) as T;
} else if (typeInfo instanceof ReifiedInterfaceInfo) {
return container.resolve(typeInfo.interfaceName) as T;
} else {
return container.resolve(typeInfo as any) as T;
}
}
export interface ISimpleDIServiceLocator {
Resolve<T>(typeInfo: RuntimeTypeInfo): T;
}
export class SimpleDIServiceLocator implements ISimpleDIServiceLocator {
public static Current: ISimpleDIServiceLocator = new SimpleDIServiceLocator();
Resolve<T>(typeInfo: RuntimeTypeInfo): T {
Debugger.Throw('Method not implemented.');
return null;
}
}
/**
* Metadata decoration to identify property that will be injected
*
* @export
* @class DIContainerDependency
* @extends {MetadataAttribute}
*/
export class DIContainerDependency extends MetadataAttribute {
/**
* The name of the dependency
*
* @type {string}
* @memberof DIContainerDependency
*/
public name: string;
/**
* The type information of the dependency
*
* @type {(RuntimeTypeInfo | ReifiedInterfaceInfo | Function)}
* @memberof DIContainerDependency
*/
public typeInfo: RuntimeTypeInfo | ReifiedInterfaceInfo | Function;
/**
* Creates an instance of DIContainerDependency.
* @param {(RuntimeTypeInfo | ReifiedInterfaceInfo | Function)} [typeInfo]
* @memberof DIContainerDependency
*/
constructor(typeInfo?: RuntimeTypeInfo | ReifiedInterfaceInfo | Function);
constructor(
name?: string,
typeInfo?: RuntimeTypeInfo | ReifiedInterfaceInfo | Function
);
constructor(p1?: any, p2?: any) {
super();
if (typeof p1 === 'string') {
this.name = p1;
this.typeInfo = p2;
} else {
this.typeInfo = p1;
}
}
}
/**
* Injects decorated properties to an existing object.
*
* This function inspects an object instance and for all properties
* having the `DIContainerDependency` metadata decoration it injects
* a resolved object to the decorated property
*
* @export
* @template T
* @param {DependencyContainer} container to use
* @param {T} obj object to process
* @return {*} {T}
*/
export function injectDecoratedProperties<T>(
container: DependencyContainer,
obj: T
): T {
let info = ReflectionHelper.getTypeInfo(obj.constructor);
for (const propertyInformation of info.getProperties()) {
for (const metadata of propertyInformation.getMetadataAttributes()) {
if (
metadata instanceof DIContainerDependency &&
propertyInformation.propertyType
) {
let typeFromPropertyInfo: any = null;
if (metadata.typeInfo instanceof ReifiedInterfaceInfo) {
typeFromPropertyInfo = metadata.typeInfo.interfaceName;
} else if (metadata.typeInfo instanceof Function) {
typeFromPropertyInfo = metadata.typeInfo;
} else if (metadata.typeInfo instanceof RuntimeTypeInfo) {
typeFromPropertyInfo =
metadata.typeInfo.JSType instanceof ReifiedInterfaceInfo
? (metadata.typeInfo.JSType as ReifiedInterfaceInfo).interfaceName
: metadata.typeInfo.JSType;
} else {
typeFromPropertyInfo =
propertyInformation.propertyType.JSType ??
propertyInformation.propertyType;
}
obj[propertyInformation.Name] = container.resolve(typeFromPropertyInfo);
}
}
}
return obj;
}
export class SimpleDIBootstrapper {
Container: DependencyContainer;
ConfigureContainer() {
Debugger.Throw('Not implemented');
}
InitializeModules() {
Debugger.Throw('Not implemented');
}
Run() {
Debugger.Throw('Not implemented');
}
public ConfigureRegionAdapterMappings() {
Debugger.Throw('Not implemented');
}
}