# HG changeset patch # User cin # Date 2020-08-03 06:44:45 # Node ID 09ea4b9e373520f081d9aec014a08a94458d4b88 # Parent 0866c62592851e4c8fc9670ca81a285076298c60 working on fluent configuration diff --git a/docs/ru/observable.md b/docs/ru/observable.md --- a/docs/ru/observable.md +++ b/docs/ru/observable.md @@ -5,7 +5,7 @@ самостоятельных событий, например, связанных с действиями пользователя. Является реализацией классического шаблона наблюдателя с возможность сообщить -о коце потока событий. Данная реализация не содержит никаких дополнительных +о конце потока событий. Данная реализация не содержит никаких дополнительных функций, таких как фильтрация, канал с состоянием, преобразования сообщений и т.п. Это сделано специально, чтобы реализация оставалась максимально простой. @@ -20,7 +20,7 @@ var events = new Observable(async (notif notify(i); } // по окончании последовательности информируем, что событий больше не будет - compelte(); + complete(); }); // создаем окно с отображением хода событий @@ -49,9 +49,9 @@ let firstEvent = await events.next(); `Observable` можно создавать из событий другого объекта, например, виджета: ```ts -// клсс +// класс class Canvas { - readonly mouseMove: IObservable<[number,number]> + mouseMove: IObservable<[number,number]>; postCreate() { // превращаем события виджета в Observable @@ -98,7 +98,7 @@ class PositionTracker implements IDestro } ``` -Существует также несколько варинатов получения сообщений +Существует также несколько вариантов получения сообщений ```ts // регистрация метода для получений событий @@ -128,7 +128,7 @@ class Map { let evt = this.viewport.click.next(ct); // преобразуем позицию на экране в координаты карты - return this.clientToCoodinates([evt.clientx,evt.clientY]); + return this.clientToCoordinates([evt.clientX,evt.clientY]); } } @@ -142,8 +142,8 @@ let coords = await map.peekCoordinates() ## Observable и последовательности -Можно сичтать, что `Observable` это некоторая аналогия итератора только в -парадигме событийного (или реактивного) программировния. Следует также понимать, +Можно считать, что `Observable` это некоторая аналогия итератора только в +парадигме событийного (или реактивного) программирования. Следует также понимать, что при переходе от синхронного процедурного программирования к событийному так же меняется и направление управления (Inverse Of Control), что означает следующее: @@ -153,7 +153,7 @@ let coords = await map.peekCoordinates() * при работе с `Observable` клиенты вынуждены обрабатывать эти события по мере их поступления и не могут на это повлиять. -Последний пункт можно изменить применив, например, буффер или канал с +Последний пункт можно изменить применив, например, буфер или канал с состоянием, т.е. очередь, но данные механизмы выходят за рамки простого шаблона наблюдателя. @@ -179,4 +179,4 @@ events.on((data) => { // будет вызван для всех сообщений processEvent(data); }); -``` \ No newline at end of file +``` diff --git a/src/main/ts/Observable.ts b/src/main/ts/Observable.ts --- a/src/main/ts/Observable.ts +++ b/src/main/ts/Observable.ts @@ -1,6 +1,6 @@ import { IObservable, IDestroyable, ICancellation, IObserver } from "./interfaces"; import { Cancellation } from "./Cancellation"; -import { argumentNotNull, destroyed } from "./safe"; +import { argumentNotNull } from "./safe"; type Handler = (x: T) => void; @@ -8,12 +8,6 @@ type Initializer = (notify: Handler { }; -const nulObserver: IObserver = Object.freeze({ - next: noop, - error: noop, - complete: noop -}); - function isObserver(val: any): val is IObserver { return val && (typeof val.next === "function"); } diff --git a/src/main/ts/di/ActivationContext.ts b/src/main/ts/di/ActivationContext.ts --- a/src/main/ts/di/ActivationContext.ts +++ b/src/main/ts/di/ActivationContext.ts @@ -1,6 +1,6 @@ import { TraceSource } from "../log/TraceSource"; -import { argumentNotNull, argumentNotEmptyString } from "../safe"; -import { Descriptor, ContainerServiceMap, ContainerKeys, ContainerResolve } from "./interfaces"; +import { argumentNotEmptyString } from "../safe"; +import { Descriptor, ContainerServiceMap, ContainerKeys, TypeOfService } from "./interfaces"; import { Container } from "./Container"; import { MapOf } from "../interfaces"; @@ -45,13 +45,16 @@ export class ActivationContext>(name: K, def?: ContainerResolve) { + resolve>(name: K): TypeOfService; + resolve, T>(name: K, def: T): TypeOfService | T; + resolve>(name: K, def: undefined): TypeOfService | undefined; + resolve, T>(name: K, def?: T): TypeOfService | T | undefined { const d = this._services[name]; if (d !== undefined) { return this.activate(d, name.toString()); } else { - if (def !== undefined && def !== null) + if (arguments.length > 1) return def; else throw new Error(`Service ${name} not found`); 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 @@ -1,8 +1,7 @@ import { TypeRegistration } from "./Configuration"; import { ExtractDependency } from "./fluent/interfaces"; -import { RegistrationBuilder } from "./fluent/RegistrationBuilder"; -export class AnnotaionBuilder { +export class AnnotationBuilder { wire

(...args: P) { return ) => T>(constructor: C) => { @@ -23,8 +22,4 @@ export class AnnotaionBuilder { - throw new Error(); - } - } 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 @@ -2,7 +2,8 @@ import { PartialServiceMap, ActivationType, ContainerKeys, - ContainerResolve + TypeOfService, + ILifetimeManager } from "./interfaces"; import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get, primitive } from "../safe"; @@ -32,7 +33,7 @@ export interface RegistrationScope extends RegistrationScope { @@ -40,6 +41,11 @@ export interface ServiceRegistration void) | string; @@ -68,7 +74,7 @@ export interface DependencyRegistration< $dependency: K; lazy?: boolean; optional?: boolean; - default?: ContainerResolve; + default?: TypeOfService; } export interface LazyDependencyRegistration = ContainerKeys> extends DependencyRegistration { @@ -225,7 +231,15 @@ export class Configuration( @@ -411,7 +427,7 @@ export class Configuration implements Resolver, IDestroyable { +export class Container implements ServiceLocator, IDestroyable { readonly _services: ContainerServiceMap; - readonly _cache: MapOf; - readonly _lifetimeManager: ILifetimeManager; readonly _cleanup: (() => void)[]; @@ -30,7 +28,6 @@ export class Container) { this._parent = parent; this._services = parent ? Object.create(parent._services) : {}; - this._cache = {}; this._cleanup = []; this._root = parent ? parent.getRootContainer() : this; this._services.container = new ValueDescriptor(this) as any; @@ -50,7 +47,7 @@ export class Container>(name: K, def?: ContainerResolve): ContainerResolve { + resolve>(name: K, def?: TypeOfService): TypeOfService { trace.debug("resolve {0}", name); const d = this._services[name]; if (d === undefined) { @@ -72,7 +69,7 @@ export class Container>(name: K, def?: ContainerResolve) { + getService>(name: K, def?: TypeOfService) { return this.resolve(name, def); } diff --git a/src/main/ts/di/LazyReferenceDescriptor.ts b/src/main/ts/di/LazyReferenceDescriptor.ts --- a/src/main/ts/di/LazyReferenceDescriptor.ts +++ b/src/main/ts/di/LazyReferenceDescriptor.ts @@ -1,23 +1,23 @@ import { argumentNotEmptyString, each } from "../safe"; import { ActivationContext } from "./ActivationContext"; -import { Descriptor, PartialServiceMap, ContainerResolve, ContainerKeys } from "./interfaces"; +import { Descriptor, PartialServiceMap, TypeOfService, ContainerKeys } from "./interfaces"; import { ActivationError } from "./ActivationError"; export interface ReferenceDescriptorParams> { name: K; optional?: boolean; - default?: ContainerResolve; + default?: TypeOfService; services?: PartialServiceMap; } export class LazyReferenceDescriptor = ContainerKeys> - implements Descriptor) => ContainerResolve)> { + implements Descriptor) => TypeOfService)> { _name: K; _optional = false; - _default: ContainerResolve | undefined; + _default: TypeOfService | undefined; _services: PartialServiceMap; @@ -53,7 +53,6 @@ export class LazyReferenceDescriptor void)[] = []; private _cache: MapOf = {}; @@ -37,8 +39,9 @@ export class LifetimeManager implements private _pending: MapOf = {}; - initialize(id: string): ILifetime { + initialize(): ILifetime { const self = this; + const id = ++nextId; return { has() { return (id in self._cache); @@ -89,33 +92,18 @@ export class LifetimeManager implements static readonly empty: ILifetimeManager = { initialize(): ILifetime { return emptyLifetime; - }, - destroy() { - throw new Error("Trying to destroy empty lifetime manager, this is a bug."); } - }; static readonly hierarchyLifetime: ILifetimeManager = { - initialize(id: string, context: ActivationContext): ILifetime { - return context.getContainer().getLifetimeManager().initialize(id, context); - }, - destroy() { - throw new Error("Trying to destroy hierarchy lifetime manager, this is a bug."); - } - }; - - static readonly singletonLifetime: ILifetimeManager = { - initialize(id: string): ILifetime { - return singletonLifetimeManager.initialize(id); - }, - destroy() { - throw new Error("Trying to destroy singleton lifetime manager, this is a bug."); + initialize(context: ActivationContext): ILifetime { + return context.getContainer().getLifetimeManager().initialize(context); } }; static readonly contextLifetime: ILifetimeManager = { - initialize(id: string, context: ActivationContext): ILifetime { + initialize(context: ActivationContext): ILifetime { + const id = String(++nextId); return { enter() { if (context.visit(id)) @@ -130,13 +118,15 @@ export class LifetimeManager implements store(item: any) { context.store(id, item); } - }; - }, - destroy() { - throw new Error("Trying to destroy empty lifetime manager, this is a bug."); } }; + + static singletonLifetime(typeId: string): ILifetimeManager { + return { + initialize() { + return emptyLifetime; + } + }; + } } - -const singletonLifetimeManager = new LifetimeManager(); 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,22 +1,22 @@ import { argumentNotEmptyString, each } from "../safe"; import { ActivationContext } from "./ActivationContext"; -import { Descriptor, PartialServiceMap, ContainerResolve, ContainerKeys } from "./interfaces"; +import { Descriptor, PartialServiceMap, TypeOfService, ContainerKeys } from "./interfaces"; export interface ReferenceDescriptorParams> { name: K; optional?: boolean; - default?: ContainerResolve; + default?: TypeOfService; services?: PartialServiceMap; } export class ReferenceDescriptor = ContainerKeys> - implements Descriptor> { + implements Descriptor> { _name: K; _optional = false; - _default: ContainerResolve | undefined; + _default: TypeOfService | undefined; _services: PartialServiceMap; diff --git a/src/main/ts/di/ServiceDescriptor.ts b/src/main/ts/di/ServiceDescriptor.ts --- a/src/main/ts/di/ServiceDescriptor.ts +++ b/src/main/ts/di/ServiceDescriptor.ts @@ -1,13 +1,10 @@ import { ActivationContext } from "./ActivationContext"; -import { Descriptor, ServiceMap, PartialServiceMap, ILifetimeManager } from "./interfaces"; -import { argumentNotNull, isPrimitive, keys, isNull } from "../safe"; +import { Descriptor, ServiceMap, PartialServiceMap, ILifetimeManager, ILifetime } from "./interfaces"; +import { isPrimitive, keys, isNull } from "../safe"; import { TraceSource } from "../log/TraceSource"; import { isDescriptor } from "./traits"; import { LifetimeManager } from "./LifetimeManager"; import { MatchingMemberKeys } from "../interfaces"; -import { Container } from "./Container"; - -let cacheId = 0; const trace = TraceSource.get("@implab/core/di/ActivationContext"); @@ -82,14 +79,14 @@ export class ServiceDescriptor void) | undefined; - _cacheId = String(++cacheId); + _lifetimeManager = LifetimeManager.empty; - _lifetime = LifetimeManager.empty; + _objectLifetime: ILifetime | undefined; constructor(opts: ServiceDescriptorParams) { if (opts.lifetime) - this._lifetime = opts.lifetime; + this._lifetimeManager = opts.lifetime; if (!isNull(opts.params)) this._params = opts.params; @@ -108,14 +105,17 @@ export class ServiceDescriptor) { - const lifetime = this._lifetime.initialize(this._cacheId, context); + if (!this._objectLifetime) + this._objectLifetime = this._lifetimeManager.initialize(context); + + const lifetime = this._objectLifetime; if (lifetime.has()) { return lifetime.get(); } else { lifetime.enter(); const instance = this._create(context); - lifetime.store(this._cacheId, this._cleanup); + lifetime.store(instance, this._cleanup); return instance; } } diff --git a/src/main/ts/di/fluent/ConfigBuilder.ts b/src/main/ts/di/fluent/ConfigBuilder.ts deleted file mode 100644 --- a/src/main/ts/di/fluent/ConfigBuilder.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Container } from "../Container"; -import { ExtractDependency, ServiceRecordBuilder } from "./interfaces"; - -export class ConfigBuilder { - register(name: K, builder: (t: ServiceRecordBuilder) => void | Promise): ConfigBuilder>; - register(name: S[K] extends ExtractDependency ? K : never, value: V): ConfigBuilder>; - register(name: K, value: S[K], raw: true): ConfigBuilder>; - register(name: K, value: any, raw = false): ConfigBuilder> { - - return this; - } - - apply(container: Container): PromiseLike { - - return Promise.resolve(); - } -} diff --git a/src/main/ts/di/fluent/Configuration.ts b/src/main/ts/di/fluent/Configuration.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/di/fluent/Configuration.ts @@ -0,0 +1,59 @@ +import { Container } from "../Container"; +import { argumentNotNull, each } from "../../safe"; +import { DescriptorBuilder } from "./DescriptorBuilder"; + +enum State { + ready, + + pending +} + +export class Configuration { + + private _state = State.ready; + + _completion: PromiseLike = Promise.resolve(); + + _builders: { [k in keyof S]?: (service: DescriptorBuilder) => void } = {}; + + register(name: K, builder: (service: DescriptorBuilder) => void): Configuration> { + argumentNotNull(builder, "builder"); + + return this; + } + + private _moveStart() { + if (this._state !== State.ready) + throw new Error("Invalid operation"); + + this._state = State.pending; + } + + private _moveDone() { + this._state = State.ready; + } + + apply(target: Container) { + this._moveStart(); + + let pending = 1; + + this._completion = new Promise((resolve, reject) => { + each(this._builders, (v, k) => { + pending++; + const d = new DescriptorBuilder(target, result => { + target.register(k, result); + if (!--pending) + resolve(); + }); + + try { + v(d); + } catch (e) { + reject(e); + } + }); + }).then(() => this._moveDone()); + } + +} diff --git a/src/main/ts/di/fluent/ConstructorBuiler.ts b/src/main/ts/di/fluent/ConstructorBuiler.ts deleted file mode 100644 --- a/src/main/ts/di/fluent/ConstructorBuiler.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { RegistrationBuilder } from "./RegistrationBuilder"; - -export class ConstructorBuilder any, S extends object> - extends RegistrationBuilder, S> { - - $type: C; - - _params: any; - - constructor(target: C, params: any) { - super(); - this.$type = target; - - this._params = params; - } - -} diff --git a/src/main/ts/di/fluent/DescriptorBuilder.ts b/src/main/ts/di/fluent/DescriptorBuilder.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/di/fluent/DescriptorBuilder.ts @@ -0,0 +1,58 @@ +import { Resolver, ServiceModule, LazyDependencyOptions, DependencyOptions } from "./interfaces"; +import { AnnotationBuilder } from "../Annotations"; +import { Container } from "../Container"; +import { Descriptor, ILifetime, ContainerKeys } from "../interfaces"; +import { ActivationContext } from "../ActivationContext"; + +export class DescriptorBuilder { + readonly _container: Container; + readonly _cb: (d: Descriptor) => void; + + constructor(container: Container, cb: (d: Descriptor) => void) { + this._container = container; + this._cb = cb; + } + service(service: AnnotationBuilder | ServiceModule) { + + } + + factory(f: (resolve: Resolver, activate: (lifetime: ILifetime, factory: () => any, cleanup?: (item: any) => void) => any) => T): void { + this._cb({ + activate(context: ActivationContext) { + const resolve = (name: ContainerKeys, opts?: DependencyOptions | LazyDependencyOptions) => { + if (opts && "lazy" in opts && opts.lazy) { + const c2 = context.clone(); + return () => { + return opts.optional ? c2.resolve(name, opts.default) : c2.resolve(name); + }; + } else { + return opts && opts.optional ? context.resolve(name, opts.default) : context.resolve(name); + } + }; + + const activate = (lifetime: ILifetime, factory: () => any, cleanup?: (item: any) => void) => { + if (lifetime.has()) { + return lifetime.get(); + } else { + lifetime.enter(); + const instance = factory(); + lifetime.store(instance, cleanup); + return instance; + } + + }; + + return f(resolve, activate); + } + }); + } + + value(v: T): void { + this._cb({ + activate() { + return v; + } + }); + } + +} diff --git a/src/main/ts/di/fluent/FactoryBuilder.ts b/src/main/ts/di/fluent/FactoryBuilder.ts deleted file mode 100644 --- a/src/main/ts/di/fluent/FactoryBuilder.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { RegistrationBuilder } from "./RegistrationBuilder"; - -export class FactoryBuilder any, S extends object> extends RegistrationBuilder, S> { - $factory: F; - - _params: any; - - constructor(target: F, params: any) { - super(); - - this.$factory = target; - this._params = params; - } -} diff --git a/src/main/ts/di/fluent/RegistrationBuilder.ts b/src/main/ts/di/fluent/RegistrationBuilder.ts deleted file mode 100644 --- a/src/main/ts/di/fluent/RegistrationBuilder.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ServiceRecordBuilder, ExtractDependency, RegistrationVisitor, ServiceRegistration } from "./interfaces"; -import { ActivationType } from "../interfaces"; - -export class RegistrationBuilder implements ServiceRegistration { - private _activationType: ActivationType = "call"; - - private _overrides: { [m in keyof S]?: (...args: any) => void } | undefined; - - - override(name: K, builder: S[K], raw: true): this; - override(name: K, builder: (t: ServiceRecordBuilder) => void): this; - override(name: S[K] extends ExtractDependency ? K : never, value: V): this; - override(name: K, builder: S[K] | ((t: ServiceRecordBuilder) => void), raw: boolean = false) { - if (!this._overrides) - this._overrides = {}; - if (raw) { - - } else if (builder instanceof Function) { - - } else { - - } - return this; - } - - activate(activation: ActivationType) { - this._activationType = activation; - return this; - } - inject(member: T[M] extends (...params: ExtractDependency) => any ? M : never, ...params: P) { - return this; - } - - visit(visitor: RegistrationVisitor) { - - } -} diff --git a/src/main/ts/di/fluent/ServiceRecordBuilder.ts b/src/main/ts/di/fluent/ServiceRecordBuilder.ts deleted file mode 100644 diff --git a/src/main/ts/di/fluent/interfaces.ts b/src/main/ts/di/fluent/interfaces.ts --- a/src/main/ts/di/fluent/interfaces.ts +++ b/src/main/ts/di/fluent/interfaces.ts @@ -1,19 +1,17 @@ import { primitive } from "../../safe"; -import { ActivationType } from "../interfaces"; -import { AnnotaionBuilder } from "../Annotations"; -import { LazyDependencyRegistration, DependencyRegistration } from "../Configuration"; -import { Container } from "../Container"; +import { AnnotationBuilder } from "../Annotations"; +import { ILifetime, TypeOfService, ContainerKeys } from "../interfaces"; -export interface DependencyOptions { +export interface DependencyOptions { optional?: boolean; - default?: T; + default?: any; } -export interface LazyDependencyOptions extends DependencyOptions { +export interface LazyDependencyOptions extends DependencyOptions { lazy: true; } -export type ExtractService = K extends keyof S ? S[K] : K; +export type ExtractService = K extends keyof S ? S[K] : never; export type ExtractDependency = D extends { $dependency: infer K } ? D extends { lazy: true } ? () => ExtractService : ExtractService : @@ -25,47 +23,26 @@ export type WalkDependencies = D e { [K in keyof D]: ExtractDependency }; export type ServiceModule = { - [m in M]: AnnotaionBuilder; + [m in M]: AnnotationBuilder; }; -export interface ServiceRecordBuilder { - type

) => T>( - target: C, ...params: P): ConstructorBuilder; - factory

) => T>( - target: F, ...params: P): FactoryBuilder; - wired(module: ServiceModule, m: M): RegistrationBuilder; - wired(module: ServiceModule): RegistrationBuilder; +export type InferReferenceType, O> = O extends { default: infer X } ? (TypeOfService | X) : + O extends { optional: true } ? (TypeOfService | undefined) : + TypeOfService; + +export interface Resolver { + , O extends LazyDependencyOptions>(this: void, name: K, opts: O): () => InferReferenceType; + , O extends DependencyOptions>(this: void, name: K, opts?: O): InferReferenceType; } -export interface RegistrationVisitor { - visitDependency(): void; - - visitObject(): void; - - visitTypeRegistration(): void; +export interface DescriptorBuilder { + service(service: AnnotationBuilder | ServiceModule): void; - visitFactoryRegistration(): void; + factory(f: (resolve: Resolver, activate: (lifetime: ILifetime, factory: () => T2, cleanup?: (item: T2) => void) => T2) => T): void; -} - -export interface ServiceRegistration { - visit(visitor: RegistrationVisitor): void; + value(v: T): void; } -export interface ConfigBuilder { - register(name: K, builder: (t: ServiceRecordBuilder) => void | Promise): ConfigBuilder>; - register(name: S[K] extends ExtractDependency ? K : never, value: V): ConfigBuilder>; - register(name: K, value: S[K], raw: true): ConfigBuilder>; - - apply(container: Container): Promise; +export interface Configuration { + register(name: K, builder: (d: DescriptorBuilder) => void): Configuration>; } - -export interface ServicesDeclaration { - build(this: void): ServiceRecordBuilder; - annotate(this: void): AnnotaionBuilder; - - dependency(this: void, name: K, opts: LazyDependencyOptions): LazyDependencyRegistration; - dependency(this: void, name: K, opts?: DependencyOptions): DependencyRegistration; - - configure(): ConfigBuilder; -} diff --git a/src/main/ts/di/interfaces.ts b/src/main/ts/di/interfaces.ts --- a/src/main/ts/di/interfaces.ts +++ b/src/main/ts/di/interfaces.ts @@ -1,5 +1,4 @@ import { ActivationContext } from "./ActivationContext"; -import { IDestroyable } from "../interfaces"; export interface Descriptor { activate(context: ActivationContext): T; @@ -11,24 +10,24 @@ export type ServiceMap export type ContainerKeys = keyof S | keyof ContainerProvided; -export type ContainerResolve = +export type TypeOfService = K extends keyof ContainerProvided ? ContainerProvided[K] : K extends keyof S ? S[K] : never; export type ContainerServiceMap = { - [K in ContainerKeys]: Descriptor>; + [K in ContainerKeys]: Descriptor>; }; export type PartialServiceMap = { [k in keyof S]?: Descriptor; }; -export interface Resolver { - resolve>(name: K, def?: ContainerResolve): ContainerResolve; +export interface ServiceLocator { + resolve>(name: K, def?: TypeOfService): TypeOfService; } export interface ContainerProvided { - container: Resolver; + container: ServiceLocator; } export type ContainerRegistered = /*{ @@ -38,11 +37,16 @@ export type ContainerRegistered): ILifetime; +export interface ILifetimeManager { + initialize(context: ActivationContext): ILifetime; } +/** + * Интерфейс для управления жизнью экземпляра объекта. Каждая регистрация имеет + * свой собственный объект `ILifetime`, который создается при первой активации + */ export interface ILifetime { + /** Проверяет, что уже создан экземпляр объекта */ has(): boolean; get(): any; diff --git a/src/main/ts/di/traits.ts b/src/main/ts/di/traits.ts --- a/src/main/ts/di/traits.ts +++ b/src/main/ts/di/traits.ts @@ -1,46 +1,19 @@ import { isPrimitive } from "../safe"; import { Descriptor } from "./interfaces"; -import { ServicesDeclaration, ServiceRecordBuilder, ServiceModule, RegistrationBuilder, ExtractDependency } from "./fluent/interfaces"; -import { AnnotaionBuilder } from "./Annotations"; -import { FactoryBuilder } from "./fluent/FactoryBuilder"; -import { ConstructorBuilder } from "./fluent/ConstructorBuiler"; +import { AnnotationBuilder } from "./Annotations"; +import { Configuration } from "./fluent/Configuration"; export function isDescriptor(x: any): x is Descriptor { return (!isPrimitive(x)) && (x.activate instanceof Function); } -export function declare(): ServicesDeclaration { +export function declare() { return { annotate() { - return new AnnotaionBuilder(); + return new AnnotationBuilder(); }, - build(): ServiceRecordBuilder { - return { - factory

) => T>( - target: F, - ...params: P - ): FactoryBuilder { - return new FactoryBuilder(target, params); - }, - - type

) => T>( - target: C, ...params: P - ): ConstructorBuilder { - return new ConstructorBuilder(target, params); - }, - - wired(module: ServiceModule, m?: M): RegistrationBuilder { - const service = m ? - module[m] : - (module as ServiceModule).service; - if (!service) - throw new Error("The specified module doen's provides a service annotation"); - return service.getRegistrationBuilder(); - } - }; - }, - configure() { + configure(): Configuration { throw new Error(); }, dependency() { 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 @@ -1,17 +1,20 @@ -import { configure, dependency, build } from "./services"; +import { configure } from "./services"; export const config = configure() - .register("bar", async s => s.wired(await import("./Bar"), "service")) - .register("box", s => import("./Box").then(m => s.wired(m))) - .register("host", "example.com") - // .registerType("bar2", Bar, [{ foo: dependency("foo"), host: "" }]); - .register("bar2", async s => s.type((await import("./Bar")).Bar, - { - foo: build().type((await import("./Foo")).Foo) - .activate("context"), - nested: { lazy: dependency("foo", { lazy: true }) }, - host: dependency("host") - }, - "") - .inject("setName", dependency("host")) + .register("host", s => s.value("example.com")) + .register("bar2", bar2 => Promise.all([import("./Foo"), import("./Bar")]) + .then(([{ Foo }, { Bar }]) => { + const lifetime: any = undefined; // new HierarchyLifetime() + bar2.factory((resolve, activate) => { + const bar = new Bar({ + foo: activate(lifetime, () => new Foo()), + nested: { + lazy: resolve("foo", { lazy: true }) + }, + host: resolve("host") + }, "some text"); + bar.setName(resolve("host")); + return bar; + }); + }) ); diff --git a/src/test/ts/mock/services.ts b/src/test/ts/mock/services.ts --- a/src/test/ts/mock/services.ts +++ b/src/test/ts/mock/services.ts @@ -1,7 +1,7 @@ import { Foo } from "./Foo"; import { Bar } from "./Bar"; import { Box } from "./Box"; -import { declare } from "../di/fluent/interfaces"; +import { declare } from "../di/traits"; /** * Сервисы доступные внутри контейнера @@ -22,4 +22,4 @@ export interface Services { /** * Экспортируем вспомогательные функции для описания сервисов и кинфогурации */ -export const { dependency, build, annotate, configure } = declare(); +export const { dependency, annotate, configure } = declare();