##// END OF EJS Templates
removed debounce(...).applyAsync
removed debounce(...).applyAsync

File last commit:

r152:8bee6a6d5f46 v1.4.0-rc10 default
r161:be122e264286 default
Show More
Configuration.ts
459 lines | 14.8 KiB | video/mp2t | TypeScriptLexer
/ src / main / ts / di / Configuration.ts
cin
changed the project structure
r49 import {
cin
configuration interfaces moved to di/Configuration module...
r118 PartialServiceMap,
cin
improved interfaces and more tight type checking
r120 ActivationType,
ContainerKeys,
cin
working on fluent configuration
r133 TypeOfService,
cin
Fixed container interfaces, separated ServiceContainer
r144 ILifetime, ServiceContainer
cin
changed the project structure
r49 } from "./interfaces";
cin
fixed bug in applying a lifetime while processing the json configuration...
r152 import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get, primitive, oid, mixin } from "../safe";
cin
changed the project structure
r49 import { AggregateDescriptor } from "./AggregateDescriptor";
import { ValueDescriptor } from "./ValueDescriptor";
import { ReferenceDescriptor } from "./ReferenceDescriptor";
import { TypeServiceDescriptor } from "./TypeServiceDescriptor";
import { FactoryServiceDescriptor } from "./FactoryServiceDescriptor";
import { TraceSource } from "../log/TraceSource";
import { ConfigError } from "./ConfigError";
import { Cancellation } from "../Cancellation";
cin
working on support commonjs modules format
r59 import { makeResolver } from "./ResolverHelper";
cin
improved interfaces and more tight type checking
r120 import { ICancellation } from "../interfaces";
cin
configuration interfaces moved to di/Configuration module...
r118 import { isDescriptor } from "./traits";
cin
Added LazyReferenceDescriptor, removed lazy behaviour from ReferenceDescriptor.
r122 import { LazyReferenceDescriptor } from "./LazyReferenceDescriptor";
cin
working on fluent configuration
r132 import { LifetimeManager } from "./LifetimeManager";
cin
fixed bug in applying a lifetime while processing the json configuration...
r152 import { ServiceDescriptorParams } from "./ServiceDescriptor";
cin
configuration interfaces moved to di/Configuration module...
r118
cin
improved interfaces and more tight type checking
r120 export interface RegistrationScope<S extends object> {
cin
configuration interfaces moved to di/Configuration module...
r118
/** сервисы, которые регистрируются в контексте активации и таким образом
* могут переопределять ранее зарегистрированные сервисы. за это свойство
* нужно платить, кроме того порядок активации будет влиять на результат
* разрешения зависимостей.
*/
cin
improved interfaces and more tight type checking
r120 services?: RegistrationMap<S>;
cin
configuration interfaces moved to di/Configuration module...
r118 }
/**
cin
working on fluent configuration
r133 * Базовый интерфейс конфигурации сервисов
cin
configuration interfaces moved to di/Configuration module...
r118 */
cin
sync
r121 export interface ServiceRegistration<T, S extends object> extends RegistrationScope<S> {
cin
configuration interfaces moved to di/Configuration module...
r118
activation?: ActivationType;
cin
sync
r121 params?: any;
cin
configuration interfaces moved to di/Configuration module...
r118
cin
working on fluent configuration
r133 /** Специальный идентификатор используется при активации singleton, если
* не указан для TypeRegistration вычисляется как oid($type)
*/
typeId?: string;
cin
configuration interfaces moved to di/Configuration module...
r118 inject?: object | object[];
cleanup?: ((instance: T) => void) | string;
}
cin
working on container configuration dsl
r124 export interface TypeRegistration<C extends new (...args: any[]) => any, S extends object> extends ServiceRegistration<InstanceType<C>, S> {
cin
sync
r121 $type: string | C;
cin
working on container configuration dsl
r124 params?: Registration<ConstructorParameters<C>, S>;
cin
configuration interfaces moved to di/Configuration module...
r118 }
cin
working on container configuration dsl
r124 export interface StrictTypeRegistration<C extends new (...args: any[]) => any, S extends object> extends ServiceRegistration<InstanceType<C>, S> {
$type: C;
params?: Registration<ConstructorParameters<C>, S>;
}
export interface FactoryRegistration<F extends (...args: any[]) => any, S extends object> extends ServiceRegistration<ReturnType<F>, S> {
cin
sync
r121 $factory: string | F;
cin
configuration interfaces moved to di/Configuration module...
r118 }
export interface ValueRegistration<T> {
$value: T;
parse?: boolean;
}
cin
improved interfaces and more tight type checking
r120 export interface DependencyRegistration<S extends object, K extends ContainerKeys<S> = ContainerKeys<S>> extends RegistrationScope<S> {
cin
configuration interfaces moved to di/Configuration module...
r118 $dependency: K;
lazy?: boolean;
optional?: boolean;
cin
working on fluent configuration
r133 default?: TypeOfService<S, K>;
cin
configuration interfaces moved to di/Configuration module...
r118 }
cin
sync
r121 export interface LazyDependencyRegistration<S extends object, K extends ContainerKeys<S> = ContainerKeys<S>> extends DependencyRegistration<S, K> {
lazy: true;
}
cin
improved interfaces and more tight type checking
r120 export type Registration<T, S extends object> = T extends primitive ? T :
(
T |
{ [k in keyof T]: Registration<T[k], S> } |
cin
working on container configuration dsl
r124 TypeRegistration<new (...args: any[]) => T, S> |
FactoryRegistration<(...args: any[]) => T, S> |
cin
improved interfaces and more tight type checking
r120 ValueRegistration<any> |
DependencyRegistration<S, keyof S>
);
export type RegistrationMap<S extends object> = {
[k in keyof S]?: Registration<S[k], S>;
};
cin
configuration interfaces moved to di/Configuration module...
r118 const _activationTypes: { [k in ActivationType]: number; } = {
singleton: 1,
container: 2,
hierarchy: 3,
context: 4,
call: 5
};
cin
sync
r121 export function isTypeRegistration(x: any): x is TypeRegistration<new () => any, any> {
cin
configuration interfaces moved to di/Configuration module...
r118 return (!isPrimitive(x)) && ("$type" in x);
}
cin
sync
r121 export function isFactoryRegistration(x: any): x is FactoryRegistration<() => any, any> {
cin
configuration interfaces moved to di/Configuration module...
r118 return (!isPrimitive(x)) && ("$factory" in x);
}
export function isValueRegistration(x: any): x is ValueRegistration<any> {
return (!isPrimitive(x)) && ("$value" in x);
}
cin
improved interfaces and more tight type checking
r120 export function isDependencyRegistration<S extends object>(x: any): x is DependencyRegistration<S, keyof S> {
cin
configuration interfaces moved to di/Configuration module...
r118 return (!isPrimitive(x)) && ("$dependency" in x);
}
export function isActivationType(x: string): x is ActivationType {
return typeof x === "string" && x in _activationTypes;
}
cin
changed the project structure
r49
const trace = TraceSource.get("@implab/core/di/Configuration");
cin
corrected code to support ts strict mode...
r115 async function mapAll(data: any[], map?: (v: any, k: number) => any): Promise<any[]>;
async function mapAll(data: any, map?: (v: any, k: string) => any): Promise<any>;
async function mapAll(data: any, map?: (v: any, k: any) => any): Promise<any> {
cin
changed the project structure
r49 if (data instanceof Array) {
return Promise.all(map ? data.map(map) : data);
} else {
const keys = Object.keys(data);
const o: any = {};
await Promise.all(keys.map(async k => {
const v = map ? map(data[k], k) : data[k];
o[k] = isPromise(v) ? await v : v;
}));
return o;
}
}
cin
working on support commonjs modules format
r59 export type ModuleResolver = (moduleName: string, ct?: ICancellation) => any;
cin
changed the project structure
r49
cin
improved interfaces and more tight type checking
r120 export class Configuration<S extends object> {
cin
changed the project structure
r49
_hasInnerDescriptors = false;
cin
Fixed container interfaces, separated ServiceContainer
r144 readonly _container: ServiceContainer<S>;
cin
changed the project structure
r49
cin
working on IoC configuration
r114 _path: Array<string>;
cin
changed the project structure
r49
cin
working on IoC configuration
r113 _configName: string | undefined;
cin
changed the project structure
r49
cin
working on IoC configuration
r113 _require: ModuleResolver | undefined;
cin
changed the project structure
r49
cin
Fixed container interfaces, separated ServiceContainer
r144 constructor(container: ServiceContainer<S>) {
cin
Added safe.delay...
r76 argumentNotNull(container, "container");
cin
changed the project structure
r49 this._container = container;
this._path = [];
}
cin
working on support commonjs modules format
r59 async loadConfiguration(moduleName: string, contextRequire?: any, ct = Cancellation.none) {
cin
working version...
r51 argumentNotEmptyString(moduleName, "moduleName");
cin
working on support commonjs modules format
r59
cin
Added support for commonjs module format, all tests are pass.
r60 trace.log(
"loadConfiguration moduleName={0}, contextRequire={1}",
moduleName,
contextRequire ? typeof (contextRequire) : "<nil>"
);
cin
working on support commonjs modules format
r59
this._configName = moduleName;
cin
working on IoC configuration
r113 const r = await makeResolver(undefined, contextRequire);
cin
working version...
r51
cin
working on support commonjs modules format
r59 const config = await r(moduleName, ct);
await this._applyConfiguration(
config,
cin
fixed "singleton" activation type handling in container configuration...
r65 await makeResolver(moduleName, contextRequire),
cin
working on support commonjs modules format
r59 ct
);
cin
working version...
r51 }
cin
tests
r136 async applyConfiguration(data: RegistrationMap<S>, opts: { contextRequire?: any; baseModule?: string }, ct = Cancellation.none) {
cin
changed the project structure
r49 argumentNotNull(data, "data");
cin
tests
r136 const _opts = opts || {};
cin
changed the project structure
r49
cin
tests
r136 await this._applyConfiguration(data, await makeResolver(_opts.baseModule, _opts.contextRequire), ct);
cin
working on support commonjs modules format
r59 }
cin
improved interfaces and more tight type checking
r120 async _applyConfiguration(data: RegistrationMap<S>, resolver?: ModuleResolver, ct = Cancellation.none) {
cin
changed the project structure
r49 trace.log("applyConfiguration");
this._configName = "$";
cin
tests moved under src/ folder...
r50 if (resolver)
this._require = resolver;
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 let services: PartialServiceMap<S>;
cin
changed the project structure
r49
try {
services = await this._visitRegistrations(data, "$");
} catch (e) {
throw this._makeError(e);
}
this._container.register(services);
}
cin
working on IoC configuration
r113 _makeError(inner: any) {
cin
changed the project structure
r49 const e = new ConfigError("Failed to load configuration", inner);
cin
working on IoC configuration
r113 e.configName = this._configName || "<inline>";
cin
changed the project structure
r49 e.path = this._makePath();
return e;
}
_makePath() {
return this._path
.reduce(
(prev, cur) => typeof cur === "number" ?
`${prev}[${cur}]` :
`${prev}.${cur}`
)
.toString();
}
async _resolveType(moduleName: string, localName: string) {
trace.log("resolveType moduleName={0}, localName={1}", moduleName, localName);
try {
const m = await this._loadModule(moduleName);
cin
working on fluent configuration
r133 if (localName) {
return get(localName, m);
} else {
if (m instanceof Function)
return m;
if ("default" in m)
return m.default;
return m;
}
cin
changed the project structure
r49 } catch (e) {
trace.error("Failed to resolve type moduleName={0}, localName={1}", moduleName, localName);
throw e;
}
}
cin
working on support commonjs modules format
r59 _loadModule(moduleName: string) {
cin
changed the project structure
r49 trace.debug("loadModule {0}", moduleName);
cin
working on IoC configuration
r113 if (!this._require)
throw new Error("Module loader isn't specified");
cin
changed the project structure
r49
cin
working on support commonjs modules format
r59 return this._require(moduleName);
cin
changed the project structure
r49 }
cin
improved interfaces and more tight type checking
r120 async _visitRegistrations(data: RegistrationMap<S>, name: string) {
cin
changed the project structure
r49 this._enter(name);
if (data.constructor &&
data.constructor.prototype !== Object.prototype)
throw new Error("Configuration must be a simple object");
const services = await mapAll(data, async (v, k) => {
cin
working on IoC configuration
r114 const d = await this._visit(v, k.toString());
cin
changed the project structure
r49 return isDescriptor(d) ? d : new AggregateDescriptor(d);
cin
corrected code to support ts strict mode...
r115 }) as PartialServiceMap<S>;
cin
changed the project structure
r49
this._leave();
return services;
}
cin
corrected code to support ts strict mode...
r115 _enter(name: string) {
cin
working on IoC configuration
r113 this._path.push(name.toString());
cin
changed the project structure
r49 trace.debug(">{0}", name);
}
_leave() {
const name = this._path.pop();
trace.debug("<{0}", name);
}
cin
working on fluent configuration, di annotations removed
r134 _visit(data: any, name: string): Promise<any> {
if (isPrimitive(data))
return Promise.resolve(new ValueDescriptor(data));
if (isDescriptor(data))
return Promise.resolve(data);
cin
changed the project structure
r49
cin
working on IoC configuration
r114 if (isDependencyRegistration<S>(data)) {
cin
changed the project structure
r49 return this._visitDependencyRegistration(data, name);
} else if (isValueRegistration(data)) {
return this._visitValueRegistration(data, name);
} else if (isTypeRegistration(data)) {
return this._visitTypeRegistration(data, name);
} else if (isFactoryRegistration(data)) {
return this._visitFactoryRegistration(data, name);
} else if (data instanceof Array) {
return this._visitArray(data, name);
}
cin
configuration interfaces moved to di/Configuration module...
r118 return this._visitObject(data, name);
cin
changed the project structure
r49 }
cin
configuration interfaces moved to di/Configuration module...
r118 async _visitObject(data: any, name: string) {
cin
changed the project structure
r49 if (data.constructor &&
data.constructor.prototype !== Object.prototype)
return new ValueDescriptor(data);
this._enter(name);
const v = await mapAll(data, delegate(this, "_visit"));
// TODO: handle inline descriptors properly
// const ex = {
// activate(ctx) {
// const value = ctx.activate(this.prop, "prop");
// // some code
// },
// // will be turned to ReferenceDescriptor
// prop: { $dependency: "depName" }
// };
this._leave();
return v;
}
cin
working on IoC configuration
r114 async _visitArray(data: any[], name: string) {
cin
changed the project structure
r49 if (data.constructor &&
data.constructor.prototype !== Array.prototype)
return new ValueDescriptor(data);
this._enter(name);
const v = await mapAll(data, delegate(this, "_visit"));
this._leave();
return v;
}
cin
sync
r121 _makeServiceParams(data: ServiceRegistration<any, S>) {
cin
fixed bug in applying a lifetime while processing the json configuration...
r152 const opts: any = {};
cin
changed the project structure
r49 if (data.services)
opts.services = this._visitRegistrations(data.services, "services");
if (data.inject) {
cin
fixed "singleton" activation type handling in container configuration...
r65 this._enter("inject");
cin
changed the project structure
r49 opts.inject = mapAll(
data.inject instanceof Array ?
data.inject :
[data.inject],
delegate(this, "_visitObject")
);
this._leave();
}
if ("params" in data)
opts.params = data.params instanceof Array ?
this._visitArray(data.params, "params") :
this._visit(data.params, "params");
if (data.activation) {
cin
fixed bug in applying a lifetime while processing the json configuration...
r152 opts.lifetime = this._getLifetimeManager(data.activation, data.typeId);
cin
changed the project structure
r49 }
if (data.cleanup)
opts.cleanup = data.cleanup;
return opts;
}
cin
working on IoC configuration
r114 async _visitValueRegistration<T>(data: ValueRegistration<T>, name: string) {
cin
changed the project structure
r49 this._enter(name);
const d = data.parse ? new AggregateDescriptor(data.$value) : new ValueDescriptor(data.$value);
this._leave();
return d;
}
cin
working on IoC configuration
r114 async _visitDependencyRegistration<K extends keyof S>(data: DependencyRegistration<S, K>, name: string) {
cin
changed the project structure
r49 argumentNotEmptyString(data && data.$dependency, "data.$dependency");
this._enter(name);
cin
Added LazyReferenceDescriptor, removed lazy behaviour from ReferenceDescriptor.
r122 const options = {
cin
changed the project structure
r49 name: data.$dependency,
optional: data.optional,
default: data.default,
services: data.services && await this._visitRegistrations(data.services, "services")
cin
Added LazyReferenceDescriptor, removed lazy behaviour from ReferenceDescriptor.
r122 };
const d = data.lazy ? new LazyReferenceDescriptor<S, K>(options) : new ReferenceDescriptor<S, K>(options);
cin
changed the project structure
r49 this._leave();
return d;
}
cin
sync
r121 async _visitTypeRegistration(data: TypeRegistration<new () => any, S>, name: string) {
cin
changed the project structure
r49 argumentNotNull(data.$type, "data.$type");
this._enter(name);
cin
fixed bug in applying a lifetime while processing the json configuration...
r152 const opts = {} as any;
cin
changed the project structure
r49 if (data.$type instanceof Function) {
opts.type = data.$type;
} else {
const [moduleName, typeName] = data.$type.split(":", 2);
cin
working on fluent configuration, di annotations removed
r134 opts.type = this._resolveType(moduleName, typeName).then(t => {
if (!(t instanceof Function))
throw Error("$type (" + data.$type + ") is not a constructable");
return t;
});
cin
changed the project structure
r49 }
cin
fixed bug in applying a lifetime while processing the json configuration...
r152 if (!data.typeId && data.activation === "singleton")
data.typeId = oid(opts.type);
mixin(opts, this._makeServiceParams(data));
cin
configuration interfaces moved to di/Configuration module...
r118 const d = new TypeServiceDescriptor<S, any, any[]>(
cin
changed the project structure
r49 await mapAll(opts)
);
this._leave();
return d;
}
cin
sync
r121 async _visitFactoryRegistration(data: FactoryRegistration<() => any, S>, name: string) {
cin
fixed "singleton" activation type handling in container configuration...
r65 argumentOfType(data.$factory, Function, "data.$factory");
cin
changed the project structure
r49 this._enter(name);
cin
fixed bug in applying a lifetime while processing the json configuration...
r152 if (!data.typeId && data.activation === "singleton")
data.typeId = oid(data.$factory);
cin
changed the project structure
r49 const opts = this._makeServiceParams(data);
cin
fixed "singleton" activation type handling in container configuration...
r65 opts.factory = data.$factory;
cin
changed the project structure
r49
cin
configuration interfaces moved to di/Configuration module...
r118 const d = new FactoryServiceDescriptor<S, any, any[]>(
cin
changed the project structure
r49 await mapAll(opts)
);
this._leave();
return d;
}
cin
working on fluent configuration
r132
cin
working on fluent configuration, di annotations removed
r134 _getLifetimeManager(activation: ActivationType, typeId: string | undefined): ILifetime {
cin
working on fluent configuration
r132 switch (activation) {
case "container":
cin
working on fluent configuration, di annotations removed
r134 return LifetimeManager.containerLifetime(this._container);
cin
working on fluent configuration
r132 case "hierarchy":
cin
working on fluent configuration, di annotations removed
r134 return LifetimeManager.hierarchyLifetime();
cin
working on fluent configuration
r132 case "context":
cin
working on fluent configuration, di annotations removed
r134 return LifetimeManager.contextLifetime();
cin
working on fluent configuration
r132 case "singleton":
cin
working on fluent configuration
r133 if (typeId === undefined)
throw Error("The singleton activation requires a typeId");
return LifetimeManager.singletonLifetime(typeId);
cin
working on fluent configuration
r132 default:
cin
working on fluent configuration, di annotations removed
r134 return LifetimeManager.empty();
cin
working on fluent configuration
r132 }
}
cin
changed the project structure
r49 }