UNPKG

@kephas/core

Version:

Provides a common infrastructure for all the other Kephas Framework components: ambient services, dynamic reflection, composition, application management, and others.

1 lines 83.1 kB
{"version":3,"file":"kephas-core.mjs","sources":["../../../../projects/kephas/core/src/lib/argumentError.ts","../../../../projects/kephas/core/src/lib/diagnostics/contracts/requires.ts","../../../../projects/kephas/core/src/lib/notImplementedError.ts","../../../../projects/kephas/core/src/lib/notSupportedError.ts","../../../../projects/kephas/core/src/lib/sealed.ts","../../../../projects/kephas/core/src/lib/expando.ts","../../../../projects/kephas/core/src/lib/commands/args.ts","../../../../projects/kephas/core/src/lib/services/context.ts","../../../../projects/kephas/core/src/lib/services/serviceError.ts","../../../../projects/kephas/core/src/lib/services/appServiceMetadata.ts","../../../../projects/kephas/core/src/lib/services/appServiceInfo.ts","../../../../projects/kephas/core/src/lib/services/appServiceInfoRegistry.ts","../../../../projects/kephas/core/src/lib/services/appService.ts","../../../../projects/kephas/core/src/lib/services/appServiceContract.ts","../../../../projects/kephas/core/src/lib/deferrable.ts","../../../../projects/kephas/core/src/lib/services/serviceHelper.ts","../../../../projects/kephas/core/src/lib/logging/logger.ts","../../../../projects/kephas/core/src/lib/injection/injectionError.ts","../../../../projects/kephas/core/src/lib/injection/injector.ts","../../../../projects/kephas/core/src/lib/injection/liteInjector.ts","../../../../projects/kephas/core/src/lib/serialization/serializable.ts","../../../../projects/kephas/core/src/lib/namespace.ts","../../../../projects/kephas/core/src/lib/type.ts","../../../../projects/kephas/core/src/lib/cryptography/hashingService.ts","../../../../projects/kephas/core/src/lib/interaction/eventHub.ts","../../../../projects/kephas/core/src/public-api.ts","../../../../projects/kephas/core/src/kephas-core.ts"],"sourcesContent":["/**\r\n * Signals that an argument is not valid.\r\n *\r\n * @export\r\n * @class ArgumentError\r\n * @extends {Error}\r\n */\r\nexport class ArgumentError extends Error {\r\n /**\r\n * Creates an instance of ArgumentError.\r\n * @param {string} message The error message.\r\n * @param {string} argName The argument name.\r\n * @memberof ArgumentError\r\n */\r\n constructor(message: string, public argName: string) {\r\n super(message);\r\n }\r\n}","import { ArgumentError } from \"../../argumentError\";\r\n\r\n/**\r\n * Provides contract checks.\r\n *\r\n * @export\r\n * @class Requires\r\n */\r\nexport class Requires {\r\n /**\r\n * Requires that the argument has a value (not null or undefined or empty).\r\n *\r\n * @static\r\n * @param {*} value\r\n * @param {string} name\r\n * @memberof Requires\r\n */\r\n public static HasValue(value: any, name: string) {\r\n if (!value) {\r\n throw new ArgumentError(`The argument '${name}' is not set.`, name);\r\n }\r\n }\r\n}\r\n","/**\r\n * Signals that an operation does not have a proper implementation.\r\n *\r\n * @export\r\n * @class NotImplementedError\r\n * @extends {Error}\r\n */\r\nexport class NotImplementedError extends Error {\r\n /**\r\n * Creates an instance of NotImplementedError.\r\n * @param {string} message The error message.\r\n * @memberof ArgumentError\r\n */\r\n constructor(message: string) {\r\n super(message);\r\n }\r\n}","/**\r\n * Signals that an operation is not supported.\r\n *\r\n * @export\r\n * @class NotSupportedError\r\n * @extends {Error}\r\n */\r\nexport class NotSupportedError extends Error {\r\n /**\r\n * Creates an instance of NotSupportedError.\r\n * @param {string} message The error message.\r\n * @memberof ArgumentError\r\n */\r\n constructor(message: string) {\r\n super(message);\r\n }\r\n}","/**\r\n * Class decorator for preventing it being specialized.\r\n *\r\n * @export\r\n * @param {Function} ctor The decorated class.\r\n */\r\nexport function Sealed(ctor: Function) {\r\n Object.freeze(ctor);\r\n Object.freeze(ctor.prototype);\r\n}","/**\r\n * Provides the functionality of a dynamic object.\r\n *\r\n * @export\r\n * @class Expando\r\n */\r\nexport class Expando {\r\n [key: string]: any;\r\n}","import { Expando } from \"../expando\";\r\n\r\n/**\r\n * Arguments used in command line execution.\r\n *\r\n * @export\r\n * @class Args\r\n * @implements {Expando}\r\n */\r\nexport class Args implements Expando {\r\n /**\r\n * Creates an instance of Args.\r\n * @param {(string | string[] | {})} [args] The arguments.\r\n * @memberof Args\r\n */\r\n constructor(args?: string | string[] | {}) {\r\n if (typeof args === 'string') {\r\n this._fillArgsFromString(args, this);\r\n }\r\n else if (Array.isArray(args)) {\r\n this._fillArgsFromStringArray(args, this);\r\n }\r\n else if (typeof args === 'object') {\r\n this._fillArgsFromObject(args, this);\r\n }\r\n }\r\n\r\n private _fillArgsFromObject(source: {}, target: Expando): Expando {\r\n for(let key in source) {\r\n target[key] = (source as Expando)[key];\r\n }\r\n return target;\r\n }\r\n\r\n private _fillArgsFromString(source: string, target: Expando): Expando {\r\n var args = source.split(' ').filter(i => i !== '');\r\n return this._fillArgsFromStringArray(args, target);\r\n }\r\n\r\n private _fillArgsFromStringArray(source: string[], target: Expando): Expando {\r\n let key = '';\r\n let value: any = null;\r\n let expectedValue = false;\r\n\r\n for (let currentArg of source) {\r\n var keyStartIndex = 0;\r\n\r\n if (currentArg.startsWith(\"--\")) {\r\n keyStartIndex = 2;\r\n }\r\n else if (currentArg.startsWith(\"-\")) {\r\n keyStartIndex = 1;\r\n }\r\n else if (currentArg.startsWith(\"/\")) {\r\n // \"/SomeSwitch\" is equivalent to \"--SomeSwitch\"\r\n keyStartIndex = 1;\r\n }\r\n\r\n // if we received a new argument, but we expected a value, add the previous key with the value \"true\"\r\n if (expectedValue) {\r\n expectedValue = false;\r\n\r\n if (keyStartIndex > 0) {\r\n // set the previous key to true and continue with processing the current arg\r\n target[key] = true;\r\n }\r\n else {\r\n target[key] = Args._unescape(currentArg);\r\n continue;\r\n }\r\n }\r\n\r\n // currentArg starts a new argument\r\n var separator = currentArg.indexOf('=');\r\n\r\n if (separator >= 0) {\r\n // currentArg specifies a key with value\r\n key = Args._unescape(currentArg.substr(keyStartIndex, separator - keyStartIndex));\r\n value = Args._unescape(currentArg.substr(separator + 1));\r\n }\r\n else {\r\n // currentArg specifies only a key\r\n // If there is no prefix in current argument, consider it as a key with value \"true\"\r\n if (keyStartIndex == 0) {\r\n key = Args._unescape(currentArg);\r\n value = true;\r\n }\r\n else {\r\n key = Args._unescape(currentArg.substr(keyStartIndex));\r\n expectedValue = true;\r\n }\r\n }\r\n\r\n // Override value when key is duplicated. So we always have the last argument win.\r\n if (!expectedValue) {\r\n target[key] = value;\r\n }\r\n }\r\n\r\n if (expectedValue) {\r\n target[key] = true;\r\n }\r\n\r\n return target;\r\n }\r\n\r\n private static _unescape(value: string): string\r\n {\r\n if (value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\"))\r\n {\r\n value = value.substr(1, value.length - 2);\r\n return value.replace(\"\\\\\\\"\", \"\\\"\");\r\n }\r\n\r\n return value;\r\n }\r\n}\r\n","import { Expando } from \"../expando\";\r\n\r\n/**\r\n * Provides contextual information.\r\n *\r\n * @export\r\n * @class Context\r\n */\r\nexport class Context extends Expando {\r\n}\r\n","/**\r\n * Signals an error with respect to a service or its registration.\r\n *\r\n * @export\r\n * @class ServiceError\r\n * @extends {Error}\r\n */\r\nexport class ServiceError extends Error {\r\n /**\r\n * Creates an instance of ServiceError.\r\n * @param {string} message The error message.\r\n * @memberof ServiceError\r\n */\r\n constructor(message: string) {\r\n super(message);\r\n }\r\n}","import { Injector } from \"../injection/injector\";\r\nimport { Type } from \"../type\";\r\nimport { AppServiceInfo } from \"./appServiceInfo\";\r\n\r\n/**\r\n * Enumerates the priority values.\r\n * They are practically a convenient way to provide integer values for defining priorities.\r\n * A lower value indicates a higher priority.\r\n *\r\n * @export\r\n * @enum {number}\r\n */\r\nexport enum Priority {\r\n /**\r\n * The lowest priority. Typically used by the null services.\r\n */\r\n Lowest = 2147483647,\r\n\r\n /**\r\n * The low priority. Typically used by the default services.\r\n */\r\n Low = 1000000,\r\n\r\n /**\r\n * The below normal priority. Typically used by services with a higher specialization than the default ones.\r\n */\r\n BelowNormal = 1000,\r\n\r\n /**\r\n * The normal priority (the default).\r\n */\r\n Normal = 0,\r\n\r\n /**\r\n * The above normal priority.\r\n */\r\n AboveNormal = -1000,\r\n\r\n /**\r\n * The high priority.\r\n */\r\n High = -1000000,\r\n\r\n /**\r\n * The highest priority.\r\n */\r\n Highest = -2147483648,\r\n}\r\n\r\n/**\r\n * Metadata for application services.\r\n *\r\n * @export\r\n * @class AppServiceMetadata\r\n */\r\nexport class AppServiceMetadata<T> {\r\n /**\r\n * Gets the override priority.\r\n *\r\n * @type {number}\r\n * @memberof AppServiceInfo\r\n */\r\n public readonly overridePriority: number = Priority.Normal;\r\n\r\n /**\r\n * Gets the processing priority.\r\n *\r\n * @type {number}\r\n * @memberof AppServiceInfo\r\n */\r\n public readonly processingPriority: number = Priority.Normal;\r\n\r\n /**\r\n * Gets the service name.\r\n *\r\n * @type {string}\r\n * @memberof AppServiceMetadata\r\n */\r\n public readonly serviceName?: string;\r\n\r\n /**\r\n * Gets the service implementation type.\r\n *\r\n * @type {Function}\r\n * @memberof AppServiceMetadata\r\n */\r\n public get serviceType(): Type<T> | undefined {\r\n return this._serviceType;\r\n }\r\n\r\n /**\r\n * Gets the application service contract information.\r\n *\r\n * @type {AppServiceInfo}\r\n * @memberof AppServiceMetadata\r\n */\r\n public get serviceContract(): AppServiceInfo | undefined {\r\n return this._serviceContract;\r\n }\r\n\r\n /**\r\n * Gets the service instance.\r\n *\r\n * @type {T}\r\n * @memberof AppServiceMetadata\r\n */\r\n public get serviceInstance(): T | undefined {\r\n return this._serviceInstance;\r\n }\r\n\r\n /**\r\n * Gets or sets the service factory.\r\n *\r\n * @type {(c: Injector) => T}\r\n * @memberof AppServiceMetadata\r\n */\r\n public readonly serviceFactory?: (c: Injector) => T;\r\n\r\n private _serviceContract?: AppServiceInfo;\r\n private _serviceType?: Type<T>;\r\n private _serviceInstance?: T;\r\n\r\n /**\r\n * Creates an instance of AppServiceMetadata.\r\n *\r\n * @param {number|Priority} [overridePriority=Priority.Normal] Optional. The override priority.\r\n * @param {number|Priority} [processingPriority=Priority.Normal] Optional. The processing priority.\r\n * @param {string} [serviceName] Optional. The service name.\r\n * @param {Type<T>} [serviceType] Optional. The service implementation type.\r\n * @param {() => T} [serviceFactory] Optional. The service factory.\r\n * @param {T} [serviceInstance] Optional. The service instance.\r\n * @param {AppServiceInfo} [serviceContract] Optional. The service contract.\r\n * @memberof AppServiceMetadata\r\n */\r\n constructor(\r\n {\r\n overridePriority = Priority.Normal,\r\n processingPriority = Priority.Normal,\r\n serviceName,\r\n serviceType,\r\n serviceFactory,\r\n serviceInstance,\r\n ...args\r\n }: {\r\n overridePriority?: number | Priority;\r\n processingPriority?: number | Priority;\r\n serviceName?: string;\r\n serviceType?: Type<T>;\r\n serviceFactory?: (c: Injector) => T;\r\n serviceInstance?: T;\r\n [key: string]: any;\r\n } = {}) {\r\n this.overridePriority = overridePriority;\r\n this.processingPriority = processingPriority;\r\n this.serviceName = serviceName;\r\n this.serviceFactory = serviceFactory;\r\n this._serviceInstance = serviceInstance;\r\n this._serviceType = serviceType;\r\n Object.assign(this, args);\r\n }\r\n}\r\n","import { Expando } from \"../expando\";\r\nimport { AbstractType } from \"../type\";\r\nimport { AppServiceMetadata } from \"./appServiceMetadata\";\r\nimport { ServiceError } from \"./serviceError\";\r\n\r\n/**\r\n * Enumerates the lifetime values for application services.\r\n *\r\n * @export\r\n * @enum {number}\r\n */\r\nexport enum AppServiceLifetime {\r\n /**\r\n * The application service is shared (default).\r\n */\r\n Singleton,\r\n\r\n /**\r\n * The application service in instantiated with every request.\r\n */\r\n Transient,\r\n\r\n /**\r\n * The application service is shared within a scope.\r\n */\r\n Scoped,\r\n}\r\n\r\n/**\r\n * Provides information about the application service.\r\n *\r\n * @export\r\n * @class AppServiceInfo\r\n */\r\nexport class AppServiceInfo implements Expando {\r\n /**\r\n * Gets a value indicating whether multiple services for this contract are allowed.\r\n *\r\n * @type {boolean}\r\n * @memberof AppServiceInfo\r\n */\r\n public readonly allowMultiple: boolean = false;\r\n\r\n /**\r\n * Gets the application service lifetime.\r\n *\r\n * @type {AppServiceLifetime}\r\n * @memberof AppServiceInfo\r\n */\r\n public readonly lifetime: AppServiceLifetime = AppServiceLifetime.Singleton;\r\n\r\n /**\r\n * Gets the contract type of the service.\r\n *\r\n * @type {AbstractType}\r\n * @memberof AppServiceInfo\r\n */\r\n public readonly contractType: AbstractType;\r\n\r\n /**\r\n * Gets the contract token of the service.\r\n *\r\n * @type {*}\r\n * @memberof AppServiceInfo\r\n */\r\n public readonly contractToken: any;\r\n\r\n /**\r\n * Gets an iteration of registered services.\r\n *\r\n * @readonly\r\n * @type {IterableIterator<AppServiceMetadata>}\r\n * @memberof AppServiceInfo\r\n */\r\n public get services(): IterableIterator<AppServiceMetadata<any>> {\r\n return this._services.values();\r\n }\r\n\r\n private _services: AppServiceMetadata<any>[] = [];\r\n\r\n /**\r\n * Creates an instance of AppServiceInfo.\r\n * @param {Type<T>} contractType The contract type.\r\n * @param {*} contractToken The contract token.\r\n * @param {boolean} [allowMultiple=false] Indicates whether multiple instances of the provided\r\n * @param {AppServiceLifetime} [lifetime=AppServiceLifetime.Singleton] The application service lifetime.\r\n * @memberof AppServiceInfo\r\n */\r\n constructor(\r\n {\r\n contractType,\r\n contractToken,\r\n allowMultiple = false,\r\n lifetime = AppServiceLifetime.Singleton,\r\n ...args\r\n }: {\r\n contractType: AbstractType;\r\n contractToken?: any;\r\n allowMultiple?: boolean;\r\n lifetime?: AppServiceLifetime;\r\n [key: string]: any;\r\n }) {\r\n this.contractType = contractType;\r\n this.contractToken = contractToken;\r\n this.allowMultiple = allowMultiple;\r\n this.lifetime = lifetime;\r\n Object.assign(this, args);\r\n }\r\n\r\n /**\r\n * Registers a service implementation for this contract.\r\n *\r\n * @template T The service implementation type.\r\n * @param {AppServiceMetadata<T>} service\r\n * @returns {(boolean | ServiceError | AppServiceMetadata<any>)}\r\n * True, if the service was registered successfully.\r\n * False, if the service was not registered due to a higher override priority service already registered.\r\n * ServiceError, if a service is already registered with the same override priority.\r\n * AppServiceMetadata<any>, if the service to register overrid an existing one. The overridden service is returned.\r\n * @memberof AppServiceInfo\r\n */\r\n private registerService<T>(service: AppServiceMetadata<T>): boolean | ServiceError | AppServiceMetadata<any> {\r\n if (this.allowMultiple) {\r\n this._services.push(service);\r\n return true;\r\n }\r\n\r\n if (this._services.length > 0) {\r\n if (this._services[0].overridePriority > service.overridePriority) {\r\n const overridden = this._services[0];\r\n this._services[0] = service;\r\n return overridden;\r\n }\r\n\r\n if (this._services[0].overridePriority === service.overridePriority) {\r\n const firstServiceType = this._services[0].serviceType;\r\n return new ServiceError(`Multiple services registered with the same override priority '${service.overridePriority}' as singleton: '${firstServiceType && firstServiceType.name}' and '${service.serviceType && service.serviceType.name}'.`);\r\n }\r\n\r\n return false;\r\n }\r\n\r\n this._services.push(service);\r\n return true;\r\n }\r\n}\r\n","import 'reflect-metadata';\r\nimport { Requires } from '../diagnostics/contracts/requires';\r\nimport { AbstractType, Type } from '../type';\r\nimport { AppServiceInfo, AppServiceLifetime } from './appServiceInfo';\r\nimport { AppServiceMetadata, Priority } from './appServiceMetadata';\r\nimport { ServiceError } from './serviceError';\r\n\r\ninterface IAppServiceInfo {\r\n /**\r\n * Registers a service implementation for this contract.\r\n *\r\n * @template T The service implementation type.\r\n * @param {AppServiceMetadata<T>} service\r\n * @returns {(boolean | ServiceError | AppServiceMetadata<any>)}\r\n * True, if the service was registered successfully.\r\n * False, if the service was not registered due to a higher override priority service already registered.\r\n * ServiceError, if a service is already registered with the same override priority.\r\n * AppServiceMetadata<any>, if the service to register overrid an existing one. The overridden service is returned.\r\n * @memberof AppServiceInfo\r\n */\r\n registerService<T>(service: AppServiceMetadata<T>): boolean | ServiceError | AppServiceMetadata<any>;\r\n}\r\n\r\n/**\r\n * Registry for the application service information.\r\n *\r\n * @export\r\n * @class AppServiceInfoRegistry\r\n */\r\nexport class AppServiceInfoRegistry {\r\n // metadata keys should be defined before the instance is created,\r\n // otherwise they will be null when registering the contracts.\r\n private static readonly _serviceContractKey = 'kephas:serviceContract';\r\n private static readonly _serviceMetadataKey = 'kephas:serviceMetadata';\r\n\r\n private static _instance: AppServiceInfoRegistry;\r\n\r\n /**\r\n * Gets the static instance of the registry.\r\n *\r\n * @static\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n public static get Instance() {\r\n return AppServiceInfoRegistry._instance\r\n ? AppServiceInfoRegistry._instance\r\n : (AppServiceInfoRegistry._instance = new AppServiceInfoRegistry());\r\n };\r\n\r\n private readonly _serviceContracts: AppServiceInfo[];\r\n private readonly _services: AppServiceMetadata<any>[];\r\n\r\n /**\r\n * Creates an instance of AppServiceInfoRegistry.\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n constructor() {\r\n this._serviceContracts = [];\r\n this._services = [];\r\n\r\n this.registerServiceContract(AppServiceInfoRegistry, new AppServiceInfo(\r\n {\r\n contractType: AppServiceInfoRegistry,\r\n lifetime: AppServiceLifetime.Singleton\r\n }));\r\n this.registerService(AppServiceInfoRegistry, new AppServiceMetadata(\r\n {\r\n overridePriority: Priority.Low,\r\n serviceType: AppServiceInfoRegistry,\r\n serviceInstance: this,\r\n }));\r\n }\r\n\r\n /**\r\n * Gets an iterator over service contracts.\r\n *\r\n * @returns {IterableIterator<AppServiceInfo>} The iterator over service contracts.\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n public get serviceContracts(): IterableIterator<AppServiceInfo> {\r\n return this._serviceContracts.values();\r\n }\r\n\r\n /**\r\n * Gets an iterator of services.\r\n *\r\n * @readonly\r\n * @type {IterableIterator<AppServiceMetadata>} The iterator over services.\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n public get services(): IterableIterator<AppServiceMetadata<any>> {\r\n return this._services.values();\r\n }\r\n\r\n /**\r\n * Registers the provided type as a service contract.\r\n *\r\n * @static\r\n * @param {AbstractType} type The type to be registered.\r\n * @param {AppServiceInfo} appServiceInfo The service information.\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n public registerServiceContract(type: AbstractType, appServiceInfo: AppServiceInfo): this {\r\n Requires.HasValue(type, 'type');\r\n Reflect.defineMetadata(AppServiceInfoRegistry._serviceContractKey, appServiceInfo, type);\r\n this._serviceContracts.push(appServiceInfo);\r\n return this;\r\n }\r\n\r\n /**\r\n * Registers the provided type as a service type.\r\n *\r\n * @static\r\n * @param {Type<T>} type The type to be registered.\r\n * @param {AppServiceMetadata} [metadata] Optional. The service metadata.\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n public registerService<T>(type: Type<T>, metadata?: AppServiceMetadata<T>): this {\r\n Requires.HasValue(type, 'type');\r\n const appServiceInfo = (metadata && metadata.serviceContract) || this._getContractOfService(type);\r\n if (!appServiceInfo) {\r\n throw new ServiceError(`The service contract for '${type.name}' could not be identified. Check that the service or one of its bases is decorated as AppServiceContract or SingletonAppServiceContract.`);\r\n }\r\n\r\n metadata = metadata || new AppServiceMetadata();\r\n metadata['_serviceType'] = type;\r\n metadata['_serviceContract'] = appServiceInfo;\r\n\r\n let result = (appServiceInfo as unknown as IAppServiceInfo).registerService(metadata);\r\n if (result instanceof ServiceError) {\r\n throw result;\r\n }\r\n\r\n if (result instanceof AppServiceMetadata) {\r\n const overriddenServiceType = result.serviceType;\r\n const overriddenIndex = this._services.findIndex(m => m.serviceType === overriddenServiceType);\r\n if (overriddenIndex >= 0) {\r\n this._services[overriddenIndex] = metadata;\r\n }\r\n result = true;\r\n }\r\n else if (result) {\r\n this._services.push(metadata);\r\n }\r\n\r\n if (result) {\r\n Reflect.defineMetadata(AppServiceInfoRegistry._serviceContractKey, appServiceInfo, type);\r\n Reflect.defineMetadata(AppServiceInfoRegistry._serviceMetadataKey, metadata, type);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Gets the service contract from the provided type, if possible.\r\n *\r\n * @param {AbstractType} type The type assumed to be a service contract or a service type.\r\n * @returns {(AppServiceInfo | null)} The AppServiceInfo instance or null, if the type is not a service contract.\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n public getServiceContract(type: AbstractType): AppServiceInfo | null {\r\n Requires.HasValue(type, 'type');\r\n return Reflect.getOwnMetadata(AppServiceInfoRegistry._serviceContractKey, type) as AppServiceInfo || null;\r\n }\r\n\r\n /**\r\n * Gets a value indicating whether a type is a service contract.\r\n *\r\n * @param {AbstractType} type The type assumed to be a service contract.\r\n * @returns {boolean}\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n public isServiceContract(type: AbstractType): boolean {\r\n Requires.HasValue(type, 'type');\r\n return Reflect.hasOwnMetadata(AppServiceInfoRegistry._serviceContractKey, type);\r\n }\r\n\r\n /**\r\n * Gets the service metadata from the provided type, if possible.\r\n *\r\n * @param {AbstractType} type The type assumed to be a service type.\r\n * @returns {(AppServiceMetadata | null)}\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n public getServiceMetadata(type: AbstractType): AppServiceMetadata<any> | null {\r\n Requires.HasValue(type, 'type');\r\n return Reflect.getOwnMetadata(AppServiceInfoRegistry._serviceMetadataKey, type) as AppServiceMetadata<any> || null;\r\n }\r\n\r\n /**\r\n * Gets a value indicating whether a type is a service.\r\n *\r\n * @param {AbstractType} type\r\n * @returns {boolean}\r\n * @memberof AppServiceInfoRegistry\r\n */\r\n public isService(type: AbstractType): boolean {\r\n Requires.HasValue(type, 'type');\r\n return Reflect.hasOwnMetadata(AppServiceInfoRegistry._serviceMetadataKey, type);\r\n }\r\n\r\n private _getContractOfService(type: AbstractType): AppServiceInfo | null {\r\n while (type) {\r\n const contract = this.getServiceContract(type);\r\n if (contract) {\r\n return contract;\r\n }\r\n\r\n const typePrototype = Object.getPrototypeOf(type.prototype);\r\n type = typePrototype && typePrototype.constructor;\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n","import { Injector } from \"../injection/injector\";\r\nimport { Type } from \"../type\";\r\nimport { AppServiceInfoRegistry } from \"./appServiceInfoRegistry\";\r\nimport { AppServiceMetadata, Priority } from \"./appServiceMetadata\";\r\n\r\n/**\r\n * Marks a class as being an application service. Its closest base registered as service contract is\r\n * considered to be its contract.\r\n *\r\n * @export\r\n * @param {number|Priority} [overridePriority=Priority.Normal] Optional. The override priority.\r\n * @param {number|Priority} [processingPriority=Priority.Normal] Optional. The processing priority.\r\n * @param {string} [serviceName] Optional. The service name.\r\n * @returns A function.\r\n */\r\nexport function AppService(\r\n {\r\n overridePriority = Priority.Normal,\r\n processingPriority = Priority.Normal,\r\n serviceName,\r\n provider,\r\n registry\r\n }: {\r\n overridePriority?: number | Priority;\r\n processingPriority?: number | Priority;\r\n serviceName?: string;\r\n provider?: ((c: Injector) => any) | {};\r\n registry?: AppServiceInfoRegistry;\r\n } = {}) {\r\n return (type: Type<any>) => {\r\n (registry || AppServiceInfoRegistry.Instance).registerService(\r\n type,\r\n new AppServiceMetadata<any>({\r\n overridePriority,\r\n processingPriority,\r\n serviceName,\r\n serviceType: type,\r\n serviceInstance: typeof provider === 'object'\r\n ? provider\r\n : undefined,\r\n serviceFactory: typeof provider === 'function'\r\n ? provider as ((c: Injector) => any)\r\n : undefined,\r\n }));\r\n };\r\n}\r\n","import { AbstractType } from \"../type\";\r\nimport { AppServiceInfo, AppServiceLifetime } from \"./appServiceInfo\";\r\nimport { AppServiceInfoRegistry } from \"./appServiceInfoRegistry\";\r\n\r\n/**\r\n * Marks a class as being contract for transient application services.\r\n *\r\n * @export\r\n * @param {boolean} [allowMultiple=false] Indicates whether multiple services may be registered with the same contract or not.\r\n * @param {AbstractType} [contractType] Indicates the contract type, if different from the decorated type.\r\n * @param {*} [contractToken] Indicates the contract token, if different from the contract type.\r\n */\r\nexport function AppServiceContract(\r\n {\r\n allowMultiple = false,\r\n contractType,\r\n contractToken,\r\n registry,\r\n ...args\r\n }: {\r\n allowMultiple?: boolean;\r\n contractType?: AbstractType;\r\n contractToken?: any;\r\n registry?: AppServiceInfoRegistry;\r\n [key: string]: any;\r\n } = {}) {\r\n return (type: AbstractType) => {\r\n contractType = contractType ? contractType : type;\r\n contractToken = contractToken ? contractToken : contractType;\r\n const appServiceInfo = new AppServiceInfo({ contractType, contractToken, allowMultiple, lifetime: AppServiceLifetime.Transient, ...args });\r\n (registry || AppServiceInfoRegistry.Instance).registerServiceContract(type, appServiceInfo);\r\n };\r\n}\r\n\r\n/**\r\n * Marks a class as being contract for singleton application services.\r\n *\r\n * @export\r\n * @param {boolean} [allowMultiple=false] Indicates whether multiple services may be registered with the same contract or not.\r\n * @param {AbstractType} [contractType] Indicates the contract type, if different from the decorated type.\r\n * @param {*} [contractToken] Indicates the contract token, if different from the contract type.\r\n */\r\nexport function SingletonAppServiceContract(\r\n {\r\n allowMultiple = false,\r\n contractType,\r\n contractToken,\r\n registry,\r\n ...args\r\n }: {\r\n allowMultiple?: boolean;\r\n contractType?: AbstractType;\r\n contractToken?: any;\r\n registry?: AppServiceInfoRegistry;\r\n [key: string]: any;\r\n } = {}) {\r\n return (type: AbstractType) => {\r\n contractType = contractType ? contractType : type;\r\n contractToken = contractToken ? contractToken : contractType;\r\n const appServiceInfo = new AppServiceInfo({ contractType, contractToken, allowMultiple, lifetime: AppServiceLifetime.Singleton, ...args });\r\n (registry || AppServiceInfoRegistry.Instance).registerServiceContract(type, appServiceInfo);\r\n };\r\n}\r\n","import { Sealed } from \"./sealed\";\r\n\r\n/**\r\n * A deferrable value.\r\n *\r\n * @export\r\n * @class Deferrable\r\n * @template T\r\n */\r\n@Sealed\r\nexport class Deferrable<T> {\r\n /**\r\n * Gets the promise of this deferrable.\r\n *\r\n * @type {Promise<T>}\r\n * @memberof Deferrable\r\n */\r\n readonly promise: Promise<T>;\r\n\r\n /**\r\n * Creates an instance of Deferrable.\r\n * @memberof Deferrable\r\n */\r\n constructor() {\r\n this.promise = new Promise<T>((resolve, reject) => {\r\n this.resolve = resolve;\r\n this.reject = reject;\r\n });\r\n }\r\n\r\n /**\r\n * Resolves the promise to the indicated value.\r\n *\r\n * @param {(T | PromiseLike<T>)} [value] The resolved value.\r\n * @memberof Deferrable\r\n */\r\n resolve: (value: T | PromiseLike<T>) => void = v => {};\r\n\r\n /**\r\n * Rejects the promise with the indicated reason.\r\n *\r\n * @param {*} [reason] The reason for rejection.\r\n * @memberof Deferrable\r\n */\r\n reject: (reason?: any) => void = r => {};\r\n}\r\n","import { Deferrable } from \"../deferrable\";\r\nimport { Context } from \"./context\";\r\n\r\n/**\r\n * Helper class for working with services.\r\n *\r\n * @export\r\n * @class ServiceHelper\r\n */\r\nexport class ServiceHelper {\r\n /**\r\n * Initializes the service asynchronously, provided it implements either the\r\n * Initializable or AsyncInitializable interfaces.\r\n *\r\n * @static\r\n * @param {{ [key: string]: any }} service\r\n * @param {Context} [context] The context to pass to the initialization method.\r\n * @returns {Promise<void>} A promise returning the asynchronous result.\r\n * @memberof ServiceHelper\r\n */\r\n static initializeAsync(service: { [key: string]: any }, context?: Context): Promise<void> {\r\n if (service.initializeAsync) {\r\n return service.initializeAsync(context);\r\n }\r\n\r\n const deferrable = new Deferrable();\r\n\r\n if (service.initialize) {\r\n deferrable.resolve(true);\r\n service.initialize(context);\r\n }\r\n else {\r\n deferrable.resolve(false);\r\n }\r\n\r\n return deferrable.promise as Promise<void>;\r\n }\r\n}\r\n","import { Expando } from \"../expando\";\r\nimport { AppService } from \"../services/appService\";\r\nimport { SingletonAppServiceContract } from \"../services/appServiceContract\";\r\nimport { Priority } from \"../services/appServiceMetadata\";\r\n\r\n/**\r\n * Enumerates the logging levels.\r\n *\r\n * @enum {number}\r\n */\r\nexport enum LogLevel {\r\n /**\r\n * Fatal errors.\r\n */\r\n Fatal,\r\n\r\n /**\r\n * Common errors.\r\n */\r\n Error,\r\n\r\n /**\r\n * Warning information.\r\n */\r\n Warning,\r\n\r\n /**\r\n * Common information.\r\n */\r\n Info,\r\n\r\n /**\r\n * Debugging information.\r\n */\r\n Debug,\r\n\r\n /**\r\n * Tracing information.\r\n */\r\n Trace,\r\n}\r\n\r\n/**\r\n * Base service for logging.\r\n *\r\n * @class Logger\r\n */\r\n@AppService({ overridePriority: Priority.Low })\r\n@SingletonAppServiceContract()\r\nexport class Logger {\r\n private _logLevel: LogLevel = LogLevel.Info;\r\n\r\n /**\r\n * Logs the information at the provided level.\r\n *\r\n * @param {LogLevel | string} level The logging level.\r\n * @param {Error} exception The error that occured (may not be specified).\r\n * @param {string} messageFormat The message format.\r\n * @param {...any[]} args The arguments for the message format.\r\n * @memberof Logger\r\n */\r\n log(level: LogLevel | string, exception: Error | null | undefined, messageFormat: string, ...args: any[]): void {\r\n if (typeof level === 'string') {\r\n level = (LogLevel as Expando)[level] as LogLevel;\r\n }\r\n\r\n if (this.isEnabled(level)) {\r\n this.write(level, exception, messageFormat, args);\r\n }\r\n }\r\n\r\n /**\r\n * Indicates whether logging at the indicated level is enabled.\r\n * @param {LogLevel | string} level The logging level.\r\n * @return true if enabled, false if not.\r\n */\r\n isEnabled(level: LogLevel | string): boolean {\r\n if (typeof level === 'string') {\r\n level = (LogLevel as Expando)[level] as LogLevel;\r\n }\r\n\r\n return level <= this._logLevel;\r\n }\r\n\r\n /**\r\n * Sets the logging level to the indicated one.\r\n *\r\n * @param {(LogLevel | string)} level The new log level.\r\n * @memberof Logger\r\n */\r\n public setLevel(level: LogLevel | string) {\r\n if (typeof level === 'string') {\r\n level = (LogLevel as Expando)[level] as LogLevel;\r\n }\r\n\r\n this._logLevel = level;\r\n }\r\n\r\n /**\r\n * Logs the event at the fatal level.\r\n *\r\n * @param {Error | string} event The event to be logged.\r\n * @param {...any[]} args The arguments for the event.\r\n * @memberof Logger\r\n */\r\n fatal(event: Error | string, ...args: any[]): void {\r\n this._log(LogLevel.Fatal, event, args);\r\n }\r\n\r\n /**\r\n * Logs the event at the error level.\r\n *\r\n * @param {Error | string} event The event to be logged.\r\n * @param {...any[]} args The arguments for the event.\r\n * @memberof Logger\r\n */\r\n error(event: Error | string, ...args: any[]): void {\r\n this._log(LogLevel.Error, event, args);\r\n }\r\n\r\n /**\r\n * Logs the event at the warning level.\r\n *\r\n * @param {Error | string} event The event to be logged.\r\n * @param {...any[]} args The arguments for the event.\r\n * @memberof Logger\r\n */\r\n warn(event: Error | string, ...args: any[]): void {\r\n this._log(LogLevel.Warning, event, args);\r\n }\r\n\r\n /**\r\n * Logs the event at the information level.\r\n *\r\n * @param {Error | string} event The event to be logged.\r\n * @param {...any[]} args The arguments for the event.\r\n * @memberof Logger\r\n */\r\n info(event: Error | string, ...args: any[]): void {\r\n this._log(LogLevel.Info, event, args);\r\n }\r\n\r\n /**\r\n * Logs the event at the debug level.\r\n *\r\n * @param {Error | string} event The event to be logged.\r\n * @param {...any[]} args The arguments for the event.\r\n * @memberof Logger\r\n */\r\n debug(event: Error | string, ...args: any[]): void {\r\n this._log(LogLevel.Debug, event, args);\r\n }\r\n\r\n /**\r\n * Logs the event at the trace level.\r\n *\r\n * @param {Error | string} event The event to be logged.\r\n * @param {...any[]} args The arguments for the event.\r\n * @memberof Logger\r\n */\r\n trace(event: Error | string, ...args: any[]): void {\r\n this._log(LogLevel.Trace, event, args);\r\n }\r\n\r\n /**\r\n * Overridable method for writing to the log.\r\n *\r\n * @param {LogLevel} level The logging level.\r\n * @param {Error} exception The error that occured (may not be specified).\r\n * @param {string} messageFormat The message format.\r\n * @param {any[]} args The arguments for the message format.\r\n * @memberof Logger\r\n */\r\n protected write(level: LogLevel, exception: Error | null | undefined, messageFormat: string, args: any[]): void {\r\n const message = exception ? exception.message : messageFormat;\r\n switch (level) {\r\n case LogLevel.Fatal:\r\n console.error('FATAL ' + message, ...args);\r\n break;\r\n case LogLevel.Error:\r\n console.error(message, ...args);\r\n break;\r\n case LogLevel.Warning:\r\n console.warn(message, ...args);\r\n break;\r\n case LogLevel.Info:\r\n console.info(message, ...args);\r\n break;\r\n case LogLevel.Debug:\r\n console.debug(message, ...args);\r\n break;\r\n case LogLevel.Trace:\r\n console.trace(message, ...args);\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n private _log(level: LogLevel, event: Error | string, args: any[]): void {\r\n if (!this.isEnabled(level)) {\r\n return;\r\n }\r\n\r\n if (typeof event === 'string') {\r\n this.write(level, null, event, args);\r\n } else {\r\n const messageFormat = args && args.length && args[0];\r\n args = (args && args.length && args.splice(0, 1)) || [];\r\n this.write(level, event, messageFormat, args);\r\n }\r\n }\r\n}\r\n","/**\r\n * Signals an injection error.\r\n *\r\n * @export\r\n * @class InjectionError\r\n * @extends {Error}\r\n */\r\nexport class InjectionError extends Error {\r\n /**\r\n * Creates an instance of InjectionError.\r\n * @param {string} message The error message.\r\n * @memberof InjectionError\r\n */\r\n constructor(message: string) {\r\n super(message);\r\n }\r\n}\r\n","import { InjectionError } from \"./injectionError\";\r\nimport { SingletonAppServiceContract } from \"../services/appServiceContract\";\r\nimport { AbstractType, Type } from \"../type\";\r\n\r\n/**\r\n * Contract for composition context.\r\n *\r\n * @export\r\n * @abstract\r\n * @class Injector\r\n */\r\n@SingletonAppServiceContract()\r\nexport abstract class Injector {\r\n private static _instance: Injector;\r\n\r\n /**\r\n * Gets or sets the static instance of the Injector.\r\n *\r\n * @readonly\r\n * @static\r\n * @type {Injector}\r\n * @memberof Injector\r\n */\r\n public static get instance(): Injector {\r\n return Injector._instance;\r\n }\r\n\r\n public static set instance(value: Injector) {\r\n if (value === Injector._instance) {\r\n return;\r\n }\r\n\r\n if (value && Injector._instance) {\r\n throw new InjectionError(`Both the instance (${Injector._instance}) and the new value (${value}) are set. If you really intend to change the injector, set it first to null and then set the new value.`);\r\n }\r\n\r\n Injector._instance = value;\r\n }\r\n\r\n /**\r\n * Gets the service instance of the required service contract type.\r\n *\r\n * @template T\r\n * @param {Type<T>} type The service contract type.\r\n * @param notFoundResolver A resolver for the case when a type cannot be resolved.\r\n * @returns {T} The requested service.\r\n * @memberof Injector\r\n */\r\n abstract resolve<T>(type: Type<T> | AbstractType, notFoundResolver?: (type: Type<T> | AbstractType) => any): T;\r\n\r\n /**\r\n * Gets an array of service instances.\r\n *\r\n * @template T\r\n * @param {Type<T>} type The service contract type.\r\n * @param notFoundResolver A resolver for the case when a type cannot be resolved.\r\n * @returns {T[]} The array of the requested service.\r\n * @memberof Injector\r\n */\r\n abstract resolveMany<T>(type: Type<T> | AbstractType, notFoundResolver?: (type: Type<T> | AbstractType) => any): T[];\r\n}\r\n","import 'reflect-metadata';\r\nimport { AppService } from '../services/appService';\r\nimport { AppServiceInfo, AppServiceLifetime } from '../services/appServiceInfo';\r\nimport { AppServiceInfoRegistry } from '../services/appServiceInfoRegistry';\r\nimport { AppServiceMetadata, Priority } from '../services/appServiceMetadata';\r\nimport { AbstractType, Type } from '../type';\r\nimport { Injector } from './injector';\r\nimport { InjectionError } from './injectionError';\r\n\r\n/**\r\n * Provides a container for the dependency injection.\r\n *\r\n * @export\r\n * @class LiteInjector\r\n */\r\n@AppService({ overridePriority: Priority.Low, provider: _ => Injector.instance })\r\nexport class LiteInjector extends Injector {\r\n private _registry: AppServiceInfoRegistry;\r\n private _singletons = new WeakMap<AbstractType, any>();\r\n\r\n /**\r\n * Creates an instance of LiteInjector.\r\n * @param {AppServiceInfoRegistry} [registry]\r\n * @memberof LiteInjector\r\n */\r\n constructor(registry?: AppServiceInfoRegistry) {\r\n super();\r\n this._registry = registry || (registry = AppServiceInfoRegistry.Instance);\r\n if (registry !== AppServiceInfoRegistry.Instance) {\r\n const appServiceInfo = new AppServiceInfo({\r\n contractType: Injector,\r\n allowMultiple: false,\r\n lifetime: AppServiceLifetime.Singleton,\r\n });\r\n registry.registerServiceContract(Injector, appServiceInfo);\r\n registry.registerService(LiteInjector, new AppServiceMetadata({\r\n overridePriority: Priority.Low,\r\n _serviceContract: appServiceInfo, // HACK: set the background field of serviceContract\r\n serviceType: LiteInjector,\r\n serviceInstance: this,\r\n }))\r\n }\r\n }\r\n\r\n /**\r\n * Gets the service instance of the required service contract type.\r\n *\r\n * @template T\r\n * @param {Type<T>} type The service contract type.\r\n * @param notFoundResolver A resolver for the case when a type cannot be resolved.\r\n * @returns {T} The requested service.\r\n * @memberof LiteInjector\r\n */\r\n public resolve<T>(type: Type<T> | AbstractType, notFoundResolver?: (type: Type<T> | AbstractType) => any): T {\r\n const serviceInfo = notFoundResolver ? this._tryGetServiceContract(type) : this._getServiceContract(type);\r\n if (!serviceInfo) {\r\n return notFoundResolver!(type);\r\n }\r\n\r\n if (serviceInfo.lifetime === AppServiceLifetime.Singleton) {\r\n let service = this._singletons.get(type);\r\n if (!service) {\r\n const serviceMetadata = this._getSingleServiceMetadata(serviceInfo);\r\n service = this._createInstance(serviceMetadata, notFoundResolver);\r\n this._singletons.set(type, service);\r\n }\r\n return service;\r\n }\r\n else {\r\n return this._createInstance(this._getSingleServiceMetadata(serviceInfo), notFoundResolver);\r\n }\r\n }\r\n\r\n /**\r\n * Gets an array of service instances.\r\n *\r\n * @template T\r\n * @param {Type<T>} type The service contract type.\r\n * @param notFoundResolver A resolver for the case when a type cannot be resolved.\r\n * @returns {T[]} The array of the requested service.\r\n * @memberof LiteInjector\r\n */\r\n public resolveMany<T>(type: Type<T> | AbstractType, notFoundResolver?: (type: Type<T> | AbstractType) => any): T[] {\r\n const serviceInfo = notFoundResolver ? this._tryGetServiceContract(type) : this._getServiceContract(type);\r\n if (!serviceInfo) {\r\n // the resolver should know that it should return an array of items.\r\n return notFoundResolver!(type);\r\n }\r\n\r\n if (serviceInfo.lifetime === AppServiceLifetime.Singleton) {\r\n let services = this._singletons.get(type);\r\n if (services === undefined || services === null) {\r\n services = [...serviceInfo.services].map(s => this._createInstance(s, notFoundResolver));\r\n this._singletons.set(type, services);\r\n }\r\n return services;\r\n }\r\n else {\r\n return [...serviceInfo.services].map(s => this._createInstance(s, notFoundResolver));\r\n }\r\n }\r\n\r\n private _tryGetServiceContract(type: AbstractType): AppServiceInfo | null {\r\n return this._registry.getServiceContract(type);\r\n }\r\n\r\n private _getServiceContract(type: AbstractType): AppServiceInfo {\r\n const serviceInfo = this._registry.getServiceContract(type);\r\n if (!serviceInfo) {\r\n throw new InjectionError(`The type '${type.name}' is not registered as a service contract.`);\r\n }\r\n\r\n return serviceInfo;\r\n }\r\n\r\n private _getSingleServiceMetadata(serviceInfo: AppServiceInfo): AppServiceMetadata<any> {\r\n const services = [...serviceInfo.services];\r\n if (services.length === 0) {\r\n throw new InjectionError(`The service contract '${serviceInfo.contractType.name}' does not have any services registered.`);\r\n }\r\n\r\n if (services.length > 1) {\r\n throw new InjectionError(`The service contract '${serviceInfo.contractType.name}' has multiple services registered: '${services.join(\"', '\")}'.`);\r\n }\r\n\r\n return services[0];\r\n }\r\n\r\n private _createInstance<T>(serviceMetadata: AppServiceMetadata<any>, notFoundResolver?: (type: Type<T> | AbstractType) => any): any {\r\n if (serviceMetadata.serviceInstance) {\r\n return serviceMetadata.serviceInstance;\r\n }\r\n\r\n if (serviceMetadata.serviceFactory) {\r\n return serviceMetadata.serviceFactory(this);\r\n }\r\n\r\n const serviceType = serviceMetadata.serviceType!;\r\n const paramTypes: Type<any>[] = Reflect.getOwnMetadata('design:paramtypes', serviceType);\r\n if (paramTypes) {\r\n const ctorArgs = paramTypes.map(t => this.resolve(t, notFoundResolver));\r\n return new serviceType(...ctorArgs);\r\n }\r\n\r\n return new serviceType();\r\n }\r\n}\r\n\r\n// make sure the injector is set.\r\nif (!Injector.instance) {\r\n Injector.instance = new LiteInjector();\r\n}\r\n","import 'reflect-metadata';\r\nimport { Requires } from '../diagnostics/contracts/requires';\r\nimport { Expando } from '../expando';\r\nimport { AbstractType } from '../type';\r\n\r\n/**\r\n * Base class for serializable objects.\r\n *\r\n * @export\r\n * @abstract\r\n * @class Serializable\r\n */\r\nexport abstract class Serializable {\r\n private static _typeFullNameKey: string = '$type';\r\n private static _typeNamespaceKey: string = 'kephas:namespace';\r\n /**\r\n