File

projects/wms-framework/src/lib/regionsframework/SimpleDIContainer.ts

Implements

ISimpleDIServiceLocator

Index

Properties
Methods

Properties

Static Current
Type : ISimpleDIServiceLocator
Default value : new SimpleDIServiceLocator()

Methods

Resolve
Resolve(typeInfo: RuntimeTypeInfo)
Type parameters :
  • T
Parameters :
Name Type Optional
typeInfo RuntimeTypeInfo No
Returns : T
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');
  }
}

result-matching ""

    No results matching ""