diff --git a/src/main/ts/di/Annotations.ts b/src/main/ts/di/Annotations.ts --- a/src/main/ts/di/Annotations.ts +++ b/src/main/ts/di/Annotations.ts @@ -72,6 +72,8 @@ type ServiceModule; }; +type PromiseOrValue = PromiseLike | T; + export interface Config { register(name: K, builder: Builder): Config>; register(name: K, m: Promise>): Config>; diff --git a/src/main/ts/di/Configuration.ts b/src/main/ts/di/Configuration.ts --- a/src/main/ts/di/Configuration.ts +++ b/src/main/ts/di/Configuration.ts @@ -18,6 +18,7 @@ import { Cancellation } from "../Cancell import { makeResolver } from "./ResolverHelper"; import { ICancellation } from "../interfaces"; import { isDescriptor } from "./traits"; +import { LazyReferenceDescriptor } from "./LazyReferenceDescriptor"; export interface RegistrationScope { @@ -357,13 +358,13 @@ export class Configuration(data: DependencyRegistration, name: string) { argumentNotEmptyString(data && data.$dependency, "data.$dependency"); this._enter(name); - const d = new ReferenceDescriptor({ + const options = { name: data.$dependency, - lazy: data.lazy, optional: data.optional, default: data.default, services: data.services && await this._visitRegistrations(data.services, "services") - }); + }; + const d = data.lazy ? new LazyReferenceDescriptor(options) : new ReferenceDescriptor(options); this._leave(); return d; } diff --git a/src/main/ts/di/LazyReferenceDescriptor.ts b/src/main/ts/di/LazyReferenceDescriptor.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/di/LazyReferenceDescriptor.ts @@ -0,0 +1,84 @@ +import { argumentNotEmptyString, each } from "../safe"; +import { ActivationContext } from "./ActivationContext"; +import { Descriptor, PartialServiceMap, ContainerResolve, ContainerKeys } from "./interfaces"; +import { ActivationError } from "./ActivationError"; + +export interface ReferenceDescriptorParams> { + name: K; + optional?: boolean; + default?: ContainerResolve; + services?: PartialServiceMap; +} + +export class LazyReferenceDescriptor = ContainerKeys> + implements Descriptor) => ContainerResolve)> { + + _name: K; + + _optional = false; + + _default: ContainerResolve | undefined; + + _services: PartialServiceMap; + + constructor(opts: ReferenceDescriptorParams) { + argumentNotEmptyString(opts && opts.name, "opts.name"); + this._name = opts.name; + this._optional = !!opts.optional; + this._default = opts.default; + + this._services = (opts.services || {}) as PartialServiceMap; + } + + activate(context: ActivationContext) { + // добавляем сервисы + if (this._services) { + each(this._services, (v, k) => context.register(k, v)); + } + + const saved = context.clone(); + + return (cfg?: PartialServiceMap) => { + // защищаем контекст на случай исключения в процессе + // активации + const ct = saved.clone(); + try { + if (cfg) { + each(cfg, (v, k) => ct.register(k, v)); + } + + return this._optional ? ct.resolve(this._name, this._default) : ct + .resolve(this._name); + } catch (error) { + throw new ActivationError(this._name.toString(), ct.getStack(), error); + } + }; + + } + + toString() { + const opts = []; + if (this._optional) + opts.push("optional"); + + opts.push("lazy"); + + const parts = [ + "@ref " + ]; + if (opts.length) { + parts.push("{"); + parts.push(opts.join()); + parts.push("} "); + } + + parts.push(this._name.toString()); + + if (this._default !== undefined && this._default !== null) { + parts.push(" = "); + parts.push(String(this._default)); + } + + return parts.join(""); + } +} diff --git a/src/main/ts/di/ReferenceDescriptor.ts b/src/main/ts/di/ReferenceDescriptor.ts --- a/src/main/ts/di/ReferenceDescriptor.ts +++ b/src/main/ts/di/ReferenceDescriptor.ts @@ -1,23 +1,19 @@ import { argumentNotEmptyString, each } from "../safe"; import { ActivationContext } from "./ActivationContext"; import { Descriptor, PartialServiceMap, ContainerResolve, ContainerKeys } from "./interfaces"; -import { ActivationError } from "./ActivationError"; export interface ReferenceDescriptorParams> { name: K; - lazy?: boolean; optional?: boolean; default?: ContainerResolve; services?: PartialServiceMap; } export class ReferenceDescriptor = ContainerKeys> - implements Descriptor | ((args?: PartialServiceMap) => ContainerResolve)> { + implements Descriptor> { _name: K; - _lazy = false; - _optional = false; _default: ContainerResolve | undefined; @@ -27,7 +23,6 @@ export class ReferenceDescriptor) { argumentNotEmptyString(opts && opts.name, "opts.name"); this._name = opts.name; - this._lazy = !!opts.lazy; this._optional = !!opts.optional; this._default = opts.default; @@ -40,39 +35,17 @@ export class ReferenceDescriptor context.register(k, v)); } - if (this._lazy) { - const saved = context.clone(); - - return (cfg?: PartialServiceMap) => { - // защищаем контекст на случай исключения в процессе - // активации - const ct = saved.clone(); - try { - if (cfg) { - each(cfg, (v, k) => ct.register(k, v)); - } + const res = this._optional ? + context.resolve(this._name, this._default) : + context.resolve(this._name); - return this._optional ? ct.resolve(this._name, this._default) : ct - .resolve(this._name); - } catch (error) { - throw new ActivationError(this._name.toString(), ct.getStack(), error); - } - }; - } else { - const v = this._optional ? - context.resolve(this._name, this._default) : - context.resolve(this._name); - - return v; - } + return res; } toString() { const opts = []; if (this._optional) opts.push("optional"); - if (this._lazy) - opts.push("lazy"); const parts = [ "@ref " diff --git a/src/test/ts/mock/config.ts b/src/test/ts/mock/config.ts --- a/src/test/ts/mock/config.ts +++ b/src/test/ts/mock/config.ts @@ -3,4 +3,4 @@ import { config } from "./services"; config() .register("bar", import("./Bar")) .register("box", import("./Box"), "service"); - //.register("foo", import("./Foo"), "Foo"); + // .register("foo", import("./Foo"), "Foo");