(nameOrConfig: K | FluentRegistrations, builder?: RegistrationBuilder): FluentConfiguration> {
- if (isPrimitive(nameOrConfig)) {
+ provided>(): FluentConfiguration> {
+ return this as FluentConfiguration>;
+ }
+
+ register(name: K, builder: RegistrationBuildersMap[K]): FluentConfiguration>;
+ register(config: RegistrationBuildersMap): FluentConfiguration>;
+ register(nameOrConfig: K | RegistrationBuildersMap, builder?: RegistrationBuildersMap[K]) {
+ if (isKey(nameOrConfig)) {
argumentNotNull(builder, "builder");
this._builders[nameOrConfig] = builder;
} else {
each(nameOrConfig, (v, k) => this.register(k, v));
}
+ return this as FluentConfiguration>;
+ }
+
+ done(missing: RequiredKeys extends never ? void : RequiredKeys) {
+ if (missing !== undefined)
+ throw new Error("The configuration isn't complete");
return this;
}
- configure(config: FluentRegistrations): ContainerConfiguration {
- return this.register(config);
- }
- apply(target: ServiceContainer, ct = Cancellation.none) {
+ apply>(target: ServiceContainer) {
let pending = 1;
- const _t2 = target as unknown as ServiceContainer;
+ const _t2 = target as ServiceContainer;
- return new Promise>((resolve, reject) => {
- function guard(v: void | Promise) {
- if (isPromise(v))
- v.catch(reject);
- }
+ const reject = (ex: unknown) => { throw ex; };
+
+ const complete = () => !--pending;
- function complete() {
- if (!--pending)
- resolve(_t2);
- }
- each(this._builders, (v, k) => {
- pending++;
- const d = new DescriptorBuilder(_t2,
- result => {
- _t2.register(k, result);
- complete();
- },
- reject
- );
+ each(this._builders, (v, k) => {
+ pending++;
+ const d = new DescriptorBuilder, NonNullable[typeof k]>>(_t2,
+ result => {
+ _t2.register(k, result);
+ complete();
+ },
+ reject
+ );
- try {
- guard(v(d, ct));
- } catch (e) {
- reject(e);
- }
- });
- complete();
+
+ v(d);
});
+ if (!complete())
+ throw new Error("The configuration didn't complete.");
+
+ return _t2 as ServiceContainer;
}
}
diff --git a/src/main/ts/LazyReferenceDescriptor.ts b/src/main/ts/LazyReferenceDescriptor.ts
deleted file mode 100644
--- a/src/main/ts/LazyReferenceDescriptor.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { argumentNotEmptyString, each } from "../safe";
-import { ActivationContext } from "./ActivationContext";
-import { Descriptor, PartialServiceMap, TypeOfService, ContainerKeys } from "./interfaces";
-import { ActivationError } from "./ActivationError";
-
-export interface ReferenceDescriptorParams> {
- name: K;
- optional?: boolean;
- default?: TypeOfService;
- services?: PartialServiceMap;
-}
-
-export class LazyReferenceDescriptor = ContainerKeys>
- implements Descriptor) => TypeOfService)> {
-
- _name: K;
-
- _optional = false;
-
- _default: TypeOfService | 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): any => {
- // защищаем контекст на случай исключения в процессе
- // активации
- const ct = cfg ? saved.clone() : saved;
- 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/LifetimeManager.ts b/src/main/ts/LifetimeManager.ts
--- a/src/main/ts/LifetimeManager.ts
+++ b/src/main/ts/LifetimeManager.ts
@@ -1,23 +1,21 @@
-import { IDestroyable, MapOf } from "../interfaces";
-import { argumentNotNull, isDestroyable, argumentNotEmptyString, isRemovable } from "../safe";
-import { ILifetime, ServiceContainer } from "./interfaces";
+import { IDestroyable, ILifetime } from "./interfaces";
import { ActivationContext } from "./ActivationContext";
+import { argumentNotNull, isDestroyable } from "./traits";
-function safeCall(item: () => void) {
+const safeCall = (item: () => void) => {
try {
item();
} catch {
// silence!
}
-}
+};
-const emptyLifetime: ILifetime = Object.freeze({
+const emptyLifetime = Object.freeze({
has() {
return false;
},
initialize() {
-
},
get() {
@@ -34,7 +32,7 @@ const emptyLifetime: ILifetime = Object.
});
-const unknownLifetime: ILifetime = Object.freeze({
+const unknownLifetime = Object.freeze({
has() {
return false;
},
@@ -54,52 +52,49 @@ const unknownLifetime: ILifetime = Objec
let nextId = 0;
-const singletons: any = {};
+const singletons: { [K:string]: unknown} = {};
export class LifetimeManager implements IDestroyable {
private _cleanup: (() => void)[] = [];
- private _cache: MapOf = {};
+ private readonly _cache: {[K: string]: unknown} = {};
private _destroyed = false;
- private _pending: MapOf = {};
+ private readonly _pending: {[K: string]: unknown} = {};
- create(): ILifetime {
- const self = this;
+ create(): ILifetime {
const id = ++nextId;
return {
- has() {
- return (id in self._cache);
+ has: () => id in this._cache,
+
+ get: () => {
+ const t = this._cache[id];
+ if (t === undefined)
+ throw new Error(`The item with with the key ${id} isn't found`);
+ return t as T;
},
- get() {
- const t = self._cache[id];
- if (t === undefined)
- throw new Error(`The item with with the key ${id} isn't found`);
- return t;
+ initialize: () => {
+ if (this._pending[id])
+ throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`);
+ this._pending[id] = true;
},
- initialize() {
- if (self._pending[id])
- throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`);
- self._pending[id] = true;
- },
-
- store(item: any, cleanup?: (item: any) => void) {
+ store: (item: T, cleanup?: (item: T) => void) => {
argumentNotNull(id, "id");
argumentNotNull(item, "item");
- if (this.has())
+ if (id in this._cache)
throw new Error(`The item with with the key ${id} already registered with this lifetime manager`);
- delete self._pending[id];
+ delete this._pending[id];
- self._cache[id] = item;
+ this._cache[id] = item;
- if (self._destroyed)
+ if (this._destroyed)
throw new Error("Lifetime manager is destroyed");
if (cleanup) {
- self._cleanup.push(() => cleanup(item));
+ this._cleanup.push(() => cleanup(item));
} else if (isDestroyable(item)) {
- self._cleanup.push(() => item.destroy());
+ this._cleanup.push(() => item.destroy());
}
}
};
@@ -113,18 +108,18 @@ export class LifetimeManager implements
}
}
- static empty(): ILifetime {
+ static empty(): ILifetime {
return emptyLifetime;
}
- static hierarchyLifetime() {
- let _lifetime = unknownLifetime;
+ static hierarchyLifetime() {
+ let _lifetime: ILifetime = unknownLifetime;
return {
- initialize(context: ActivationContext) {
+ initialize(context: ActivationContext