##// END OF EJS Templates
sync
sync

File last commit:

r115:691199f665e0 ioc ts support
r117:6149d2260004 ioc ts support
Show More
ServiceDescriptor.ts
238 lines | 7.3 KiB | video/mp2t | TypeScriptLexer
/ src / main / ts / di / ServiceDescriptor.ts
cin
changed the project structure
r49 import { ActivationContext } from "./ActivationContext";
cin
corrected code to support ts strict mode...
r115 import { Descriptor, ActivationType, ServiceMap, isDescriptor, Parse, PartialServiceMap } from "./interfaces";
cin
changed the project structure
r49 import { Container } from "./Container";
cin
corrected code to support ts strict mode...
r115 import { argumentNotNull, isPrimitive, each, keys, isNull } from "../safe";
cin
changed the project structure
r49 import { TraceSource } from "../log/TraceSource";
let cacheId = 0;
const trace = TraceSource.get("@implab/core/di/ActivationContext");
cin
corrected code to support ts strict mode...
r115 function injectMethod<T, M extends keyof T, S, A>(target: T, method: M, context: ActivationContext<S>, args: A) {
cin
changed the project structure
r49 const m = target[method];
cin
corrected code to support ts strict mode...
r115 if (!m || typeof m !== "function")
cin
changed the project structure
r49 throw new Error("Method '" + method + "' not found");
if (args instanceof Array)
cin
fixed "singleton" activation type handling in container configuration...
r65 return m.apply(target, _parse(args, context, "." + method));
cin
changed the project structure
r49 else
cin
fixed "singleton" activation type handling in container configuration...
r65 return m.call(target, _parse(args, context, "." + method));
cin
changed the project structure
r49 }
cin
corrected code to support ts strict mode...
r115 function makeClenupCallback<T>(target: T, method: Cleaner<T>): () => void;
function makeClenupCallback(target: any, method: any) {
cin
changed the project structure
r49 if (typeof (method) === "string") {
return () => {
target[method]();
};
} else {
return () => {
method(target);
};
}
}
cin
corrected code to support ts strict mode...
r115 function _parse<T, S>(value: T, context: ActivationContext<S>, path: string): Parse<T> {
cin
changed the project structure
r49 if (isPrimitive(value))
cin
corrected code to support ts strict mode...
r115 return value as any;
cin
changed the project structure
r49
trace.debug("parse {0}", path);
if (isDescriptor(value))
return context.activate(value, path);
if (value instanceof Array)
cin
corrected code to support ts strict mode...
r115 return value.map((x, i) => _parse(x, context, `${path}[${i}]`)) as any;
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 const t: any = {};
keys(value).forEach(p => t[p] = _parse(value[p], context, `${path}.${p}`));
cin
changed the project structure
r49
return t;
}
cin
corrected code to support ts strict mode...
r115 export type Cleaner<T> = ((x: T) => void) | keyof Extract<T, { [M in keyof T]: () => void }>;
export type InjectionSpec<T> = {
[m in keyof T]?: any;
};
export interface ServiceDescriptorParams<S, T, P extends any[]> {
cin
changed the project structure
r49 activation?: ActivationType;
cin
corrected code to support ts strict mode...
r115 owner: Container<S>;
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 params?: P;
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 inject?: InjectionSpec<T>[];
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 services?: PartialServiceMap<S>;
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 cleanup?: Cleaner<T>;
cin
changed the project structure
r49 }
cin
corrected code to support ts strict mode...
r115 export class ServiceDescriptor<S, T, P extends any[]> implements Descriptor<S, T> {
_instance: T | undefined;
cin
changed the project structure
r49
_hasInstance = false;
_activationType = ActivationType.Call;
cin
corrected code to support ts strict mode...
r115 _services: ServiceMap<S>;
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 _params: P | undefined;
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 _inject: InjectionSpec<T>[];
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 _cleanup: Cleaner<T> | undefined;
cin
changed the project structure
r49
_cacheId: any;
cin
corrected code to support ts strict mode...
r115 _owner: Container<S>;
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 constructor(opts: ServiceDescriptorParams<S, T, P>) {
cin
changed the project structure
r49 argumentNotNull(opts, "opts");
argumentNotNull(opts.owner, "owner");
this._owner = opts.owner;
cin
corrected code to support ts strict mode...
r115 if (!isNull(opts.activation))
cin
changed the project structure
r49 this._activationType = opts.activation;
cin
corrected code to support ts strict mode...
r115 if (!isNull(opts.params))
cin
changed the project structure
r49 this._params = opts.params;
cin
corrected code to support ts strict mode...
r115 this._inject = opts.inject || [];
cin
changed the project structure
r49
cin
corrected code to support ts strict mode...
r115 this._services = (opts.services || {}) as ServiceMap<S>;
cin
changed the project structure
r49
if (opts.cleanup) {
if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
throw new Error(
"The cleanup parameter must be either a function or a function name");
this._cleanup = opts.cleanup;
}
}
cin
corrected code to support ts strict mode...
r115 activate(context: ActivationContext<S>) {
cin
changed the project structure
r49 // if we have a local service records, register them first
cin
corrected code to support ts strict mode...
r115 let instance: T;
cin
changed the project structure
r49
// ensure we have a cache id
if (!this._cacheId)
this._cacheId = ++cacheId;
switch (this._activationType) {
case ActivationType.Singleton: // SINGLETON
// if the value is cached return it
if (this._hasInstance)
return this._instance;
// singletons are bound to the root container
const container = context.container.getRootContainer();
if (container.has(this._cacheId)) {
instance = container.get(this._cacheId);
} else {
instance = this._create(context);
container.store(this._cacheId, instance);
if (this._cleanup)
container.onDispose(
makeClenupCallback(instance, this._cleanup));
}
this._hasInstance = true;
return (this._instance = instance);
case ActivationType.Container: // CONTAINER
// return a cached value
if (this._hasInstance)
return this._instance;
// create an instance
instance = this._create(context);
// the instance is bound to the container
if (this._cleanup)
this._owner.onDispose(
makeClenupCallback(instance, this._cleanup));
// cache and return the instance
this._hasInstance = true;
return (this._instance = instance);
case ActivationType.Context: // CONTEXT
// return a cached value if one exists
if (context.has(this._cacheId))
return context.get(this._cacheId);
// context context activated instances are controlled by callers
return context.store(this._cacheId, this._create(context));
case ActivationType.Call: // CALL
// per-call created instances are controlled by callers
return this._create(context);
case ActivationType.Hierarchy: // HIERARCHY
// hierarchy activated instances are behave much like container activated
// except they are created and bound to the child container
// return a cached value
if (context.container.has(this._cacheId))
return context.container.get(this._cacheId);
instance = this._create(context);
if (this._cleanup)
context.container.onDispose(makeClenupCallback(
instance,
this._cleanup));
return context.container.store(this._cacheId, instance);
default:
throw new Error("Invalid activation type: " + this._activationType);
}
}
isInstanceCreated() {
return this._hasInstance;
}
getInstance() {
return this._instance;
}
cin
corrected code to support ts strict mode...
r115 _factory(...params: any[]): T {
cin
changed the project structure
r49 throw Error("Not implemented");
}
cin
corrected code to support ts strict mode...
r115 _create(context: ActivationContext<S>) {
cin
changed the project structure
r49 trace.debug(`constructing ${context._name}`);
if (this._activationType !== ActivationType.Call &&
context.visit(this._cacheId) > 0)
throw new Error("Recursion detected");
if (this._services) {
cin
corrected code to support ts strict mode...
r115 keys(this._services).forEach(p => context.register(p, this._services[p]));
cin
changed the project structure
r49 }
cin
corrected code to support ts strict mode...
r115 let instance: T;
cin
changed the project structure
r49
if (this._params === undefined) {
instance = this._factory();
} else if (this._params instanceof Array) {
instance = this._factory.apply(this, _parse(this._params, context, "args"));
} else {
instance = this._factory(_parse(this._params, context, "args"));
}
if (this._inject) {
this._inject.forEach(spec => {
for (const m in spec)
injectMethod(instance, m, context, spec[m]);
});
}
return instance;
}
}